re PR middle-end/38492 ([graphite] segfaulting code when compiled with -fgraphite -fgraphite-identity)

2009-01-05  Sebastian Pop  <sebastian.pop@amd.com>

	PR tree-optimization/38492
	* graphite.c (rename_map_elt, debug_rename_elt,
        debug_rename_map_1, debug_rename_map, new_rename_map_elt,
        rename_map_elt_info, eq_rename_map_elts,
        get_new_name_from_old_name, bb_in_sese_p): Moved around.
	(sese_find_uses_to_rename_use): Renamed sese_build_livein_liveouts_use.
	(sese_find_uses_to_rename_bb): Renamed sese_build_livein_liveouts_bb.
	(sese_build_livein_liveouts): New.
	(new_sese, free_sese): New.
	(new_scop): Call new_sese.
	(free_scop): Call free_sese.
	(rename_variables_from_edge, rename_phis_end_scop): Removed.
	(register_old_new_names): Renamed register_old_and_new_names.
	(register_scop_liveout_renames, add_loop_exit_phis,
	insert_loop_close_phis, struct igp,
	default_liveout_before_guard, add_guard_exit_phis,
	insert_guard_phis, copy_renames): New.
	(translate_clast): Call insert_loop_close_phis and insert_guard_phis.
	(sese_add_exit_phis_edge): Renamed scop_add_exit_phis_edge.
	(rewrite_into_sese_closed_ssa): Renamed scop_insert_phis_for_liveouts.
	(scop_adjust_phis_for_liveouts): New.
	(gloog): Call scop_adjust_phis_for_liveouts.

	* graphite.h (struct sese): Documented.  Added fields liveout,
        num_ver and livein.
	(SESE_LIVEOUT, SESE_LIVEIN, SESE_LIVEIN_VER, SESE_NUM_VER): New.
	(new_sese, free_sese, sese_build_livein_liveouts): Declared.
	(struct scop): Added field liveout_renames.
	(SCOP_LIVEOUT_RENAMES): New.

From-SVN: r143097
This commit is contained in:
Sebastian Pop 2009-01-05 21:21:16 +00:00 committed by Sebastian Pop
parent eefe5da052
commit 7b10257fdd
3 changed files with 533 additions and 227 deletions

View File

@ -1,3 +1,35 @@
2009-01-05 Sebastian Pop <sebastian.pop@amd.com>
PR tree-optimization/38492
* graphite.c (rename_map_elt, debug_rename_elt,
debug_rename_map_1, debug_rename_map, new_rename_map_elt,
rename_map_elt_info, eq_rename_map_elts,
get_new_name_from_old_name, bb_in_sese_p): Moved around.
(sese_find_uses_to_rename_use): Renamed sese_build_livein_liveouts_use.
(sese_find_uses_to_rename_bb): Renamed sese_build_livein_liveouts_bb.
(sese_build_livein_liveouts): New.
(new_sese, free_sese): New.
(new_scop): Call new_sese.
(free_scop): Call free_sese.
(rename_variables_from_edge, rename_phis_end_scop): Removed.
(register_old_new_names): Renamed register_old_and_new_names.
(register_scop_liveout_renames, add_loop_exit_phis,
insert_loop_close_phis, struct igp,
default_liveout_before_guard, add_guard_exit_phis,
insert_guard_phis, copy_renames): New.
(translate_clast): Call insert_loop_close_phis and insert_guard_phis.
(sese_add_exit_phis_edge): Renamed scop_add_exit_phis_edge.
(rewrite_into_sese_closed_ssa): Renamed scop_insert_phis_for_liveouts.
(scop_adjust_phis_for_liveouts): New.
(gloog): Call scop_adjust_phis_for_liveouts.
* graphite.h (struct sese): Documented. Added fields liveout,
num_ver and livein.
(SESE_LIVEOUT, SESE_LIVEIN, SESE_LIVEIN_VER, SESE_NUM_VER): New.
(new_sese, free_sese, sese_build_livein_liveouts): Declared.
(struct scop): Added field liveout_renames.
(SCOP_LIVEOUT_RENAMES): New.
2009-01-05 Harsha Jagasia <harsha.jagasia@amd.com>
PR tree-optimization/38510

View File

@ -1183,6 +1183,169 @@ free_graphite_bb (struct graphite_bb *gbb)
XDELETE (gbb);
}
/* Structure containing the mapping between the old names and the new
names used after block copy in the new loop context. */
typedef struct rename_map_elt
{
tree old_name, new_name;
} *rename_map_elt;
/* Print to stderr the element ELT. */
static void
debug_rename_elt (rename_map_elt elt)
{
fprintf (stderr, "(");
print_generic_expr (stderr, elt->old_name, 0);
fprintf (stderr, ", ");
print_generic_expr (stderr, elt->new_name, 0);
fprintf (stderr, ")\n");
}
/* Helper function for debug_rename_map. */
static int
debug_rename_map_1 (void **slot, void *s ATTRIBUTE_UNUSED)
{
struct rename_map_elt *entry = (struct rename_map_elt *) *slot;
debug_rename_elt (entry);
return 1;
}
/* Print to stderr all the elements of MAP. */
void
debug_rename_map (htab_t map)
{
htab_traverse (map, debug_rename_map_1, NULL);
}
/* Constructs a new SCEV_INFO_STR structure for VAR and INSTANTIATED_BELOW. */
static inline rename_map_elt
new_rename_map_elt (tree old_name, tree new_name)
{
rename_map_elt res;
res = XNEW (struct rename_map_elt);
res->old_name = old_name;
res->new_name = new_name;
return res;
}
/* Computes a hash function for database element ELT. */
static hashval_t
rename_map_elt_info (const void *elt)
{
return htab_hash_pointer (((const struct rename_map_elt *) elt)->old_name);
}
/* Compares database elements E1 and E2. */
static int
eq_rename_map_elts (const void *e1, const void *e2)
{
const struct rename_map_elt *elt1 = (const struct rename_map_elt *) e1;
const struct rename_map_elt *elt2 = (const struct rename_map_elt *) e2;
return (elt1->old_name == elt2->old_name);
}
/* Returns the new name associated to OLD_NAME in MAP. */
static tree
get_new_name_from_old_name (htab_t map, tree old_name)
{
struct rename_map_elt tmp;
PTR *slot;
tmp.old_name = old_name;
slot = htab_find_slot (map, &tmp, NO_INSERT);
if (slot && *slot)
return ((rename_map_elt) *slot)->new_name;
return old_name;
}
/* Returns true when BB is in REGION. */
static bool
bb_in_sese_p (basic_block bb, sese region)
{
return pointer_set_contains (SESE_REGION_BBS (region), bb);
}
/* For a USE in BB, if BB is outside REGION, mark the USE in the
SESE_LIVEIN and SESE_LIVEOUT sets. */
static void
sese_build_livein_liveouts_use (sese region, basic_block bb, tree use)
{
unsigned ver;
basic_block def_bb;
if (TREE_CODE (use) != SSA_NAME)
return;
ver = SSA_NAME_VERSION (use);
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;
if (!SESE_LIVEIN_VER (region, ver))
SESE_LIVEIN_VER (region, ver) = BITMAP_ALLOC (NULL);
bitmap_set_bit (SESE_LIVEIN_VER (region, ver), bb->index);
bitmap_set_bit (SESE_LIVEOUT (region), ver);
}
/* Marks for rewrite all the SSA_NAMES defined in REGION and that are
used in BB that is outside of the REGION. */
static void
sese_build_livein_liveouts_bb (sese region, basic_block bb)
{
gimple_stmt_iterator bsi;
edge e;
edge_iterator ei;
ssa_op_iter iter;
tree var;
FOR_EACH_EDGE (e, ei, bb->succs)
for (bsi = gsi_start_phis (e->dest); !gsi_end_p (bsi); gsi_next (&bsi))
sese_build_livein_liveouts_use (region, bb,
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_TREE_OPERAND (var, gsi_stmt (bsi), iter, SSA_OP_ALL_USES)
sese_build_livein_liveouts_use (region, bb, var);
}
/* Build the SESE_LIVEIN and SESE_LIVEOUT for REGION. */
void
sese_build_livein_liveouts (sese region)
{
basic_block bb;
SESE_LIVEOUT (region) = BITMAP_ALLOC (NULL);
SESE_NUM_VER (region) = num_ssa_names;
SESE_LIVEIN (region) = XCNEWVEC (bitmap, SESE_NUM_VER (region));
FOR_EACH_BB (bb)
sese_build_livein_liveouts_bb (region, bb);
}
/* Register basic blocks belonging to a region in a pointer set. */
static void
@ -1203,6 +1366,47 @@ register_bb_in_sese (basic_block entry_bb, basic_block exit_bb, sese region)
}
}
/* Builds a new SESE region from edges ENTRY and EXIT. */
sese
new_sese (edge entry, edge exit)
{
sese res = XNEW (struct sese);
SESE_ENTRY (res) = entry;
SESE_EXIT (res) = exit;
SESE_REGION_BBS (res) = pointer_set_create ();
register_bb_in_sese (entry->dest, exit->dest, res);
SESE_LIVEOUT (res) = NULL;
SESE_NUM_VER (res) = 0;
SESE_LIVEIN (res) = NULL;
return res;
}
/* Deletes REGION. */
void
free_sese (sese region)
{
int i;
for (i = 0; i < SESE_NUM_VER (region); i++)
BITMAP_FREE (SESE_LIVEIN_VER (region, i));
if (SESE_LIVEIN (region))
free (SESE_LIVEIN (region));
if (SESE_LIVEOUT (region))
BITMAP_FREE (SESE_LIVEOUT (region));
pointer_set_destroy (SESE_REGION_BBS (region));
XDELETE (region);
}
/* Creates a new scop starting with ENTRY. */
static scop_p
@ -1212,12 +1416,7 @@ new_scop (edge entry, edge exit)
gcc_assert (entry && exit);
SCOP_REGION (scop) = XNEW (struct sese);
SESE_ENTRY (SCOP_REGION (scop)) = entry;
SESE_EXIT (SCOP_REGION (scop)) = exit;
SESE_REGION_BBS (SCOP_REGION (scop)) = pointer_set_create ();
register_bb_in_sese (SCOP_ENTRY (scop), SCOP_EXIT (scop),
SCOP_REGION (scop));
SCOP_REGION (scop) = new_sese (entry, exit);
SCOP_BBS (scop) = VEC_alloc (graphite_bb_p, heap, 3);
SCOP_OLDIVS (scop) = VEC_alloc (name_tree, heap, 3);
SCOP_BBS_B (scop) = BITMAP_ALLOC (NULL);
@ -1230,6 +1429,8 @@ new_scop (edge entry, edge exit)
SCOP_LOOP2CLOOG_LOOP (scop) = htab_create (10, hash_loop_to_cloog_loop,
eq_loop_to_cloog_loop,
free);
SCOP_LIVEOUT_RENAMES (scop) = htab_create (10, rename_map_elt_info,
eq_rename_map_elts, free);
return scop;
}
@ -1261,7 +1462,8 @@ free_scop (scop_p scop)
VEC_free (name_tree, heap, SCOP_PARAMS (scop));
cloog_program_free (SCOP_PROG (scop));
htab_delete (SCOP_LOOP2CLOOG_LOOP (scop));
XDELETE (SCOP_REGION (scop));
htab_delete (SCOP_LIVEOUT_RENAMES (scop));
free_sese (SCOP_REGION (scop));
XDELETE (scop);
}
@ -3754,94 +3956,6 @@ graphite_create_new_loop (scop_p scop, edge entry_edge,
return loop;
}
/* Structure containing the mapping between the old names and the new
names used after block copy in the new loop context. */
typedef struct rename_map_elt
{
tree old_name, new_name;
} *rename_map_elt;
/* Print to stderr the element ELT. */
static void
debug_rename_elt (rename_map_elt elt)
{
fprintf (stderr, "(");
print_generic_expr (stderr, elt->old_name, 0);
fprintf (stderr, ", ");
print_generic_expr (stderr, elt->new_name, 0);
fprintf (stderr, ")\n");
}
/* Helper function for debug_rename_map. */
static int
debug_rename_map_1 (void **slot, void *s ATTRIBUTE_UNUSED)
{
struct rename_map_elt *entry = (struct rename_map_elt *) *slot;
debug_rename_elt (entry);
return 1;
}
/* Print to stderr all the elements of MAP. */
void
debug_rename_map (htab_t map)
{
htab_traverse (map, debug_rename_map_1, NULL);
}
/* Constructs a new SCEV_INFO_STR structure for VAR and INSTANTIATED_BELOW. */
static inline rename_map_elt
new_rename_map_elt (tree old_name, tree new_name)
{
rename_map_elt res;
res = XNEW (struct rename_map_elt);
res->old_name = old_name;
res->new_name = new_name;
return res;
}
/* Computes a hash function for database element ELT. */
static hashval_t
rename_map_elt_info (const void *elt)
{
return htab_hash_pointer (((const struct rename_map_elt *) elt)->old_name);
}
/* Compares database elements E1 and E2. */
static int
eq_rename_map_elts (const void *e1, const void *e2)
{
const struct rename_map_elt *elt1 = (const struct rename_map_elt *) e1;
const struct rename_map_elt *elt2 = (const struct rename_map_elt *) e2;
return (elt1->old_name == elt2->old_name);
}
/* Returns the new name associated to OLD_NAME in MAP. */
static tree
get_new_name_from_old_name (htab_t map, tree old_name)
{
struct rename_map_elt tmp;
PTR *slot;
tmp.old_name = old_name;
slot = htab_find_slot (map, &tmp, NO_INSERT);
if (slot && *slot)
return ((rename_map_elt) *slot)->new_name;
return old_name;
}
/* Rename the SSA_NAMEs used in STMT and that appear in IVSTACK. */
static void
@ -4032,38 +4146,6 @@ rename_variables (basic_block bb, htab_t map)
rename_variables_in_stmt (gsi_stmt (gsi), map);
}
/* Rename following the information from MAP the PHI node argument
corresponding to the edge E. In order to allow several renames of
that argument, we match the original SSA_NAME on the argument
coming from the edge different than E. */
static void
rename_variables_from_edge (edge e, gimple phi, htab_t map)
{
int n = e->dest_idx == 0 ? 1 : 0;
tree old_name = gimple_phi_arg_def (phi, n);
tree new_name = get_new_name_from_old_name (map, old_name);
gcc_assert (gimple_phi_num_args (phi) == 2
&& gimple_phi_arg_edge (phi, e->dest_idx) == e);
SET_PHI_ARG_DEF (phi, n, new_name);
}
/* Rename all the phi arguments for the edges comming from the scop
according to the MAP. */
static void
rename_phis_end_scop (scop_p scop, htab_t map)
{
basic_block after_scop = SCOP_EXIT (scop);
edge e = SESE_EXIT (SCOP_REGION (scop));
gimple_stmt_iterator gsi;
for (gsi = gsi_start_phis (after_scop); !gsi_end_p (gsi); gsi_next (&gsi))
rename_variables_from_edge (e, gsi_stmt (gsi), map);
}
/* Remove condition from BB. */
static void
@ -4144,7 +4226,7 @@ build_iv_mapping (loop_iv_stack ivstack, htab_t map, gbb_p gbb, scop_p scop)
/* Register in MAP the tuple (old_name, new_name). */
static void
register_old_new_names (htab_t map, tree old_name, tree new_name)
register_old_and_new_names (htab_t map, tree old_name, tree new_name)
{
struct rename_map_elt tmp;
PTR *slot;
@ -4193,11 +4275,32 @@ graphite_copy_stmts_from_block (basic_block bb, basic_block new_bb, htab_t map)
{
tree old_name = DEF_FROM_PTR (def_p);
tree new_name = create_new_def_for (old_name, copy, def_p);
register_old_new_names (map, old_name, new_name);
register_old_and_new_names (map, old_name, new_name);
}
}
}
/* Records in SCOP_LIVEOUT_RENAMES the names that are live out of
the SCOP and that appear in the RENAME_MAP. */
static void
register_scop_liveout_renames (scop_p scop, htab_t rename_map)
{
int i;
sese region = SCOP_REGION (scop);
for (i = 0; i < SESE_NUM_VER (region); i++)
if (bitmap_bit_p (SESE_LIVEOUT (region), i)
&& is_gimple_reg (ssa_name (i)))
{
tree old_name = ssa_name (i);
tree new_name = get_new_name_from_old_name (rename_map, old_name);
register_old_and_new_names (SCOP_LIVEOUT_RENAMES (scop),
old_name, new_name);
}
}
/* 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. */
@ -4215,15 +4318,153 @@ copy_bb_and_scalar_dependences (basic_block bb, scop_p scop,
rename_variables (new_bb, map);
remove_phi_nodes (new_bb);
expand_scalar_variables (new_bb, scop, context_loop, map);
rename_phis_end_scop (scop, map);
register_scop_liveout_renames (scop, map);
return next_e;
}
/* Translates a CLAST statement STMT to GCC representation. NEXT_E is
the edge where new generated code should be attached. BB_EXIT is the last
basic block that defines the scope of code generation. CONTEXT_LOOP is the
loop in which the generated code will be placed (might be NULL). */
/* Helper function for htab_traverse in insert_loop_close_phis. */
static int
add_loop_exit_phis (void **slot, void *s)
{
struct rename_map_elt *entry = (struct rename_map_elt *) *slot;
tree new_name = entry->new_name;
basic_block bb = (basic_block) s;
gimple phi = create_phi_node (new_name, bb);
tree res = create_new_def_for (gimple_phi_result (phi), phi,
gimple_phi_result_ptr (phi));
add_phi_arg (phi, new_name, single_pred_edge (bb));
entry->new_name = res;
*slot = entry;
return 1;
}
/* Iterate over the SCOP_LIVEOUT_RENAMES (SCOP) and get tuples of the
form (OLD_NAME, NEW_NAME). Insert in BB "RES = phi (NEW_NAME)",
and finally register in SCOP_LIVEOUT_RENAMES (scop) the tuple
(OLD_NAME, RES). */
static void
insert_loop_close_phis (scop_p scop, basic_block bb)
{
update_ssa (TODO_update_ssa);
htab_traverse (SCOP_LIVEOUT_RENAMES (scop), add_loop_exit_phis, bb);
update_ssa (TODO_update_ssa);
}
/* Helper structure for htab_traverse in insert_guard_phis. */
struct igp {
basic_block bb;
edge true_edge, false_edge;
htab_t liveout_before_guard;
};
/* Return the default name that is before the guard. */
static tree
default_liveout_before_guard (htab_t liveout_before_guard, tree old_name)
{
tree res = get_new_name_from_old_name (liveout_before_guard, old_name);
if (res == old_name)
{
if (is_gimple_reg (res))
return fold_convert (TREE_TYPE (res), integer_zero_node);
return gimple_default_def (cfun, res);
}
return res;
}
/* Helper function for htab_traverse in insert_guard_phis. */
static int
add_guard_exit_phis (void **slot, void *s)
{
struct rename_map_elt *entry = (struct rename_map_elt *) *slot;
struct igp *i = (struct igp *) s;
basic_block bb = i->bb;
edge true_edge = i->true_edge;
edge false_edge = i->false_edge;
tree name1 = entry->new_name;
tree name2 = default_liveout_before_guard (i->liveout_before_guard,
entry->old_name);
gimple phi = create_phi_node (name1, bb);
tree res = create_new_def_for (gimple_phi_result (phi), phi,
gimple_phi_result_ptr (phi));
add_phi_arg (phi, name1, true_edge);
add_phi_arg (phi, name2, false_edge);
entry->new_name = res;
*slot = entry;
return 1;
}
/* Iterate over the SCOP_LIVEOUT_RENAMES (SCOP) and get tuples of the
form (OLD_NAME, NAME1). If there is a correspondent tuple of
OLD_NAME in LIVEOUT_BEFORE_GUARD, i.e. (OLD_NAME, NAME2) then
insert in BB
| RES = phi (NAME1 (on TRUE_EDGE), NAME2 (on FALSE_EDGE))"
if there is no tuple for OLD_NAME in LIVEOUT_BEFORE_GUARD, insert
| RES = phi (NAME1 (on TRUE_EDGE),
| DEFAULT_DEFINITION of NAME1 (on FALSE_EDGE))".
Finally register in SCOP_LIVEOUT_RENAMES (scop) the tuple
(OLD_NAME, RES). */
static void
insert_guard_phis (scop_p scop, basic_block bb, edge true_edge,
edge false_edge, htab_t liveout_before_guard)
{
struct igp i;
i.bb = bb;
i.true_edge = true_edge;
i.false_edge = false_edge;
i.liveout_before_guard = liveout_before_guard;
update_ssa (TODO_update_ssa);
htab_traverse (SCOP_LIVEOUT_RENAMES (scop), add_guard_exit_phis, &i);
update_ssa (TODO_update_ssa);
}
/* Helper function for htab_traverse. */
static int
copy_renames (void **slot, void *s)
{
struct rename_map_elt *entry = (struct rename_map_elt *) *slot;
htab_t res = (htab_t) s;
tree old_name = entry->old_name;
tree new_name = entry->new_name;
struct rename_map_elt tmp;
PTR *x;
tmp.old_name = old_name;
x = htab_find_slot (res, &tmp, INSERT);
if (!*x)
*x = new_rename_map_elt (old_name, new_name);
return 1;
}
/* Translates a CLAST statement STMT to GCC representation in the
context of a SCOP.
- NEXT_E is the edge where new generated code should be attached.
- CONTEXT_LOOP is the loop in which the generated code will be placed
(might be NULL).
- IVSTACK contains the surrounding loops around the statement to be
translated.
*/
static edge
translate_clast (scop_p scop, struct loop *context_loop,
@ -4264,14 +4505,16 @@ translate_clast (scop_p scop, struct loop *context_loop,
ivstack, context_loop ? context_loop
: get_loop (0));
edge last_e = single_exit (loop);
next_e = translate_clast (scop, loop, ((struct clast_for *) stmt)->body,
single_pred_edge (loop->latch), ivstack);
redirect_edge_succ_nodup (next_e, loop->latch);
set_immediate_dominator (CDI_DOMINATORS, next_e->dest, next_e->src);
loop_iv_stack_pop (ivstack);
last_e = single_succ_edge (split_edge (last_e));
insert_loop_close_phis (scop, last_e->src);
recompute_all_dominators ();
graphite_verify ();
return translate_clast (scop, context_loop, stmt->next, last_e, ivstack);
@ -4279,15 +4522,28 @@ translate_clast (scop_p scop, struct loop *context_loop,
if (CLAST_STMT_IS_A (stmt, stmt_guard))
{
htab_t liveout_before_guard = htab_create (10, rename_map_elt_info,
eq_rename_map_elts, free);
edge last_e = graphite_create_new_guard (scop, next_e,
((struct clast_guard *) stmt),
ivstack);
edge true_e = get_true_edge_from_guard_bb (next_e->dest);
edge false_e = get_false_edge_from_guard_bb (next_e->dest);
edge exit_true_e = single_succ_edge (true_e->dest);
edge exit_false_e = single_succ_edge (false_e->dest);
htab_traverse (SCOP_LIVEOUT_RENAMES (scop), copy_renames,
liveout_before_guard);
next_e = translate_clast (scop, context_loop,
((struct clast_guard *) stmt)->then,
true_e, ivstack);
insert_guard_phis (scop, last_e->src, exit_true_e, exit_false_e,
liveout_before_guard);
htab_delete (liveout_before_guard);
recompute_all_dominators ();
graphite_verify ();
return translate_clast (scop, context_loop, stmt->next, last_e, ivstack);
}
@ -4710,72 +4966,10 @@ move_sese_in_condition (sese region)
return if_region;
}
/* Returns true when BB is in REGION. */
static bool
bb_in_sese_p (basic_block bb, sese region)
{
return pointer_set_contains (SESE_REGION_BBS (region), bb);
}
/* For USE in BB, if it is used outside of the REGION it is defined in,
mark it for rewrite. Record basic block BB where it is used
to USE_BLOCKS. Record the ssa name index to NEED_PHIS bitmap. */
static void
sese_find_uses_to_rename_use (sese region, basic_block bb, tree use,
bitmap *use_blocks, bitmap need_phis)
{
unsigned ver;
basic_block def_bb;
if (TREE_CODE (use) != SSA_NAME)
return;
ver = SSA_NAME_VERSION (use);
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;
if (!use_blocks[ver])
use_blocks[ver] = BITMAP_ALLOC (NULL);
bitmap_set_bit (use_blocks[ver], bb->index);
bitmap_set_bit (need_phis, ver);
}
/* Marks names that are used in BB and outside of the loop they are
defined in for rewrite. Records the set of blocks in that the ssa
names are defined to USE_BLOCKS. Record the SSA names that will
need exit PHIs in NEED_PHIS. */
static void
sese_find_uses_to_rename_bb (sese region, basic_block bb,
bitmap *use_blocks, bitmap need_phis)
{
gimple_stmt_iterator bsi;
edge e;
edge_iterator ei;
ssa_op_iter iter;
tree var;
FOR_EACH_EDGE (e, ei, bb->succs)
for (bsi = gsi_start_phis (e->dest); !gsi_end_p (bsi); gsi_next (&bsi))
sese_find_uses_to_rename_use (region, 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))
FOR_EACH_SSA_TREE_OPERAND (var, gsi_stmt (bsi), iter, SSA_OP_ALL_USES)
sese_find_uses_to_rename_use (region, bb, var, use_blocks, need_phis);
}
/* Add exit phis for USE on EXIT. */
static void
sese_add_exit_phis_edge (basic_block exit, tree use, edge false_e, edge true_e)
scop_add_exit_phis_edge (basic_block exit, tree use, edge false_e, edge true_e)
{
gimple phi = create_phi_node (use, exit);
@ -4786,10 +4980,10 @@ sese_add_exit_phis_edge (basic_block exit, tree use, edge false_e, edge true_e)
}
/* Add phi nodes for VAR that is used in LIVEIN. Phi nodes are
inserted in block WHERE. */
inserted in block BB. */
static void
sese_add_exit_phis_var (basic_block where, tree var, bitmap livein,
scop_add_exit_phis_var (basic_block bb, tree var, bitmap livein,
edge false_e, edge true_e)
{
bitmap def;
@ -4805,39 +4999,82 @@ sese_add_exit_phis_var (basic_block where, tree var, bitmap livein,
compute_global_livein (livein, def);
BITMAP_FREE (def);
sese_add_exit_phis_edge (where, var, false_e, true_e);
scop_add_exit_phis_edge (bb, var, false_e, true_e);
}
/* Insert in the block WHERE phi nodes for variables defined in REGION
and used outside the REGION. */
/* Insert in the block BB phi nodes for variables defined in REGION
and used outside the REGION. The code generation moves REGION in
the else clause of an "if (1)" and generates code in the then
clause that is at this point empty:
| if (1)
| empty;
| else
| REGION;
*/
static void
rewrite_into_sese_closed_ssa (sese region, basic_block where,
edge false_e, edge true_e)
scop_insert_phis_for_liveouts (sese region, basic_block bb,
edge false_e, edge true_e)
{
unsigned i;
basic_block bb;
bitmap_iterator bi;
bitmap names_to_rename = BITMAP_ALLOC (NULL);
unsigned old_num_ssa_names = num_ssa_names;
bitmap *use_blocks = XCNEWVEC (bitmap, old_num_ssa_names);
update_ssa (TODO_update_ssa);
FOR_EACH_BB (bb)
sese_find_uses_to_rename_bb (region, bb, use_blocks, names_to_rename);
EXECUTE_IF_SET_IN_BITMAP (names_to_rename, 0, i, bi)
sese_add_exit_phis_var (where, ssa_name (i), use_blocks[i],
EXECUTE_IF_SET_IN_BITMAP (SESE_LIVEOUT (region), 0, i, bi)
scop_add_exit_phis_var (bb, ssa_name (i), SESE_LIVEIN_VER (region, i),
false_e, true_e);
update_ssa (TODO_update_ssa);
}
for (i = 0; i < old_num_ssa_names; i++)
BITMAP_FREE (use_blocks[i]);
/* 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
code in the then clause:
free (use_blocks);
BITMAP_FREE (names_to_rename);
| if (1)
| generated code from REGION;
| else
| REGION;
To adjust the phi nodes after the condition, SCOP_LIVEOUT_RENAMES
hash table is used: this stores for a name that is part of the
LIVEOUT of SCOP_REGION its new name in the generated code. */
static void
scop_adjust_phis_for_liveouts (scop_p scop, basic_block bb, edge false_e,
edge true_e)
{
gimple_stmt_iterator si;
for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
{
unsigned i, false_i;
gimple phi = gsi_stmt (si);
if (!is_gimple_reg (PHI_RESULT (phi)))
continue;
for (i = 0; i < gimple_phi_num_args (phi); i++)
if (gimple_phi_arg_edge (phi, i) == false_e)
{
false_i = i;
break;
}
for (i = 0; i < gimple_phi_num_args (phi); i++)
if (gimple_phi_arg_edge (phi, i) == true_e)
{
tree old_name = gimple_phi_arg_def (phi, false_i);
tree new_name = get_new_name_from_old_name
(SCOP_LIVEOUT_RENAMES (scop), old_name);
gcc_assert (old_name != new_name);
SET_PHI_ARG_DEF (phi, i, new_name);
}
}
}
/* Returns the first cloog name used in EXPR. */
@ -4976,24 +5213,33 @@ gloog (scop_p scop, struct clast_stmt *stmt)
}
if_region = move_sese_in_condition (SCOP_REGION (scop));
rewrite_into_sese_closed_ssa (SCOP_REGION (scop),
if_region->region->exit->src,
if_region->false_region->exit,
if_region->true_region->exit);
sese_build_livein_liveouts (SCOP_REGION (scop));
scop_insert_phis_for_liveouts (SCOP_REGION (scop),
if_region->region->exit->src,
if_region->false_region->exit,
if_region->true_region->exit);
recompute_all_dominators ();
graphite_verify ();
context_loop = SESE_ENTRY (SCOP_REGION (scop))->src->loop_father;
compute_cloog_iv_types (stmt);
new_scop_exit_edge = translate_clast (scop, context_loop,
stmt, if_region->true_region->entry,
new_scop_exit_edge = translate_clast (scop, context_loop, stmt,
if_region->true_region->entry,
&ivstack);
free_loop_iv_stack (&ivstack);
cloog_clast_free (stmt);
graphite_verify ();
scop_adjust_phis_for_liveouts (scop,
if_region->region->exit->src,
if_region->false_region->exit,
if_region->true_region->exit);
recompute_all_dominators ();
graphite_verify ();
cleanup_tree_cfg ();
recompute_all_dominators ();
graphite_verify ();
free_loop_iv_stack (&ivstack);
cloog_clast_free (stmt);
}
/* Returns the number of data references in SCOP. */

View File

@ -275,13 +275,36 @@ DEF_VEC_ALLOC_P (name_tree, heap);
by two edges. */
typedef struct sese
{
/* Single ENTRY and single EXIT from the SESE region. */
edge entry, exit;
/* REGION_BASIC_BLOCKS contains the set of all the basic blocks
belonging to the SESE region. */
struct pointer_set_t *region_basic_blocks;
/* An SSA_NAME version is flagged in the LIVEOUT bitmap if the
SSA_NAME is defined inside and used outside the SESE region. */
bitmap liveout;
/* The overall number of SSA_NAME versions used to index LIVEIN. */
int num_ver;
/* For each SSA_NAME version VER in LIVEOUT, LIVEIN[VER] contains
the set of basic blocks indices that contain a use of VER. */
bitmap *livein;
} *sese;
#define SESE_ENTRY(S) (S->entry)
#define SESE_EXIT(S) (S->exit)
#define SESE_REGION_BBS(S) (S->region_basic_blocks)
#define SESE_LIVEOUT(S) (S->liveout)
#define SESE_LIVEIN(S) (S->livein)
#define SESE_LIVEIN_VER(S, I) (S->livein[I])
#define SESE_NUM_VER(S) (S->num_ver)
extern sese new_sese (edge, edge);
extern void free_sese (sese);
extern void sese_build_livein_liveouts (sese);
/* A SCOP is a Static Control Part of the program, simple enough to be
represented in polyhedral form. */
@ -319,6 +342,10 @@ struct scop
can only add new params before generating the bb domains, otherwise they
become invalid. */
bool add_params;
/* LIVEOUT_RENAMES registers the rename mapping that has to be
applied after code generation. */
htab_t liveout_renames;
};
#define SCOP_BBS(S) S->bbs
@ -341,6 +368,7 @@ struct scop
#define SCOP_PROG(S) S->program
#define SCOP_LOOP2CLOOG_LOOP(S) S->loop2cloog_loop
#define SCOP_LOOPS_MAPPING(S) S->loops_mapping
#define SCOP_LIVEOUT_RENAMES(S) S->liveout_renames
extern void debug_scop (scop_p, int);
extern void debug_scops (int);