/* Perform doloop optimizations
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
Based on code by Michael P. Hayes (m.hayes@elec.canterbury.ac.nz)
This file is part of GCC.
basic_block *body = get_loop_body (loop), bb;
rtx insn;
unsigned i;
+ bool result = true;
/* Check for loops that may not terminate under special conditions. */
if (!desc->simple_p
enable count-register loops in this case. */
if (dump_file)
fprintf (dump_file, "Doloop: Possible infinite iteration case.\n");
- return false;
+ result = false;
+ goto cleanup;
}
for (i = 0; i < loop->num_nodes; i++)
{
/* A called function may clobber any special registers required for
low-overhead looping. */
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
{
if (dump_file)
fprintf (dump_file, "Doloop: Function call in loop.\n");
- return false;
+ result = false;
+ goto cleanup;
}
/* Some targets (eg, PPC) use the count register for branch on table
instructions. ??? This should be a target specific check. */
- if (GET_CODE (insn) == JUMP_INSN
+ if (JUMP_P (insn)
&& (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
|| GET_CODE (PATTERN (insn)) == ADDR_VEC))
{
if (dump_file)
fprintf (dump_file, "Doloop: Computed branch in the loop.\n");
- return false;
+ result = false;
+ goto cleanup;
}
}
}
+ result = true;
+
+cleanup:
free (body);
- return true;
+ return result;
}
/* Adds test of COND jumping to DEST to the end of BB. */
describes the loop, DESC describes the number of iterations of the
loop, and DOLOOP_INSN is the low-overhead looping insn to emit at the
end of the loop. CONDITION is the condition separated from the
- DOLOOP_SEQ. */
+ DOLOOP_SEQ. COUNT is the number of iterations of the LOOP. */
static void
doloop_modify (struct loop *loop, struct niter_desc *desc,
- rtx doloop_seq, rtx condition)
+ rtx doloop_seq, rtx condition, rtx count)
{
rtx counter_reg;
- rtx count, tmp, noloop = NULL_RTX;
+ rtx tmp, noloop = NULL_RTX;
rtx sequence;
rtx jump_insn;
rtx jump_label;
int nonneg = 0, irr;
bool increment_count;
basic_block loop_end = desc->out_edge->src;
+ enum machine_mode mode;
jump_insn = BB_END (loop_end);
counter_reg = XEXP (condition, 0);
if (GET_CODE (counter_reg) == PLUS)
counter_reg = XEXP (counter_reg, 0);
+ mode = GET_MODE (counter_reg);
- count = desc->niter_expr;
increment_count = false;
switch (GET_CODE (condition))
{
case NE:
/* Currently only NE tests against zero and one are supported. */
- if (XEXP (condition, 1) == const1_rtx)
+ noloop = XEXP (condition, 1);
+ if (noloop != const0_rtx)
{
+ gcc_assert (noloop == const1_rtx);
increment_count = true;
- noloop = const1_rtx;
}
- else if (XEXP (condition, 1) == const0_rtx)
- noloop = const0_rtx;
- else
- abort ();
break;
case GE:
/* Currently only GE tests against zero are supported. */
- if (XEXP (condition, 1) != const0_rtx)
- abort ();
+ gcc_assert (XEXP (condition, 1) == const0_rtx);
noloop = constm1_rtx;
Note that the maximum value loaded is iterations_max - 1. */
if (desc->niter_max
<= ((unsigned HOST_WIDEST_INT) 1
- << (GET_MODE_BITSIZE (GET_MODE (counter_reg)) - 1)))
+ << (GET_MODE_BITSIZE (mode) - 1)))
nonneg = 1;
break;
/* Abort if an invalid doloop pattern has been generated. */
default:
- abort ();
+ gcc_unreachable ();
}
if (increment_count)
- count = simplify_gen_binary (PLUS, desc->mode, count, const1_rtx);
+ count = simplify_gen_binary (PLUS, mode, count, const1_rtx);
/* Insert initialization of the count register into the loop header. */
start_sequence ();
if (desc->noloop_assumptions)
{
- rtx ass = desc->noloop_assumptions;
+ rtx ass = copy_rtx (desc->noloop_assumptions);
basic_block preheader = loop_preheader_edge (loop)->src;
basic_block set_zero
= loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX);
/* Expand the condition testing the assumptions and if it does not pass,
reset the count register to 0. */
add_test (XEXP (ass, 0), preheader, set_zero);
- preheader->succ->flags &= ~EDGE_FALLTHRU;
- cnt = preheader->succ->count;
- preheader->succ->probability = 0;
- preheader->succ->count = 0;
- irr = preheader->succ->flags & EDGE_IRREDUCIBLE_LOOP;
+ single_succ_edge (preheader)->flags &= ~EDGE_FALLTHRU;
+ cnt = single_succ_edge (preheader)->count;
+ single_succ_edge (preheader)->probability = 0;
+ single_succ_edge (preheader)->count = 0;
+ irr = single_succ_edge (preheader)->flags & EDGE_IRREDUCIBLE_LOOP;
te = make_edge (preheader, new_preheader, EDGE_FALLTHRU | irr);
te->probability = REG_BR_PROB_BASE;
te->count = cnt;
for (ass = XEXP (ass, 1); ass; ass = XEXP (ass, 1))
{
bb = loop_split_edge_with (te, NULL_RTX);
- te = bb->succ;
+ te = single_succ_edge (bb);
add_test (XEXP (ass, 0), bb, set_zero);
make_edge (bb, set_zero, irr);
}
{
enum machine_mode mode;
rtx doloop_seq, doloop_pat, doloop_reg;
- rtx iterations;
+ rtx iterations, count;
rtx iterations_max;
rtx start_label;
rtx condition;
unsigned level, est_niter;
struct niter_desc *desc;
+ unsigned word_mode_size;
+ unsigned HOST_WIDE_INT word_mode_max;
if (dump_file)
fprintf (dump_file, "Doloop: Processing loop %d.\n", loop->num);
return false;
}
+ count = copy_rtx (desc->niter_expr);
iterations = desc->const_iter ? desc->niter_expr : const0_rtx;
iterations_max = GEN_INT (desc->niter_max);
level = get_loop_level (loop) + 1;
doloop_reg = gen_reg_rtx (mode);
doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
GEN_INT (level), start_label);
- if (! doloop_seq && mode != word_mode)
+
+ word_mode_size = GET_MODE_BITSIZE (word_mode);
+ word_mode_max
+ = ((unsigned HOST_WIDE_INT) 1 << (word_mode_size - 1) << 1) - 1;
+ if (! doloop_seq
+ && mode != word_mode
+ /* Before trying mode different from the one in that # of iterations is
+ computed, we must be sure that the number of iterations fits into
+ the new mode. */
+ && (word_mode_size >= GET_MODE_BITSIZE (mode)
+ || desc->niter_max <= word_mode_max))
{
+ if (word_mode_size > GET_MODE_BITSIZE (mode))
+ {
+ count = simplify_gen_unary (ZERO_EXTEND, word_mode,
+ count, mode);
+ iterations = simplify_gen_unary (ZERO_EXTEND, word_mode,
+ iterations, mode);
+ iterations_max = simplify_gen_unary (ZERO_EXTEND, word_mode,
+ iterations_max, mode);
+ }
+ else
+ {
+ count = lowpart_subreg (word_mode, count, mode);
+ iterations = lowpart_subreg (word_mode, iterations, mode);
+ iterations_max = lowpart_subreg (word_mode, iterations_max, mode);
+ }
PUT_MODE (doloop_reg, word_mode);
doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
GEN_INT (level), start_label);
{
while (NEXT_INSN (doloop_pat) != NULL_RTX)
doloop_pat = NEXT_INSN (doloop_pat);
- if (GET_CODE (doloop_pat) == JUMP_INSN)
+ if (JUMP_P (doloop_pat))
doloop_pat = PATTERN (doloop_pat);
else
doloop_pat = NULL_RTX;
return false;
}
- doloop_modify (loop, desc, doloop_seq, condition);
+ doloop_modify (loop, desc, doloop_seq, condition, count);
return true;
}