/* Forward declarations. */
+static void invalidate_loops_containing_label PARAMS ((rtx));
static void find_and_verify_loops PARAMS ((rtx, struct loops *));
static void mark_loop_jump PARAMS ((rtx, struct loop *));
static void prescan_loop PARAMS ((struct loop *));
static void loop_dump_aux PARAMS ((const struct loop *, FILE *, int));
static void loop_delete_insns PARAMS ((rtx, rtx));
static HOST_WIDE_INT remove_constant_addition PARAMS ((rtx *));
+static rtx gen_load_of_final_value PARAMS ((rtx, rtx));
void debug_ivs PARAMS ((const struct loop *));
void debug_iv_class PARAMS ((const struct iv_class *));
void debug_biv PARAMS ((const struct induction *));
/* Regs that are set more than once are not allowed to match
or be matched. I'm no longer sure why not. */
+ /* Only pseudo registers are allowed to match or be matched,
+ since move_movables does not validate the change. */
/* Perhaps testing m->consec_sets would be more appropriate here? */
for (m = movables->head; m; m = m->next)
if (m->match == 0 && regs->array[m->regno].n_times_set == 1
+ && m->regno >= FIRST_PSEUDO_REGISTER
&& !m->partial)
{
struct movable *m1;
/* We want later insns to match the first one. Don't make the first
one match any later ones. So start this loop at m->next. */
for (m1 = m->next; m1; m1 = m1->next)
- /* ??? HACK! move_movables does not verify that the replacement
- is valid, which can have disasterous effects with hard regs
- and match_dup. Turn combination off for now. */
- if (0 && m != m1 && m1->match == 0
+ if (m != m1 && m1->match == 0
&& regs->array[m1->regno].n_times_set == 1
+ && m1->regno >= FIRST_PSEUDO_REGISTER
/* A reg used outside the loop mustn't be eliminated. */
&& !m1->global
/* A reg used for zero-extending mustn't be eliminated. */
loop_info->unknown_address_altered = 1;
loop_info->has_nonconst_call = 1;
}
+ else if (pure_call_p (insn))
+ loop_info->has_nonconst_call = 1;
loop_info->has_call = 1;
if (can_throw_internal (insn))
loop_info->has_multiple_exit_targets = 1;
}
}
\f
+/* Invalidate all loops containing LABEL. */
+
+static void
+invalidate_loops_containing_label (label)
+ rtx label;
+{
+ struct loop *loop;
+ for (loop = uid_loop[INSN_UID (label)]; loop; loop = loop->outer)
+ loop->invalid = 1;
+}
+
/* Scan the function looking for loops. Record the start and end of each loop.
Also mark as invalid loops any loops that contain a setjmp or are branched
to from outside the loop. */
/* Any loop containing a label used in an initializer must be invalidated,
because it can be jumped into from anywhere. */
-
for (label = forced_labels; label; label = XEXP (label, 1))
- {
- for (loop = uid_loop[INSN_UID (XEXP (label, 0))];
- loop; loop = loop->outer)
- loop->invalid = 1;
- }
+ invalidate_loops_containing_label (XEXP (label, 0));
/* Any loop containing a label used for an exception handler must be
invalidated, because it can be jumped into from anywhere. */
-
- for (label = exception_handler_labels; label; label = XEXP (label, 1))
- {
- for (loop = uid_loop[INSN_UID (XEXP (label, 0))];
- loop; loop = loop->outer)
- loop->invalid = 1;
- }
+ for_each_eh_label (invalidate_loops_containing_label);
/* Now scan all insn's in the function. If any JUMP_INSN branches into a
loop that it is not contained within, that loop is marked invalid.
{
rtx note = find_reg_note (insn, REG_LABEL, NULL_RTX);
if (note)
- {
- for (loop = uid_loop[INSN_UID (XEXP (note, 0))];
- loop; loop = loop->outer)
- loop->invalid = 1;
- }
+ invalidate_loops_containing_label (XEXP (note, 0));
}
if (GET_CODE (insn) != JUMP_INSN)
v->mult_val, v->add_val, v->dest_reg);
else if (v->final_value)
loop_insn_sink_or_swim (loop,
- gen_move_insn (v->dest_reg, v->final_value));
+ gen_load_of_final_value (v->dest_reg,
+ v->final_value));
if (loop_dump_stream)
{
value, so we don't need another one. We can't calculate the
proper final value for such a biv here anyways. */
if (bl->final_value && ! bl->reversed)
- loop_insn_sink_or_swim (loop, gen_move_insn
- (bl->biv->dest_reg, bl->final_value));
+ loop_insn_sink_or_swim (loop,
+ gen_load_of_final_value (bl->biv->dest_reg,
+ bl->final_value));
if (loop_dump_stream)
fprintf (loop_dump_stream, "Reg %d: biv eliminated\n",
/* See above note wrt final_value. But since we couldn't eliminate
the biv, we must set the value after the loop instead of before. */
else if (bl->final_value && ! bl->reversed)
- loop_insn_sink (loop, gen_move_insn (bl->biv->dest_reg,
- bl->final_value));
+ loop_insn_sink (loop, gen_load_of_final_value (bl->biv->dest_reg,
+ bl->final_value));
}
/* Go through all the instructions in the loop, making all the
collected. Always unroll loops that would be as small or smaller
unrolled than when rolled. */
if ((flags & LOOP_UNROLL)
- || (loop_info->n_iterations > 0
+ || (!(flags & LOOP_FIRST_PASS)
+ && loop_info->n_iterations > 0
&& unrolled_insn_copies <= insn_count))
unroll_loop (loop, insn_count, 1);
case CONST:
/* convert_modes aborts if we try to convert to or from CCmode, so just
exclude that case. It is very unlikely that a condition code value
- would be a useful iterator anyways. */
+ would be a useful iterator anyways. convert_modes aborts if we try to
+ convert a float mode to non-float or vice versa too. */
if (loop->level == 1
- && GET_MODE_CLASS (mode) != MODE_CC
- && GET_MODE_CLASS (GET_MODE (dest_reg)) != MODE_CC)
+ && GET_MODE_CLASS (mode) == GET_MODE_CLASS (GET_MODE (dest_reg))
+ && GET_MODE_CLASS (mode) != MODE_CC)
{
/* Possible bug here? Perhaps we don't know the mode of X. */
*inc_val = convert_modes (GET_MODE (dest_reg), mode, x, 0);
if ((REGNO_LAST_UID (bl->regno) != INSN_UID (first_compare))
|| ! bl->init_insn
|| REGNO_FIRST_UID (bl->regno) != INSN_UID (bl->init_insn))
- loop_insn_sink (loop, gen_move_insn (reg, final_value));
+ loop_insn_sink (loop, gen_load_of_final_value (reg, final_value));
/* Delete compare/branch at end of loop. */
delete_related_insns (PREV_INSN (loop_end));
{
case LE:
if ((unsigned HOST_WIDE_INT) const_val != max_val >> 1)
- code = LT, op1 = GEN_INT (const_val + 1);
+ code = LT, op1 = gen_int_mode (const_val + 1, GET_MODE (op0));
break;
/* When cross-compiling, const_val might be sign-extended from
if ((HOST_WIDE_INT) (const_val & max_val)
!= (((HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (GET_MODE (op0)) - 1))))
- code = GT, op1 = GEN_INT (const_val - 1);
+ code = GT, op1 = gen_int_mode (const_val - 1, GET_MODE (op0));
break;
case LEU:
if (uconst_val < max_val)
- code = LTU, op1 = GEN_INT (uconst_val + 1);
+ code = LTU, op1 = gen_int_mode (uconst_val + 1, GET_MODE (op0));
break;
case GEU:
if (uconst_val != 0)
- code = GTU, op1 = GEN_INT (uconst_val - 1);
+ code = GTU, op1 = gen_int_mode (uconst_val - 1, GET_MODE (op0));
break;
default:
&& rtx_equal_p (SET_DEST (set), mem))
SET_REGNO_REG_SET (&store_copies, REGNO (SET_SRC (set)));
- /* Replace the memory reference with the shadow register. */
- replace_loop_mems (p, loop_info->mems[i].mem,
- loop_info->mems[i].reg);
+ /* If this is a call which uses / clobbers this memory
+ location, we must not change the interface here. */
+ if (GET_CODE (p) == CALL_INSN
+ && reg_mentioned_p (loop_info->mems[i].mem,
+ CALL_INSN_FUNCTION_USAGE (p)))
+ {
+ cancel_changes (0);
+ loop_info->mems[i].optimize = 0;
+ break;
+ }
+ else
+ /* Replace the memory reference with the shadow register. */
+ replace_loop_mems (p, loop_info->mems[i].mem,
+ loop_info->mems[i].reg);
}
if (GET_CODE (p) == CODE_LABEL
maybe_never = 1;
}
- if (! apply_change_group ())
+ if (! loop_info->mems[i].optimize)
+ ; /* We found we couldn't do the replacement, so do nothing. */
+ else if (! apply_change_group ())
/* We couldn't replace all occurrences of the MEM. */
loop_info->mems[i].optimize = 0;
else
return loop_insn_emit_before (loop, 0, loop->sink, pattern);
}
+/* bl->final_value can be eighter general_operand or PLUS of general_operand
+ and constant. Emit sequence of intructions to load it into REG */
+static rtx
+gen_load_of_final_value (reg, final_value)
+ rtx reg, final_value;
+{
+ rtx seq;
+ start_sequence ();
+ final_value = force_operand (final_value, reg);
+ if (final_value != reg)
+ emit_move_insn (reg, final_value);
+ seq = gen_sequence ();
+ end_sequence ();
+ return seq;
+}
/* If the loop has multiple exits, emit insn for PATTERN before the
loop to ensure that it will always be executed no matter how the