cfghooks.c (lv_flush_pending_stmts, [...]): New.

2005-03-30 Mostafa Hagog <mustafa@il.ibm.com>

        * cfghooks.c (lv_flush_pending_stmts,
        cfg_hook_duplicate_loop_to_header_edge, extract_cond_bb_edges,
        lv_adjust_loop_header_phi, lv_add_condition_to_bb): New.
        * cfghooks.h (cfg_hook_duplicate_loop_to_header_edge,
        lv_add_condition_to_bb,
        lv_adjust_loop_header_phi, extract_cond_bb_edges,
        flush_pending_stmts): New in cfg_hooks structure.
        (cfg_hook_duplicate_loop_to_header_edge, lv_flush_pending_stmts,
        extract_cond_bb_edges, lv_adjust_loop_header_phi,
        lv_add_condition_to_bb): New declarations.
        * cfgloop.h (duplicate_loop_to_header_edge): Change return type to
        bool.
        (loop_version): Declare.
        * cfgloopmanip.c (cfghooks.h): Include.
        (duplicate_loop_to_header_edge): Change return type to bool.
        (loop_version, lv_adjust_loop_entry_edge): Move here.
        * cfgrtl.c (cfgloop.h): Include.
        (rtl_verify_flow_info_1): Fix.
        (rtl_lv_add_condition_to_bb, rtl_extract_cond_bb_edges): New.
        (rtl_cfg_hooks, cfg_layout_rtl_cfg_hook): Add hooks to
        initialization.
        * tree-cfg.c (tree_lv_adjust_loop_header_phi,
        tree_lv_add_condition_to_bb): New.
        (tree_cfg_hooks): Add new hooks to initialization.
        * tree-ssa-loop-manip.c (lv_adjust_loop_header_phi,
        lv_adjust_loop_entry_edge, tree_ssa_loop_version): Remove.

From-SVN: r97481
This commit is contained in:
Mostafa Hagog 2005-04-03 08:44:33 +00:00 committed by Mostafa Hagog
parent 2be74e4108
commit 1cb7dfc3b3
9 changed files with 415 additions and 186 deletions

View File

@ -1,3 +1,32 @@
2005-04-03 Mostafa Hagog <mustafa@il.ibm.com>
* cfghooks.c (lv_flush_pending_stmts,
cfg_hook_duplicate_loop_to_header_edge, extract_cond_bb_edges,
lv_adjust_loop_header_phi, lv_add_condition_to_bb): New.
* cfghooks.h (cfg_hook_duplicate_loop_to_header_edge,
lv_add_condition_to_bb,
lv_adjust_loop_header_phi, extract_cond_bb_edges,
flush_pending_stmts): New in cfg_hooks structure.
(cfg_hook_duplicate_loop_to_header_edge, lv_flush_pending_stmts,
extract_cond_bb_edges, lv_adjust_loop_header_phi,
lv_add_condition_to_bb): New declarations.
* cfgloop.h (duplicate_loop_to_header_edge): Change return type to
bool.
(loop_version): Declare.
* cfgloopmanip.c (cfghooks.h): Include.
(duplicate_loop_to_header_edge): Change return type to bool.
(loop_version, lv_adjust_loop_entry_edge): Move here.
* cfgrtl.c (cfgloop.h): Include.
(rtl_verify_flow_info_1): Fix.
(rtl_lv_add_condition_to_bb, rtl_extract_cond_bb_edges): New.
(rtl_cfg_hooks, cfg_layout_rtl_cfg_hook): Add hooks to
initialization.
* tree-cfg.c (tree_lv_adjust_loop_header_phi,
tree_lv_add_condition_to_bb): New.
(tree_cfg_hooks): Add new hooks to initialization.
* tree-ssa-loop-manip.c (lv_adjust_loop_header_phi,
lv_adjust_loop_entry_edge, tree_ssa_loop_version): Remove.
2005-04-03 Kazu Hirata <kazu@cs.umass.edu>
* config/stormy16/stormy16.h (PREDICATE_CODES): Add SUBREG to

View File

@ -823,3 +823,66 @@ execute_on_shrinking_pred (edge e)
if (cfg_hooks->execute_on_shrinking_pred)
cfg_hooks->execute_on_shrinking_pred (e);
}
/* This is used inside loop versioning when we want to insert
stmts/insns on the edges, which have a different behaviour
in tree's and in RTL, so we made a CFG hook. */
void
lv_flush_pending_stmts (edge e)
{
if (cfg_hooks->flush_pending_stmts)
cfg_hooks->flush_pending_stmts (e);
}
/* Loop versioning uses the duplicate_loop_to_header_edge to create
a new version of the loop basic-blocks, the parameters here are
exactly the same as in duplicate_loop_to_header_edge or
tree_duplicate_loop_to_header_edge; while in tree-ssa there is
additional work to maintain ssa information that's why there is
a need to call the tree_duplicate_loop_to_header_edge rather
than duplicate_loop_to_header_edge when we are in tree mode. */
bool
cfg_hook_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)
{
gcc_assert (cfg_hooks->cfg_hook_duplicate_loop_to_header_edge);
return cfg_hooks->cfg_hook_duplicate_loop_to_header_edge (loop, e, loops,
ndupl, wont_exit,
orig, to_remove,
n_to_remove, flags);
}
/* Conditional jumps are represented differently in trees and RTL,
this hook takes a basic block that is known to have a cond jump
at its end and extracts the taken and not taken eges out of it
and store it in E1 and E2 respectively. */
void
extract_cond_bb_edges (basic_block b, edge *e1, edge *e2)
{
gcc_assert (cfg_hooks->extract_cond_bb_edges);
cfg_hooks->extract_cond_bb_edges (b, e1, e2);
}
/* Responsible for updating the ssa info (PHI nodes) on the
new conidtion basic block that guargs the versioned loop. */
void
lv_adjust_loop_header_phi (basic_block first, basic_block second,
basic_block new, edge e)
{
if (cfg_hooks->lv_adjust_loop_header_phi)
cfg_hooks->lv_adjust_loop_header_phi (first, second, new, e);
}
/* Conditions in trees and RTL are different so we need
a different handling when we add the condition to the
versioning code. */
void
lv_add_condition_to_bb (basic_block first, basic_block second,
basic_block new, void *cond)
{
gcc_assert (cfg_hooks->lv_add_condition_to_bb);
cfg_hooks->lv_add_condition_to_bb (first, second, new, cond);
}

View File

@ -108,6 +108,33 @@ struct cfg_hooks
/* This function is called immediately before edge E is removed from
the edge vector E->dest->preds. */
void (*execute_on_shrinking_pred) (edge);
/* A hook for duplicating loop in CFG, currently this is used
in loop versioning. */
bool (*cfg_hook_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);
/* Add conition to new basic block and update CFG used in loop
versioning. */
void (*lv_add_condition_to_bb) (basic_block, basic_block, basic_block,
void *);
/* Update the PHI nodes in case of loop versioning. */
void (*lv_adjust_loop_header_phi) (basic_block, basic_block,
basic_block, edge);
/* Given a condition BB extract the true/false taken/not taken edges
(depending if we are on tree's or RTL). */
void (*extract_cond_bb_edges) (basic_block, edge *, edge *);
/* Add PHI arguments queued in PENDINT_STMT list on edge E to edge
E->dest (only in tree-ssa loop versioning. */
void (*flush_pending_stmts) (edge);
};
extern void verify_flow_info (void);
@ -136,6 +163,20 @@ extern bool block_ends_with_condjump_p (basic_block bb);
extern int flow_call_edges_add (sbitmap);
extern void execute_on_growing_pred (edge);
extern void execute_on_shrinking_pred (edge);
extern bool cfg_hook_duplicate_loop_to_header_edge (struct loop *loop, edge,
struct loops *loops,
unsigned int ndupl,
sbitmap wont_exit,
edge orig, edge *to_remove,
unsigned int *n_to_remove,
int flags);
extern void lv_flush_pending_stmts (edge);
extern void extract_cond_bb_edges (basic_block, edge *, edge*);
extern void lv_adjust_loop_header_phi (basic_block, basic_block, basic_block,
edge);
extern void lv_add_condition_to_bb (basic_block, basic_block, basic_block,
void *);
/* Hooks containers. */
extern struct cfg_hooks tree_cfg_hooks;

View File

@ -298,11 +298,13 @@ extern bool can_duplicate_loop_p (struct loop *loop);
extern struct loop * duplicate_loop (struct loops *, struct loop *,
struct loop *);
extern int duplicate_loop_to_header_edge (struct loop *, edge, struct loops *,
unsigned, sbitmap, edge, edge *,
unsigned *, int);
extern bool duplicate_loop_to_header_edge (struct loop *, edge, struct loops *,
unsigned, sbitmap, edge, edge *,
unsigned *, int);
extern struct loop *loopify (struct loops *, edge, edge,
basic_block, edge, edge, bool);
struct loop * loop_version (struct loops *, struct loop *, void *,
basic_block *);
extern bool remove_path (struct loops *, edge);
extern edge split_loop_bb (basic_block, void *);

View File

@ -28,6 +28,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "basic-block.h"
#include "cfgloop.h"
#include "cfglayout.h"
#include "cfghooks.h"
#include "output.h"
static void duplicate_subloops (struct loops *, struct loop *, struct loop *);
@ -837,7 +838,7 @@ update_single_exits_after_duplication (basic_block *bbs, unsigned nbbs,
original LOOP body, the other copies are numbered in order given by control
flow through them) into TO_REMOVE array. Returns false if duplication is
impossible. */
int
bool
duplicate_loop_to_header_edge (struct loop *loop, edge e, struct loops *loops,
unsigned int ndupl, sbitmap wont_exit,
edge orig, edge *to_remove,
@ -1354,6 +1355,135 @@ create_loop_notes (void)
flow_loops_free (&loops);
}
/* This function is called from loop_version. It splits the entry edge
of the loop we want to version, adds the versioning condition, and
adjust the edges to the two versions of the loop appropriately.
e is an incoming edge. Returns the basic block containing the
condition.
--- edge e ---- > [second_head]
Split it and insert new conditional expression and adjust edges.
--- edge e ---> [cond expr] ---> [first_head]
|
+---------> [second_head]
*/
static basic_block
lv_adjust_loop_entry_edge (basic_block first_head,
basic_block second_head,
edge e,
tree cond_expr)
{
basic_block new_head = NULL;
edge e1;
gcc_assert (e->dest == second_head);
/* Split edge 'e'. This will create a new basic block, where we can
insert conditional expr. */
new_head = split_edge (e);
lv_add_condition_to_bb (first_head, second_head, new_head,
cond_expr);
e1 = make_edge (new_head, first_head, EDGE_TRUE_VALUE);
set_immediate_dominator (CDI_DOMINATORS, first_head, new_head);
set_immediate_dominator (CDI_DOMINATORS, second_head, new_head);
/* Adjust loop header phi nodes. */
lv_adjust_loop_header_phi (first_head, second_head, new_head, e1);
return new_head;
}
/* Main entry point for Loop Versioning transformation.
This transformation given a condition and a loop, creates
-if (condition) { loop_copy1 } else { loop_copy2 },
where loop_copy1 is the loop transformed in one way, and loop_copy2
is the loop transformed in another way (or unchanged). 'condition'
may be a run time test for things that were not resolved by static
analysis (overlapping ranges (anti-aliasing), alignment, etc.). */
struct loop *
loop_version (struct loops *loops, struct loop * loop,
void *cond_expr, basic_block *condition_bb)
{
basic_block first_head, second_head;
edge entry, latch_edge, exit, true_edge, false_edge;
int irred_flag;
struct loop *nloop;
/* CHECKME: Loop versioning does not handle nested loop at this point. */
if (loop->inner)
return NULL;
/* Record entry and latch edges for the loop */
entry = loop_preheader_edge (loop);
irred_flag = entry->flags & EDGE_IRREDUCIBLE_LOOP;
entry->flags &= ~EDGE_IRREDUCIBLE_LOOP;
/* Note down head of loop as first_head. */
first_head = entry->dest;
/* Duplicate loop. */
if (!cfg_hook_duplicate_loop_to_header_edge (loop, entry, loops, 1,
NULL, NULL, NULL, NULL, 0))
return NULL;
/* After duplication entry edge now points to new loop head block.
Note down new head as second_head. */
second_head = entry->dest;
/* Split loop entry edge and insert new block with cond expr. */
*condition_bb = lv_adjust_loop_entry_edge (first_head, second_head,
entry, cond_expr);
if (!*condition_bb)
{
entry->flags |= irred_flag;
return NULL;
}
latch_edge = single_succ_edge (loop->latch->rbi->copy);
extract_cond_bb_edges (*condition_bb, &true_edge, &false_edge);
nloop = loopify (loops,
latch_edge,
single_pred_edge (loop->header->rbi->copy),
*condition_bb, true_edge, false_edge,
false /* Do not redirect all edges. */);
exit = loop->single_exit;
if (exit)
nloop->single_exit = find_edge (exit->src->rbi->copy, exit->dest);
/* loopify redirected latch_edge. Update its PENDING_STMTS. */
lv_flush_pending_stmts (latch_edge);
/* loopify redirected condition_bb's succ edge. Update its PENDING_STMTS. */
extract_cond_bb_edges (*condition_bb, &true_edge, &false_edge);
lv_flush_pending_stmts (false_edge);
/* Adjust irreducible flag. */
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;
single_pred_edge ((*condition_bb))->flags |= EDGE_IRREDUCIBLE_LOOP;
}
/* At this point condition_bb is loop predheader with two successors,
first_head and second_head. Make sure that loop predheader has only
one successor. */
loop_split_edge_with (loop_preheader_edge (loop), NULL);
loop_split_edge_with (loop_preheader_edge (nloop), NULL);
return nloop;
}
/* The structure of LOOPS might have changed. Some loops might get removed
(and their headers and latches were set to NULL), loop exists might get
removed (thus the loop nesting may be wrong), and some blocks and edges

View File

@ -57,7 +57,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "cfglayout.h"
#include "expr.h"
#include "target.h"
#include "cfgloop.h"
/* The labels mentioned in non-jump rtl. Valid during find_basic_blocks. */
/* ??? Should probably be using LABEL_NUSES instead. It would take a
@ -2028,7 +2028,7 @@ rtl_verify_flow_info_1 (void)
err = 1;
}
if (n_branch != 1 && any_condjump_p (BB_END (bb))
&& JUMP_LABEL (BB_END (bb)) != BB_HEAD (fallthru->dest))
&& JUMP_LABEL (BB_END (bb)) == BB_HEAD (fallthru->dest))
{
error ("Wrong amount of branch edges after conditional jump %i", bb->index);
err = 1;
@ -2997,6 +2997,66 @@ rtl_flow_call_edges_add (sbitmap blocks)
return blocks_split;
}
/* Add COMP_RTX as a condition at end of COND_BB. FIRST_HEAD is
the conditional branch traget, SECOND_HEAD should be the fall-thru
there is no need to handle this here the loop versioning code handles
this. the reason for SECON_HEAD is that it is needed for condition
in trees, and this should be of the same type since it is a hook. */
static void
rtl_lv_add_condition_to_bb (basic_block first_head ,
basic_block second_head ATTRIBUTE_UNUSED,
basic_block cond_bb, void *comp_rtx)
{
rtx label, seq, jump;
rtx op0 = XEXP ((rtx)comp_rtx, 0);
rtx op1 = XEXP ((rtx)comp_rtx, 1);
enum rtx_code comp = GET_CODE ((rtx)comp_rtx);
enum machine_mode mode;
label = block_label (first_head);
mode = GET_MODE (op0);
if (mode == VOIDmode)
mode = GET_MODE (op1);
start_sequence ();
op0 = force_operand (op0, NULL_RTX);
op1 = force_operand (op1, NULL_RTX);
do_compare_rtx_and_jump (op0, op1, comp, 0,
mode, NULL_RTX, NULL_RTX, label);
jump = get_last_insn ();
JUMP_LABEL (jump) = label;
LABEL_NUSES (label)++;
seq = get_insns ();
end_sequence ();
/* Add the new cond , in the new head. */
emit_insn_after(seq, BB_END(cond_bb));
}
/* Given a block B with unconditional branch at its end, get the
store the return the branch edge and the fall-thru edge in
BRANCH_EDGE and FALLTHRU_EDGE respectively. */
static void
rtl_extract_cond_bb_edges (basic_block b, edge *branch_edge,
edge *fallthru_edge)
{
edge e = EDGE_SUCC (b, 0);
if (e->flags & EDGE_FALLTHRU)
{
*fallthru_edge = e;
*branch_edge = EDGE_SUCC (b, 1);
}
else
{
*branch_edge = e;
*fallthru_edge = EDGE_SUCC (b, 1);
}
}
/* Implementation of CFG manipulation for linearized RTL. */
struct cfg_hooks rtl_cfg_hooks = {
"rtl",
@ -3021,7 +3081,12 @@ struct cfg_hooks rtl_cfg_hooks = {
rtl_block_ends_with_condjump_p,
rtl_flow_call_edges_add,
NULL, /* execute_on_growing_pred */
NULL /* execute_on_shrinking_pred */
NULL, /* execute_on_shrinking_pred */
NULL, /* duplicate loop for trees */
NULL, /* lv_add_condition_to_bb */
NULL, /* lv_adjust_loop_header_phi*/
NULL, /* extract_cond_bb_edges */
NULL /* flush_pending_stmts */
};
/* Implementation of CFG manipulation for cfg layout RTL, where
@ -3059,6 +3124,11 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
rtl_block_ends_with_condjump_p,
rtl_flow_call_edges_add,
NULL, /* execute_on_growing_pred */
NULL /* execute_on_shrinking_pred */
NULL, /* execute_on_shrinking_pred */
duplicate_loop_to_header_edge, /* duplicate loop for trees */
rtl_lv_add_condition_to_bb, /* lv_add_condition_to_bb */
NULL, /* lv_adjust_loop_header_phi*/
rtl_extract_cond_bb_edges, /* extract_cond_bb_edges */
NULL /* flush_pending_stmts */
};

View File

@ -5687,6 +5687,71 @@ tree_execute_on_shrinking_pred (edge e)
remove_phi_args (e);
}
/*---------------------------------------------------------------------------
Helper functions for Loop versioning
---------------------------------------------------------------------------*/
/* Adjust phi nodes for 'first' basic block. 'second' basic block is a copy
of 'first'. Both of them are dominated by 'new_head' basic block. When
'new_head' was created by 'second's incoming edge it received phi arguments
on the edge by split_edge(). Later, additional edge 'e' was created to
connect 'new_head' and 'first'. Now this routine adds phi args on this
additional edge 'e' that new_head to second edge received as part of edge
splitting.
*/
static void
tree_lv_adjust_loop_header_phi (basic_block first, basic_block second,
basic_block new_head, edge e)
{
tree phi1, phi2;
/* Browse all 'second' basic block phi nodes and add phi args to
edge 'e' for 'first' head. PHI args are always in correct order. */
for (phi2 = phi_nodes (second), phi1 = phi_nodes (first);
phi2 && phi1;
phi2 = PHI_CHAIN (phi2), phi1 = PHI_CHAIN (phi1))
{
edge e2 = find_edge (new_head, second);
if (e2)
{
tree def = PHI_ARG_DEF (phi2, e2->dest_idx);
add_phi_arg (phi1, def, e);
}
}
}
/* Adds a if else statement to COND_BB with condition COND_EXPR.
SECOND_HEAD is the destination of the THEN and FIRST_HEAD is
the destination of the ELSE part. */
static void
tree_lv_add_condition_to_bb (basic_block first_head, basic_block second_head,
basic_block cond_bb, void *cond_e)
{
block_stmt_iterator bsi;
tree goto1 = NULL_TREE;
tree goto2 = NULL_TREE;
tree new_cond_expr = NULL_TREE;
tree cond_expr = (tree) cond_e;
edge e0;
/* Build new conditional expr */
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 = build3 (COND_EXPR, void_type_node, cond_expr, goto1, goto2);
/* Add new cond in cond_bb. */
bsi = bsi_start (cond_bb);
bsi_insert_after (&bsi, new_cond_expr, BSI_NEW_STMT);
/* Adjust edges appropriately to connect new head with first head
as well as second head. */
e0 = single_succ_edge (cond_bb);
e0->flags &= ~EDGE_FALLTHRU;
e0->flags |= EDGE_FALSE_VALUE;
}
struct cfg_hooks tree_cfg_hooks = {
"tree",
tree_verify_flow_info,
@ -5711,6 +5776,11 @@ struct cfg_hooks tree_cfg_hooks = {
tree_flow_call_edges_add, /* flow_call_edges_add */
tree_execute_on_growing_pred, /* execute_on_growing_pred */
tree_execute_on_shrinking_pred, /* execute_on_shrinking_pred */
tree_duplicate_loop_to_header_edge, /* duplicate loop for trees */
tree_lv_add_condition_to_bb, /* lv_add_condition_to_bb */
tree_lv_adjust_loop_header_phi, /* lv_adjust_loop_header_phi*/
extract_true_false_edges_from_block, /* extract_cond_bb_edges */
flush_pending_stmts /* flush_pending_stmts */
};

View File

@ -677,179 +677,3 @@ tree_duplicate_loop_to_header_edge (struct loop *loop, edge e,
return true;
}
/*---------------------------------------------------------------------------
Loop versioning
---------------------------------------------------------------------------*/
/* Adjust phi nodes for 'first' basic block. 'second' basic block is a copy
of 'first'. Both of them are dominated by 'new_head' basic block. When
'new_head' was created by 'second's incoming edge it received phi arguments
on the edge by split_edge(). Later, additional edge 'e' was created to
connect 'new_head' and 'first'. Now this routine adds phi args on this
additional edge 'e' that new_head to second edge received as part of edge
splitting.
*/
static void
lv_adjust_loop_header_phi (basic_block first, basic_block second,
basic_block new_head, edge e)
{
tree phi1, phi2;
/* Browse all 'second' basic block phi nodes and add phi args to
edge 'e' for 'first' head. PHI args are always in correct order. */
for (phi2 = phi_nodes (second), phi1 = phi_nodes (first);
phi2 && phi1;
phi2 = PHI_CHAIN (phi2), phi1 = PHI_CHAIN (phi1))
{
edge e2 = find_edge (new_head, second);
if (e2)
{
tree def = PHI_ARG_DEF (phi2, e2->dest_idx);
add_phi_arg (phi1, def, e);
}
}
}
/* Adjust entry edge for lv.
e is an incoming edge.
--- edge e ---- > [second_head]
Split it and insert new conditional expression and adjust edges.
--- edge e ---> [cond expr] ---> [first_head]
|
+---------> [second_head]
*/
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 new_head = NULL;
tree goto1 = NULL_TREE;
tree goto2 = NULL_TREE;
tree new_cond_expr = NULL_TREE;
edge e0, e1;
gcc_assert (e->dest == second_head);
/* Split edge 'e'. This will create a new basic block, where we can
insert conditional expr. */
new_head = split_edge (e);
/* Build new conditional expr */
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 = build3 (COND_EXPR, void_type_node, cond_expr, goto1, goto2);
/* Add new cond. in new head. */
bsi = bsi_start (new_head);
bsi_insert_after (&bsi, new_cond_expr, BSI_NEW_STMT);
/* Adjust edges appropriately to connect new head with first head
as well as second head. */
e0 = single_succ_edge (new_head);
e0->flags &= ~EDGE_FALLTHRU;
e0->flags |= EDGE_FALSE_VALUE;
e1 = make_edge (new_head, first_head, EDGE_TRUE_VALUE);
set_immediate_dominator (CDI_DOMINATORS, first_head, new_head);
set_immediate_dominator (CDI_DOMINATORS, second_head, new_head);
/* Adjust loop header phi nodes. */
lv_adjust_loop_header_phi (first_head, second_head, new_head, e1);
return new_head;
}
/* Main entry point for Loop Versioning transformation.
This transformation given a condition and a loop, creates
-if (condition) { loop_copy1 } else { loop_copy2 },
where loop_copy1 is the loop transformed in one way, and loop_copy2
is the loop transformed in another way (or unchanged). 'condition'
may be a run time test for things that were not resolved by static
analysis (overlapping ranges (anti-aliasing), alignment, etc.). */
struct loop *
tree_ssa_loop_version (struct loops *loops, struct loop * loop,
tree cond_expr, basic_block *condition_bb)
{
edge entry, latch_edge, exit, true_edge, false_edge;
basic_block first_head, second_head;
int irred_flag;
struct loop *nloop;
/* CHECKME: Loop versioning does not handle nested loop at this point. */
if (loop->inner)
return NULL;
/* Record entry and latch edges for the loop */
entry = loop_preheader_edge (loop);
/* Note down head of loop as first_head. */
first_head = entry->dest;
/* Duplicate loop. */
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;
}
/* After duplication entry edge now points to new loop head block.
Note down new head as second_head. */
second_head = entry->dest;
/* Split loop entry edge and insert new block with cond expr. */
*condition_bb = lv_adjust_loop_entry_edge (first_head, second_head, entry,
cond_expr);
latch_edge = single_succ_edge (loop->latch->rbi->copy);
extract_true_false_edges_from_block (*condition_bb, &true_edge, &false_edge);
nloop = loopify (loops,
latch_edge,
single_pred_edge (loop->header->rbi->copy),
*condition_bb, true_edge, false_edge,
false /* Do not redirect all edges. */);
exit = loop->single_exit;
if (exit)
nloop->single_exit = find_edge (exit->src->rbi->copy, exit->dest);
/* loopify redirected latch_edge. Update its PENDING_STMTS. */
flush_pending_stmts (latch_edge);
/* loopify redirected condition_bb's succ edge. Update its PENDING_STMTS. */
extract_true_false_edges_from_block (*condition_bb, &true_edge, &false_edge);
flush_pending_stmts (false_edge);
/* Adjust irreducible flag. */
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;
single_pred_edge ((*condition_bb))->flags |= EDGE_IRREDUCIBLE_LOOP;
}
/* At this point condition_bb is loop predheader with two successors,
first_head and second_head. Make sure that loop predheader has only
one successor. */
loop_split_edge_with (loop_preheader_edge (loop), NULL);
loop_split_edge_with (loop_preheader_edge (nloop), NULL);
return nloop;
}

View File

@ -283,6 +283,6 @@ tree_unswitch_loop (struct loops *loops, struct loop *loop,
gcc_assert (EDGE_COUNT (unswitch_on->succs) == 2);
gcc_assert (loop->inner == NULL);
return tree_ssa_loop_version (loops, loop, unshare_expr (cond),
&condition_bb);
return loop_version (loops, loop, unshare_expr (cond),
&condition_bb);
}