summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4>2007-11-13 15:20:40 +0000
committerdnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4>2007-11-13 15:20:40 +0000
commit18346ecd861dc66e71dafe48ff216cfa4dc95a21 (patch)
treeb04ec56bade931807b6ed40c6d251c05aa588f0b
parent62e369b3a7e2a62037d4b22f55f96530b76bb9f8 (diff)
downloadgcc-18346ecd861dc66e71dafe48ff216cfa4dc95a21.tar.gz
pr 33870
* tree.h (strcut tree_memory_tag): add field unpartitionable. remove field in_nested_struct. (struct tree_struct_field_tag): add field nesting_level. (sft_in_nested_struct): remove. (sft_nesting_level): define. (sft_unpartitionable_p): define. * tree-ssa-alias.c (mem_sym_score): if mp->var is not partitionable, return long_max. (compute_memory_partitions): do not partition sfts marked unpartitionable. (create_sft): add argument nesting_level. set sft_nesting_level with it. update all users. (create_overlap_variables_for): show nesting level. * tree-dfa.c (dump_subvars_for): likewise. (dump_variable): likewise. show whether the sft is partitionable or not. * tree-flow.h (struct fieldoff): remove field in_nested_struct. add field nesting_level. * tree-ssa-structalias.c (struct variable_info): remove field in_nested_struct. (push_fields_onto_fieldstack): add argument nesting_level. update all users. update documentation. update pair->nesting_level with nesting_level. make recursive calls with nesting_level + 1. (set_uids_in_ptset): if an sft is added to the points-to set, mark it as unpartitionable. * tree-ssa-operands.c (ref_nesting_level): new. (add_vars_for_offset): call it. add argument full_ref. update callers. if var is inside a nested structure and the nesting level of full_ref is lower than the nesting level of var, adjust offset by the offset of var. testsuite/ChangeLog PR 33870 * gcc.c-torture/execute/pr33870-1.c: New test. * gcc.dg/tree-ssa/alias-16.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@130141 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog39
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr33870-1.c94
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/alias-16.c33
-rw-r--r--gcc/tree-dfa.c13
-rw-r--r--gcc/tree-flow.h10
-rw-r--r--gcc/tree-ssa-alias.c36
-rw-r--r--gcc/tree-ssa-operands.c52
-rw-r--r--gcc/tree-ssa-structalias.c85
-rw-r--r--gcc/tree.h17
10 files changed, 318 insertions, 67 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7dfb2ae7968..ffff6ccaa2c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,42 @@
+2007-11-13 diego novillo <dnovillo@google.com>
+
+ pr 33870
+ * tree.h (strcut tree_memory_tag): add field unpartitionable.
+ remove field in_nested_struct.
+ (struct tree_struct_field_tag): add field nesting_level.
+ (sft_in_nested_struct): remove.
+ (sft_nesting_level): define.
+ (sft_unpartitionable_p): define.
+ * tree-ssa-alias.c (mem_sym_score): if mp->var is not
+ partitionable, return long_max.
+ (compute_memory_partitions): do not partition sfts marked
+ unpartitionable.
+ (create_sft): add argument nesting_level. set
+ sft_nesting_level with it. update all users.
+ (create_overlap_variables_for): show nesting level.
+ * tree-dfa.c (dump_subvars_for): likewise.
+ (dump_variable): likewise.
+ show whether the sft is partitionable or not.
+ * tree-flow.h (struct fieldoff): remove field
+ in_nested_struct.
+ add field nesting_level.
+ * tree-ssa-structalias.c (struct variable_info): remove
+ field in_nested_struct.
+ (push_fields_onto_fieldstack): add argument
+ nesting_level. update all users.
+ update documentation.
+ update pair->nesting_level with nesting_level.
+ make recursive calls with nesting_level + 1.
+ (set_uids_in_ptset): if an sft is added to the points-to
+ set, mark it as unpartitionable.
+ * tree-ssa-operands.c (ref_nesting_level): new.
+ (add_vars_for_offset): call it.
+ add argument full_ref. update
+ callers.
+ if var is inside a nested structure and the nesting level
+ of full_ref is lower than the nesting level of var,
+ adjust offset by the offset of var.
+
2007-11-13 Victor Kaplansky <victork@il.ibm.com>
PR tree-optimization/32582
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 6bbbe33a2e7..a1166ece4a9 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2007-11-13 Diego Novillo <dnovillo@google.com>
+
+ PR 33870
+ * gcc.c-torture/execute/pr33870-1.c: New test.
+ * gcc.dg/tree-ssa/alias-16.c: New test.
+
2007-11-13 Jakub Jelinek <jakub@redhat.com>
PR c++/29225
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr33870-1.c b/gcc/testsuite/gcc.c-torture/execute/pr33870-1.c
new file mode 100644
index 00000000000..af5a40db66b
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr33870-1.c
@@ -0,0 +1,94 @@
+extern void abort (void);
+
+typedef struct PgHdr PgHdr;
+typedef unsigned char u8;
+struct PgHdr {
+int y;
+struct {
+ unsigned int pgno;
+ PgHdr *pNextHash, *pPrevHash;
+ PgHdr *pNextFree, *pPrevFree;
+ PgHdr *pNextAll;
+ u8 inJournal;
+ short int nRef;
+ PgHdr *pDirty, *pPrevDirty;
+ unsigned int notUsed;
+} x;
+};
+PgHdr **xx;
+volatile int vx;
+static inline PgHdr *merge_pagelist(PgHdr *pA, PgHdr *pB)
+{
+ PgHdr result;
+ PgHdr *pTail;
+ xx = &result.x.pDirty;
+ pTail = &result;
+ while( pA && pB ){
+ if( pA->x.pgno<pB->x.pgno ){
+ pTail->x.pDirty = pA;
+ pTail = pA;
+ pA = pA->x.pDirty;
+ }else{
+ pTail->x.pDirty = pB;
+ pTail = pB;
+ pB = pB->x.pDirty;
+ }
+ vx = (*xx)->y;
+ }
+ if( pA ){
+ pTail->x.pDirty = pA;
+ }else if( pB ){
+ pTail->x.pDirty = pB;
+ }else{
+ pTail->x.pDirty = 0;
+ }
+ return result.x.pDirty;
+}
+
+PgHdr * __attribute__((noinline)) sort_pagelist(PgHdr *pIn)
+{
+ PgHdr *a[25], *p;
+ int i;
+ __builtin_memset (a, 0, sizeof (a));
+ while( pIn ){
+ p = pIn;
+ pIn = p->x.pDirty;
+ p->x.pDirty = 0;
+ for(i=0; i<25 -1; i++){
+ if( a[i]==0 ){
+ a[i] = p;
+ break;
+ }else{
+ p = merge_pagelist(a[i], p);
+ a[i] = 0;
+ a[i] = 0;
+ }
+ }
+ if( i==25 -1 ){
+ a[i] = merge_pagelist(a[i], p);
+ }
+ }
+ p = a[0];
+ for(i=1; i<25; i++){
+ p = merge_pagelist (p, a[i]);
+ }
+ return p;
+}
+
+int main()
+{
+ PgHdr a[5];
+ PgHdr *p;
+ a[0].x.pgno = 5;
+ a[0].x.pDirty = &a[1];
+ a[1].x.pgno = 4;
+ a[1].x.pDirty = &a[2];
+ a[2].x.pgno = 1;
+ a[2].x.pDirty = &a[3];
+ a[3].x.pgno = 3;
+ a[3].x.pDirty = 0;
+ p = sort_pagelist (&a[0]);
+ if (p->x.pDirty == p)
+ abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-16.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-16.c
new file mode 100644
index 00000000000..cf10fa913ce
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-16.c
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-options "-O --param max-aliased-vops=1" } */
+
+/* Compile with -O --param max-aliased-vops=1. This partitions all
+ the initial SFTs for 'm' which was causing the operand scanner to
+ miss adding the right SFTs to p->b[2]. */
+extern void abort (void);
+
+struct X {
+ int a;
+ struct Y {
+ int b[4];
+ } b;
+ struct Y c;
+} m;
+
+struct X n;
+
+foo (int i)
+{
+ struct Y *p = (i > 10) ? &m.b : &n.c;
+ p->b[2] = 10;
+ m.b.b[3] = 6;
+ n.c.b[2] = 3;
+ return p->b[2] + n.c.b[2] + m.b.b[3];
+}
+
+main()
+{
+ if (foo (3) != 12)
+ abort ();
+ return 0;
+}
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index 4880e83618e..65a32d935d1 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -287,7 +287,9 @@ dump_subvars_for (FILE *file, tree var)
for (i = 0; VEC_iterate (tree, sv, i, subvar); ++i)
{
print_generic_expr (file, subvar, dump_flags);
- fprintf (file, "@" HOST_WIDE_INT_PRINT_UNSIGNED " ", SFT_OFFSET (subvar));
+ fprintf (file, "@" HOST_WIDE_INT_PRINT_UNSIGNED, SFT_OFFSET (subvar));
+ fprintf (file, "[%u]", SFT_NESTING_LEVEL (subvar));
+ fprintf (file, " ");
}
fprintf (file, "}");
@@ -417,6 +419,15 @@ dump_variable (FILE *file, tree var)
fprintf (file, ", partition symbols: ");
dump_decl_set (file, MPT_SYMBOLS (var));
}
+
+ if (TREE_CODE (var) == STRUCT_FIELD_TAG)
+ {
+ fprintf (file, ", offset: " HOST_WIDE_INT_PRINT_UNSIGNED,
+ SFT_OFFSET (var));
+ fprintf (file, ", nesting: %u", SFT_NESTING_LEVEL (var));
+ fprintf (file, ", partitionable: %s",
+ SFT_UNPARTITIONABLE_P (var) ? "NO" : "YES");
+ }
}
fprintf (file, "\n");
diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h
index 02e9543dd68..83761951859 100644
--- a/gcc/tree-flow.h
+++ b/gcc/tree-flow.h
@@ -1159,9 +1159,9 @@ struct fieldoff
/* Field. */
tree decl;
- /* True if this field is inside a structure nested inside the base
- containing object. */
- unsigned int in_nested_struct : 1;
+ /* Nesting level. This number represents how many structures are
+ wrapping this field. */
+ unsigned nesting_level;
/* Offset from the base of the base containing object to this field. */
HOST_WIDE_INT offset;
@@ -1173,8 +1173,8 @@ typedef struct fieldoff fieldoff_s;
DEF_VEC_O(fieldoff_s);
DEF_VEC_ALLOC_O(fieldoff_s,heap);
-int push_fields_onto_fieldstack (tree, VEC(fieldoff_s,heap) **,
- HOST_WIDE_INT, bool *, tree);
+int push_fields_onto_fieldstack (tree, VEC(fieldoff_s,heap) **, HOST_WIDE_INT,
+ bool *, tree, unsigned);
void sort_fieldstack (VEC(fieldoff_s,heap) *);
void init_alias_heapvars (void);
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index f2e30646d4c..31e04bcca29 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -828,6 +828,13 @@ count_mem_refs (long *num_vuses_p, long *num_vdefs_p,
static inline long
mem_sym_score (mem_sym_stats_t mp)
{
+ /* Unpartitionable SFTs are automatically thrown to the bottom of
+ the list. They are not stored in partitions, but they are used
+ for computing overall statistics. */
+ if (TREE_CODE (mp->var) == STRUCT_FIELD_TAG
+ && SFT_UNPARTITIONABLE_P (mp->var))
+ return LONG_MAX;
+
return mp->frequency_writes * 64 + mp->frequency_reads * 32
+ mp->num_direct_writes * 16 + mp->num_direct_reads * 8
+ mp->num_indirect_writes * 4 + mp->num_indirect_reads * 2
@@ -1392,8 +1399,8 @@ update_reference_counts (struct mem_ref_stats_d *mem_ref_stats)
static void
build_mp_info (struct mem_ref_stats_d *mem_ref_stats,
- VEC(mem_sym_stats_t,heap) **mp_info_p,
- VEC(tree,heap) **tags_p)
+ VEC(mem_sym_stats_t,heap) **mp_info_p,
+ VEC(tree,heap) **tags_p)
{
tree var;
referenced_var_iterator rvi;
@@ -1591,6 +1598,15 @@ compute_memory_partitions (void)
if (!need_to_partition_p (mem_ref_stats))
break;
+ /* SFTs that are marked unpartitionable should not be added to
+ partitions. These SFTs are special because they mark the
+ first SFT into a structure where a pointer is pointing to.
+ This is needed by the operand scanner to find adjacent
+ fields. See add_vars_for_offset for details. */
+ if (TREE_CODE (mp_p->var) == STRUCT_FIELD_TAG
+ && SFT_UNPARTITIONABLE_P (mp_p->var))
+ continue;
+
mpt = find_partition_for (mp_p);
estimate_vop_reduction (mem_ref_stats, mp_p, mpt);
}
@@ -3774,7 +3790,8 @@ get_or_create_used_part_for (size_t uid)
static tree
create_sft (tree var, tree field, unsigned HOST_WIDE_INT offset,
- unsigned HOST_WIDE_INT size, alias_set_type alias_set)
+ unsigned HOST_WIDE_INT size, alias_set_type alias_set,
+ unsigned nesting_level)
{
tree subvar = create_tag_raw (STRUCT_FIELD_TAG, field, "SFT");
@@ -3794,6 +3811,8 @@ create_sft (tree var, tree field, unsigned HOST_WIDE_INT offset,
SFT_OFFSET (subvar) = offset;
SFT_SIZE (subvar) = size;
SFT_ALIAS_SET (subvar) = alias_set;
+ SFT_NESTING_LEVEL (subvar) = nesting_level;
+
return subvar;
}
@@ -3814,7 +3833,7 @@ create_overlap_variables_for (tree var)
return;
push_fields_onto_fieldstack (TREE_TYPE (var), &fieldstack, 0, NULL,
- TREE_TYPE (var));
+ TREE_TYPE (var), 0);
if (VEC_length (fieldoff_s, fieldstack) != 0)
{
subvar_t *subvars;
@@ -3897,7 +3916,6 @@ create_overlap_variables_for (tree var)
field, skip it. Note that we always need the field at
offset 0 so we can properly handle pointers to the
structure. */
-
if ((fo->offset != 0
&& ((fo->offset <= up->minused
&& fo->offset + fosize <= up->minused)
@@ -3906,8 +3924,9 @@ create_overlap_variables_for (tree var)
&& fosize == lastfosize
&& currfotype == lastfotype))
continue;
- subvar = create_sft (var, fo->type, fo->offset,
- fosize, fo->alias_set);
+
+ subvar = create_sft (var, fo->type, fo->offset, fosize,
+ fo->alias_set, fo->nesting_level);
VEC_quick_push (tree, *subvars, subvar);
if (dump_file)
@@ -3918,7 +3937,8 @@ create_overlap_variables_for (tree var)
SFT_OFFSET (subvar));
fprintf (dump_file, " size " HOST_WIDE_INT_PRINT_DEC,
SFT_SIZE (subvar));
- fprintf (dump_file, "\n");
+ fprintf (dump_file, " nesting level %d\n",
+ SFT_NESTING_LEVEL (subvar));
}
lastfotype = currfotype;
diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c
index 87eec7452b7..cd8ade68639 100644
--- a/gcc/tree-ssa-operands.c
+++ b/gcc/tree-ssa-operands.c
@@ -1367,8 +1367,33 @@ access_can_touch_variable (tree ref, tree alias, HOST_WIDE_INT offset,
return true;
}
+
+/* Given an aggregate expression FULL_REF, return the number of
+ aggregates that are containing FULL_REF. So, given a structure
+ reference a.b.c.d, the nesting level for this expression is 2 (the
+ number of '.' in the expression minus 1). */
+
+static unsigned
+ref_nesting_level (tree full_ref)
+{
+ unsigned nesting_level = 0;
+
+ if (!handled_component_p (full_ref))
+ return 0;
+
+ full_ref = TREE_OPERAND (full_ref, 0);
+ while (handled_component_p (full_ref))
+ {
+ nesting_level++;
+ full_ref = TREE_OPERAND (full_ref, 0);
+ }
+
+ return nesting_level;
+}
+
+
/* Add the actual variables FULL_REF can access, given a member of
- full_ref's points-to set VAR, where FULL_REF is an access of SIZE at
+ FULL_REF's points-to set VAR, where FULL_REF is an access of SIZE at
OFFSET from var. IS_CALL_SITE is true if this is a call, and IS_DEF
is true if this is supposed to be a vdef, and false if this should
be a VUSE.
@@ -1386,10 +1411,12 @@ access_can_touch_variable (tree ref, tree alias, HOST_WIDE_INT offset,
This is necessary because foop only actually points to foo's first
member, so that is all the points-to set contains. However, an access
to foop->a may be touching some single SFT if we have created some
- SFT's for a structure. */
+ SFT's for a structure.
+
+ FULL_REF is the original memory expression being analyzed. */
static bool
-add_vars_for_offset (tree var, unsigned HOST_WIDE_INT offset,
+add_vars_for_offset (tree full_ref, tree var, unsigned HOST_WIDE_INT offset,
unsigned HOST_WIDE_INT size, bool is_def)
{
bool added = false;
@@ -1397,14 +1424,21 @@ add_vars_for_offset (tree var, unsigned HOST_WIDE_INT offset,
subvar_t sv;
unsigned int i;
- if (SFT_IN_NESTED_STRUCT (var))
+ if (full_ref
+ && SFT_NESTING_LEVEL (var) > 0
+ && ref_nesting_level (full_ref) < SFT_NESTING_LEVEL (var))
{
/* Since VAR is an SFT inside a nested structure, the OFFSET
computed by get_ref_base_and_extent is the offset from the
- start of the immediately containing structure. However, to
- find out what other SFTs are affected by this reference, we
- need to know the offsets starting at the root structure in
- the nesting hierarchy.
+ start of the immediately containing structure. If VAR is an
+ SFT inside a nested structure, then FULL_REF may be a
+ reference to the structure immediately enclosing SFT, and so
+ OFFSET will be the offset from the start of the immediately
+ enclosing structure.
+
+ However, to find out what other SFTs are affected by this
+ reference, we need to know the offsets starting at the root
+ structure in the nesting hierarchy.
For instance, given the following structure:
@@ -1541,7 +1575,7 @@ add_virtual_operand (tree var, stmt_ann_t s_ann, int flags,
if it is a potential points-to location. */
if (TREE_CODE (al) == STRUCT_FIELD_TAG
&& TREE_CODE (var) == NAME_MEMORY_TAG)
- none_added &= !add_vars_for_offset (al, offset, size,
+ none_added &= !add_vars_for_offset (full_ref, al, offset, size,
flags & opf_def);
else
{
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index 2d3a40a8731..479145ab6e9 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -253,15 +253,6 @@ struct variable_info
variable. This is used for C++ placement new. */
unsigned int no_tbaa_pruning : 1;
- /* True if this variable is inside a structure nested in the
- structure for the base variable. For instance, in
- struct X { int a; struct Y { int b; int c; } }, the variables for
- fields 'b' and 'c' are inside a nested structure. We are not
- interested in tracking how many levels of nesting, just whether
- there is nesting at all. This is later used to adjust offsets
- for pointers pointing into sub-structures. */
- unsigned int in_nested_struct : 1;
-
/* Points-to set for this variable. */
bitmap solution;
@@ -4050,19 +4041,28 @@ sort_fieldstack (VEC(fieldoff_s,heap) *fieldstack)
fieldoff_compare);
}
-/* Given a TYPE, and a vector of field offsets FIELDSTACK, push all the fields
- of TYPE onto fieldstack, recording their offsets along the way.
- OFFSET is used to keep track of the offset in this entire structure, rather
- than just the immediately containing structure. Returns the number
- of fields pushed.
+/* Given a TYPE, and a vector of field offsets FIELDSTACK, push all
+ the fields of TYPE onto fieldstack, recording their offsets along
+ the way.
+
+ OFFSET is used to keep track of the offset in this entire
+ structure, rather than just the immediately containing structure.
+ Returns the number of fields pushed.
+
HAS_UNION is set to true if we find a union type as a field of
- TYPE. ADDRESSABLE_TYPE is the type of the outermost object that could have
- its address taken. */
+ TYPE.
+
+ ADDRESSABLE_TYPE is the type of the outermost object that could
+ have its address taken.
+
+ NESTING_LEVEL indicates whether TYPE is a structure nested inside
+ another, it starts at 0 and it is incremented by one on every
+ structure recursed into. */
int
push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
HOST_WIDE_INT offset, bool *has_union,
- tree addressable_type)
+ tree addressable_type, unsigned nesting_level)
{
tree field;
int count = 0;
@@ -4119,11 +4119,14 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
if (!AGGREGATE_TYPE_P (TREE_TYPE (type))) /* var_can_have_subvars */
push = true;
else if (!(pushed = push_fields_onto_fieldstack
- (TREE_TYPE (type), fieldstack,
- offset + i * TREE_INT_CST_LOW (elsz), has_union,
+ (TREE_TYPE (type),
+ fieldstack,
+ offset + i * TREE_INT_CST_LOW (elsz),
+ has_union,
(TYPE_NONALIASED_COMPONENT (type)
? addressable_type
- : TREE_TYPE (type)))))
+ : TREE_TYPE (type)),
+ nesting_level + 1)))
/* Empty structures may have actual size, like in C++. So
see if we didn't push any subfields and the size is
nonzero, push the field onto the stack */
@@ -4142,12 +4145,7 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
pair->alias_set = get_alias_set (addressable_type);
else
pair->alias_set = -1;
-
- /* If the base offset is positive, this field belongs to
- a structure nested inside the base structure. */
- if (offset > 0)
- pair->in_nested_struct = true;
-
+ pair->nesting_level = nesting_level;
count++;
}
else
@@ -4171,11 +4169,14 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
if (!var_can_have_subvars (field))
push = true;
else if (!(pushed = push_fields_onto_fieldstack
- (TREE_TYPE (field), fieldstack,
- offset + bitpos_of_field (field), has_union,
+ (TREE_TYPE (field),
+ fieldstack,
+ offset + bitpos_of_field (field),
+ has_union,
(DECL_NONADDRESSABLE_P (field)
? addressable_type
- : TREE_TYPE (field))))
+ : TREE_TYPE (field)),
+ nesting_level + 1))
&& DECL_SIZE (field)
&& !integer_zerop (DECL_SIZE (field)))
/* Empty structures may have actual size, like in C++. So
@@ -4196,12 +4197,7 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
pair->alias_set = get_alias_set (addressable_type);
else
pair->alias_set = -1;
-
- /* If the base offset is positive, this field belongs to
- a structure nested inside the base structure. */
- if (offset > 0)
- pair->in_nested_struct = true;
-
+ pair->nesting_level = nesting_level;
count++;
}
else
@@ -4401,7 +4397,7 @@ create_variable_info_for (tree decl, const char *name)
if (var_can_have_subvars (decl) && use_field_sensitive && !hasunion)
{
push_fields_onto_fieldstack (decltype, &fieldstack, 0, &hasunion,
- decltype);
+ decltype, 0);
if (hasunion)
{
VEC_free (fieldoff_s, heap, fieldstack);
@@ -4512,7 +4508,6 @@ create_variable_info_for (tree decl, const char *name)
newvi->offset = fo->offset;
newvi->size = TREE_INT_CST_LOW (fo->size);
newvi->fullsize = vi->fullsize;
- newvi->in_nested_struct = fo->in_nested_struct;
insert_into_field_list (vi, newvi);
VEC_safe_push (varinfo_t, heap, varmap, newvi);
if (is_global && (!flag_whole_program || !in_ipa_mode))
@@ -4764,8 +4759,20 @@ set_uids_in_ptset (tree ptr, bitmap into, bitmap from, bool is_derefed,
if (no_tbaa_pruning
|| (!is_derefed && !vi->directly_dereferenced)
|| alias_sets_conflict_p (ptr_alias_set, var_alias_set))
- bitmap_set_bit (into, DECL_UID (sft));
- SFT_IN_NESTED_STRUCT (sft) = vi->in_nested_struct;
+ {
+ bitmap_set_bit (into, DECL_UID (sft));
+
+ /* If SFT is inside a nested structure, it will
+ be needed by the operand scanner to adjust
+ offsets when adding operands to memory
+ expressions that dereference PTR. This means
+ that memory partitioning may not partition
+ this SFT because the operand scanner will not
+ be able to find the other SFTs next to this
+ one. */
+ if (SFT_NESTING_LEVEL (sft) > 0)
+ SFT_UNPARTITIONABLE_P (sft) = true;
+ }
}
}
else
diff --git a/gcc/tree.h b/gcc/tree.h
index decc05dc3c3..00b193fd77f 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2555,10 +2555,10 @@ struct tree_memory_tag GTY(())
bitmap GTY ((skip)) aliases;
/* True if this tag has global scope. */
- unsigned int is_global:1;
+ unsigned int is_global : 1;
- /* True if this SFT is for a field in a nested structure. */
- unsigned int in_nested_struct : 1;
+ /* True if this tag should not be grouped into a memory partition. */
+ unsigned int unpartitionable : 1;
};
#define MTAG_GLOBAL(NODE) (TREE_MEMORY_TAG_CHECK (NODE)->mtag.is_global)
@@ -2579,6 +2579,11 @@ struct tree_struct_field_tag GTY(())
/* Alias set for a DECL_NONADDRESSABLE_P field. Otherwise -1. */
alias_set_type alias_set;
+
+ /* Nesting level for this subvariable. This indicates how many
+ structures are wrapping this field. Fields at the top level have
+ a nesting level of 0. */
+ unsigned int nesting_level;
};
#define SFT_PARENT_VAR(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.parent_var)
@@ -2587,8 +2592,10 @@ struct tree_struct_field_tag GTY(())
#define SFT_NONADDRESSABLE_P(NODE) \
(STRUCT_FIELD_TAG_CHECK (NODE)->sft.alias_set != -1)
#define SFT_ALIAS_SET(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.alias_set)
-#define SFT_IN_NESTED_STRUCT(NODE) \
- (STRUCT_FIELD_TAG_CHECK (NODE)->sft.common.in_nested_struct)
+#define SFT_NESTING_LEVEL(NODE) \
+ (STRUCT_FIELD_TAG_CHECK (NODE)->sft.nesting_level)
+#define SFT_UNPARTITIONABLE_P(NODE) \
+ (STRUCT_FIELD_TAG_CHECK (NODE)->sft.common.unpartitionable)
/* Memory Partition Tags (MPTs) group memory symbols under one
common name for the purposes of placing memory PHI nodes. */