cfgloopanal.c: New file.
* cfgloopanal.c: New file. * cfgloopmanip.c: New file. * Makefile.in (cfgloopanal.o, cfgloopmanip.o): New. (toplev.o, loop.o, doloop.o, unroll.o, cfgloop.o, predict.o, cfglayout.o): Add dependency on cfgloop.h. (cfgloop.o): Add flags.h dependency. * basic-block.h (BB_IRREDUCIBLE_LOOP, BB_SUPERBLOCK): New flags. (VLS_EXPECT_PREHEADERS, VLS_EXPECT_SIMPLE_LATCHES): Removed. (struct loop, struct loops, flow_loops_find, flow_loops_update, flow_loops_free, flow_loops_dump, flow_loop_dump, flow_loop_scan, flow_loop_tree_node_add, flow_loop_tree_node_remove, LOOP_TREE,,LOOP_PRE_HEADER, LOOP_ENTRY_EDGES, LOOP_EXIT_EDGES, LOOP_ALL, flow_loop_outside_edge_p, flow_loop_nested_p, flow_bb_inside_loop_p, get_loop_body, loop_preheader_edge, loop_latch_edge, add_bb_to_loop, remove_bb_from_loops, find_common_loop, verify_loop_structure): Declarations moved to ... * cfgloop.h: New file. * bb-reorder.c (reorder_basic_blocks): Modified. * cfglayout.c: Include cfgloop.h. (cleanup_unconditional_jumps, cfg_layout_redirect_edge, cfg_layout_duplicate_bb, cfg_layout_initialize): Update loop structure. (break_superblocks): New static function. (cfg_layout_finalize): Use it. (cfg_layout_split_block): New function. * cfglayout.h (struct reorder_block_def): Add copy and duplicated fields. (cfg_layout_initialize, cfg_layout_redirect_edge): Declaration changed. (cfg_layout_split_block): Declare. * cfgloop.c: Include cfgloop.h and flags.h. (flow_loop_dump, flow_loops_free, flow_loop_exit_edges_find, get_loop_body): Avoid signed versus unsigned comparison warnings. (make_forwarder_block, flow_loops_find, loop_preheader_edge, loop_latch_edge): Modified. (verify_loop_structure): Modified to use flags stored in loop structure; check irreducible loops. (cancel_loop, cancel_loop_tree): New functions. (estimate_probability): Use loop analysis code for predictions. (estimate_loops_at_level): Avoid signed versus unsigned comparison warnings. * doloop.c: Include cfgloop.h. * loop.c: Include cfgloop.h. * predict.c: Include cfgloop.h. * toplev.c: Include cfgloop.h. * unroll.c: Include cfgloop.h. * tracer.c (tracer): Modified. From-SVN: r61730
This commit is contained in:
parent
55d0e5e022
commit
3d436d2ac5
@ -1,3 +1,52 @@
|
||||
2003-01-24 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
|
||||
|
||||
* cfgloopanal.c: New file.
|
||||
* cfgloopmanip.c: New file.
|
||||
* Makefile.in (cfgloopanal.o, cfgloopmanip.o): New.
|
||||
(toplev.o, loop.o, doloop.o, unroll.o, cfgloop.o, predict.o,
|
||||
cfglayout.o): Add dependency on cfgloop.h.
|
||||
(cfgloop.o): Add flags.h dependency.
|
||||
* basic-block.h (BB_IRREDUCIBLE_LOOP, BB_SUPERBLOCK): New flags.
|
||||
(VLS_EXPECT_PREHEADERS, VLS_EXPECT_SIMPLE_LATCHES): Removed.
|
||||
(struct loop, struct loops, flow_loops_find, flow_loops_update,
|
||||
flow_loops_free, flow_loops_dump, flow_loop_dump,
|
||||
flow_loop_scan, flow_loop_tree_node_add, flow_loop_tree_node_remove,
|
||||
LOOP_TREE,,LOOP_PRE_HEADER, LOOP_ENTRY_EDGES, LOOP_EXIT_EDGES,
|
||||
LOOP_ALL, flow_loop_outside_edge_p, flow_loop_nested_p,
|
||||
flow_bb_inside_loop_p, get_loop_body, loop_preheader_edge,
|
||||
loop_latch_edge, add_bb_to_loop, remove_bb_from_loops,
|
||||
find_common_loop, verify_loop_structure): Declarations moved to ...
|
||||
* cfgloop.h: New file.
|
||||
* bb-reorder.c (reorder_basic_blocks): Modified.
|
||||
* cfglayout.c: Include cfgloop.h.
|
||||
(cleanup_unconditional_jumps, cfg_layout_redirect_edge,
|
||||
cfg_layout_duplicate_bb, cfg_layout_initialize): Update loop structure.
|
||||
(break_superblocks): New static function.
|
||||
(cfg_layout_finalize): Use it.
|
||||
(cfg_layout_split_block): New function.
|
||||
* cfglayout.h (struct reorder_block_def): Add copy and duplicated
|
||||
fields.
|
||||
(cfg_layout_initialize, cfg_layout_redirect_edge): Declaration
|
||||
changed.
|
||||
(cfg_layout_split_block): Declare.
|
||||
* cfgloop.c: Include cfgloop.h and flags.h.
|
||||
(flow_loop_dump, flow_loops_free, flow_loop_exit_edges_find,
|
||||
get_loop_body): Avoid signed versus unsigned comparison warnings.
|
||||
(make_forwarder_block, flow_loops_find, loop_preheader_edge,
|
||||
loop_latch_edge): Modified.
|
||||
(verify_loop_structure): Modified to use flags stored in loop structure;
|
||||
check irreducible loops.
|
||||
(cancel_loop, cancel_loop_tree): New functions.
|
||||
(estimate_probability): Use loop analysis code for predictions.
|
||||
(estimate_loops_at_level): Avoid signed versus unsigned comparison
|
||||
warnings.
|
||||
* doloop.c: Include cfgloop.h.
|
||||
* loop.c: Include cfgloop.h.
|
||||
* predict.c: Include cfgloop.h.
|
||||
* toplev.c: Include cfgloop.h.
|
||||
* unroll.c: Include cfgloop.h.
|
||||
* tracer.c (tracer): Modified.
|
||||
|
||||
2003-01-24 Kazu Hirata <kazu@cs.umass.edu>
|
||||
|
||||
* config/h8300/h8300.c (get_shift_alg): Fix a typo.
|
||||
|
@ -770,6 +770,7 @@ C_OBJS = c-parse.o c-lang.o c-pretty-print.o $(C_AND_OBJC_OBJS)
|
||||
|
||||
OBJS = alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o \
|
||||
cfg.o cfganal.o cfgbuild.o cfgcleanup.o cfglayout.o cfgloop.o \
|
||||
cfgloopanal.o cfgloopmanip.o \
|
||||
cfgrtl.o combine.o conflict.o convert.o cse.o cselib.o dbxout.o \
|
||||
debug.o df.o diagnostic.o doloop.o dominance.o \
|
||||
dwarf2asm.o dwarf2out.o dwarfout.o emit-rtl.o except.o explow.o \
|
||||
@ -1428,7 +1429,7 @@ toplev.o : toplev.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_
|
||||
dwarf2out.h sdbout.h dbxout.h $(EXPR_H) hard-reg-set.h $(BASIC_BLOCK_H) \
|
||||
graph.h $(LOOP_H) except.h $(REGS_H) $(TIMEVAR_H) $(lang_options_files) \
|
||||
ssa.h $(PARAMS_H) $(TM_P_H) reload.h dwarf2asm.h $(TARGET_H) \
|
||||
langhooks.h insn-flags.h options.h cfglayout.h real.h
|
||||
langhooks.h insn-flags.h options.h cfglayout.h real.h cfgloop.h
|
||||
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
|
||||
-DTARGET_NAME=\"$(target_alias)\" \
|
||||
-c $(srcdir)/toplev.c $(OUTPUT_OPTION)
|
||||
@ -1560,13 +1561,15 @@ profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TRE
|
||||
$(TARGET_H) langhooks.h profile.h libfuncs.h gt-profile.h $(HASHTAB_H)
|
||||
loop.o : loop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h $(LOOP_H) \
|
||||
insn-config.h $(REGS_H) hard-reg-set.h $(RECOG_H) $(EXPR_H) \
|
||||
real.h $(PREDICT_H) $(BASIC_BLOCK_H) function.h \
|
||||
real.h $(PREDICT_H) $(BASIC_BLOCK_H) function.h cfgloop.h \
|
||||
toplev.h varray.h except.h cselib.h $(OPTABS_H) $(TM_P_H)
|
||||
doloop.o : doloop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \
|
||||
$(LOOP_H) $(EXPR_H) hard-reg-set.h $(BASIC_BLOCK_H) $(TM_P_H) toplev.h
|
||||
$(LOOP_H) $(EXPR_H) hard-reg-set.h $(BASIC_BLOCK_H) $(TM_P_H) toplev.h \
|
||||
cfgloop.h
|
||||
unroll.o : unroll.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) insn-config.h \
|
||||
function.h $(INTEGRATE_H) $(REGS_H) $(RECOG_H) flags.h $(EXPR_H) $(LOOP_H) toplev.h \
|
||||
hard-reg-set.h varray.h $(BASIC_BLOCK_H) $(TM_P_H) $(PREDICT_H) $(PARAMS_H)
|
||||
hard-reg-set.h varray.h $(BASIC_BLOCK_H) $(TM_P_H) $(PREDICT_H) $(PARAMS_H) \
|
||||
cfgloop.h
|
||||
alloc-pool.o : alloc-pool.c $(CONFIG_H) $(SYSTEM_H) alloc-pool.h
|
||||
flow.o : flow.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
|
||||
flags.h insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h \
|
||||
@ -1585,8 +1588,12 @@ cfgbuild.o : cfgbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) fla
|
||||
cfgcleanup.o : cfgcleanup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
|
||||
$(TIMEVAR_H) $(BASIC_BLOCK_H) hard-reg-set.h output.h flags.h $(RECOG_H) toplev.h \
|
||||
$(GGC_H) insn-config.h cselib.h $(TARGET_H) $(TM_P_H)
|
||||
cfgloop.o : cfgloop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
|
||||
$(BASIC_BLOCK_H) hard-reg-set.h
|
||||
cfgloop.o : cfgloop.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
|
||||
$(BASIC_BLOCK_H) hard-reg-set.h cfgloop.h flags.h
|
||||
cfgloopanal.o : cfgloopanal.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
|
||||
$(BASIC_BLOCK_H) hard-reg-set.h cfgloop.h $(EXPR_H)
|
||||
cfgloopmanip.o : cfgloopmanip.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
|
||||
$(BASIC_BLOCK_H) hard-reg-set.h cfgloop.h cfglayout.h output.h
|
||||
dominance.o : dominance.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
|
||||
hard-reg-set.h $(BASIC_BLOCK_H) et-forest.h
|
||||
et-forest.o : et-forest.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) et-forest.h alloc-pool.h
|
||||
@ -1669,7 +1676,7 @@ reg-stack.o : reg-stack.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $
|
||||
predict.o: predict.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
|
||||
flags.h insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h \
|
||||
$(RECOG_H) function.h except.h $(EXPR_H) $(TM_P_H) $(PREDICT_H) real.h \
|
||||
$(PARAMS_H) $(TARGET_H)
|
||||
$(PARAMS_H) $(TARGET_H) cfgloop.h
|
||||
lists.o: lists.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h $(RTL_H) $(GGC_H)
|
||||
bb-reorder.o : bb-reorder.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
|
||||
$(TREE_H) flags.h $(BASIC_BLOCK_H) hard-reg-set.h output.h cfglayout.h $(TARGET_H)
|
||||
@ -1678,7 +1685,7 @@ tracer.o : tracer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_
|
||||
$(PARAMS_H) profile.h
|
||||
cfglayout.o : cfglayout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
|
||||
insn-config.h $(BASIC_BLOCK_H) hard-reg-set.h output.h function.h \
|
||||
cfglayout.h
|
||||
cfglayout.h cfgloop.h
|
||||
timevar.o : timevar.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TIMEVAR_H) flags.h \
|
||||
intl.h toplev.h
|
||||
regrename.o : regrename.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
|
||||
|
@ -153,6 +153,9 @@ typedef struct edge_def {
|
||||
|
||||
#define EDGE_COMPLEX (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH)
|
||||
|
||||
/* Declared in cfgloop.h. */
|
||||
struct loop;
|
||||
struct loops;
|
||||
|
||||
/* A basic block is a sequence of instructions with only entry and
|
||||
only one exit. If any one of the instructions are executed, they
|
||||
@ -240,6 +243,8 @@ typedef struct basic_block_def {
|
||||
#define BB_NEW 2
|
||||
#define BB_REACHABLE 4
|
||||
#define BB_VISITED 8
|
||||
#define BB_IRREDUCIBLE_LOOP 16
|
||||
#define BB_SUPERBLOCK 32
|
||||
|
||||
/* Number of basic blocks in the current function. */
|
||||
|
||||
@ -360,6 +365,9 @@ extern void tidy_fallthru_edges PARAMS ((void));
|
||||
extern void flow_reverse_top_sort_order_compute PARAMS ((int *));
|
||||
extern int flow_depth_first_order_compute PARAMS ((int *, int *));
|
||||
extern void flow_preorder_transversal_compute PARAMS ((int *));
|
||||
extern int dfs_enumerate_from PARAMS ((basic_block, int,
|
||||
bool (*)(basic_block, void *),
|
||||
basic_block *, int, void *));
|
||||
extern void dump_edge_info PARAMS ((FILE *, edge, int));
|
||||
extern void clear_edges PARAMS ((void));
|
||||
extern void mark_critical_edges PARAMS ((void));
|
||||
@ -369,165 +377,6 @@ extern rtx first_insn_after_basic_block_note PARAMS ((basic_block));
|
||||
|
||||
typedef struct dominance_info *dominance_info;
|
||||
|
||||
/* Structure to hold information for each natural loop. */
|
||||
struct loop
|
||||
{
|
||||
/* Index into loops array. */
|
||||
int num;
|
||||
|
||||
/* Basic block of loop header. */
|
||||
basic_block header;
|
||||
|
||||
/* Basic block of loop latch. */
|
||||
basic_block latch;
|
||||
|
||||
/* Basic block of loop pre-header or NULL if it does not exist. */
|
||||
basic_block pre_header;
|
||||
|
||||
/* Array of edges along the pre-header extended basic block trace.
|
||||
The source of the first edge is the root node of pre-header
|
||||
extended basic block, if it exists. */
|
||||
edge *pre_header_edges;
|
||||
|
||||
/* Number of edges along the pre_header extended basic block trace. */
|
||||
int num_pre_header_edges;
|
||||
|
||||
/* The first block in the loop. This is not necessarily the same as
|
||||
the loop header. */
|
||||
basic_block first;
|
||||
|
||||
/* The last block in the loop. This is not necessarily the same as
|
||||
the loop latch. */
|
||||
basic_block last;
|
||||
|
||||
/* Bitmap of blocks contained within the loop. */
|
||||
sbitmap nodes;
|
||||
|
||||
/* Number of blocks contained within the loop. */
|
||||
int num_nodes;
|
||||
|
||||
/* Array of edges that enter the loop. */
|
||||
edge *entry_edges;
|
||||
|
||||
/* Number of edges that enter the loop. */
|
||||
int num_entries;
|
||||
|
||||
/* Array of edges that exit the loop. */
|
||||
edge *exit_edges;
|
||||
|
||||
/* Number of edges that exit the loop. */
|
||||
int num_exits;
|
||||
|
||||
/* Bitmap of blocks that dominate all exits of the loop. */
|
||||
sbitmap exits_doms;
|
||||
|
||||
/* The loop nesting depth. */
|
||||
int depth;
|
||||
|
||||
/* Superloops of the loop. */
|
||||
struct loop **pred;
|
||||
|
||||
/* The height of the loop (enclosed loop levels) within the loop
|
||||
hierarchy tree. */
|
||||
int level;
|
||||
|
||||
/* The outer (parent) loop or NULL if outermost loop. */
|
||||
struct loop *outer;
|
||||
|
||||
/* The first inner (child) loop or NULL if innermost loop. */
|
||||
struct loop *inner;
|
||||
|
||||
/* Link to the next (sibling) loop. */
|
||||
struct loop *next;
|
||||
|
||||
/* Nonzero if the loop is invalid (e.g., contains setjmp.). */
|
||||
int invalid;
|
||||
|
||||
/* Auxiliary info specific to a pass. */
|
||||
void *aux;
|
||||
|
||||
/* The following are currently used by loop.c but they are likely to
|
||||
disappear as loop.c is converted to use the CFG. */
|
||||
|
||||
/* Nonzero if the loop has a NOTE_INSN_LOOP_VTOP. */
|
||||
rtx vtop;
|
||||
|
||||
/* Nonzero if the loop has a NOTE_INSN_LOOP_CONT.
|
||||
A continue statement will generate a branch to NEXT_INSN (cont). */
|
||||
rtx cont;
|
||||
|
||||
/* The NOTE_INSN_LOOP_BEG. */
|
||||
rtx start;
|
||||
|
||||
/* The NOTE_INSN_LOOP_END. */
|
||||
rtx end;
|
||||
|
||||
/* For a rotated loop that is entered near the bottom,
|
||||
this is the label at the top. Otherwise it is zero. */
|
||||
rtx top;
|
||||
|
||||
/* Place in the loop where control enters. */
|
||||
rtx scan_start;
|
||||
|
||||
/* The position where to sink insns out of the loop. */
|
||||
rtx sink;
|
||||
|
||||
/* List of all LABEL_REFs which refer to code labels outside the
|
||||
loop. Used by routines that need to know all loop exits, such as
|
||||
final_biv_value and final_giv_value.
|
||||
|
||||
This does not include loop exits due to return instructions.
|
||||
This is because all bivs and givs are pseudos, and hence must be
|
||||
dead after a return, so the presence of a return does not affect
|
||||
any of the optimizations that use this info. It is simpler to
|
||||
just not include return instructions on this list. */
|
||||
rtx exit_labels;
|
||||
|
||||
/* The number of LABEL_REFs on exit_labels for this loop and all
|
||||
loops nested inside it. */
|
||||
int exit_count;
|
||||
};
|
||||
|
||||
|
||||
/* Structure to hold CFG information about natural loops within a function. */
|
||||
struct loops
|
||||
{
|
||||
/* Number of natural loops in the function. */
|
||||
int num;
|
||||
|
||||
/* Maxium nested loop level in the function. */
|
||||
int levels;
|
||||
|
||||
/* Array of natural loop descriptors (scanning this array in reverse order
|
||||
will find the inner loops before their enclosing outer loops). */
|
||||
struct loop *array;
|
||||
|
||||
/* The above array is unused in new loop infrastructure and is kept only for
|
||||
purposes of the old loop optimizer. Instead we store just pointers to
|
||||
loops here. */
|
||||
struct loop **parray;
|
||||
|
||||
/* Pointer to root of loop heirachy tree. */
|
||||
struct loop *tree_root;
|
||||
|
||||
/* Information derived from the CFG. */
|
||||
struct cfg
|
||||
{
|
||||
/* The bitmap vector of dominators or NULL if not computed. */
|
||||
dominance_info dom;
|
||||
|
||||
/* The ordering of the basic blocks in a depth first search. */
|
||||
int *dfs_order;
|
||||
|
||||
/* The reverse completion ordering of the basic blocks found in a
|
||||
depth first search. */
|
||||
int *rc_order;
|
||||
} cfg;
|
||||
|
||||
/* Headers shared by multiple loops that should be merged. */
|
||||
sbitmap shared_headers;
|
||||
};
|
||||
|
||||
/* Structure to group all of the information to process IF-THEN and
|
||||
IF-THEN-ELSE blocks for the conditional execution support. This
|
||||
needs to be in a public file in case the IFCVT macros call
|
||||
@ -555,19 +404,6 @@ typedef struct ce_if_block
|
||||
|
||||
} ce_if_block_t;
|
||||
|
||||
extern int flow_loops_find PARAMS ((struct loops *, int flags));
|
||||
extern int flow_loops_update PARAMS ((struct loops *, int flags));
|
||||
extern void flow_loops_free PARAMS ((struct loops *));
|
||||
extern void flow_loops_dump PARAMS ((const struct loops *, FILE *,
|
||||
void (*)(const struct loop *,
|
||||
FILE *, int), int));
|
||||
extern void flow_loop_dump PARAMS ((const struct loop *, FILE *,
|
||||
void (*)(const struct loop *,
|
||||
FILE *, int), int));
|
||||
extern int flow_loop_scan PARAMS ((struct loops *, struct loop *, int));
|
||||
extern void flow_loop_tree_node_add PARAMS ((struct loop *, struct loop *));
|
||||
extern void flow_loop_tree_node_remove PARAMS ((struct loop *));
|
||||
|
||||
/* This structure maintains an edge list vector. */
|
||||
struct edge_list
|
||||
{
|
||||
@ -658,15 +494,6 @@ enum update_life_extent
|
||||
#define CLEANUP_THREADING 64 /* Do jump threading. */
|
||||
#define CLEANUP_NO_INSN_DEL 128 /* Do not try to delete trivially dead
|
||||
insns. */
|
||||
/* Flags for loop discovery. */
|
||||
|
||||
#define LOOP_TREE 1 /* Build loop hierarchy tree. */
|
||||
#define LOOP_PRE_HEADER 2 /* Analyse loop pre-header. */
|
||||
#define LOOP_ENTRY_EDGES 4 /* Find entry edges. */
|
||||
#define LOOP_EXIT_EDGES 8 /* Find exit edges. */
|
||||
#define LOOP_EDGES (LOOP_ENTRY_EDGES | LOOP_EXIT_EDGES)
|
||||
#define LOOP_ALL 15 /* All of the above */
|
||||
|
||||
extern void life_analysis PARAMS ((rtx, FILE *, int));
|
||||
extern int update_life_info PARAMS ((sbitmap, enum update_life_extent,
|
||||
int));
|
||||
@ -752,26 +579,6 @@ extern void free_aux_for_edges PARAMS ((void));
|
||||
debugger, and it is declared extern so we don't get warnings about
|
||||
it being unused. */
|
||||
extern void verify_flow_info PARAMS ((void));
|
||||
extern bool flow_loop_outside_edge_p PARAMS ((const struct loop *, edge));
|
||||
extern bool flow_loop_nested_p PARAMS ((const struct loop *,
|
||||
const struct loop *));
|
||||
extern bool flow_bb_inside_loop_p PARAMS ((const struct loop *,
|
||||
const basic_block));
|
||||
extern basic_block *get_loop_body PARAMS ((const struct loop *));
|
||||
extern int dfs_enumerate_from PARAMS ((basic_block, int,
|
||||
bool (*)(basic_block, void *),
|
||||
basic_block *, int, void *));
|
||||
|
||||
extern edge loop_preheader_edge PARAMS ((struct loop *));
|
||||
extern edge loop_latch_edge PARAMS ((struct loop *));
|
||||
|
||||
extern void add_bb_to_loop PARAMS ((basic_block, struct loop *));
|
||||
extern void remove_bb_from_loops PARAMS ((basic_block));
|
||||
extern struct loop * find_common_loop PARAMS ((struct loop *, struct loop *));
|
||||
|
||||
extern void verify_loop_structure PARAMS ((struct loops *, int));
|
||||
#define VLS_EXPECT_PREHEADERS 1
|
||||
#define VLS_EXPECT_SIMPLE_LATCHES 2
|
||||
|
||||
typedef struct conflict_graph_def *conflict_graph;
|
||||
|
||||
|
@ -268,7 +268,7 @@ reorder_basic_blocks ()
|
||||
if ((* targetm.cannot_modify_jumps_p) ())
|
||||
return;
|
||||
|
||||
cfg_layout_initialize ();
|
||||
cfg_layout_initialize (NULL);
|
||||
|
||||
make_reorder_chain ();
|
||||
|
||||
|
@ -31,6 +31,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "function.h"
|
||||
#include "obstack.h"
|
||||
#include "cfglayout.h"
|
||||
#include "cfgloop.h"
|
||||
|
||||
/* The contents of the current function definition are allocated
|
||||
in this obstack, and all are freed at the end of the function. */
|
||||
@ -48,10 +49,11 @@ static void set_block_levels PARAMS ((tree, int));
|
||||
static void change_scope PARAMS ((rtx, tree, tree));
|
||||
|
||||
void verify_insn_chain PARAMS ((void));
|
||||
static void cleanup_unconditional_jumps PARAMS ((void));
|
||||
static void cleanup_unconditional_jumps PARAMS ((struct loops *));
|
||||
static void fixup_fallthru_exit_predecessor PARAMS ((void));
|
||||
static rtx unlink_insn_chain PARAMS ((rtx, rtx));
|
||||
static rtx duplicate_insn_chain PARAMS ((rtx, rtx));
|
||||
static void break_superblocks PARAMS ((void));
|
||||
|
||||
static rtx
|
||||
unlink_insn_chain (first, last)
|
||||
@ -612,10 +614,12 @@ verify_insn_chain ()
|
||||
/* Remove any unconditional jumps and forwarder block creating fallthru
|
||||
edges instead. During BB reordering, fallthru edges are not required
|
||||
to target next basic block in the linear CFG layout, so the unconditional
|
||||
jumps are not needed. */
|
||||
jumps are not needed. If LOOPS is not null, also update loop structure &
|
||||
dominators. */
|
||||
|
||||
static void
|
||||
cleanup_unconditional_jumps ()
|
||||
cleanup_unconditional_jumps (loops)
|
||||
struct loops *loops;
|
||||
{
|
||||
basic_block bb;
|
||||
|
||||
@ -637,6 +641,25 @@ cleanup_unconditional_jumps ()
|
||||
fprintf (rtl_dump_file, "Removing forwarder BB %i\n",
|
||||
bb->index);
|
||||
|
||||
if (loops)
|
||||
{
|
||||
/* bb cannot be loop header, as it only has one entry
|
||||
edge. It could be a loop latch. */
|
||||
if (bb->loop_father->header == bb)
|
||||
abort ();
|
||||
|
||||
if (bb->loop_father->latch == bb)
|
||||
bb->loop_father->latch = bb->pred->src;
|
||||
|
||||
if (get_immediate_dominator
|
||||
(loops->cfg.dom, bb->succ->dest) == bb)
|
||||
set_immediate_dominator
|
||||
(loops->cfg.dom, bb->succ->dest, bb->pred->src);
|
||||
|
||||
remove_bb_from_loops (bb);
|
||||
delete_from_dominance_info (loops->cfg.dom, bb);
|
||||
}
|
||||
|
||||
redirect_edge_succ_nodup (bb->pred, bb->succ->dest);
|
||||
flow_delete_block (bb);
|
||||
bb = prev;
|
||||
@ -822,13 +845,14 @@ duplicate_insn_chain (from, to)
|
||||
}
|
||||
|
||||
/* Redirect Edge to DEST. */
|
||||
void
|
||||
bool
|
||||
cfg_layout_redirect_edge (e, dest)
|
||||
edge e;
|
||||
basic_block dest;
|
||||
{
|
||||
basic_block src = e->src;
|
||||
basic_block old_next_bb = src->next_bb;
|
||||
bool ret;
|
||||
|
||||
/* Redirect_edge_and_branch may decide to turn branch into fallthru edge
|
||||
in the case the basic block appears to be in sequence. Avoid this
|
||||
@ -849,9 +873,11 @@ cfg_layout_redirect_edge (e, dest)
|
||||
delete_insn (src->end);
|
||||
}
|
||||
redirect_edge_succ_nodup (e, dest);
|
||||
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
redirect_edge_and_branch (e, dest);
|
||||
ret = redirect_edge_and_branch (e, dest);
|
||||
|
||||
/* We don't want simplejumps in the insn stream during cfglayout. */
|
||||
if (simplejump_p (src->end))
|
||||
@ -861,6 +887,22 @@ cfg_layout_redirect_edge (e, dest)
|
||||
src->succ->flags |= EDGE_FALLTHRU;
|
||||
}
|
||||
src->next_bb = old_next_bb;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Same as split_block but update cfg_layout structures. */
|
||||
edge
|
||||
cfg_layout_split_block (bb, insn)
|
||||
basic_block bb;
|
||||
rtx insn;
|
||||
{
|
||||
edge fallthru = split_block (bb, insn);
|
||||
|
||||
alloc_aux_for_block (fallthru->dest, sizeof (struct reorder_block_def));
|
||||
RBI (fallthru->dest)->footer = RBI (fallthru->src)->footer;
|
||||
RBI (fallthru->src)->footer = NULL;
|
||||
return fallthru;
|
||||
}
|
||||
|
||||
/* Create a duplicate of the basic block BB and redirect edge E into it. */
|
||||
@ -949,6 +991,7 @@ cfg_layout_duplicate_bb (bb, e)
|
||||
bb->frequency = 0;
|
||||
|
||||
RBI (new_bb)->original = bb;
|
||||
RBI (bb)->copy = new_bb;
|
||||
return new_bb;
|
||||
}
|
||||
|
||||
@ -956,17 +999,47 @@ cfg_layout_duplicate_bb (bb, e)
|
||||
CFG layout changes. It keeps LOOPS up-to-date if not null. */
|
||||
|
||||
void
|
||||
cfg_layout_initialize ()
|
||||
cfg_layout_initialize (loops)
|
||||
struct loops *loops;
|
||||
{
|
||||
/* Our algorithm depends on fact that there are now dead jumptables
|
||||
around the code. */
|
||||
alloc_aux_for_blocks (sizeof (struct reorder_block_def));
|
||||
|
||||
cleanup_unconditional_jumps ();
|
||||
cleanup_unconditional_jumps (loops);
|
||||
|
||||
record_effective_endpoints ();
|
||||
}
|
||||
|
||||
/* Splits superblocks. */
|
||||
static void
|
||||
break_superblocks ()
|
||||
{
|
||||
sbitmap superblocks;
|
||||
int i, need;
|
||||
|
||||
superblocks = sbitmap_alloc (n_basic_blocks);
|
||||
sbitmap_zero (superblocks);
|
||||
|
||||
need = 0;
|
||||
|
||||
for (i = 0; i < n_basic_blocks; i++)
|
||||
if (BASIC_BLOCK(i)->flags & BB_SUPERBLOCK)
|
||||
{
|
||||
BASIC_BLOCK(i)->flags &= ~BB_SUPERBLOCK;
|
||||
SET_BIT (superblocks, i);
|
||||
need = 1;
|
||||
}
|
||||
|
||||
if (need)
|
||||
{
|
||||
rebuild_jump_labels (get_insns ());
|
||||
find_many_sub_basic_blocks (superblocks);
|
||||
}
|
||||
|
||||
free (superblocks);
|
||||
}
|
||||
|
||||
/* Finalize the changes: reorder insn list according to the sequence, enter
|
||||
compensation code, rebuild scope forest. */
|
||||
|
||||
@ -982,6 +1055,8 @@ cfg_layout_finalize ()
|
||||
|
||||
free_aux_for_blocks ();
|
||||
|
||||
break_superblocks ();
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
verify_flow_info ();
|
||||
#endif
|
||||
|
@ -25,6 +25,9 @@ typedef struct reorder_block_def
|
||||
rtx footer;
|
||||
basic_block next;
|
||||
basic_block original;
|
||||
/* Used by loop copying. */
|
||||
basic_block copy;
|
||||
int duplicated;
|
||||
|
||||
/* These fields are used by bb-reorder pass. */
|
||||
int visited;
|
||||
@ -32,10 +35,11 @@ typedef struct reorder_block_def
|
||||
|
||||
#define RBI(BB) ((reorder_block_def) (BB)->aux)
|
||||
|
||||
extern void cfg_layout_initialize PARAMS ((void));
|
||||
extern void cfg_layout_initialize PARAMS ((struct loops *));
|
||||
extern void cfg_layout_finalize PARAMS ((void));
|
||||
extern bool cfg_layout_can_duplicate_bb_p PARAMS ((basic_block));
|
||||
extern basic_block cfg_layout_duplicate_bb PARAMS ((basic_block, edge));
|
||||
extern void scope_to_insns_initialize PARAMS ((void));
|
||||
extern void scope_to_insns_finalize PARAMS ((void));
|
||||
extern void cfg_layout_redirect_edge PARAMS ((edge, basic_block));
|
||||
extern bool cfg_layout_redirect_edge PARAMS ((edge, basic_block));
|
||||
extern edge cfg_layout_split_block PARAMS ((basic_block, rtx));
|
||||
|
106
gcc/cfgloop.c
106
gcc/cfgloop.c
@ -26,6 +26,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "hard-reg-set.h"
|
||||
#include "basic-block.h"
|
||||
#include "toplev.h"
|
||||
#include "cfgloop.h"
|
||||
#include "flags.h"
|
||||
|
||||
/* Ratio of frequencies of edges so that one of more latch edges is
|
||||
considered to belong to inner loop with same header. */
|
||||
@ -114,7 +116,7 @@ flow_loop_dump (loop, file, loop_dump_aux, verbose)
|
||||
int verbose;
|
||||
{
|
||||
basic_block *bbs;
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
if (! loop || ! loop->header)
|
||||
return;
|
||||
@ -206,7 +208,7 @@ flow_loops_free (loops)
|
||||
{
|
||||
if (loops->parray)
|
||||
{
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
if (! loops->num)
|
||||
abort ();
|
||||
@ -275,7 +277,7 @@ flow_loop_exit_edges_find (loop)
|
||||
{
|
||||
edge e;
|
||||
basic_block node, *bbs;
|
||||
int num_exits, i;
|
||||
unsigned num_exits, i;
|
||||
|
||||
loop->exit_edges = NULL;
|
||||
loop->num_exits = 0;
|
||||
@ -609,6 +611,10 @@ make_forwarder_block (bb, redirect_latch, redirect_nonlatch, except,
|
||||
|
||||
insn = PREV_INSN (first_insn_after_basic_block_note (bb));
|
||||
|
||||
/* For empty block split_block will return NULL. */
|
||||
if (bb->end == insn)
|
||||
emit_note_after (NOTE_INSN_DELETED, insn);
|
||||
|
||||
fallthru = split_block (bb, insn);
|
||||
dummy = fallthru->src;
|
||||
bb = fallthru->dest;
|
||||
@ -926,9 +932,11 @@ flow_loops_find (loops, flags)
|
||||
loops->cfg.dom = NULL;
|
||||
free_dominance_info (dom);
|
||||
}
|
||||
|
||||
loops->state = 0;
|
||||
#ifdef ENABLE_CHECKING
|
||||
verify_flow_info ();
|
||||
verify_loop_structure (loops, 0);
|
||||
verify_loop_structure (loops);
|
||||
#endif
|
||||
|
||||
return loops->num;
|
||||
@ -992,7 +1000,7 @@ get_loop_body (loop)
|
||||
const struct loop *loop;
|
||||
{
|
||||
basic_block *tovisit, bb;
|
||||
int tv = 0;
|
||||
unsigned tv = 0;
|
||||
|
||||
if (!loop->num_nodes)
|
||||
abort ();
|
||||
@ -1003,7 +1011,7 @@ get_loop_body (loop)
|
||||
if (loop->latch == EXIT_BLOCK_PTR)
|
||||
{
|
||||
/* There may be blocks unreachable from EXIT_BLOCK. */
|
||||
if (loop->num_nodes != n_basic_blocks + 2)
|
||||
if (loop->num_nodes != (unsigned) n_basic_blocks + 2)
|
||||
abort ();
|
||||
FOR_EACH_BB (bb)
|
||||
tovisit[tv++] = bb;
|
||||
@ -1073,18 +1081,57 @@ find_common_loop (loop_s, loop_d)
|
||||
return loop_s;
|
||||
}
|
||||
|
||||
/* Cancels the LOOP; it must be innermost one. */
|
||||
void
|
||||
cancel_loop (loops, loop)
|
||||
struct loops *loops;
|
||||
struct loop *loop;
|
||||
{
|
||||
basic_block *bbs;
|
||||
unsigned i;
|
||||
|
||||
if (loop->inner)
|
||||
abort ();
|
||||
|
||||
/* Move blocks up one level (they should be removed as soon as possible). */
|
||||
bbs = get_loop_body (loop);
|
||||
for (i = 0; i < loop->num_nodes; i++)
|
||||
bbs[i]->loop_father = loop->outer;
|
||||
|
||||
/* Remove the loop from structure. */
|
||||
flow_loop_tree_node_remove (loop);
|
||||
|
||||
/* Remove loop from loops array. */
|
||||
loops->parray[loop->num] = NULL;
|
||||
|
||||
/* Free loop data. */
|
||||
flow_loop_free (loop);
|
||||
}
|
||||
|
||||
/* Cancels LOOP and all its subloops. */
|
||||
void
|
||||
cancel_loop_tree (loops, loop)
|
||||
struct loops *loops;
|
||||
struct loop *loop;
|
||||
{
|
||||
while (loop->inner)
|
||||
cancel_loop_tree (loops, loop->inner);
|
||||
cancel_loop (loops, loop);
|
||||
}
|
||||
|
||||
/* Checks that LOOPS are allright:
|
||||
-- sizes of loops are allright
|
||||
-- results of get_loop_body really belong to the loop
|
||||
-- loop header have just single entry edge and single latch edge
|
||||
-- loop latches have only single successor that is header of their loop
|
||||
-- irreducible loops are correctly marked
|
||||
*/
|
||||
void
|
||||
verify_loop_structure (loops, flags)
|
||||
verify_loop_structure (loops)
|
||||
struct loops *loops;
|
||||
int flags;
|
||||
{
|
||||
int *sizes, i, j;
|
||||
unsigned *sizes, i, j;
|
||||
sbitmap irreds;
|
||||
basic_block *bbs, bb;
|
||||
struct loop *loop;
|
||||
int err = 0;
|
||||
@ -1137,14 +1184,14 @@ verify_loop_structure (loops, flags)
|
||||
if (!loop)
|
||||
continue;
|
||||
|
||||
if ((flags & VLS_EXPECT_PREHEADERS)
|
||||
if ((loops->state & LOOPS_HAVE_PREHEADERS)
|
||||
&& (!loop->header->pred->pred_next
|
||||
|| loop->header->pred->pred_next->pred_next))
|
||||
{
|
||||
error ("Loop %d's header does not have exactly 2 entries.", i);
|
||||
err = 1;
|
||||
}
|
||||
if (flags & VLS_EXPECT_SIMPLE_LATCHES)
|
||||
if (loops->state & LOOPS_HAVE_SIMPLE_LATCHES)
|
||||
{
|
||||
if (!loop->latch->succ
|
||||
|| loop->latch->succ->succ_next)
|
||||
@ -1170,6 +1217,39 @@ verify_loop_structure (loops, flags)
|
||||
}
|
||||
}
|
||||
|
||||
/* Check irreducible loops. */
|
||||
if (loops->state & LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS)
|
||||
{
|
||||
/* Record old info. */
|
||||
irreds = sbitmap_alloc (last_basic_block);
|
||||
FOR_EACH_BB (bb)
|
||||
if (bb->flags & BB_IRREDUCIBLE_LOOP)
|
||||
SET_BIT (irreds, bb->index);
|
||||
else
|
||||
RESET_BIT (irreds, bb->index);
|
||||
|
||||
/* Recount it. */
|
||||
mark_irreducible_loops (loops);
|
||||
|
||||
/* Compare. */
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
if ((bb->flags & BB_IRREDUCIBLE_LOOP)
|
||||
&& !TEST_BIT (irreds, bb->index))
|
||||
{
|
||||
error ("Basic block %d should be marked irreducible.", bb->index);
|
||||
err = 1;
|
||||
}
|
||||
else if (!(bb->flags & BB_IRREDUCIBLE_LOOP)
|
||||
&& TEST_BIT (irreds, bb->index))
|
||||
{
|
||||
error ("Basic block %d should not be marked irreducible.", bb->index);
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
free (irreds);
|
||||
}
|
||||
|
||||
if (err)
|
||||
abort ();
|
||||
}
|
||||
@ -1177,7 +1257,7 @@ verify_loop_structure (loops, flags)
|
||||
/* Returns latch edge of LOOP. */
|
||||
edge
|
||||
loop_latch_edge (loop)
|
||||
struct loop *loop;
|
||||
const struct loop *loop;
|
||||
{
|
||||
edge e;
|
||||
|
||||
@ -1190,7 +1270,7 @@ loop_latch_edge (loop)
|
||||
/* Returns preheader edge of LOOP. */
|
||||
edge
|
||||
loop_preheader_edge (loop)
|
||||
struct loop *loop;
|
||||
const struct loop *loop;
|
||||
{
|
||||
edge e;
|
||||
|
||||
|
314
gcc/cfgloop.h
Normal file
314
gcc/cfgloop.h
Normal file
@ -0,0 +1,314 @@
|
||||
/* Natural loop functions
|
||||
Copyright (C) 1987, 1997, 1998, 1999, 2000, 2001, 2002
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING. If not, write to the Free
|
||||
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
/* Structure to hold decision about unrolling/peeling. */
|
||||
enum lpt_dec
|
||||
{
|
||||
LPT_NONE,
|
||||
LPT_PEEL_COMPLETELY,
|
||||
LPT_PEEL_SIMPLE,
|
||||
LPT_UNROLL_CONSTANT,
|
||||
LPT_UNROLL_RUNTIME,
|
||||
LPT_UNROLL_STUPID
|
||||
};
|
||||
|
||||
struct lpt_decision
|
||||
{
|
||||
enum lpt_dec decision;
|
||||
unsigned times;
|
||||
};
|
||||
|
||||
/* Description of loop for simple loop unrolling. */
|
||||
struct loop_desc
|
||||
{
|
||||
int postincr; /* 1 if increment/decrement is done after loop exit condition. */
|
||||
rtx stride; /* Value added to VAR in each iteration. */
|
||||
rtx var; /* Loop control variable. */
|
||||
rtx var_alts; /* List of definitions of its initial value. */
|
||||
rtx lim; /* Expression var is compared with. */
|
||||
rtx lim_alts; /* List of definitions of its initial value. */
|
||||
bool const_iter; /* True if it iterates constant number of times. */
|
||||
unsigned HOST_WIDE_INT niter;
|
||||
/* Number of iterations if it is constant. */
|
||||
bool may_be_zero; /* If we cannot determine that the first iteration will pass. */
|
||||
enum rtx_code cond; /* Exit condition. */
|
||||
int neg; /* Set to 1 if loop ends when condition is satisfied. */
|
||||
edge out_edge; /* The exit edge. */
|
||||
edge in_edge; /* And the other one. */
|
||||
int n_branches; /* Number of branches inside the loop. */
|
||||
};
|
||||
|
||||
/* Structure to hold information for each natural loop. */
|
||||
struct loop
|
||||
{
|
||||
/* Index into loops array. */
|
||||
int num;
|
||||
|
||||
/* Basic block of loop header. */
|
||||
basic_block header;
|
||||
|
||||
/* Basic block of loop latch. */
|
||||
basic_block latch;
|
||||
|
||||
/* Basic block of loop preheader or NULL if it does not exist. */
|
||||
basic_block pre_header;
|
||||
|
||||
/* For loop unrolling/peeling decision. */
|
||||
struct lpt_decision lpt_decision;
|
||||
|
||||
/* Simple loop description. */
|
||||
int simple;
|
||||
struct loop_desc desc;
|
||||
int has_desc;
|
||||
|
||||
/* Number of loop insns. */
|
||||
unsigned ninsns;
|
||||
|
||||
/* Average number of executed insns per iteration. */
|
||||
unsigned av_ninsns;
|
||||
|
||||
/* Array of edges along the preheader extended basic block trace.
|
||||
The source of the first edge is the root node of preheader
|
||||
extended basic block, if it exists. */
|
||||
edge *pre_header_edges;
|
||||
|
||||
/* Number of edges along the pre_header extended basic block trace. */
|
||||
int num_pre_header_edges;
|
||||
|
||||
/* The first block in the loop. This is not necessarily the same as
|
||||
the loop header. */
|
||||
basic_block first;
|
||||
|
||||
/* The last block in the loop. This is not necessarily the same as
|
||||
the loop latch. */
|
||||
basic_block last;
|
||||
|
||||
/* Bitmap of blocks contained within the loop. */
|
||||
sbitmap nodes;
|
||||
|
||||
/* Number of blocks contained within the loop. */
|
||||
unsigned num_nodes;
|
||||
|
||||
/* Array of edges that enter the loop. */
|
||||
edge *entry_edges;
|
||||
|
||||
/* Number of edges that enter the loop. */
|
||||
int num_entries;
|
||||
|
||||
/* Array of edges that exit the loop. */
|
||||
edge *exit_edges;
|
||||
|
||||
/* Number of edges that exit the loop. */
|
||||
int num_exits;
|
||||
|
||||
/* Bitmap of blocks that dominate all exits of the loop. */
|
||||
sbitmap exits_doms;
|
||||
|
||||
/* The loop nesting depth. */
|
||||
int depth;
|
||||
|
||||
/* Superloops of the loop. */
|
||||
struct loop **pred;
|
||||
|
||||
/* The height of the loop (enclosed loop levels) within the loop
|
||||
hierarchy tree. */
|
||||
int level;
|
||||
|
||||
/* The outer (parent) loop or NULL if outermost loop. */
|
||||
struct loop *outer;
|
||||
|
||||
/* The first inner (child) loop or NULL if innermost loop. */
|
||||
struct loop *inner;
|
||||
|
||||
/* Link to the next (sibling) loop. */
|
||||
struct loop *next;
|
||||
|
||||
/* Loop that is copy of this loop. */
|
||||
struct loop *copy;
|
||||
|
||||
/* Non-zero if the loop is invalid (e.g., contains setjmp.). */
|
||||
int invalid;
|
||||
|
||||
/* Auxiliary info specific to a pass. */
|
||||
void *aux;
|
||||
|
||||
/* The following are currently used by loop.c but they are likely to
|
||||
disappear as loop.c is converted to use the CFG. */
|
||||
|
||||
/* Non-zero if the loop has a NOTE_INSN_LOOP_VTOP. */
|
||||
rtx vtop;
|
||||
|
||||
/* Non-zero if the loop has a NOTE_INSN_LOOP_CONT.
|
||||
A continue statement will generate a branch to NEXT_INSN (cont). */
|
||||
rtx cont;
|
||||
|
||||
/* The dominator of cont. */
|
||||
rtx cont_dominator;
|
||||
|
||||
/* The NOTE_INSN_LOOP_BEG. */
|
||||
rtx start;
|
||||
|
||||
/* The NOTE_INSN_LOOP_END. */
|
||||
rtx end;
|
||||
|
||||
/* For a rotated loop that is entered near the bottom,
|
||||
this is the label at the top. Otherwise it is zero. */
|
||||
rtx top;
|
||||
|
||||
/* Place in the loop where control enters. */
|
||||
rtx scan_start;
|
||||
|
||||
/* The position where to sink insns out of the loop. */
|
||||
rtx sink;
|
||||
|
||||
/* List of all LABEL_REFs which refer to code labels outside the
|
||||
loop. Used by routines that need to know all loop exits, such as
|
||||
final_biv_value and final_giv_value.
|
||||
|
||||
This does not include loop exits due to return instructions.
|
||||
This is because all bivs and givs are pseudos, and hence must be
|
||||
dead after a return, so the presence of a return does not affect
|
||||
any of the optimizations that use this info. It is simpler to
|
||||
just not include return instructions on this list. */
|
||||
rtx exit_labels;
|
||||
|
||||
/* The number of LABEL_REFs on exit_labels for this loop and all
|
||||
loops nested inside it. */
|
||||
int exit_count;
|
||||
};
|
||||
|
||||
/* Flags for state of loop structure. */
|
||||
enum
|
||||
{
|
||||
LOOPS_HAVE_PREHEADERS = 1,
|
||||
LOOPS_HAVE_SIMPLE_LATCHES = 2,
|
||||
LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS = 4
|
||||
};
|
||||
|
||||
/* Structure to hold CFG information about natural loops within a function. */
|
||||
struct loops
|
||||
{
|
||||
/* Number of natural loops in the function. */
|
||||
unsigned num;
|
||||
|
||||
/* Maximum nested loop level in the function. */
|
||||
unsigned levels;
|
||||
|
||||
/* Array of natural loop descriptors (scanning this array in reverse order
|
||||
will find the inner loops before their enclosing outer loops). */
|
||||
struct loop *array;
|
||||
|
||||
/* The above array is unused in new loop infrastructure and is kept only for
|
||||
purposes of the old loop optimizer. Instead we store just pointers to
|
||||
loops here. */
|
||||
struct loop **parray;
|
||||
|
||||
/* Pointer to root of loop hierarchy tree. */
|
||||
struct loop *tree_root;
|
||||
|
||||
/* Information derived from the CFG. */
|
||||
struct cfg
|
||||
{
|
||||
/* The bitmap vector of dominators or NULL if not computed. */
|
||||
dominance_info dom;
|
||||
|
||||
/* The ordering of the basic blocks in a depth first search. */
|
||||
int *dfs_order;
|
||||
|
||||
/* The reverse completion ordering of the basic blocks found in a
|
||||
depth first search. */
|
||||
int *rc_order;
|
||||
} cfg;
|
||||
|
||||
/* Headers shared by multiple loops that should be merged. */
|
||||
sbitmap shared_headers;
|
||||
|
||||
/* State of loops. */
|
||||
int state;
|
||||
};
|
||||
|
||||
/* Flags for loop discovery. */
|
||||
|
||||
#define LOOP_TREE 1 /* Build loop hierarchy tree. */
|
||||
#define LOOP_PRE_HEADER 2 /* Analyze loop preheader. */
|
||||
#define LOOP_ENTRY_EDGES 4 /* Find entry edges. */
|
||||
#define LOOP_EXIT_EDGES 8 /* Find exit edges. */
|
||||
#define LOOP_EDGES (LOOP_ENTRY_EDGES | LOOP_EXIT_EDGES)
|
||||
#define LOOP_ALL 15 /* All of the above */
|
||||
|
||||
/* Loop recognition. */
|
||||
extern int flow_loops_find PARAMS ((struct loops *, int flags));
|
||||
extern int flow_loops_update PARAMS ((struct loops *, int flags));
|
||||
extern void flow_loops_free PARAMS ((struct loops *));
|
||||
extern void flow_loops_dump PARAMS ((const struct loops *, FILE *,
|
||||
void (*)(const struct loop *,
|
||||
FILE *, int), int));
|
||||
extern void flow_loop_dump PARAMS ((const struct loop *, FILE *,
|
||||
void (*)(const struct loop *,
|
||||
FILE *, int), int));
|
||||
extern int flow_loop_scan PARAMS ((struct loops *,
|
||||
struct loop *, int));
|
||||
void mark_irreducible_loops PARAMS ((struct loops *));
|
||||
|
||||
/* Loop datastructure manipulation/querying. */
|
||||
extern void flow_loop_tree_node_add PARAMS ((struct loop *, struct loop *));
|
||||
extern void flow_loop_tree_node_remove PARAMS ((struct loop *));
|
||||
extern bool flow_loop_outside_edge_p PARAMS ((const struct loop *, edge));
|
||||
extern bool flow_loop_nested_p PARAMS ((const struct loop *,
|
||||
const struct loop *));
|
||||
extern bool flow_bb_inside_loop_p PARAMS ((const struct loop *,
|
||||
basic_block));
|
||||
extern struct loop * find_common_loop PARAMS ((struct loop *, struct loop *));
|
||||
extern int num_loop_insns PARAMS ((struct loop *));
|
||||
extern int average_num_loop_insns PARAMS ((struct loop *));
|
||||
|
||||
/* Loops & cfg manipulation. */
|
||||
extern basic_block *get_loop_body PARAMS ((const struct loop *));
|
||||
|
||||
extern edge loop_preheader_edge PARAMS ((const struct loop *));
|
||||
extern edge loop_latch_edge PARAMS ((const struct loop *));
|
||||
|
||||
extern void add_bb_to_loop PARAMS ((basic_block, struct loop *));
|
||||
extern void remove_bb_from_loops PARAMS ((basic_block));
|
||||
|
||||
extern void cancel_loop PARAMS ((struct loops *, struct loop *));
|
||||
extern void cancel_loop_tree PARAMS ((struct loops *, struct loop *));
|
||||
|
||||
extern basic_block loop_split_edge_with PARAMS ((edge, rtx, struct loops *));
|
||||
|
||||
enum
|
||||
{
|
||||
CP_SIMPLE_PREHEADERS = 1,
|
||||
CP_INSIDE_CFGLAYOUT = 2
|
||||
};
|
||||
|
||||
extern void create_preheaders PARAMS ((struct loops *, int));
|
||||
extern void force_single_succ_latches PARAMS ((struct loops *));
|
||||
|
||||
extern void verify_loop_structure PARAMS ((struct loops *));
|
||||
|
||||
/* Loop analysis. */
|
||||
extern bool simple_loop_p PARAMS ((struct loops *, struct loop *,
|
||||
struct loop_desc *));
|
||||
extern rtx count_loop_iterations PARAMS ((struct loop_desc *, rtx, rtx));
|
||||
extern bool just_once_each_iteration_p PARAMS ((struct loops *,struct loop *,
|
||||
basic_block));
|
||||
extern unsigned expected_loop_iterations PARAMS ((const struct loop *));
|
1097
gcc/cfgloopanal.c
Normal file
1097
gcc/cfgloopanal.c
Normal file
File diff suppressed because it is too large
Load Diff
226
gcc/cfgloopmanip.c
Normal file
226
gcc/cfgloopmanip.c
Normal file
@ -0,0 +1,226 @@
|
||||
/* Loop manipulation code for GNU compiler.
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING. If not, write to the Free
|
||||
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tm.h"
|
||||
#include "rtl.h"
|
||||
#include "hard-reg-set.h"
|
||||
#include "basic-block.h"
|
||||
#include "cfgloop.h"
|
||||
#include "cfglayout.h"
|
||||
#include "output.h"
|
||||
|
||||
static basic_block create_preheader PARAMS ((struct loop *, dominance_info,
|
||||
int));
|
||||
|
||||
/* Creates a pre-header for a LOOP. Returns newly created block. Unless
|
||||
CP_SIMPLE_PREHEADERS is set in FLAGS, we only force LOOP to have single
|
||||
entry; otherwise we also force preheader block to have only one successor.
|
||||
*/
|
||||
static basic_block
|
||||
create_preheader (loop, dom, flags)
|
||||
struct loop *loop;
|
||||
dominance_info dom;
|
||||
int flags;
|
||||
{
|
||||
edge e, fallthru;
|
||||
basic_block dummy;
|
||||
basic_block jump, src;
|
||||
struct loop *cloop, *ploop;
|
||||
int nentry = 0;
|
||||
rtx insn;
|
||||
|
||||
cloop = loop->outer;
|
||||
|
||||
for (e = loop->header->pred; e; e = e->pred_next)
|
||||
{
|
||||
if (e->src == loop->latch)
|
||||
continue;
|
||||
nentry++;
|
||||
}
|
||||
if (!nentry)
|
||||
abort ();
|
||||
if (nentry == 1)
|
||||
{
|
||||
for (e = loop->header->pred; e->src == loop->latch; e = e->pred_next);
|
||||
if (!(flags & CP_SIMPLE_PREHEADERS)
|
||||
|| !e->src->succ->succ_next)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
insn = first_insn_after_basic_block_note (loop->header);
|
||||
if (insn)
|
||||
insn = PREV_INSN (insn);
|
||||
else
|
||||
insn = get_last_insn ();
|
||||
if (insn == loop->header->end)
|
||||
{
|
||||
/* Split_block would not split block after its end. */
|
||||
emit_note_after (NOTE_INSN_DELETED, insn);
|
||||
}
|
||||
if (flags & CP_INSIDE_CFGLAYOUT)
|
||||
fallthru = cfg_layout_split_block (loop->header, insn);
|
||||
else
|
||||
fallthru = split_block (loop->header, insn);
|
||||
dummy = fallthru->src;
|
||||
loop->header = fallthru->dest;
|
||||
|
||||
/* The header could be a latch of some superloop(s); due to design of
|
||||
split_block, it would now move to fallthru->dest. */
|
||||
for (ploop = loop; ploop; ploop = ploop->outer)
|
||||
if (ploop->latch == dummy)
|
||||
ploop->latch = fallthru->dest;
|
||||
|
||||
add_to_dominance_info (dom, fallthru->dest);
|
||||
|
||||
/* Redirect edges. */
|
||||
for (e = dummy->pred; e; e = e->pred_next)
|
||||
{
|
||||
src = e->src;
|
||||
if (src == loop->latch)
|
||||
break;
|
||||
}
|
||||
if (!e)
|
||||
abort ();
|
||||
|
||||
dummy->frequency -= EDGE_FREQUENCY (e);
|
||||
dummy->count -= e->count;
|
||||
fallthru->count -= e->count;
|
||||
if (flags & CP_INSIDE_CFGLAYOUT)
|
||||
cfg_layout_redirect_edge (e, loop->header);
|
||||
else
|
||||
{
|
||||
jump = redirect_edge_and_branch_force (e, loop->header);
|
||||
if (jump)
|
||||
{
|
||||
add_to_dominance_info (dom, jump);
|
||||
set_immediate_dominator (dom, jump, src);
|
||||
add_bb_to_loop (jump, loop);
|
||||
loop->latch = jump;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update structures. */
|
||||
redirect_immediate_dominators (dom, dummy, loop->header);
|
||||
set_immediate_dominator (dom, loop->header, dummy);
|
||||
loop->header->loop_father = loop;
|
||||
add_bb_to_loop (dummy, cloop);
|
||||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "Created preheader block for loop %i\n",
|
||||
loop->num);
|
||||
|
||||
return dummy;
|
||||
}
|
||||
|
||||
/* Create preheaders for each loop; for meaning of flags see
|
||||
create_preheader. */
|
||||
void
|
||||
create_preheaders (loops, flags)
|
||||
struct loops *loops;
|
||||
int flags;
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 1; i < loops->num; i++)
|
||||
create_preheader (loops->parray[i], loops->cfg.dom, flags);
|
||||
loops->state |= LOOPS_HAVE_PREHEADERS;
|
||||
}
|
||||
|
||||
/* Forces all loop latches to have only single successor. */
|
||||
void
|
||||
force_single_succ_latches (loops)
|
||||
struct loops *loops;
|
||||
{
|
||||
unsigned i;
|
||||
struct loop *loop;
|
||||
edge e;
|
||||
|
||||
for (i = 1; i < loops->num; i++)
|
||||
{
|
||||
loop = loops->parray[i];
|
||||
if (!loop->latch->succ->succ_next)
|
||||
continue;
|
||||
|
||||
for (e = loop->header->pred; e->src != loop->latch; e = e->pred_next);
|
||||
loop_split_edge_with (e, NULL_RTX, loops);
|
||||
}
|
||||
loops->state |= LOOPS_HAVE_SIMPLE_LATCHES;
|
||||
}
|
||||
|
||||
/* A quite stupid function to put INSNS on E. They are supposed to form
|
||||
just one basic block. Jumps out are not handled, so cfg do not have to
|
||||
be ok after this function. */
|
||||
basic_block
|
||||
loop_split_edge_with (e, insns, loops)
|
||||
edge e;
|
||||
rtx insns;
|
||||
struct loops *loops;
|
||||
{
|
||||
basic_block src, dest, new_bb;
|
||||
struct loop *loop_c;
|
||||
edge new_e;
|
||||
|
||||
src = e->src;
|
||||
dest = e->dest;
|
||||
|
||||
loop_c = find_common_loop (src->loop_father, dest->loop_father);
|
||||
|
||||
/* Create basic block for it. */
|
||||
|
||||
new_bb = create_basic_block (NULL_RTX, NULL_RTX, EXIT_BLOCK_PTR->prev_bb);
|
||||
add_to_dominance_info (loops->cfg.dom, new_bb);
|
||||
add_bb_to_loop (new_bb, loop_c);
|
||||
new_bb->flags = insns ? BB_SUPERBLOCK : 0;
|
||||
if (src->flags & BB_IRREDUCIBLE_LOOP)
|
||||
{
|
||||
/* We expect simple preheaders here. */
|
||||
if ((dest->flags & BB_IRREDUCIBLE_LOOP)
|
||||
|| dest->loop_father->header == dest)
|
||||
new_bb->flags |= BB_IRREDUCIBLE_LOOP;
|
||||
}
|
||||
|
||||
new_e = make_edge (new_bb, dest, EDGE_FALLTHRU);
|
||||
new_e->probability = REG_BR_PROB_BASE;
|
||||
new_e->count = e->count;
|
||||
|
||||
new_bb->count = e->count;
|
||||
new_bb->frequency = EDGE_FREQUENCY (e);
|
||||
cfg_layout_redirect_edge (e, new_bb);
|
||||
|
||||
alloc_aux_for_block (new_bb, sizeof (struct reorder_block_def));
|
||||
if (insns)
|
||||
{
|
||||
start_sequence ();
|
||||
emit_insn (insns);
|
||||
insns = get_insns ();
|
||||
end_sequence ();
|
||||
emit_insn_after (insns, new_bb->end);
|
||||
}
|
||||
|
||||
set_immediate_dominator (loops->cfg.dom, new_bb, src);
|
||||
set_immediate_dominator (loops->cfg.dom, dest,
|
||||
recount_dominator (loops->cfg.dom, dest));
|
||||
|
||||
if (dest->loop_father->latch == src)
|
||||
dest->loop_father->latch = new_bb;
|
||||
|
||||
return new_bb;
|
||||
}
|
@ -31,6 +31,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "basic-block.h"
|
||||
#include "toplev.h"
|
||||
#include "tm_p.h"
|
||||
#include "cfgloop.h"
|
||||
|
||||
|
||||
/* This module is used to modify loops with a determinable number of
|
||||
|
@ -56,6 +56,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "predict.h"
|
||||
#include "insn-flags.h"
|
||||
#include "optabs.h"
|
||||
#include "cfgloop.h"
|
||||
|
||||
/* Not really meaningful values, but at least something. */
|
||||
#ifndef SIMULTANEOUS_PREFETCHES
|
||||
@ -495,7 +496,7 @@ loop_optimize (f, dumpfile, flags)
|
||||
|
||||
/* Allocate and initialize auxiliary loop information. */
|
||||
loops_info = xcalloc (loops->num, sizeof (struct loop_info));
|
||||
for (i = 0; i < loops->num; i++)
|
||||
for (i = 0; i < (int) loops->num; i++)
|
||||
loops->array[i].aux = loops_info + i;
|
||||
|
||||
/* Now find all register lifetimes. This must be done after
|
||||
|
@ -52,6 +52,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "params.h"
|
||||
#include "target.h"
|
||||
#include "loop.h"
|
||||
#include "cfgloop.h"
|
||||
|
||||
/* real constants: 0, 1, 1-1/REG_BR_PROB_BASE, REG_BR_PROB_BASE,
|
||||
1/REG_BR_PROB_BASE, 0.5, BB_FREQ_MAX. */
|
||||
@ -425,7 +426,7 @@ estimate_probability (loops_info)
|
||||
{
|
||||
dominance_info dominators, post_dominators;
|
||||
basic_block bb;
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
connect_infinite_loops_to_exit ();
|
||||
dominators = calculate_dominance_info (CDI_DOMINATORS);
|
||||
@ -436,13 +437,28 @@ estimate_probability (loops_info)
|
||||
for (i = 1; i < loops_info->num; i++)
|
||||
{
|
||||
basic_block bb, *bbs;
|
||||
int j;
|
||||
unsigned j;
|
||||
int exits;
|
||||
struct loop *loop = loops_info->parray[i];
|
||||
struct loop_desc desc;
|
||||
unsigned HOST_WIDE_INT niter;
|
||||
|
||||
flow_loop_scan (loops_info, loop, LOOP_EXIT_EDGES);
|
||||
exits = loop->num_exits;
|
||||
|
||||
if (simple_loop_p (loops_info, loop, &desc)
|
||||
&& desc.const_iter)
|
||||
{
|
||||
niter = desc.niter + 1;
|
||||
if (niter == 0) /* We might overflow here. */
|
||||
niter = desc.niter;
|
||||
|
||||
predict_edge (desc.in_edge, PRED_LOOP_ITERATIONS,
|
||||
REG_BR_PROB_BASE
|
||||
- (REG_BR_PROB_BASE + niter /2)
|
||||
/ niter);
|
||||
}
|
||||
|
||||
bbs = get_loop_body (loop);
|
||||
for (j = 0; j < loop->num_nodes; j++)
|
||||
{
|
||||
@ -1060,7 +1076,7 @@ estimate_loops_at_level (first_loop)
|
||||
{
|
||||
edge e;
|
||||
basic_block *bbs;
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
estimate_loops_at_level (loop->inner);
|
||||
|
||||
|
@ -73,6 +73,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "target.h"
|
||||
#include "langhooks.h"
|
||||
#include "cfglayout.h"
|
||||
#include "cfgloop.h"
|
||||
|
||||
#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
|
||||
#include "dwarf2out.h"
|
||||
|
@ -366,7 +366,7 @@ tracer ()
|
||||
{
|
||||
if (n_basic_blocks <= 1)
|
||||
return;
|
||||
cfg_layout_initialize ();
|
||||
cfg_layout_initialize (NULL);
|
||||
mark_dfs_back_edges ();
|
||||
if (rtl_dump_file)
|
||||
dump_flow_info (rtl_dump_file);
|
||||
|
@ -150,6 +150,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "basic-block.h"
|
||||
#include "predict.h"
|
||||
#include "params.h"
|
||||
#include "cfgloop.h"
|
||||
|
||||
/* The prime factors looked for when trying to unroll a loop by some
|
||||
number which is modulo the total number of iterations. Just checking
|
||||
|
Loading…
Reference in New Issue
Block a user