mirror of git://gcc.gnu.org/git/gcc.git
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>
|
2005-04-03 Kazu Hirata <kazu@cs.umass.edu>
|
||||||
|
|
||||||
* config/stormy16/stormy16.h (PREDICATE_CODES): Add SUBREG to
|
* 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)
|
if (cfg_hooks->execute_on_shrinking_pred)
|
||||||
cfg_hooks->execute_on_shrinking_pred (e);
|
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
|
/* This function is called immediately before edge E is removed from
|
||||||
the edge vector E->dest->preds. */
|
the edge vector E->dest->preds. */
|
||||||
void (*execute_on_shrinking_pred) (edge);
|
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);
|
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 int flow_call_edges_add (sbitmap);
|
||||||
extern void execute_on_growing_pred (edge);
|
extern void execute_on_growing_pred (edge);
|
||||||
extern void execute_on_shrinking_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. */
|
/* Hooks containers. */
|
||||||
extern struct cfg_hooks tree_cfg_hooks;
|
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 *,
|
extern struct loop * duplicate_loop (struct loops *, struct loop *,
|
||||||
struct loop *);
|
struct loop *);
|
||||||
extern int duplicate_loop_to_header_edge (struct loop *, edge, struct loops *,
|
extern bool duplicate_loop_to_header_edge (struct loop *, edge, struct loops *,
|
||||||
unsigned, sbitmap, edge, edge *,
|
unsigned, sbitmap, edge, edge *,
|
||||||
unsigned *, int);
|
unsigned *, int);
|
||||||
extern struct loop *loopify (struct loops *, edge, edge,
|
extern struct loop *loopify (struct loops *, edge, edge,
|
||||||
basic_block, edge, edge, bool);
|
basic_block, edge, edge, bool);
|
||||||
|
struct loop * loop_version (struct loops *, struct loop *, void *,
|
||||||
|
basic_block *);
|
||||||
extern bool remove_path (struct loops *, edge);
|
extern bool remove_path (struct loops *, edge);
|
||||||
extern edge split_loop_bb (basic_block, void *);
|
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 "basic-block.h"
|
||||||
#include "cfgloop.h"
|
#include "cfgloop.h"
|
||||||
#include "cfglayout.h"
|
#include "cfglayout.h"
|
||||||
|
#include "cfghooks.h"
|
||||||
#include "output.h"
|
#include "output.h"
|
||||||
|
|
||||||
static void duplicate_subloops (struct loops *, struct loop *, struct loop *);
|
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
|
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
|
flow through them) into TO_REMOVE array. Returns false if duplication is
|
||||||
impossible. */
|
impossible. */
|
||||||
int
|
bool
|
||||||
duplicate_loop_to_header_edge (struct loop *loop, edge e, struct loops *loops,
|
duplicate_loop_to_header_edge (struct loop *loop, edge e, struct loops *loops,
|
||||||
unsigned int ndupl, sbitmap wont_exit,
|
unsigned int ndupl, sbitmap wont_exit,
|
||||||
edge orig, edge *to_remove,
|
edge orig, edge *to_remove,
|
||||||
|
@ -1354,6 +1355,135 @@ create_loop_notes (void)
|
||||||
flow_loops_free (&loops);
|
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
|
/* 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
|
(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
|
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 "cfglayout.h"
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
|
#include "cfgloop.h"
|
||||||
|
|
||||||
/* The labels mentioned in non-jump rtl. Valid during find_basic_blocks. */
|
/* The labels mentioned in non-jump rtl. Valid during find_basic_blocks. */
|
||||||
/* ??? Should probably be using LABEL_NUSES instead. It would take a
|
/* ??? Should probably be using LABEL_NUSES instead. It would take a
|
||||||
|
@ -2028,7 +2028,7 @@ rtl_verify_flow_info_1 (void)
|
||||||
err = 1;
|
err = 1;
|
||||||
}
|
}
|
||||||
if (n_branch != 1 && any_condjump_p (BB_END (bb))
|
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);
|
error ("Wrong amount of branch edges after conditional jump %i", bb->index);
|
||||||
err = 1;
|
err = 1;
|
||||||
|
@ -2997,6 +2997,66 @@ rtl_flow_call_edges_add (sbitmap blocks)
|
||||||
return blocks_split;
|
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. */
|
/* Implementation of CFG manipulation for linearized RTL. */
|
||||||
struct cfg_hooks rtl_cfg_hooks = {
|
struct cfg_hooks rtl_cfg_hooks = {
|
||||||
"rtl",
|
"rtl",
|
||||||
|
@ -3021,7 +3081,12 @@ struct cfg_hooks rtl_cfg_hooks = {
|
||||||
rtl_block_ends_with_condjump_p,
|
rtl_block_ends_with_condjump_p,
|
||||||
rtl_flow_call_edges_add,
|
rtl_flow_call_edges_add,
|
||||||
NULL, /* execute_on_growing_pred */
|
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
|
/* 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_block_ends_with_condjump_p,
|
||||||
rtl_flow_call_edges_add,
|
rtl_flow_call_edges_add,
|
||||||
NULL, /* execute_on_growing_pred */
|
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);
|
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 = {
|
struct cfg_hooks tree_cfg_hooks = {
|
||||||
"tree",
|
"tree",
|
||||||
tree_verify_flow_info,
|
tree_verify_flow_info,
|
||||||
|
@ -5711,6 +5776,11 @@ struct cfg_hooks tree_cfg_hooks = {
|
||||||
tree_flow_call_edges_add, /* flow_call_edges_add */
|
tree_flow_call_edges_add, /* flow_call_edges_add */
|
||||||
tree_execute_on_growing_pred, /* execute_on_growing_pred */
|
tree_execute_on_growing_pred, /* execute_on_growing_pred */
|
||||||
tree_execute_on_shrinking_pred, /* execute_on_shrinking_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;
|
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 (EDGE_COUNT (unswitch_on->succs) == 2);
|
||||||
gcc_assert (loop->inner == NULL);
|
gcc_assert (loop->inner == NULL);
|
||||||
|
|
||||||
return tree_ssa_loop_version (loops, loop, unshare_expr (cond),
|
return loop_version (loops, loop, unshare_expr (cond),
|
||||||
&condition_bb);
|
&condition_bb);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue