This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
mips16 elimination of return address pointer
- From: Alexandre Oliva <aoliva at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: 18 Mar 2002 16:04:03 -0300
- Subject: mips16 elimination of return address pointer
- Organization: GCC Team, Red Hat
gcc.c-torture/execute/20010122-1.c exposed further problems in
register elimination, this time in handling of RETURN_ADDRESS_POINTER.
First off, we generated an invalid instruction: the `R' constraint has
no way to verify that it must not accept mems of offsets of registers
other than $sp, and it's kind of pointless to introduce yet another
constraint with this limitation. I have simplified the insn we used
to use for $ra stores such that it will only be used when it doesn't
require any reloads. In general, we'll only use this pattern for
saving $ra in the stack, in which case we'll probably be using a valid
sp offset anyway, or when loading $ra directly into a pseudo that ends
up assigned to a stack slot, in which case we may end up using a frame
pointer reference (which was the case in this example), in which case
we need reload to fix it up by using a temporary.
The second problem was that register elimination rules for $rap were
significantly broken. With the current elimination infrastructure,
there's just no way to eliminate say (mem:SI (reg:SI rap)) to (reg:SI
ra) (we ended up generating (mem:SI (reg:SI ra))), and this is not
necessary since RETURN_ADDR_RTX already generates (reg:SI ra) instead
of (mem:SI (reg:SI rap)) within leaf functions. So I have removed the
nonsensical entry from ELIMINABLE_REGS and the corresponding tests in
CAN_ELIMINATE and, while at that, I brought in a patch by Graham Stott
that got RETURN_ADDR_RTX to use $ra directly for RETURN_ADDR_RTX in
leaf functions, since $ra does not have to be saved on them. It has
the unfortunate side effect that now $ra is now marked as ever_live
and saved/restored, but at least we're better off than before. I've
also ensured we wouldn't eliminate $rap in favor of $sp when a frame
pointer is needed, since then we can't assume offsets from sp are
known.
Finally, I have fixed the elimination offset from $rap to the hard
frame pointer, that, in the case of mips16, differs from the stack
pointer at the end of the prologue.
After this patch, 20010122-1.c passed on all combinations of ABIs,
register and long sizes and ISAs I could test for a Red Hat-internal
mips port I'm working on, and it didn't introduce any regressions.
This patch was also tested in net GCC mainline, with a bootstrap on
mips-sgi-irix6.5. Eric Christopher approved it, so I'm checking it
in.
Index: gcc/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
* config/mips/mips.h (ELIMINABLE_REGS): Can't eliminate
RETURN_ADDRESS_POINTER_REGNUM to $ra.
(CAN_ELIMINATE): Only eliminate it to $sp if a frame pointer is
not needed. Disregard leaf_function_p().
(INITIAL_ELIMINATION_OFFSET): Adjust for elimination of rap to
mips16 frame pointer.
* config/mips/mips.md (store ra): Only to small SP offsets.
2001-08-22 Graham Stott <grahams@redhat.com>
* config/mips/mips.h (RETURN_ADDR_RTX): For a leaf function
return a REG rtx for the return address register.
Index: gcc/config/mips/mips.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/mips/mips.h,v
retrieving revision 1.168
diff -u -p -r1.168 mips.h
--- gcc/config/mips/mips.h 2002/03/17 00:02:30 1.168
+++ gcc/config/mips/mips.h 2002/03/18 08:00:16
@@ -2417,9 +2417,12 @@ extern enum reg_class mips_char_to_class
frame except by disassembling instructions in the prologue/epilogue.
So currently we support only the current frame. */
-#define RETURN_ADDR_RTX(count, frame) \
- ((count == 0) \
- ? gen_rtx_MEM (Pmode, gen_rtx_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM))\
+#define RETURN_ADDR_RTX(count, frame) \
+ (((count) == 0) \
+ ? (leaf_function_p () \
+ ? gen_rtx_REG (Pmode, GP_REG_FIRST + 31) \
+ : gen_rtx_MEM (Pmode, gen_rtx_REG (Pmode, \
+ RETURN_ADDRESS_POINTER_REGNUM))) \
: (rtx) 0)
/* Structure to be filled in by compute_frame_size with register
@@ -2483,7 +2486,6 @@ extern struct mips_frame_info current_fr
{ RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ RETURN_ADDRESS_POINTER_REGNUM, GP_REG_FIRST + 30}, \
{ RETURN_ADDRESS_POINTER_REGNUM, GP_REG_FIRST + 17}, \
- { RETURN_ADDRESS_POINTER_REGNUM, GP_REG_FIRST + 31}, \
{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ FRAME_POINTER_REGNUM, GP_REG_FIRST + 30}, \
{ FRAME_POINTER_REGNUM, GP_REG_FIRST + 17}}
@@ -2510,10 +2512,8 @@ extern struct mips_frame_info current_fr
#define CAN_ELIMINATE(FROM, TO) \
(((FROM) == RETURN_ADDRESS_POINTER_REGNUM \
- && ((! leaf_function_p () \
- && ((TO) == STACK_POINTER_REGNUM \
- || (TO) == HARD_FRAME_POINTER_REGNUM)) \
- || ((TO) == GP_REG_FIRST + 31 && leaf_function_p ()))) \
+ && (((TO) == STACK_POINTER_REGNUM && ! frame_pointer_needed) \
+ || (TO) == HARD_FRAME_POINTER_REGNUM)) \
|| ((FROM) != RETURN_ADDRESS_POINTER_REGNUM \
&& ((TO) == HARD_FRAME_POINTER_REGNUM \
|| ((TO) == STACK_POINTER_REGNUM && ! frame_pointer_needed \
@@ -2553,11 +2553,11 @@ extern struct mips_frame_info current_fr
so we must add 4 bytes to the offset to get the right value. */ \
else if ((FROM) == RETURN_ADDRESS_POINTER_REGNUM) \
{ \
- if (leaf_function_p ()) \
- (OFFSET) = 0; \
- else (OFFSET) = current_frame_info.gp_sp_offset \
- + ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)) \
- * (BYTES_BIG_ENDIAN != 0)); \
+ (OFFSET) = current_frame_info.gp_sp_offset \
+ + ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)) \
+ * (BYTES_BIG_ENDIAN != 0)); \
+ if (TARGET_MIPS16 && (TO) != STACK_POINTER_REGNUM) \
+ (OFFSET) -= current_function_outgoing_args_size; \
} \
else \
abort(); \
@@ -4153,7 +4153,7 @@ while (0)
"$0", "at", "v0", "v1", "a0", "a1", "a2", "a3", \
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", \
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", \
- "t8", "t9", "k0", "k1", "gp", "sp", "$fp", "ra", \
+ "t8", "t9", "k0", "k1", "gp", "sp", "$fp", "ra", \
"$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", \
"$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", \
"$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", \
Index: gcc/config/mips/mips.md
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/mips/mips.md,v
retrieving revision 1.120
diff -u -p -r1.120 mips.md
--- gcc/config/mips/mips.md 2002/03/16 23:58:35 1.120
+++ gcc/config/mips/mips.md 2002/03/18 08:00:18
@@ -5489,22 +5489,25 @@ move\\t%0,%z4\\n\\
}
}")
-;; For mips16, we need a special case to handle storing $31 into
-;; memory, since we don't have a constraint to match $31. This
-;; instruction can be generated by save_restore_insns.
+;; We can only store $ra directly into a small sp offset. Should the
+;; offset be too wide, non-constant or not sp-based, leave it up to
+;; reload to choose a scratch register.
(define_insn ""
- [(set (match_operand:SI 0 "memory_operand" "=R,m")
+ [(set (mem:SI (plus:SI (reg:SI 29)
+ (match_operand:SI 0 "small_int" "n")))
(reg:SI 31))]
"TARGET_MIPS16"
- "*
-{
- operands[1] = gen_rtx (REG, SImode, 31);
- return mips_move_1word (operands, insn, FALSE);
-}"
+ "sw\\t$31,%0($sp)"
[(set_attr "type" "store")
(set_attr "mode" "SI")
- (set_attr "length" "4,8")])
+ (set_attr_alternative
+ "length"
+ [(if_then_else
+ (lt (symbol_ref "(unsigned HOST_WIDE_INT) INTVAL (operands[0])")
+ (const_int 1024))
+ (const_int 4)
+ (const_int 8))])])
;; The difference between these two is whether or not ints are allowed
;; in FP registers (off by default, use -mdebugh to enable).
--
Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist Professional serial bug killer