diff options
author | dnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-11-13 15:20:40 +0000 |
---|---|---|
committer | dnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-11-13 15:20:40 +0000 |
commit | 18346ecd861dc66e71dafe48ff216cfa4dc95a21 (patch) | |
tree | b04ec56bade931807b6ed40c6d251c05aa588f0b | |
parent | 62e369b3a7e2a62037d4b22f55f96530b76bb9f8 (diff) | |
download | gcc-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/ChangeLog | 39 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/execute/pr33870-1.c | 94 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/alias-16.c | 33 | ||||
-rw-r--r-- | gcc/tree-dfa.c | 13 | ||||
-rw-r--r-- | gcc/tree-flow.h | 10 | ||||
-rw-r--r-- | gcc/tree-ssa-alias.c | 36 | ||||
-rw-r--r-- | gcc/tree-ssa-operands.c | 52 | ||||
-rw-r--r-- | gcc/tree-ssa-structalias.c | 85 | ||||
-rw-r--r-- | gcc/tree.h | 17 |
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. */ |