OSDN Git Service

gcc/
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 5 Oct 2009 19:45:54 +0000 (19:45 +0000)
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 5 Oct 2009 19:45:54 +0000 (19:45 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@152466 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/mips/mips-protos.h
gcc/config/mips/mips.c
gcc/config/mips/mips.h

index 1840726..2f611f0 100644 (file)
@@ -1,5 +1,25 @@
 2009-10-05  Richard Sandiford  <rdsandiford@googlemail.com>
 
+       * 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.
+
+2009-10-05  Richard Sandiford  <rdsandiford@googlemail.com>
+
        * config/mips/mips.h (DWARF_FRAME_RETURN_COLUMN): Replace
        GP_REG_FIRST + 31 with RETURN_ADDR_REGNUM.
        (INCOMING_RETURN_ADDR_RTX): Likewise.
index abcc2d4..429a621 100644 (file)
@@ -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 */
index cbe8447..e44eb49 100644 (file)
@@ -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);
 }
 \f
-/* 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));
 }
-
 \f
 /* 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
 
index b17512f..50bc4ea 100644 (file)
@@ -2433,14 +2433,15 @@ typedef struct mips_args {
 #define EXIT_IGNORE_STACK 1
 
 \f
-/* 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.  */