rtx, int));
static int reg_dead_after_loop PARAMS ((const struct loop *, rtx));
static rtx fold_rtx_mult_add PARAMS ((rtx, rtx, rtx, enum machine_mode));
-static int verify_addresses PARAMS ((struct induction *, rtx, int));
static rtx remap_split_bivs PARAMS ((struct loop *, rtx));
static rtx find_common_reg_term PARAMS ((rtx, rtx));
static rtx subtract_reg_term PARAMS ((rtx, rtx));
}
else if (loop_info->n_iterations > 0
/* Avoid overflow in the next expression. */
- && loop_info->n_iterations < MAX_UNROLLED_INSNS
- && loop_info->n_iterations * insn_count < MAX_UNROLLED_INSNS)
+ && loop_info->n_iterations < (unsigned) MAX_UNROLLED_INSNS
+ && loop_info->n_iterations * insn_count < (unsigned) MAX_UNROLLED_INSNS)
{
unroll_number = loop_info->n_iterations;
unroll_type = UNROLL_COMPLETELY;
for (i = 3; i >= 0; i--)
while (factors[i].count--)
{
- if (temp * factors[i].factor < MAX_UNROLLED_INSNS)
+ if (temp * factors[i].factor < (unsigned) MAX_UNROLLED_INSNS)
{
unroll_number *= factors[i].factor;
temp *= factors[i].factor;
/* Keep track of the unroll factor for the loop. */
loop_info->unroll_number = unroll_number;
+ /* And whether the loop has been preconditioned. */
+ loop_info->preconditioned = loop_preconditioned;
+
/* For each biv and giv, determine whether it can be safely split into
a different variable for each unrolled copy of the loop body.
We precalculate and save this info here, since computing it is
{
/* VTOP notes are valid only before the loop exit test.
If placed anywhere else, loop may generate bad code.
- There is no need to test for NOTE_INSN_LOOP_CONT notes
- here, since COPY_NOTES_FROM will be at most one or two (for cc0)
- instructions before the last insn in the loop, and if the
- end test is that short, there will be a VTOP note between
- the CONT note and the test. */
+ Although COPY_NOTES_FROM will be at most one or two (for cc0)
+ instructions before the last insn in the loop, COPY_NOTES_FROM
+ can be a NOTE_INSN_LOOP_CONT note if there is no VTOP note,
+ as in a do .. while loop. */
if (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK
- && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_VTOP)
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_VTOP
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_CONT)
emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
}
}
for (v = bl->biv; v; v = v->next_iv)
{
if (v->always_computable && v->mult_val == const1_rtx
- && ! v->maybe_multiple)
+ && ! v->maybe_multiple
+ && SCALAR_INT_MODE_P (v->mode))
result = fold_rtx_mult_add (result, const1_rtx, v->add_val, v->mode);
else
return 0;
return result;
}
-/* Return 1 if the first and last unrolled copy of the address giv V is valid
- for the instruction that is using it. Do not make any changes to that
- instruction. */
-
-static int
-verify_addresses (v, giv_inc, unroll_number)
- struct induction *v;
- rtx giv_inc;
- int unroll_number;
-{
- int ret = 1;
- rtx orig_addr = *v->location;
- rtx last_addr = plus_constant (v->dest_reg,
- INTVAL (giv_inc) * (unroll_number - 1));
-
- /* First check to see if either address would fail. Handle the fact
- that we have may have a match_dup. */
- if (! validate_replace_rtx (*v->location, v->dest_reg, v->insn)
- || ! validate_replace_rtx (*v->location, last_addr, v->insn))
- ret = 0;
-
- /* Now put things back the way they were before. This should always
- succeed. */
- if (! validate_replace_rtx (*v->location, orig_addr, v->insn))
- abort ();
-
- return ret;
-}
-
/* For every giv based on the biv BL, check to determine whether it is
splittable. This is a subroutine to find_splittable_regs ().
struct iv_class *bl;
enum unroll_types unroll_type;
rtx increment;
- int unroll_number;
+ int unroll_number ATTRIBUTE_UNUSED;
{
struct loop_ivs *ivs = LOOP_IVS (loop);
struct induction *v, *v2;
splittable_regs[REGNO (v->new_reg)] = value;
}
else
- {
- /* Splitting address givs is useful since it will often allow us
- to eliminate some increment insns for the base giv as
- unnecessary. */
-
- /* If the addr giv is combined with a dest_reg giv, then all
- references to that dest reg will be remapped, which is NOT
- what we want for split addr regs. We always create a new
- register for the split addr giv, just to be safe. */
-
- /* If we have multiple identical address givs within a
- single instruction, then use a single pseudo reg for
- both. This is necessary in case one is a match_dup
- of the other. */
-
- v->const_adjust = 0;
-
- if (v->same_insn)
- {
- v->dest_reg = v->same_insn->dest_reg;
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Sharing address givs in insn %d\n",
- INSN_UID (v->insn));
- }
- /* If multiple address GIVs have been combined with the
- same dest_reg GIV, do not create a new register for
- each. */
- else if (unroll_type != UNROLL_COMPLETELY
- && v->giv_type == DEST_ADDR
- && v->same && v->same->giv_type == DEST_ADDR
- && v->same->unrolled
- /* combine_givs_p may return true for some cases
- where the add and mult values are not equal.
- To share a register here, the values must be
- equal. */
- && rtx_equal_p (v->same->mult_val, v->mult_val)
- && rtx_equal_p (v->same->add_val, v->add_val)
- /* If the memory references have different modes,
- then the address may not be valid and we must
- not share registers. */
- && verify_addresses (v, giv_inc, unroll_number))
- {
- v->dest_reg = v->same->dest_reg;
- v->shared = 1;
- }
- else if (unroll_type != UNROLL_COMPLETELY)
- {
- /* If not completely unrolling the loop, then create a new
- register to hold the split value of the DEST_ADDR giv.
- Emit insn to initialize its value before loop start. */
-
- rtx tem = gen_reg_rtx (v->mode);
- struct induction *same = v->same;
- rtx new_reg = v->new_reg;
- record_base_value (REGNO (tem), v->add_val, 0);
-
- /* If the address giv has a constant in its new_reg value,
- then this constant can be pulled out and put in value,
- instead of being part of the initialization code. */
-
- if (GET_CODE (new_reg) == PLUS
- && GET_CODE (XEXP (new_reg, 1)) == CONST_INT)
- {
- v->dest_reg
- = plus_constant (tem, INTVAL (XEXP (new_reg, 1)));
-
- /* Only succeed if this will give valid addresses.
- Try to validate both the first and the last
- address resulting from loop unrolling, if
- one fails, then can't do const elim here. */
- if (verify_addresses (v, giv_inc, unroll_number))
- {
- /* Save the negative of the eliminated const, so
- that we can calculate the dest_reg's increment
- value later. */
- v->const_adjust = -INTVAL (XEXP (new_reg, 1));
-
- new_reg = XEXP (new_reg, 0);
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Eliminating constant from giv %d\n",
- REGNO (tem));
- }
- else
- v->dest_reg = tem;
- }
- else
- v->dest_reg = tem;
-
- /* If the address hasn't been checked for validity yet, do so
- now, and fail completely if either the first or the last
- unrolled copy of the address is not a valid address
- for the instruction that uses it. */
- if (v->dest_reg == tem
- && ! verify_addresses (v, giv_inc, unroll_number))
- {
- for (v2 = v->next_iv; v2; v2 = v2->next_iv)
- if (v2->same_insn == v)
- v2->same_insn = 0;
-
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Invalid address for giv at insn %d\n",
- INSN_UID (v->insn));
- continue;
- }
-
- v->new_reg = new_reg;
- v->same = same;
-
- /* We set this after the address check, to guarantee that
- the register will be initialized. */
- v->unrolled = 1;
-
- /* To initialize the new register, just move the value of
- new_reg into it. This is not guaranteed to give a valid
- instruction on machines with complex addressing modes.
- If we can't recognize it, then delete it and emit insns
- to calculate the value from scratch. */
- loop_insn_hoist (loop, gen_rtx_SET (VOIDmode, tem,
- copy_rtx (v->new_reg)));
- if (recog_memoized (PREV_INSN (loop->start)) < 0)
- {
- rtx sequence, ret;
-
- /* We can't use bl->initial_value to compute the initial
- value, because the loop may have been preconditioned.
- We must calculate it from NEW_REG. */
- delete_related_insns (PREV_INSN (loop->start));
-
- start_sequence ();
- ret = force_operand (v->new_reg, tem);
- if (ret != tem)
- emit_move_insn (tem, ret);
- sequence = get_insns ();
- end_sequence ();
- loop_insn_hoist (loop, sequence);
-
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Invalid init insn, rewritten.\n");
- }
- }
- else
- {
- v->dest_reg = value;
-
- /* Check the resulting address for validity, and fail
- if the resulting address would be invalid. */
- if (! verify_addresses (v, giv_inc, unroll_number))
- {
- for (v2 = v->next_iv; v2; v2 = v2->next_iv)
- if (v2->same_insn == v)
- v2->same_insn = 0;
-
- if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Invalid address for giv at insn %d\n",
- INSN_UID (v->insn));
- continue;
- }
- }
-
- /* Store the value of dest_reg into the insn. This sharing
- will not be a problem as this insn will always be copied
- later. */
-
- *v->location = v->dest_reg;
-
- /* If this address giv is combined with a dest reg giv, then
- save the base giv's induction pointer so that we will be
- able to handle this address giv properly. The base giv
- itself does not have to be splittable. */
-
- if (v->same && v->same->giv_type == DEST_REG)
- addr_combined_regs[REGNO (v->same->new_reg)] = v->same;
-
- if (GET_CODE (v->new_reg) == REG)
- {
- /* This giv maybe hasn't been combined with any others.
- Make sure that it's giv is marked as splittable here. */
-
- splittable_regs[REGNO (v->new_reg)] = value;
-
- /* Make it appear to depend upon itself, so that the
- giv will be properly split in the main loop above. */
- if (! v->same)
- {
- v->same = v;
- addr_combined_regs[REGNO (v->new_reg)] = v;
- }
- }
-
- if (loop_dump_stream)
- fprintf (loop_dump_stream, "DEST_ADDR giv being split.\n");
- }
+ continue;
}
else
{
/* Try to calculate the final value as a function of the biv it depends
upon. The only exit from the loop must be the fall through at the bottom
- (otherwise it may not have its final value when the loop exits). */
+ and the insn that sets the giv must be executed on every iteration
+ (otherwise the giv may not have its final value when the loop exits). */
/* ??? Can calculate the final giv value by subtracting off the
extra biv increments times the giv's mult_val. The loop must have
to be known. */
if (n_iterations != 0
- && ! loop->exit_count)
+ && ! loop->exit_count
+ && v->always_executed)
{
/* ?? It is tempting to use the biv's value here since these insns will
be put after the loop, and hence the biv will have its final value
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. */
- last_loop_insn = PREV_INSN (loop->end);
+ last_loop_insn = prev_nonnote_insn (loop->end);
/* ??? We should probably try harder to find the jump insn
at the end of the loop. The following code assumes that
}
return 0;
}
- else if (comparison_code == EQ)
- {
- if (loop_dump_stream)
- fprintf (loop_dump_stream, "Loop iterations: EQ comparison loop.\n");
- return 0;
- }
else if (GET_CODE (final_value) != CONST_INT)
{
if (loop_dump_stream)
}
return 0;
}
+ else if (comparison_code == EQ)
+ {
+ rtx inc_once;
+
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream, "Loop iterations: EQ comparison loop.\n");
+
+ inc_once = gen_int_mode (INTVAL (initial_value) + INTVAL (increment),
+ GET_MODE (iteration_var));
+
+ if (inc_once == final_value)
+ {
+ /* The iterator value once through the loop is equal to the
+ comparision value. Either we have an infinite loop, or
+ we'll loop twice. */
+ if (increment == const0_rtx)
+ return 0;
+ loop_info->n_iterations = 2;
+ }
+ else
+ loop_info->n_iterations = 1;
+
+ if (GET_CODE (loop_info->initial_value) == CONST_INT)
+ loop_info->final_value
+ = gen_int_mode ((INTVAL (loop_info->initial_value)
+ + loop_info->n_iterations * INTVAL (increment)),
+ GET_MODE (iteration_var));
+ else
+ loop_info->final_value
+ = plus_constant (loop_info->initial_value,
+ loop_info->n_iterations * INTVAL (increment));
+ loop_info->final_equiv_value
+ = gen_int_mode ((INTVAL (initial_value)
+ + loop_info->n_iterations * INTVAL (increment)),
+ GET_MODE (iteration_var));
+ return loop_info->n_iterations;
+ }
/* Final_larger is 1 if final larger, 0 if they are equal, otherwise -1. */
if (unsigned_p)