hashval_t
rename_map_elt_info (const void *elt)
{
- return htab_hash_pointer (((const struct rename_map_elt_s *) elt)->old_name);
+ return SSA_NAME_VERSION (((const struct rename_map_elt_s *) elt)->old_name);
}
/* Compares database elements E1 and E2. */
PHI_ARG_DEF_FROM_EDGE (gsi_stmt (bsi), e));
for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
- FOR_EACH_SSA_USE_OPERAND (use_p, gsi_stmt (bsi), iter, SSA_OP_ALL_USES)
- sese_build_liveouts_use (region, liveouts, bb, USE_FROM_PTR (use_p));
+ {
+ gimple stmt = gsi_stmt (bsi);
+
+ if (is_gimple_debug (stmt))
+ continue;
+
+ FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_ALL_USES)
+ sese_build_liveouts_use (region, liveouts, bb, USE_FROM_PTR (use_p));
+ }
+}
+
+/* For a USE in BB, return true if BB is outside REGION and it's not
+ in the LIVEOUTS set. */
+
+static bool
+sese_bad_liveouts_use (sese region, bitmap liveouts, basic_block bb,
+ tree use)
+{
+ unsigned ver;
+ basic_block def_bb;
+
+ if (TREE_CODE (use) != SSA_NAME)
+ return false;
+
+ ver = SSA_NAME_VERSION (use);
+
+ /* If it's in liveouts, the variable will get a new PHI node, and
+ the debug use will be properly adjusted. */
+ if (bitmap_bit_p (liveouts, ver))
+ return false;
+
+ def_bb = gimple_bb (SSA_NAME_DEF_STMT (use));
+
+ if (!def_bb
+ || !bb_in_sese_p (def_bb, region)
+ || bb_in_sese_p (bb, region))
+ return false;
+
+ return true;
+}
+
+/* Reset debug stmts that reference SSA_NAMES defined in REGION that
+ are not marked as liveouts. */
+
+static void
+sese_reset_debug_liveouts_bb (sese region, bitmap liveouts, basic_block bb)
+{
+ gimple_stmt_iterator bsi;
+ ssa_op_iter iter;
+ use_operand_p use_p;
+
+ for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+ {
+ gimple stmt = gsi_stmt (bsi);
+
+ if (!is_gimple_debug (stmt))
+ continue;
+
+ FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_ALL_USES)
+ if (sese_bad_liveouts_use (region, liveouts, bb,
+ USE_FROM_PTR (use_p)))
+ {
+ gimple_debug_bind_reset_value (stmt);
+ update_stmt (stmt);
+ break;
+ }
+ }
}
/* Build the LIVEOUTS of REGION: the set of variables defined inside
FOR_EACH_BB (bb)
sese_build_liveouts_bb (region, liveouts, bb);
+ if (MAY_HAVE_DEBUG_INSNS)
+ FOR_EACH_BB (bb)
+ sese_reset_debug_liveouts_bb (region, liveouts, bb);
}
/* Builds a new SESE region from edges ENTRY and EXIT. */
SESE_LOOP_NEST (region) = VEC_alloc (loop_p, heap, 3);
SESE_ADD_PARAMS (region) = true;
SESE_PARAMS (region) = VEC_alloc (tree, heap, 3);
- SESE_PARAMS_INDEX (region) = htab_create (10, clast_name_index_elt_info,
- eq_clast_name_indexes, free);
- SESE_PARAMS_NAMES (region) = XNEWVEC (char *, num_ssa_names);
return region;
}
SESE_LOOPS (region) = BITMAP_ALLOC (NULL);
VEC_free (tree, heap, SESE_PARAMS (region));
- VEC_free (loop_p, heap, SESE_LOOP_NEST (region));
-
- if (SESE_PARAMS_INDEX (region))
- htab_delete (SESE_PARAMS_INDEX (region));
-
- /* Do not free SESE_PARAMS_NAMES: CLooG does that. */
+ VEC_free (loop_p, heap, SESE_LOOP_NEST (region));
XDELETE (region);
}
get_vdef_before_sese (sese region, tree name, sbitmap visited)
{
unsigned i;
- gimple def_stmt = SSA_NAME_DEF_STMT (name);
- basic_block def_bb = gimple_bb (def_stmt);
+ gimple stmt = SSA_NAME_DEF_STMT (name);
+ basic_block def_bb = gimple_bb (stmt);
if (!def_bb || !bb_in_sese_p (def_bb, region))
return name;
SET_BIT (visited, def_bb->index);
- switch (gimple_code (def_stmt))
+ switch (gimple_code (stmt))
{
case GIMPLE_PHI:
- for (i = 0; i < gimple_phi_num_args (def_stmt); i++)
+ for (i = 0; i < gimple_phi_num_args (stmt); i++)
{
- tree arg = gimple_phi_arg_def (def_stmt, i);
- tree res = get_vdef_before_sese (region, arg, visited);
+ tree arg = gimple_phi_arg_def (stmt, i);
+ tree res;
+
+ if (gimple_bb (SSA_NAME_DEF_STMT (arg))
+ && def_bb->index == gimple_bb (SSA_NAME_DEF_STMT (arg))->index)
+ continue;
+
+ res = get_vdef_before_sese (region, arg, visited);
if (res)
return res;
}
return NULL_TREE;
+ case GIMPLE_ASSIGN:
+ case GIMPLE_CALL:
+ {
+ use_operand_p use_p = gimple_vuse_op (stmt);
+ tree use = USE_FROM_PTR (use_p);
+
+ if (def_bb->index == gimple_bb (SSA_NAME_DEF_STMT (use))->index)
+ RESET_BIT (visited, def_bb->index);
+
+ return get_vdef_before_sese (region, use, visited);
+ }
+
default:
return NULL_TREE;
}
}
}
-/* Returns the name associated to OLD_NAME in MAP. */
+/* Returns the expression associated to OLD_NAME in MAP. */
static tree
get_rename (htab_t map, tree old_name)
struct rename_map_elt_s tmp;
PTR *slot;
+ gcc_assert (TREE_CODE (old_name) == SSA_NAME);
tmp.old_name = old_name;
slot = htab_find_slot (map, &tmp, NO_INSERT);
return old_name;
}
-/* Register in MAP the rename tuple (old_name, expr). */
+/* Register in MAP the rename tuple (OLD_NAME, EXPR). */
void
set_rename (htab_t map, tree old_name, tree expr)
*slot = new_rename_map_elt (old_name, expr);
}
+/* Renames the expression T following the tuples (OLD_NAME, EXPR) in
+ the rename map M. Returns the expression T after renaming. */
+
+static tree
+rename_variables_in_expr (htab_t m, tree t)
+{
+ if (!t)
+ return t;
+
+ if (TREE_CODE (t) == SSA_NAME)
+ return get_rename (m, t);
+
+ switch (TREE_CODE_LENGTH (TREE_CODE (t)))
+ {
+ case 3:
+ TREE_OPERAND (t, 2) = rename_variables_in_expr (m, TREE_OPERAND (t, 2));
+
+ case 2:
+ TREE_OPERAND (t, 1) = rename_variables_in_expr (m, TREE_OPERAND (t, 1));
+
+ case 1:
+ TREE_OPERAND (t, 0) = rename_variables_in_expr (m, TREE_OPERAND (t, 0));
+
+ default:
+ return t;
+ }
+}
+
+/* Renames all the loop->nb_iterations expressions following the
+ tuples (OLD_NAME, EXPR) in RENAME_MAP. */
+
+void
+rename_nb_iterations (htab_t rename_map)
+{
+ loop_iterator li;
+ struct loop *loop;
+
+ FOR_EACH_LOOP (li, loop, 0)
+ loop->nb_iterations = rename_variables_in_expr (rename_map,
+ loop->nb_iterations);
+}
+
+/* Renames all the parameters of SESE following the tuples (OLD_NAME,
+ EXPR) in RENAME_MAP. */
+
+void
+rename_sese_parameters (htab_t rename_map, sese region)
+{
+ int i;
+ tree p;
+
+ for (i = 0; VEC_iterate (tree, SESE_PARAMS (region), i, p); i++)
+ VEC_replace (tree, SESE_PARAMS (region), i,
+ rename_variables_in_expr (rename_map, p));
+}
+
/* Adjusts the phi nodes in the block BB for variables defined in
SCOP_REGION and used outside the SCOP_REGION. The code generation
moves SCOP_REGION in the else clause of an "if (1)" and generates
unsigned i;
unsigned false_i = 0;
gimple phi = gsi_stmt (si);
+ tree res = gimple_phi_result (phi);
- if (!is_gimple_reg (PHI_RESULT (phi)))
+ if (!is_gimple_reg (res))
{
sese_adjust_vphi (region, phi, true_e);
continue;
}
SET_PHI_ARG_DEF (phi, i, expr);
+ set_rename (rename_map, old_name, res);
}
}
}
/* Rename the SSA_NAMEs used in STMT and that appear in MAP. */
-static void
+static void
rename_variables_in_stmt (gimple stmt, htab_t map, gimple_stmt_iterator *insert_gsi)
{
ssa_op_iter iter;
FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_ALL_USES)
{
tree use = USE_FROM_PTR (use_p);
- tree expr = get_rename (map, use);
- tree type_use = TREE_TYPE (use);
- tree type_expr = TREE_TYPE (expr);
+ tree expr, type_use, type_expr;
gimple_seq stmts;
+ if (TREE_CODE (use) != SSA_NAME)
+ continue;
+
+ expr = get_rename (map, use);
if (use == expr)
continue;
+ type_use = TREE_TYPE (use);
+ type_expr = TREE_TYPE (expr);
+
if (type_use != type_expr
|| (TREE_CODE (expr) != SSA_NAME
&& is_gimple_reg (use)))
{
- tree var = create_tmp_var (type_use, "var");
+ tree var;
+
+ if (is_gimple_debug (stmt))
+ {
+ if (gimple_debug_bind_p (stmt))
+ gimple_debug_bind_reset_value (stmt);
+ else
+ gcc_unreachable ();
+
+ break;
+ }
+
+ var = create_tmp_var (type_use, "var");
if (type_use != type_expr)
expr = fold_convert (type_use, expr);
to translate the names of induction variables. */
static tree
-expand_scalar_variables_ssa_name (tree op0, basic_block bb,
- sese region, htab_t map,
+expand_scalar_variables_ssa_name (tree type, tree op0, basic_block bb,
+ sese region, htab_t map,
gimple_stmt_iterator *gsi)
{
gimple def_stmt;
tree new_op;
-
+
if (is_parameter (region, op0)
|| is_iv (op0))
- return get_rename (map, op0);
-
+ return fold_convert (type, get_rename (map, op0));
+
def_stmt = SSA_NAME_DEF_STMT (op0);
/* Check whether we already have a rename for OP0. */
if (new_op != op0
&& gimple_bb (SSA_NAME_DEF_STMT (new_op)) == bb)
- return new_op;
-
+ return fold_convert (type, new_op);
+
if (gimple_bb (def_stmt) == bb)
{
/* If the defining statement is in the basic block already
we do not need to create a new expression for it, we
only need to ensure its operands are expanded. */
expand_scalar_variables_stmt (def_stmt, bb, region, map, gsi);
- return new_op;
+ return fold_convert (type, new_op);
}
else
{
if (!gimple_bb (def_stmt)
|| !bb_in_sese_p (gimple_bb (def_stmt), region))
- return new_op;
+ return fold_convert (type, new_op);
switch (gimple_code (def_stmt))
{
used to translate the names of induction variables. */
static tree
-expand_scalar_variables_expr (tree type, tree op0, enum tree_code code,
- tree op1, basic_block bb, sese region,
+expand_scalar_variables_expr (tree type, tree op0, enum tree_code code,
+ tree op1, basic_block bb, sese region,
htab_t map, gimple_stmt_iterator *gsi)
{
if (TREE_CODE_CLASS (code) == tcc_constant
{
tree old_name = TREE_OPERAND (op0, 0);
tree expr = expand_scalar_variables_ssa_name
- (old_name, bb, region, map, gsi);
+ (type, old_name, bb, region, map, gsi);
if (TREE_CODE (expr) != SSA_NAME
&& is_gimple_reg (old_name))
return build4 (ARRAY_REF, type, base, subscript, op02, op03);
}
+ case COMPONENT_REF:
+ return op0;
+
default:
/* The above cases should catch everything. */
gcc_unreachable ();
enum tree_code op0_code = TREE_CODE (op0);
tree op0_expr = expand_scalar_variables_expr (op0_type, op0, op0_code,
NULL, bb, region, map, gsi);
-
+
return fold_build1 (code, type, op0_expr);
}
}
if (code == SSA_NAME)
- return expand_scalar_variables_ssa_name (op0, bb, region, map, gsi);
+ return expand_scalar_variables_ssa_name (type, op0, bb, region, map, gsi);
if (code == ADDR_EXPR)
- return op0;
+ {
+ tree op00 = TREE_OPERAND (op0, 0);
+
+ if (handled_component_p (op00)
+ && TREE_CODE (op00) == ARRAY_REF)
+ {
+ tree e = expand_scalar_variables_expr (TREE_TYPE (op00), op00,
+ TREE_CODE (op00),
+ NULL, bb, region, map, gsi);
+ return fold_build1 (code, TREE_TYPE (op0), e);
+ }
+
+ return op0;
+ }
gcc_unreachable ();
return NULL;
only induction variables from the generated code: MAP contains the
induction variables renaming mapping, and is used to translate the
names of induction variables. */
-
+
static void
expand_scalar_variables_stmt (gimple stmt, basic_block bb, sese region,
htab_t map, gimple_stmt_iterator *gsi)
if (use_expr == use)
continue;
+ if (is_gimple_debug (stmt))
+ {
+ if (gimple_debug_bind_p (stmt))
+ gimple_debug_bind_reset_value (stmt);
+ else
+ gcc_unreachable ();
+
+ break;
+ }
+
if (TREE_CODE (use_expr) != SSA_NAME)
{
tree var = create_tmp_var (type, "var");
induction variables renaming mapping, and is used to translate the
names of induction variables. */
-static void
+static void
expand_scalar_variables (basic_block bb, sese region, htab_t map)
{
gimple_stmt_iterator gsi;
-
+
for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi);)
{
gimple stmt = gsi_stmt (gsi);
/* Rename all the SSA_NAMEs from block BB according to the MAP. */
-static void
+static void
rename_variables (basic_block bb, htab_t map)
{
gimple_stmt_iterator gsi;
gimple_stmt_iterator insert_gsi = gsi_start_bb (bb);
-
+
for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi); gsi_next (&gsi))
rename_variables_in_stmt (gsi_stmt (gsi), map, &insert_gsi);
}
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->flags & EDGE_TRUE_VALUE)
+ if (e->flags & EDGE_TRUE_VALUE)
return e;
gcc_unreachable ();
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->succs)
- if (!(e->flags & EDGE_TRUE_VALUE))
+ if (!(e->flags & EDGE_TRUE_VALUE))
return e;
gcc_unreachable ();
/* Returns true when NAME is defined in LOOP. */
static bool
-defined_in_loop_p (tree name, loop_p loop)
+name_defined_in_loop_p (tree name, loop_p loop)
{
- gimple stmt = SSA_NAME_DEF_STMT (name);
+ return !SSA_NAME_IS_DEFAULT_DEF (name)
+ && gimple_bb (SSA_NAME_DEF_STMT (name))->loop_father == loop;
+}
+
+/* Returns true when EXPR contains SSA_NAMEs defined in LOOP. */
+
+static bool
+expr_defined_in_loop_p (tree expr, loop_p loop)
+{
+ switch (TREE_CODE_LENGTH (TREE_CODE (expr)))
+ {
+ case 3:
+ return expr_defined_in_loop_p (TREE_OPERAND (expr, 0), loop)
+ || expr_defined_in_loop_p (TREE_OPERAND (expr, 1), loop)
+ || expr_defined_in_loop_p (TREE_OPERAND (expr, 2), loop);
- return (gimple_bb (stmt)->loop_father == loop);
+ case 2:
+ return expr_defined_in_loop_p (TREE_OPERAND (expr, 0), loop)
+ || expr_defined_in_loop_p (TREE_OPERAND (expr, 1), loop);
+
+ case 1:
+ return expr_defined_in_loop_p (TREE_OPERAND (expr, 0), loop);
+
+ case 0:
+ return TREE_CODE (expr) == SSA_NAME
+ && name_defined_in_loop_p (expr, loop);
+
+ default:
+ return false;
+ }
}
/* Returns the gimple statement that uses NAME outside the loop it is
struct rename_map_elt_s *entry;
alep_p a;
loop_p loop;
- tree expr, new_name;
+ tree expr, new_name, old_name;
bool def_in_loop_p, used_outside_p, need_close_phi_p;
gimple old_close_phi;
- if (!slot || !data)
+ if (!slot || !*slot || !data)
return 1;
entry = (struct rename_map_elt_s *) *slot;
a = (alep_p) data;
loop = a->loop;
- expr = entry->expr;
+ new_name = expr = entry->expr;
+ old_name = entry->old_name;
+
+ def_in_loop_p = expr_defined_in_loop_p (expr, loop);
+ if (!def_in_loop_p)
+ return 1;
+
+ /* Remove the old rename from the map when the expression is defined
+ in the loop that we're closing. */
+ free (*slot);
+ *slot = NULL;
if (TREE_CODE (expr) != SSA_NAME)
return 1;
- new_name = expr;
- def_in_loop_p = defined_in_loop_p (new_name, loop);
- old_close_phi = alive_after_loop (entry->old_name);
+ old_close_phi = alive_after_loop (old_name);
used_outside_p = (old_close_phi != NULL);
- need_close_phi_p = (def_in_loop_p && used_outside_p
+ need_close_phi_p = (used_outside_p
&& close_phi_not_yet_inserted_p (loop, new_name));
/* Insert a loop close phi node. */
new_res));
}
- /* Remove the old rename from the map. */
- if (def_in_loop_p && *slot)
- {
- free (*slot);
- *slot = NULL;
- }
-
return 1;
}
return res;
}
+/* Prepares EXPR to be a good phi argument when the phi result is
+ RES. Insert needed statements on edge E. */
+
+static tree
+convert_for_phi_arg (tree expr, tree res, edge e)
+{
+ tree type = TREE_TYPE (res);
+
+ if (TREE_TYPE (expr) != type)
+ expr = fold_convert (type, expr);
+
+ if (TREE_CODE (expr) != SSA_NAME
+ && !is_gimple_min_invariant (expr))
+ {
+ tree var = create_tmp_var (type, "var");
+ gimple_seq stmts;
+
+ expr = build2 (MODIFY_EXPR, type, var, expr);
+ expr = force_gimple_operand (expr, &stmts, true, NULL);
+ gsi_insert_seq_on_edge_immediate (e, stmts);
+ }
+
+ return expr;
+}
+
/* Helper function for htab_traverse in insert_guard_phis. */
static int
basic_block bb = i->bb;
edge true_edge = i->true_edge;
edge false_edge = i->false_edge;
+ tree res = entry->old_name;
tree name1 = entry->expr;
- tree name2 = default_before_guard (i->before_guard, entry->old_name);
+ tree name2 = default_before_guard (i->before_guard, res);
gimple phi;
- tree res;
- gimple_seq stmts;
/* Nothing to be merged if the name before the guard is the same as
the one after. */
if (name1 == name2)
return 1;
- if (TREE_TYPE (name1) != TREE_TYPE (name2))
- name1 = fold_convert (TREE_TYPE (name2), name1);
-
- if (TREE_CODE (name1) != SSA_NAME
- && (TREE_CODE (name2) != SSA_NAME
- || is_gimple_reg (name2)))
- {
- tree type = TREE_TYPE (name2);
- tree var = create_tmp_var (type, "var");
-
- name1 = build2 (MODIFY_EXPR, type, var, name1);
- name1 = force_gimple_operand (name1, &stmts, true, NULL);
- gsi_insert_seq_on_edge_immediate (true_edge, stmts);
- }
+ name1 = convert_for_phi_arg (name1, res, true_edge);
+ name2 = convert_for_phi_arg (name2, res, false_edge);
- phi = create_phi_node (entry->old_name, bb);
+ phi = create_phi_node (res, bb);
res = create_new_def_for (gimple_phi_result (phi), phi,
gimple_phi_result_ptr (phi));
/* Iterate over RENAME_MAP and get tuples of the form (OLD, NAME1).
If there is a correspondent tuple (OLD, NAME2) in BEFORE_GUARD,
with NAME1 different than NAME2, then insert in BB the phi node:
-
+
| RES = phi (NAME1 (on TRUE_EDGE), NAME2 (on FALSE_EDGE))"
if there is no tuple for OLD in BEFORE_GUARD, insert
{
def_operand_p def_p;
ssa_op_iter op_iter;
- int region;
gimple stmt = gsi_stmt (gsi);
gimple copy;
gsi_insert_after (&gsi_tgt, copy, GSI_NEW_STMT);
mark_sym_for_renaming (gimple_vop (cfun));
- region = lookup_stmt_eh_region (stmt);
- if (region >= 0)
- add_stmt_to_eh_region (copy, region);
+ maybe_duplicate_eh_stmt (copy, stmt);
gimple_duplicate_stmt_histograms (cfun, copy, cfun, stmt);
/* Create new names for all the definitions created by COPY and
/* Copies BB and includes in the copied BB all the statements that can
be reached following the use-def chains from the memory accesses,
and returns the next edge following this new block. */
-
+
edge
copy_bb_and_scalar_dependences (basic_block bb, sese region,
edge next_e, htab_t map)
recompute_all_dominators ();
SESE_EXIT (region) = false_edge;
+
+ if (if_region->false_region)
+ free (if_region->false_region);
if_region->false_region = region;
if (slot)
{
edge e;
edge_iterator ei;
- sese sese_region = GGC_NEW (struct sese_s);
- sese true_region = GGC_NEW (struct sese_s);
- sese false_region = GGC_NEW (struct sese_s);
- ifsese if_region = GGC_NEW (struct ifsese_s);
+ sese sese_region = XNEW (struct sese_s);
+ sese true_region = XNEW (struct sese_s);
+ sese false_region = XNEW (struct sese_s);
+ ifsese if_region = XNEW (struct ifsese_s);
edge exit = create_empty_if_region_on_edge (entry, condition);
if_region->region = sese_region;
move_sese_in_condition (sese region)
{
basic_block pred_block = split_edge (SESE_ENTRY (region));
- ifsese if_region = NULL;
+ ifsese if_region;
SESE_ENTRY (region) = single_succ_edge (pred_block);
if_region = create_if_region_on_edge (single_pred_edge (pred_block), integer_one_node);
return if_region;
}
-/* Reset the loop->aux pointer for all loops in REGION. */
+/* Replaces the condition of the IF_REGION with CONDITION:
+ | if (CONDITION)
+ | true_region;
+ | else
+ | false_region;
+*/
void
-sese_reset_aux_in_loops (sese region)
+set_ifsese_condition (ifsese if_region, tree condition)
{
- int i;
- loop_p loop;
-
- for (i = 0; VEC_iterate (loop_p, SESE_LOOP_NEST (region), i, loop); i++)
- loop->aux = NULL;
+ sese region = if_region->region;
+ edge entry = region->entry;
+ basic_block bb = entry->dest;
+ gimple last = last_stmt (bb);
+ gimple_stmt_iterator gsi = gsi_last_bb (bb);
+ gimple cond_stmt;
+
+ gcc_assert (gimple_code (last) == GIMPLE_COND);
+
+ gsi_remove (&gsi, true);
+ gsi = gsi_last_bb (bb);
+ condition = force_gimple_operand_gsi (&gsi, condition, true, NULL,
+ false, GSI_NEW_STMT);
+ cond_stmt = gimple_build_cond_from_tree (condition, NULL_TREE, NULL_TREE);
+ gsi = gsi_last_bb (bb);
+ gsi_insert_after (&gsi, cond_stmt, GSI_NEW_STMT);
}
/* Returns the scalar evolution of T in REGION. Every variable that