2010-01-05  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/42614
	* tree-ssa-alias.c (compute_flow_insensitive_aliasing):
	Compute SMT aliases before symbol aliases.

	* gcc.c-torture/execute/pr42614.c: New testcase.

Index: gcc/tree-ssa-alias.c
===================================================================
--- gcc/tree-ssa-alias.c.orig	2010-01-11 14:26:24.000000000 +0100
+++ gcc/tree-ssa-alias.c	2010-01-11 14:28:02.000000000 +0100
@@ -2484,48 +2484,6 @@ compute_flow_insensitive_aliasing (struc
   size_t i;
 
   timevar_push (TV_FLOW_INSENSITIVE);
-  /* For every pointer P, determine which addressable variables may alias
-     with P's symbol memory tag.  */
-  for (i = 0; i < ai->num_pointers; i++)
-    {
-      size_t j;
-      struct alias_map_d *p_map = ai->pointers[i];
-      tree tag = symbol_mem_tag (p_map->var);
-      tree var;
-
-      for (j = 0; j < ai->num_addressable_vars; j++)
-	{
-	  struct alias_map_d *v_map;
-	  var_ann_t v_ann;
-	  tree alias_var;
-	  
-	  v_map = ai->addressable_vars[j];
-	  var = v_map->var;
-	  v_ann = var_ann (var);
-
-	  /* We used to skip variables that have never been written to
-	     if the memory tag has been never written to directly (or
-	     either of them were call clobbered).  This is not enough
-	     though, as this misses writes through the tags aliases.
-	     So, for correctness we need to include any aliased
-	     variable here.  */
-
-	  /* For the may_alias_p query we have to use the parent variable.  */
-	  alias_var = (TREE_CODE (var) == STRUCT_FIELD_TAG
-		       ? SFT_PARENT_VAR (var) : var);
-	  if (may_alias_p (p_map->var, p_map->set,
-			   alias_var, get_alias_set (alias_var), false))
-	    {
-	      /* We should never have a var with subvars here, because
-	         they shouldn't get into the set of addressable vars */
-	      gcc_assert (!var_can_have_subvars (var)
-			  || get_subvars_for_var (var) == NULL);
-
-	      /* Add VAR to TAG's may-aliases set.  */
-	      add_may_alias (tag, var);
-	    }
-	}
-    }
 
   /* Since this analysis is based exclusively on symbols, it fails to
      handle cases where two pointers P and Q have different memory
@@ -2546,7 +2504,11 @@ compute_flow_insensitive_aliasing (struc
 
      To avoid this problem, we do a final traversal of AI->POINTERS
      looking for pairs of pointers that have no aliased symbols in
-     common and yet have conflicting alias set numbers.  */
+     common and yet have conflicting alias set numbers.
+
+     Note this has to be done first as we only can avoid adding
+     aliases for common memory tag aliases, not for common symbol
+     aliases as they might get pruned by the operand scanner later.  */
   for (i = 0; i < ai->num_pointers; i++)
     {
       size_t j;
@@ -2577,6 +2539,49 @@ compute_flow_insensitive_aliasing (struc
 	}
     }
 
+  /* For every pointer P, determine which addressable variables may alias
+     with P's symbol memory tag.  */
+  for (i = 0; i < ai->num_pointers; i++)
+    {
+      size_t j;
+      struct alias_map_d *p_map = ai->pointers[i];
+      tree tag = symbol_mem_tag (p_map->var);
+      tree var;
+
+      for (j = 0; j < ai->num_addressable_vars; j++)
+	{
+	  struct alias_map_d *v_map;
+	  var_ann_t v_ann;
+	  tree alias_var;
+	  
+	  v_map = ai->addressable_vars[j];
+	  var = v_map->var;
+	  v_ann = var_ann (var);
+
+	  /* We used to skip variables that have never been written to
+	     if the memory tag has been never written to directly (or
+	     either of them were call clobbered).  This is not enough
+	     though, as this misses writes through the tags aliases.
+	     So, for correctness we need to include any aliased
+	     variable here.  */
+
+	  /* For the may_alias_p query we have to use the parent variable.  */
+	  alias_var = (TREE_CODE (var) == STRUCT_FIELD_TAG
+		       ? SFT_PARENT_VAR (var) : var);
+	  if (may_alias_p (p_map->var, p_map->set,
+			   alias_var, get_alias_set (alias_var), false))
+	    {
+	      /* We should never have a var with subvars here, because
+	         they shouldn't get into the set of addressable vars */
+	      gcc_assert (!var_can_have_subvars (var)
+			  || get_subvars_for_var (var) == NULL);
+
+	      /* Add VAR to TAG's may-aliases set.  */
+	      add_may_alias (tag, var);
+	    }
+	}
+    }
+
   /* We have to add all HEAP variables to all SMTs aliases bitmaps.
      As we don't know which effective type the HEAP will have we cannot
      do better here and we need the conflicts with obfuscated pointers
Index: gcc/testsuite/gcc.c-torture/execute/pr42614.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/gcc.c-torture/execute/pr42614.c	2010-01-11 14:26:24.000000000 +0100
@@ -0,0 +1,68 @@
+extern void *malloc(__SIZE_TYPE__);
+extern void abort(void);
+extern void free(void *);
+
+typedef struct SEntry
+{
+  unsigned char num;
+} TEntry;
+
+typedef struct STable
+{
+  TEntry data[2];
+} TTable;
+
+TTable *init ()
+{
+  return malloc(sizeof(TTable));
+}
+
+void
+expect_func (int a, unsigned char *b) __attribute__ ((noinline));
+
+static inline void
+inlined_wrong (TEntry *entry_p, int flag);
+
+void
+inlined_wrong (TEntry *entry_p, int flag)
+{
+  unsigned char index;
+  entry_p->num = 0;
+
+  if (flag == 0)
+    abort();
+
+  for (index = 0; index < 1; index++)
+    entry_p->num++;
+
+  if (!entry_p->num)
+    {
+      abort();
+    }
+}
+
+void
+expect_func (int a, unsigned char *b)
+{
+  if (abs ((a == 0)))
+    abort ();
+  if (abs ((b == 0)))
+    abort ();
+}
+
+int
+main ()
+{
+  unsigned char index = 0;
+  TTable *table_p = init();
+  TEntry work;
+
+  inlined_wrong (&(table_p->data[1]), 1);
+  expect_func (1, &index);
+  inlined_wrong (&work, 1);
+
+  free (table_p);
+
+  return 0;
+}
+
