Commit 50654f6c by Zdenek Dvorak Committed by Zdenek Dvorak

loop-iv.c: New file.

	* loop-iv.c: New file.
	* Makefile.in (loop-iv.o): New.
	* basic_block.h (FOR_BB_INSNS, FOR_BB_INSNS_REVERSE): New macros.
	* cfgloop.c (fill_sons_in_loop, get_loop_body_in_dom_order,
	num_loop_branches): New functions.
	* cfgloop.h (get_loop_body_in_dom_order, num_loop_branches,
	iv_analysis_loop_init, iv_get_reaching_def, iv_analyse, get_iv_value,
	find_simple_exit, iv_number_of_iterations, iv_analysis_done,
	get_simple_loop_desc, free_simple_loop_desc): Declare.
	(simple_loop_desc): New inline function.
	(struct rtx_iv, struct niter_desc): New.
	* cfgloopmanip.c (loopify): Specify semantics more precisely.
	* expr.c (force_operand): Handle subregs of expressions created by
	loop unroller.
	* loop-init.c (loop_optimizer_init, loop_optimizer_finalize): Move
	parts of the initialization to toplev.c
	* loop-unroll.c (loop_exit_at_end_p): New.
	(unroll_and_peel_loops): Call iv_analysis_done.
	(decide_peel_once_rolling, decide_peel_completely,
	decide_unroll_stupid, decide_unroll_constant_iterations,
	decide_unroll_runtime_iterations, decide_peel_simple,
	peel_loop_simple, unroll_loop_stupid, unroll_loop_constant_iterations,
	unroll_loop_runtime_iterations): Use new simple loop analysis.
	* loop-unswitch.c (compare_and_jump_seq): New.
	(may_unswitch_on_p): Renamed to ...
	(may_unswitch_on): Use new iv analysis.
	(reversed_condition): Export.
	(unswitch_single_loop, unswitch_loop): Use new iv analysis.
	* predict.c (estimate_probability): Use new simple loop analysis.
	* rtl.h (get_mode_bounds, reversed_condition,compare_and_jump_seq,
	canon_condition, simplify_using_condition): Declare.
	* stor-layout.c (get_mode_bounds): New.
	* toplev.c (rest_of_handle_loop2): Some parts of
	initialization/finalization moved here from loop-init.c.

From-SVN: r77951
parent cc7ce44e
2004-02-17 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
* loop-iv.c: New file.
* Makefile.in (loop-iv.o): New.
* basic_block.h (FOR_BB_INSNS, FOR_BB_INSNS_REVERSE): New macros.
* cfgloop.c (fill_sons_in_loop, get_loop_body_in_dom_order,
num_loop_branches): New functions.
* cfgloop.h (get_loop_body_in_dom_order, num_loop_branches,
iv_analysis_loop_init, iv_get_reaching_def, iv_analyse, get_iv_value,
find_simple_exit, iv_number_of_iterations, iv_analysis_done,
get_simple_loop_desc, free_simple_loop_desc): Declare.
(simple_loop_desc): New inline function.
(struct rtx_iv, struct niter_desc): New.
* cfgloopmanip.c (loopify): Specify semantics more precisely.
* expr.c (force_operand): Handle subregs of expressions created by
loop unroller.
* loop-init.c (loop_optimizer_init, loop_optimizer_finalize): Move
parts of the initialization to toplev.c
* loop-unroll.c (loop_exit_at_end_p): New.
(unroll_and_peel_loops): Call iv_analysis_done.
(decide_peel_once_rolling, decide_peel_completely,
decide_unroll_stupid, decide_unroll_constant_iterations,
decide_unroll_runtime_iterations, decide_peel_simple,
peel_loop_simple, unroll_loop_stupid, unroll_loop_constant_iterations,
unroll_loop_runtime_iterations): Use new simple loop analysis.
* loop-unswitch.c (compare_and_jump_seq): New.
(may_unswitch_on_p): Renamed to ...
(may_unswitch_on): Use new iv analysis.
(reversed_condition): Export.
(unswitch_single_loop, unswitch_loop): Use new iv analysis.
* predict.c (estimate_probability): Use new simple loop analysis.
* rtl.h (get_mode_bounds, reversed_condition,compare_and_jump_seq,
canon_condition, simplify_using_condition): Declare.
* stor-layout.c (get_mode_bounds): New.
* toplev.c (rest_of_handle_loop2): Some parts of
initialization/finalization moved here from loop-init.c.
2004-02-17 Kazu Hirata <kazu@cs.umass.edu>
* config/h8300/h8300.h (FIXED_REGISTERS): Add the soft frame
......
......@@ -848,7 +848,7 @@ OBJS-common = \
cfgloopanal.o cfgloopmanip.o loop-init.o loop-unswitch.o loop-unroll.o \
cfgrtl.o combine.o conflict.o convert.o coverage.o cse.o cselib.o \
dbxout.o debug.o df.o diagnostic.o dojump.o doloop.o dominance.o \
dwarf2asm.o dwarf2out.o emit-rtl.o except.o explow.o \
dwarf2asm.o dwarf2out.o emit-rtl.o except.o explow.o loop-iv.o \
expmed.o expr.o final.o flow.o fold-const.o function.o gcse.o \
genrtl.o ggc-common.o global.o graph.o gtype-desc.o \
haifa-sched.o hooks.o ifcvt.o insn-attrtab.o insn-emit.o insn-modes.o \
......@@ -1719,6 +1719,8 @@ cfgloop.o : cfgloop.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) coretypes.h $(TM_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) coretypes.h $(TM_H)
loop-iv.o : loop-iv.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(GGC_H) \
$(BASIC_BLOCK_H) hard-reg-set.h cfgloop.h $(EXPR_H) coretypes.h $(TM_H)
cfgloopmanip.o : cfgloopmanip.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
$(BASIC_BLOCK_H) hard-reg-set.h cfgloop.h cfglayout.h output.h coretypes.h $(TM_H)
loop-init.o : loop-init.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \
......
......@@ -288,6 +288,17 @@ extern varray_type basic_block_info;
#define FOR_EACH_BB_REVERSE(BB) \
FOR_BB_BETWEEN (BB, EXIT_BLOCK_PTR->prev_bb, ENTRY_BLOCK_PTR, prev_bb)
/* For iterating over insns in basic block. */
#define FOR_BB_INSNS(BB, INSN) \
for ((INSN) = BB_HEAD (BB); \
(INSN) != NEXT_INSN (BB_END (BB)); \
(INSN) = NEXT_INSN (INSN))
#define FOR_BB_INSNS_REVERSE(BB, INSN) \
for ((INSN) = BB_END (BB); \
(INSN) != PREV_INSN (BB_HEAD (BB)); \
(INSN) = PREV_INSN (INSN))
/* Cycles through _all_ basic blocks, even the fake ones (entry and
exit block). */
......
......@@ -959,6 +959,62 @@ get_loop_body (const struct loop *loop)
return tovisit;
}
/* Fills dominance descendants inside LOOP of the basic block BB into
array TOVISIT from index *TV. */
static void
fill_sons_in_loop (const struct loop *loop, basic_block bb,
basic_block *tovisit, int *tv)
{
basic_block son, postpone = NULL;
tovisit[(*tv)++] = bb;
for (son = first_dom_son (CDI_DOMINATORS, bb);
son;
son = next_dom_son (CDI_DOMINATORS, son))
{
if (!flow_bb_inside_loop_p (loop, son))
continue;
if (dominated_by_p (CDI_DOMINATORS, loop->latch, son))
{
postpone = son;
continue;
}
fill_sons_in_loop (loop, son, tovisit, tv);
}
if (postpone)
fill_sons_in_loop (loop, postpone, tovisit, tv);
}
/* Gets body of a LOOP (that must be different from the outermost loop)
sorted by dominance relation. Additionally, if a basic block s dominates
the latch, then only blocks dominated by s are be after it. */
basic_block *
get_loop_body_in_dom_order (const struct loop *loop)
{
basic_block *tovisit;
int tv;
if (!loop->num_nodes)
abort ();
tovisit = xcalloc (loop->num_nodes, sizeof (basic_block));
if (loop->latch == EXIT_BLOCK_PTR)
abort ();
tv = 0;
fill_sons_in_loop (loop, loop->header, tovisit, &tv);
if (tv != (int) loop->num_nodes)
abort ();
return tovisit;
}
/* Gets exit edges of a LOOP, returning their number in N_EDGES. */
edge *
get_loop_exit_edges (const struct loop *loop, unsigned int *n_edges)
......@@ -988,6 +1044,27 @@ get_loop_exit_edges (const struct loop *loop, unsigned int *n_edges)
return edges;
}
/* Counts the number of conditional branches inside LOOP. */
unsigned
num_loop_branches (const struct loop *loop)
{
unsigned i, n;
basic_block * body;
if (loop->latch == EXIT_BLOCK_PTR)
abort ();
body = get_loop_body (loop);
n = 0;
for (i = 0; i < loop->num_nodes; i++)
if (body[i]->succ && body[i]->succ->succ_next)
n++;
free (body);
return n;
}
/* Adds basic block BB to LOOP. */
void
add_bb_to_loop (basic_block bb, struct loop *loop)
......
......@@ -278,7 +278,9 @@ extern int average_num_loop_insns (struct loop *);
/* Loops & cfg manipulation. */
extern basic_block *get_loop_body (const struct loop *);
extern basic_block *get_loop_body_in_dom_order (const struct loop *);
extern edge *get_loop_exit_edges (const struct loop *, unsigned *);
extern unsigned num_loop_branches (const struct loop *);
extern edge loop_preheader_edge (const struct loop *);
extern edge loop_latch_edge (const struct loop *);
......@@ -322,6 +324,114 @@ extern void unloop (struct loops *, struct loop *);
extern bool remove_path (struct loops *, edge);
extern edge split_loop_bb (basic_block, rtx);
/* Induction variable analysis. */
/* The description of induction variable. The things are a bit complicated
due to need to handle subregs and extends. The value of the object described
by it can be obtained as follows (all computations are done in extend_mode):
Value in i-th iteration is
delta + mult * extend_{extend_mode} (subreg_{mode} (base + i * step)).
If first_special is true, the value in the first iteration is
delta + mult * base
If extend = NIL, first_special must be false, delta 0, mult 1 and value is
subreg_{mode} (base + i * step)
The get_iv_value function can be used to obtain these expressions.
??? Add a third mode field that would specify the mode in that inner
computation is done, which would enable it to be different from the
outer one? */
struct rtx_iv
{
/* Its base and step (mode of base and step is supposed to be extend_mode,
see the description above). */
rtx base, step;
/* The type of extend applied to it (SIGN_EXTEND, ZERO_EXTEND or NIL). */
enum rtx_code extend;
/* Operations applied in the extended mode. */
rtx delta, mult;
/* The mode it is extended to. */
enum machine_mode extend_mode;
/* The mode the variable iterates in. */
enum machine_mode mode;
/* Whether we have already filled the remaining fields. */
unsigned analysed : 1;
/* Whether the first iteration needs to be handled specially. */
unsigned first_special : 1;
};
/* This should replace struct loop_desc. We keep this just so that we are
able to compare the results. */
struct niter_desc
{
/* The edge out of the loop. */
edge out_edge;
/* The other edge leading from the condition. */
edge in_edge;
/* True if we are able to say anything about number of iterations of the
loop. */
bool simple_p;
/* True if the loop iterates the constant number of times. */
bool const_iter;
/* Number of iterations if constant. */
unsigned HOST_WIDEST_INT niter;
/* Upper bound on the number of iterations. */
unsigned HOST_WIDEST_INT niter_max;
/* Assumptions under that the rest of the information is valid. */
rtx assumptions;
/* Assumptions under that the loop ends before reaching the latch,
even if value of niter_expr says otherwise. */
rtx noloop_assumptions;
/* Condition under that the loop is infinite. */
rtx infinite;
/* Whether the comparison is signed. */
bool signed_p;
/* The mode in that niter_expr should be computed. */
enum machine_mode mode;
/* The number of iterations of the loop. */
rtx niter_expr;
};
extern void iv_analysis_loop_init (struct loop *);
extern rtx iv_get_reaching_def (rtx, rtx);
extern bool iv_analyse (rtx, rtx, struct rtx_iv *);
extern rtx get_iv_value (struct rtx_iv *, rtx);
extern void find_simple_exit (struct loop *, struct niter_desc *);
extern void iv_number_of_iterations (struct loop *, rtx, rtx,
struct niter_desc *);
extern void iv_analysis_done (void);
extern struct niter_desc *get_simple_loop_desc (struct loop *loop);
extern void free_simple_loop_desc (struct loop *loop);
static inline struct niter_desc *
simple_loop_desc (struct loop *loop)
{
return loop->aux;
}
/* Loop optimizer initialization. */
extern struct loops *loop_optimizer_init (FILE *);
extern void loop_optimizer_finalize (struct loops *, FILE *);
......
......@@ -480,11 +480,13 @@ scale_loop_frequencies (struct loop *loop, int num, int den)
accordingly. Everything between them plus LATCH_EDGE destination must
be dominated by HEADER_EDGE destination, and back-reachable from
LATCH_EDGE source. HEADER_EDGE is redirected to basic block SWITCH_BB,
SWITCH_BB->succ to original destination of LATCH_EDGE and
SWITCH_BB->succ->succ_next to original destination of HEADER_EDGE.
FALLTHRU_EDGE (SWITCH_BB) to original destination of HEADER_EDGE and
BRANCH_EDGE (SWITCH_BB) to original destination of LATCH_EDGE.
Returns newly created loop. */
struct loop *
loopify (struct loops *loops, edge latch_edge, edge header_edge, basic_block switch_bb)
loopify (struct loops *loops, edge latch_edge, edge header_edge,
basic_block switch_bb)
{
basic_block succ_bb = latch_edge->dest;
basic_block pred_bb = header_edge->src;
......@@ -509,13 +511,15 @@ loopify (struct loops *loops, edge latch_edge, edge header_edge, basic_block swi
/* Redirect edges. */
loop_redirect_edge (latch_edge, loop->header);
loop_redirect_edge (BRANCH_EDGE (switch_bb), succ_bb);
loop_redirect_edge (header_edge, switch_bb);
loop_redirect_edge (switch_bb->succ->succ_next, loop->header);
loop_redirect_edge (switch_bb->succ, succ_bb);
loop_redirect_edge (FALLTHRU_EDGE (switch_bb), loop->header);
/* Update dominators. */
set_immediate_dominator (CDI_DOMINATORS, switch_bb, pred_bb);
set_immediate_dominator (CDI_DOMINATORS, loop->header, switch_bb);
set_immediate_dominator (CDI_DOMINATORS, succ_bb, switch_bb);
/* Compute new loop. */
......
......@@ -5588,6 +5588,20 @@ force_operand (rtx value, rtx target)
rtx subtarget = get_subtarget (target);
enum rtx_code code = GET_CODE (value);
/* Check for subreg applied to an expression produced by loop optimizer. */
if (code == SUBREG
&& GET_CODE (SUBREG_REG (value)) != REG
&& GET_CODE (SUBREG_REG (value)) != MEM)
{
value = simplify_gen_subreg (GET_MODE (value),
force_reg (GET_MODE (SUBREG_REG (value)),
force_operand (SUBREG_REG (value),
NULL_RTX)),
GET_MODE (SUBREG_REG (value)),
SUBREG_BYTE (value));
code = GET_CODE (value);
}
/* Check for a PIC address load. */
if ((code == PLUS || code == MINUS)
&& XEXP (value, 0) == pic_offset_table_rtx
......
......@@ -36,9 +36,6 @@ loop_optimizer_init (FILE *dumpfile)
struct loops *loops = xcalloc (1, sizeof (struct loops));
edge e;
/* Initialize structures for layout changes. */
cfg_layout_initialize ();
/* Avoid annoying special cases of edges going to exit
block. */
for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
......@@ -49,18 +46,11 @@ loop_optimizer_init (FILE *dumpfile)
if (flow_loops_find (loops, LOOP_TREE) <= 1)
{
basic_block bb;
/* No loops. */
flow_loops_free (loops);
free_dominance_info (CDI_DOMINATORS);
free (loops);
/* Make chain. */
FOR_EACH_BB (bb)
if (bb->next_bb != EXIT_BLOCK_PTR)
bb->rbi->next = bb->next_bb;
cfg_layout_finalize ();
return NULL;
}
......@@ -94,13 +84,14 @@ loop_optimizer_init (FILE *dumpfile)
void
loop_optimizer_finalize (struct loops *loops, FILE *dumpfile)
{
basic_block bb;
unsigned i;
/* Finalize layout changes. */
/* Make chain. */
FOR_EACH_BB (bb)
if (bb->next_bb != EXIT_BLOCK_PTR)
bb->rbi->next = bb->next_bb;
if (!loops)
return;
for (i = 1; i < loops->num; i++)
if (loops->parray[i])
free_simple_loop_desc (loops->parray[i]);
/* Another dump. */
flow_loops_dump (loops, dumpfile, NULL, 1);
......@@ -110,9 +101,6 @@ loop_optimizer_finalize (struct loops *loops, FILE *dumpfile)
free_dominance_info (CDI_DOMINATORS);
free (loops);
/* Finalize changes. */
cfg_layout_finalize ();
/* Checking. */
#ifdef ENABLE_CHECKING
verify_flow_info ();
......
This diff is collapsed. Click to expand it.
......@@ -406,13 +406,16 @@ estimate_probability (struct loops *loops_info)
unsigned j;
int exits;
struct loop *loop = loops_info->parray[i];
struct loop_desc desc;
struct niter_desc desc;
unsigned HOST_WIDE_INT niter;
flow_loop_scan (loop, LOOP_EXIT_EDGES);
exits = loop->num_exits;
if (simple_loop_p (loop, &desc) && desc.const_iter)
iv_analysis_loop_init (loop);
find_simple_exit (loop, &desc);
if (desc.simple_p && desc.const_iter)
{
int prob;
niter = desc.niter + 1;
......@@ -472,6 +475,8 @@ estimate_probability (struct loops *loops_info)
free (bbs);
}
iv_analysis_done ();
/* Attempt to predict conditional jumps using a number of heuristics. */
FOR_EACH_BB (bb)
{
......
......@@ -2361,4 +2361,15 @@ extern void tracer (void);
/* In var-tracking.c */
extern void variable_tracking_main (void);
/* In stor-layout.c. */
extern void get_mode_bounds (enum machine_mode, int, rtx *, rtx *);
/* In loop-unswitch.c */
extern rtx reversed_condition (rtx);
extern rtx compare_and_jump_seq (rtx, rtx, enum rtx_code, rtx, int, rtx);
/* In loop-iv.c */
extern rtx canon_condition (rtx);
extern void simplify_using_condition (rtx, rtx *, struct bitmap_head_def *);
#endif /* ! GCC_RTL_H */
......@@ -2118,4 +2118,27 @@ get_best_mode (int bitsize, int bitpos, unsigned int align,
return mode;
}
/* Gets minimal and maximal values for MODE (signed or unsigned depending on
SIGN). */
void
get_mode_bounds (enum machine_mode mode, int sign, rtx *mmin, rtx *mmax)
{
int size = GET_MODE_BITSIZE (mode);
if (size > HOST_BITS_PER_WIDE_INT)
abort ();
if (sign)
{
*mmin = GEN_INT (-((unsigned HOST_WIDE_INT) 1 << (size - 1)));
*mmax = GEN_INT (((unsigned HOST_WIDE_INT) 1 << (size - 1)) - 1);
}
else
{
*mmin = const0_rtx;
*mmax = GEN_INT (((unsigned HOST_WIDE_INT) 1 << (size - 1) << 1) - 1);
}
}
#include "gt-stor-layout.h"
......@@ -3034,11 +3034,16 @@ static void
rest_of_handle_loop2 (tree decl, rtx insns)
{
struct loops *loops;
basic_block bb;
timevar_push (TV_LOOP);
open_dump_file (DFI_loop2, decl);
if (rtl_dump_file)
dump_flow_info (rtl_dump_file);
/* Initialize structures for layout changes. */
cfg_layout_initialize ();
loops = loop_optimizer_init (rtl_dump_file);
if (loops)
......@@ -3056,6 +3061,12 @@ rest_of_handle_loop2 (tree decl, rtx insns)
loop_optimizer_finalize (loops, rtl_dump_file);
}
/* Finalize layout changes. */
FOR_EACH_BB (bb)
if (bb->next_bb != EXIT_BLOCK_PTR)
bb->rbi->next = bb->next_bb;
cfg_layout_finalize ();
cleanup_cfg (CLEANUP_EXPENSIVE);
delete_trivially_dead_insns (insns, max_reg_num ());
reg_scan (insns, max_reg_num (), 0);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment