[committed] Use $15 as the MIPS static chain register.
Richard Sandiford
rdsandiford@googlemail.com
Sat Aug 9 19:05:00 GMT 2008
MIPS16 code is supposed to use the following sequence to load $gp:
0: li $v0,%hi(_gp_disp)
4: addiupc $v1,%lo(_gp_disp)
8: sll $v0,16
12: addu $v0,$v1
14: move $gp,$v0
Unfortunately, $2 (aka $v0) is already used as the static chain
register, so this sequence doesn't work for nested functions.
This patch changes the static chain register from $2 to $15.
The choice of register is internal to the translation unit,
except in one regard: _mcount saves and restores $2 and
the argument registers, but it does not save and restore $15.
(Thanks to Dan for pointing out the failure.)
Having an extra couple of moves when profiling nested functions
doesn't seem too bad, so I simply made the choice of $15 unconditional.
That seems safer than trying to use different registers for
MIPS16 and non-MIPS16 code.
Only the MIPS SDE MDK configuration supports MIPS16 profiling, and it
doesn't support PIC, so neither of the patched FUNCTION_PROFILERs
will clobber the static chain register. Something cleverer will be
needed if MIPS16 profiling support is added in future.
I had to update the nested function trampolines to account for this
change. While there, I simplied them a little. We now load the target
address directly into $25, instead of going through a temporary register.
Tested on mips64-linux-gnu and mipsisa64-elf. Applied.
Richard
gcc/
* config/mips/mips.h (STATIC_CHAIN_REGNUM): Remap to $15.
(FUNCTION_PROFILER): Save the static chain pointer into $2
beforehand and restore it aftewards.
(TRAMPOLINE_TEMPLATE): Adjust accordingly. Load the target
address directly into $25 and call the function through $25;
do not clobber $3. Pad the DImode version to cover the space
left by the deleted $25 <- $3 move.
(TRAMPOLINE_SIZE): Adjust the size of the SImode version after
the removal of the $25 <- $3 move.
(INITIALIZE_TRAMPOLINE): Update offsets accordingly.
* config/mips/sdemtk.h (FUNCTION_PROFILER): As for mips.h.
Index: gcc/config/mips/mips.h
===================================================================
--- gcc/config/mips/mips.h 2008-08-09 10:15:14.000000000 +0100
+++ gcc/config/mips/mips.h 2008-08-09 10:19:45.000000000 +0100
@@ -1657,7 +1657,7 @@ #define HARD_FRAME_POINTER_REGNUM \
#define FRAME_POINTER_REQUIRED (mips_frame_pointer_required ())
/* Register in which static-chain is passed to a function. */
-#define STATIC_CHAIN_REGNUM (GP_REG_FIRST + 2)
+#define STATIC_CHAIN_REGNUM (GP_REG_FIRST + 15)
/* Registers used as temporaries in prologue/epilogue code. If we're
generating mips16 code, these registers must come from the core set
@@ -2181,6 +2181,10 @@ #define FUNCTION_PROFILER(FILE, LABELNO)
fprintf (FILE, "\t.set\tnoat\n"); \
fprintf (FILE, "\tmove\t%s,%s\t\t# save current return address\n", \
reg_names[GP_REG_FIRST + 1], reg_names[GP_REG_FIRST + 31]); \
+ /* _mcount treats $2 as the static chain register. */ \
+ if (cfun->static_chain_decl != NULL) \
+ fprintf (FILE, "\tmove\t%s,%s\n", reg_names[2], \
+ reg_names[STATIC_CHAIN_REGNUM]); \
if (!TARGET_NEWABI) \
{ \
fprintf (FILE, \
@@ -2192,6 +2196,10 @@ #define FUNCTION_PROFILER(FILE, LABELNO)
} \
fprintf (FILE, "\tjal\t_mcount\n"); \
fprintf (FILE, "\t.set\tat\n"); \
+ /* _mcount treats $2 as the static chain register. */ \
+ if (cfun->static_chain_decl != NULL) \
+ fprintf (FILE, "\tmove\t%s,%s\n", reg_names[STATIC_CHAIN_REGNUM], \
+ reg_names[2]); \
}
/* The profiler preserves all interesting registers, including $31. */
@@ -2231,20 +2239,19 @@ #define TRAMPOLINE_TEMPLATE(STREAM)
fprintf (STREAM, "\t.word\t0x00000000\t\t# nop\n"); \
if (ptr_mode == DImode) \
{ \
- fprintf (STREAM, "\t.word\t0xdfe30014\t\t# ld $3,20($31)\n"); \
- fprintf (STREAM, "\t.word\t0xdfe2001c\t\t# ld $2,28($31)\n"); \
- fprintf (STREAM, "\t.word\t0x0060c82d\t\t# dmove $25,$3\n"); \
+ fprintf (STREAM, "\t.word\t0xdff90014\t\t# ld $25,20($31)\n"); \
+ fprintf (STREAM, "\t.word\t0xdfef001c\t\t# ld $15,28($31)\n"); \
} \
else \
{ \
- fprintf (STREAM, "\t.word\t0x8fe30014\t\t# lw $3,20($31)\n"); \
- fprintf (STREAM, "\t.word\t0x8fe20018\t\t# lw $2,24($31)\n"); \
- fprintf (STREAM, "\t.word\t0x0060c821\t\t# move $25,$3\n"); \
+ fprintf (STREAM, "\t.word\t0x8ff90010\t\t# lw $25,16($31)\n"); \
+ fprintf (STREAM, "\t.word\t0x8fef0014\t\t# lw $15,20($31)\n"); \
} \
- fprintf (STREAM, "\t.word\t0x00600008\t\t# jr $3\n"); \
+ fprintf (STREAM, "\t.word\t0x03200008\t\t# jr $25\n"); \
if (ptr_mode == DImode) \
{ \
fprintf (STREAM, "\t.word\t0x0020f82d\t\t# dmove $31,$1\n"); \
+ fprintf (STREAM, "\t.word\t0x00000000\t\t# <padding>\n"); \
fprintf (STREAM, "\t.dword\t0x00000000\t\t# <function address>\n"); \
fprintf (STREAM, "\t.dword\t0x00000000\t\t# <static chain value>\n"); \
} \
@@ -2259,7 +2266,7 @@ #define TRAMPOLINE_TEMPLATE(STREAM)
/* A C expression for the size in bytes of the trampoline, as an
integer. */
-#define TRAMPOLINE_SIZE (32 + GET_MODE_SIZE (ptr_mode) * 2)
+#define TRAMPOLINE_SIZE (ptr_mode == DImode ? 48 : 36)
/* Alignment required for trampolines, in bits. */
@@ -2289,7 +2296,7 @@ #define INITIALIZE_TRAMPOLINE(ADDR, FUNC
{ \
rtx func_addr, chain_addr, end_addr; \
\
- func_addr = plus_constant (ADDR, 32); \
+ func_addr = plus_constant (ADDR, ptr_mode == DImode ? 32 : 28); \
chain_addr = plus_constant (func_addr, GET_MODE_SIZE (ptr_mode)); \
mips_emit_move (gen_rtx_MEM (ptr_mode, func_addr), FUNC); \
mips_emit_move (gen_rtx_MEM (ptr_mode, chain_addr), CHAIN); \
Index: gcc/config/mips/sdemtk.h
===================================================================
--- gcc/config/mips/sdemtk.h 2008-08-09 10:09:00.000000000 +0100
+++ gcc/config/mips/sdemtk.h 2008-08-09 10:19:45.000000000 +0100
@@ -94,12 +94,20 @@ #define MIPS_ICACHE_SYNC(ADDR, SIZE)
#define FUNCTION_PROFILER(FILE, LABELNO) \
{ \
fprintf (FILE, "\t.set\tnoat\n"); \
+ /* _mcount treats $2 as the static chain register. */ \
+ if (cfun->static_chain_decl != NULL) \
+ fprintf (FILE, "\tmove\t%s,%s\n", reg_names[2], \
+ reg_names[STATIC_CHAIN_REGNUM]); \
/* MIPS16 code passes saved $ra in $v1 instead of $at. */ \
fprintf (FILE, "\tmove\t%s,%s\n", \
reg_names[GP_REG_FIRST + (TARGET_MIPS16 ? 3 : 1)], \
reg_names[GP_REG_FIRST + 31]); \
fprintf (FILE, "\tjal\t_mcount\n"); \
fprintf (FILE, "\t.set\tat\n"); \
+ /* _mcount treats $2 as the static chain register. */ \
+ if (cfun->static_chain_decl != NULL) \
+ fprintf (FILE, "\tmove\t%s,%s\n", reg_names[STATIC_CHAIN_REGNUM], \
+ reg_names[2]); \
}
/* ...nor does the call sequence preserve $31. */
More information about the Gcc-patches
mailing list