This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

mips16 elimination of return address pointer


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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]