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]

Don't consider &PTR->FLD a dereference of PTR


VRP was wrongly considering a pointer to be non-NULL in this test
case from Jeff.  We were blindly counting all pointer
dereferences, even those inside ADDR_EXPRs.  Those are not
dereference, but offset computations.

There is a wrinkle, however.  If the only references to a pointer
P are inside &P->FLD, and we end up propagating that expression,
the original alias pass will not have considered P as
dereferenced and so P will be without memory tags.  This leads to
DCE removing dereferences of P after we propagate &P->FLD to
dereference sites.

Bootstrapped and tested x86, x86-64, ppc64 and ia64.



	* tree-ssa-alias.c (count_ptr_derefs): Do not consider
	&PTR->FLD a dereference of PTR.
	* tree-ssa-structalias.c (update_alias_info): Consider &PTR->FLD
	a potential dereference of PTR.

testsuite/ChangeLog

	* gcc.dg/tree-ssa/20050719-1.c: New test.

Index: tree-ssa-alias.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-alias.c,v
retrieving revision 2.105
diff -d -u -p -r2.105 tree-ssa-alias.c
--- tree-ssa-alias.c	19 Jul 2005 03:36:13 -0000	2.105
+++ tree-ssa-alias.c	21 Jul 2005 20:41:53 -0000
@@ -344,12 +344,20 @@ struct count_ptr_d
    (ALIGN/MISALIGNED_)INDIRECT_REF nodes for the pointer passed in DATA.  */
 
 static tree
-count_ptr_derefs (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
+count_ptr_derefs (tree *tp, int *walk_subtrees, void *data)
 {
   struct count_ptr_d *count_p = (struct count_ptr_d *) data;
 
+  /* Do not walk inside ADDR_EXPR nodes.  In the expression &ptr->fld,
+     pointer 'ptr' is *not* dereferenced, it is simply used to compute
+     the address of 'fld' as 'ptr + offsetof(fld)'.  */
+  if (TREE_CODE (*tp) == ADDR_EXPR)
+    {
+      *walk_subtrees = 0;
+      return NULL_TREE;
+    }
+
   if (INDIRECT_REF_P (*tp) && TREE_OPERAND (*tp, 0) == count_p->ptr)
-/*       || (TREE_CODE (*tp) == MEM_REF && MEM_REF_SYMBOL (*tp) == count_p->ptr)) */
     count_p->count++;
 
   return NULL_TREE;
Index: tree-ssa-structalias.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-structalias.c,v
retrieving revision 2.21
diff -d -u -p -r2.21 tree-ssa-structalias.c
--- tree-ssa-structalias.c	16 Jul 2005 22:27:21 -0000	2.21
+++ tree-ssa-structalias.c	21 Jul 2005 20:41:54 -0000
@@ -2550,7 +2550,7 @@ update_alias_info (tree stmt, struct ali
       tree op, var;
       var_ann_t v_ann;
       struct ptr_info_def *pi;
-      bool is_store;
+      bool is_store, is_potential_deref;
       unsigned num_uses, num_derefs;
 
       op = USE_FROM_PTR (use_p);
@@ -2607,7 +2607,42 @@ update_alias_info (tree stmt, struct ali
 	 is an escape point, whether OP escapes.  */
       count_uses_and_derefs (op, stmt, &num_uses, &num_derefs, &is_store);
 
-      if (num_derefs > 0)
+      /* Handle a corner case involving address expressions of the
+	 form '&PTR->FLD'.  The problem with these expressions is that
+	 they do not represent a dereference of PTR.  However, if some
+	 other transformation propagates them into an INDIRECT_REF
+	 expression, we end up with '*(&PTR->FLD)' which is folded
+	 into 'PTR->FLD'.
+
+	 So, if the original code had no other dereferences of PTR,
+	 the aliaser will not create memory tags for it, and when
+	 &PTR->FLD gets propagated to INDIRECT_REF expressions, the
+	 memory operations will receive no V_MAY_DEF/VUSE operands.
+
+	 One solution would be to have count_uses_and_derefs consider
+	 &PTR->FLD a dereference of PTR.  But that is wrong, since it
+	 is not really a dereference but an offset calculation.
+
+	 What we do here is to recognize these special ADDR_EXPR
+	 nodes.  Since these expressions are never GIMPLE values (they
+	 are not GIMPLE invariants), they can only appear on the RHS
+	 of an assignment and their base address is always an
+	 INDIRECT_REF expression.  */
+      is_potential_deref = false;
+      if (TREE_CODE (stmt) == MODIFY_EXPR
+	  && TREE_CODE (TREE_OPERAND (stmt, 1)) == ADDR_EXPR
+	  && !is_gimple_val (TREE_OPERAND (stmt, 1)))
+	{
+	  /* If the RHS if of the form &PTR->FLD and PTR == OP, then
+	     this represents a potential dereference of PTR.  */
+	  tree rhs = TREE_OPERAND (stmt, 1);
+	  tree base = get_base_address (TREE_OPERAND (rhs, 0));
+	  if (TREE_CODE (base) == INDIRECT_REF
+	      && TREE_OPERAND (base, 0) == op)
+	    is_potential_deref = true;
+	}
+
+      if (num_derefs > 0 || is_potential_deref)
 	{
 	  /* Mark OP as dereferenced.  In a subsequent pass,
 	     dereferenced pointers that point to a set of
Index: testsuite/gcc.dg/tree-ssa/20050719-1.c
===================================================================
RCS file: testsuite/gcc.dg/tree-ssa/20050719-1.c
diff -N testsuite/gcc.dg/tree-ssa/20050719-1.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/tree-ssa/20050719-1.c	21 Jul 2005 20:41:56 -0000
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+extern void abort (void) __attribute__ ((__nothrow__)) __attribute__
+((__noreturn__));
+extern void exit (int __status) __attribute__ ((__nothrow__))
+__attribute__ ((__noreturn__));
+
+struct bootLoader {
+  int x;
+};
+
+void
+zap(struct bootLoader *bootLoader)
+{
+  /* The expression on the RHS of the assignment is *not* a
+     dereference of pointer 'bootLoader'.  It is merely used as an
+     offset calculation.  VRP was erroneously removing the if()
+     because it thought that 'bootLoader' was always dereferenced.  */
+  int *boot = &bootLoader->x;
+
+  if (bootLoader)
+    {
+      useboot (boot);
+    }
+}
+
+int
+useboot (void *boot)
+{
+  abort ();
+}
+
+main()
+{
+  zap (0);
+}


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