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


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

[tree-ssa] Improve jump threading


This patch introduces a new jump threading pass based on the dominator
optimizer.

Improving our jump threading code is actually quite important in our
goal of being able to eliminate the path following code in cse1.  Extensive
analysis of cse1's behavior has indicated that the RTL jump threader is
exposing numerous opportunities for cse1's path following code.  I'll
note that the RTL jump threader is actually quite good these days.  It's
proving challenging to match its optimization capabilities.

This is the first of hopefully 2-3 significant improvements to the SSA
jump threading code.  This patch allows us to thread through a block
which contains PHI nodes followed by a COND_EXPR.

Fundamentally, when we thread jumps in this manner, we are changing things
enough that we must update the SSA graph.  Basically for every variable
referenced in a PHI node which we thread through needs to be re-rewritten.

Initially I had hoped to be able to do this as part of the existing
dominator optimizer pass.  However, it became abundantly clear that a
separate pass to perform jump threading was the right way to go for now.

The key issue is that to be able to correctly perform the SSA graph updates
we have to either be able to run the out-of-ssa pass on a selected group
of variables, or we have to know that we can safely drop the SSA version
numbers and just re-write the affected variables.

I didn't see an easy way to constrain the out-of-ssa pass to only
translate specific variables out of SSA form, so I choose the alternate
path of doing these optimizations when we can still safely drop the
SSA version numbers and re-write the affected variable (ie before the
existing dominator optimizer).

Before this patch, on my testbucket the jump threading done by the
dominator optimizer finds 2820 jump threading opportunities.  The
RTL jump threader finds an additional 5337 jump threading opportunities.
After applying this patch the dominator based threader finds 5059
jump threading opportunities and the RTL version finds 3295 jump
threading opportunities.

[ Yes, you will note that the total number of threaded jumps goes up
  by about 200 with this patch -- which means that this patch is
  actually exposing new jump threading opportunities that we were
  missing before. ]


	* timevar.def (TV_TREE_SSA_THREAD_JUMPS): New timevar.
	* tree-dump.c (dump_files): Add dump file for jump threading.
	* tree.h (TDI_thread_jumps): New enum member.
	* tree-cfg.c (tree_block_forwards_to): No longer static.
	* tree-flow.h (tree_block_forwards_to): Prototype.
	(tree_ssa_dominator_thread_jumps): Likewise.
	* tree-optimize.c (optimize_function_tree): Call jump threader.
	* tree-ssa-dom.c (tree_ssa_dominator_optimize_1): New function.
	Common code for redundancy elimination and jump threading on
	the dominator tree.  Slightly different callback initialization
	for redundancy elimination and jump threading.  Initialize
	block forwardable attribute.
	(tree_ssa_dominator_optimize): Call tree_ssa_dominator_optimize_1.
	(tree_ssa_dominator_thread_jumps): New function.
	(thread_edge): Mark results of PHI nodes as needing rewriting if
	we have threaded through a block with PHI nodes.
	(thread_through_successor): If thread_through_phis is nonzero,
	then allow jump threading through blocks with PHI nodes.  If the
	target block is a forwarder block, then forward the jump.
	(thread_jumps_walk_stmts): Statement walker for dominator thread
	jumping.
	
	* tree-ssa-dom.c (record_equivalence_from_incoming_edge): Fix
	comment typo.
	
	
Index: timevar.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/timevar.def,v
retrieving revision 1.14.2.19
diff -c -3 -p -r1.14.2.19 timevar.def
*** timevar.def	18 Oct 2003 23:59:51 -0000	1.14.2.19
--- timevar.def	24 Oct 2003 03:59:12 -0000
*************** DEFTIMEVAR (TV_TREE_INSERT_PHI_NODES , "
*** 70,75 ****
--- 70,76 ----
  DEFTIMEVAR (TV_TREE_SSA_REWRITE_BLOCKS, "tree SSA rewrite")
  DEFTIMEVAR (TV_TREE_SSA_OTHER	     , "tree SSA other")
  DEFTIMEVAR (TV_TREE_DFA	             , "tree dataflow analysis")
+ DEFTIMEVAR (TV_TREE_SSA_THREAD_JUMPS , "tree thread jumps")
  DEFTIMEVAR (TV_TREE_SSA_DOMINATOR_OPTS   , "dominator optimization")
  DEFTIMEVAR (TV_TREE_CCP		     , "tree CCP")
  DEFTIMEVAR (TV_TREE_PRE		     , "tree PRE")
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.182
diff -c -3 -p -r1.1.4.182 tree-cfg.c
*** tree-cfg.c	23 Oct 2003 00:35:22 -0000	1.1.4.182
--- tree-cfg.c	24 Oct 2003 03:59:19 -0000
*************** static bool blocks_unreachable_p (bitmap
*** 138,144 ****
  static void remove_blocks (bitmap);
  static void cleanup_control_flow (void);
  static void thread_unconditional_jumps (void);
- static basic_block tree_block_forwards_to (basic_block bb);
  static bool disconnect_unreachable_case_labels (basic_block, tree);
  static edge find_taken_edge_cond_expr (basic_block, tree);
  static edge find_taken_edge_switch_expr (basic_block, tree);
--- 138,143 ----
*************** remove_stmt (tree *stmt_p, bool remove_a
*** 2144,2150 ****
     transfers control to a new destination).  If BB is a forwarding block,
     then return the ultimate destination.  */
  
! static basic_block
  tree_block_forwards_to (basic_block bb)
  {
    block_stmt_iterator bsi;
--- 2143,2149 ----
     transfers control to a new destination).  If BB is a forwarding block,
     then return the ultimate destination.  */
  
! basic_block
  tree_block_forwards_to (basic_block bb)
  {
    block_stmt_iterator bsi;
Index: tree-dump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-dump.c,v
retrieving revision 1.6.2.43
diff -c -3 -p -r1.6.2.43 tree-dump.c
*** tree-dump.c	22 Oct 2003 19:38:52 -0000	1.6.2.43
--- tree-dump.c	24 Oct 2003 03:59:20 -0000
*************** static struct dump_file_info dump_files[
*** 660,665 ****
--- 660,666 ----
    {".pta", "tree-pta", 0, 0},
    {".alias", "tree-alias", 0, 0},
    {".ssa1", "tree-ssa1", 0, 0},
+   {".thread", "tree-jumpthread", 0, 0},
    {".dom1", "tree-dom1", 0, 0},
    {".ssa2", "tree-ssa2", 0, 0},
    {".dce1", "tree-dce1", 0, 0},
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.132
diff -c -3 -p -r1.1.4.132 tree-flow.h
*** tree-flow.h	23 Oct 2003 00:35:23 -0000	1.1.4.132
--- tree-flow.h	24 Oct 2003 03:59:21 -0000
*************** extern basic_block label_to_block (tree)
*** 445,450 ****
--- 445,451 ----
  extern bool cleanup_cond_expr_graph (basic_block, tree);
  extern bool cleanup_switch_expr_graph (basic_block, tree);
  extern void tree_optimize_tail_calls (void);
+ extern basic_block tree_block_forwards_to (basic_block bb);
  
  /* In tree-dfa.c  */
  void find_referenced_vars (tree);
*************** bool fold_stmt (tree *);
*** 514,519 ****
--- 515,521 ----
  tree widen_bitfield (tree, tree, tree);
  
  /* In tree-ssa-dom.c  */
+ extern void tree_ssa_dominator_thread_jumps (tree, enum tree_dump_index);
  extern void tree_ssa_dominator_optimize (tree, sbitmap, enum 
tree_dump_index);
  extern void dump_dominator_optimization_stats (FILE *);
  extern void debug_dominator_optimization_stats (void);
Index: tree-optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-optimize.c,v
retrieving revision 1.1.4.58
diff -c -3 -p -r1.1.4.58 tree-optimize.c
*** tree-optimize.c	23 Oct 2003 16:45:52 -0000	1.1.4.58
--- tree-optimize.c	24 Oct 2003 03:59:21 -0000
*************** optimize_function_tree (tree fndecl)
*** 104,109 ****
--- 104,111 ----
        /* Perform dominator optimizations.  */
        if (flag_tree_dom)
  	{
+ 	  tree_ssa_dominator_thread_jumps (fndecl, TDI_thread_jumps);
+ 
  	  sbitmap_zero (vars_to_rename);
  	  tree_ssa_dominator_optimize (fndecl, vars_to_rename, TDI_dom_1);
  
Index: tree-ssa-dom.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-dom.c,v
retrieving revision 1.1.2.64
diff -c -3 -p -r1.1.2.64 tree-ssa-dom.c
*** tree-ssa-dom.c	22 Oct 2003 19:38:52 -0000	1.1.2.64
--- tree-ssa-dom.c	24 Oct 2003 03:59:25 -0000
*************** static bool cfg_altered;
*** 69,74 ****
--- 69,79 ----
     this bitmap.  */
  static sbitmap vars_to_rename;
  
+ /* Nonzero if we should thread jumps through blocks which contain PHI
+    nodes.  This is not safe once we have performed any transformation
+    which extends the lifetime of variables.  */
+ static int thread_through_phis;
+ 
  /* Statistics for dominator optimizations.  */
  struct opt_stats_d
  {
*************** static void dom_opt_initialize_block (st
*** 203,208 ****
--- 208,216 ----
  				      basic_block, tree);
  static void dom_opt_walk_stmts (struct dom_walk_data *, basic_block, tree);
  static void cprop_into_phis (struct dom_walk_data *, basic_block, tree);
+ static void tree_ssa_dominator_optimize_1 (tree, enum tree_dump_index,
+ 					   timevar_id_t);
+ static void thread_jumps_walk_stmts (struct dom_walk_data *, basic_block, 
tree);
  
  /* Return the value associated with variable VAR in TABLE.  */
  
*************** set_value_for (tree var, tree value)
*** 222,227 ****
--- 230,276 ----
  }
  
  
+ 
+ /* Thread jumps in FNDECL based on equivalences created by walking the
+    dominator tree.
+ 
+    Fundamentally this optimization changes the dominator tree in ways
+    that other optimizers care about.  Furthermore, if we thread a jump
+    through a block with PHI nodes, then we need to re-rewrite all the
+    variables appearing in those PHI nodes.
+ 
+    The need to be able to re-rewrite those variables means that this
+    jump threading optimization must be run before we make any transformations
+    which could extend the lifetime of any variable or replace a use of a 
+    variable with a constant.  Thus this optimizer is the first optimizer we
+    run once we are in SSA form and this optimizer is responsible for updaing
+    the SSA form if transformations are made.
+ 
+    A more limited form of this optimizer is run as part of the main dominator
+    optimizer which does not make transformations which require the ability to
+    re-rewrite variables.  Specifically the later version of this optimizer
+    does not thread through blocks with PHI nodes.
+ 
+    PHASE indicates which dump file from the DUMP_FILES array to use when
+    dumping debugging information.  */
+ 
+ void
+ tree_ssa_dominator_thread_jumps (tree fndecl, enum tree_dump_index phase)
+ {
+   /* Indicate that we can thread through blocks with PHI nodes.  */
+   thread_through_phis = 1;
+ 
+   /* The jump threader will always perform any necessary rewriting, so
+      we do not expose VAR_TO_RENAME to our caller, we just allocate and
+      deallocate one here.  */
+   vars_to_rename = sbitmap_alloc (num_referenced_vars);
+   sbitmap_zero (vars_to_rename);
+ 
+   tree_ssa_dominator_optimize_1 (fndecl, phase, TV_TREE_SSA_THREAD_JUMPS);
+ 
+   sbitmap_free (vars_to_rename);
+ }
+ 
  /* Optimize function FNDECL based on the dominator tree.  This does
     simple const/copy propagation and redundant expression elimination using
     value numbering.
*************** void
*** 237,246 ****
  tree_ssa_dominator_optimize (tree fndecl, sbitmap vars,
  			     enum tree_dump_index phase)
  {
    edge e;
    struct dom_walk_data walk_data;
  
!   timevar_push (TV_TREE_SSA_DOMINATOR_OPTS);
  
    /* Set up debugging dump files.  */
    dump_file = dump_begin (phase, &dump_flags);
--- 286,320 ----
  tree_ssa_dominator_optimize (tree fndecl, sbitmap vars,
  			     enum tree_dump_index phase)
  {
+   /* Indicate we can not thread through blocks with PHI nodes.  */
+   thread_through_phis = 0;
+ 
+   /* Once we have the ability to attach pass-global data to the dominator
+      walker datastructure this (along with other pass-global data) should
+      move into that structure.  */
+   vars_to_rename = vars;
+ 
+   tree_ssa_dominator_optimize_1 (fndecl, phase, TV_TREE_SSA_DOMINATOR_OPTS);
+ }
+ 
+ /* Common driver for dominator based jump threading, redundancy elimination
+    and const/copy propagation. 
+ 
+    Optimize function FNDECL based on a walk through the dominator tree.
+ 
+    PHASE indicates which dump file from the DUMP_FILES array to use when
+    dumping debugging information.  */
+ 
+ static void
+ tree_ssa_dominator_optimize_1 (tree fndecl,
+ 			       enum tree_dump_index phase,
+ 			       timevar_id_t timevar)
+ {
+   basic_block bb;
    edge e;
    struct dom_walk_data walk_data;
  
!   timevar_push (timevar);
  
    /* Set up debugging dump files.  */
    dump_file = dump_begin (phase, &dump_flags);
*************** tree_ssa_dominator_optimize (tree fndecl
*** 256,271 ****
  
    /* Setup callbacks for the generic dominator tree walker.  */
    walk_data.before_dom_children_before_stmts = dom_opt_initialize_block;
-   walk_data.before_dom_children_walk_stmts = dom_opt_walk_stmts;
-   walk_data.before_dom_children_after_stmts = cprop_into_phis;
-   walk_data.after_dom_children_after_stmts = dom_opt_finalize_block;
-   walk_data.after_dom_children_walk_stmts = NULL;
    walk_data.after_dom_children_before_stmts = NULL;
  
!   /* Once we have the ability to attach pass-global data to the dominator
!      walker datastructure this (along with other pass-global data) should
!      move into that structure.  */
!   vars_to_rename = vars;
  
    /* Build the dominator tree if necessary. 
  
--- 330,351 ----
  
    /* Setup callbacks for the generic dominator tree walker.  */
    walk_data.before_dom_children_before_stmts = dom_opt_initialize_block;
    walk_data.after_dom_children_before_stmts = NULL;
+   walk_data.after_dom_children_walk_stmts = NULL;
+   walk_data.after_dom_children_after_stmts = dom_opt_finalize_block;
  
!   /* Customize walker based on whether or not we are threading jumps
!      through blocks with PHI nodes or not.  */
!   if (thread_through_phis)
!     {
!       walk_data.before_dom_children_walk_stmts = thread_jumps_walk_stmts;
!       walk_data.before_dom_children_after_stmts = NULL;
!     }
!   else
!     {
!       walk_data.before_dom_children_walk_stmts = dom_opt_walk_stmts;
!       walk_data.before_dom_children_after_stmts = cprop_into_phis;
!     }
  
    /* Build the dominator tree if necessary. 
  
*************** tree_ssa_dominator_optimize (tree fndecl
*** 277,282 ****
--- 357,367 ----
      if (dom_children (e->dest))
        break;
  
+   /* Reset block_forwardable in each block's annotation.  We use that
+      attribute when threading through COND_EXPRs.  */
+   FOR_EACH_BB (bb)
+     bb_ann (bb)->forwardable = 1;
+ 
    /* If we did not find any dominator children in the successors of the
       entry block, then rebuild the dominator tree.  */
    if (e == NULL)
*************** tree_ssa_dominator_optimize (tree fndecl
*** 371,377 ****
    VARRAY_FREE (edges_to_redirect);
    VARRAY_FREE (redirection_targets);
  
!   timevar_pop (TV_TREE_SSA_DOMINATOR_OPTS);
  }
  
  
--- 456,462 ----
    VARRAY_FREE (edges_to_redirect);
    VARRAY_FREE (redirection_targets);
  
!   timevar_pop (timevar);
  }
  
  
*************** thread_edge (edge e, basic_block dest)
*** 385,399 ****
--- 470,501 ----
    tree label, goto_stmt, stmt;
    basic_block bb = e->src, new_bb;
    int flags = e->flags;
+   tree phi;
  
+ #ifdef ENABLE_CHECKING
    if (e != bb->succ
        || bb->succ->succ_next)
      abort ();
  
+   if (! thread_through_phis
+       && (phi_nodes (e->dest) || phi_nodes (dest)))
+     abort ();
+ #endif
+ 
    /* Remove EDGE_FALLTHRU from the edge (by convention, control edges are
       not fallthru).  */
    flags &= ~EDGE_FALLTHRU;
  
+   /* If there are PHI nodes at the original destination, then we need to
+      re-rename the variables referenced by those PHI nodes.
+ 
+      Since we only thread through blocks with PHI nodes before doing
+      any kind of propagation or redundancy elimination, we know that
+      all the PHI arguments are different versions of the same variable,
+      so we only need to mark the underlying variable for PHI_RESULT.  */
+   for (phi = phi_nodes (e->dest); phi; phi = TREE_CHAIN (phi))
+     SET_BIT (vars_to_rename, var_ann (SSA_NAME_VAR (PHI_RESULT (phi)))->uid);
+ 
    /* We need a label at our final destination.  If it does not already exist,
       create it.  */
    if (!dest_stmt
*************** thread_edge (edge e, basic_block dest)
*** 421,428 ****
        new_bb = NULL;
      }
  
-   /* Update/insert PHI nodes as necessary.  */
- 
    /* Now update the edges in the CFG.  */
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
--- 523,528 ----
*************** thread_through_successor (basic_block bb
*** 453,478 ****
    /* If we have a single successor, then we may be able to thread
       the edge out of our block to a destination of our successor.
  
!      To simplify the initial implementation we require that
!      our successor have no PHI nodes.  */
!   if (bb->succ && bb->succ->succ_next == NULL && ! phi_nodes (bb->succ->
dest))
!     {
!       block_stmt_iterator i = bsi_start (bb->succ->dest);
!       tree stmt;
! 
!       /* Get the successor's first real statement.  */
!       while (! bsi_end_p (i)
! 	     && (IS_EMPTY_STMT (bsi_stmt (i))
! 		 || TREE_CODE (bsi_stmt (i)) == LABEL_EXPR))
! 	bsi_next (&i);
!       stmt = bsi_end_p (i) ? NULL : bsi_stmt (i);
  
!       /* If the successor's first real statement is a COND_EXPR, then
! 	 see if we know which arm will be taken.  */
        if (stmt && TREE_CODE (stmt) == COND_EXPR)
  	{
! 	  tree cached_lhs = lookup_avail_expr (stmt, block_avail_exprs, false);
  
  	  if (cached_lhs)
  	    {
  	      edge taken_edge = find_taken_edge (bb->succ->dest, cached_lhs);
--- 553,605 ----
    /* If we have a single successor, then we may be able to thread
       the edge out of our block to a destination of our successor.
  
!      Only thread through a successor with PHI nodes if explicitly asked to.  
*/
!   if (bb->succ && bb->succ->succ_next == NULL
!       && (thread_through_phis || ! phi_nodes (bb->succ->dest)))
!     {
!       block_stmt_iterator bsi = bsi_start (bb->succ->dest);
!       tree stmt = NULL;
! 
!       /* Walk past any empty statements and labels.  */
!       while (! bsi_end_p (bsi)
! 	     && (stmt = bsi_stmt (bsi))
! 	     && (IS_EMPTY_STMT (stmt)
! 		 || TREE_CODE (stmt) == LABEL_EXPR))
! 	bsi_next (&bsi);
  
!       /* If we stopped at a COND_EXPR, then see if we know which arm will
! 	 be taken.  */
        if (stmt && TREE_CODE (stmt) == COND_EXPR)
  	{
! 	  tree cached_lhs;
! 	  unsigned int i;
! 
! 	  /* If we are threading through PHIs, then make sure that none
! 	     of the PHIs set results which are used by the conditional.
! 
! 	     Otherwise this optimization would short-circuit loops.  */
! 	  if (thread_through_phis)
! 	    {
! 	      varray_type table;
! 
! 	      get_stmt_operands (stmt);
! 	      table = use_ops (stmt_ann (stmt));
! 
! 	      for (i = 0; table && i < VARRAY_ACTIVE_SIZE (table); i++)
! 		{
! 		  tree *op_p = VARRAY_TREE_PTR (table, i);
! 		  tree def_stmt = SSA_NAME_DEF_STMT (*op_p);
! 	
! 		  /* See if this operand is defined by a PHI node in
! 		     BB's successor.  If it is, then we can not thread
! 		     this jump.  */
! 		  if (TREE_CODE (def_stmt) == PHI_NODE
! 		      && bb_for_stmt (def_stmt) == bb->succ->dest)
! 		    return;
! 		}
! 	    }
  
+ 	  cached_lhs = lookup_avail_expr (stmt, block_avail_exprs, false);
  	  if (cached_lhs)
  	    {
  	      edge taken_edge = find_taken_edge (bb->succ->dest, cached_lhs);
*************** thread_through_successor (basic_block bb
*** 484,489 ****
--- 611,625 ----
  		 bypass the conditional at our original destination.  */
  	      if (dest && ! phi_nodes (dest))
  		{
+ 		  basic_block forwards_to;
+ 		  int saved_forwardable = bb_ann (bb)->forwardable;
+ 
+ 		  bb_ann (bb)->forwardable = 0;
+ 
+ 		  forwards_to = tree_block_forwards_to (dest);
+ 
+ 		  bb_ann (bb)->forwardable = saved_forwardable;
+ 		  dest = (forwards_to ? forwards_to : dest);
  		  VARRAY_PUSH_EDGE (edges_to_redirect, bb->succ);
  		  VARRAY_PUSH_BB (redirection_targets, dest);
  		}
*************** record_equivalences_from_incoming_edge (
*** 693,699 ****
  
    /* If we have a single predecessor, then extract EDGE_FLAGS from
       our single incoming edge.  Otherwise clear EDGE_FLAGS and
!      PAREND_BLOCK_LAST_STMT since they're not needed.  */
    if (bb->pred && !bb->pred->pred_next)
      {
        edge_flags = bb->pred->flags;
--- 829,835 ----
  
    /* If we have a single predecessor, then extract EDGE_FLAGS from
       our single incoming edge.  Otherwise clear EDGE_FLAGS and
!      PARENT_BLOCK_LAST_STMT since they're not needed.  */
    if (bb->pred && !bb->pred->pred_next)
      {
        edge_flags = bb->pred->flags;
*************** dom_opt_walk_stmts (struct dom_walk_data
*** 846,851 ****
--- 982,1042 ----
  	 find it again.  */
        if (optimize_stmt (si, &bd->avail_exprs))
  	VARRAY_PUSH_TREE (bd->stmts_to_rescan, bsi_stmt (si));
+     }
+ }
+ 
+ /* Alternate statement walker for jump threading.  The primary difference
+    between this walker and the previous one is we merely want to record
+    equivalences, not take action on them.  So instead of calling
+    optimize_stmt, we just enter the appropriate equivalences into the
+    hash tables.  */
+ 
+ static void
+ thread_jumps_walk_stmts (struct dom_walk_data *walk_data,
+ 			 basic_block bb,
+ 			 tree parent_block_last_stmt ATTRIBUTE_UNUSED)
+ {
+   block_stmt_iterator si;
+ 
+   /* Examine each statement within the basic block.  */
+   for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
+     {
+       struct dom_walk_block_data *bd
+ 	= VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack);
+       tree stmt = bsi_stmt (si);
+       int may_optimize_p;
+       varray_type vdefs;
+ 
+       /* Check for redundant computations.  Do this optimization only
+ 	 for assignments that have no volatile ops and conditionals.  */
+ 
+       /* This is a simpler test than the one in optimize_stmt because
+ 	 we only care about recording equivalences for assignments.
+          RETURN_EXPRs, COND_EXPRs, and SWITCH_EXPRs can be ignored.  */
+       may_optimize_p = (!stmt_ann (stmt)->has_volatile_ops
+ 			&& TREE_CODE (stmt) == MODIFY_EXPR
+ 			&& ! TREE_SIDE_EFFECTS (TREE_OPERAND (stmt, 1)));
+ 
+       vdefs = vdef_ops (stmt_ann (stmt));
+ 
+       /* Tighten the set of RHS expressions we can enter into the hash
+ 	 tables.  Specifically, we can not enter the RHS into the hash
+ 	 table if the LHS is not an SSA_NAME, the LHS occurs in an
+ 	 abnormal PHI, or if the statement makes aliased stores
+ 	 (in addition to all the conditions for may_optimize_p).  */
+       if (may_optimize_p
+ 	  && TREE_CODE (TREE_OPERAND (stmt, 0)) == SSA_NAME
+ 	  && ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (TREE_OPERAND (stmt, 0))
+ 	  && ! stmt_ann (stmt)->makes_aliased_stores
+ 	  && ! vdefs)
+ 	lookup_avail_expr (stmt, &bd->avail_exprs, true);
+ 
+       /* Even if we couldn't enter LHS = RHS into the expression hash tables,
+ 	 this statement may still generate other equivalences.  For example,
+ 	 an aliased store can indicate that a pointer has a nonzero value.  */
+       if (TREE_CODE (stmt) == MODIFY_EXPR)
+ 	record_equivalences_from_stmt (stmt, &bd->avail_exprs,
+ 				       may_optimize_p, stmt_ann (stmt));
      }
  }
  
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.112
diff -c -3 -p -r1.342.2.112 tree.h
*** tree.h	23 Oct 2003 16:45:52 -0000	1.342.2.112
--- tree.h	24 Oct 2003 03:59:36 -0000
*************** enum tree_dump_index
*** 3502,3507 ****
--- 3502,3508 ----
    /* Optimization passes.  The ordering and numbering of these phases must
       be the same as the one in optimize_function_tree().  */
    TDI_ssa_1,
+   TDI_thread_jumps,
    TDI_dom_1,
    TDI_ssa_2,
    TDI_dce_1,











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