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]

[tuples] Tuplify invariant motion


Hi,

this patch enables lcSSA form creation and tuplifies lim, as well as
fixing a few things to make it work:

1) gimple_could_trap_p is factored out of tree_could_trap_p.
2) the remove_eh_info argument of gsi_remove is renamed to make it
   clear that it really means "do not destroy anything permanent,
   I am going to reinsert this statement elsewhere"; and we now
   do not free the operands of the statement if this argument is false.
3) gimple_find_edge_insert_loc is made to use gsi_last_bb, so that
   commit_edge_insertions updates stmt->basic block mapping correctly

The patch causes one misscompilation (gcc.c-torture/execute/pr34176.c)
in the testsuite (virtual operands are wrong, making lim perform an
illegal transformation).  I will try to fix this, but I would like to
commit the bulk of the patch now (possibly with lim disabled, if
preferable) in order to avoid having to fix conflicts with other
changes.  OK?

Zdenek

	* tree-ssa-loop-im.c: Tuplify.
	* tree-ssa-loop-manip.c (add_exit_phis_edge, find_uses_to_rename_stmt,
	find_uses_to_rename_bb, check_loop_closed_ssa_use,
	check_loop_closed_ssa_stmt, verify_loop_closed_ssa): Ditto.
	* gimple-dummy.c (rewrite_into_loop_closed_ssa, tree_ssa_lim,
	verify_loop_closed_ssa, replace_exp): Removed.
	* tree-ssa-loop.c (tree_ssa_loop_init, tree_ssa_loop_done): Comment
	out scev initialization and finalization.
	* gimple-iterator.c (gsi_remove): Rename remove_eh_info to
	remove_permanently.  Do not free operands if remove_permanently
	is false.
	(gimple_find_edge_insert_loc): Use gsi_last_bb.
	* tree-eh.c (operation_could_trap_p): Factored out of ...
	(tree_could_trap_p): ... here.
	* tree-ssa-copy.c (replace_exp): Enable.
	* tree-flow.h (movement_possibility): Declaration changed.
	(operation_could_trap_p): Declare.
	* Makefile.in (tree-ssa-loop-im.o): Add pointer-set.h dependency.
	(gimple.o): Add FLAGS_H dependency.
	* gimple.c: Include flags.h.
	(gimple_could_trap_p): New function.
	* gimple.h (gimple_could_trap_p): Declare.
	* tree-cfg.c (replace_uses_by): Check that op is not null.
	* passes.c (init_optimization_passes): Enable pass_lim.

Index: tree-ssa-loop-im.c
===================================================================
*** tree-ssa-loop-im.c	(revision 132706)
--- tree-ssa-loop-im.c	(working copy)
*************** along with GCC; see the file COPYING3.  
*** 38,46 ****
  #include "flags.h"
  #include "real.h"
  #include "hashtab.h"
  
- /* FIXME tuples.  */
- #if 0
  /* TODO:  Support for predicated code motion.  I.e.
  
     while (1)
--- 38,45 ----
  #include "flags.h"
  #include "real.h"
  #include "hashtab.h"
+ #include "pointer-set.h"
  
  /* TODO:  Support for predicated code motion.  I.e.
  
     while (1)
*************** along with GCC; see the file COPYING3.  
*** 68,74 ****
  
  struct depend
  {
!   tree stmt;
    struct depend *next;
  };
  
--- 67,73 ----
  
  struct depend
  {
!   gimple stmt;
    struct depend *next;
  };
  
*************** struct lim_aux_data
*** 101,116 ****
  				   MAX_LOOP loop.  */
  };
  
! #define LIM_DATA(STMT) (TREE_CODE (STMT) == PHI_NODE \
! 			? NULL \
! 			: (struct lim_aux_data *) (stmt_ann (STMT)->common.aux))
  
  /* Description of a memory reference location for store motion.  */
  
  struct mem_ref_loc
  {
    tree *ref;			/* The reference itself.  */
!   tree stmt;			/* The statement in that it occurs.  */
    struct mem_ref_loc *next;	/* Next use in the chain.  */
  };
  
--- 100,115 ----
  				   MAX_LOOP loop.  */
  };
  
! /* Maps statements to their lim_aux_data.  */
! 
! static struct pointer_map_t *lim_aux_data_map;
  
  /* Description of a memory reference location for store motion.  */
  
  struct mem_ref_loc
  {
    tree *ref;			/* The reference itself.  */
!   gimple stmt;			/* The statement in that it occurs.  */
    struct mem_ref_loc *next;	/* Next use in the chain.  */
  };
  
*************** struct mem_ref
*** 141,146 ****
--- 140,190 ----
     block will be executed.  */
  #define ALWAYS_EXECUTED_IN(BB) ((struct loop *) (BB)->aux)
  
+ static struct lim_aux_data *
+ init_lim_data (gimple stmt)
+ {
+   void **p = pointer_map_insert (lim_aux_data_map, stmt);
+ 
+   *p = XCNEW (struct lim_aux_data);
+   return *p;
+ }
+ 
+ static struct lim_aux_data *
+ get_lim_data (gimple stmt)
+ {
+   void **p = pointer_map_contains (lim_aux_data_map, stmt);
+   if (!p)
+     return NULL;
+ 
+   return *p;
+ }
+ 
+ /* Releases the memory occupied by DATA.  */
+ 
+ static void
+ free_lim_aux_data (struct lim_aux_data *data)
+ {
+   struct depend *dep, *next;
+ 
+   for (dep = data->depends; dep; dep = next)
+     {
+       next = dep->next;
+       free (dep);
+     }
+   free (data);
+ }
+ 
+ static void
+ clear_lim_data (gimple stmt)
+ {
+   void **p = pointer_map_contains (lim_aux_data_map, stmt);
+   if (!p)
+     return;
+ 
+   free_lim_aux_data (*p);
+   *p = NULL;
+ }
+ 
  /* Calls CBCK for each index in memory reference ADDR_P.  There are two
     kinds situations handled; in each of these cases, the memory reference
     and DATA are passed to the callback:
*************** for_each_index (tree *addr_p, bool (*cbc
*** 235,277 ****
     Otherwise return MOVE_IMPOSSIBLE.  */
  
  enum move_pos
! movement_possibility (tree stmt)
  {
!   tree lhs, rhs;
  
    if (flag_unswitch_loops
!       && TREE_CODE (stmt) == COND_EXPR)
      {
        /* If we perform unswitching, force the operands of the invariant
  	 condition to be moved out of the loop.  */
        return MOVE_POSSIBLE;
      }
  
!   if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
!     return MOVE_IMPOSSIBLE;
! 
!   if (stmt_ends_bb_p (stmt))
      return MOVE_IMPOSSIBLE;
  
!   if (stmt_ann (stmt)->has_volatile_ops)
!     return MOVE_IMPOSSIBLE;
! 
!   lhs = GIMPLE_STMT_OPERAND (stmt, 0);
!   if (TREE_CODE (lhs) == SSA_NAME
!       && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
!     return MOVE_IMPOSSIBLE;
! 
!   rhs = GIMPLE_STMT_OPERAND (stmt, 1);
! 
!   if (TREE_SIDE_EFFECTS (rhs)
!       || tree_could_throw_p (rhs))
!     return MOVE_IMPOSSIBLE;
! 
!   if (TREE_CODE (lhs) != SSA_NAME
!       || tree_could_trap_p (rhs))
!     return MOVE_PRESERVE_EXECUTION;
! 
!   if (get_call_expr_in (stmt))
      {
        /* While pure or const call is guaranteed to have no side effects, we
  	 cannot move it arbitrarily.  Consider code like
--- 279,304 ----
     Otherwise return MOVE_IMPOSSIBLE.  */
  
  enum move_pos
! movement_possibility (gimple stmt)
  {
!   tree lhs;
!   enum move_pos ret = MOVE_POSSIBLE;
  
    if (flag_unswitch_loops
!       && gimple_code (stmt) == GIMPLE_COND)
      {
        /* If we perform unswitching, force the operands of the invariant
  	 condition to be moved out of the loop.  */
        return MOVE_POSSIBLE;
      }
  
!   if (stmt_ends_bb_p (stmt)
!       || gimple_has_volatile_ops (stmt)
!       || gimple_has_side_effects (stmt)
!       || stmt_could_throw_p (stmt))
      return MOVE_IMPOSSIBLE;
  
!   if (gimple_code (stmt) == GIMPLE_CALL)
      {
        /* While pure or const call is guaranteed to have no side effects, we
  	 cannot move it arbitrarily.  Consider code like
*************** movement_possibility (tree stmt)
*** 291,299 ****
  	 invalid arguments, moving out a function call that is not executed
  	 may cause performance regressions in case the call is costly and
  	 not executed at all.  */
!       return MOVE_PRESERVE_EXECUTION;
      }
!   return MOVE_POSSIBLE;
  }
  
  /* Suppose that operand DEF is used inside the LOOP.  Returns the outermost
--- 318,340 ----
  	 invalid arguments, moving out a function call that is not executed
  	 may cause performance regressions in case the call is costly and
  	 not executed at all.  */
!       ret = MOVE_PRESERVE_EXECUTION;
!       lhs = gimple_call_lhs (stmt);
      }
!   else if (gimple_code (stmt) == GIMPLE_ASSIGN)
!     lhs = gimple_assign_lhs (stmt);
!   else
!     return MOVE_IMPOSSIBLE;
! 
!   if (TREE_CODE (lhs) == SSA_NAME
!       && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
!     return MOVE_IMPOSSIBLE;
! 
!   if (TREE_CODE (lhs) != SSA_NAME
!       || gimple_could_trap_p (stmt))
!     return MOVE_PRESERVE_EXECUTION;
! 
!   return ret;
  }
  
  /* Suppose that operand DEF is used inside the LOOP.  Returns the outermost
*************** movement_possibility (tree stmt)
*** 304,316 ****
  static struct loop *
  outermost_invariant_loop (tree def, struct loop *loop)
  {
!   tree def_stmt;
    basic_block def_bb;
    struct loop *max_loop;
  
!   if (TREE_CODE (def) != SSA_NAME)
      return superloop_at_depth (loop, 1);
  
    def_stmt = SSA_NAME_DEF_STMT (def);
    def_bb = gimple_bb (def_stmt);
    if (!def_bb)
--- 345,364 ----
  static struct loop *
  outermost_invariant_loop (tree def, struct loop *loop)
  {
!   gimple def_stmt;
    basic_block def_bb;
    struct loop *max_loop;
+   struct lim_aux_data *lim_data;
  
!   if (!def)
      return superloop_at_depth (loop, 1);
  
+   if (TREE_CODE (def) != SSA_NAME)
+     {
+       gcc_assert (is_gimple_min_invariant (def));
+       return superloop_at_depth (loop, 1);
+     }
+ 
    def_stmt = SSA_NAME_DEF_STMT (def);
    def_bb = gimple_bb (def_stmt);
    if (!def_bb)
*************** outermost_invariant_loop (tree def, stru
*** 318,326 ****
  
    max_loop = find_common_loop (loop, def_bb->loop_father);
  
!   if (LIM_DATA (def_stmt) && LIM_DATA (def_stmt)->max_loop)
      max_loop = find_common_loop (max_loop,
! 				 loop_outer (LIM_DATA (def_stmt)->max_loop));
    if (max_loop == loop)
      return NULL;
    max_loop = superloop_at_depth (loop, loop_depth (max_loop) + 1);
--- 366,375 ----
  
    max_loop = find_common_loop (loop, def_bb->loop_father);
  
!   lim_data = get_lim_data (def_stmt);
!   if (lim_data != NULL && lim_data->max_loop != NULL)
      max_loop = find_common_loop (max_loop,
! 				 loop_outer (lim_data->max_loop));
    if (max_loop == loop)
      return NULL;
    max_loop = superloop_at_depth (loop, loop_depth (max_loop) + 1);
*************** outermost_invariant_loop (tree def, stru
*** 328,369 ****
    return max_loop;
  }
  
- /* Returns the outermost superloop of LOOP in that the expression EXPR is
-    invariant.  */
- 
- static struct loop *
- outermost_invariant_loop_expr (tree expr, struct loop *loop)
- {
-   enum tree_code_class codeclass = TREE_CODE_CLASS (TREE_CODE (expr));
-   unsigned i, nops;
-   struct loop *max_loop = superloop_at_depth (loop, 1), *aloop;
- 
-   if (TREE_CODE (expr) == SSA_NAME
-       || TREE_CODE (expr) == INTEGER_CST
-       || is_gimple_min_invariant (expr))
-     return outermost_invariant_loop (expr, loop);
- 
-   if (codeclass != tcc_unary
-       && codeclass != tcc_binary
-       && codeclass != tcc_expression
-       && codeclass != tcc_vl_exp
-       && codeclass != tcc_comparison)
-     return NULL;
- 
-   nops = TREE_OPERAND_LENGTH (expr);
-   for (i = 0; i < nops; i++)
-     {
-       aloop = outermost_invariant_loop_expr (TREE_OPERAND (expr, i), loop);
-       if (!aloop)
- 	return NULL;
- 
-       if (flow_loop_nested_p (max_loop, aloop))
- 	max_loop = aloop;
-     }
- 
-   return max_loop;
- }
- 
  /* DATA is a structure containing information associated with a statement
     inside LOOP.  DEF is one of the operands of this statement.
     
--- 377,382 ----
*************** static bool
*** 380,389 ****
  add_dependency (tree def, struct lim_aux_data *data, struct loop *loop,
  		bool add_cost)
  {
!   tree def_stmt = SSA_NAME_DEF_STMT (def);
    basic_block def_bb = gimple_bb (def_stmt);
    struct loop *max_loop;
    struct depend *dep;
  
    if (!def_bb)
      return true;
--- 393,403 ----
  add_dependency (tree def, struct lim_aux_data *data, struct loop *loop,
  		bool add_cost)
  {
!   gimple def_stmt = SSA_NAME_DEF_STMT (def);
    basic_block def_bb = gimple_bb (def_stmt);
    struct loop *max_loop;
    struct depend *dep;
+   struct lim_aux_data *def_data;
  
    if (!def_bb)
      return true;
*************** add_dependency (tree def, struct lim_aux
*** 395,401 ****
    if (flow_loop_nested_p (data->max_loop, max_loop))
      data->max_loop = max_loop;
  
!   if (!LIM_DATA (def_stmt))
      return true;
  
    if (add_cost
--- 409,416 ----
    if (flow_loop_nested_p (data->max_loop, max_loop))
      data->max_loop = max_loop;
  
!   def_data = get_lim_data (def_stmt);
!   if (!def_data)
      return true;
  
    if (add_cost
*************** add_dependency (tree def, struct lim_aux
*** 404,410 ****
  	 on it, we will be able to avoid creating a new register for
  	 it (since it will be only used in these dependent invariants).  */
        && def_bb->loop_father == loop)
!     data->cost += LIM_DATA (def_stmt)->cost;
  
    dep = XNEW (struct depend);
    dep->stmt = def_stmt;
--- 419,425 ----
  	 on it, we will be able to avoid creating a new register for
  	 it (since it will be only used in these dependent invariants).  */
        && def_bb->loop_father == loop)
!     data->cost += def_data->cost;
  
    dep = XNEW (struct depend);
    dep->stmt = def_stmt;
*************** add_dependency (tree def, struct lim_aux
*** 419,454 ****
     values.  */
  
  static unsigned
! stmt_cost (tree stmt)
  {
!   tree rhs;
    unsigned cost = 1;
  
    /* Always try to create possibilities for unswitching.  */
!   if (TREE_CODE (stmt) == COND_EXPR)
      return LIM_EXPENSIVE;
  
-   rhs = GENERIC_TREE_OPERAND (stmt, 1);
- 
    /* Hoisting memory references out should almost surely be a win.  */
    if (stmt_references_memory_p (stmt))
      cost += 20;
  
!   switch (TREE_CODE (rhs))
      {
-     case CALL_EXPR:
        /* We should be hoisting calls if possible.  */
  
        /* Unless the call is a builtin_constant_p; this always folds to a
  	 constant, so moving it is useless.  */
!       rhs = get_callee_fndecl (rhs);
!       if (DECL_BUILT_IN_CLASS (rhs) == BUILT_IN_NORMAL
! 	  && DECL_FUNCTION_CODE (rhs) == BUILT_IN_CONSTANT_P)
  	return 0;
  
!       cost += 20;
!       break;
  
      case MULT_EXPR:
      case TRUNC_DIV_EXPR:
      case CEIL_DIV_EXPR:
--- 434,472 ----
     values.  */
  
  static unsigned
! stmt_cost (gimple stmt)
  {
!   tree fndecl;
    unsigned cost = 1;
  
    /* Always try to create possibilities for unswitching.  */
!   if (gimple_code (stmt) == GIMPLE_COND)
      return LIM_EXPENSIVE;
  
    /* Hoisting memory references out should almost surely be a win.  */
    if (stmt_references_memory_p (stmt))
      cost += 20;
  
!   if (gimple_code (stmt) == GIMPLE_CALL)
      {
        /* We should be hoisting calls if possible.  */
  
        /* Unless the call is a builtin_constant_p; this always folds to a
  	 constant, so moving it is useless.  */
!       fndecl = gimple_call_fndecl (stmt);
!       if (fndecl
! 	  && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
! 	  && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CONSTANT_P)
  	return 0;
  
!       return cost + 20;
!     }
! 
!   if (gimple_code (stmt) != GIMPLE_ASSIGN)
!     return cost;
  
+   switch (gimple_assign_subcode (stmt))
+     {
      case MULT_EXPR:
      case TRUNC_DIV_EXPR:
      case CEIL_DIV_EXPR:
*************** stmt_cost (tree stmt)
*** 487,498 ****
     is defined in, and true otherwise.  */
  
  static bool
! determine_max_movement (tree stmt, bool must_preserve_exec)
  {
    basic_block bb = gimple_bb (stmt);
    struct loop *loop = bb->loop_father;
    struct loop *level;
!   struct lim_aux_data *lim_data = LIM_DATA (stmt);
    tree val;
    ssa_op_iter iter;
    
--- 505,516 ----
     is defined in, and true otherwise.  */
  
  static bool
! determine_max_movement (gimple stmt, bool must_preserve_exec)
  {
    basic_block bb = gimple_bb (stmt);
    struct loop *loop = bb->loop_father;
    struct loop *level;
!   struct lim_aux_data *lim_data = get_lim_data (stmt);
    tree val;
    ssa_op_iter iter;
    
*************** determine_max_movement (tree stmt, bool 
*** 521,544 ****
     operands) is hoisted at least out of the loop LEVEL.  */
  
  static void
! set_level (tree stmt, struct loop *orig_loop, struct loop *level)
  {
    struct loop *stmt_loop = gimple_bb (stmt)->loop_father;
    struct depend *dep;
  
    stmt_loop = find_common_loop (orig_loop, stmt_loop);
!   if (LIM_DATA (stmt) && LIM_DATA (stmt)->tgt_loop)
      stmt_loop = find_common_loop (stmt_loop,
! 				  loop_outer (LIM_DATA (stmt)->tgt_loop));
    if (flow_loop_nested_p (stmt_loop, level))
      return;
  
!   gcc_assert (LIM_DATA (stmt));
!   gcc_assert (level == LIM_DATA (stmt)->max_loop
! 	      || flow_loop_nested_p (LIM_DATA (stmt)->max_loop, level));
  
!   LIM_DATA (stmt)->tgt_loop = level;
!   for (dep = LIM_DATA (stmt)->depends; dep; dep = dep->next)
      set_level (dep->stmt, orig_loop, level);
  }
  
--- 539,563 ----
     operands) is hoisted at least out of the loop LEVEL.  */
  
  static void
! set_level (gimple stmt, struct loop *orig_loop, struct loop *level)
  {
    struct loop *stmt_loop = gimple_bb (stmt)->loop_father;
    struct depend *dep;
+   struct lim_aux_data *lim_data;
  
    stmt_loop = find_common_loop (orig_loop, stmt_loop);
!   lim_data = get_lim_data (stmt);
!   if (lim_data != NULL && lim_data->tgt_loop != NULL)
      stmt_loop = find_common_loop (stmt_loop,
! 				  loop_outer (lim_data->tgt_loop));
    if (flow_loop_nested_p (stmt_loop, level))
      return;
  
!   gcc_assert (level == lim_data->max_loop
! 	      || flow_loop_nested_p (lim_data->max_loop, level));
  
!   lim_data->tgt_loop = level;
!   for (dep = lim_data->depends; dep; dep = dep->next)
      set_level (dep->stmt, orig_loop, level);
  }
  
*************** set_level (tree stmt, struct loop *orig_
*** 547,615 ****
     information to set it more sanely.  */
  
  static void
! set_profitable_level (tree stmt)
  {
!   set_level (stmt, gimple_bb (stmt)->loop_father, LIM_DATA (stmt)->max_loop);
  }
  
! /* Returns true if STMT is not a pure call.  */
  
  static bool
! nonpure_call_p (tree stmt)
  {
!   tree call = get_call_expr_in (stmt);
! 
!   if (!call)
      return false;
  
!   return TREE_SIDE_EFFECTS (call) != 0;
! }
! 
! /* Releases the memory occupied by DATA.  */
! 
! static void
! free_lim_aux_data (struct lim_aux_data *data)
! {
!   struct depend *dep, *next;
! 
!   for (dep = data->depends; dep; dep = next)
!     {
!       next = dep->next;
!       free (dep);
!     }
!   free (data);
  }
  
  /* Rewrite a/b to a*(1/b).  Return the invariant stmt to process.  */
  
! static tree
! rewrite_reciprocal (block_stmt_iterator *bsi)
  {
!   tree stmt, lhs, rhs, stmt1, stmt2, var, name, tmp;
  
!   stmt = bsi_stmt (*bsi);
!   lhs = GENERIC_TREE_OPERAND (stmt, 0);
!   rhs = GENERIC_TREE_OPERAND (stmt, 1);
  
!   /* stmt must be GIMPLE_MODIFY_STMT.  */
!   var = create_tmp_var (TREE_TYPE (rhs), "reciptmp");
    add_referenced_var (var);
  
!   tmp = build2 (RDIV_EXPR, TREE_TYPE (rhs),
! 		build_real (TREE_TYPE (rhs), dconst1),
! 		TREE_OPERAND (rhs, 1));
!   stmt1 = build_gimple_modify_stmt (var, tmp);
    name = make_ssa_name (var, stmt1);
!   GIMPLE_STMT_OPERAND (stmt1, 0) = name;
!   tmp = build2 (MULT_EXPR, TREE_TYPE (rhs),
! 		name, TREE_OPERAND (rhs, 0));
!   stmt2 = build_gimple_modify_stmt (lhs, tmp);
  
    /* Replace division stmt with reciprocal and multiply stmts.
       The multiply stmt is not invariant, so update iterator
       and avoid rescanning.  */
!   bsi_replace (bsi, stmt1, true);
!   bsi_insert_after (bsi, stmt2, BSI_NEW_STMT);
    SSA_NAME_DEF_STMT (lhs) = stmt2;
  
    /* Continue processing with invariant reciprocal statement.  */
--- 566,615 ----
     information to set it more sanely.  */
  
  static void
! set_profitable_level (gimple stmt)
  {
!   set_level (stmt, gimple_bb (stmt)->loop_father, get_lim_data (stmt)->max_loop);
  }
  
! /* Returns true if STMT is a call that has side effects.  */
  
  static bool
! nonpure_call_p (gimple stmt)
  {
!   if (gimple_code (stmt) != GIMPLE_CALL)
      return false;
  
!   return gimple_has_side_effects (stmt);
  }
  
  /* Rewrite a/b to a*(1/b).  Return the invariant stmt to process.  */
  
! static gimple
! rewrite_reciprocal (gimple_stmt_iterator *bsi)
  {
!   gimple stmt, stmt1, stmt2;
!   tree var, name, lhs, type;
  
!   stmt = gsi_stmt (*bsi);
!   lhs = gimple_assign_lhs (stmt);
!   type = TREE_TYPE (lhs);
  
!   var = create_tmp_var (type, "reciptmp");
    add_referenced_var (var);
  
!   stmt1 = gimple_build_assign_with_ops (RDIV_EXPR,
! 		var, build_real (type, dconst1), gimple_assign_rhs2 (stmt));
    name = make_ssa_name (var, stmt1);
!   gimple_assign_set_lhs (stmt1, name);
! 
!   stmt2 = gimple_build_assign_with_ops (MULT_EXPR, lhs, name,
! 					gimple_assign_rhs1 (stmt));
  
    /* Replace division stmt with reciprocal and multiply stmts.
       The multiply stmt is not invariant, so update iterator
       and avoid rescanning.  */
!   gsi_replace (bsi, stmt1, true);
!   gsi_insert_after (bsi, stmt2, GSI_NEW_STMT);
    SSA_NAME_DEF_STMT (lhs) = stmt2;
  
    /* Continue processing with invariant reciprocal statement.  */
*************** rewrite_reciprocal (block_stmt_iterator 
*** 619,696 ****
  /* Check if the pattern at *BSI is a bittest of the form
     (A >> B) & 1 != 0 and in this case rewrite it to A & (1 << B) != 0.  */
  
! static tree
! rewrite_bittest (block_stmt_iterator *bsi)
  {
!   tree stmt, lhs, rhs, var, name, use_stmt, stmt1, stmt2, t;
    use_operand_p use;
  
!   stmt = bsi_stmt (*bsi);
!   lhs = GENERIC_TREE_OPERAND (stmt, 0);
!   rhs = GENERIC_TREE_OPERAND (stmt, 1);
  
    /* Verify that the single use of lhs is a comparison against zero.  */
    if (TREE_CODE (lhs) != SSA_NAME
        || !single_imm_use (lhs, &use, &use_stmt)
!       || TREE_CODE (use_stmt) != COND_EXPR)
      return stmt;
!   t = COND_EXPR_COND (use_stmt);
!   if (TREE_OPERAND (t, 0) != lhs
!       || (TREE_CODE (t) != NE_EXPR
! 	  && TREE_CODE (t) != EQ_EXPR)
!       || !integer_zerop (TREE_OPERAND (t, 1)))
      return stmt;
  
    /* Get at the operands of the shift.  The rhs is TMP1 & 1.  */
!   stmt1 = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0));
!   if (TREE_CODE (stmt1) != GIMPLE_MODIFY_STMT)
      return stmt;
  
    /* There is a conversion in between possibly inserted by fold.  */
!   t = GIMPLE_STMT_OPERAND (stmt1, 1);
!   if (TREE_CODE (t) == NOP_EXPR
!       || TREE_CODE (t) == CONVERT_EXPR)
      {
!       t = TREE_OPERAND (t, 0);
        if (TREE_CODE (t) != SSA_NAME
  	  || !has_single_use (t))
  	return stmt;
        stmt1 = SSA_NAME_DEF_STMT (t);
!       if (TREE_CODE (stmt1) != GIMPLE_MODIFY_STMT)
  	return stmt;
-       t = GIMPLE_STMT_OPERAND (stmt1, 1);
      }
  
    /* Verify that B is loop invariant but A is not.  Verify that with
       all the stmt walking we are still in the same loop.  */
!   if (TREE_CODE (t) == RSHIFT_EXPR
!       && loop_containing_stmt (stmt1) == loop_containing_stmt (stmt)
!       && outermost_invariant_loop_expr (TREE_OPERAND (t, 1),
!                                         loop_containing_stmt (stmt1)) != NULL
!       && outermost_invariant_loop_expr (TREE_OPERAND (t, 0),
!                                         loop_containing_stmt (stmt1)) == NULL)
!     {
!       tree a = TREE_OPERAND (t, 0);
!       tree b = TREE_OPERAND (t, 1);
  
        /* 1 << B */
        var = create_tmp_var (TREE_TYPE (a), "shifttmp");
        add_referenced_var (var);
        t = fold_build2 (LSHIFT_EXPR, TREE_TYPE (a),
  		       build_int_cst (TREE_TYPE (a), 1), b);
!       stmt1 = build_gimple_modify_stmt (var, t);
        name = make_ssa_name (var, stmt1);
!       GIMPLE_STMT_OPERAND (stmt1, 0) = name;
  
        /* A & (1 << B) */
        t = fold_build2 (BIT_AND_EXPR, TREE_TYPE (a), a, name);
!       stmt2 = build_gimple_modify_stmt (var, t);
        name = make_ssa_name (var, stmt2);
!       GIMPLE_STMT_OPERAND (stmt2, 0) = name;
        SET_USE (use, name);
  
!       bsi_insert_before (bsi, stmt1, BSI_SAME_STMT);
!       bsi_replace (bsi, stmt2, true);
  
        return stmt1;
      }
--- 619,693 ----
  /* Check if the pattern at *BSI is a bittest of the form
     (A >> B) & 1 != 0 and in this case rewrite it to A & (1 << B) != 0.  */
  
! static gimple
! rewrite_bittest (gimple_stmt_iterator *bsi)
  {
!   gimple stmt, use_stmt, stmt1, stmt2;
!   tree lhs, var, name, t, a, b;
    use_operand_p use;
  
!   stmt = gsi_stmt (*bsi);
!   lhs = gimple_assign_lhs (stmt);
  
    /* Verify that the single use of lhs is a comparison against zero.  */
    if (TREE_CODE (lhs) != SSA_NAME
        || !single_imm_use (lhs, &use, &use_stmt)
!       || gimple_code (use_stmt) != GIMPLE_COND)
      return stmt;
!   if (gimple_cond_lhs (use_stmt) != lhs
!       || (gimple_cond_code (use_stmt) != NE_EXPR
! 	  && gimple_cond_code (use_stmt) != EQ_EXPR)
!       || !integer_zerop (gimple_cond_rhs (use_stmt)))
      return stmt;
  
    /* Get at the operands of the shift.  The rhs is TMP1 & 1.  */
!   stmt1 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt));
!   if (gimple_code (stmt1) != GIMPLE_ASSIGN)
      return stmt;
  
    /* There is a conversion in between possibly inserted by fold.  */
!   if (gimple_assign_subcode (stmt1) == NOP_EXPR
!       || gimple_assign_subcode (stmt1) == CONVERT_EXPR)
      {
!       t = gimple_assign_rhs1 (stmt1);
        if (TREE_CODE (t) != SSA_NAME
  	  || !has_single_use (t))
  	return stmt;
        stmt1 = SSA_NAME_DEF_STMT (t);
!       if (gimple_code (stmt1) != GIMPLE_ASSIGN)
  	return stmt;
      }
  
    /* Verify that B is loop invariant but A is not.  Verify that with
       all the stmt walking we are still in the same loop.  */
!   if (gimple_assign_subcode (stmt1) != RSHIFT_EXPR
!       || loop_containing_stmt (stmt1) != loop_containing_stmt (stmt))
!     return stmt;
! 
!   a = gimple_assign_rhs1 (stmt1);
!   b = gimple_assign_rhs2 (stmt1);
  
+   if (outermost_invariant_loop (b, loop_containing_stmt (stmt1)) != NULL
+       && outermost_invariant_loop (a, loop_containing_stmt (stmt1)) == NULL)
+     {
        /* 1 << B */
        var = create_tmp_var (TREE_TYPE (a), "shifttmp");
        add_referenced_var (var);
        t = fold_build2 (LSHIFT_EXPR, TREE_TYPE (a),
  		       build_int_cst (TREE_TYPE (a), 1), b);
!       stmt1 = gimple_build_assign (var, t);
        name = make_ssa_name (var, stmt1);
!       gimple_assign_set_lhs (stmt1, name);
  
        /* A & (1 << B) */
        t = fold_build2 (BIT_AND_EXPR, TREE_TYPE (a), a, name);
!       stmt2 = gimple_build_assign (var, t);
        name = make_ssa_name (var, stmt2);
!       gimple_assign_set_lhs (stmt2, name);
        SET_USE (use, name);
  
!       gsi_insert_before (bsi, stmt1, GSI_SAME_STMT);
!       gsi_replace (bsi, stmt2, true);
  
        return stmt1;
      }
*************** determine_invariantness_stmt (struct dom
*** 708,717 ****
  			      basic_block bb)
  {
    enum move_pos pos;
!   block_stmt_iterator bsi;
!   tree stmt, rhs;
    bool maybe_never = ALWAYS_EXECUTED_IN (bb) == NULL;
    struct loop *outermost = ALWAYS_EXECUTED_IN (bb);
  
    if (!loop_outer (bb->loop_father))
      return;
--- 705,715 ----
  			      basic_block bb)
  {
    enum move_pos pos;
!   gimple_stmt_iterator bsi;
!   gimple stmt;
    bool maybe_never = ALWAYS_EXECUTED_IN (bb) == NULL;
    struct loop *outermost = ALWAYS_EXECUTED_IN (bb);
+   struct lim_aux_data *lim_data;
  
    if (!loop_outer (bb->loop_father))
      return;
*************** determine_invariantness_stmt (struct dom
*** 720,728 ****
      fprintf (dump_file, "Basic block %d (loop %d -- depth %d):\n\n",
  	     bb->index, bb->loop_father->num, loop_depth (bb->loop_father));
  
!   for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
      {
!       stmt = bsi_stmt (bsi);
  
        pos = movement_possibility (stmt);
        if (pos == MOVE_IMPOSSIBLE)
--- 718,726 ----
      fprintf (dump_file, "Basic block %d (loop %d -- depth %d):\n\n",
  	     bb->index, bb->loop_father->num, loop_depth (bb->loop_father));
  
!   for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
      {
!       stmt = gsi_stmt (bsi);
  
        pos = movement_possibility (stmt);
        if (pos == MOVE_IMPOSSIBLE)
*************** determine_invariantness_stmt (struct dom
*** 735,788 ****
  	  continue;
  	}
  
!       if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
  	{
! 	  rhs = GIMPLE_STMT_OPERAND (stmt, 1);
  
  	  /* If divisor is invariant, convert a/b to a*(1/b), allowing reciprocal
  	     to be hoisted out of loop, saving expensive divide.  */
  	  if (pos == MOVE_POSSIBLE
! 	      && TREE_CODE (rhs) == RDIV_EXPR
  	      && flag_unsafe_math_optimizations
  	      && !flag_trapping_math
! 	      && outermost_invariant_loop_expr (TREE_OPERAND (rhs, 1),
! 						loop_containing_stmt (stmt)) != NULL
! 	      && outermost_invariant_loop_expr (rhs,
! 						loop_containing_stmt (stmt)) == NULL)
  	    stmt = rewrite_reciprocal (&bsi);
  
  	  /* If the shift count is invariant, convert (A >> B) & 1 to
  	     A & (1 << B) allowing the bit mask to be hoisted out of the loop
  	     saving an expensive shift.  */
  	  if (pos == MOVE_POSSIBLE
! 	      && TREE_CODE (rhs) == BIT_AND_EXPR
! 	      && integer_onep (TREE_OPERAND (rhs, 1))
! 	      && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
! 	      && has_single_use (TREE_OPERAND (rhs, 0)))
  	    stmt = rewrite_bittest (&bsi);
  	}
  
!       stmt_ann (stmt)->common.aux = xcalloc (1, sizeof (struct lim_aux_data));
!       LIM_DATA (stmt)->always_executed_in = outermost;
  
        if (maybe_never && pos == MOVE_PRESERVE_EXECUTION)
  	continue;
  
        if (!determine_max_movement (stmt, pos == MOVE_PRESERVE_EXECUTION))
  	{
! 	  LIM_DATA (stmt)->max_loop = NULL;
  	  continue;
  	}
  
        if (dump_file && (dump_flags & TDF_DETAILS))
  	{
! 	  print_generic_stmt_indented (dump_file, stmt, 0, 2);
  	  fprintf (dump_file, "  invariant up to level %d, cost %d.\n\n",
! 		   loop_depth (LIM_DATA (stmt)->max_loop),
! 		   LIM_DATA (stmt)->cost);
  	}
  
!       if (LIM_DATA (stmt)->cost >= LIM_EXPENSIVE)
  	set_profitable_level (stmt);
      }
  }
--- 733,789 ----
  	  continue;
  	}
  
!       if (gimple_code (stmt) == GIMPLE_ASSIGN
! 	  && (get_gimple_rhs_class (gimple_assign_subcode (stmt))
! 	      == GIMPLE_BINARY_RHS))
  	{
! 	  tree op0 = gimple_assign_rhs1 (stmt);
! 	  tree op1 = gimple_assign_rhs2 (stmt);
! 	  struct loop *ol1 = outermost_invariant_loop (op1,
! 					loop_containing_stmt (stmt));
  
  	  /* If divisor is invariant, convert a/b to a*(1/b), allowing reciprocal
  	     to be hoisted out of loop, saving expensive divide.  */
  	  if (pos == MOVE_POSSIBLE
! 	      && gimple_assign_subcode (stmt) == RDIV_EXPR
  	      && flag_unsafe_math_optimizations
  	      && !flag_trapping_math
! 	      && ol1 != NULL
! 	      && outermost_invariant_loop (op0, ol1) == NULL)
  	    stmt = rewrite_reciprocal (&bsi);
  
  	  /* If the shift count is invariant, convert (A >> B) & 1 to
  	     A & (1 << B) allowing the bit mask to be hoisted out of the loop
  	     saving an expensive shift.  */
  	  if (pos == MOVE_POSSIBLE
! 	      && gimple_assign_subcode (stmt) == BIT_AND_EXPR
! 	      && integer_onep (op1)
! 	      && TREE_CODE (op0) == SSA_NAME
! 	      && has_single_use (op0))
  	    stmt = rewrite_bittest (&bsi);
  	}
  
!       lim_data = init_lim_data (stmt);
!       lim_data->always_executed_in = outermost;
  
        if (maybe_never && pos == MOVE_PRESERVE_EXECUTION)
  	continue;
  
        if (!determine_max_movement (stmt, pos == MOVE_PRESERVE_EXECUTION))
  	{
! 	  lim_data->max_loop = NULL;
  	  continue;
  	}
  
        if (dump_file && (dump_flags & TDF_DETAILS))
  	{
! 	  print_gimple_stmt (dump_file, stmt, 2, 0);
  	  fprintf (dump_file, "  invariant up to level %d, cost %d.\n\n",
! 		   loop_depth (lim_data->max_loop),
! 		   lim_data->cost);
  	}
  
!       if (lim_data->cost >= LIM_EXPENSIVE)
  	set_profitable_level (stmt);
      }
  }
*************** move_computations_stmt (struct dom_walk_
*** 815,862 ****
  			basic_block bb)
  {
    struct loop *level;
!   block_stmt_iterator bsi;
!   tree stmt;
    unsigned cost = 0;
  
    if (!loop_outer (bb->loop_father))
      return;
  
!   for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
      {
!       stmt = bsi_stmt (bsi);
  
!       if (!LIM_DATA (stmt))
  	{
! 	  bsi_next (&bsi);
  	  continue;
  	}
  
!       cost = LIM_DATA (stmt)->cost;
!       level = LIM_DATA (stmt)->tgt_loop;
!       free_lim_aux_data (LIM_DATA (stmt));
!       stmt_ann (stmt)->common.aux = NULL;
  
        if (!level)
  	{
! 	  bsi_next (&bsi);
  	  continue;
  	}
  
        /* We do not really want to move conditionals out of the loop; we just
  	 placed it here to force its operands to be moved if necessary.  */
!       if (TREE_CODE (stmt) == COND_EXPR)
  	continue;
  
        if (dump_file && (dump_flags & TDF_DETAILS))
  	{
  	  fprintf (dump_file, "Moving statement\n");
! 	  print_generic_stmt (dump_file, stmt, 0);
  	  fprintf (dump_file, "(cost %u) out of loop %d.\n\n",
  		   cost, level->num);
  	}
!       bsi_insert_on_edge (loop_preheader_edge (level), stmt);
!       bsi_remove (&bsi, false);
      }
  }
  
--- 816,864 ----
  			basic_block bb)
  {
    struct loop *level;
!   gimple_stmt_iterator bsi;
!   gimple stmt;
    unsigned cost = 0;
+   struct lim_aux_data *lim_data;
  
    if (!loop_outer (bb->loop_father))
      return;
  
!   for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); )
      {
!       stmt = gsi_stmt (bsi);
  
!       lim_data = get_lim_data (stmt);
!       if (lim_data == NULL)
  	{
! 	  gsi_next (&bsi);
  	  continue;
  	}
  
!       cost = lim_data->cost;
!       level = lim_data->tgt_loop;
!       clear_lim_data (stmt);
  
        if (!level)
  	{
! 	  gsi_next (&bsi);
  	  continue;
  	}
  
        /* We do not really want to move conditionals out of the loop; we just
  	 placed it here to force its operands to be moved if necessary.  */
!       if (gimple_code (stmt) == GIMPLE_COND)
  	continue;
  
        if (dump_file && (dump_flags & TDF_DETAILS))
  	{
  	  fprintf (dump_file, "Moving statement\n");
! 	  print_gimple_stmt (dump_file, stmt, 0, 0);
  	  fprintf (dump_file, "(cost %u) out of loop %d.\n\n",
  		   cost, level->num);
  	}
!       gsi_remove (&bsi, false);
!       gsi_insert_on_edge (loop_preheader_edge (level), stmt);
      }
  }
  
*************** move_computations (void)
*** 876,882 ****
    walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
    fini_walk_dominator_tree (&walk_data);
  
!   bsi_commit_edge_inserts ();
    if (need_ssa_update_p ())
      rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
  }
--- 878,884 ----
    walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
    fini_walk_dominator_tree (&walk_data);
  
!   gsi_commit_edge_inserts ();
    if (need_ssa_update_p ())
      rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
  }
*************** move_computations (void)
*** 887,906 ****
  static bool
  may_move_till (tree ref, tree *index, void *data)
  {
!   struct loop *loop = (struct loop*) data, *max_loop;
  
    /* If REF is an array reference, check also that the step and the lower
       bound is invariant in LOOP.  */
    if (TREE_CODE (ref) == ARRAY_REF)
      {
!       tree step = array_ref_element_size (ref);
!       tree lbound = array_ref_low_bound (ref);
  
!       max_loop = outermost_invariant_loop_expr (step, loop);
        if (!max_loop)
  	return false;
  
!       max_loop = outermost_invariant_loop_expr (lbound, loop);
        if (!max_loop)
  	return false;
      }
--- 889,908 ----
  static bool
  may_move_till (tree ref, tree *index, void *data)
  {
!   struct loop *loop = (struct loop *) data, *max_loop;
  
    /* If REF is an array reference, check also that the step and the lower
       bound is invariant in LOOP.  */
    if (TREE_CODE (ref) == ARRAY_REF)
      {
!       tree step = TREE_OPERAND (ref, 3);
!       tree lbound = TREE_OPERAND (ref, 2);
  
!       max_loop = outermost_invariant_loop (step, loop);
        if (!max_loop)
  	return false;
  
!       max_loop = outermost_invariant_loop (lbound, loop);
        if (!max_loop)
  	return false;
      }
*************** may_move_till (tree ref, tree *index, vo
*** 912,946 ****
    return true;
  }
  
! /* Forces statements defining (invariant) SSA names in expression EXPR to be
     moved out of the LOOP.  ORIG_LOOP is the loop in that EXPR is used.  */
  
  static void
! force_move_till_expr (tree expr, struct loop *orig_loop, struct loop *loop)
  {
!   enum tree_code_class codeclass = TREE_CODE_CLASS (TREE_CODE (expr));
!   unsigned i, nops;
! 
!   if (TREE_CODE (expr) == SSA_NAME)
!     {
!       tree stmt = SSA_NAME_DEF_STMT (expr);
!       if (IS_EMPTY_STMT (stmt))
! 	return;
  
!       set_level (stmt, orig_loop, loop);
!       return;
!     }
  
!   if (codeclass != tcc_unary
!       && codeclass != tcc_binary
!       && codeclass != tcc_expression
!       && codeclass != tcc_vl_exp
!       && codeclass != tcc_comparison)
      return;
  
!   nops = TREE_OPERAND_LENGTH (expr);
!   for (i = 0; i < nops; i++)
!     force_move_till_expr (TREE_OPERAND (expr, i), orig_loop, loop);
  }
  
  /* Forces statement defining invariants in REF (and *INDEX) to be moved out of
--- 914,938 ----
    return true;
  }
  
! /* If OP is SSA NAME, force the statement that defines it to be
     moved out of the LOOP.  ORIG_LOOP is the loop in that EXPR is used.  */
  
  static void
! force_move_till_op (tree op, struct loop *orig_loop, struct loop *loop)
  {
!   gimple stmt;
  
!   if (!op
!       || is_gimple_min_invariant (op))
!     return;
  
!   gcc_assert (TREE_CODE (op) == SSA_NAME);
!       
!   stmt = SSA_NAME_DEF_STMT (op);
!   if (gimple_nop_p (stmt))
      return;
  
!   set_level (stmt, orig_loop, loop);
  }
  
  /* Forces statement defining invariants in REF (and *INDEX) to be moved out of
*************** struct fmt_data
*** 956,981 ****
  static bool
  force_move_till (tree ref, tree *index, void *data)
  {
-   tree stmt;
    struct fmt_data *fmt_data = (struct fmt_data *) data;
  
    if (TREE_CODE (ref) == ARRAY_REF)
      {
!       tree step = array_ref_element_size (ref);
!       tree lbound = array_ref_low_bound (ref);
  
!       force_move_till_expr (step, fmt_data->orig_loop, fmt_data->loop);
!       force_move_till_expr (lbound, fmt_data->orig_loop, fmt_data->loop);
      }
  
!   if (TREE_CODE (*index) != SSA_NAME)
!     return true;
! 
!   stmt = SSA_NAME_DEF_STMT (*index);
!   if (IS_EMPTY_STMT (stmt))
!     return true;
! 
!   set_level (stmt, fmt_data->orig_loop, fmt_data->loop);
  
    return true;
  }
--- 948,965 ----
  static bool
  force_move_till (tree ref, tree *index, void *data)
  {
    struct fmt_data *fmt_data = (struct fmt_data *) data;
  
    if (TREE_CODE (ref) == ARRAY_REF)
      {
!       tree step = TREE_OPERAND (ref, 3);
!       tree lbound = TREE_OPERAND (ref, 2);
  
!       force_move_till_op (step, fmt_data->orig_loop, fmt_data->loop);
!       force_move_till_op (lbound, fmt_data->orig_loop, fmt_data->loop);
      }
  
!   force_move_till_op (*index, fmt_data->orig_loop, fmt_data->loop);
  
    return true;
  }
*************** force_move_till (tree ref, tree *index, 
*** 984,990 ****
     occurs in statement STMT.  */
  
  static void
! record_mem_ref_loc (struct mem_ref_loc **mem_refs, tree stmt, tree *ref)
  {
    struct mem_ref_loc *aref = XNEW (struct mem_ref_loc);
  
--- 968,974 ----
     occurs in statement STMT.  */
  
  static void
! record_mem_ref_loc (struct mem_ref_loc **mem_refs, gimple stmt, tree *ref)
  {
    struct mem_ref_loc *aref = XNEW (struct mem_ref_loc);
  
*************** schedule_sm (struct loop *loop, VEC (edg
*** 1154,1162 ****
    struct mem_ref_loc *aref;
    tree tmp_var;
    unsigned i;
!   tree load, store;
    struct fmt_data fmt_data;
    edge ex;
  
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
--- 1138,1147 ----
    struct mem_ref_loc *aref;
    tree tmp_var;
    unsigned i;
!   gimple load, store;
    struct fmt_data fmt_data;
    edge ex;
+   struct lim_aux_data *lim_data;
  
    if (dump_file && (dump_flags & TDF_DETAILS))
      {
*************** schedule_sm (struct loop *loop, VEC (edg
*** 1174,1196 ****
  
    rewrite_mem_refs (tmp_var, mem_refs);
    for (aref = mem_refs; aref; aref = aref->next)
!     if (LIM_DATA (aref->stmt))
!       LIM_DATA (aref->stmt)->sm_done = true;
  
    /* Emit the load & stores.  */
!   load = build_gimple_modify_stmt (tmp_var, ref);
!   get_stmt_ann (load)->common.aux = xcalloc (1, sizeof (struct lim_aux_data));
!   LIM_DATA (load)->max_loop = loop;
!   LIM_DATA (load)->tgt_loop = loop;
  
    /* Put this into the latch, so that we are sure it will be processed after
       all dependencies.  */
!   bsi_insert_on_edge (loop_latch_edge (loop), load);
  
    for (i = 0; VEC_iterate (edge, exits, i, ex); i++)
      {
!       store = build_gimple_modify_stmt (unshare_expr (ref), tmp_var);
!       bsi_insert_on_edge (ex, store);
      }
  }
  
--- 1159,1184 ----
  
    rewrite_mem_refs (tmp_var, mem_refs);
    for (aref = mem_refs; aref; aref = aref->next)
!     {
!       lim_data = get_lim_data (aref->stmt);
!       if (lim_data != NULL)
! 	lim_data->sm_done = true;
!     }
  
    /* Emit the load & stores.  */
!   load = gimple_build_assign (tmp_var, ref);
!   lim_data = init_lim_data (load);
!   lim_data->max_loop = loop;
!   lim_data->tgt_loop = loop;
  
    /* Put this into the latch, so that we are sure it will be processed after
       all dependencies.  */
!   gsi_insert_on_edge (loop_latch_edge (loop), load);
  
    for (i = 0; VEC_iterate (edge, exits, i, ex); i++)
      {
!       store = gimple_build_assign (unshare_expr (ref), tmp_var);
!       gsi_insert_on_edge (ex, store);
      }
  }
  
*************** determine_lsm_ref (struct loop *loop, VE
*** 1208,1213 ****
--- 1196,1202 ----
  {
    struct mem_ref_loc *aref;
    struct loop *must_exec;
+   struct lim_aux_data *lim_data;
  
    /* In case the memory is not stored to, there is nothing for SM to do.  */
    if (!ref->is_stored)
*************** determine_lsm_ref (struct loop *loop, VE
*** 1233,1242 ****
  
        for (aref = ref->locs; aref; aref = aref->next)
  	{
! 	  if (!LIM_DATA (aref->stmt))
  	    continue;
  
! 	  must_exec = LIM_DATA (aref->stmt)->always_executed_in;
  	  if (!must_exec)
  	    continue;
  
--- 1222,1232 ----
  
        for (aref = ref->locs; aref; aref = aref->next)
  	{
! 	  lim_data = get_lim_data (aref->stmt);
! 	  if (lim_data == NULL)
  	    continue;
  
! 	  must_exec = lim_data->always_executed_in;
  	  if (!must_exec)
  	    continue;
  
*************** memref_eq (const void *obj1, const void 
*** 1310,1316 ****
  
  static void
  gather_mem_refs_stmt (struct loop *loop, htab_t mem_refs,
! 		      bitmap clobbered_vops, tree stmt,
  		      struct mem_ref **mem_ref_list)
  {
    tree *lhs, *rhs, *mem = NULL;
--- 1300,1306 ----
  
  static void
  gather_mem_refs_stmt (struct loop *loop, htab_t mem_refs,
! 		      bitmap clobbered_vops, gimple stmt,
  		      struct mem_ref **mem_ref_list)
  {
    tree *lhs, *rhs, *mem = NULL;
*************** gather_mem_refs_stmt (struct loop *loop,
*** 1320,1346 ****
    ssa_op_iter oi;
    tree vname;
    bool is_stored;
  
    if (ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
      return;
  
    /* Recognize MEM = (SSA_NAME | invariant) and SSA_NAME = MEM patterns.  */
!   if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
      goto fail;
  
!   lhs = &GIMPLE_STMT_OPERAND (stmt, 0);
!   rhs = &GIMPLE_STMT_OPERAND (stmt, 1);
  
    if (TREE_CODE (*lhs) == SSA_NAME)
      {
!       if (!is_gimple_addressable (*rhs))
  	goto fail;
  
        mem = rhs;
        is_stored = false;
      }
!   else if (TREE_CODE (*rhs) == SSA_NAME
! 	   || is_gimple_min_invariant (*rhs))
      {
        mem = lhs;
        is_stored = true;
--- 1310,1342 ----
    ssa_op_iter oi;
    tree vname;
    bool is_stored;
+   enum tree_code rhs_code;
  
    if (ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
      return;
  
    /* Recognize MEM = (SSA_NAME | invariant) and SSA_NAME = MEM patterns.  */
!   if (gimple_code (stmt) != GIMPLE_ASSIGN)
      goto fail;
  
!   lhs = gimple_assign_lhs_ptr (stmt);
!   rhs_code = gimple_assign_subcode (stmt);
!   if (get_gimple_rhs_class (rhs_code) == GIMPLE_SINGLE_RHS)
!     rhs = gimple_assign_rhs1_ptr (stmt);
!   else
!     rhs = NULL;
  
    if (TREE_CODE (*lhs) == SSA_NAME)
      {
!       if (rhs == NULL || !is_gimple_addressable (*rhs))
  	goto fail;
  
        mem = rhs;
        is_stored = false;
      }
!   else if (rhs
! 	   && (TREE_CODE (*rhs) == SSA_NAME
! 	       || is_gimple_min_invariant (*rhs)))
      {
        mem = lhs;
        is_stored = true;
*************** static struct mem_ref *
*** 1394,1408 ****
  gather_mem_refs (struct loop *loop, bitmap clobbered_vops)
  {
    basic_block *body = get_loop_body (loop);
!   block_stmt_iterator bsi;
    unsigned i;
    struct mem_ref *mem_ref_list = NULL;
    htab_t mem_refs = htab_create (100, memref_hash, memref_eq, NULL);
  
    for (i = 0; i < loop->num_nodes; i++)
      {
!       for (bsi = bsi_start (body[i]); !bsi_end_p (bsi); bsi_next (&bsi))
! 	gather_mem_refs_stmt (loop, mem_refs, clobbered_vops, bsi_stmt (bsi),
  			      &mem_ref_list);
      }
  
--- 1390,1404 ----
  gather_mem_refs (struct loop *loop, bitmap clobbered_vops)
  {
    basic_block *body = get_loop_body (loop);
!   gimple_stmt_iterator bsi;
    unsigned i;
    struct mem_ref *mem_ref_list = NULL;
    htab_t mem_refs = htab_create (100, memref_hash, memref_eq, NULL);
  
    for (i = 0; i < loop->num_nodes; i++)
      {
!       for (bsi = gsi_start_bb (body[i]); !gsi_end_p (bsi); gsi_next (&bsi))
! 	gather_mem_refs_stmt (loop, mem_refs, clobbered_vops, gsi_stmt (bsi),
  			      &mem_ref_list);
      }
  
*************** determine_lsm (void)
*** 1510,1516 ****
        determine_lsm_loop (loop);
      }
  
!   bsi_commit_edge_inserts ();
  }
  
  /* Fills ALWAYS_EXECUTED_IN information for basic blocks of LOOP, i.e.
--- 1506,1512 ----
        determine_lsm_loop (loop);
      }
  
!   gsi_commit_edge_inserts ();
  }
  
  /* Fills ALWAYS_EXECUTED_IN information for basic blocks of LOOP, i.e.
*************** static void
*** 1587,1606 ****
  tree_ssa_lim_initialize (void)
  {
    sbitmap contains_call = sbitmap_alloc (last_basic_block);
!   block_stmt_iterator bsi;
    struct loop *loop;
    basic_block bb;
  
    sbitmap_zero (contains_call);
    FOR_EACH_BB (bb)
      {
!       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
  	{
! 	  if (nonpure_call_p (bsi_stmt (bsi)))
  	    break;
  	}
  
!       if (!bsi_end_p (bsi))
  	SET_BIT (contains_call, bb->index);
      }
  
--- 1583,1602 ----
  tree_ssa_lim_initialize (void)
  {
    sbitmap contains_call = sbitmap_alloc (last_basic_block);
!   gimple_stmt_iterator bsi;
    struct loop *loop;
    basic_block bb;
  
    sbitmap_zero (contains_call);
    FOR_EACH_BB (bb)
      {
!       for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
  	{
! 	  if (nonpure_call_p (gsi_stmt (bsi)))
  	    break;
  	}
  
!       if (!gsi_end_p (bsi))
  	SET_BIT (contains_call, bb->index);
      }
  
*************** tree_ssa_lim_initialize (void)
*** 1608,1613 ****
--- 1604,1611 ----
      fill_always_executed_in (loop, contains_call);
  
    sbitmap_free (contains_call);
+ 
+   lim_aux_data_map = pointer_map_create ();
  }
  
  /* Cleans up after the invariant motion pass.  */
*************** tree_ssa_lim_finalize (void)
*** 1621,1626 ****
--- 1619,1626 ----
      {
        bb->aux = NULL;
      }
+ 
+   pointer_map_destroy (lim_aux_data_map);
  }
  
  /* Moves invariants from loops.  Only "expensive" invariants are moved out --
*************** tree_ssa_lim (void)
*** 1645,1648 ****
  
    tree_ssa_lim_finalize ();
  }
- #endif
--- 1645,1647 ----
Index: tree-ssa-loop-manip.c
===================================================================
*** tree-ssa-loop-manip.c	(revision 132706)
--- tree-ssa-loop-manip.c	(working copy)
*************** create_iv (tree base, tree step, tree va
*** 128,140 ****
    add_phi_arg (stmt, initial, loop_preheader_edge (loop));
    add_phi_arg (stmt, va, loop_latch_edge (loop));
  }
  
  /* Add exit phis for the USE on EXIT.  */
  
  static void
  add_exit_phis_edge (basic_block exit, tree use)
  {
!   tree phi, def_stmt = SSA_NAME_DEF_STMT (use);
    basic_block def_bb = gimple_bb (def_stmt);
    struct loop *def_loop;
    edge e;
--- 128,141 ----
    add_phi_arg (stmt, initial, loop_preheader_edge (loop));
    add_phi_arg (stmt, va, loop_latch_edge (loop));
  }
+ #endif
  
  /* Add exit phis for the USE on EXIT.  */
  
  static void
  add_exit_phis_edge (basic_block exit, tree use)
  {
!   gimple phi, def_stmt = SSA_NAME_DEF_STMT (use);
    basic_block def_bb = gimple_bb (def_stmt);
    struct loop *def_loop;
    edge e;
*************** add_exit_phis_edge (basic_block exit, tr
*** 153,159 ****
      return;
  
    phi = create_phi_node (use, exit);
!   create_new_def_for (PHI_RESULT (phi), phi, PHI_RESULT_PTR (phi));
    FOR_EACH_EDGE (e, ei, exit->preds)
      add_phi_arg (phi, use, e);
  }
--- 154,161 ----
      return;
  
    phi = create_phi_node (use, exit);
!   create_new_def_for (gimple_phi_result (phi), phi,
! 		      gimple_phi_result_ptr (phi));
    FOR_EACH_EDGE (e, ei, exit->preds)
      add_phi_arg (phi, use, e);
  }
*************** find_uses_to_rename_use (basic_block bb,
*** 267,273 ****
     NEED_PHIS.  */
  
  static void
! find_uses_to_rename_stmt (tree stmt, bitmap *use_blocks, bitmap need_phis)
  {
    ssa_op_iter iter;
    tree var;
--- 269,275 ----
     NEED_PHIS.  */
  
  static void
! find_uses_to_rename_stmt (gimple stmt, bitmap *use_blocks, bitmap need_phis)
  {
    ssa_op_iter iter;
    tree var;
*************** find_uses_to_rename_stmt (tree stmt, bit
*** 285,302 ****
  static void
  find_uses_to_rename_bb (basic_block bb, bitmap *use_blocks, bitmap need_phis)
  {
!   block_stmt_iterator bsi;
    edge e;
    edge_iterator ei;
-   tree phi;
  
    FOR_EACH_EDGE (e, ei, bb->succs)
!     for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi))
!       find_uses_to_rename_use (bb, PHI_ARG_DEF_FROM_EDGE (phi, e),
  			       use_blocks, need_phis);
   
!   for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
!     find_uses_to_rename_stmt (bsi_stmt (bsi), use_blocks, need_phis);
  }
       
  /* Marks names that are used outside of the loop they are defined in
--- 287,305 ----
  static void
  find_uses_to_rename_bb (basic_block bb, bitmap *use_blocks, bitmap need_phis)
  {
!   gimple_stmt_iterator bsi;
    edge e;
    edge_iterator ei;
  
    FOR_EACH_EDGE (e, ei, bb->succs)
!     for (bsi = gsi_start (phi_nodes (e->dest)); 
! 	 !gsi_end_p (bsi);
! 	 gsi_next (&bsi))
!       find_uses_to_rename_use (bb, PHI_ARG_DEF_FROM_EDGE (gsi_stmt (bsi), e),
  			       use_blocks, need_phis);
   
!   for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
!     find_uses_to_rename_stmt (gsi_stmt (bsi), use_blocks, need_phis);
  }
       
  /* Marks names that are used outside of the loop they are defined in
*************** rewrite_into_loop_closed_ssa (bitmap cha
*** 404,410 ****
  static void
  check_loop_closed_ssa_use (basic_block bb, tree use)
  {
!   tree def;
    basic_block def_bb;
    
    if (TREE_CODE (use) != SSA_NAME || !is_gimple_reg (use))
--- 407,413 ----
  static void
  check_loop_closed_ssa_use (basic_block bb, tree use)
  {
!   gimple def;
    basic_block def_bb;
    
    if (TREE_CODE (use) != SSA_NAME || !is_gimple_reg (use))
*************** check_loop_closed_ssa_use (basic_block b
*** 419,425 ****
  /* Checks invariants of loop closed ssa form in statement STMT in BB.  */
  
  static void
! check_loop_closed_ssa_stmt (basic_block bb, tree stmt)
  {
    ssa_op_iter iter;
    tree var;
--- 422,428 ----
  /* Checks invariants of loop closed ssa form in statement STMT in BB.  */
  
  static void
! check_loop_closed_ssa_stmt (basic_block bb, gimple stmt)
  {
    ssa_op_iter iter;
    tree var;
*************** void
*** 434,442 ****
  verify_loop_closed_ssa (void)
  {
    basic_block bb;
!   block_stmt_iterator bsi;
!   tree phi;
!   unsigned i;
  
    if (number_of_loops () <= 1)
      return;
--- 437,446 ----
  verify_loop_closed_ssa (void)
  {
    basic_block bb;
!   gimple_stmt_iterator bsi;
!   gimple phi;
!   edge e;
!   edge_iterator ei;
  
    if (number_of_loops () <= 1)
      return;
*************** verify_loop_closed_ssa (void)
*** 445,460 ****
  
    FOR_EACH_BB (bb)
      {
!       for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
! 	for (i = 0; i < (unsigned) PHI_NUM_ARGS (phi); i++)
! 	  check_loop_closed_ssa_use (PHI_ARG_EDGE (phi, i)->src,
! 				     PHI_ARG_DEF (phi, i));
  
!       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
! 	check_loop_closed_ssa_stmt (bb, bsi_stmt (bsi));
      }
  }
  
  /* Split loop exit edge EXIT.  The things are a bit complicated by a need to
     preserve the loop closed ssa form.  The newly created block is returned.  */
  
--- 449,469 ----
  
    FOR_EACH_BB (bb)
      {
!       for (bsi = gsi_start (phi_nodes (bb)); !gsi_end_p (bsi); gsi_next (&bsi))
! 	{
! 	  phi = gsi_stmt (bsi);
! 	  FOR_EACH_EDGE (e, ei, bb->preds)
! 	    check_loop_closed_ssa_use (e->src,
! 				       PHI_ARG_DEF_FROM_EDGE (phi, e));
! 	}
  
!       for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
! 	check_loop_closed_ssa_stmt (bb, gsi_stmt (bsi));
      }
  }
  
+ /* FIXME tuples.  */
+ #if 0
  /* Split loop exit edge EXIT.  The things are a bit complicated by a need to
     preserve the loop closed ssa form.  The newly created block is returned.  */
  
Index: gimple-dummy.c
===================================================================
*** gimple-dummy.c	(revision 132706)
--- gimple-dummy.c	(working copy)
*************** DUMMY_FN (multiply_by_cost)
*** 65,71 ****
  DUMMY_FN (nowrap_type_p)
  DUMMY_FN (optimize_inline_calls)
  DUMMY_FN (remove_empty_loops)
- DUMMY_FN (rewrite_into_loop_closed_ssa)
  DUMMY_FN (scev_const_prop)
  DUMMY_FN (scev_finalize)
  DUMMY_FN (scev_initialize)
--- 65,70 ----
*************** DUMMY_FN (gimple_duplicate_loop_to_heade
*** 75,81 ****
  DUMMY_FN (tree_function_versioning)
  DUMMY_FN (tree_int_cst_sign_bit)
  DUMMY_FN (tree_ssa_iv_optimize)
- DUMMY_FN (tree_ssa_lim)
  DUMMY_FN (tree_ssa_prefetch_arrays)
  DUMMY_FN (tree_ssa_unswitch_loops)
  DUMMY_FN (tree_unroll_loops_completely)
--- 74,79 ----
*************** DUMMY_FN (tree_versionable_function_p)
*** 83,94 ****
  DUMMY_FN (vec_set_verbosity_level)
  DUMMY_FN (vect_set_verbosity_level)
  DUMMY_FN (vectorize_loops)
- DUMMY_FN (verify_loop_closed_ssa)
  DUMMY_FN (number_of_iterations_exit)
  DUMMY_FN (loop_niter_by_eval)
  DUMMY_FN (estimated_loop_iterations_int)
  DUMMY_FN (substitute_in_loop_info)
- DUMMY_FN (replace_exp)
  DUMMY_FN (remove_iv)
  DUMMY_FN (omp_reduction_init)
  DUMMY_FN (diagnose_omp_structured_block_errors)
--- 81,90 ----
Index: tree-ssa-loop.c
===================================================================
*** tree-ssa-loop.c	(revision 132706)
--- tree-ssa-loop.c	(working copy)
*************** tree_ssa_loop_init (void)
*** 81,87 ****
--- 81,90 ----
    if (number_of_loops () <= 1)
      return 0;
  
+ /* FIXME tuples.  */
+ #if 0
    scev_initialize ();
+ #endif
    return 0;
  }
    
*************** struct tree_opt_pass pass_iv_optimize =
*** 580,587 ****
--- 583,593 ----
  static unsigned int
  tree_ssa_loop_done (void)
  {
+ /* FIXME tuples.  */
+ #if 0
    free_numbers_of_iterations_estimates ();
    scev_finalize ();
+ #endif
    loop_optimizer_finalize ();
    return 0;
  }
Index: gimple-iterator.c
===================================================================
*** gimple-iterator.c	(revision 132706)
--- gimple-iterator.c	(working copy)
*************** gsi_insert_after (gimple_stmt_iterator *
*** 370,384 ****
  /* Remove the current stmt from the sequence.  The iterator is updated
     to point to the next statement.
  
!    When REMOVE_EH_INFO is true we remove the statement pointed to by
!    iterator I from the EH tables.  Otherwise we do not modify the EH
!    tables.
! 
!    Generally, REMOVE_EH_INFO should be true when the statement is
!    going to be removed from the IL and not reinserted elsewhere.  */
  
  void
! gsi_remove (gimple_stmt_iterator *i, bool remove_eh_info)
  {
    gimple_seq_node cur, next, prev;
    gimple stmt = gsi_stmt (*i);
--- 370,382 ----
  /* Remove the current stmt from the sequence.  The iterator is updated
     to point to the next statement.
  
!    REMOVE_PERMANENTLY is true when the statement is going to be removed
!    from the IL and not reinserted elsewhere.  In that case we remove the
!    statement pointed to by iterator I from the EH tables, and free its
!    operand caches.  Otherwise we do not modify this information.  */
  
  void
! gsi_remove (gimple_stmt_iterator *i, bool remove_permanently)
  {
    gimple_seq_node cur, next, prev;
    gimple stmt = gsi_stmt (*i);
*************** gsi_remove (gimple_stmt_iterator *i, boo
*** 386,396 ****
    /* Free all the data flow information for STMT.  */
    gimple_set_bb (stmt, NULL);
    delink_stmt_imm_use (stmt);
-   free_stmt_operands (stmt);
    gimple_set_modified (stmt, true);
  
!   if (remove_eh_info)
      {
        remove_stmt_from_eh_region (stmt);
        gimple_remove_stmt_histograms (cfun, stmt);
      }
--- 384,394 ----
    /* Free all the data flow information for STMT.  */
    gimple_set_bb (stmt, NULL);
    delink_stmt_imm_use (stmt);
    gimple_set_modified (stmt, true);
  
!   if (remove_permanently)
      {
+       free_stmt_operands (stmt);
        remove_stmt_from_eh_region (stmt);
        gimple_remove_stmt_histograms (cfun, stmt);
      }
*************** restart:
*** 541,547 ****
  
        if (gsi_end_p (*gsi))
  	{
! 	  *gsi = gsi_last (bb_seq (dest));
  	  return true;
  	}
        else
--- 539,545 ----
  
        if (gsi_end_p (*gsi))
  	{
! 	  *gsi = gsi_last_bb (dest);
  	  return true;
  	}
        else
*************** restart:
*** 556,562 ****
        && single_succ_p (src)
        && src != ENTRY_BLOCK_PTR)
      {
!       *gsi = gsi_last (bb_seq (src));
        if (gsi_end_p (*gsi))
  	return true;
  
--- 554,560 ----
        && single_succ_p (src)
        && src != ENTRY_BLOCK_PTR)
      {
!       *gsi = gsi_last_bb (src);
        if (gsi_end_p (*gsi))
  	return true;
  
Index: tree-eh.c
===================================================================
*** tree-eh.c	(revision 132706)
--- tree-eh.c	(working copy)
*************** verify_eh_edges (tree stmt)
*** 2011,2093 ****
  #endif
  
  
! /* Return true if EXPR can trap, as in dereferencing an invalid pointer
!    location or floating point arithmetic.  C.f. the rtl version, may_trap_p.
!    This routine expects only GIMPLE lhs or rhs input.  */
  
  bool
! tree_could_trap_p (tree expr)
  {
!   enum tree_code code = TREE_CODE (expr);
!   bool honor_nans = false;
!   bool honor_snans = false;
!   bool fp_operation = false;
!   bool honor_trapv = false;
!   tree t, base;
! 
!   if (TREE_CODE_CLASS (code) == tcc_comparison
!       || TREE_CODE_CLASS (code) == tcc_unary
!       || TREE_CODE_CLASS (code) == tcc_binary)
!     {
!       t = TREE_TYPE (expr);
!       fp_operation = FLOAT_TYPE_P (t);
!       if (fp_operation)
! 	{
! 	  honor_nans = flag_trapping_math && !flag_finite_math_only;
! 	  honor_snans = flag_signaling_nans != 0;
! 	}
!       else if (INTEGRAL_TYPE_P (t) && TYPE_OVERFLOW_TRAPS (t))
! 	honor_trapv = true;
!     }
  
!  restart:
!   switch (code)
      {
-     case TARGET_MEM_REF:
-       /* For TARGET_MEM_REFs use the information based on the original
- 	 reference.  */
-       expr = TMR_ORIGINAL (expr);
-       code = TREE_CODE (expr);
-       goto restart;
- 
-     case COMPONENT_REF:
-     case REALPART_EXPR:
-     case IMAGPART_EXPR:
-     case BIT_FIELD_REF:
-     case VIEW_CONVERT_EXPR:
-     case WITH_SIZE_EXPR:
-       expr = TREE_OPERAND (expr, 0);
-       code = TREE_CODE (expr);
-       goto restart;
- 
-     case ARRAY_RANGE_REF:
-       base = TREE_OPERAND (expr, 0);
-       if (tree_could_trap_p (base))
- 	return true;
- 
-       if (TREE_THIS_NOTRAP (expr))
- 	return false;
- 
-       return !range_in_array_bounds_p (expr);
- 
-     case ARRAY_REF:
-       base = TREE_OPERAND (expr, 0);
-       if (tree_could_trap_p (base))
- 	return true;
- 
-       if (TREE_THIS_NOTRAP (expr))
- 	return false;
- 
-       return !in_array_bounds_p (expr);
- 
-     case INDIRECT_REF:
-     case ALIGN_INDIRECT_REF:
-     case MISALIGNED_INDIRECT_REF:
-       return !TREE_THIS_NOTRAP (expr);
- 
-     case ASM_EXPR:
-       return TREE_THIS_VOLATILE (expr);
- 
      case TRUNC_DIV_EXPR:
      case CEIL_DIV_EXPR:
      case FLOOR_DIV_EXPR:
--- 2011,2036 ----
  #endif
  
  
! /* Return true if operation OP may trap.  FP_OPERATION is true if OP is applied
!    on floating-point values.  HONOR_TRAPV is true if OP is applied on integer
!    type operands that may trap.  If OP is a division operator, DIVISOR contains
!    the value of the divisor.  */
  
  bool
! operation_could_trap_p (enum tree_code op, bool fp_operation, bool honor_trapv,
! 			tree divisor)
  {
!   bool honor_nans = (fp_operation && flag_trapping_math
! 		     && !flag_finite_math_only);
!   bool honor_snans = fp_operation && flag_signaling_nans != 0;
! 
!   if (TREE_CODE_CLASS (op) != tcc_comparison
!       || TREE_CODE_CLASS (op) != tcc_unary
!       || TREE_CODE_CLASS (op) != tcc_binary)
!     return false;
  
!   switch (op)
      {
      case TRUNC_DIV_EXPR:
      case CEIL_DIV_EXPR:
      case FLOOR_DIV_EXPR:
*************** tree_could_trap_p (tree expr)
*** 2102,2109 ****
  	return true;
        if (fp_operation)
  	return flag_trapping_math;
!       t = TREE_OPERAND (expr, 1);
!       if (!TREE_CONSTANT (t) || integer_zerop (t))
          return true;
        return false;
  
--- 2045,2051 ----
  	return true;
        if (fp_operation)
  	return flag_trapping_math;
!       if (!TREE_CONSTANT (divisor) || integer_zerop (divisor))
          return true;
        return false;
  
*************** tree_could_trap_p (tree expr)
*** 2149,2154 ****
--- 2091,2183 ----
  	return true;
        return false;
  
+     default:
+       /* Any floating arithmetic may trap.  */
+       if (fp_operation && flag_trapping_math)
+ 	return true;
+ 
+       return false;
+     }
+ }
+ 
+ /* Return true if EXPR can trap, as in dereferencing an invalid pointer
+    location or floating point arithmetic.  C.f. the rtl version, may_trap_p.
+    This routine expects only GIMPLE lhs or rhs input.  */
+ 
+ bool
+ tree_could_trap_p (tree expr)
+ {
+   enum tree_code code;
+   bool fp_operation = false;
+   bool honor_trapv = false;
+   tree t, base, div = NULL_TREE;
+ 
+   if (!expr)
+     return false;
+  
+   code = TREE_CODE (expr);
+   t = TREE_TYPE (expr);
+ 
+   if (t)
+     {
+       fp_operation = FLOAT_TYPE_P (t);
+       honor_trapv = INTEGRAL_TYPE_P (t) && TYPE_OVERFLOW_TRAPS (t);
+     }
+ 
+   if (TREE_CODE_CLASS (code) == tcc_binary)
+     div = TREE_OPERAND (expr, 1);
+   if (operation_could_trap_p (code, fp_operation, honor_trapv, div))
+     return true;
+ 
+  restart:
+   switch (code)
+     {
+     case TARGET_MEM_REF:
+       /* For TARGET_MEM_REFs use the information based on the original
+ 	 reference.  */
+       expr = TMR_ORIGINAL (expr);
+       code = TREE_CODE (expr);
+       goto restart;
+ 
+     case COMPONENT_REF:
+     case REALPART_EXPR:
+     case IMAGPART_EXPR:
+     case BIT_FIELD_REF:
+     case VIEW_CONVERT_EXPR:
+     case WITH_SIZE_EXPR:
+       expr = TREE_OPERAND (expr, 0);
+       code = TREE_CODE (expr);
+       goto restart;
+ 
+     case ARRAY_RANGE_REF:
+       base = TREE_OPERAND (expr, 0);
+       if (tree_could_trap_p (base))
+ 	return true;
+ 
+       if (TREE_THIS_NOTRAP (expr))
+ 	return false;
+ 
+       return !range_in_array_bounds_p (expr);
+ 
+     case ARRAY_REF:
+       base = TREE_OPERAND (expr, 0);
+       if (tree_could_trap_p (base))
+ 	return true;
+ 
+       if (TREE_THIS_NOTRAP (expr))
+ 	return false;
+ 
+       return !in_array_bounds_p (expr);
+ 
+     case INDIRECT_REF:
+     case ALIGN_INDIRECT_REF:
+     case MISALIGNED_INDIRECT_REF:
+       return !TREE_THIS_NOTRAP (expr);
+ 
+     case ASM_EXPR:
+       return TREE_THIS_VOLATILE (expr);
+ 
+ 
      case CALL_EXPR:
        t = get_callee_fndecl (expr);
        /* Assume that calls to weak functions may trap.  */
*************** tree_could_trap_p (tree expr)
*** 2157,2165 ****
        return false;
  
      default:
-       /* Any floating arithmetic may trap.  */
-       if (fp_operation && flag_trapping_math)
- 	return true;
        return false;
      }
  }
--- 2186,2191 ----
Index: tree-ssa-copy.c
===================================================================
*** tree-ssa-copy.c	(revision 132706)
--- tree-ssa-copy.c	(working copy)
*************** propagate_value (use_operand_p op_p, tre
*** 336,341 ****
--- 336,352 ----
    replace_exp_1 (op_p, val, true);
  }
  
+ /* Replace *OP_P with value VAL (assumed to be a constant or another SSA_NAME).
+ 
+    Use this version when not const/copy propagating values.  For example,
+    PRE uses this version when building expressions as they would appear
+    in specific blocks taking into account actions of PHI nodes.  */
+ 
+ void
+ replace_exp (use_operand_p op_p, tree val)
+ {
+   replace_exp_1 (op_p, val, false);
+ }
  
  /* FIXME tuples.  */
  #if 0
*************** propagate_tree_value (tree *op_p, tree v
*** 367,385 ****
  }
  
  
- /* Replace *OP_P with value VAL (assumed to be a constant or another SSA_NAME).
- 
-    Use this version when not const/copy propagating values.  For example,
-    PRE uses this version when building expressions as they would appear
-    in specific blocks taking into account actions of PHI nodes.  */
- 
- void
- replace_exp (use_operand_p op_p, tree val)
- {
-   replace_exp_1 (op_p, val, false);
- }
- 
- 
  /*---------------------------------------------------------------------------
  				Copy propagation
  ---------------------------------------------------------------------------*/
--- 378,383 ----
Index: tree-flow.h
===================================================================
*** tree-flow.h	(revision 132706)
--- tree-flow.h	(working copy)
*************** enum move_pos
*** 1033,1039 ****
  				   become executed -- memory accesses, ... */
      MOVE_POSSIBLE		/* Unlimited movement.  */
    };
! extern enum move_pos movement_possibility (tree);
  char *get_lsm_tmp_name (tree, unsigned);
  
  /* In tree-flow-inline.h  */
--- 1033,1039 ----
  				   become executed -- memory accesses, ... */
      MOVE_POSSIBLE		/* Unlimited movement.  */
    };
! extern enum move_pos movement_possibility (gimple);
  char *get_lsm_tmp_name (tree, unsigned);
  
  /* In tree-flow-inline.h  */
*************** static inline bool unmodifiable_var_p (c
*** 1045,1050 ****
--- 1045,1051 ----
  /* In tree-eh.c  */
  extern void make_eh_edges (gimple);
  extern bool tree_could_trap_p (tree);
+ extern bool operation_could_trap_p (enum tree_code, bool, bool, tree);
  extern bool stmt_could_throw_p (gimple);
  extern bool tree_could_throw_p (tree);
  extern bool stmt_can_throw_internal (gimple);
Index: Makefile.in
===================================================================
*** Makefile.in	(revision 132706)
--- Makefile.in	(working copy)
*************** tree-ssa-loop-im.o : tree-ssa-loop-im.c 
*** 2208,2214 ****
     $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) domwalk.h \
     $(PARAMS_H) output.h $(DIAGNOSTIC_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
     $(TREE_DUMP_H) tree-pass.h $(FLAGS_H) $(REAL_H) $(BASIC_BLOCK_H) \
!    hard-reg-set.h
  tree-ssa-math-opts.o : tree-ssa-math-opts.c $(TREE_FLOW_H) $(CONFIG_H) \
     $(SYSTEM_H) $(TREE_H) $(TIMEVAR_H) tree-pass.h $(TM_H) $(FLAGS_H) \
     alloc-pool.h $(BASIC_BLOCK_H) $(TARGET_H)
--- 2208,2214 ----
     $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) domwalk.h \
     $(PARAMS_H) output.h $(DIAGNOSTIC_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
     $(TREE_DUMP_H) tree-pass.h $(FLAGS_H) $(REAL_H) $(BASIC_BLOCK_H) \
!    hard-reg-set.h pointer-set.h
  tree-ssa-math-opts.o : tree-ssa-math-opts.c $(TREE_FLOW_H) $(CONFIG_H) \
     $(SYSTEM_H) $(TREE_H) $(TIMEVAR_H) tree-pass.h $(TM_H) $(FLAGS_H) \
     alloc-pool.h $(BASIC_BLOCK_H) $(TARGET_H)
*************** tree-gimple.o : tree-gimple.c $(CONFIG_H
*** 2313,2319 ****
     output.h $(TREE_FLOW_H)
  gimple.o : gimple.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
     $(GGC_H) $(TREE_GIMPLE_H) $(GIMPLE_H) $(DIAGNOSTIC_H) gt-gimple.h \
!    $(TREE_FLOW_H) value-prof.h
  # FIXME tuples.  Do not merge.
  gimple-dummy.o: gimple-dummy.c $(CONFIG_H) $(SYSTEM_H)
  gimple-pretty-print.o : gimple-pretty-print.c $(CONFIG_H) $(SYSTEM_H) \
--- 2313,2319 ----
     output.h $(TREE_FLOW_H)
  gimple.o : gimple.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \
     $(GGC_H) $(TREE_GIMPLE_H) $(GIMPLE_H) $(DIAGNOSTIC_H) gt-gimple.h \
!    $(TREE_FLOW_H) value-prof.h $(FLAGS_H)
  # FIXME tuples.  Do not merge.
  gimple-dummy.o: gimple-dummy.c $(CONFIG_H) $(SYSTEM_H)
  gimple-pretty-print.o : gimple-pretty-print.c $(CONFIG_H) $(SYSTEM_H) \
Index: gimple.c
===================================================================
*** gimple.c	(revision 132706)
--- gimple.c	(working copy)
*************** Software Foundation, 51 Franklin Street,
*** 34,39 ****
--- 34,40 ----
  #include "diagnostic.h"
  #include "tree-flow.h"
  #include "value-prof.h"
+ #include "flags.h"
  
  #define DEFGSCODE(SYM, NAME)	NAME,
  const char *const gimple_code_name[] = {
*************** gimple_seq_has_side_effects (gimple_seq 
*** 1770,1773 ****
--- 1771,1818 ----
    return false;
  }
  
+ /* Return true if statement S can trap.  */
+ 
+ bool
+ gimple_could_trap_p (gimple s)
+ {
+   size_t i;
+   tree t, div = NULL_TREE;
+   enum tree_code op;
+ 
+   for (i = 0; i < gimple_num_ops (s); i++)
+     if (tree_could_trap_p (gimple_op (s, i)))
+       return true;
+ 
+   switch (gimple_code (s))
+     {
+     case GIMPLE_ASM:
+       return gimple_asm_volatile_p (s);
+ 
+     case GIMPLE_CALL:
+       t = gimple_call_fndecl (s);
+       /* Assume that calls to weak functions may trap.  */
+       if (!t || !DECL_P (t) || DECL_WEAK (t))
+ 	return true;
+       return false;
+ 
+     case GIMPLE_ASSIGN:
+       t = gimple_expr_type (s);
+       op = gimple_subcode (s);
+       if (get_gimple_rhs_class (op) == GIMPLE_BINARY_RHS)
+ 	div = gimple_assign_rhs2 (s);
+       if (operation_could_trap_p (op,
+ 				  FLOAT_TYPE_P (t),
+ 				  (INTEGRAL_TYPE_P (t)
+ 				   && TYPE_OVERFLOW_TRAPS (t)),
+ 				  div))
+ 	return true;
+       return false;
+ 
+     default:
+       return false;
+     }
+ 
+ }
+ 
  #include "gt-gimple.h"
Index: gimple.h
===================================================================
*** gimple.h	(revision 132706)
--- gimple.h	(working copy)
*************** gimple gimple_build_cond_from_tree (tree
*** 569,574 ****
--- 569,575 ----
  void gimple_cond_set_condition_from_tree (gimple, tree);
  bool gimple_has_side_effects (gimple);
  bool gimple_seq_has_side_effects (gimple_seq);
+ bool gimple_could_trap_p (gimple);
  
  /* In builtins.c  */
  extern bool validate_arglist (const_gimple, ...);
Index: tree-cfg.c
===================================================================
*** tree-cfg.c	(revision 132706)
--- tree-cfg.c	(working copy)
*************** replace_uses_by (tree name, tree val)
*** 1282,1288 ****
  	  for (i = 0; i < gimple_num_ops (stmt); i++)
  	    {
  	      tree op = gimple_op (stmt, i);
! 	      if (TREE_CODE (op) == ADDR_EXPR)
  		recompute_tree_invariant_for_addr_expr (op);
  	    }
  
--- 1282,1288 ----
  	  for (i = 0; i < gimple_num_ops (stmt); i++)
  	    {
  	      tree op = gimple_op (stmt, i);
! 	      if (op && TREE_CODE (op) == ADDR_EXPR)
  		recompute_tree_invariant_for_addr_expr (op);
  	    }
  
Index: passes.c
===================================================================
*** passes.c	(revision 132706)
--- passes.c	(working copy)
*************** init_optimization_passes (void)
*** 642,654 ****
--- 642,658 ----
        NEXT_PASS (pass_split_crit_edges);
        NEXT_PASS (pass_pre);
        NEXT_PASS (pass_sink_code);
+ #endif
        NEXT_PASS (pass_tree_loop);
  	{
  	  struct tree_opt_pass **p = &pass_tree_loop.sub;
  	  NEXT_PASS (pass_tree_loop_init);
+ #if 0
  	  NEXT_PASS (pass_copy_prop);
  	  NEXT_PASS (pass_dce_loop);
+ #endif
  	  NEXT_PASS (pass_lim);
+ #if 0
  	  NEXT_PASS (pass_predcom);
  	  NEXT_PASS (pass_tree_unswitch);
  	  NEXT_PASS (pass_scev_cprop);
*************** init_optimization_passes (void)
*** 668,675 ****
--- 672,681 ----
  	  NEXT_PASS (pass_parallelize_loops);
  	  NEXT_PASS (pass_loop_prefetch);
  	  NEXT_PASS (pass_iv_optimize);
+ #endif
  	  NEXT_PASS (pass_tree_loop_done);
  	}
+ #if 0
        NEXT_PASS (pass_cse_reciprocals);
        NEXT_PASS (pass_convert_to_rsqrt);
        NEXT_PASS (pass_reassoc);


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