This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[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);