public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [tree-ssa] CCP and variable reference fixes [patch]
@ 2002-11-07  4:36 Diego Novillo
  2002-11-07  8:34 ` Jason Merrill
  0 siblings, 1 reply; 5+ messages in thread
From: Diego Novillo @ 2002-11-07  4:36 UTC (permalink / raw)
  To: gcc-patches

- Removes unnecessary fields from tree_ref structure.  We don't
  need to keep pointers into the expression nor operand for each
  reference.  This makes it possible for a pass to replicate a
  statement and replace references from the original statement
  into the copy.
  
  Useful when a pass needs to try a replacement before committing
  changes.  References inside a statement should be replaced with
  calls to replace_ref_in.


- Changes the way CCP operates.  Instead of traversing
  references, we now traverse statements in a block.  It's
  actually sparser that way.  We were visiting the same statement
  multiple times before.

- Fixes a bug in visit_phi_node.  We were not checking for
  killing definitions reaching the PHI node.  We were also not
  checking whether the PHI node was volatile.


Bootstrapped and tested on x86.

Diego.



	* Makefile.in (tree-ssa-ccp.o): Add dependency on tree-inline.h
	* tree-cfg.c (find_taken_edge): New function.
	(cleanup_cond_expr_graph): Call it.
	(disconnect_unreachable_case_labels): Call it.

	* tree-dfa.c (struct clobber_data_d): Remove field
	parent_expr_p.  Update all users.
	(find_refs_in_expr): Remove argument parent_expr_p.  Update all users.
	(create_ref): Remove arguments parent_expr_p and operand_p.  Update
	all users.
	(replace_ref_in): Rename from replace_ref_operand_with.  Update all
	users.  Find the operand in the statement and replace it with a new
	operand.
	(replace_ref_r): New local function.
	(is_killing_def): Also handle V_PHI references.
	(output_ref): Move from tree-flow-inline.h

	* tree-flow-inline.h (ref_expr): Remove.  Update all users.
	(restore_ref_operand): Remove.  Update all users.
	(set_output_ref): Remove.  Update all users.
	(is_assignment_stmt): New function.
	(is_may_def, is_may_use, is_partial_def, is_partial_use,
	is_volatile_def, is_volatile_use, is_default_def,
	is_clobbering_def, is_initializing_def, is_relocating_def,
	is_addressof_use, is_pure_use): Check reference type first.
	(is_pure_def): New function.

	* tree-flow.h (struct tree_ref_common): Remove fields expr_p,
	operand_p and orig_operand.  Update all users.
	(struct tree_ann_d): Remove field output_ref.  Update all users.

	* tree-ssa-ccp.c: Include tree-inline.h.
	(simulate_block): Simulate every statement in the block, not its
	references
	(simulate_def_use_chains): Simulate statements containing uses
	reached by the definition.
	(substitute_and_fold): Traverse statements, not references.
	Call fold_stmt.
	(visit_phi_node): If PHI node is marked volatile, assume varying.
	(visit_stmt): Rename from visit_expression_for.  Work on a
	statement, not a reference.
	(visit_assignment): Rename from visit_assignment_for.  Work on a
	statement, not a reference.
	(visit_cond_stmt): Rename from visit_condexpr_for.  Work on a
	statement, not a reference.
	(evaluate_stmt): Rename from evaluate_expr.  Work on a statement,
	not a reference.
	(initialize): Initialize special definitions to varying.
	(replace_uses_in): Work on a statement, not an expression.
	(fold_stmt): Rename from ccp_fold.  Work on a statement, not an
	expression.
	(get_rhs): New local function.
	(set_rhs): New local function.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.903.2.47
diff -d -u -p -r1.903.2.47 Makefile.in
--- Makefile.in	6 Nov 2002 12:20:55 -0000	1.903.2.47
+++ Makefile.in	7 Nov 2002 04:37:46 -0000
@@ -1567,7 +1567,7 @@ ssa-ccp.o : ssa-ccp.c $(CONFIG_H) system
     $(BASIC_BLOCK_H) ssa.h insn-config.h $(RECOG_H) output.h \
     errors.h $(GGC_H) df.h function.h
 tree-ssa-ccp.o : tree-ssa-ccp.c $(CONFIG_H) system.h errors.h $(TREE_H) \
-    $(RTL_H) $(TM_P_H) $(TREE_FLOW_H) diagnostic.h
+    $(RTL_H) $(TM_P_H) $(TREE_FLOW_H) diagnostic.h tree-inline.h
 df.o : df.c $(CONFIG_H) system.h $(RTL_H) insn-config.h $(RECOG_H) \
    function.h $(REGS_H) $(OBSTACK_H) hard-reg-set.h $(BASIC_BLOCK_H) df.h \
    $(FIBHEAP_H)
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.26
diff -d -u -p -r1.1.4.26 tree-cfg.c
--- tree-cfg.c	6 Nov 2002 22:22:34 -0000	1.1.4.26
+++ tree-cfg.c	7 Nov 2002 04:37:47 -0000
@@ -1074,6 +1074,7 @@ cleanup_cond_expr_graph (bb)
 {
   tree cond_expr = first_stmt (bb);
   tree val;
+  edge taken_edge;
 
 #if defined ENABLE_CHECKING
   if (TREE_CODE (cond_expr) != COND_EXPR)
@@ -1081,30 +1082,10 @@ cleanup_cond_expr_graph (bb)
 #endif
 
   val = COND_EXPR_COND (cond_expr);
-  if (really_constant_p (val))
+  taken_edge = find_taken_edge (bb, val);
+  if (taken_edge)
     {
-      bool always_false;
-      edge e, taken_edge, next;
-
-      /* Determine which branch of the if() will be taken.  */
-      taken_edge = NULL;
-      always_false = (simple_cst_equal (val, integer_zero_node) == 1);
-      for (e = bb->succ; e; e = e->succ_next)
-	{
-	  if (((e->flags & EDGE_TRUE_VALUE) && !always_false)
-	      || ((e->flags & EDGE_FALSE_VALUE) && always_false))
-	    {
-	      taken_edge = e;
-	      break;
-	    }
-	}
-
-      if (taken_edge == NULL)
-	{
-	  /* If E is not going to the THEN nor the ELSE clause, then it's
-	     the fallthru edge to the successor block of the if() block.  */
-	  taken_edge = find_edge (bb, successor_block (bb));
-	}
+      edge e, next;
 
       /* Remove all the edges except the one that is always executed.  */
       for (e = bb->succ; e; e = next)
@@ -1162,61 +1143,134 @@ static void
 disconnect_unreachable_case_labels (bb)
      basic_block bb;
 {
-  edge e, default_edge, taken_edge;
+  edge taken_edge;
   tree switch_val;
 
-  default_edge = NULL;
-  taken_edge = NULL;
-
   switch_val = SWITCH_COND (first_stmt (bb));
-  if (!really_constant_p (switch_val))
-    return;
+  taken_edge = find_taken_edge (bb, switch_val);
+  if (taken_edge)
+    {
+      edge e, next;
 
-  /* See if the switch() value matches one of the case labels.  */
-  for (e = bb->succ; e; e = e->succ_next)
+      /* Remove all the edges that go to case labels that will never
+	 be taken.  */
+      for (e = bb->succ; e; e = next)
+	{
+	  next = e->succ_next;
+	  if (e != taken_edge)
+	    remove_edge (e);
+	}
+    }
+}
+
+
+/* Given a control block BB and a constant value VAL, return the edge
+   that will be taken out of BLOCK.  If VAL does not match a unique edge,
+   NULL is returned.  */
+
+edge
+find_taken_edge (bb, val)
+     basic_block bb;
+     tree val;
+{
+  tree stmt;
+  edge e, taken_edge;
+
+  stmt = first_stmt (bb);
+
+#if defined ENABLE_CHECKING
+  if (!is_ctrl_stmt (stmt))
+    abort ();
+#endif
+
+  /* If VAL is not a constant, we can't determine which edge might
+     be taken.  */
+  if (val == NULL || !really_constant_p (val))
+    return NULL;
+
+  taken_edge = NULL;
+  if (TREE_CODE (stmt) == COND_EXPR)
     {
-      tree val;
-      edge dest_edge = e;
-      tree dest_t = first_stmt (dest_edge->dest);
+      bool always_false;
+      bool always_true;
 
-      if (TREE_CODE (dest_t) != CASE_LABEL_EXPR)
-	continue;
+      /* Determine which branch of the if() will be taken.  */
+      always_false = (simple_cst_equal (val, integer_zero_node) == 1);
+      always_true = (simple_cst_equal (val, integer_one_node) == 1);
 
-      val = CASE_LOW (dest_t);
-      if (val == NULL_TREE)
+      /* If VAL is a constant but it can't be reduced to a 0 or a 1, then
+	 we don't really know which edge will be taken at runtime.  This
+	 may happen when comparing addresses (e.g., if (&var1 == 4))  */
+      if (!always_false && !always_true)
+	return NULL;
+
+      for (e = bb->succ; e; e = e->succ_next)
 	{
-	  /* Remember that we found a default label, just in case no other
-	     label matches the switch() value.  */
-	  default_edge = dest_edge;
+	  if (((e->flags & EDGE_TRUE_VALUE) && always_true)
+	      || ((e->flags & EDGE_FALSE_VALUE) && always_false))
+	    {
+	      taken_edge = e;
+	      break;
+	    }
 	}
-      else if (simple_cst_equal (val, switch_val) == 1)
+
+      if (taken_edge == NULL)
 	{
-	  /* We found the unique label that will be taken by the switch.
-	     No need to keep looking.  All the other labels are never
-	     reached directly from the switch().  */
-	  taken_edge = dest_edge;
-	  break;
+	  /* If E is not going to the THEN nor the ELSE clause, then it's
+	     the fallthru edge to the successor block of the if() block.  */
+	  taken_edge = find_edge (bb, successor_block (bb));
 	}
     }
-
-  /* If no case exists for the value used in the switch(), we use the
-     default label.  */
-  if (taken_edge == NULL)
-    taken_edge = default_edge;
-
-  /* Remove all the edges that go to case labels that will never be taken.  */
-  if (taken_edge)
+  else if (TREE_CODE (stmt) == SWITCH_EXPR)
     {
-      edge next;
-      for (e = bb->succ; e; e = next)
+      edge default_edge = NULL;
+
+      /* See if the switch() value matches one of the case labels.  */
+      for (e = bb->succ; e; e = e->succ_next)
 	{
-	  next = e->succ_next;
-	  if (e != taken_edge)
-	    remove_edge (e);
+	  tree label_val;
+	  edge dest_edge = e;
+	  tree dest_t = first_stmt (dest_edge->dest);
+
+	  /* Remember the edge out of the switch() just in case there is no
+	     matching label in the body.  */
+	  if (TREE_CODE (dest_t) != CASE_LABEL_EXPR)
+	    continue;
+
+	  label_val = CASE_LOW (dest_t);
+	  if (label_val == NULL_TREE)
+	    {
+	      /* Remember that we found a default label, just in case no other
+	         label matches the switch() value.  */
+	      default_edge = dest_edge;
+	    }
+	  else if (simple_cst_equal (label_val, val) == 1)
+	    {
+	      /* We found the unique label that will be taken by the switch.
+	         No need to keep looking.  All the other labels are never
+	         reached directly from the switch().  */
+	      taken_edge = dest_edge;
+	      break;
+	    }
 	}
+
+      /* If no case exists for the value used in the switch(), we use the
+         default label.  If the switch() has no label, we use the edge
+	 going out of the switch() body.  */
+      if (taken_edge == NULL)
+	taken_edge = default_edge 
+		     ? default_edge
+		     : find_edge (bb, successor_block (bb));
     }
-}
+  else
+    {
+      /* LOOP_EXPR nodes are always followed by their successor block.  */
+      taken_edge = bb->succ;
+    }
+
 
+  return taken_edge;
+}
 
 
 /*---------------------------------------------------------------------------
Index: tree-dfa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-dfa.c,v
retrieving revision 1.1.4.41
diff -d -u -p -r1.1.4.41 tree-dfa.c
--- tree-dfa.c	6 Nov 2002 22:22:33 -0000	1.1.4.41
+++ tree-dfa.c	7 Nov 2002 04:37:47 -0000
@@ -37,7 +37,6 @@ Boston, MA 02111-1307, USA.  */
 #include "tree-simple.h"
 #include "tree-flow.h"
 #include "tree-inline.h"
-
 #include "tree-alias-common.h"
 
 /* Local declarations.  */
@@ -45,9 +44,13 @@ struct clobber_data_d
 {
   basic_block bb;
   tree *parent_stmt_p;
-  tree *parent_expr_p;
 };
 
+struct replace_data_d
+{
+  tree old;
+  tree new;
+};
 
 /* DFA Statistics.  */
 struct dfa_stats_d
@@ -79,7 +82,7 @@ extern int tree_ssa_dump_flags;
 
 /* Local functions.  */
 static void find_refs_in_expr		PARAMS ((tree *, enum tree_ref_type,
-      						 unsigned, basic_block, tree *,
+      						 unsigned, basic_block,
 						 tree *));
 static void add_referenced_var		PARAMS ((tree));
 static void dump_if_different		PARAMS ((FILE *, const char * const,
@@ -94,10 +97,10 @@ static tree clobber_vars_r		PARAMS ((tre
 static void compute_may_aliases		PARAMS ((void));
 static void find_may_aliases_for	PARAMS ((tree));
 static void add_may_alias		PARAMS ((tree, tree));
-static inline bool may_alias_p			PARAMS ((tree, tree));
-static bool is_visible_to		PARAMS ((tree, tree));
+static inline bool may_alias_p		PARAMS ((tree, tree));
 static size_t tree_ref_size		PARAMS ((enum tree_ref_type));
 static inline tree create_indirect_ref	PARAMS ((tree));
+static tree replace_ref_r		PARAMS ((tree *, int *, void *));
 
 
 /* Global declarations.  */
@@ -167,37 +170,29 @@ find_refs_in_stmt (stmt_p, bb)
   switch (code)
     {
     case COND_EXPR:
-      find_refs_in_expr (&COND_EXPR_COND (stmt), V_USE, 0, bb, stmt_p,
-	                 &COND_EXPR_COND (stmt));
+      find_refs_in_expr (&COND_EXPR_COND (stmt), V_USE, 0, bb, stmt_p);
       break;
 
     case SWITCH_EXPR:
-      find_refs_in_expr (&SWITCH_COND (stmt), V_USE, 0, bb, stmt_p,
-	                 &SWITCH_COND (stmt));
+      find_refs_in_expr (&SWITCH_COND (stmt), V_USE, 0, bb, stmt_p);
       break;
 
     case ASM_EXPR:
-      find_refs_in_expr (&ASM_INPUTS (stmt), V_USE, 0, bb, stmt_p,
-	                 &ASM_INPUTS (stmt));
-      find_refs_in_expr (&ASM_OUTPUTS (stmt), V_DEF, TRM_CLOBBER, bb, stmt_p,
-	                 &ASM_OUTPUTS (stmt));
-      find_refs_in_expr (&ASM_CLOBBERS (stmt), V_DEF, TRM_CLOBBER, bb, stmt_p,
-	                 &ASM_CLOBBERS (stmt));
+      find_refs_in_expr (&ASM_INPUTS (stmt), V_USE, 0, bb, stmt_p);
+      find_refs_in_expr (&ASM_OUTPUTS (stmt), V_DEF, TRM_CLOBBER, bb, stmt_p);
+      find_refs_in_expr (&ASM_CLOBBERS (stmt), V_DEF, TRM_CLOBBER, bb, stmt_p);
       break;
 
     case RETURN_EXPR:
-      find_refs_in_expr (&TREE_OPERAND (stmt, 0), V_USE, 0, bb, stmt_p, 
-	                 &TREE_OPERAND (stmt, 0));
+      find_refs_in_expr (&TREE_OPERAND (stmt, 0), V_USE, 0, bb, stmt_p);
       break;
 
     case GOTO_EXPR:
-      find_refs_in_expr (&GOTO_DESTINATION (stmt), V_USE, 0, bb, stmt_p,
-	                 &GOTO_DESTINATION (stmt));
+      find_refs_in_expr (&GOTO_DESTINATION (stmt), V_USE, 0, bb, stmt_p);
       break;
 
     case LABEL_EXPR:
-      find_refs_in_expr (&LABEL_EXPR_LABEL (stmt), V_USE, 0, bb, stmt_p,
-			 &LABEL_EXPR_LABEL (stmt));
+      find_refs_in_expr (&LABEL_EXPR_LABEL (stmt), V_USE, 0, bb, stmt_p);
       break;
 
       /* These nodes contain no variable references.  */
@@ -207,7 +202,7 @@ find_refs_in_stmt (stmt_p, bb)
       break;
 
     default:
-      find_refs_in_expr (stmt_p, V_USE, 0, bb, stmt_p, stmt_p);
+      find_refs_in_expr (stmt_p, V_USE, 0, bb, stmt_p);
     }
 }
 
@@ -219,29 +214,19 @@ find_refs_in_stmt (stmt_p, bb)
 
    REF_MOD is the set of modifier flags for REF_TYPE.
 
-   BB, PARENT_STMT_P and PARENT_EXPR_P give the location of *EXPR_P in the
-      program.
-      
-   NOTE: PARENT_EXPR_P and PARENT_STMT_P may point to the same tree.  For
-      instance, given the statement 'a = b + c;', they both point to the
-      MODIFY_EXPR tree.
-      
-      However, given 'if (a > b)', PARENT_STMT_P will point to the
-      COND_EXPR tree, while PARENT_EXPR_P will point to the GT_EXPR tree.  */
+   BB and PARENT_STMT_P give the location of *EXPR_P in the program.  */
 
 static void
-find_refs_in_expr (expr_p, ref_type, ref_mod, bb, parent_stmt_p, parent_expr_p)
+find_refs_in_expr (expr_p, ref_type, ref_mod, bb, parent_stmt_p)
      tree *expr_p;
      enum tree_ref_type ref_type;
      unsigned ref_mod;
      basic_block bb;
      tree *parent_stmt_p;
-     tree *parent_expr_p;
 {
   enum tree_code code;
   char class;
   tree expr = *expr_p;
-  tree parent_expr = *parent_expr_p;
   tree parent_stmt = *parent_stmt_p;
 
   if (expr == NULL || expr == error_mark_node)
@@ -260,18 +245,16 @@ find_refs_in_expr (expr_p, ref_type, ref
     return;
 
   /* If this reference is associated with a non SIMPLE expression, then we
-     mark the parent expression non SIMPLE and recursively clobber every
-     variable referenced by PARENT_EXPR.  FIXME: TREE_NOT_GIMPLE must die.  */
-  if (parent_stmt && parent_expr && TREE_NOT_GIMPLE (expr))
+     mark the statement non GIMPLE and recursively clobber every
+     variable referenced by PARENT_STMT.  FIXME  TREE_NOT_GIMPLE must die.  */
+  if (parent_stmt && TREE_NOT_GIMPLE (expr))
     {
       struct clobber_data_d clobber_data;
 
-      TREE_NOT_GIMPLE (parent_expr) = 1;
       TREE_NOT_GIMPLE (parent_stmt) = 1;
       clobber_data.bb = bb;
-      clobber_data.parent_expr_p = parent_expr_p;
       clobber_data.parent_stmt_p = parent_stmt_p;
-      walk_tree (parent_expr_p, clobber_vars_r, &clobber_data, NULL);
+      walk_tree (parent_stmt_p, clobber_vars_r, &clobber_data, NULL);
       return;
     }
 
@@ -285,8 +268,7 @@ find_refs_in_expr (expr_p, ref_type, ref
   /* If we found a _DECL node, create a reference to it and return.  */
   if (code == VAR_DECL || code == PARM_DECL)
     {
-      create_ref (expr, ref_type, ref_mod, bb, parent_stmt_p, parent_expr_p,
-	          expr_p, 1);
+      create_ref (expr, ref_type, ref_mod, bb, parent_stmt_p, 1);
 
       /* If we just created a V_DEF reference for a pointer variable 'p',
 	 we have to clobber the associated '*p' variable, because now 'p'
@@ -298,7 +280,7 @@ find_refs_in_expr (expr_p, ref_type, ref
 	    set_indirect_var (expr, create_indirect_ref (expr));
 
 	  create_ref (indirect_var (expr), V_DEF, TRM_RELOCATE, bb,
-		      parent_stmt_p, parent_expr_p, NULL, 1);
+		      parent_stmt_p, 1);
 	}
 
       return;
@@ -337,8 +319,7 @@ find_refs_in_expr (expr_p, ref_type, ref
       tree ptr_sym = get_base_symbol (ptr);
 
       /* Create a V_USE reference for the pointer variable itself.  */
-      find_refs_in_expr (&TREE_OPERAND (expr, 0), V_USE, 0, bb, parent_stmt_p,
-	                 parent_expr_p);
+      find_refs_in_expr (&TREE_OPERAND (expr, 0), V_USE, 0, bb, parent_stmt_p);
 
       /* If this is the first INDIRECT_REF node we find for PTR, set EXPR
 	 to be the indirect variable used to represent all dereferences of
@@ -347,7 +328,7 @@ find_refs_in_expr (expr_p, ref_type, ref
 	set_indirect_var (ptr_sym, expr);
 
       create_ref (indirect_var (ptr_sym), ref_type, ref_mod, bb, parent_stmt_p,
-		  parent_expr_p, expr_p, 1);
+		  1);
 
       return;
     }
@@ -363,12 +344,10 @@ find_refs_in_expr (expr_p, ref_type, ref
       /* Change the reference type to a partial def/use when processing
 	 the LHS of the reference.  */
       find_refs_in_expr (&TREE_OPERAND (expr, 0), ref_type,
-	                 ref_mod | TRM_PARTIAL, bb, parent_stmt_p,
-			 parent_expr_p);
+	                 ref_mod | TRM_PARTIAL, bb, parent_stmt_p);
 
       /* References on the RHS of the array are always used as indices.  */
-      find_refs_in_expr (&TREE_OPERAND (expr, 1), V_USE, 0, bb, parent_stmt_p,
-			 parent_expr_p);
+      find_refs_in_expr (&TREE_OPERAND (expr, 1), V_USE, 0, bb, parent_stmt_p);
       return;
     }
 
@@ -390,8 +369,7 @@ find_refs_in_expr (expr_p, ref_type, ref
       /* Modify the reference to be a partial reference of the LHS of the
 	 expression.  */
       find_refs_in_expr (&TREE_OPERAND (expr, 0), ref_type,
-	                 ref_mod | TRM_PARTIAL, bb, parent_stmt_p,
-			 parent_expr_p);
+	                 ref_mod | TRM_PARTIAL, bb, parent_stmt_p);
       return;
     }
 
@@ -399,10 +377,8 @@ find_refs_in_expr (expr_p, ref_type, ref
      references.  */
   if (code == INIT_EXPR || code == MODIFY_EXPR)
     {
-      find_refs_in_expr (&TREE_OPERAND (expr, 1), V_USE, 0, bb, parent_stmt_p,
-			 parent_expr_p);
-      find_refs_in_expr (&TREE_OPERAND (expr, 0), V_DEF, 0, bb, parent_stmt_p,
-			 parent_expr_p);
+      find_refs_in_expr (&TREE_OPERAND (expr, 1), V_USE, 0, bb, parent_stmt_p);
+      find_refs_in_expr (&TREE_OPERAND (expr, 0), V_DEF, 0, bb, parent_stmt_p);
       return;
     }
  
@@ -419,11 +395,9 @@ find_refs_in_expr (expr_p, ref_type, ref
       tree callee;
       int flags;
 
-      find_refs_in_expr (&TREE_OPERAND (expr, 0), V_USE, 0, bb, parent_stmt_p,
-			  parent_expr_p);
+      find_refs_in_expr (&TREE_OPERAND (expr, 0), V_USE, 0, bb, parent_stmt_p);
 
-      find_refs_in_expr (&TREE_OPERAND (expr, 1), V_USE, 0, bb, parent_stmt_p,
-			  parent_expr_p);
+      find_refs_in_expr (&TREE_OPERAND (expr, 1), V_USE, 0, bb, parent_stmt_p);
 
       callee = get_callee_fndecl (expr);
       flags = (callee) ? flags_from_decl_or_type (callee) : 0;
@@ -432,10 +406,8 @@ find_refs_in_expr (expr_p, ref_type, ref
 	  may-use followed by a clobbering definition of GLOBAL_VAR.  */
       if (! (flags & (ECF_CONST | ECF_PURE)))
 	{
-	  create_ref (global_var, V_USE, TRM_MAY, bb, parent_stmt_p, NULL,
-	              NULL, 1);
-	  create_ref (global_var, V_DEF, TRM_CLOBBER, bb, parent_stmt_p, NULL,
-	              NULL, 1);
+	  create_ref (global_var, V_USE, TRM_MAY, bb, parent_stmt_p, 1);
+	  create_ref (global_var, V_DEF, TRM_CLOBBER, bb, parent_stmt_p, 1);
 	}
 
       return;
@@ -446,7 +418,7 @@ find_refs_in_expr (expr_p, ref_type, ref
   if (code == ADDR_EXPR)
     {
       find_refs_in_expr (&TREE_OPERAND (expr, 0), V_USE, TRM_ADDRESSOF, bb,
-			 parent_stmt_p, parent_expr_p);
+			 parent_stmt_p);
       return;
     }
 
@@ -457,7 +429,7 @@ find_refs_in_expr (expr_p, ref_type, ref
 
       for (op = expr; op; op = TREE_CHAIN (op))
 	find_refs_in_expr (&TREE_VALUE (op), ref_type, ref_mod, bb,
-	                   parent_stmt_p, parent_expr_p);
+	                   parent_stmt_p);
       return;
     }
 
@@ -467,7 +439,7 @@ find_refs_in_expr (expr_p, ref_type, ref
       || code == VA_ARG_EXPR)
     {
       find_refs_in_expr (&TREE_OPERAND (expr, 0), ref_type, ref_mod, bb,
-			 parent_stmt_p, parent_expr_p);
+			 parent_stmt_p);
       return;
     }
 
@@ -481,9 +453,9 @@ find_refs_in_expr (expr_p, ref_type, ref
       || code == CONSTRUCTOR)
     {
       find_refs_in_expr (&TREE_OPERAND (expr, 0), ref_type, ref_mod, bb,
-		         parent_stmt_p, parent_expr_p);
+		         parent_stmt_p);
       find_refs_in_expr (&TREE_OPERAND (expr, 1), ref_type, ref_mod, bb,
-	                 parent_stmt_p, parent_expr_p);
+	                 parent_stmt_p);
       return;
     }
 
@@ -796,9 +768,9 @@ tree_ref_size (ref_type)
       bitmask built from the TRM_* constants.  This bitmask is used to set
       the corresponding bitfield in the various tree_ref structures.
 
-   BB, PARENT_STMT_P, PARENT_EXPR_P and OPERAND_P give the exact location
-      of the reference.  The last three can be NULL in the case of
-      artificial references (PHI nodes, default definitions, etc).
+   BB and PARENT_STMT_P give the location of the reference.  PARENT_STMT_P
+      can be NULL in the case of artificial references (PHI nodes, default
+      definitions, etc).
 
    ADD_TO_BB should be 1 if the caller wants the reference to be added
       to the list of references for BB (i.e., bb_refs (BB)).  In that case,
@@ -810,21 +782,17 @@ tree_ref_size (ref_type)
       responsible for the placement of the newly created reference.  */
 
 tree_ref
-create_ref (var, ref_type, ref_mod, bb, parent_stmt_p, parent_expr_p, operand_p,
-            add_to_bb)
+create_ref (var, ref_type, ref_mod, bb, parent_stmt_p, add_to_bb)
      tree var;
      enum tree_ref_type ref_type;
      unsigned ref_mod;
      basic_block bb;
      tree *parent_stmt_p;
-     tree *parent_expr_p;
-     tree *operand_p;
      int add_to_bb;
 {
   size_t size;
   tree_ref ref;
   tree parent_stmt = (parent_stmt_p) ? *parent_stmt_p : NULL_TREE;
-  tree parent_expr = (parent_expr_p) ? *parent_expr_p : NULL_TREE;
 
 #if defined ENABLE_CHECKING
   if (bb == NULL)
@@ -852,9 +820,6 @@ create_ref (var, ref_type, ref_mod, bb, 
   ref->common.type = ref_type;
   ref->common.bb = bb;
   ref->common.stmt_p = parent_stmt_p;
-  ref->common.expr_p = parent_expr_p;
-  ref->common.operand_p = operand_p;
-  ref->common.orig_operand = (operand_p) ? *operand_p : NULL;
 
   /* Set the reference type modifier flags.  */
   if (ref_mod & TRM_MAY)
@@ -926,15 +891,10 @@ create_ref (var, ref_type, ref_mod, bb, 
       /* Add this reference to the list of references for the variable.  */
       add_tree_ref (var, ref);
 
-      /* Add the reference to the list of references for the parent
-	 expression.  */
-      if (parent_expr)
-	add_tree_ref (parent_expr, ref);
-
       /* In some cases the parent statement and parent expression are the
 	 same tree node.  For instance 'a = 5;'.  Avoid adding the same
 	 reference twice to the same list in these cases.  */
-      if (parent_stmt && parent_stmt != parent_expr)
+      if (parent_stmt)
 	add_tree_ref (parent_stmt, ref);
     }
 
@@ -943,19 +903,6 @@ create_ref (var, ref_type, ref_mod, bb, 
   if (add_to_bb)
     add_ref_to_list_end (bb_refs (bb), ref);
 
-  /* If this is an unmodified V_DEF reference, then this reference
-     represents the output of its parent statement (i.e., the reference is
-     the LHS of an assignment).  In this case, tell the parent statement
-     about it.
-
-     This is useful for algorithms like constant propagation when
-     evaluating expressions, the output reference for the expression is
-     where the lattice value of the expression can be stored.  */
-  if (ref_type == V_DEF
-      && ref_mod == 0
-      && !TREE_NOT_GIMPLE (parent_stmt))
-    set_output_ref (parent_stmt, ref);
-
   return ref;
 }
 
@@ -1021,33 +968,119 @@ add_referenced_var (var)
 			     Code replacement
 ---------------------------------------------------------------------------*/
 
-/* Replace the operand for a reference with a new operand.
+/* Replace reference REF in statement STMT with a new variable or constant OP.
 
    FIXME: Need to properly update DFA information (create new references,
    update SSA links, etc).  */
 
 void
-replace_ref_operand_with (ref, op)
+replace_ref_in (stmt, ref, op)
+     tree stmt;
      tree_ref ref;
      tree op;
 {
-  if (ref->common.operand_p)
-    *(ref->common.operand_p) = op;
-}
+  enum tree_code code;
+  struct replace_data_d replace_data;
 
+  STRIP_WFL (stmt);
+  STRIP_NOPS (stmt);
 
-/* Replace the expression for a reference with a new expression.
+#if defined ENABLE_CHECKING
+  if (!really_constant_p (op) && !DECL_P (op))
+    abort ();
 
-   FIXME: Need to properly update DFA information (create new references,
-   update SSA links, etc).  */
+  if (ref_type (ref) != V_DEF && ref_type (ref) != V_USE)
+    abort ();
 
-void
-replace_ref_expr_with (ref, expr)
-     tree_ref ref;
-     tree expr;
+  if (ref_type (ref) == V_DEF && !DECL_P (op))
+    abort ();
+
+  if (DECL_P (stmt))
+    abort ();
+#endif
+
+  replace_data.old = ref_var (ref);
+  replace_data.new = op;
+  code = TREE_CODE (stmt);
+  switch (code)
+    {
+    case INIT_EXPR:
+    case MODIFY_EXPR:
+      if (ref_type (ref) == V_DEF)
+	walk_tree (&TREE_OPERAND (stmt, 0), replace_ref_r, &replace_data, NULL);
+      else
+	walk_tree (&TREE_OPERAND (stmt, 1), replace_ref_r, &replace_data, NULL);
+      break;
+
+    case CALL_EXPR:
+      walk_tree (&TREE_OPERAND (stmt, 0), replace_ref_r, &replace_data, NULL);
+      walk_tree (&TREE_OPERAND (stmt, 1), replace_ref_r, &replace_data, NULL);
+      break;
+
+    case COND_EXPR:
+      walk_tree (&COND_EXPR_COND (stmt), replace_ref_r, &replace_data, NULL);
+      break;
+
+    case SWITCH_EXPR:
+      walk_tree (&SWITCH_COND (stmt), replace_ref_r, &replace_data, NULL);
+      break;
+
+    case ASM_EXPR:
+      if (ref_type (ref) == V_USE)
+	walk_tree (&ASM_INPUTS (stmt), replace_ref_r, &replace_data, NULL);
+      else
+	{
+	  walk_tree (&ASM_OUTPUTS (stmt), replace_ref_r, &replace_data, NULL);
+	  walk_tree (&ASM_CLOBBERS (stmt), replace_ref_r, &replace_data, NULL);
+	}
+      break;
+
+    case RETURN_EXPR:
+      walk_tree (&TREE_OPERAND (stmt, 0), replace_ref_r, &replace_data, NULL);
+      break;
+
+    case GOTO_EXPR:
+      walk_tree (&GOTO_DESTINATION (stmt), replace_ref_r, &replace_data, NULL);
+      break;
+
+    case LABEL_EXPR:
+      walk_tree (&LABEL_EXPR_LABEL (stmt), replace_ref_r, &replace_data, NULL);
+      break;
+
+      /* These nodes contain no variable references.  */
+    case LOOP_EXPR:
+    case BIND_EXPR:
+    case CASE_LABEL_EXPR:
+      break;
+
+    default:
+      abort ();
+    }
+}
+
+
+/* Call back for walk_tree to replace references in expression *TP.  */
+
+static tree
+replace_ref_r (tp, walk_subtrees, data)
+     tree *tp;
+     int *walk_subtrees ATTRIBUTE_UNUSED;
+     void *data;
 {
-  if (ref->common.expr_p)
-    *(ref->common.expr_p) = expr;
+  struct replace_data_d *replace_data = (struct replace_data_d *)data;
+  tree t = *tp;
+  tree old = replace_data->old;
+  tree new = replace_data->new;
+
+  /* INDIRECT_REF nodes cannot be compared directly.  */
+  if (TREE_CODE (old) == INDIRECT_REF
+      && TREE_CODE (t) == INDIRECT_REF
+      && TREE_OPERAND (old, 0) == TREE_OPERAND (t, 0))
+    *tp = new;
+  else if (old == t)
+    *tp = new;
+
+  return NULL_TREE;
 }
 
 
@@ -1166,8 +1199,8 @@ dump_ref (outf, prefix, ref, indent, det
 
   fprintf (outf, "): line %d, bb %d, id %lu, ", lineno, bbix, ref_id (ref));
 
-  if (ref_expr (ref))
-    print_generic_expr (outf, ref_expr (ref), 0);
+  if (ref_stmt (ref))
+    print_generic_stmt (outf, ref_stmt (ref), TDF_SLIM);
   else
     fprintf (outf, "<nil>");
 
@@ -1772,10 +1805,9 @@ clobber_vars_r (tp, walk_subtrees, data)
   /* Create may-use and clobber references for every *_DECL in sight.  */
   if (code == VAR_DECL || code == PARM_DECL)
     {
-      create_ref (*tp, V_USE, TRM_MAY, clobber->bb, clobber->parent_stmt_p,
-		  clobber->parent_expr_p, NULL, 1);
+      create_ref (*tp, V_USE, TRM_MAY, clobber->bb, clobber->parent_stmt_p, 1);
       create_ref (*tp, V_DEF, TRM_CLOBBER, clobber->bb, clobber->parent_stmt_p,
-		  clobber->parent_expr_p, NULL, 1); 
+		  1);
     }
 
   return NULL;
@@ -1849,8 +1881,7 @@ may_alias_p (ptr, var_sym)
   if (var_sym == ptr_sym
       || !POINTER_TYPE_P (TREE_TYPE (ptr_sym))
       || !TREE_ADDRESSABLE (var_sym)
-      || DECL_ARTIFICIAL (var_sym)
-      || !is_visible_to (var_sym, ptr_sym))
+      || DECL_ARTIFICIAL (var_sym))
     return false;
 
   ptr_alias_set = get_alias_set (TREE_TYPE (ptr));
@@ -1889,23 +1920,6 @@ find_may_aliases_for (ptr)
 }
 
 
-
-
-/* Return true if SYM1 and SYM2 are visible to each other.  Visibility is
-   determined based on the scopes where each variable is declared.  Both
-   scopes must be the same or one must be enclosed in the other.  */
-
-static bool
-is_visible_to (sym1, sym2)
-     tree sym1;
-     tree sym2;
-{
-  /* FIXME  This should be implemented by traversing the SUPERCONTEXT and
-     SUBBLOCKS links for the each symbol's BIND_EXPR node.  */
-  return true;
-}
-
-
 /* Return true if REF is a V_DEF reference for VAR.  This function handles
    relocations of pointers.  Relocating a pointer, clobbers any dereference
    of the pointer, but it does not affect any of its aliases.  For
@@ -1957,13 +1971,13 @@ is_killing_def (def, use)
   tree use_var = ref_var (use);
 
   if ((ref_type (def) != V_DEF && ref_type (def) != V_PHI)
-      || ref_type (use) != V_USE)
+      || (ref_type (use) != V_USE && ref_type (use) != V_PHI))
     return false;
 
   /* Partial, potential and volatile definitions are no killers.  */
-  if (is_partial_def (def)
-      || is_volatile_def (def)
-      || is_may_def (def))
+  if (is_partial_ref (def)
+      || is_volatile_ref (def)
+      || is_may_ref (def))
     return false;
 
   /* Common case.  Both references are for the same variable.  */
@@ -2111,6 +2125,29 @@ find_decl_location (decl, block)
       tree *loc = find_decl_location (decl, sub);
       if (loc)
 	return loc;
+    }
+
+  return NULL;
+}
+
+
+/* Return the V_DEF reference at the LHS of an assignment statement T.  */
+
+tree_ref
+output_ref (t)
+     tree t;
+{
+  STRIP_WFL (t);
+  STRIP_NOPS (t);
+  if (is_assignment_stmt (t))
+    {
+      ref_list_iterator i;
+      for (i = rli_start (tree_refs (t)); !rli_after_end (i); rli_step (&i))
+	{
+	  tree_ref def = rli_ref (i);
+	  if (ref_type (def) == V_DEF && !def->vdef.m_clobber)
+	    return def;
+	}
     }
 
   return NULL;
Index: tree-flow-inline.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow-inline.h,v
retrieving revision 1.1.2.11
diff -d -u -p -r1.1.2.11 tree-flow-inline.h
--- tree-flow-inline.h	6 Nov 2002 22:22:34 -0000	1.1.2.11
+++ tree-flow-inline.h	7 Nov 2002 04:37:47 -0000
@@ -47,13 +47,6 @@ ref_bb (ref)
 }
 
 static inline tree
-ref_expr (ref)
-     tree_ref ref;
-{
-  return ref->common.expr_p ? *(ref->common.expr_p) : NULL_TREE;
-}
-
-static inline tree
 ref_stmt (ref)
      tree_ref ref;
 {
@@ -176,14 +169,6 @@ set_phi_arg (phi, i, arg)
   VARRAY_GENERIC_PTR (phi->vphi.phi_args, i) = (PTR)arg;
 }
 
-static inline void
-restore_ref_operand (ref)
-     tree_ref ref;
-{
-  if (ref->common.operand_p)
-    *(ref->common.operand_p) = ref->common.orig_operand;
-}
-  
 static inline tree_ann
 tree_annotation (t)
      tree t;
@@ -325,32 +310,6 @@ get_filename (expr)
     return "???";
 }
 
-static inline tree_ref
-output_ref (t)
-     tree t;
-{
-  return tree_annotation (t) ? tree_annotation (t)->output_ref : NULL;
-}
-
-static inline void
-set_output_ref (t, def)
-     tree t;
-     tree_ref def;
-{
-  tree_ann ann;
-#if defined ENABLE_CHECKING
-  {
-    tree w = t;
-    STRIP_WFL (w);
-    STRIP_NOPS (w);
-    if (TREE_CODE (w) != MODIFY_EXPR && TREE_CODE (w) != INIT_EXPR)
-      abort ();
-  }
-#endif
-  ann = tree_annotation (t) ? tree_annotation (t) : create_tree_ann (t);
-  ann->output_ref = def;
-}
-
 static inline void
 set_tree_flag (t, flag)
      tree t;
@@ -772,6 +731,15 @@ is_exec_stmt (t)
 }
 
 static inline bool
+is_assignment_stmt (t)
+     tree t;
+{
+  STRIP_WFL (t);
+  STRIP_NOPS (t);
+  return (TREE_CODE (t) == MODIFY_EXPR || TREE_CODE (t) == INIT_EXPR);
+}
+
+static inline bool
 is_may_ref (ref)
      tree_ref ref;
 {
@@ -782,14 +750,14 @@ static inline bool
 is_may_def (ref)
      tree_ref ref;
 {
-  return is_may_ref (ref) && ref_type (ref) == V_DEF;
+  return ref_type (ref) == V_DEF && is_may_ref (ref);
 }
 
 static inline bool
 is_may_use (ref)
      tree_ref ref;
 {
-  return is_may_ref (ref) && ref_type (ref) == V_USE;
+  return ref_type (ref) == V_USE && is_may_ref (ref);
 }
 
 static inline bool
@@ -803,14 +771,14 @@ static inline bool
 is_partial_def (ref)
      tree_ref ref;
 {
-  return is_partial_ref (ref) && ref_type (ref) == V_DEF;
+  return ref_type (ref) == V_DEF && is_partial_ref (ref);
 }
 
 static inline bool
 is_partial_use (ref)
      tree_ref ref;
 {
-  return is_partial_ref (ref) && ref_type (ref) == V_USE;
+  return ref_type (ref) == V_USE && is_partial_ref (ref);
 }
 
 static inline bool
@@ -824,60 +792,74 @@ static inline bool
 is_volatile_def (ref)
      tree_ref ref;
 {
-  return is_volatile_ref (ref) && ref_type (ref) == V_DEF;
+  return ref_type (ref) == V_DEF && is_volatile_ref (ref);
 }
 
 static inline bool
 is_volatile_use (ref)
      tree_ref ref;
 {
-  return is_volatile_ref (ref) && ref_type (ref) == V_USE;
+  return ref_type (ref) == V_USE && is_volatile_ref (ref);
 }
 
 static inline bool
 is_default_def (ref)
      tree_ref ref;
 {
-  return ref->vdef.m_default && ref_type (ref) == V_DEF;
+  return ref_type (ref) == V_DEF && ref->vdef.m_default;
 }
 
 static inline bool
 is_clobbering_def (ref)
      tree_ref ref;
 {
-  return ref->vdef.m_clobber && ref_type (ref) == V_DEF;
+  return ref_type (ref) == V_DEF && ref->vdef.m_clobber;
 }
 
 static inline bool
 is_initializing_def (ref)
      tree_ref ref;
 {
-  return ref->vdef.m_initial && ref_type (ref) == V_DEF;
+  return ref_type (ref) == V_DEF && ref->vdef.m_initial;
 }
 
 static inline bool
 is_relocating_def (ref)
      tree_ref ref;
 {
-  return ref->vdef.m_relocate && ref_type (ref) == V_DEF;
+  return ref_type (ref) == V_DEF && ref->vdef.m_relocate;
 }
 
 static inline bool
 is_addressof_use (ref)
      tree_ref ref;
 {
-  return ref->vuse.m_addressof && ref_type (ref) == V_USE;
+  return ref_type (ref) == V_USE && ref->vuse.m_addressof;
 }
 
 static inline bool
 is_pure_use (ref)
      tree_ref ref;
 {
-  return !ref->vuse.m_addressof
+  return ref_type (ref) == V_USE
+	 && !ref->vuse.m_addressof
          && !is_may_ref (ref)
 	 && !is_partial_ref (ref)
-	 && !is_volatile_ref (ref)
-	 && ref_type (ref) == V_USE;
+	 && !is_volatile_ref (ref);
+}
+
+static inline bool
+is_pure_def (ref)
+     tree_ref ref;
+{
+  return ref_type (ref) == V_DEF
+	 && !ref->vdef.m_default
+	 && !ref->vdef.m_clobber
+	 && !ref->vdef.m_initial
+	 && !ref->vdef.m_relocate
+         && !is_may_ref (ref)
+	 && !is_partial_ref (ref)
+	 && !is_volatile_ref (ref);
 }
 
 /* Return TRUE if we reached the end of the list with iterator I.  */
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.33
diff -d -u -p -r1.1.4.33 tree-flow.h
--- tree-flow.h	6 Nov 2002 22:22:34 -0000	1.1.4.33
+++ tree-flow.h	7 Nov 2002 04:37:47 -0000
@@ -46,11 +46,7 @@ enum tree_ref_type {
      represents a killing definition of the associated variable via an
      assignment expression (i.e., all the bits of the variable are
      modified).  Note that unmodified V_DEF references are only allowed for
-     MODIFY_EXPR and INIT_EXPR expressions.
-
-     In this case, this reference will represent the output value of the
-     associated expression.  For instance, 'a = 3' creates a V_DEF
-     reference for 'a' and calling output_ref('a = 3') returns this V_DEF.  */
+     MODIFY_EXPR and INIT_EXPR expressions.  */
   V_DEF,
 
   /* A V_USE reference represents a read operation from the associated
@@ -120,28 +116,14 @@ struct tree_ref_common GTY(())
   /* Reference type.  */
   enum tree_ref_type type;
 
-  /* Variable being referenced.  This may be a _DECL or an INDIRECT_REF
-     node.  */
+  /* Variable being referenced.  This may be a _DECL, an INDIRECT_REF
+     node or an expression (in the case of E_* references).  */
   tree var;
 
   /* Statement containing the reference.  Maybe NULL for special references
      (e.g., default definitions inserted at the start of every function).  */
   tree * GTY((skip (""))) stmt_p;
 
-  /* Expression tree containing the reference.  Maybe NULL for special
-     references (e.g., default definitions inserted at the start of every
-     function).  */
-  tree * GTY((skip (""))) expr_p;
-
-  /* Pointer to operand of EXPR containing VAR.  Used when substituting the
-     operand with some other value in transformations like constant
-     propagation.  Maybe NULL for special references (e.g., default
-     definitions inserted at the start of every function).  */
-  tree * GTY((skip (""))) operand_p;
-
-  /* Original value stored in *OPERAND_P.  Used by restore_ref_operand.  */
-  tree orig_operand;
-
   /* Basic block containing the reference.  */
   basic_block GTY((skip (""))) bb;
 
@@ -395,12 +377,9 @@ typedef union tree_ref_d *tree_ref;
 static inline enum tree_ref_type ref_type	PARAMS ((tree_ref));
 static inline tree ref_var			PARAMS ((tree_ref));
 static inline tree ref_stmt			PARAMS ((tree_ref));
-static inline tree ref_expr			PARAMS ((tree_ref));
 static inline basic_block ref_bb		PARAMS ((tree_ref));
 static inline unsigned long ref_id		PARAMS ((tree_ref));
-static inline void restore_ref_operand		PARAMS ((tree_ref));
-extern void replace_ref_operand_with		PARAMS ((tree_ref, tree));
-extern void replace_ref_expr_with		PARAMS ((tree_ref, tree));
+extern void replace_ref_in			PARAMS ((tree, tree_ref, tree));
 extern void replace_ref_stmt_with		PARAMS ((tree_ref, tree));
 
 
@@ -433,6 +412,7 @@ static inline bool is_initializing_def		
 static inline bool is_relocating_def		PARAMS ((tree_ref));
 static inline bool is_addressof_use		PARAMS ((tree_ref));
 static inline bool is_pure_use			PARAMS ((tree_ref));
+static inline bool is_pure_def			PARAMS ((tree_ref));
 
 /* For phi_node_arg.  */
 static inline edge phi_arg_edge			PARAMS ((phi_node_arg));
@@ -511,10 +491,6 @@ struct tree_ann_d GTY(())
   /* Flags used to mark optimization-dependent state.  See TF_* below.  */
   HOST_WIDE_INT flags;
 
-  /* Output reference.  This is the V_DEF reference at the LHS of
-     assignments (MODIFY_EXPR and INIT_EXPR).  */
-  tree_ref output_ref;
-
   /* Set of variables that may be aliases of this variable.  */
   varray_type may_aliases;
 };
@@ -546,8 +522,6 @@ static inline void set_tree_flag	PARAMS 
 static inline void clear_tree_flag	PARAMS ((tree, enum tree_flags));
 static inline enum tree_flags tree_flags PARAMS ((tree));
 static inline void reset_tree_flags	PARAMS ((tree));
-static inline tree_ref output_ref	PARAMS ((tree));
-static inline void set_output_ref	PARAMS ((tree, tree_ref));
 static inline tree indirect_var		PARAMS ((tree));
 static inline void set_indirect_var	PARAMS ((tree, tree));
 static inline tree may_alias		PARAMS ((tree, size_t));
@@ -555,6 +529,7 @@ static inline size_t num_may_alias	PARAM
 static inline int get_lineno		PARAMS ((tree));
 static inline const char *get_filename	PARAMS ((tree));
 static inline bool is_exec_stmt		PARAMS ((tree));
+static inline bool is_assignment_stmt	PARAMS ((tree));
 
 
 /*---------------------------------------------------------------------------
@@ -679,6 +654,7 @@ extern tree last_stmt			PARAMS ((basic_b
 extern tree *last_stmt_ptr			PARAMS ((basic_block));
 extern basic_block latch_block		PARAMS ((basic_block));
 extern bool is_latch_block		PARAMS ((basic_block));
+extern edge find_taken_edge		PARAMS ((basic_block, tree));
 
 
 /* In tree-dfa.c  */
@@ -687,7 +663,7 @@ extern void find_refs_in_stmt           
 extern tree_ann create_tree_ann 	PARAMS ((tree));
 extern tree_ref create_ref		PARAMS ((tree, enum tree_ref_type,
       						 unsigned, basic_block, tree *,
-						 tree *, tree *, int));
+						 int));
 extern void debug_ref			PARAMS ((tree_ref));
 extern void dump_ref			PARAMS ((FILE *, const char *, tree_ref,
       						 int, int));
@@ -726,8 +702,9 @@ extern bool ref_defines			PARAMS ((tree_
 extern bool is_killing_def		PARAMS ((tree_ref, tree_ref));
 extern int get_alias_index		PARAMS ((tree, tree));
 extern enum tree_ref_structure_enum tree_ref_structure PARAMS ((tree_ref));
-void remove_decl			PARAMS ((tree));
-tree * find_decl_location		PARAMS ((tree, tree));
+extern void remove_decl			PARAMS ((tree));
+extern tree * find_decl_location	PARAMS ((tree, tree));
+extern tree_ref output_ref		PARAMS ((tree));
 
 
 /* In tree-ssa.c  */
Index: tree-ssa-ccp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-ccp.c,v
retrieving revision 1.1.2.29
diff -d -u -p -r1.1.2.29 tree-ssa-ccp.c
--- tree-ssa-ccp.c	5 Nov 2002 23:50:39 -0000	1.1.2.29
+++ tree-ssa-ccp.c	7 Nov 2002 04:37:47 -0000
@@ -45,6 +45,7 @@ Software Foundation, 59 Temple Place - S
 #include "hard-reg-set.h"
 #include "basic-block.h"
 #include "diagnostic.h"
+#include "tree-inline.h"
 #include "tree-flow.h"
 #include "tree-simple.h"
 
@@ -88,27 +89,28 @@ static struct edge_list *edges;
    nodes that need to be visited are accessed using imm_uses (D).  */
 ref_list ssa_edges;
 
-static void initialize                 PARAMS ((void));
-static void finalize                   PARAMS ((void));
-static void visit_phi_node             PARAMS ((tree_ref));
-static value cp_lattice_meet           PARAMS ((value, value));
-static void visit_expression_for       PARAMS ((tree_ref));
-static void visit_condexpr_for         PARAMS ((tree_ref));
-static void visit_assignment_for       PARAMS ((tree_ref));
-static void add_outgoing_control_edges PARAMS ((basic_block));
-static void add_control_edge           PARAMS ((edge));
-static void def_to_undefined           PARAMS ((tree_ref));
-static void def_to_varying             PARAMS ((tree_ref));
-static void set_lattice_value          PARAMS ((tree_ref, value));
-static void simulate_block             PARAMS ((basic_block));
-static void simulate_def_use_chains    PARAMS ((tree_ref));
-static void substitute_and_fold        PARAMS ((void));
-static value evaluate_expr             PARAMS ((tree));
-static void dump_lattice_value         PARAMS ((FILE *, const char *, value));
-static tree widen_bitfield             PARAMS ((tree, tree, tree));
-static void replace_uses_in            PARAMS ((tree));
-static void restore_expr               PARAMS ((tree));
-static tree ccp_fold                   PARAMS ((tree));
+static void initialize			PARAMS ((void));
+static void finalize			PARAMS ((void));
+static void visit_phi_node		PARAMS ((tree_ref));
+static value cp_lattice_meet		PARAMS ((value, value));
+static void visit_stmt			PARAMS ((tree));
+static void visit_cond_stmt		PARAMS ((tree));
+static void visit_assignment		PARAMS ((tree));
+static void add_outgoing_control_edges	PARAMS ((basic_block));
+static void add_control_edge		PARAMS ((edge));
+static void def_to_undefined		PARAMS ((tree_ref));
+static void def_to_varying		PARAMS ((tree_ref));
+static void set_lattice_value		PARAMS ((tree_ref, value));
+static void simulate_block		PARAMS ((basic_block));
+static void simulate_def_use_chains	PARAMS ((tree_ref));
+static void substitute_and_fold		PARAMS ((void));
+static value evaluate_stmt		PARAMS ((tree));
+static void dump_lattice_value		PARAMS ((FILE *, const char *, value));
+static tree widen_bitfield		PARAMS ((tree, tree, tree));
+static bool replace_uses_in		PARAMS ((tree));
+static void fold_stmt			PARAMS ((tree));
+static tree get_rhs			PARAMS ((tree));
+static void set_rhs			PARAMS ((tree, tree));
 
 
 /* Debugging dumps.  */
@@ -137,7 +139,6 @@ tree_ssa_ccp (fndecl)
 	{
 	  /* Pull the next block to simulate off the worklist.  */
 	  basic_block dest_block;
-
 	  dest_block = ((edge)VARRAY_TOP_GENERIC_PTR (edge_info))->dest;
 	  VARRAY_POP (edge_info);
 	  simulate_block (dest_block);
@@ -177,7 +178,7 @@ tree_ssa_ccp (fndecl)
 }
 
 
-/* Simulate the execution of BLOCK.  Evaluate the expression associated
+/* Simulate the execution of BLOCK.  Evaluate the statement associated
    with each variable reference inside the block.  */
 
 static void
@@ -191,53 +192,43 @@ simulate_block (block)
   if (block == EXIT_BLOCK_PTR)
     return;
 
-  /* Similarly, if the block contains no references, we have nothing to do.  */
-  blockrefs = bb_refs (block);
-  if (blockrefs == NULL)
-    return;
+#if defined ENABLE_CHECKING
+  if (block->index < 0 || block->index > last_basic_block)
+    abort ();
+#endif
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "\nSimulating block %d\n", block->index);
 
   /* Always simulate PHI nodes, even if we have simulated this block
      before.  Note that all PHI nodes are consecutive within a block.  */
+  blockrefs = bb_refs (block);
   for (i = rli_start (blockrefs); !rli_after_end (i); rli_step (&i))
     if (ref_type (rli_ref (i)) == V_PHI)
       visit_phi_node (rli_ref (i));
 
-#if defined ENABLE_CHECKING
-  if (block->index < 0 || block->index > last_basic_block)
-    abort ();
-#endif
-
   /* If this is the first time we've simulated this block, then we
-     must simulate each of its insns.  */
+     must simulate each of its statements.  */
   if (!TEST_BIT (executable_blocks, block->index))
     {
-      edge succ_edge = block->succ;
+      gimple_stmt_iterator j;
 
       /* Note that we have simulated this block.  */
       SET_BIT (executable_blocks, block->index);
 
-      for (i = rli_start (blockrefs); !rli_after_end (i); rli_step (&i))
-	{
-	  /* Simulate each reference within the block.  */
-	  if (ref_type (rli_ref (i)) != V_PHI)
-	    visit_expression_for (rli_ref (i));
-	} 
+      for (j = gsi_start_bb (block); !gsi_after_end (j); gsi_step_bb (&j))
+	visit_stmt (gsi_stmt (j));
 
-      /* If we haven't looked at the next block, and it has a
-	 single successor, add it onto the worklist.  This is because
-	 if we only have one successor, we know it gets executed,
-	 so we don't have to wait for cprop to tell us. */
-      if (succ_edge && succ_edge->succ_next == NULL)
-	add_control_edge (succ_edge);
+      /* If the block has a single successor, it will always get executed.
+	 Add it to the worklist.  */
+      if (block->succ && block->succ->succ_next == NULL)
+	add_control_edge (block->succ);
     }
 }
 
 
 /* Follow the def-use chains for definition DEF and simulate all the
-   expressions reached by it.  */
+   statements reached by it.  */
 
 static void
 simulate_def_use_chains (def)
@@ -253,11 +244,13 @@ simulate_def_use_chains (def)
     {
       tree_ref ref = rli_ref (i);
 
-      /* Note that we only visit unmodified V_USE references.  We don't
-	 want to deal with any modifiers here.  */
+      /* Visit the statement containing the use reached by DEF, only if the
+	 destination block is marked executable.  Note that we only visit
+	 unmodified V_USE references.  We don't want to deal with any
+	 modifiers here.  */
       if (is_pure_use (ref)
 	  && TEST_BIT (executable_blocks, ref_bb (ref)->index))
-	visit_expression_for (ref);
+	visit_stmt (ref_stmt (ref));
 
       /* PHI nodes are always visited, regardless of whether or not the
 	 destination block is executable.  */
@@ -275,52 +268,40 @@ substitute_and_fold ()
   basic_block bb;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "\nSubstituing constants and folding expressions\n\n");
+    fprintf (dump_file, "\nSubstituing constants and folding statements\n\n");
 
-  /* Substitute constants in every expression of every basic block.  */
+  /* Substitute constants in every statement of every basic block.  */
   FOR_EACH_BB (bb)
     {
-      tree new_expr;
-      ref_list_iterator i;
+      gimple_stmt_iterator i;
 
-      for (i = rli_start (bb_refs (bb)); !rli_after_end (i); rli_step (&i))
+      for (i = gsi_start_bb (bb); !gsi_after_end (i); gsi_step_bb (&i))
 	{
-	  tree_ref ref = rli_ref (i);
-	  tree expr = ref_expr (ref);
-	  tree stmt = ref_stmt (ref);
-
-	  /* Skip references not attached to statements and expressions.  */
-	  if (expr == NULL_TREE)
-	    continue;
-
-	  /* We are only interested in expressions that contain unmodified
-	     V_USE references.  */
-	  if (!is_pure_use (ref))
-	    continue;
+	  tree stmt = gsi_stmt (i);
 
 	  /* Skip statements that have been folded already.  */
-	  if (tree_flags (stmt) & TF_FOLDED)
+	  if (tree_flags (stmt) & TF_FOLDED
+	      || !is_exec_stmt (stmt))
 	    continue;
 
-	  /* Replace the expression with its folded version in the statement
-	     and mark it folded.  Note that in the case of assignment
-	     expressions, we fold their RHS (fold() does not handle
-	     assignments).  */
+	  /* Replace the statement with its folded version and mark it
+	     folded.  */
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    {
-	      fprintf (dump_file, "Line %d: replaced ", get_lineno (expr));
-	      print_generic_stmt (dump_file, expr, TDF_SLIM);
+	      fprintf (dump_file, "Line %d: replaced ", get_lineno (stmt));
+	      print_generic_stmt (dump_file, stmt, TDF_SLIM);
 	    }
 
-	  replace_uses_in (expr);
-	  new_expr = ccp_fold (expr);
-	  replace_ref_expr_with (ref, new_expr);
-	  set_tree_flag (stmt, TF_FOLDED);
+	  if (replace_uses_in (stmt))
+	    {
+	      fold_stmt (stmt);
+	      set_tree_flag (stmt, TF_FOLDED);
+	    }
 
 	  if (dump_file && (dump_flags & TDF_DETAILS))
 	    {
 	      fprintf (dump_file, " with ");
-	      print_generic_stmt (dump_file, new_expr, TDF_SLIM);
+	      print_generic_stmt (dump_file, stmt, TDF_SLIM);
 	      fprintf (dump_file, "\n");
 	    }
 	}
@@ -346,41 +327,55 @@ visit_phi_node (phi_node)
   phi_val.lattice_val = UNDEFINED;
   phi_val.const_value = NULL_TREE;
 
-  /* Compute the meet operator over all the PHI arguments. */
-  for (i = 0; i < num_phi_args (phi_node); i++)
-    {
-      phi_node_arg arg = phi_arg (phi_node, i);
-      edge e = phi_arg_edge (arg);
+  if (!is_volatile_ref (phi_node))
+    for (i = 0; i < num_phi_args (phi_node); i++)
+      {
+	/* Compute the meet operator over all the PHI arguments. */
 
-      if (dump_file && (dump_flags & TDF_DETAILS))
-	{
-	  fprintf (dump_file, "\n    Argument #%d (%d -> %d %sexecutable)\n",
-	           i, e->src->index, e->dest->index,
-		   (e->flags & EDGE_EXECUTABLE) ? "" : "not ");
-	}
+	phi_node_arg arg = phi_arg (phi_node, i);
+	edge e = phi_arg_edge (arg);
 
-      /* If the incoming edge is executable, Compute the meet operator for
-	 the existing value of the PHI node and the current PHI argument.  */
-      if (e->flags & EDGE_EXECUTABLE)
-	{
-	  tree_ref rdef;
-	  value rdef_val;
-	  
-	  rdef = phi_arg_def (arg);
-	  rdef_val = values[ref_id (rdef)];
-	  phi_val = cp_lattice_meet (phi_val, rdef_val);
+	if (dump_file && (dump_flags & TDF_DETAILS))
+	  {
+	    fprintf (dump_file, "\n    Argument #%d (%d -> %d %sexecutable)\n",
+		    i, e->src->index, e->dest->index,
+		    (e->flags & EDGE_EXECUTABLE) ? "" : "not ");
+	  }
 
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    {
-	      dump_ref (dump_file, "\t", phi_arg_def (arg), 0, 0);
-	      dump_lattice_value (dump_file, "\tValue: ", rdef_val);
-	      fprintf (dump_file, "\n");
-	    }
+	/* If the incoming edge is executable, Compute the meet operator for
+	   the existing value of the PHI node and the current PHI argument.  */
+	if (e->flags & EDGE_EXECUTABLE)
+	  {
+	    tree_ref rdef;
+	    value rdef_val;
+	    
+	    rdef = phi_arg_def (arg);
 
-	  if (phi_val.lattice_val == VARYING)
-	    break;
-	}
-    }
+	    if (is_killing_def (rdef, phi_node))
+	      {
+		rdef_val = values[ref_id (rdef)];
+		phi_val = cp_lattice_meet (phi_val, rdef_val);
+	      }
+	    else
+	      {
+		/* If RDEF is a non-killing definition, we cannot assume
+		   anything about this PHI's node value.  In that case, set
+		   its value to VARYING.  */
+		phi_val.lattice_val = VARYING;
+		phi_val.const_value = NULL_TREE;
+	      }
+
+	    if (dump_file && (dump_flags & TDF_DETAILS))
+	      {
+		dump_ref (dump_file, "\t", phi_arg_def (arg), 0, 0);
+		dump_lattice_value (dump_file, "\tValue: ", rdef_val);
+		fprintf (dump_file, "\n");
+	      }
+
+	    if (phi_val.lattice_val == VARYING)
+	      break;
+	  }
+      }
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -436,99 +431,73 @@ cp_lattice_meet (val1, val2)
 }
 
 
-/* Evaluate the expression associated with REF.  If the expression produces
-   an output value and its evaluation changes the lattice value of its
-   output, do the following:
+/* Evaluate statement STMT.  If the statement produces an output value and
+   its evaluation changes the lattice value of its output, do the following:
 
-   - If the expression is an assignment, add all the SSA edges starting at
+   - If the statement is an assignment, add all the SSA edges starting at
      this definition.
 
-   - If the expression controls a conditional branch:
-   	. If the expression evaluates to non-constant, add all edges to
+   - If the statement is a conditional branch:
+   	. If the statement evaluates to non-constant, add all edges to
 	  worklist.
-	. If the expression is constant, add the edge executed as the
+	. If the statement is constant, add the edge executed as the
 	  result of the branch.  */
 
 static void
-visit_expression_for (ref)
-     tree_ref ref;
+visit_stmt (stmt)
+     tree stmt;
 {
-  tree expr;
-
-#if defined ENABLE_CHECKING
-  /* PHI references should be handled by visit_phi_node.  */
-  if (ref_type (ref) == V_PHI)
-    abort ();
-#endif
-
-  /* First examine the reference to see if it's a special definition
-     (clobbering, partial or may-def), mark it varying and add SSA edges
-     that may be coming out of it.  */
-  if (is_clobbering_def (ref)
-      || is_partial_def (ref)
-      || is_may_def (ref)
-      || is_relocating_def (ref))
-    def_to_varying (ref);
-
-  expr = ref_expr (ref);
-  
-  /* No need to do anything if the reference is not associated with an
-     expression.  */
-  if (expr == NULL)
+  /* FIXME: This is lame.  All statements should be in GIMPLE form.  */
+  if (TREE_NOT_GIMPLE (stmt))
     return;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
-      fprintf (dump_file, "\nVisiting expression: ");
-      print_generic_expr (dump_file, expr, 0);
-      dump_ref (dump_file, "\nfor reference: ", ref, 0, 0);
+      fprintf (dump_file, "\nVisiting statement: ");
+      print_generic_stmt (dump_file, stmt, TDF_SLIM);
+      fprintf (dump_file, "\n");
     }
   
-  /* Now examine the expression.  If the expression produces an output
-     value, evaluate the expression to see if the lattice value of its
-     output has changed.  */
-  if (output_ref (expr))
-    visit_assignment_for (ref);
+  /* Now examine the statement.  If the statement produces an output
+     value, evaluate it to see if the lattice value of its output has
+     changed.  */
+  if (is_assignment_stmt (stmt))
+    visit_assignment (stmt);
 
-  /* If the expression is the predicate of a control statement, see if we
-     can determine which branch will be taken.  */
-  else if (is_simple_condexpr (expr) && ref_bb (ref)->flags & BB_CONTROL_EXPR)
-    visit_condexpr_for (ref);
+  /* If STMT is a control statement, see if we can determine which branch
+     will be taken.  */
+  else if (is_ctrl_stmt (stmt))
+    visit_cond_stmt (stmt);
 
-  /* If the expression is a computed goto, mark all the output edges
+  /* If STMT is a computed goto, mark all the output edges
      executable.  */
-  else if (is_computed_goto (ref_stmt (ref)))
-    add_outgoing_control_edges (ref_bb (ref));
+  else if (is_computed_goto (stmt))
+    add_outgoing_control_edges (bb_for_stmt (stmt));
 }
 
 
-/* Visit the assignment expression holding reference REF.  */
+/* Visit the assignment statement STMT.  Set the value of its LHS to the
+   value computed by the RHS.  */
 
 static void
-visit_assignment_for (ref)
-     tree_ref ref;
+visit_assignment (stmt)
+     tree stmt;
 {
-  tree expr;
   value val;
 
-  expr = ref_expr (ref);
-  STRIP_WFL (expr);
-  STRIP_NOPS (expr);
-
 #if defined ENABLE_CHECKING
-  if (TREE_CODE (expr) != MODIFY_EXPR
-      && TREE_CODE (expr) != INIT_EXPR)
+  if (!is_assignment_stmt (stmt))
     abort ();
 #endif
 
-  /* Evaluate the expression.  */
-  val = evaluate_expr (expr);
+  /* Evaluate the statement.  */
+  val = evaluate_stmt (stmt);
 
   /* FIXME: Hack.  If this was a definition of a bitfield, we need to widen
      the constant value into the type of the destination variable.  This
      should not be necessary if GCC represented bitfields properly.  */
   {
-    tree lhs = TREE_OPERAND (expr, 0);
+    tree lhs = TREE_OPERAND (stmt, 0);
     if (val.lattice_val == CONSTANT
 	&& TREE_CODE (lhs) == COMPONENT_REF
 	&& DECL_BIT_FIELD (TREE_OPERAND (lhs, 1)))
@@ -543,55 +512,44 @@ visit_assignment_for (ref)
 	    val.const_value = NULL;
 	  }
       }
-    }
+  }
 
-  /* Set the lattice value of the expression's output.  */
-  set_lattice_value (output_ref (expr), val);
+  /* Set the lattice value of the statement's output.  */
+  set_lattice_value (output_ref (stmt), val);
 }
 
 
-/* Visit the conditional expression that contains reference REF.  If it
-   evaluates to a constant value, mark outgoing edges appropriately.  */
+/* Visit the conditional statement STMT.  If it evaluates to a constant value,
+   mark outgoing edges appropriately.  */
 
 static void
-visit_condexpr_for (ref)
-     tree_ref ref;
+visit_cond_stmt (stmt)
+     tree stmt;
 {
-  edge curredge;
+  edge e;
   value val;
-  basic_block block = ref_bb (ref);
-  tree expr = ref_expr (ref);
-
-  val = evaluate_expr (expr);
+  basic_block block;
 
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      tree t = ref_stmt (ref);
-      STRIP_WFL (t);
-      STRIP_NOPS (t);
-      fprintf (dump_file, "Predicate is for a control statement: %s\n",
-	       tree_code_name[TREE_CODE (t)]);
-      dump_lattice_value (dump_file, "value: ", val);
-      fprintf (dump_file, "\n");
-    }
+#if defined ENABLE_CHECKING
+  if (!is_ctrl_stmt (stmt))
+    abort ();
+#endif
 
-  /* Mark successor blocks on executable edges as executable (if they
-     have not already been marked).   */
-  for (curredge = block->succ; curredge; curredge = curredge->succ_next)
-    {
-      /* If this is an edge for TRUE values but the predicate is false,
-	 then skip it.  */
-      if ((curredge->flags & EDGE_TRUE_VALUE)
-	  && simple_cst_equal (val.const_value, integer_zero_node) == 1)
-	continue;
+  block = bb_for_stmt (stmt);
+  val = evaluate_stmt (stmt);
 
-      /* Similarly for FALSE edges.  */
-      if ((curredge->flags & EDGE_FALSE_VALUE)
-	  && simple_cst_equal (val.const_value, integer_one_node) == 1)
-	continue;
+  /* If the predicate is undefined, do nothing.  */
+  if (val.lattice_val == UNDEFINED)
+    return;
 
-      add_control_edge (curredge);
-    }
+  /* Find which edge out of the conditional block will be taken and add it
+     to the worklist.  If no single edge can be determined statically, add
+     all outgoing edges from BLOCK.  */
+  e = find_taken_edge (block, val.const_value);
+  if (e)
+    add_control_edge (e);
+  else
+    add_outgoing_control_edges (block);
 }
 
 
@@ -627,38 +585,28 @@ add_control_edge (e)
 }
 
 
-/* Evaluate the expression EXPR.  */
+/* Evaluate statement STMT.  */
 
 static value
-evaluate_expr (expr)
-     tree expr;
+evaluate_stmt (stmt)
+     tree stmt;
 {
   value val;
-  tree simplified;
-
-#if defined ENABLE_CHECKING
-  /* FIXME: This test is lame.  All expressions should be in GIMPLE form.  */
-  if (TREE_NOT_GIMPLE (expr))
-    abort ();
-#endif
+  tree simplified, copy;
 
   val.lattice_val = VARYING;
   val.const_value = NULL_TREE;
-  simplified = NULL_TREE;
 
-  /* Replace all V_USE references in the expression with their immediate
-     reaching definition.  */
-  replace_uses_in (expr);
-
-  /* Fold the expression.  */
-  simplified = ccp_fold (deep_copy_node (expr));
-
-  STRIP_WFL (simplified);
-  STRIP_NOPS (simplified);
-  if (TREE_CODE (simplified) == INIT_EXPR
-      || TREE_CODE (simplified) == MODIFY_EXPR)
-    simplified = TREE_OPERAND (simplified, 1);
+  /* Evaluate a copy of the original statement.  */
+  STRIP_WFL (stmt);
+  STRIP_NOPS (stmt);
+  copy = stmt;
+  walk_tree (&copy, copy_tree_r, NULL, NULL);
+  if (replace_uses_in (copy))
+    fold_stmt (copy);
 
+  /* Extract the folded value from the statement.  */
+  simplified = get_rhs (copy);
   if (simplified && really_constant_p (simplified))
     {
       val.lattice_val = CONSTANT;
@@ -668,8 +616,8 @@ evaluate_expr (expr)
   /* Debugging dumps.  */
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
-      fprintf (dump_file, "Expression evaluates to ");
-      print_generic_expr (dump_file, expr, 0);
+      fprintf (dump_file, "Statement evaluates to ");
+      print_generic_stmt (dump_file, copy, TDF_SLIM);
       fprintf (dump_file, " which is ");
       if (val.lattice_val == CONSTANT)
 	{
@@ -684,7 +632,6 @@ evaluate_expr (expr)
       fprintf (dump_file, "\n");
     }
 
-  restore_expr (expr);
 
   return val;
 }
@@ -822,6 +769,14 @@ initialize ()
 		  values[id].const_value = DECL_INITIAL (var);
 		}
 	    }
+
+	  /* Special definitions (clobbering, partial or may-def) are all
+	     considered VARYING.  */
+	  else if (!is_pure_def (r))
+	    {
+	      values[id].lattice_val = VARYING;
+	      values[id].const_value = NULL_TREE;
+	    }
 	}
     }
 
@@ -929,14 +884,15 @@ set_lattice_value (def, val)
 }
 
 
-/* Replace USE reference in the expression EXPR with their immediate reaching
-   definition.  */
+/* Replace USE references in statement STMT with their immediate reaching
+   definition.  Return true if at least one reference was replaced.  */
 
-static void
-replace_uses_in (expr)
-     tree expr;
+static bool
+replace_uses_in (stmt)
+     tree stmt;
 {
-  ref_list refs = tree_refs (expr);
+  bool replaced = false;
+  ref_list refs = tree_refs (stmt);
   ref_list_iterator i;
 
   for (i = rli_start (refs); !rli_after_end (i); rli_step (&i))
@@ -949,8 +905,8 @@ replace_uses_in (expr)
       if (!is_pure_use (use))
 	continue;
 
-      /* The lattice value of a USE reference is the value of its
-	 immediately reaching definition.  */
+      /* The lattice value of a USE reference is the value of its immediately
+	 reaching definition.  */
       rdef = imm_reaching_def (use);
 
       /* We are only interested in killing definitions.  If we are reached
@@ -962,74 +918,78 @@ replace_uses_in (expr)
       rdef_id = ref_id (rdef);
       if (values[rdef_id].lattice_val == CONSTANT)
 	{
-#if defined ENABLE_CHECKING
-	  if (values[rdef_id].const_value == NULL_TREE)
-	    abort ();
-#endif
-	  /* The reference is a constant, substitute it into the
-	     expression.  */
-	  replace_ref_operand_with (use, values[rdef_id].const_value);
-	}
-      else
-	{
-	  /* The reference is not a constant, restore its original value.  */
-	  restore_ref_operand (use);
+	  replace_ref_in (stmt, use, values[rdef_id].const_value);
+	  replaced = true;
 	}
     }
+
+  return replaced;
 }
 
 
-/* Restore expression EXPR to its original form.  */
+/* Fold statement STMT.  */
 
 static void
-restore_expr (expr)
-     tree expr;
+fold_stmt (stmt)
+     tree stmt;
 {
-  ref_list refs = tree_refs (expr);
-  ref_list_iterator i;
+  tree rhs, result;
 
-  for (i = rli_start (refs); !rli_after_end (i); rli_step (&i))
+  STRIP_WFL (stmt);
+  STRIP_NOPS (stmt);
+  rhs = get_rhs (stmt);
+  if (rhs)
     {
-      /* Only restore pure V_USE references (those are the only types
-	 of references changed by replace_uses_in.  */
-      if (is_pure_use (rli_ref (i)))
-	restore_ref_operand (rli_ref (i));
+      result = fold (rhs);
+      set_rhs (stmt, result);
     }
 }
 
 
-/* Fold EXPR.  If EXPR is an assignment, fold its RHS and return a new
-   assignment with the folded RHS (fold does not handle assignment
-   expressions).  */
+/* Get the main expression from statement STMT.  */
 
 static tree
-ccp_fold (expr)
-     tree expr;
+get_rhs (stmt)
+     tree stmt;
 {
-  tree result, to_fold, w_expr;
+  enum tree_code code = TREE_CODE (stmt);
 
-  /* If the expression is an assignment, get its RHS.  */
-  w_expr = expr;
-  STRIP_WFL (w_expr);
-  STRIP_NOPS (w_expr);
-  if (TREE_CODE (w_expr) == MODIFY_EXPR
-      || TREE_CODE (w_expr) == INIT_EXPR)
-    to_fold = TREE_OPERAND (w_expr, 1);
+  if (code == MODIFY_EXPR || code == INIT_EXPR)
+    return TREE_OPERAND (stmt, 1);
+  if (code == COND_EXPR)
+    return COND_EXPR_COND (stmt);
+  else if (code == SWITCH_EXPR)
+    return SWITCH_COND (stmt);
+  else if (code == RETURN_EXPR)
+    return TREE_OPERAND (stmt, 0);
+  else if (code == GOTO_EXPR)
+    return GOTO_DESTINATION (stmt);
+  else if (code == LABEL_EXPR)
+    return LABEL_EXPR_LABEL (stmt);
   else
-    to_fold = expr;
+    return stmt;
+}
 
-  result = fold (to_fold);
 
-  /* If we folded the RHS of the original expression, store the folded
-     expression there and return the original expression (which will have
-     the new folded RHS).  */
-  if (TREE_CODE (w_expr) == MODIFY_EXPR
-      || TREE_CODE (w_expr) == INIT_EXPR)
-    {
-      TREE_OPERAND (w_expr, 1) = result;
-      return expr;
-    }
-  else
-    /* Otherwise, return the folded expression.  */
-    return result;
+/* Set the main expression of STMT to EXPR.  */
+
+static void
+set_rhs (stmt, expr)
+     tree stmt;
+     tree expr;
+{
+  enum tree_code code = TREE_CODE (stmt);
+
+  if (code == MODIFY_EXPR || code == INIT_EXPR)
+    TREE_OPERAND (stmt, 1) = expr;
+  if (code == COND_EXPR)
+    COND_EXPR_COND (stmt) = expr;
+  else if (code == SWITCH_EXPR)
+    SWITCH_COND (stmt) = expr;
+  else if (code == RETURN_EXPR)
+    TREE_OPERAND (stmt, 0) = expr;
+  else if (code == GOTO_EXPR)
+    GOTO_DESTINATION (stmt) = expr;
+  else if (code == LABEL_EXPR)
+    LABEL_EXPR_LABEL (stmt) = expr;
 }
Index: tree-ssa-pre.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-pre.c,v
retrieving revision 1.1.4.32
diff -d -u -p -r1.1.4.32 tree-ssa-pre.c
--- tree-ssa-pre.c	6 Nov 2002 22:22:34 -0000	1.1.4.32
+++ tree-ssa-pre.c	7 Nov 2002 04:37:48 -0000
@@ -772,27 +772,21 @@ insert_occ_in_preorder_dt_order_1 (ei, f
 	{
 	  tree *killexpr  = VARRAY_GENERIC_PTR (ei->kills, i);
 	  
-	  newref = create_ref (*killexpr,
-			       E_KILL, 0, block, killexpr,
-			       killexpr, NULL, true);
+	  newref = create_ref (*killexpr, E_KILL, 0, block, killexpr, 1);
 	  VARRAY_PUSH_GENERIC_PTR (ei->erefs, newref);
 	  fibheap_insert (fh, preorder_count++, newref);
 	}
       else if (VARRAY_GENERIC_PTR (ei->lefts, i) != NULL)
 	{
 	  tree *leftexpr = VARRAY_GENERIC_PTR (ei->lefts, i);
-	  newref = create_ref (*leftexpr, 
-			       E_LEFT, 0, block, leftexpr,
-			       leftexpr, NULL, true);
+	  newref = create_ref (*leftexpr, E_LEFT, 0, block, leftexpr, 1);
 	  VARRAY_PUSH_GENERIC_PTR (ei->erefs, newref);
 	  fibheap_insert (fh, preorder_count++, newref);
 	}
       else
 	{
 	  tree *occurexpr = VARRAY_GENERIC_PTR (ei->occurs, i);
-	  newref = create_ref (*occurexpr,
-				  E_USE, 0, block, occurexpr, 
-				  occurexpr, NULL, true);
+	  newref = create_ref (*occurexpr, E_USE, 0, block, occurexpr, 1);
 	  VARRAY_PUSH_GENERIC_PTR (ei->erefs, newref);
 	  set_expruse_def (newref, NULL);
 	  set_exprref_class (newref, 0);
@@ -812,8 +806,7 @@ insert_occ_in_preorder_dt_order_1 (ei, f
         {
           if (phi_at_block (ei, succ->dest) != NULL)
             {
-              tree_ref newref = create_ref (NULL, E_USE, 0, block, 0, 
-					    0, 0, true);
+              tree_ref newref = create_ref (NULL, E_USE, 0, block, 0, 1);
               tree_ref phi = phi_at_block (ei, succ->dest);
 	      VARRAY_PUSH_GENERIC_PTR (ei->erefs, newref);
               set_expruse_def (newref, NULL);
@@ -837,8 +830,7 @@ insert_occ_in_preorder_dt_order_1 (ei, f
 	  if (preorder_count != 0)
 	    {
 	      tree_ref newref;
-	      newref = create_ref (NULL, E_EXIT, 0, block, 
-				   NULL, NULL, NULL, true);
+	      newref = create_ref (NULL, E_EXIT, 0, block, NULL, 1);
 	      VARRAY_PUSH_GENERIC_PTR (ei->erefs, newref);
 	      fibheap_insert (fh, preorder_count++, newref);
 	    }
@@ -1564,10 +1556,7 @@ temp_fix_refs (lookin, lookfor, replacew
     {
       tree_ref ref = rli_ref (rli);
       if (ref_stmt (ref) == lookfor)
-	{
-	  ref->common.stmt_p = replacewith;
-	  ref->common.expr_p = replacewith;
-	}
+	ref->common.stmt_p = replacewith;
     }
 }
 
@@ -1820,10 +1809,8 @@ done:
                     expruse_def (X) = new occurrence. 
 		  */		  
 
-		  set_expruse_def (X,create_ref (expr, E_USE, 0,
-						 ref_bb (X), newexprplace,
-						 newexprplace, newexprplace, 
-						 true));
+		  set_expruse_def (X,create_ref (expr, E_USE, 0, ref_bb (X),
+			                         newexprplace, 1));
 		  set_bb_for_stmt (*newexprplace, ref_bb (X));
 		  
 		  VARRAY_PUSH_GENERIC_PTR (ei->erefs, expruse_def (X));
@@ -1920,9 +1907,7 @@ expr_phi_insertion (dfs, ei)
 
   EXECUTE_IF_SET_IN_SBITMAP(dfphis, 0, i, 
   {
-    tree_ref ref = create_ref (ei->expr, E_PHI, 0,
-                                BASIC_BLOCK (i), 
-                                NULL, NULL, NULL, true);
+    tree_ref ref = create_ref (ei->expr, E_PHI, 0, BASIC_BLOCK (i), NULL, 1);
     VARRAY_PUSH_GENERIC_PTR (ei->erefs, ref);
     set_exprref_processed (ref, false);
     set_exprref_processed2 (ref, false);
@@ -2730,7 +2715,6 @@ code_motion (ei, temp)
 
 	      
 	      use->common.stmt_p = &TREE_OPERAND (newstmt, 1);
-	      use->common.expr_p = &TREE_OPERAND (newstmt, 1);
 
 	      /* REMOVE AFTER DFA UPDATE */
 	      temp_fix_refs (use_stmt, newstmt, &TREE_OPERAND (newstmt, 1));
Index: tree-ssa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa.c,v
retrieving revision 1.1.4.28
diff -d -u -p -r1.1.4.28 tree-ssa.c
--- tree-ssa.c	5 Nov 2002 23:50:39 -0000	1.1.4.28
+++ tree-ssa.c	7 Nov 2002 04:37:48 -0000
@@ -808,7 +808,7 @@ add_phi_node (bb, var)
 	 first executable statement.  This is for debugging convenience.
 	 This way, the PHI node will have line number information.  */
       stmt_p = !bb_empty_p (bb) ? bb->head_tree_p : NULL;
-      phi = create_ref (var, V_PHI, 0, bb, stmt_p, NULL, NULL, false);
+      phi = create_ref (var, V_PHI, 0, bb, stmt_p, 0);
       add_ref_to_list_begin (bb_refs (bb), phi);
 
       VARRAY_TREE (added, bb->index) = var;
@@ -951,7 +951,7 @@ create_default_def (var)
     mod = TRM_DEFAULT;
 
   /* Create a default definition and set it to be CURRDEF(var).  */
-  def = create_ref (var, V_DEF, mod, decl_bb, NULL, NULL, NULL, false);
+  def = create_ref (var, V_DEF, mod, decl_bb, NULL, 0);
   add_ref_to_list_begin (bb_refs (decl_bb), def);
   set_currdef_for (var, def);
 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [tree-ssa] CCP and variable reference fixes [patch]
  2002-11-07  4:36 [tree-ssa] CCP and variable reference fixes [patch] Diego Novillo
@ 2002-11-07  8:34 ` Jason Merrill
  2002-11-07  8:59   ` Daniel Berlin
  2002-11-07 11:48   ` Diego Novillo
  0 siblings, 2 replies; 5+ messages in thread
From: Jason Merrill @ 2002-11-07  8:34 UTC (permalink / raw)
  To: Diego Novillo; +Cc: gcc-patches

On Thu, 7 Nov 2002 07:36:17 -0500, Diego Novillo <dnovillo@redhat.com> wrote:

> - Removes unnecessary fields from tree_ref structure.  We don't
>   need to keep pointers into the expression nor operand for each
>   reference.  This makes it possible for a pass to replicate a
>   statement and replace references from the original statement
>   into the copy.

When rth and I were talking about this later, it occurred to me that if we
can have an expression with uses of two different defs of the same variable
in a single stmt, then we do need a use to refer directly to its instance
of the variable within the statement.

Jason

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [tree-ssa] CCP and variable reference fixes [patch]
  2002-11-07  8:34 ` Jason Merrill
@ 2002-11-07  8:59   ` Daniel Berlin
  2002-11-07 11:48   ` Diego Novillo
  1 sibling, 0 replies; 5+ messages in thread
From: Daniel Berlin @ 2002-11-07  8:59 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Diego Novillo, gcc-patches


On Thursday, November 7, 2002, at 11:31  AM, Jason Merrill wrote:

> On Thu, 7 Nov 2002 07:36:17 -0500, Diego Novillo <dnovillo@redhat.com> 
> wrote:
>
>> - Removes unnecessary fields from tree_ref structure.  We don't
>>   need to keep pointers into the expression nor operand for each
>>   reference.  This makes it possible for a pass to replicate a
>>   statement and replace references from the original statement
>>   into the copy.
>
> When rth and I were talking about this later, it occurred to me that 
> if we
> can have an expression with uses of two different defs of the same 
> variable
> in a single stmt,
This isn't possible.

It would imply you could have

a = b + b

where each use of b has a different def.


You'd need to have an undefined self-modifying statement (b = a + ++a 
or something) , and since we are in GIMPLE form, it would have been 
broken up (even though it's not valid anyway).

It's only "technically" possible for the may aliasing uses, where you 
might end up with uses of two different defs of the same pointer.
But even then, you only have a *problem* if the variable names in the 
statement are the same, and they have the same use, which is also 
impossible, since they can only have a different use if they have a 
different name.

> then we do need a use to refer directly to its instance
> of the variable within the statement.
>
> Jason

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [tree-ssa] CCP and variable reference fixes [patch]
  2002-11-07  8:34 ` Jason Merrill
  2002-11-07  8:59   ` Daniel Berlin
@ 2002-11-07 11:48   ` Diego Novillo
  2002-11-07 14:08     ` Jason Merrill
  1 sibling, 1 reply; 5+ messages in thread
From: Diego Novillo @ 2002-11-07 11:48 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

On Thu, 07 Nov 2002, Jason Merrill wrote:

> On Thu, 7 Nov 2002 07:36:17 -0500, Diego Novillo <dnovillo@redhat.com> wrote:
> 
> > - Removes unnecessary fields from tree_ref structure.  We don't
> >   need to keep pointers into the expression nor operand for each
> >   reference.  This makes it possible for a pass to replicate a
> >   statement and replace references from the original statement
> >   into the copy.
> 
> When rth and I were talking about this later, it occurred to me that if we
> can have an expression with uses of two different defs of the same variable
> in a single stmt, then we do need a use to refer directly to its instance
> of the variable within the statement.
> 
Impossible.  If you have two uses of the same variable coming
from different definitions, then your SSA information is
completely broken.  It's actually not possible for the SSA
builder to create such a thing (it keeps a single instance of
'current definition').


Diego.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [tree-ssa] CCP and variable reference fixes [patch]
  2002-11-07 11:48   ` Diego Novillo
@ 2002-11-07 14:08     ` Jason Merrill
  0 siblings, 0 replies; 5+ messages in thread
From: Jason Merrill @ 2002-11-07 14:08 UTC (permalink / raw)
  To: Diego Novillo; +Cc: gcc-patches

On Thu, 7 Nov 2002 14:48:32 -0500, Diego Novillo <dnovillo@redhat.com> wrote:

> On Thu, 07 Nov 2002, Jason Merrill wrote:
>
>> On Thu, 7 Nov 2002 07:36:17 -0500, Diego Novillo <dnovillo@redhat.com> wrote:
>> 
>> > - Removes unnecessary fields from tree_ref structure.  We don't
>> >   need to keep pointers into the expression nor operand for each
>> >   reference.  This makes it possible for a pass to replicate a
>> >   statement and replace references from the original statement
>> >   into the copy.
>> 
>> When rth and I were talking about this later, it occurred to me that if we
>> can have an expression with uses of two different defs of the same variable
>> in a single stmt, then we do need a use to refer directly to its instance
>> of the variable within the statement.
>> 
> Impossible.  If you have two uses of the same variable coming
> from different definitions, then your SSA information is
> completely broken.  It's actually not possible for the SSA
> builder to create such a thing (it keeps a single instance of
> 'current definition').

Well, rth suggested that such a thing was possible in our talk on Tuesday,
but never actually came up with an example.  Y'all work it out for
yourselves.

Jason

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2002-11-07 22:08 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-11-07  4:36 [tree-ssa] CCP and variable reference fixes [patch] Diego Novillo
2002-11-07  8:34 ` Jason Merrill
2002-11-07  8:59   ` Daniel Berlin
2002-11-07 11:48   ` Diego Novillo
2002-11-07 14:08     ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).