aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/config/mips/mips.md4
-rw-r--r--gcc/function.c65
3 files changed, 69 insertions, 13 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 41aa8e0..64c3dba 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,16 @@
+2003-11-14 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ PR/6552
+ * function.c (struct epi_info): New field const_equiv.
+ (update_epilogue_consts): New function.
+ (keep_stack_depressed): Clear new field and verify scratch register
+ doesn't have it set.
+ Call new function via note_stores.
+ (handle_epilogue_set): Allow setting SP equiv reg in different mode.
+ Allow PLUS where second operand is register known set to constant.
+ (emit_equiv_load): Write load using proper mode if source different.
+ * config/mips/mips.md (return_internal): Put (return) first.
+
2003-11-14 Kazu Hirata <kazu@cs.umass.edu>
* config/h8300/lib1funcs.asm (___udivsi3): Add a comment.
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index 5a4e89e..203ac2e 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -8249,8 +8249,8 @@ ld\t%2,%1-%S1(%2)\;daddu\t%2,%2,$31\;%*j\t%2%/"
;; Normal return.
(define_insn "return_internal"
- [(use (match_operand 0 "pmode_register_operand" ""))
- (return)]
+ [(return)
+ (use (match_operand 0 "pmode_register_operand" ""))]
""
"%*j\t%0%/"
[(set_attr "type" "jump")
diff --git a/gcc/function.c b/gcc/function.c
index ef1afaa..f191aec 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -7296,9 +7296,12 @@ struct epi_info
rtx equiv_reg_src; /* If nonzero, the value that SP_EQUIV_REG
should be set to once we no longer need
its value. */
+ rtx const_equiv[FIRST_PSEUDO_REGISTER]; /* Any known constant equivalences
+ for registers. */
};
static void handle_epilogue_set (rtx, struct epi_info *);
+static void update_epilogue_consts PARAMS ((rtx, rtx, void *));
static void emit_equiv_load (struct epi_info *);
/* Modify INSN, a list of one or more insns that is part of the epilogue, to
@@ -7311,8 +7314,7 @@ keep_stack_depressed (rtx insns)
struct epi_info info;
rtx insn, next;
- /* If the epilogue is just a single instruction, it ust be OK as is. */
-
+ /* If the epilogue is just a single instruction, it must be OK as is. */
if (NEXT_INSN (insns) == NULL_RTX)
return insns;
@@ -7324,6 +7326,9 @@ keep_stack_depressed (rtx insns)
info.sp_offset = 0;
info.equiv_reg_src = 0;
+ for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+ info.const_equiv[j] = 0;
+
insn = insns;
next = NULL_RTX;
while (insn != NULL_RTX)
@@ -7415,7 +7420,8 @@ keep_stack_depressed (rtx insns)
&& !refers_to_regno_p (regno,
regno + HARD_REGNO_NREGS (regno,
Pmode),
- info.equiv_reg_src, NULL))
+ info.equiv_reg_src, NULL)
+ && info.const_equiv[regno] == 0)
break;
if (regno == FIRST_PSEUDO_REGISTER)
@@ -7471,6 +7477,8 @@ keep_stack_depressed (rtx insns)
info.sp_equiv_reg = info.new_sp_equiv_reg;
info.sp_offset = info.new_sp_offset;
+ /* Now update any constants this insn sets. */
+ note_stores (PATTERN (insn), update_epilogue_consts, &info);
insn = next;
}
@@ -7494,11 +7502,18 @@ handle_epilogue_set (rtx set, struct epi_info *p)
if (SET_DEST (set) != stack_pointer_rtx)
abort ();
- if (GET_CODE (SET_SRC (set)) == PLUS
- && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT)
+ if (GET_CODE (SET_SRC (set)) == PLUS)
{
p->new_sp_equiv_reg = XEXP (SET_SRC (set), 0);
- p->new_sp_offset = INTVAL (XEXP (SET_SRC (set), 1));
+ if (GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT)
+ p->new_sp_offset = INTVAL (XEXP (SET_SRC (set), 1));
+ else if (GET_CODE (XEXP (SET_SRC (set), 1)) == REG
+ && REGNO (XEXP (SET_SRC (set), 1)) < FIRST_PSEUDO_REGISTER
+ && p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))] != 0)
+ p->new_sp_offset
+ = INTVAL (p->const_equiv[REGNO (XEXP (SET_SRC (set), 1))]);
+ else
+ abort ();
}
else
p->new_sp_equiv_reg = SET_SRC (set), p->new_sp_offset = 0;
@@ -7521,11 +7536,16 @@ handle_epilogue_set (rtx set, struct epi_info *p)
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. */
+ 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 (!rtx_equal_p (p->new_sp_equiv_reg, SET_DEST (set))
- || p->equiv_reg_src != 0)
+ 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
@@ -7548,15 +7568,38 @@ handle_epilogue_set (rtx set, struct epi_info *p)
}
}
+/* 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;
+
+ if (GET_CODE (dest) != REG || REGNO (dest) >= FIRST_PSEUDO_REGISTER)
+ return;
+ else if (GET_CODE (x) == CLOBBER || ! rtx_equal_p (dest, SET_DEST (x))
+ || GET_CODE (SET_SRC (x)) != CONST_INT)
+ p->const_equiv[REGNO (dest)] = 0;
+ else
+ p->const_equiv[REGNO (dest)] = SET_SRC (x);
+}
+
/* 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)
- emit_move_insn (p->sp_equiv_reg, p->equiv_reg_src);
+ {
+ 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));
- p->equiv_reg_src = 0;
+ emit_move_insn (dest, p->equiv_reg_src);
+ p->equiv_reg_src = 0;
+ }
}
#endif