loop.h (precondition_loop_p): Added new mode argument.
* loop.h (precondition_loop_p): Added new mode argument. * unroll.c (precondition_loop_p): Likewise. (approx_final_value): Function deleted and subsumed into loop_iterations. (loop_find_equiv_value): New function. (loop_iterations): Use loop_find_equiv_value to find increments too large to be immediate constants. Also use it to find terms common to initial and final iteration values that can be removed. From-SVN: r23885
This commit is contained in:
parent
302670f3f0
commit
e96b4d7a44
@ -1,3 +1,15 @@
|
||||
Thu Nov 26 18:26:21 1998 Michael Hayes <m.hayes@elec.canterbury.ac.nz>
|
||||
|
||||
* loop.h (precondition_loop_p): Added new mode argument.
|
||||
* unroll.c (precondition_loop_p): Likewise.
|
||||
(approx_final_value): Function deleted and subsumed
|
||||
into loop_iterations.
|
||||
(loop_find_equiv_value): New function.
|
||||
(loop_iterations): Use loop_find_equiv_value to find increments
|
||||
too large to be immediate constants. Also use it to find terms
|
||||
common to initial and final iteration values that can be removed.
|
||||
|
||||
|
||||
Thu Nov 26 18:05:04 1998 Michael Hayes <m.hayes@elec.canterbury.ac.nz>
|
||||
|
||||
* loop.h (struct loop_info): Define new structure.
|
||||
|
@ -215,7 +215,8 @@ void unroll_loop PROTO((rtx, int, rtx, rtx, struct loop_info *, int));
|
||||
rtx biv_total_increment PROTO((struct iv_class *, rtx, rtx));
|
||||
unsigned HOST_WIDE_INT loop_iterations PROTO((rtx, rtx, struct loop_info *));
|
||||
int precondition_loop_p PROTO((rtx, struct loop_info *,
|
||||
rtx *, rtx *, rtx *));
|
||||
rtx *, rtx *, rtx *,
|
||||
enum machine_mode *mode));
|
||||
rtx final_biv_value PROTO((struct iv_class *, rtx, rtx,
|
||||
unsigned HOST_WIDE_INT));
|
||||
rtx final_giv_value PROTO((struct induction *, rtx, rtx,
|
||||
|
424
gcc/unroll.c
424
gcc/unroll.c
@ -195,7 +195,6 @@ static void final_reg_note_copy PROTO((rtx, struct inline_remap *));
|
||||
static void copy_loop_body PROTO((rtx, rtx, struct inline_remap *, rtx, int,
|
||||
enum unroll_types, rtx, rtx, rtx, rtx));
|
||||
void iteration_info PROTO((rtx, rtx *, rtx *, rtx, rtx));
|
||||
static rtx approx_final_value PROTO((enum rtx_code, rtx, int *, int *));
|
||||
static int find_splittable_regs PROTO((enum unroll_types, rtx, rtx, rtx, int,
|
||||
unsigned HOST_WIDE_INT));
|
||||
static int find_splittable_givs PROTO((struct iv_class *, enum unroll_types,
|
||||
@ -849,12 +848,13 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
|
||||
if (unroll_type == UNROLL_NAIVE && ! splitting_not_safe && strength_reduce_p)
|
||||
{
|
||||
rtx initial_value, final_value, increment;
|
||||
enum machine_mode mode;
|
||||
|
||||
if (precondition_loop_p (loop_start, loop_info,
|
||||
&initial_value, &final_value, &increment))
|
||||
&initial_value, &final_value, &increment,
|
||||
&mode))
|
||||
{
|
||||
register rtx diff ;
|
||||
enum machine_mode mode;
|
||||
rtx *labels;
|
||||
int abs_inc, neg_inc;
|
||||
|
||||
@ -886,21 +886,6 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
|
||||
|
||||
start_sequence ();
|
||||
|
||||
/* Decide what mode to do these calculations in. Choose the larger
|
||||
of final_value's mode and initial_value's mode, or a full-word if
|
||||
both are constants. */
|
||||
mode = GET_MODE (final_value);
|
||||
if (mode == VOIDmode)
|
||||
{
|
||||
mode = GET_MODE (initial_value);
|
||||
if (mode == VOIDmode)
|
||||
mode = word_mode;
|
||||
}
|
||||
else if (mode != GET_MODE (initial_value)
|
||||
&& (GET_MODE_SIZE (mode)
|
||||
< GET_MODE_SIZE (GET_MODE (initial_value))))
|
||||
mode = GET_MODE (initial_value);
|
||||
|
||||
/* Calculate the difference between the final and initial values.
|
||||
Final value may be a (plus (reg x) (const_int 1)) rtx.
|
||||
Let the following cse pass simplify this if initial value is
|
||||
@ -1314,10 +1299,11 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
|
||||
|
||||
int
|
||||
precondition_loop_p (loop_start, loop_info,
|
||||
initial_value, final_value, increment)
|
||||
initial_value, final_value, increment, mode)
|
||||
rtx loop_start;
|
||||
struct loop_info *loop_info;
|
||||
rtx *initial_value, *final_value, *increment;
|
||||
enum machine_mode *mode;
|
||||
{
|
||||
|
||||
if (loop_info->n_iterations > 0)
|
||||
@ -1325,6 +1311,7 @@ precondition_loop_p (loop_start, loop_info,
|
||||
*initial_value = const0_rtx;
|
||||
*increment = const1_rtx;
|
||||
*final_value = GEN_INT (loop_info->n_iterations);
|
||||
*mode = word_mode;
|
||||
|
||||
if (loop_dump_stream)
|
||||
{
|
||||
@ -1430,6 +1417,21 @@ precondition_loop_p (loop_start, loop_info,
|
||||
*increment = loop_info->increment;
|
||||
*final_value = loop_info->final_value;
|
||||
|
||||
/* Decide what mode to do these calculations in. Choose the larger
|
||||
of final_value's mode and initial_value's mode, or a full-word if
|
||||
both are constants. */
|
||||
*mode = GET_MODE (*final_value);
|
||||
if (*mode == VOIDmode)
|
||||
{
|
||||
*mode = GET_MODE (*initial_value);
|
||||
if (*mode == VOIDmode)
|
||||
*mode = word_mode;
|
||||
}
|
||||
else if (*mode != GET_MODE (*initial_value)
|
||||
&& (GET_MODE_SIZE (*mode)
|
||||
< GET_MODE_SIZE (GET_MODE (*initial_value))))
|
||||
*mode = GET_MODE (*initial_value);
|
||||
|
||||
/* Success! */
|
||||
if (loop_dump_stream)
|
||||
fprintf (loop_dump_stream, "Preconditioning: Successful.\n");
|
||||
@ -2421,60 +2423,6 @@ iteration_info (iteration_var, initial_value, increment, loop_start, loop_end)
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate the approximate final value of the iteration variable
|
||||
which has an loop exit test with code COMPARISON_CODE and comparison value
|
||||
of COMPARISON_VALUE. Also returns an indication of whether the comparison
|
||||
was signed or unsigned, and the direction of the comparison. This info is
|
||||
needed to calculate the number of loop iterations. */
|
||||
|
||||
static rtx
|
||||
approx_final_value (comparison_code, comparison_value, unsigned_p, compare_dir)
|
||||
enum rtx_code comparison_code;
|
||||
rtx comparison_value;
|
||||
int *unsigned_p;
|
||||
int *compare_dir;
|
||||
{
|
||||
/* Calculate the final value of the induction variable.
|
||||
The exact final value depends on the branch operator, and increment sign.
|
||||
This is only an approximate value. It will be wrong if the iteration
|
||||
variable is not incremented by one each time through the loop, and
|
||||
approx final value - start value % increment != 0. */
|
||||
|
||||
*unsigned_p = 0;
|
||||
switch (comparison_code)
|
||||
{
|
||||
case LEU:
|
||||
*unsigned_p = 1;
|
||||
case LE:
|
||||
*compare_dir = 1;
|
||||
return plus_constant (comparison_value, 1);
|
||||
case GEU:
|
||||
*unsigned_p = 1;
|
||||
case GE:
|
||||
*compare_dir = -1;
|
||||
return plus_constant (comparison_value, -1);
|
||||
case EQ:
|
||||
/* Can not calculate a final value for this case. */
|
||||
*compare_dir = 0;
|
||||
return 0;
|
||||
case LTU:
|
||||
*unsigned_p = 1;
|
||||
case LT:
|
||||
*compare_dir = 1;
|
||||
return comparison_value;
|
||||
break;
|
||||
case GTU:
|
||||
*unsigned_p = 1;
|
||||
case GT:
|
||||
*compare_dir = -1;
|
||||
return comparison_value;
|
||||
case NE:
|
||||
*compare_dir = 0;
|
||||
return comparison_value;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
/* For each biv and giv, determine whether it can be safely split into
|
||||
a different variable for each unrolled copy of the loop body. If it
|
||||
@ -3398,6 +3346,51 @@ final_giv_value (v, loop_start, loop_end, n_iterations)
|
||||
}
|
||||
|
||||
|
||||
/* Look back before LOOP_START for then insn that sets REG and return
|
||||
the equivalent constant if there is a REG_EQUAL note otherwise just
|
||||
the SET_SRC of REG. */
|
||||
|
||||
static rtx
|
||||
loop_find_equiv_value (loop_start, reg)
|
||||
rtx loop_start;
|
||||
rtx reg;
|
||||
{
|
||||
rtx insn, set;
|
||||
rtx ret;
|
||||
|
||||
ret = reg;
|
||||
for (insn = PREV_INSN (loop_start); insn ; insn = PREV_INSN (insn))
|
||||
{
|
||||
if (GET_CODE (insn) == CODE_LABEL)
|
||||
break;
|
||||
|
||||
else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
|
||||
&& reg_set_p (reg, insn))
|
||||
{
|
||||
/* We found the last insn before the loop that sets the register.
|
||||
If it sets the entire register, and has a REG_EQUAL note,
|
||||
then use the value of the REG_EQUAL note. */
|
||||
if ((set = single_set (insn))
|
||||
&& (SET_DEST (set) == reg))
|
||||
{
|
||||
rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
|
||||
|
||||
/* Only use the REG_EQUAL note if it is a constant.
|
||||
Other things, divide in particular, will cause
|
||||
problems later if we use them. */
|
||||
if (note && GET_CODE (XEXP (note, 0)) != EXPR_LIST
|
||||
&& CONSTANT_P (XEXP (note, 0)))
|
||||
ret = XEXP (note, 0);
|
||||
else
|
||||
ret = SET_SRC (set);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Calculate the number of loop iterations. Returns the exact number of loop
|
||||
iterations if it can be calculated, otherwise returns zero. */
|
||||
|
||||
@ -3409,23 +3402,28 @@ loop_iterations (loop_start, loop_end, loop_info)
|
||||
rtx comparison, comparison_value;
|
||||
rtx iteration_var, initial_value, increment, final_value;
|
||||
enum rtx_code comparison_code;
|
||||
HOST_WIDE_INT i;
|
||||
HOST_WIDE_INT abs_inc;
|
||||
unsigned HOST_WIDE_INT abs_diff;
|
||||
int off_by_one;
|
||||
int increment_dir;
|
||||
int unsigned_compare, compare_dir, final_larger;
|
||||
unsigned long tempu;
|
||||
int unsigned_p, compare_dir, final_larger;
|
||||
rtx last_loop_insn;
|
||||
|
||||
loop_info->n_iterations = 0;
|
||||
loop_info->initial_value = 0;
|
||||
loop_info->initial_equiv_value = 0;
|
||||
loop_info->comparison_value = 0;
|
||||
loop_info->final_value = 0;
|
||||
loop_info->final_equiv_value = 0;
|
||||
loop_info->increment = 0;
|
||||
loop_info->iteration_var = 0;
|
||||
loop_info->unroll_number = 1;
|
||||
|
||||
/* First find the iteration variable. If the last insn is a conditional
|
||||
branch, and the insn before tests a register value, make that the
|
||||
iteration variable. */
|
||||
|
||||
loop_info->initial_value = 0;
|
||||
loop_info->increment = 0;
|
||||
loop_info->final_value = 0;
|
||||
loop_info->iteration_var = 0;
|
||||
loop_info->unroll_number = 2;
|
||||
|
||||
/* We used to use pren_nonnote_insn here, but that fails because it might
|
||||
/* We used to use prev_nonnote_insn here, but that fails because it might
|
||||
accidentally get the branch for a contained loop if the branch for this
|
||||
loop was deleted. We can only trust branches immediately before the
|
||||
loop_end. */
|
||||
@ -3436,7 +3434,7 @@ loop_iterations (loop_start, loop_end, loop_info)
|
||||
{
|
||||
if (loop_dump_stream)
|
||||
fprintf (loop_dump_stream,
|
||||
"Loop unrolling: No final conditional branch found.\n");
|
||||
"Loop iterations: No final conditional branch found.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3451,7 +3449,7 @@ loop_iterations (loop_start, loop_end, loop_info)
|
||||
{
|
||||
if (loop_dump_stream)
|
||||
fprintf (loop_dump_stream,
|
||||
"Loop unrolling: Comparison not against register.\n");
|
||||
"Loop iterations: Comparison not against register.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3467,102 +3465,201 @@ loop_iterations (loop_start, loop_end, loop_info)
|
||||
/* iteration_info already printed a message. */
|
||||
return 0;
|
||||
|
||||
unsigned_p = 0;
|
||||
off_by_one = 0;
|
||||
switch (comparison_code)
|
||||
{
|
||||
case LEU:
|
||||
unsigned_p = 1;
|
||||
case LE:
|
||||
compare_dir = 1;
|
||||
off_by_one = 1;
|
||||
break;
|
||||
case GEU:
|
||||
unsigned_p = 1;
|
||||
case GE:
|
||||
compare_dir = -1;
|
||||
off_by_one = -1;
|
||||
break;
|
||||
case EQ:
|
||||
/* Cannot determine loop iterations with this case. */
|
||||
compare_dir = 0;
|
||||
break;
|
||||
case LTU:
|
||||
unsigned_p = 1;
|
||||
case LT:
|
||||
compare_dir = 1;
|
||||
break;
|
||||
case GTU:
|
||||
unsigned_p = 1;
|
||||
case GT:
|
||||
compare_dir = -1;
|
||||
case NE:
|
||||
compare_dir = 0;
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* If the comparison value is an invariant register, then try to find
|
||||
its value from the insns before the start of the loop. */
|
||||
|
||||
final_value = comparison_value;
|
||||
if (GET_CODE (comparison_value) == REG && invariant_p (comparison_value))
|
||||
{
|
||||
rtx insn, set;
|
||||
|
||||
for (insn = PREV_INSN (loop_start); insn ; insn = PREV_INSN (insn))
|
||||
{
|
||||
if (GET_CODE (insn) == CODE_LABEL)
|
||||
break;
|
||||
|
||||
else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
|
||||
&& reg_set_p (comparison_value, insn))
|
||||
{
|
||||
/* We found the last insn before the loop that sets the register.
|
||||
If it sets the entire register, and has a REG_EQUAL note,
|
||||
then use the value of the REG_EQUAL note. */
|
||||
if ((set = single_set (insn))
|
||||
&& (SET_DEST (set) == comparison_value))
|
||||
{
|
||||
rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
|
||||
|
||||
/* Only use the REG_EQUAL note if it is a constant.
|
||||
Other things, divide in particular, will cause
|
||||
problems later if we use them. */
|
||||
if (note && GET_CODE (XEXP (note, 0)) != EXPR_LIST
|
||||
&& CONSTANT_P (XEXP (note, 0)))
|
||||
comparison_value = XEXP (note, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
final_value = loop_find_equiv_value (loop_start, comparison_value);
|
||||
/* If we don't get an invariant final value, we are better
|
||||
off with the original register. */
|
||||
if (!invariant_p (final_value))
|
||||
final_value = comparison_value;
|
||||
}
|
||||
|
||||
final_value = approx_final_value (comparison_code, comparison_value,
|
||||
&unsigned_compare, &compare_dir);
|
||||
/* Calculate the approximate final value of the induction variable
|
||||
(on the last successful iteration). The exact final value
|
||||
depends on the branch operator, and increment sign. It will be
|
||||
wrong if the iteration variable is not incremented by one each
|
||||
time through the loop and (comparison_value + off_by_one -
|
||||
initial_value) % increment != 0.
|
||||
??? Note that the final_value may overflow and thus final_larger
|
||||
will be bogus. A potentially infinite loop will be classified
|
||||
as immediate, e.g. for (i = 0x7ffffff0; i <= 0x7fffffff; i++) */
|
||||
if (off_by_one)
|
||||
final_value = plus_constant (final_value, off_by_one);
|
||||
|
||||
/* Save the calculated values describing this loop's bounds, in case
|
||||
precondition_loop_p will need them later. These values can not be
|
||||
recalculated inside precondition_loop_p because strength reduction
|
||||
optimizations may obscure the loop's structure. */
|
||||
optimizations may obscure the loop's structure.
|
||||
|
||||
loop_info->iteration_var = iteration_var;
|
||||
These values are only required by precondition_loop_p and insert_bct
|
||||
whenever the number of iterations cannot be computed at compile time.
|
||||
Only the difference between final_value and initial_value is
|
||||
important. Note that final_value is only approximate. */
|
||||
loop_info->initial_value = initial_value;
|
||||
loop_info->comparison_value = comparison_value;
|
||||
loop_info->final_value = plus_constant (comparison_value, off_by_one);
|
||||
loop_info->increment = increment;
|
||||
loop_info->final_value = final_value;
|
||||
loop_info->iteration_var = iteration_var;
|
||||
loop_info->comparison_code = comparison_code;
|
||||
|
||||
if (REG_P (initial_value))
|
||||
{
|
||||
rtx temp = final_value;
|
||||
|
||||
/* initial_value = reg1, final_value = reg2 + const, where reg1
|
||||
!= reg2. Try to find what reg1 is equivalent to. Hopefully
|
||||
it will either be reg2 or reg2 plus a constant. */
|
||||
if (GET_CODE (temp) == PLUS)
|
||||
temp = XEXP (temp, 0);
|
||||
if (REG_P (temp) && REGNO (temp) != REGNO (initial_value))
|
||||
initial_value = loop_find_equiv_value (loop_start, initial_value);
|
||||
}
|
||||
|
||||
/* If have initial_value = reg + const1 and final_value = reg +
|
||||
const2, then replace initial_value with const1 and final_value
|
||||
with const2. This should be safe since we are protected by the
|
||||
initial comparison before entering the loop. */
|
||||
if ((GET_CODE (initial_value) == REG || GET_CODE (initial_value) == PLUS)
|
||||
&& (GET_CODE (final_value) == REG || GET_CODE (final_value) == PLUS))
|
||||
{
|
||||
rtx init_op0;
|
||||
rtx fini_op0;
|
||||
rtx init_op1;
|
||||
rtx fini_op1;
|
||||
|
||||
if (GET_CODE (initial_value) == PLUS)
|
||||
init_op1 = XEXP (initial_value, 1), init_op0 = XEXP (initial_value, 0);
|
||||
else
|
||||
init_op1 = const0_rtx, init_op0 = initial_value;
|
||||
|
||||
if (GET_CODE (final_value) == PLUS)
|
||||
fini_op1 = XEXP (final_value, 1), fini_op0 = XEXP (final_value, 0);
|
||||
else
|
||||
fini_op1 = const0_rtx, fini_op0 = final_value;
|
||||
|
||||
/* Remove register common factor if present. */
|
||||
if (REG_P (init_op0) && init_op0 == fini_op0)
|
||||
{
|
||||
initial_value = init_op1;
|
||||
final_value = fini_op1;
|
||||
}
|
||||
else if (REG_P (init_op0) && init_op0 == fini_op1)
|
||||
{
|
||||
initial_value = init_op1;
|
||||
final_value = fini_op0;
|
||||
}
|
||||
else if (REG_P (init_op1) && init_op1 == fini_op0)
|
||||
{
|
||||
initial_value = init_op0;
|
||||
final_value = fini_op1;
|
||||
}
|
||||
else if (REG_P (init_op1) && init_op1 == fini_op1)
|
||||
{
|
||||
initial_value = init_op0;
|
||||
final_value = fini_op0;
|
||||
}
|
||||
}
|
||||
loop_info->initial_equiv_value = initial_value;
|
||||
loop_info->final_equiv_value = final_value;
|
||||
|
||||
if (increment == 0)
|
||||
{
|
||||
if (loop_dump_stream)
|
||||
fprintf (loop_dump_stream,
|
||||
"Loop unrolling: Increment value can't be calculated.\n");
|
||||
"Loop iterations: Increment value can't be calculated.\n");
|
||||
return 0;
|
||||
}
|
||||
else if (GET_CODE (increment) != CONST_INT)
|
||||
|
||||
if (GET_CODE (increment) != CONST_INT)
|
||||
{
|
||||
increment = loop_find_equiv_value (loop_start, increment);
|
||||
|
||||
if (GET_CODE (increment) != CONST_INT)
|
||||
{
|
||||
if (loop_dump_stream)
|
||||
{
|
||||
fprintf (loop_dump_stream,
|
||||
"Loop iterations: Increment value not constant ");
|
||||
print_rtl (loop_dump_stream, increment);
|
||||
fprintf (loop_dump_stream, ".\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
loop_info->increment = increment;
|
||||
}
|
||||
|
||||
if (GET_CODE (initial_value) != CONST_INT)
|
||||
{
|
||||
if (loop_dump_stream)
|
||||
{
|
||||
fprintf (loop_dump_stream,
|
||||
"Loop iterations: Initial value not constant ");
|
||||
print_rtl (loop_dump_stream, initial_value);
|
||||
fprintf (loop_dump_stream, ".\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (comparison_code == EQ)
|
||||
{
|
||||
if (loop_dump_stream)
|
||||
fprintf (loop_dump_stream,
|
||||
"Loop unrolling: Increment value not constant.\n");
|
||||
return 0;
|
||||
}
|
||||
else if (GET_CODE (initial_value) != CONST_INT)
|
||||
{
|
||||
if (loop_dump_stream)
|
||||
fprintf (loop_dump_stream,
|
||||
"Loop unrolling: Initial value not constant.\n");
|
||||
return 0;
|
||||
}
|
||||
else if (final_value == 0)
|
||||
{
|
||||
if (loop_dump_stream)
|
||||
fprintf (loop_dump_stream,
|
||||
"Loop unrolling: EQ comparison loop.\n");
|
||||
"Loop iterations: EQ comparison loop.\n");
|
||||
return 0;
|
||||
}
|
||||
else if (GET_CODE (final_value) != CONST_INT)
|
||||
{
|
||||
if (loop_dump_stream)
|
||||
fprintf (loop_dump_stream,
|
||||
"Loop unrolling: Final value not constant.\n");
|
||||
{
|
||||
fprintf (loop_dump_stream,
|
||||
"Loop iterations: Final value not constant ");
|
||||
print_rtl (loop_dump_stream, final_value);
|
||||
fprintf (loop_dump_stream, ".\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ?? Final value and initial value do not have to be constants.
|
||||
Only their difference has to be constant. When the iteration variable
|
||||
is an array address, the final value and initial value might both
|
||||
be addresses with the same base but different constant offsets.
|
||||
Final value must be invariant for this to work.
|
||||
|
||||
To do this, need some way to find the values of registers which are
|
||||
invariant. */
|
||||
|
||||
/* Final_larger is 1 if final larger, 0 if they are equal, otherwise -1. */
|
||||
if (unsigned_compare)
|
||||
if (unsigned_p)
|
||||
final_larger
|
||||
= ((unsigned HOST_WIDE_INT) INTVAL (final_value)
|
||||
> (unsigned HOST_WIDE_INT) INTVAL (initial_value))
|
||||
@ -3614,35 +3711,40 @@ loop_iterations (loop_start, loop_end, loop_info)
|
||||
{
|
||||
if (loop_dump_stream)
|
||||
fprintf (loop_dump_stream,
|
||||
"Loop unrolling: Not normal loop.\n");
|
||||
"Loop iterations: Not normal loop.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calculate the number of iterations, final_value is only an approximation,
|
||||
so correct for that. Note that tempu and loop_info->n_iterations are
|
||||
so correct for that. Note that abs_diff and n_iterations are
|
||||
unsigned, because they can be as large as 2^n - 1. */
|
||||
|
||||
i = INTVAL (increment);
|
||||
if (i > 0)
|
||||
tempu = INTVAL (final_value) - INTVAL (initial_value);
|
||||
else if (i < 0)
|
||||
abs_inc = INTVAL (increment);
|
||||
if (abs_inc > 0)
|
||||
abs_diff = INTVAL (final_value) - INTVAL (initial_value);
|
||||
else if (abs_inc < 0)
|
||||
{
|
||||
tempu = INTVAL (initial_value) - INTVAL (final_value);
|
||||
i = -i;
|
||||
abs_diff = INTVAL (initial_value) - INTVAL (final_value);
|
||||
abs_inc = -abs_inc;
|
||||
}
|
||||
else
|
||||
abort ();
|
||||
|
||||
/* For NE tests, make sure that the iteration variable won't miss the
|
||||
final value. If tempu mod i is not zero, then the iteration variable
|
||||
will overflow before the loop exits, and we can not calculate the
|
||||
number of iterations. */
|
||||
if (compare_dir == 0 && (tempu % i) != 0)
|
||||
/* For NE tests, make sure that the iteration variable won't miss
|
||||
the final value. If abs_diff mod abs_incr is not zero, then the
|
||||
iteration variable will overflow before the loop exits, and we
|
||||
can not calculate the number of iterations. */
|
||||
if (compare_dir == 0 && (abs_diff % abs_inc) != 0)
|
||||
return 0;
|
||||
|
||||
return tempu / i + ((tempu % i) != 0);
|
||||
/* Note that the number of iterations could be calculated using
|
||||
(abs_diff + abs_inc - 1) / abs_inc, provided care was taken to
|
||||
handle potential overflow of the summation. */
|
||||
loop_info->n_iterations = abs_diff / abs_inc + ((abs_diff % abs_inc) != 0);
|
||||
return loop_info->n_iterations;
|
||||
}
|
||||
|
||||
|
||||
/* Replace uses of split bivs with their split pseudo register. This is
|
||||
for original instructions which remain after loop unrolling without
|
||||
copying. */
|
||||
|
Loading…
Reference in New Issue
Block a user