[tree-ssa] DCE and aliasing fixes [patch]

Diego Novillo dnovillo@redhat.com
Mon Feb 3 03:55:00 GMT 2003


This patch fixes enough bugs in DCE and aliasing that we can now
at least enable -ftree-dce when running the testsuite.  We still
can't bootstrap with DCE enabled.  We reach stage2 and fail when
the stage2 compiler miscompiles genrecog.

The main changes are:

- When the compiler finds a call to a pure or const function, it
  should consider that any pointer passed to the function will be
  dereferenced.  This is to address the following problem: Suppose
  that function 'foo' is constant but receives a pointer to a
  local variable:

	    int foo (int *x)
	    {
	      return *x;
	    }

	    int bar()
	    {
	      i = 10;
	      p = &i;
	      return foo (p);
	    }

  Since p has never been dereferenced in function bar(), the
  alias analyzer will never associate 'i' with '*p', which then
  causes DCE to kill the assignment to 'i' because it's never
  used in bar(). To address this problem, we add a VUSE<*p> at
  the call site of foo().


- Handle aliases to fields inside a structure.  Suppose that we
  are dealing with the following code:

	    1	struct elem
	    2	{
	    3	  float x;
	    4	};
	    5	
	    6	struct list
	    7	{
	    8	  struct elem *next;
	    9	};
	    10	
	    11	float foo (struct list *p)
	    12	{
	    13	  struct elem *q;
	    14	  ...
	    15	  q = p->next;
	    16	  q->x = 5;
	    17	  return p->next->x;
	    18	}

  '*q' and '*p' have nonconflicting alias sets because '*q' is of
  type 'struct elem'.  However, it is possible to access '*p' via
  '*q' because '*p' does have a conflicting alias set with
  'struct elem *'.  Therefore, we also need to check for
  conflicts between '*p' and 'q'.

- Alias tags should alias themselves, otherwise when the code
  makes a direct reference to them, they are considered real
  uses.  For instance, suppose that '*p' is the alias tag for 'i' and 'j':

		  1	i = ...
		  2	*p = ...
		  3	... = i

  If '*p' is not made an alias of itself, then the assignment at
  line 2 will be considered a killing definition of '*p'.  This
  would make the assignment to 'i' at line 1 appear dead because
  the use of 'i' at line 3 is now reached by the assignment to
  '*p' at line 2.

  If '*p' does not alias 'i' at runtime, the compiler would've
  generated wrong code.  This fixes the regression of
  gcc.c-torture/execute/950929-1.c.

- There are some minor changes to the aliasing code, some code
  factoring and macros renamed (SSA_NAME_DECL is now
  SSA_NAME_VAR).

- DCE was not considering CALL_EXPRs to be implicitly live.


These are the new regressions that you will see now that
-ftree-dce is enabled in the testsuite:

         FAIL: gcc.c-torture/execute/20000603-1.c execution
         FAIL: gcc.c-torture/execute/20010209-1.c execution
         FAIL: gcc.c-torture/execute/20020412-1.c execution
         FAIL: gcc.c-torture/execute/921017-1.c execution

All of them, except 20000603-1.c are due to variable length
arrays.  The problem here is that VLAs use variables inside the
declaration itself and the dataflow routines never look at
declarations, only executable statements.  Therefore, DCE
considers those variables dead because it doesn't see their uses.
To fix this we need the gimplifier to expose the semantics of
VLAs in the code.

The failure for 20000603-1.c occurs only when inlining.  The
problem is with our aliasing code, but I still haven't found out
exactly what's failing.

Bootstrapped and tested on x86.


Diego.

	* tree-dfa.c (get_expr_operands): Add a VUSE for the dereference of
	every pointer passed in a function call.
	Move code to add an operand for the base pointer of an
	INDIRECT_REF ...
	(add_stmt_operand): ... here.
	Add a VUSE for the base pointer of every INDIRECT_REF variable.
	(find_may_aliases_for): Fix starting index for the loop that scans
	INDIRECT_REFs for aliasing.
	Factor code that marks two variables aliased into
	register_new_alias.
	(register_new_alias): New function.
	(may_alias_p): Handle aliasing of structure fields.
	(add_may_alias): Fix documentation.
	(find_vars_r): Factor code that adds a new referenced variable into
	add_referenced_var.
	(add_referenced_var): New function.
	(add_indirect_ref_var): New function.
	(get_virtual_var): Handle variables wrapped in SSA_NAMEs.
	(set_may_alias_global_mem): Move from ...
	* tree-flow-inline.h: ... here.

	* tree-ssa-dce.c (need_to_preserve_store): CALL_EXPRs are
	implicitly live.  VA_ARG_EXPRs are not.
	(stmt_useful_p):

	* tree.h (SSA_NAME_VAR): Rename from SSA_NAME_DECL.  Update all
	users.
	(struct tree_ssa_name): Rename field 'decl' to 'var'.  Update all
	users.
	(SSA_DECL_P): Accept only VAR_DECLs and PARM_DECLs possibly wrapped
	inside an SSA_NAME node.
	(SSA_VAR_P): Also accept SSA_NAME nodes.

testsuite/

	* lib/c-torture.exp (TORTURE_OPTIONS): Add -ftree-dce.

Index: tree-dfa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-dfa.c,v
retrieving revision 1.1.4.68
diff -d -u -p -r1.1.4.68 tree-dfa.c
--- tree-dfa.c	30 Jan 2003 21:37:49 -0000	1.1.4.68
+++ tree-dfa.c	3 Feb 2003 01:16:39 -0000
@@ -104,9 +104,13 @@ static void add_stmt_operand		PARAMS ((t
       						 voperands_t));
 static void add_immediate_use		PARAMS ((tree, tree));
 static tree find_vars_r			PARAMS ((tree *, int *, void *));
+static void add_referenced_var		PARAMS ((tree, void *));
+static void add_indirect_ref_var	PARAMS ((tree, void *));
 static void compute_immediate_uses_for	PARAMS ((tree, int));
 static void add_may_alias		PARAMS ((tree, tree));
 static bool call_may_clobber		PARAMS ((tree));
+static void register_new_alias		PARAMS ((tree, tree, HOST_WIDE_INT,
+						 tree, tree, HOST_WIDE_INT));
 
 
 /* Global declarations.  */
@@ -315,12 +319,6 @@ get_expr_operands (stmt, expr_p, is_def,
   if (SSA_VAR_P (expr))
     {
       add_stmt_operand (expr_p, stmt, is_def, false, prev_vops);
-
-      /* Pointer dereferences represent a VUSE of their base pointer.  */
-      if (TREE_CODE (expr) == INDIRECT_REF)
-	add_stmt_operand (&TREE_OPERAND (expr, 0), stmt, false, true,
-			  prev_vops);
-
       return;
     }
 
@@ -374,20 +372,59 @@ get_expr_operands (stmt, expr_p, is_def,
      *GLOBAL_VAR (See find_vars_r).  */
   if (code == CALL_EXPR)
     {
+      tree op;
+      bool may_clobber = call_may_clobber (expr);
+
       /* Find uses in the called function.  */
       get_expr_operands (stmt, &TREE_OPERAND (expr, 0), false, prev_vops);
 
-      /* If the called function is neither pure nor const, we create a
-	  clobbering definition of *GLOBAL_VAR.  */
-      if (call_may_clobber (expr))
+      if (may_clobber)
 	{
-	  tree v = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (global_var)),
-		      	   global_var);
+	  /* If the called function is neither pure nor const, we create a
+	     clobbering definition of *GLOBAL_VAR.  */
+	  tree v = indirect_ref (global_var);
 	  add_stmt_operand (&v, stmt, true, true, prev_vops);
 	}
 
-      /* Find uses for all the arguments to the function.  */
-      get_expr_operands (stmt, &TREE_OPERAND (expr, 1), 0, prev_vops);
+      /* Add all the arguments to the function.  If the function will not
+	 clobber any local variable, check if it may dereference a local
+	 pointer.  If so, add a VUSE for the dereferenced pointer.  This is
+	 to address the following problem: Supose that function 'foo' is
+	 constant but receives a pointer to a local variable:
+
+	    int foo (int *x)
+	    {
+	      return *x;
+	    }
+
+	    int bar()
+	    {
+	      i = 10;
+	      p = &i;
+	      return foo (p);
+	    }
+
+	 Since p has never been dereferenced in function bar(), the alias
+	 analyzer will never associate 'i' with '*p', which then causes DCE
+	 to kill the assignment to 'i' because it's never used in bar().
+	 To address this problem, we add a VUSE<*p> at the call site of
+	 foo().  */
+      for (op = TREE_OPERAND (expr, 1); op; op = TREE_CHAIN (op))
+	{
+	  tree arg = TREE_VALUE (op);
+
+	  add_stmt_operand (&TREE_VALUE (op), stmt, false, false, prev_vops);
+
+	  /* If the function may not clobber locals, add a VUSE<*p> for
+	     every pointer p passed in the argument list (see note above).  */
+	  if (!may_clobber
+	      && SSA_DECL_P (arg)
+	      && POINTER_TYPE_P (TREE_TYPE (arg)))
+	    {
+	      tree deref = indirect_ref (arg);
+	      add_stmt_operand (&deref, stmt, false, true, prev_vops);
+	    }
+	}
 
       return;
     }
@@ -539,7 +576,6 @@ add_stmt_operand (var_p, stmt, is_def, f
 	}
     }
 
-
   /* A definition of a pointer variable 'p' clobbers its associated
      indirect variable '*p', because now 'p' is pointing to a different
      memory location.  */
@@ -559,6 +595,18 @@ add_stmt_operand (var_p, stmt, is_def, f
 		  		    get_base_symbol (TREE_OPERAND (stmt, 1))))
 	set_may_alias_global_mem (deref);
     }
+
+
+  /* Pointer dereferences represent a VUSE of their base pointer.  If
+     needed, strip its SSA version, to access the base pointer.  Otherwise
+     we won't recognize use of pointers after variables have been renamed.
+     For instance, in (*p)_35, we need to add an operand for 'p', and for
+     that we need to remove the SSA version number first.  */
+  if (TREE_CODE (var) == SSA_NAME)
+    var = SSA_NAME_VAR (var);
+
+  if (TREE_CODE (var) == INDIRECT_REF)
+    add_stmt_operand (&TREE_OPERAND (var, 0), stmt, false, true, prev_vops);
 }
 
 
@@ -639,7 +687,7 @@ add_vdef (var, stmt, prev_vops)
       for (i = 0; i < VARRAY_ACTIVE_SIZE (prev_vops->vdef_ops); i++)
 	{
 	  tree d = VARRAY_TREE (prev_vops->vdef_ops, i);
-	  if (same_var_p (var, SSA_NAME_DECL (VDEF_RESULT (d))))
+	  if (same_var_p (var, SSA_NAME_VAR (VDEF_RESULT (d))))
 	    {
 	      vdef = d;
 	      break;
@@ -695,7 +743,7 @@ add_vuse (var, stmt, prev_vops)
       for (i = 0; i < VARRAY_ACTIVE_SIZE (prev_vops->vuse_ops); i++)
 	{
 	  tree u = VARRAY_TREE (prev_vops->vuse_ops, i);
-	  if (same_var_p (var, SSA_NAME_DECL (u)))
+	  if (same_var_p (var, SSA_NAME_VAR (u)))
 	    {
 	      vuse = u;
 	      break;
@@ -1528,7 +1576,43 @@ may_alias_p (v1, v1_base, v1_alias_set, 
 
   /* If the alias sets don't conflict then PTR cannot alias VAR.  */
   if (!alias_sets_conflict_p (ptr_alias_set, var_alias_set))
-    return false;
+    {
+      /* Handle aliases to structure fields.  If VAR is an INDIRECT_REF for
+	 a pointer type contained in another structure then PTR and VAR
+	 will not have conflicting alias sets, but PTR may have a conflict
+	 with VAR's base pointer.  Suppose that we are dealing with the
+	 following code:
+
+	    1	struct elem
+	    2	{
+	    3	  float x;
+	    4	};
+	    5	
+	    6	struct list
+	    7	{
+	    8	  struct elem *next;
+	    9	};
+	    10	
+	    11	float foo (struct list *p)
+	    12	{
+	    13	  struct elem *q;
+	    14	  ...
+	    15	  q = p->next;
+	    16	  q->x = 5;
+	    17	  return p->next->x;
+	    18	}
+
+	 '*q' and '*p' have nonconflicting alias sets because '*q' is of
+	 type 'struct elem'.  However, it is possible to access '*p' via
+	 '*q' because '*p' does have a conflicting alias set with
+	 'struct elem *'.  Therefore, we also need to check for conflicts
+	 between '*p' and 'q'.  */
+      if (TREE_CODE (var) == INDIRECT_REF
+	  && AGGREGATE_TYPE_P (TREE_TYPE (ptr)))
+	return alias_sets_conflict_p (ptr_alias_set, get_alias_set (var_sym));
+      else
+	return false;
+    }
 
   /* If -ftree-points-to is given, check if PTR may point to VAR.  */
   if (flag_tree_points_to)
@@ -1574,57 +1658,18 @@ find_may_aliases_for (indirect_ref_index
   /* Note that our aliasing properties are symmetric, so we can
      start this loop at INDIRECT_REF_INDEX + 1 to cut down on the
      runtime for this routine.  */
-  for (i = indirect_ref_index; i < num_indirect_refs; i++)
+  for (i = indirect_ref_index + 1; i < num_indirect_refs; i++)
     {
       tree v2 = VARRAY_TREE (indirect_refs, i);
       tree v2_base = VARRAY_TREE (indirect_refs_base, i);
       HOST_WIDE_INT v2_alias_set = VARRAY_INT (indirect_refs_alias_set, i);
 
-      if (v1 == v2)
-	continue;
-
       if (may_alias_p (v1, v1_base, v1_alias_set, v2, v2_base, v2_alias_set))
-	{
-	  tree at;
-
-	  if (flag_tree_points_to == PTA_NONE)
-	    {
-	      /* Since we are not doing points-to analysis, we aggregate
-		 all the aliases into a single representative alias that
-		 represents a group of variables with similar aliasing
-		 characteristics.  */
-	      at = find_alias_tag (v1, v1_base, v1_alias_set,
-			      	   v2, v2_base, v2_alias_set);
-	      if (at == NULL_TREE)
-		{
-		  at = v1;
-		  alias_tags [num_alias_tags].alias_tags = v1;
-		  alias_tags [num_alias_tags].base_symbol = v1_base;
-		  alias_tags [num_alias_tags].alias_set = v1_alias_set;
-		  num_alias_tags++;
-		}
-	      add_may_alias (v2, at);
-	    }
-	  else
-	    {
-	      /* With points-to analysis, we can add all the aliases we find
-		 for a variable because the alias sets are much smaller
-		 than what we get when doing type-based aliasing.  */
-	      at = v1;
-	      add_may_alias (v2, at);
-	      add_may_alias (at, v2);
-	    }
-
-	  /* If V2 may access global memory, mark both AT and V1 as aliases
-	     for global memory.  */
-	  if (may_access_global_mem (v2, v2_base))
-	    {
-	      set_may_alias_global_mem (at);
-	      set_may_alias_global_mem (v1);
-	    }
-	}
+	register_new_alias (v1, v1_base, v1_alias_set, v2, v2_base,
+			    v2_alias_set);
     }
 
+  /* Now check if V1 may alias any of the addressable variables.  */
   for (i = 0; i < num_addressable_vars; i++)
     {
       tree v2 = VARRAY_TREE (addressable_vars, i);
@@ -1635,46 +1680,91 @@ find_may_aliases_for (indirect_ref_index
 	continue;
 
       if (may_alias_p (v1, v1_base, v1_alias_set, v2, v2_base, v2_alias_set))
+	register_new_alias (v1, v1_base, v1_alias_set, v2, v2_base,
+			    v2_alias_set);
+    }
+}
+
+
+/* Establish an aliasing relation between V1 and V2.  If we are not doing
+   points-to analysis (-ftree-points-to is not set), this function will
+   aggregate aliases into a single alias set.  Otherwise, V1 and V2 will be
+   added to each other's alias sets.
+
+   The caller also provides the base symbol and alias set for V1 and V2 in
+   V1_BASE, V2_BASE, V1_ALIAS_SET and V2_ALIAS_SET.  */
+
+static void
+register_new_alias (v1, v1_base, v1_alias_set, v2, v2_base, v2_alias_set)
+     tree v1;
+     tree v1_base;
+     HOST_WIDE_INT v1_alias_set;
+     tree v2;
+     tree v2_base;
+     HOST_WIDE_INT v2_alias_set;
+{
+  tree at;
+
+  if (flag_tree_points_to == PTA_NONE)
+    {
+      /* Since we are not doing points-to analysis, we aggregate
+         all the aliases into a single representative alias that
+         represents a group of variables with similar aliasing
+         characteristics.  */
+      at = find_alias_tag (v1, v1_base, v1_alias_set,
+			   v2, v2_base, v2_alias_set);
+      if (at == NULL_TREE)
 	{
-	  tree at;
+	  at = v1;
+	  alias_tags[num_alias_tags].alias_tags = v1;
+	  alias_tags[num_alias_tags].base_symbol = v1_base;
+	  alias_tags[num_alias_tags].alias_set = v1_alias_set;
+	  num_alias_tags++;
 
-	  if (flag_tree_points_to == PTA_NONE)
-	    {
-	      /* Since we are not doing points-to analysis, we aggregate
-		 all the aliases into a single representative alias that
-		 represents a group of variables with similar aliasing
-		 characteristics.  */
-	      at = find_alias_tag (v1, v1_base, v1_alias_set,	
-				   v2, v2_base, v2_alias_set);
-	      if (at == NULL_TREE)
-		{
-		  at = v1;
-		  alias_tags [num_alias_tags].alias_tags = v1;
-		  alias_tags [num_alias_tags].base_symbol = v1_base;
-		  alias_tags [num_alias_tags].alias_set = v1_alias_set;
-		  num_alias_tags++;
-		}
-	      add_may_alias (v2, at);
-	    }
-	  else
-	    {
-	      /* With points-to analysis, we can add all the aliases we find
-		 for a variable because the alias sets are much smaller
-		 than what we get when doing type-based aliasing.  */
-	      at = v1;
-	      add_may_alias (v2, at);
-	      add_may_alias (at, v2);
-	    }
+	  /* Force the alias tag to alias itself.  This avoids problems
+	     when the program is accessing the alias tag directly. For
+	     instance, suppose that '*p' is the alias tag for 'i' and 'j':
 
-	  /* If V2 may access global memory, mark both AT and V1 as aliases
-	     for global memory.  */
-	  if (may_access_global_mem (v2, v2_base))
-	    {
-	      set_may_alias_global_mem (at);
-	      set_may_alias_global_mem (v1);
-	    }
+		  1	i = ...
+		  2	*p = ...
+		  3	... = i
+
+	     If '*p' is not made an alias of itself, then the assignment at
+	     line 2 will be considered a killing definition of '*p'.  This
+	     would make the assignment to 'i' at line 1 appear dead because
+	     the use of 'i' at line 3 is now reached by the assignment to
+	     '*p' at line 2.
+
+	     If '*p' does not alias 'i' at runtime, the compiler would've
+	     generated wrong code.  This fixes the regression of
+	     gcc.c-torture/execute/950929-1.c.  */
+	  add_may_alias (at, at);
 	}
+
+      add_may_alias (v2, at);
+    }
+  else
+    {
+      /* With points-to analysis, we can add all the aliases we find
+         for a variable because the alias sets are much smaller
+         than what we get when doing type-based aliasing.  */
+      at = v1;
+      add_may_alias (v2, at);
+      add_may_alias (at, v2);
+    }
+
+  /* If V2 may access global memory, mark both AT and V1 as aliases
+     for global memory.  */
+  if (may_access_global_mem (v2, v2_base))
+    {
+      set_may_alias_global_mem (at);
+      set_may_alias_global_mem (v1);
     }
+
+  /* If V1 is an alias for global memory and V2 is a pointer, then V2 may
+     also point to global memory.  Mark it.  */
+  if (POINTER_TYPE_P (TREE_TYPE (v2)) && may_alias_global_mem_p (v1))
+    set_may_alias_global_mem (v2);
 }
 
 
@@ -1705,8 +1795,7 @@ add_may_alias (var, alias)
 
 /* Traverse the ALIAS_TAGS array looking for an alias tag that may alias
    variable V1 or V2.  The caller also provides the base symbol and
-   alias set V1 and V2 in V1_BASE, V2_BASE, V1_ALIAS_SET and V2_ALIAS_SET.
- 
+   alias set for V1 and V2 in V1_BASE, V2_BASE, V1_ALIAS_SET and V2_ALIAS_SET.
  
    If no entry is found for either V1 or V2, return NULL_TREE to tell the
    caller that it should create a new entry in the ALIAS_TAG array.  */
@@ -1896,10 +1985,11 @@ find_vars_r (tp, walk_subtrees, data)
     int *walk_subtrees ATTRIBUTE_UNUSED;
     void *data ATTRIBUTE_UNUSED;
 {
-  htab_t vars_found = ((htab_t *) data)[0];
-  htab_t indirect_refs_found = ((htab_t *) data)[1];
-  htab_t addressable_vars_found = ((htab_t *) data)[2];
-  tree var = *tp;
+  if (SSA_VAR_P (*tp))
+    {
+      add_referenced_var (*tp, data);
+      return NULL_TREE;
+    }
 
   /* Function calls.  Consider them a reference for an artificial variable
      called GLOBAL_VAR.  This variable is a pointer that will alias every
@@ -1913,89 +2003,126 @@ find_vars_r (tp, walk_subtrees, data)
 
      This is used to model the effects that the called function may have on
      local and global variables that might be visible to it.  */
-  if (TREE_CODE (var) == CALL_EXPR)
+  if (TREE_CODE (*tp) == CALL_EXPR)
     {
-      if (call_may_clobber (var))
+      if (call_may_clobber (*tp))
+	add_indirect_ref_var (global_var, data);
+      else
 	{
-	  if (!is_dereferenced (global_var))
+	  tree op;
+
+	  /* If the function does not clobber locals, it still may
+	     dereference them.  Scan its operands to see if it receives any
+	     pointers.  For every pointer 'p' add '*p' to the list of
+	     referenced variables.  */
+	  for (op = TREE_OPERAND (*tp, 1); op; op = TREE_CHAIN (op))
 	    {
-	      var = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (global_var)),
-			    global_var);
-	      set_indirect_ref (global_var, var);
+	      tree arg = TREE_VALUE (op);
+	      if (SSA_DECL_P (arg) && POINTER_TYPE_P (TREE_TYPE (arg)))
+		add_indirect_ref_var (arg, data);
 	    }
-	  else
-	    var = indirect_ref (global_var);
 	}
     }
 
-  if (SSA_VAR_P (var))
-    {
-      void **slot;
-      tree sym;
-      tree ind;
+  return NULL_TREE;
+}
 
-      /* Get the underlying symbol.  We will need it shortly.  */
-      if (TREE_CODE (var) == INDIRECT_REF)
-	{
-	  sym = get_base_symbol (TREE_OPERAND (var, 0));
-	  ind = var;
 
-	  if (!is_dereferenced (sym))
-	    set_indirect_ref (sym, ind);
-	  else
-	    ind = indirect_ref (sym);
-	}
-      else
-	{
-	  sym = get_base_symbol (var);
-	  ind = NULL_TREE;
-	}
+/* Add VAR to the list of dereferenced variables.  Also add it to the sets
+   ADDRESSABLE_VARS or INDIRECT_REFS needed for alias analysis.  DATA is an
+   array with three hash tables used to avoid adding the same variable more
+   than once to its corresponding set.  Note that this function assumes
+   that VAR is a valid SSA variable.  */
 
-      /* Make VAR either the canonical INDIRECT_REF or the real symbol.  */
-      var = (ind ? ind : var);
+static void
+add_referenced_var (var, data)
+     tree var;
+     void *data;
+{
+  void **slot;
+  tree sym;
+  tree ind;
+  htab_t vars_found = ((htab_t *) data)[0];
+  htab_t indirect_refs_found = ((htab_t *) data)[1];
+  htab_t addressable_vars_found = ((htab_t *) data)[2];
 
-      /* First handle an INDIRECT_REF.  */
-      if (ind)
-	{
-	  slot = htab_find_slot (indirect_refs_found, (void *)var, INSERT);
-	  if (*slot == NULL)
-	    {
-	      *slot = (void *)var;
-	      VARRAY_PUSH_TREE (indirect_refs, var);
-	      VARRAY_PUSH_TREE (indirect_refs_base, sym);
-	      VARRAY_PUSH_INT (indirect_refs_alias_set, get_alias_set (var));
-	      num_indirect_refs++;
-	    }
+  /* Get the underlying symbol.  We will need it shortly.  */
+  if (TREE_CODE (var) == INDIRECT_REF)
+    {
+      sym = get_base_symbol (TREE_OPERAND (var, 0));
+      ind = var;
 
-	}
-      else if (TREE_ADDRESSABLE (sym)
-	       || decl_function_context (sym) == NULL)
-	{
-	  slot = htab_find_slot (addressable_vars_found, (void *)var, INSERT);
+      if (!is_dereferenced (sym))
+	set_indirect_ref (sym, ind);
+      else
+	ind = indirect_ref (sym);
+    }
+  else
+    {
+      sym = get_base_symbol (var);
+      ind = NULL_TREE;
+    }
 
-	  if (*slot == NULL)
-	    {
-	      *slot = (void *)var;
-	      VARRAY_PUSH_TREE (addressable_vars, var);
-	      VARRAY_PUSH_TREE (addressable_vars_base, sym);
-	      VARRAY_PUSH_INT (addressable_vars_alias_set,
-			       get_alias_set (var));
-	      num_addressable_vars++;
-	    }
+  /* Make VAR either the canonical INDIRECT_REF or the real symbol.  */
+  var = (ind ? ind : var);
+
+  /* First handle an INDIRECT_REF.  */
+  if (ind)
+    {
+      slot = htab_find_slot (indirect_refs_found, (void *) var, INSERT);
+      if (*slot == NULL)
+	{
+	  *slot = (void *) var;
+	  VARRAY_PUSH_TREE (indirect_refs, var);
+	  VARRAY_PUSH_TREE (indirect_refs_base, sym);
+	  VARRAY_PUSH_INT (indirect_refs_alias_set, get_alias_set (var));
+	  num_indirect_refs++;
 	}
-	  
-      slot = htab_find_slot (vars_found, (void *) var, INSERT);
+    }
+  else if (TREE_ADDRESSABLE (sym) || decl_function_context (sym) == NULL)
+    {
+      slot = htab_find_slot (addressable_vars_found, (void *) var, INSERT);
       if (*slot == NULL)
 	{
-	  /* This is the first time we find this variable, add it to the
-	     REFERENCED_VARS array.  */
 	  *slot = (void *) var;
-	  VARRAY_PUSH_TREE (referenced_vars, var);
-	  num_referenced_vars++;
+	  VARRAY_PUSH_TREE (addressable_vars, var);
+	  VARRAY_PUSH_TREE (addressable_vars_base, sym);
+	  VARRAY_PUSH_INT (addressable_vars_alias_set, get_alias_set (var));
+	  num_addressable_vars++;
 	}
     }
 
-  return NULL_TREE;
+  slot = htab_find_slot (vars_found, (void *) var, INSERT);
+  if (*slot == NULL)
+    {
+      /* This is the first time we find this variable, add it to the
+         REFERENCED_VARS array.  */
+      *slot = (void *) var;
+      VARRAY_PUSH_TREE (referenced_vars, var);
+      num_referenced_vars++;
+    }
+}
+
+
+/* Add a reference to the INDIRECT_REF node of variable VAR.  If VAR has
+   not been dereferenced yet, create a new INDIRECT_REF node for it.  DATA
+   is as in add_referenced_var.  Note that VAR is assumed to be a valid
+   pointer decl.  */
+
+static void
+add_indirect_ref_var (var, data)
+     tree var;
+     void *data;
+{
+  tree deref = indirect_ref (var);
+
+  if (deref == NULL_TREE)
+    {
+      deref = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (var)), var);
+      set_indirect_ref (var, deref);
+    }
+
+  add_referenced_var (deref, data);
 }
 
 
@@ -2039,6 +2166,9 @@ get_virtual_var (var)
 
   STRIP_NOPS (var);
 
+  if (TREE_CODE (var) == SSA_NAME)
+    var = SSA_NAME_VAR (var);
+
   code = TREE_CODE (var);
 
   while (code == ARRAY_REF
@@ -2070,4 +2200,22 @@ call_may_clobber (expr)
   callee = get_callee_fndecl (expr);
   flags = (callee) ? flags_from_decl_or_type (callee) : 0;
   return (! (flags & (ECF_CONST | ECF_PURE | ECF_NORETURN)));
+}
+
+
+/* Mark VAR as an alias for global memory.  This means that loads or stores
+   to VAR may reference data outside the scope of the current function.  */
+
+void
+set_may_alias_global_mem (var)
+     tree var;
+{
+  var_ann_t ann = var_ann (var);
+  if (ann == NULL)
+    ann = create_var_ann (var);
+  ann->may_alias_global_mem = 1;
+  if (SSA_DECL_P (var)
+      && POINTER_TYPE_P (TREE_TYPE (var))
+      && ann->indirect_ref)
+    set_may_alias_global_mem (ann->indirect_ref);
 }
Index: tree-flow-inline.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow-inline.h,v
retrieving revision 1.1.2.21
diff -d -u -p -r1.1.2.21 tree-flow-inline.h
--- tree-flow-inline.h	29 Jan 2003 00:35:19 -0000	1.1.2.21
+++ tree-flow-inline.h	3 Feb 2003 01:16:39 -0000
@@ -36,7 +36,7 @@ var_ann (t)
   /* SSA_NAME nodes share the same annotations as the VAR_DECL node that
      they wrap.  */
   if (TREE_CODE (t) == SSA_NAME)
-    t = SSA_NAME_DECL (t);
+    t = SSA_NAME_VAR (t);
 
   /* INDIRECT_REF nodes share the annotation from the canonical
      dereference for their base pointer (see find_vars_r).  */
@@ -88,16 +88,6 @@ is_aliased (var)
      tree var;
 {
   return may_aliases (var) != NULL;
-}
-
-static inline void
-set_may_alias_global_mem (var)
-     tree var;
-{
-  var_ann_t ann = var_ann (var);
-  if (ann == NULL)
-    ann = create_var_ann (var);
-  ann->may_alias_global_mem = 1;
 }
 
 static inline bool
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.47
diff -d -u -p -r1.1.4.47 tree-flow.h
--- tree-flow.h	30 Jan 2003 18:50:20 -0000	1.1.4.47
+++ tree-flow.h	3 Feb 2003 01:16:39 -0000
@@ -171,7 +171,6 @@ static inline tree create_indirect_ref		
 static inline varray_type may_aliases		PARAMS ((tree));
 static inline bool is_aliased			PARAMS ((tree));
 static inline bool may_alias_global_mem_p 	PARAMS ((tree));
-static inline void set_may_alias_global_mem	PARAMS ((tree));
 static inline bool is_dereferenced	 	PARAMS ((tree));
 static inline void set_indirect_ref		PARAMS ((tree, tree));
 static inline tree indirect_ref			PARAMS ((tree));
@@ -343,6 +342,7 @@ static inline bool same_var_p		PARAMS ((
 extern void dump_alias_info		PARAMS ((FILE *));
 extern void debug_alias_info		PARAMS ((void));
 extern tree get_virtual_var		PARAMS ((tree));
+extern void set_may_alias_global_mem	PARAMS ((tree));
 
 /* Flags used when computing reaching definitions and reached uses.  */
 #define TDFA_USE_OPS		1 << 0
Index: tree-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-pretty-print.c,v
retrieving revision 1.1.2.14
diff -d -u -p -r1.1.2.14 tree-pretty-print.c
--- tree-pretty-print.c	30 Jan 2003 03:02:26 -0000	1.1.2.14
+++ tree-pretty-print.c	3 Feb 2003 01:16:39 -0000
@@ -1255,10 +1255,10 @@ dump_generic_node (buffer, node, spc, fl
       break;
 
     case SSA_NAME:
-      if (TREE_CODE (SSA_NAME_DECL (node)) == INDIRECT_REF)
+      if (TREE_CODE (SSA_NAME_VAR (node)) == INDIRECT_REF)
 	output_add_string (buffer, "(");
-      dump_generic_node (buffer, SSA_NAME_DECL (node), spc, flags);
-      if (TREE_CODE (SSA_NAME_DECL (node)) == INDIRECT_REF)
+      dump_generic_node (buffer, SSA_NAME_VAR (node), spc, flags);
+      if (TREE_CODE (SSA_NAME_VAR (node)) == INDIRECT_REF)
 	output_add_string (buffer, ")");
       output_add_string (buffer, "_");
       output_decimal (buffer, SSA_NAME_VERSION (node));
Index: tree-simple.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-simple.c,v
retrieving revision 1.1.4.26
diff -d -u -p -r1.1.4.26 tree-simple.c
--- tree-simple.c	28 Jan 2003 05:14:23 -0000	1.1.4.26
+++ tree-simple.c	3 Feb 2003 01:16:39 -0000
@@ -949,7 +949,7 @@ get_base_symbol (t)
       return t;
 
     case SSA_NAME:
-      return get_base_symbol (SSA_NAME_DECL (t));
+      return get_base_symbol (SSA_NAME_VAR (t));
 
     case ARRAY_REF:
     case COMPONENT_REF:
Index: tree-ssa-ccp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-ccp.c,v
retrieving revision 1.1.2.42
diff -d -u -p -r1.1.2.42 tree-ssa-ccp.c
--- tree-ssa-ccp.c	28 Jan 2003 05:14:23 -0000	1.1.2.42
+++ tree-ssa-ccp.c	3 Feb 2003 01:16:39 -0000
@@ -342,7 +342,7 @@ visit_phi_node (phi)
   phi_val.lattice_val = UNDEFINED;
   phi_val.const_val = NULL_TREE;
 
-  if (!TREE_THIS_VOLATILE (SSA_NAME_DECL (PHI_RESULT (phi))))
+  if (!TREE_THIS_VOLATILE (SSA_NAME_VAR (PHI_RESULT (phi))))
     for (i = 0; i < PHI_NUM_ARGS (phi); i++)
       {
 	/* Compute the meet operator over all the PHI arguments. */
@@ -361,7 +361,7 @@ visit_phi_node (phi)
 	  {
 	    tree rdef = PHI_ARG_DEF (phi, i);
 
-	    if (!TREE_THIS_VOLATILE (SSA_NAME_DECL (rdef)))
+	    if (!TREE_THIS_VOLATILE (SSA_NAME_VAR (rdef)))
 	      {
 		value *rdef_val = get_value (rdef);
 		phi_val = cp_lattice_meet (phi_val, *rdef_val);
Index: tree-ssa-dce.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-dce.c,v
retrieving revision 1.1.2.22
diff -d -u -p -r1.1.2.22 tree-ssa-dce.c
--- tree-ssa-dce.c	29 Jan 2003 13:14:14 -0000	1.1.2.22
+++ tree-ssa-dce.c	3 Feb 2003 01:16:39 -0000
@@ -216,7 +216,7 @@ need_to_preserve_store (var)
   if (var == NULL)
     return false;
 
-  sym = SSA_NAME_DECL (var);
+  sym = SSA_NAME_VAR (var);
   base_symbol = get_base_symbol (var);
 
   /* Stores to volatiles must be preserved.  */
@@ -284,19 +284,18 @@ stmt_useful_p (stmt)
   varray_type ops;
   size_t i;
 
-  /* Instructions that are implicitly live.  Asms and Returns are required.
-     Labels are kept because they are control flow, and we have no way of
-     knowing whether they can be removed.   DCE can eliminate all the other
-     statements in a block, and CFG can then remove the block and labels.
-     VA_ARG_EXPR behaves like a builtin function call to
-     __builtin_va_arg().  */
+  /* Instructions that are implicitly live.  Function calls, asm and return
+     statements are required.  Labels are kept because they are control
+     flow, and we have no way of knowing whether they can be removed.   DCE
+     can eliminate all the other statements in a block, and CFG can then
+     remove the block and labels.  */
   if ((TREE_CODE (stmt) == ASM_EXPR)
       || (TREE_CODE (stmt) == RETURN_EXPR)
       || (TREE_CODE (stmt) == CASE_LABEL_EXPR)
-      || (TREE_CODE (stmt) == VA_ARG_EXPR)
+      || (TREE_CODE (stmt) == CALL_EXPR)
+      || (TREE_CODE (stmt) == LABEL_EXPR)
       || ((TREE_CODE (stmt) == MODIFY_EXPR)
-	  && (TREE_CODE (TREE_OPERAND (stmt, 1)) == VA_ARG_EXPR))
-      || (TREE_CODE (stmt) == LABEL_EXPR))
+	  && (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)))
     return true;
 
   /* GOTO_EXPR nodes to nonlocal labels need to be kept (This fixes
Index: tree-ssa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa.c,v
retrieving revision 1.1.4.44
diff -d -u -p -r1.1.4.44 tree-ssa.c
--- tree-ssa.c	29 Jan 2003 04:14:37 -0000	1.1.4.44
+++ tree-ssa.c	3 Feb 2003 01:16:39 -0000
@@ -403,7 +403,7 @@ rewrite_block (bb)
 
       for (phi = phi_nodes (e->dest); phi; phi = TREE_CHAIN (phi))
 	{
-	  tree currdef = currdef_for (SSA_NAME_DECL (PHI_RESULT (phi)), true);
+	  tree currdef = currdef_for (SSA_NAME_VAR (PHI_RESULT (phi)), true);
 	  add_phi_arg (phi, currdef, e);
 	}
     }
@@ -429,7 +429,7 @@ rewrite_block (bb)
 	  VARRAY_POP (block_defs);
 	}
       else
-	var = SSA_NAME_DECL (saved_def);
+	var = SSA_NAME_VAR (saved_def);
 
       set_currdef_for (var, saved_def);
     }
@@ -458,14 +458,14 @@ rewrite_out_of_ssa (fndecl)
 	if (def_op (stmt))
 	  {
 	    tree *def_p = def_op (stmt);
-	    *def_p = SSA_NAME_DECL (*def_p);
+	    *def_p = SSA_NAME_VAR (*def_p);
 	  }
 
 	ops = use_ops (stmt);
 	for (i = 0; ops && i < VARRAY_ACTIVE_SIZE (ops); i++)
 	  {
 	    tree *use_p = VARRAY_GENERIC_PTR (ops, i);
-	    *use_p = SSA_NAME_DECL (*use_p);
+	    *use_p = SSA_NAME_VAR (*use_p);
 	  }
       }
 
@@ -752,7 +752,7 @@ register_new_def (def, block_defs_p)
      tree def;
      varray_type *block_defs_p;
 {
-  tree var = SSA_NAME_DECL (def);
+  tree var = SSA_NAME_VAR (def);
   tree currdef = currdef_for (var, false);
 
   /* If the current reaching definition is NULL, push the variable
Index: tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.263.2.21
diff -d -u -p -r1.263.2.21 tree.c
--- tree.c	28 Jan 2003 05:14:23 -0000	1.263.2.21
+++ tree.c	3 Feb 2003 01:16:39 -0000
@@ -4908,7 +4908,7 @@ make_ssa_name (var, stmt)
   t = make_node (SSA_NAME);
 
   TREE_TYPE (t) = TREE_TYPE (var);
-  SSA_NAME_DECL (t) = var;
+  SSA_NAME_VAR (t) = var;
   SSA_NAME_DEF_STMT (t) = stmt;
   SSA_NAME_VERSION (t) = next_ssa_version++;
 
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.42
diff -d -u -p -r1.342.2.42 tree.h
--- tree.h	29 Jan 2003 02:22:04 -0000	1.342.2.42
+++ tree.h	3 Feb 2003 01:16:40 -0000
@@ -1010,17 +1010,17 @@ struct tree_exp GTY(())
     operands[1];
 };
 

-/* SSA_NAME accessors.  SSA_NAME_DECL returns the _DECL node being
+/* SSA_NAME accessors.  SSA_NAME_VAR returns the variable being
    referenced.  SSA_NAME_DEF_STMT returns the statement that defines
    this reference.  */
-#define SSA_NAME_DECL(NODE)	SSA_NAME_CHECK (NODE)->ssa_name.decl
+#define SSA_NAME_VAR(NODE)	SSA_NAME_CHECK (NODE)->ssa_name.var
 #define SSA_NAME_DEF_STMT(NODE)	SSA_NAME_CHECK (NODE)->ssa_name.def_stmt
 #define SSA_NAME_VERSION(NODE)	SSA_NAME_CHECK (NODE)->ssa_name.version
 
 struct tree_ssa_name GTY(())
 {
   struct tree_common common;
-  tree decl;
+  tree var;
   tree def_stmt;
   unsigned int version;
 };
@@ -1527,14 +1527,20 @@ struct tree_type GTY(())
 /* Nonzero if DECL represents a decl.  */
 #define DECL_P(DECL)	(TREE_CODE_CLASS (TREE_CODE (DECL)) == 'd')
 
-/* Nonzero if DECL represents a decl or an SSA name.  */
-#define SSA_DECL_P(DECL) (TREE_CODE (DECL) == VAR_DECL	\
-    			  || TREE_CODE (DECL) == PARM_DECL \
-			  || TREE_CODE (DECL) == SSA_NAME)
+/* Nonzero if DECL represents a decl or an SSA name for a decl.  */
+#define SSA_DECL_P(DECL) \
+	(TREE_CODE (DECL) == VAR_DECL	\
+	 || TREE_CODE (DECL) == PARM_DECL \
+	 || (TREE_CODE (DECL) == SSA_NAME \
+	     && (TREE_CODE (SSA_NAME_VAR (DECL)) == VAR_DECL \
+		 || TREE_CODE (SSA_NAME_VAR (DECL)) == PARM_DECL)))
+			      
 
 /* Nonzero if NODE is a variable for the SSA analyzer.  Variables are SSA
-   decls and INDIRECT_REF nodes.  */
-#define SSA_VAR_P(NODE) (SSA_DECL_P (NODE) || TREE_CODE (NODE) == INDIRECT_REF)
+   decls, SSA names and INDIRECT_REF nodes.  */
+#define SSA_VAR_P(NODE) (SSA_DECL_P (NODE) \
+    			 || TREE_CODE (NODE) == SSA_NAME \
+    			 || TREE_CODE (NODE) == INDIRECT_REF)
 
 /* This is the name of the object as written by the user.
    It is an IDENTIFIER_NODE.  */
Index: testsuite/lib/c-torture.exp
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/lib/c-torture.exp,v
retrieving revision 1.17
diff -d -u -p -r1.17 c-torture.exp
--- testsuite/lib/c-torture.exp	25 May 2002 03:40:20 -0000	1.17
+++ testsuite/lib/c-torture.exp	3 Feb 2003 01:16:45 -0000
@@ -34,13 +34,13 @@ if ![info exists TORTURE_OPTIONS] {
     # choose to disable inlining functions by default, even when optimizing.
     set TORTURE_OPTIONS [list \
 	{ -O0 } \
-	{ -O1 } \
-	{ -O2 } \
-	{ -O3 -fomit-frame-pointer } \
-	{ -O3 -fomit-frame-pointer -funroll-loops } \
-	{ -O3 -fomit-frame-pointer -funroll-all-loops -finline-functions } \
-	{ -O3 -g } \
-	{ -Os } ]
+	{ -O1 -ftree-dce } \
+	{ -O2 -ftree-dce } \
+	{ -O3 -fomit-frame-pointer -ftree-dce } \
+	{ -O3 -fomit-frame-pointer -funroll-loops -ftree-dce } \
+	{ -O3 -fomit-frame-pointer -funroll-all-loops -finline-functions -ftree-dce } \
+	{ -O3 -g -ftree-dce } \
+	{ -Os -ftree-dce } ]
 }
 
 



More information about the Gcc-patches mailing list