tree-ssa-loop-manip.c [plain text]
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "tm_p.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "output.h"
#include "diagnostic.h"
#include "tree-flow.h"
#include "tree-dump.h"
#include "timevar.h"
#include "cfgloop.h"
#include "tree-pass.h"
#include "cfglayout.h"
static basic_block lv_adjust_loop_entry_edge (basic_block, basic_block, edge,
tree);
static void lv_update_pending_stmts (edge e);
static void lv_adjust_loop_header_phi (basic_block, basic_block, basic_block,
edge);
static void
copy_phi_nodes (struct loop *loop, unsigned first_new_block, bool peeling)
{
unsigned i;
basic_block bb, orig;
tree phi, new_phi, def;
edge e, new_e;
edge latch = loop_latch_edge (loop), entry = loop_preheader_edge (loop);
for (i = first_new_block; i < (unsigned) last_basic_block; i++)
{
tree nlist;
bb = BASIC_BLOCK (i);
orig = bb->rbi->original;
for (phi = phi_nodes (orig); phi; phi = TREE_CHAIN (phi))
{
new_phi = create_phi_node (PHI_RESULT (phi), bb);
if (orig == loop->header)
{
if (!bb->pred || bb->pred->pred_next)
abort ();
new_e = bb->pred;
e = (peeling && bb->rbi->copy_number == 1 ? entry : latch);
def = phi_element_for_edge (phi, e)->def;
add_phi_arg (&new_phi, def, new_e);
continue;
}
for (new_e = bb->pred; new_e; new_e = new_e->pred_next)
{
e = find_edge (new_e->src->rbi->original, orig);
if (!e)
abort ();
def = phi_element_for_edge (phi, e)->def;
add_phi_arg (&new_phi, def, new_e);
}
}
nlist = nreverse (phi_nodes (bb));
set_phi_nodes (bb, nlist);
}
if (peeling)
{
for (phi = phi_nodes (loop->header); phi; phi = TREE_CHAIN (phi))
{
def = phi_element_for_edge (phi, latch)->def;
phi_element_for_edge (phi, entry)->def = def;
}
}
}
static tree
collect_defs (struct loop *loop)
{
basic_block *body = get_loop_body (loop);
unsigned i, j;
tree phi, stmt;
block_stmt_iterator bsi;
def_optype defs;
vdef_optype vdefs;
tree ret = NULL_TREE;
for (i = 0; i < loop->num_nodes; i++)
{
for (bsi = bsi_start (body[i]); !bsi_end_p (bsi); bsi_next (&bsi))
{
stmt = bsi_stmt (bsi);
get_stmt_operands (stmt);
defs = STMT_DEF_OPS (stmt);
for (j = 0; j < NUM_DEFS (defs); j++)
ret = tree_cons (NULL, DEF_OP (defs, j), ret);
vdefs = STMT_VDEF_OPS (stmt);
for (j = 0; j < NUM_VDEFS (vdefs); j++)
ret = tree_cons (NULL, VDEF_RESULT (vdefs, j), ret);
}
for (phi = phi_nodes (body[i]); phi; phi = TREE_CHAIN (phi))
ret = tree_cons (NULL, PHI_RESULT (phi), ret);
}
return ret;
}
static void
allocate_new_names (tree definitions, unsigned ndupl, bool origin)
{
tree def;
unsigned i;
ssa_name_ann_t ann;
tree *new_names;
bool abnormal;
for (; definitions; definitions = TREE_CHAIN (definitions))
{
def = TREE_VALUE (definitions);
ann = get_ssa_name_ann (def);
new_names = xmalloc (sizeof (tree) * (ndupl + (origin ? 1 : 0)));
abnormal = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def);
for (i = (origin ? 0 : 1); i <= ndupl; i++)
{
new_names[i] = duplicate_ssa_name (def, SSA_NAME_DEF_STMT (def));
SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_names[i]) = abnormal;
}
ann->common.aux = new_names;
}
}
static void
rename_op (tree *op_p, bool def, tree stmt, unsigned n_copy)
{
ssa_name_ann_t ann;
tree *new_names;
if(!op_p)
return;
if (TREE_CODE (*op_p) != SSA_NAME)
return;
ann = ssa_name_ann (*op_p);
new_names = ann ? ann->common.aux : NULL;
if (!new_names)
return;
*op_p = new_names[n_copy];
if (def)
SSA_NAME_DEF_STMT (*op_p) = stmt;
}
static void
rename_variables_in_bb (basic_block bb)
{
tree phi;
block_stmt_iterator bsi;
tree stmt;
stmt_ann_t ann;
use_optype uses;
vuse_optype vuses;
def_optype defs;
vdef_optype vdefs;
unsigned i, nbb = bb->rbi->copy_number;
edge e;
for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
rename_op (&PHI_RESULT (phi), true, phi, nbb);
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
stmt = bsi_stmt (bsi);
get_stmt_operands (stmt);
ann = stmt_ann (stmt);
uses = USE_OPS (ann);
for (i = 0; i < NUM_USES (uses); i++)
rename_op (USE_OP_PTR (uses, i), false, stmt, nbb);
defs = DEF_OPS (ann);
for (i = 0; i < NUM_DEFS (defs); i++)
rename_op (DEF_OP_PTR (defs, i), true, stmt, nbb);
vuses = VUSE_OPS (ann);
for (i = 0; i < NUM_VUSES (vuses); i++)
rename_op (VUSE_OP_PTR (vuses, i), false, stmt, nbb);
vdefs = VDEF_OPS (ann);
for (i = 0; i < NUM_VDEFS (vdefs); i++)
{
rename_op (VDEF_OP_PTR (vdefs, i), false, stmt, nbb);
rename_op (VDEF_RESULT_PTR (vdefs, i), true, stmt, nbb);
}
}
for (e = bb->succ; e; e = e->succ_next)
for (phi = phi_nodes (e->dest); phi; phi = TREE_CHAIN (phi))
rename_op (&phi_element_for_edge (phi, e)->def, false, phi, nbb);
}
static void
rename_variables (unsigned first_new_block)
{
unsigned i;
basic_block bb;
for (i = first_new_block; i < (unsigned) last_basic_block; i++)
{
bb = BASIC_BLOCK (i);
rename_variables_in_bb (bb);
if (bb->rbi->copy_number == 1)
rename_variables_in_bb (bb->rbi->original);
}
}
static void
free_new_names (tree definitions, bool origin)
{
tree def;
ssa_name_ann_t ann;
for (; definitions; definitions = TREE_CHAIN (definitions))
{
def = TREE_VALUE (definitions);
ann = ssa_name_ann (def);
free (ann->common.aux);
ann->common.aux = NULL;
if (origin)
release_ssa_name (def);
}
}
static void
set_phi_def_stmts (basic_block bb)
{
tree phi;
for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
SSA_NAME_DEF_STMT (PHI_RESULT (phi)) = phi;
}
static void
extend_exit_phi_nodes (unsigned first_new_block, edge exit)
{
basic_block exit_block = exit->dest;
edge ae;
tree phi, def;
for (phi = phi_nodes (exit_block); phi; phi = TREE_CHAIN (phi))
{
def = phi_element_for_edge (phi, exit)->def;
for (ae = exit_block->pred; ae; ae = ae->pred_next)
{
if (ae->src->index < (int) first_new_block)
continue;
if (ae->src->rbi->original != exit->src)
continue;
add_phi_arg (&phi, def, ae);
}
}
}
bool
tree_duplicate_loop_to_header_edge (struct loop *loop, edge e,
struct loops *loops,
unsigned int ndupl, sbitmap wont_exit,
edge orig, edge *to_remove,
unsigned int *n_to_remove, int flags)
{
unsigned first_new_block;
basic_block bb;
unsigned i;
bool peeling = (e != loop_latch_edge (loop));
edge latch, latch_copy;
tree phi, arg, map, def;
tree definitions;
edge *exits;
unsigned n_exits;
if (!(loops->state & LOOPS_HAVE_SIMPLE_LATCHES))
return false;
if (!(loops->state & LOOPS_HAVE_PREHEADERS))
return false;
#ifdef ENABLE_CHECKING
verify_loop_closed_ssa ();
#endif
exits = get_loop_exit_edges (loop, &n_exits);
definitions = collect_defs (loop);
first_new_block = last_basic_block;
if (!duplicate_loop_to_header_edge (loop, e, loops, ndupl, wont_exit,
orig, to_remove, n_to_remove, flags))
return false;
allocate_new_names (definitions, ndupl, true);
latch = loop_latch_edge (loop);
latch_copy = peeling ? loop_preheader_edge (loop) : latch;
map = PENDING_STMT (e);
PENDING_STMT (e) = NULL;
for (phi = phi_nodes (loop->header), arg = map;
phi;
phi = TREE_CHAIN (phi), arg = TREE_CHAIN (arg))
{
def = TREE_VALUE (arg);
add_phi_arg (&phi, def, latch_copy);
}
if (arg)
abort ();
for (i = 0; i < n_exits; i++)
extend_exit_phi_nodes (first_new_block, exits[i]);
free (exits);
copy_phi_nodes (loop, first_new_block, peeling);
rename_variables (first_new_block);
free_new_names (definitions, true);
for (i = first_new_block; i < (unsigned) last_basic_block; i++)
{
bb = BASIC_BLOCK (i);
set_phi_def_stmts (bb);
if (bb->rbi->copy_number == 1)
set_phi_def_stmts (bb->rbi->original);
}
#ifdef ENABLE_CHECKING
verify_loop_closed_ssa ();
#endif
return true;
}
void
test_unrolling_and_peeling (struct loops *loops)
{
struct loop *loop;
unsigned i;
for (i = 1; i < loops->num; i++)
{
loop = loops->parray[i];
if (!loop
|| loop->inner)
continue;
tree_duplicate_loop_to_header_edge (loop, loop_preheader_edge (loop),
loops, 2, NULL, NULL, NULL, NULL, 0);
verify_loop_structure (loops);
verify_ssa ();
tree_duplicate_loop_to_header_edge (loop, loop_latch_edge (loop),
loops, 2, NULL, NULL, NULL, NULL, 0);
verify_loop_structure (loops);
verify_ssa ();
}
}
static basic_block
lv_adjust_loop_entry_edge (basic_block first_head,
basic_block second_head,
edge e,
tree cond_expr)
{
block_stmt_iterator bsi;
basic_block orig_head = e->src;
basic_block new_head = NULL;
tree goto1 = NULL_TREE;
tree goto2 = NULL_TREE;
tree new_cond_expr = NULL_TREE;
edge e0, e1;
new_head = split_edge (e);
set_immediate_dominator (CDI_DOMINATORS, new_head, orig_head);
goto1 = build1 (GOTO_EXPR, void_type_node, tree_block_label (first_head));
goto2 = build1 (GOTO_EXPR, void_type_node, tree_block_label (second_head));
new_cond_expr = build (COND_EXPR, void_type_node, cond_expr, goto1, goto2);
bsi = bsi_start (new_head);
bsi_insert_after (&bsi, new_cond_expr, BSI_NEW_STMT);
e1 = make_edge (new_head, first_head, EDGE_TRUE_VALUE);
set_immediate_dominator (CDI_DOMINATORS, first_head, new_head);
make_edge (new_head, second_head, EDGE_FALSE_VALUE);
set_immediate_dominator (CDI_DOMINATORS, second_head, new_head);
lv_adjust_loop_header_phi (first_head, second_head, new_head, e1);
for (e0 = new_head->succ; e0; e0 = e0->succ_next)
if (e0->dest == second_head)
e0->flags &= ~EDGE_FALLTHRU;
return new_head;
}
static void
lv_update_pending_stmts (edge e)
{
basic_block dest;
tree phi, arg, def;
if (!PENDING_STMT (e))
return;
dest = e->dest;
for (phi = phi_nodes (dest), arg = PENDING_STMT (e);
phi;
phi = TREE_CHAIN (phi), arg = TREE_CHAIN (arg))
{
def = TREE_VALUE (arg);
add_phi_arg (&phi, def, e);
}
PENDING_STMT (e) = NULL;
}
static void
lv_adjust_loop_header_phi (basic_block first, basic_block second,
basic_block new_head, edge e)
{
tree phi1, phi2;
for (phi2 = phi_nodes (second), phi1 = phi_nodes (first);
phi2 && phi1;
phi2 = TREE_CHAIN (phi2), phi1 = TREE_CHAIN (phi1))
{
int i;
for (i = 0; i < PHI_NUM_ARGS (phi2); i++)
{
if (PHI_ARG_EDGE (phi2, i)->src == new_head)
{
tree def = PHI_ARG_DEF (phi2, i);
add_phi_arg (&phi1, def, e);
}
}
}
}
struct loop *
tree_ssa_loop_version (struct loops *loops, struct loop * loop,
tree cond_expr, basic_block *condition_bb)
{
edge entry, latch_edge;
basic_block first_head, second_head;
int irred_flag;
struct loop *nloop;
if (loop->inner)
return NULL;
entry = loop_preheader_edge (loop);
first_head = entry->dest;
irred_flag = entry->flags & EDGE_IRREDUCIBLE_LOOP;
entry->flags &= ~EDGE_IRREDUCIBLE_LOOP;
if (!tree_duplicate_loop_to_header_edge (loop, entry, loops, 1,
NULL, NULL, NULL, NULL, 0))
{
entry->flags |= irred_flag;
return NULL;
}
second_head = entry->dest;
*condition_bb = lv_adjust_loop_entry_edge (first_head, second_head, entry,
cond_expr);
latch_edge = loop->latch->rbi->copy->succ;
nloop = loopify (loops,
latch_edge,
loop->header->rbi->copy->pred,
*condition_bb,
false );
lv_update_pending_stmts (latch_edge);
lv_update_pending_stmts (FALLTHRU_EDGE (*condition_bb));
if (irred_flag)
{
(*condition_bb)->flags |= BB_IRREDUCIBLE_LOOP;
loop_preheader_edge (loop)->flags |= EDGE_IRREDUCIBLE_LOOP;
loop_preheader_edge (nloop)->flags |= EDGE_IRREDUCIBLE_LOOP;
(*condition_bb)->pred->flags |= EDGE_IRREDUCIBLE_LOOP;
}
loop_split_edge_with (loop_preheader_edge (loop), NULL);
loop_split_edge_with (loop_preheader_edge (nloop), NULL);
loop_split_edge_with (loop_latch_edge (loop), NULL);
loop_split_edge_with (loop_latch_edge (nloop), NULL);
return nloop;
}
void
update_lv_condition (basic_block *bb, tree new_cond)
{
tree stmt;
block_stmt_iterator bsi = bsi_last (*bb);
stmt = bsi_stmt (bsi);
if (TREE_CODE (stmt) == COND_EXPR)
{
TREE_OPERAND (stmt, 0) = new_cond;
modify_stmt (stmt);
}
else
abort ();
}
void
test_loop_versioning (struct loops *loops)
{
struct loop *loop;
unsigned i;
tree cond_expr;
for (i = 1; i < loops->num; i = i+ 2)
{
struct loop *nloop;
basic_block condition_bb;
loop = loops->parray[i];
if (!loop)
continue;
cond_expr = build (EQ_EXPR, boolean_type_node,
integer_one_node,
integer_zero_node);
nloop = tree_ssa_loop_version (loops, loop, cond_expr, &condition_bb);
if (nloop)
{
verify_loop_structure (loops);
verify_dominators (CDI_DOMINATORS);
verify_ssa ();
update_lv_condition (&condition_bb, boolean_true_node);
}
}
}
static void
add_exit_phis_edge (basic_block exit, tree use)
{
tree phi, def_stmt = SSA_NAME_DEF_STMT (use);
basic_block def_bb = bb_for_stmt (def_stmt);
struct loop *def_loop;
edge e;
for (e = exit->pred; e; e = e->pred_next)
{
def_loop = find_common_loop (def_bb->loop_father, e->src->loop_father);
if (!flow_bb_inside_loop_p (def_loop, e->dest))
break;
}
if (!e)
return;
phi = create_phi_node (use, exit);
for (e = exit->pred; e; e = e->pred_next)
add_phi_arg (&phi, use, e);
SSA_NAME_DEF_STMT (use) = def_stmt;
}
static void
add_exit_phis_var (tree var, bitmap livein, bitmap exits)
{
bitmap def;
int index;
basic_block def_bb = bb_for_stmt (SSA_NAME_DEF_STMT (var));
bitmap_clear_bit (livein, def_bb->index);
def = BITMAP_XMALLOC ();
bitmap_set_bit (def, def_bb->index);
compute_global_livein (livein, def);
BITMAP_XFREE (def);
EXECUTE_IF_AND_IN_BITMAP (exits, livein, 0, index,
add_exit_phis_edge (BASIC_BLOCK (index), var));
}
static void
add_exit_phis (bitmap names_to_rename, bitmap *use_blocks, bitmap loop_exits,
tree *ssa_names)
{
unsigned i;
EXECUTE_IF_SET_IN_BITMAP (names_to_rename, 0, i,
{
add_exit_phis_var (ssa_names[i], use_blocks[i], loop_exits);
});
}
static bitmap
get_loops_exits (void)
{
bitmap exits = BITMAP_XMALLOC ();
basic_block bb;
edge e;
FOR_EACH_BB (bb)
{
for (e = bb->pred; e; e = e->pred_next)
if (e->src != ENTRY_BLOCK_PTR
&& !flow_bb_inside_loop_p (e->src->loop_father, bb))
{
bitmap_set_bit (exits, bb->index);
break;
}
}
return exits;
}
static void
find_uses_to_rename_use (basic_block bb, tree use, bitmap names_to_rename,
bitmap *use_blocks, tree *names)
{
unsigned ver;
basic_block def_bb;
struct loop *def_loop;
if (TREE_CODE (use) != SSA_NAME)
return;
ver = SSA_NAME_VERSION (use);
def_bb = bb_for_stmt (SSA_NAME_DEF_STMT (use));
if (!def_bb)
return;
def_loop = def_bb->loop_father;
if (!def_loop->outer)
return;
names[ver] = use;
if (!use_blocks[ver])
use_blocks[ver] = BITMAP_XMALLOC ();
bitmap_set_bit (use_blocks[ver], bb->index);
if (!flow_bb_inside_loop_p (def_loop, bb))
bitmap_set_bit (names_to_rename, ver);
}
static void
find_uses_to_rename_stmt (tree stmt, bitmap names_to_rename,
bitmap *use_blocks, tree *names)
{
use_optype uses;
vuse_optype vuses;
vdef_optype vdefs;
stmt_ann_t ann;
unsigned i;
basic_block bb = bb_for_stmt (stmt);
get_stmt_operands (stmt);
ann = stmt_ann (stmt);
uses = USE_OPS (ann);
for (i = 0; i < NUM_USES (uses); i++)
find_uses_to_rename_use (bb, USE_OP (uses, i),
names_to_rename, use_blocks, names);
vuses = VUSE_OPS (ann);
for (i = 0; i < NUM_VUSES (vuses); i++)
find_uses_to_rename_use (bb, VUSE_OP (vuses, i),
names_to_rename, use_blocks, names);
vdefs = VDEF_OPS (ann);
for (i = 0; i < NUM_VDEFS (vdefs); i++)
find_uses_to_rename_use (bb, VDEF_OP (vdefs, i),
names_to_rename, use_blocks, names);
}
static void
find_uses_to_rename (bitmap names_to_rename, bitmap *use_blocks, tree *names)
{
basic_block bb;
block_stmt_iterator bsi;
tree phi;
unsigned i;
FOR_EACH_BB (bb)
{
for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
for (i = 0; i < (unsigned) PHI_NUM_ARGS (phi); i++)
find_uses_to_rename_use (PHI_ARG_EDGE (phi, i)->src,
PHI_ARG_DEF (phi, i),
names_to_rename, use_blocks, names);
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
find_uses_to_rename_stmt (bsi_stmt (bsi),
names_to_rename, use_blocks, names);
}
}
void
rewrite_into_loop_closed_ssa (void)
{
bitmap names_to_rename = BITMAP_XMALLOC ();
bitmap loop_exits = get_loops_exits ();
bitmap *use_blocks;
tree *ssa_names;
unsigned i;
tree_ssa_dce_no_cfg_changes ();
use_blocks = xcalloc (highest_ssa_version, sizeof (bitmap));
ssa_names = xcalloc (highest_ssa_version, sizeof (tree));
find_uses_to_rename (names_to_rename, use_blocks, ssa_names);
add_exit_phis (names_to_rename, use_blocks, loop_exits, ssa_names);
for (i = 0; i < highest_ssa_version; i++)
BITMAP_XFREE (use_blocks[i]);
free (use_blocks);
free (ssa_names);
BITMAP_XFREE (loop_exits);
rewrite_ssa_into_ssa (names_to_rename);
BITMAP_XFREE (names_to_rename);
BITMAP_XFREE (loop_exits);
}
static void
check_loop_closed_ssa_use (basic_block bb, tree use)
{
tree def;
basic_block def_bb;
if (TREE_CODE (use) != SSA_NAME)
return;
def = SSA_NAME_DEF_STMT (use);
def_bb = bb_for_stmt (def);
if (def_bb
&& !flow_bb_inside_loop_p (def_bb->loop_father, bb))
abort ();
}
static void
check_loop_closed_ssa_stmt (basic_block bb, tree stmt)
{
use_optype uses;
vuse_optype vuses;
vdef_optype vdefs;
stmt_ann_t ann;
unsigned i;
get_stmt_operands (stmt);
ann = stmt_ann (stmt);
uses = USE_OPS (ann);
for (i = 0; i < NUM_USES (uses); i++)
check_loop_closed_ssa_use (bb, USE_OP (uses, i));
vuses = VUSE_OPS (ann);
for (i = 0; i < NUM_VUSES (vuses); i++)
check_loop_closed_ssa_use (bb, VUSE_OP (vuses, i));
vdefs = VDEF_OPS (ann);
for (i = 0; i < NUM_VDEFS (vdefs); i++)
check_loop_closed_ssa_use (bb, VDEF_OP (vdefs, i));
}
void
verify_loop_closed_ssa (void)
{
basic_block bb;
block_stmt_iterator bsi;
tree phi;
unsigned i;
verify_ssa ();
FOR_EACH_BB (bb)
{
for (phi = phi_nodes (bb); phi; phi = TREE_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));
}
}
static void
tdlte_rename_variables_in_loop (struct loop *loop)
{
unsigned i;
basic_block *bbs;
bbs = get_loop_body (loop);
for (i = 0; i < loop->num_nodes; i++)
{
rename_variables_in_bb (bbs[i]);
}
free (bbs);
}
static void
tdlte_copy_phi_nodes (struct loop *loop, struct loop *new_loop)
{
tree phi, new_phi, def;
edge new_e;
edge latch = loop_latch_edge (loop);
tree nlist;
for (phi = phi_nodes (loop->header); phi; phi = TREE_CHAIN (phi))
{
new_phi = create_phi_node (PHI_RESULT (phi), new_loop->header);
new_e = new_loop->header->pred;
def = phi_element_for_edge (phi, latch)->def;
add_phi_arg (&new_phi, def, new_e);
}
nlist = nreverse (phi_nodes (new_loop->header));
set_phi_nodes (new_loop->header, nlist);
}
static bool
tree_duplicate_loop_to_exit_cfg (struct loop *loop, struct loops *loops,
struct loop **new_loop_p)
{
struct loop *target;
basic_block *new_bbs, *bbs;
edge latch_edge;
unsigned i;
unsigned n = loop->num_nodes;
struct loop *new_loop;
basic_block exit_dest;
bbs = get_loop_body (loop);
if (!can_copy_bbs_p (bbs, loop->num_nodes))
{
free (bbs);
return false;
}
new_bbs = xmalloc (sizeof (basic_block) * loop->num_nodes);
latch_edge = loop_latch_edge (loop);
if(loop->inner)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"Loop duplication failed. Loop is not innermost.\n");
free (bbs);
return false;
}
if(loop->num_exits != 1)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"More than one exit from loop.\n");
return false;
}
target = loop->outer;
if(!target)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"Loop is outer-most loop.\n");
return false;
}
new_loop = duplicate_loop (loops, loop, target);
if(!new_loop)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"duplicate_loop returns NULL.\n");
return false;
}
copy_bbs (bbs, n, new_bbs, NULL, 0, NULL, NULL);
for (i = 0; i < n; i++)
new_bbs[i]->rbi->copy_number = 1;
exit_dest = loop->exit_edges[0]->dest;
if(!exit_dest)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"First exit basic block of loop is NULL.\n");
return false;
}
redirect_edge_and_branch_force (loop->exit_edges[0],
new_bbs[0]);
set_immediate_dominator (CDI_DOMINATORS, new_bbs[0], loop->exit_edges[0]->src);
set_immediate_dominator (CDI_DOMINATORS, exit_dest, new_loop->header);
free (new_bbs);
free (bbs);
*new_loop_p = new_loop;
return true;
}
bool
tree_duplicate_loop_to_exit (struct loop *loop, struct loops *loops)
{
struct loop *new_loop = NULL;
tree definitions;
edge pred;
tree *new_names, new_var;
tree phi, def;
unsigned first_new_block;
ssa_name_ann_t ann;
definitions = collect_defs (loop);
first_new_block = last_basic_block;
if(!tree_duplicate_loop_to_exit_cfg (loop, loops, &new_loop))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"tree_duplicate_loop_to_exit failed.\n");
return false;
}
if(!new_loop)
abort();
allocate_new_names (definitions, 1, false);
tdlte_copy_phi_nodes (loop, new_loop);
tdlte_rename_variables_in_loop (new_loop);
for (phi = phi_nodes (new_loop->header); phi; phi = TREE_CHAIN (phi))
{
pred = new_loop->header->pred;
def = phi_element_for_edge (phi, pred)->def;
if (TREE_CODE (def) != SSA_NAME)
continue;
ann = ssa_name_ann (def);
new_names = ann ? ann->common.aux : NULL;
if (!new_names)
continue;
new_var = new_names[new_loop->header->rbi->copy_number];
add_phi_arg (&phi, new_var, loop_latch_edge(new_loop));
}
free_new_names (definitions, false);
return true;
}