+
+ if (p->new_sp_equiv_reg == 0 || GET_CODE (p->new_sp_equiv_reg) != REG)
+ abort ();
+
+ return;
+ }
+
+ /* Next handle the case where we are setting SP's equivalent register.
+ If we already have a value to set it to, abort. We could update, but
+ there seems little point in handling that case. Note that we have
+ to allow for the case where we are setting the register set in
+ the previous part of a PARALLEL inside a single insn. But use the
+ old offset for any updates within this insn. We must allow for the case
+ where the register is being set in a different (usually wider) mode than
+ Pmode). */
+ else if (p->new_sp_equiv_reg != 0 && reg_set_p (p->new_sp_equiv_reg, set))
+ {
+ if (p->equiv_reg_src != 0
+ || GET_CODE (p->new_sp_equiv_reg) != REG
+ || GET_CODE (SET_DEST (set)) != REG
+ || GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) > BITS_PER_WORD
+ || REGNO (p->new_sp_equiv_reg) != REGNO (SET_DEST (set)))
+ abort ();
+ else
+ p->equiv_reg_src
+ = simplify_replace_rtx (SET_SRC (set), stack_pointer_rtx,
+ plus_constant (p->sp_equiv_reg,
+ p->sp_offset));
+ }
+
+ /* Otherwise, replace any references to SP in the insn to its new value
+ and emit the insn. */
+ else
+ {
+ SET_SRC (set) = simplify_replace_rtx (SET_SRC (set), stack_pointer_rtx,
+ plus_constant (p->sp_equiv_reg,
+ p->sp_offset));
+ SET_DEST (set) = simplify_replace_rtx (SET_DEST (set), stack_pointer_rtx,
+ plus_constant (p->sp_equiv_reg,
+ p->sp_offset));
+ emit_insn (set);
+ }
+}
+
+/* Update the tracking information for registers set to constants. */
+
+static void
+update_epilogue_consts (rtx dest, rtx x, void *data)
+{
+ struct epi_info *p = (struct epi_info *) data;
+ rtx new;
+
+ if (GET_CODE (dest) != REG || REGNO (dest) >= FIRST_PSEUDO_REGISTER)
+ return;
+
+ /* If we are either clobbering a register or doing a partial set,
+ show we don't know the value. */
+ else if (GET_CODE (x) == CLOBBER || ! rtx_equal_p (dest, SET_DEST (x)))
+ p->const_equiv[REGNO (dest)] = 0;
+
+ /* If we are setting it to a constant, record that constant. */
+ else if (GET_CODE (SET_SRC (x)) == CONST_INT)
+ p->const_equiv[REGNO (dest)] = SET_SRC (x);
+
+ /* If this is a binary operation between a register we have been tracking
+ and a constant, see if we can compute a new constant value. */
+ else if ((GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == 'c'
+ || GET_RTX_CLASS (GET_CODE (SET_SRC (x))) == '2')
+ && GET_CODE (XEXP (SET_SRC (x), 0)) == REG
+ && REGNO (XEXP (SET_SRC (x), 0)) < FIRST_PSEUDO_REGISTER
+ && p->const_equiv[REGNO (XEXP (SET_SRC (x), 0))] != 0
+ && GET_CODE (XEXP (SET_SRC (x), 1)) == CONST_INT
+ && 0 != (new = simplify_binary_operation
+ (GET_CODE (SET_SRC (x)), GET_MODE (dest),
+ p->const_equiv[REGNO (XEXP (SET_SRC (x), 0))],
+ XEXP (SET_SRC (x), 1)))
+ && GET_CODE (new) == CONST_INT)
+ p->const_equiv[REGNO (dest)] = new;
+
+ /* Otherwise, we can't do anything with this value. */
+ else
+ p->const_equiv[REGNO (dest)] = 0;
+}
+
+/* Emit an insn to do the load shown in p->equiv_reg_src, if needed. */
+
+static void
+emit_equiv_load (struct epi_info *p)
+{
+ if (p->equiv_reg_src != 0)
+ {
+ rtx dest = p->sp_equiv_reg;
+
+ if (GET_MODE (p->equiv_reg_src) != GET_MODE (dest))
+ dest = gen_rtx_REG (GET_MODE (p->equiv_reg_src),
+ REGNO (p->sp_equiv_reg));
+
+ emit_move_insn (dest, p->equiv_reg_src);
+ p->equiv_reg_src = 0;