This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Fix PR 33870


Richard Guenther wrote:

taking the address of result.x.pDirty causes the SFT to be marked as
in substructure and the problem re-surfaces.

Yes. Thanks for the test case. The original patch did not take into account that the nesting level of the memory reference is also important.


There are two problems here:

1- Given an arbitrary memory expression M dereferencing a pointer P into a nested structure, the offset computed for M is the offset starting at P. However, the offsets computed for the original SFTs are offsets from the top of the pointed-to memory object O. So, when we recognize this situation, we must adjust the offsets. This was the situation recognized and fixed by the original patch.

The bug was in the detection of whether P is "pointing to the middle of an object". This is where the nesting level comes in to play. Suppose that M was the expression p_3->b[3] and the original pointed-to object was v.x.y:

		struct {
			...
			struct {
				...
				struct {
					...
					int b[4];
				} y;
			} x;
		} v;

p_3 = &v.x.y;

If alias analysis created SFTs for this structure, the array 'b' will have 4 SFTs associated with it. Say SFT.12, SFT.13, SFT.14 and SFT.15. However, only SFT.12 will be added to the alias set of p_3's name tag.

So, when we see the expression 'p_3->b[3]', we compute an offset of 96, but we need SFT.14 which will probably have an offset much higher than that. So, we adjust 96 by the offset of SFT.12 and get to SFT.14.

In the original patch, we recognized this situation by asking whether the SFT.12 was inside a nested structure. However, it may happen that the pointer was actually pointing to the base of the original object 'v'. In which case, we would have the expression 'p_3->x.y.b[3]', which also takes us to SFT.12.

But in this case, the offset we computed from 'p_3->x.y.b[3]' is *already* the right offset, so adding the offset of SFT.12 to it gives us the wrong offset. So, what this patch does is determine the nesting level of each SFT and the nesting level of the memory expression. We only need to adjust the offset of an SFT if the nesting level of the memory expression is lower than the nesting level of the SFT that we are analyzing.


2- The second problem we have with this scheme is that we rely on the presence of key SFTs to adjust offsets when we detect references to nested aggregates. This is something we cannot easily undo because inside the operand scanner we cannot really start doing use-def chain chasing to determine the original pointed-to objects. This work has already been done by alias analysis, so duplicating this in the operand scanner would be wasteful.


This means that this scheme cannot tolerate these key SFTs to be partitioned away. If they are partitioned, then inside the operand scanner is essentially impossible to determine where in the structure is an arbitrary memory expression referring to. This is shown in the new test gcc.dg/tree-ssa/alias-16.c.

One way to deal with this would be to use the pointed-to set for the base pointer instead of the alias set of the name tag. This has the problem that we'd miss the compile-time benefits of partitioning, as we would be traversing the original sets instead of the partitioned (smaller) alias sets. Also, we may want to get rid of the duplicate pointed-to/alias sets in the future (not sure if they're both worth keeping).

The other way of dealing with this is to recognize which SFTs are important to not partition and make sure they are never partitioned. During alias analysis, if a nested SFT is added to the alias set of a pointer, then it is marked as unpartitionable. The partitioner, in turn, gives these SFTs a very high score and makes sure that they are never added to a partition. The effects of this are/should be negligible as it only involves a single SFT and nested structures.

The new test alias-16.c tests for these edge cases.

Tested on x86_64 and ppc64. Committed to trunk.


Diego.
2007-11-12  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.

testsuite/ChangeLog
	
	PR 33870
	* gcc.c-torture/execute/pr33870-1.c: New test.
	* gcc.dg/tree-ssa/alias-16.c: New test.

Index: tree.h
===================================================================
--- tree.h	(revision 130139)
+++ tree.h	(working copy)
@@ -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.  */
Index: testsuite/gcc.c-torture/execute/pr33870-1.c
===================================================================
--- testsuite/gcc.c-torture/execute/pr33870-1.c	(revision 0)
+++ testsuite/gcc.c-torture/execute/pr33870-1.c	(revision 0)
@@ -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;
+}
Index: testsuite/gcc.dg/tree-ssa/alias-16.c
===================================================================
--- testsuite/gcc.dg/tree-ssa/alias-16.c	(revision 0)
+++ testsuite/gcc.dg/tree-ssa/alias-16.c	(revision 0)
@@ -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: tree-ssa-alias.c
===================================================================
--- tree-ssa-alias.c	(revision 130139)
+++ tree-ssa-alias.c	(working copy)
@@ -828,6 +828,13 @@ count_mem_refs (long *num_vuses_p, long 
 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_
 
 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, unsign
   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;
Index: tree-dfa.c
===================================================================
--- tree-dfa.c	(revision 130139)
+++ tree-dfa.c	(working copy)
@@ -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");
Index: tree-flow.h
===================================================================
--- tree-flow.h	(revision 130139)
+++ tree-flow.h	(working copy)
@@ -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);
Index: tree-ssa-structalias.c
===================================================================
--- tree-ssa-structalias.c	(revision 130139)
+++ tree-ssa-structalias.c	(working copy)
@@ -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) *f
 	 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, 
 	  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, 
 		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, 
 	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, 
 	      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, con
   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, con
 	  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
 		  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
Index: tree-ssa-operands.c
===================================================================
--- tree-ssa-operands.c	(revision 130139)
+++ tree-ssa-operands.c	(working copy)
@@ -1367,8 +1367,33 @@ access_can_touch_variable (tree ref, tre
   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, tre
    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 
   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_
 	     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
 	    {

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]