diff options
author | Richard Sandiford <rdsandiford@googlemail.com> | 2009-10-05 19:45:54 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2009-10-05 19:45:54 +0000 |
commit | c640a3bd210fb2fddbfc5118e37a99dbe8a0a14b (patch) | |
tree | 525e11396150f9067933a78b22862a0296eebd0a /gcc/config/mips | |
parent | 293593b15fbf08603d6fa038e8e4614b41166c9f (diff) | |
download | gcc-c640a3bd210fb2fddbfc5118e37a99dbe8a0a14b.zip gcc-c640a3bd210fb2fddbfc5118e37a99dbe8a0a14b.tar.gz gcc-c640a3bd210fb2fddbfc5118e37a99dbe8a0a14b.tar.bz2 |
mips-protos.h (mips_trampoline_code_size): Declare.
gcc/
* config/mips/mips-protos.h (mips_trampoline_code_size): Declare.
* config/mips/mips.h (TRAMPOLINE_SIZE): Redefine as the size of
a code block followed by two pointers.
(TRAMPOLINE_ALIGNMENT): Define to 64 for 32-bit targets too.
* config/mips/mips.c (MIPS_LOAD_PTR): New macro.
(MIPS_MOVE): Likewise.
(MIPS_LUI): Likewise.
(MIPS_JR): Likewise.
(MIPS_BAL): Likewise.
(MIPS_NOP): Likewise.
(mips_asm_trampoline_template): Delete.
(mips_trampoline_code_size): New function.
(mips_trampoline_init): Add shorter sequences for all cases
except Pmode == DImoe && !TARGET_USE_PIC_FN_ADDR_REG.
Calculate the opcodes directly, rather than copying from a template.
Only flush the code part of the trampoline.
(TARGET_ASM_TRAMPOLINE_TEMPLATE): Delete.
From-SVN: r152466
Diffstat (limited to 'gcc/config/mips')
-rw-r--r-- | gcc/config/mips/mips-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/mips/mips.c | 226 | ||||
-rw-r--r-- | gcc/config/mips/mips.h | 11 |
3 files changed, 187 insertions, 51 deletions
diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index abcc2d4..429a621 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -343,5 +343,6 @@ extern void mips_expand_vector_init (rtx, rtx); extern bool mips_eh_uses (unsigned int); extern bool mips_epilogue_uses (unsigned int); extern void mips_final_prescan_insn (rtx, rtx *, int); +extern int mips_trampoline_code_size (void); #endif /* ! GCC_MIPS_PROTOS_H */ diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index cbe8447..e44eb49 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -126,6 +126,40 @@ along with GCC; see the file COPYING3. If not see /* True if bit BIT is set in VALUE. */ #define BITSET_P(VALUE, BIT) (((VALUE) & (1 << (BIT))) != 0) +/* Return the opcode for a ptr_mode load of the form: + + l[wd] DEST, OFFSET(BASE). */ +#define MIPS_LOAD_PTR(DEST, OFFSET, BASE) \ + (((ptr_mode == DImode ? 0x37 : 0x23) << 26) \ + | ((BASE) << 21) \ + | ((DEST) << 16) \ + | (OFFSET)) + +/* Return the opcode to move register SRC into register DEST. */ +#define MIPS_MOVE(DEST, SRC) \ + ((TARGET_64BIT ? 0x2d : 0x21) \ + | ((DEST) << 11) \ + | ((SRC) << 21)) + +/* Return the opcode for: + + lui DEST, VALUE. */ +#define MIPS_LUI(DEST, VALUE) \ + ((0xf << 26) | ((DEST) << 16) | (VALUE)) + +/* Return the opcode to jump to register DEST. */ +#define MIPS_JR(DEST) \ + (((DEST) << 21) | 0x8) + +/* Return the opcode for: + + bal . + (1 + OFFSET) * 4. */ +#define MIPS_BAL(OFFSET) \ + ((0x1 << 26) | (0x11 << 16) | (OFFSET)) + +/* Return the usual opcode for a nop. */ +#define MIPS_NOP 0 + /* Classifies an address. ADDRESS_REG @@ -15889,41 +15923,21 @@ mips_final_postscan_insn (FILE *file ATTRIBUTE_UNUSED, rtx insn, mips_pop_asm_switch (&mips_noat); } -/* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */ +/* Return the size in bytes of the trampoline code, padded to + TRAMPOLINE_ALIGNMENT bits. The static chain pointer and target + function address immediately follow. */ -static void -mips_asm_trampoline_template (FILE *f) -{ - if (ptr_mode == DImode) - fprintf (f, "\t.word\t0x03e0082d\t\t# dmove $1,$31\n"); - else - fprintf (f, "\t.word\t0x03e00821\t\t# move $1,$31\n"); - fprintf (f, "\t.word\t0x04110001\t\t# bgezal $0,.+8\n"); - fprintf (f, "\t.word\t0x00000000\t\t# nop\n"); - if (ptr_mode == DImode) - { - fprintf (f, "\t.word\t0xdff90014\t\t# ld $25,20($31)\n"); - fprintf (f, "\t.word\t0xdfef001c\t\t# ld $15,28($31)\n"); - } - else - { - fprintf (f, "\t.word\t0x8ff90010\t\t# lw $25,16($31)\n"); - fprintf (f, "\t.word\t0x8fef0014\t\t# lw $15,20($31)\n"); - } - fprintf (f, "\t.word\t0x03200008\t\t# jr $25\n"); - if (ptr_mode == DImode) - { - fprintf (f, "\t.word\t0x0020f82d\t\t# dmove $31,$1\n"); - fprintf (f, "\t.word\t0x00000000\t\t# <padding>\n"); - fprintf (f, "\t.dword\t0x00000000\t\t# <function address>\n"); - fprintf (f, "\t.dword\t0x00000000\t\t# <static chain value>\n"); - } +int +mips_trampoline_code_size (void) +{ + if (TARGET_USE_PIC_FN_ADDR_REG) + return 4 * 4; + else if (ptr_mode == DImode) + return 8 * 4; + else if (ISA_HAS_LOAD_DELAY) + return 6 * 4; else - { - fprintf (f, "\t.word\t0x0020f821\t\t# move $31,$1\n"); - fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); - fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); - } + return 4 * 4; } /* Implement TARGET_TRAMPOLINE_INIT. */ @@ -15931,23 +15945,145 @@ mips_asm_trampoline_template (FILE *f) static void mips_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) { - rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); - rtx mem, addr, end_addr; + rtx addr, end_addr, high, low, opcode, mem; + rtx trampoline[8]; + unsigned int i, j; + HOST_WIDE_INT end_addr_offset, static_chain_offset, target_function_offset; + + /* Work out the offsets of the pointers from the start of the + trampoline code. */ + end_addr_offset = mips_trampoline_code_size (); + static_chain_offset = end_addr_offset; + target_function_offset = static_chain_offset + GET_MODE_SIZE (ptr_mode); - emit_block_move (m_tramp, assemble_trampoline_template (), - GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); + /* Get pointers to the beginning and end of the code block. */ + addr = force_reg (Pmode, XEXP (m_tramp, 0)); + end_addr = mips_force_binary (Pmode, PLUS, addr, GEN_INT (end_addr_offset)); - mem = adjust_address (m_tramp, ptr_mode, ptr_mode == DImode ? 32 : 28); - mips_emit_move (mem, force_reg (ptr_mode, fnaddr)); - mem = adjust_address (mem, ptr_mode, GET_MODE_SIZE (ptr_mode)); - mips_emit_move (mem, force_reg (ptr_mode, chain_value)); +#define OP(X) gen_int_mode (X, SImode) - addr = force_reg (ptr_mode, XEXP (m_tramp, 0)); - end_addr = gen_reg_rtx (ptr_mode); + /* Build up the code in TRAMPOLINE. */ + i = 0; + if (TARGET_USE_PIC_FN_ADDR_REG) + { + /* $25 contains the address of the trampoline. Emit code of the form: + + l[wd] $1, target_function_offset($25) + l[wd] $static_chain, static_chain_offset($25) + jr $1 + move $25,$1. */ + trampoline[i++] = OP (MIPS_LOAD_PTR (AT_REGNUM, + target_function_offset, + PIC_FUNCTION_ADDR_REGNUM)); + trampoline[i++] = OP (MIPS_LOAD_PTR (STATIC_CHAIN_REGNUM, + static_chain_offset, + PIC_FUNCTION_ADDR_REGNUM)); + trampoline[i++] = OP (MIPS_JR (AT_REGNUM)); + trampoline[i++] = OP (MIPS_MOVE (PIC_FUNCTION_ADDR_REGNUM, AT_REGNUM)); + } + else if (ptr_mode == DImode) + { + /* It's too cumbersome to create the full 64-bit address, so let's + instead use: + + move $1, $31 + bal 1f + nop + 1: l[wd] $25, target_function_offset - 12($31) + l[wd] $static_chain, static_chain_offset - 12($31) + jr $25 + move $31, $1 + + where 12 is the offset of "1:" from the start of the code block. */ + trampoline[i++] = OP (MIPS_MOVE (AT_REGNUM, RETURN_ADDR_REGNUM)); + trampoline[i++] = OP (MIPS_BAL (1)); + trampoline[i++] = OP (MIPS_NOP); + trampoline[i++] = OP (MIPS_LOAD_PTR (PIC_FUNCTION_ADDR_REGNUM, + target_function_offset - 12, + RETURN_ADDR_REGNUM)); + trampoline[i++] = OP (MIPS_LOAD_PTR (STATIC_CHAIN_REGNUM, + static_chain_offset - 12, + RETURN_ADDR_REGNUM)); + trampoline[i++] = OP (MIPS_JR (PIC_FUNCTION_ADDR_REGNUM)); + trampoline[i++] = OP (MIPS_MOVE (RETURN_ADDR_REGNUM, AT_REGNUM)); + } + else + { + /* If the target has load delays, emit: + + lui $1, %hi(end_addr) + lw $25, %lo(end_addr + ...)($1) + lw $static_chain, %lo(end_addr + ...)($1) + jr $25 + nop + + Otherwise emit: + + lui $1, %hi(end_addr) + lw $25, %lo(end_addr + ...)($1) + jr $25 + lw $static_chain, %lo(end_addr + ...)($1). */ + + /* Split END_ADDR into %hi and %lo values. Trampolines are aligned + to 64 bits, so the %lo value will have the bottom 3 bits clear. */ + high = expand_simple_binop (SImode, PLUS, end_addr, GEN_INT (0x8000), + NULL, false, OPTAB_WIDEN); + high = expand_simple_binop (SImode, LSHIFTRT, high, GEN_INT (16), + NULL, false, OPTAB_WIDEN); + low = convert_to_mode (SImode, gen_lowpart (HImode, end_addr), true); + + /* Emit the LUI. */ + opcode = OP (MIPS_LUI (AT_REGNUM, 0)); + trampoline[i++] = expand_simple_binop (SImode, IOR, opcode, high, + NULL, false, OPTAB_WIDEN); + + /* Emit the load of the target function. */ + opcode = OP (MIPS_LOAD_PTR (PIC_FUNCTION_ADDR_REGNUM, + target_function_offset - end_addr_offset, + AT_REGNUM)); + trampoline[i++] = expand_simple_binop (SImode, IOR, opcode, low, + NULL, false, OPTAB_WIDEN); + + /* Emit the JR here, if we can. */ + if (!ISA_HAS_LOAD_DELAY) + trampoline[i++] = OP (MIPS_JR (PIC_FUNCTION_ADDR_REGNUM)); + + /* Emit the load of the static chain register. */ + opcode = OP (MIPS_LOAD_PTR (STATIC_CHAIN_REGNUM, + static_chain_offset - end_addr_offset, + AT_REGNUM)); + trampoline[i++] = expand_simple_binop (SImode, IOR, opcode, low, + NULL, false, OPTAB_WIDEN); + + /* Emit the JR, if we couldn't above. */ + if (ISA_HAS_LOAD_DELAY) + { + trampoline[i++] = OP (MIPS_JR (PIC_FUNCTION_ADDR_REGNUM)); + trampoline[i++] = OP (MIPS_NOP); + } + } + +#undef OP + + /* Copy the trampoline code. Leave any padding uninitialized. */ + for (j = 0; j < i; j++) + { + mem = adjust_address (m_tramp, SImode, j * GET_MODE_SIZE (SImode)); + mips_emit_move (mem, trampoline[j]); + } + + /* Set up the static chain pointer field. */ + mem = adjust_address (m_tramp, ptr_mode, static_chain_offset); + mips_emit_move (mem, chain_value); + + /* Set up the target function field. */ + mem = adjust_address (m_tramp, ptr_mode, target_function_offset); + mips_emit_move (mem, XEXP (DECL_RTL (fndecl), 0)); + + /* Flush the code part of the trampoline. */ emit_insn (gen_add3_insn (end_addr, addr, GEN_INT (TRAMPOLINE_SIZE))); emit_insn (gen_clear_cache (addr, end_addr)); } - /* Initialize the GCC target structure. */ #undef TARGET_ASM_ALIGNED_HI_OP @@ -16129,8 +16265,6 @@ mips_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) #undef TARGET_CAN_ELIMINATE #define TARGET_CAN_ELIMINATE mips_can_eliminate -#undef TARGET_ASM_TRAMPOLINE_TEMPLATE -#define TARGET_ASM_TRAMPOLINE_TEMPLATE mips_asm_trampoline_template #undef TARGET_TRAMPOLINE_INIT #define TARGET_TRAMPOLINE_INIT mips_trampoline_init diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index b17512f..50bc4ea 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -2433,14 +2433,15 @@ typedef struct mips_args { #define EXIT_IGNORE_STACK 1 -/* A C expression for the size in bytes of the trampoline, as an - integer. */ +/* Trampolines are a block of code followed by two pointers. */ -#define TRAMPOLINE_SIZE (ptr_mode == DImode ? 48 : 36) +#define TRAMPOLINE_SIZE \ + (mips_trampoline_code_size () + GET_MODE_SIZE (ptr_mode) * 2) -/* Alignment required for trampolines, in bits. */ +/* Forcing a 64-bit alignment for 32-bit targets allows us to load two + pointers from a single LUI base. */ -#define TRAMPOLINE_ALIGNMENT GET_MODE_BITSIZE (ptr_mode) +#define TRAMPOLINE_ALIGNMENT 64 /* mips_trampoline_init calls this library function to flush program and data caches. */ |