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:
parent
2be74e4108
commit
1cb7dfc3b3
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 *);
|
||||
|
||||
|
@ -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
|
||||
|
78
gcc/cfgrtl.c
78
gcc/cfgrtl.c
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user