OSDN Git Service

pr 33870
authordnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 13 Nov 2007 15:20:40 +0000 (15:20 +0000)
committerdnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 13 Nov 2007 15:20:40 +0000 (15:20 +0000)
* 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

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/pr33870-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/alias-16.c [new file with mode: 0644]
gcc/tree-dfa.c
gcc/tree-flow.h
gcc/tree-ssa-alias.c
gcc/tree-ssa-operands.c
gcc/tree-ssa-structalias.c
gcc/tree.h

index 7dfb2ae..ffff6cc 100644 (file)
@@ -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
 2007-11-13  Victor Kaplansky  <victork@il.ibm.com>
 
        PR tree-optimization/32582
index 6bbbe33..a1166ec 100644 (file)
@@ -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
 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 (file)
index 0000000..af5a40d
--- /dev/null
@@ -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 (file)
index 0000000..cf10fa9
--- /dev/null
@@ -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;
+}
index 4880e83..65a32d9 100644 (file)
@@ -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);
   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, "}");
     }
 
   fprintf (file, "}");
@@ -417,6 +419,15 @@ dump_variable (FILE *file, tree var)
          fprintf (file, ", partition symbols: ");
          dump_decl_set (file, MPT_SYMBOLS (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");
     }
 
   fprintf (file, "\n");
index 02e9543..8376195 100644 (file)
@@ -1159,9 +1159,9 @@ struct fieldoff
   /* Field.  */
   tree decl;
 
   /* 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;  
 
   /* 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);
 
 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);
 void sort_fieldstack (VEC(fieldoff_s,heap) *);
 
 void init_alias_heapvars (void);
index f2e3064..31e04bc 100644 (file)
@@ -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)
 {
 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
   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,
 
 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;
 {
   tree var;
   referenced_var_iterator rvi;
@@ -1591,6 +1598,15 @@ compute_memory_partitions (void)
       if (!need_to_partition_p (mem_ref_stats))
        break;
 
       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);
     }
       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,
 
 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");
 
 {
   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_OFFSET (subvar) = offset;
   SFT_SIZE (subvar) = size;
   SFT_ALIAS_SET (subvar) = alias_set;
+  SFT_NESTING_LEVEL (subvar) = nesting_level;
+
   return subvar;
 }
 
   return subvar;
 }
 
@@ -3814,7 +3833,7 @@ create_overlap_variables_for (tree var)
     return;
 
   push_fields_onto_fieldstack (TREE_TYPE (var), &fieldstack, 0, NULL,
     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;
   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.  */
             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)
          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;
                  && 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)
          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));
                       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;
            }
          
          lastfotype = currfotype;
index 87eec74..cd8ade6 100644 (file)
@@ -1367,8 +1367,33 @@ access_can_touch_variable (tree ref, tree alias, HOST_WIDE_INT offset,
   return true;
 }
 
   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
 /* 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.
    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
    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
 
 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;
                     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;
 
   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
     {
       /* 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:
 
 
         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)
             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
            {
                                                flags & opf_def);
          else
            {
index 2d3a40a..479145a 100644 (file)
@@ -253,15 +253,6 @@ struct variable_info
      variable.  This is used for C++ placement new.  */
   unsigned int no_tbaa_pruning : 1;
 
      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;
 
   /* Points-to set for this variable.  */
   bitmap solution;
 
@@ -4050,19 +4041,28 @@ sort_fieldstack (VEC(fieldoff_s,heap) *fieldstack)
         fieldoff_compare);
 }
 
         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
    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,
 
 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;
 {
   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
          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
                      (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 */
            /* 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;
                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
              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
        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
                    (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
                 && 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;
              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
            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,
   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);
       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->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))
          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))
                  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
                }
            }
          else
index decc05d..00b193f 100644 (file)
@@ -2555,10 +2555,10 @@ struct tree_memory_tag GTY(())
   bitmap GTY ((skip)) aliases;
 
   /* True if this tag has global scope.  */
   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)
 };
 
 #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;
 
   /* 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)
 };
 
 #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_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.  */
 
 /* Memory Partition Tags (MPTs) group memory symbols under one
    common name for the purposes of placing memory PHI nodes.  */