summaryrefslogtreecommitdiff
path: root/gcc/config/ia64/ia64.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/ia64/ia64.c')
-rw-r--r--gcc/config/ia64/ia64.c53
1 files changed, 42 insertions, 11 deletions
diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
index 7e757523381..75c8f0ee6c4 100644
--- a/gcc/config/ia64/ia64.c
+++ b/gcc/config/ia64/ia64.c
@@ -302,6 +302,7 @@ static enum machine_mode ia64_promote_function_mode (const_tree,
int *,
const_tree,
int);
+static void ia64_trampoline_init (rtx, tree, rtx);
/* Table of valid machine attributes. */
static const struct attribute_spec ia64_attribute_table[] =
@@ -532,6 +533,9 @@ static const struct attribute_spec ia64_attribute_table[] =
#undef TARGET_CAN_ELIMINATE
#define TARGET_CAN_ELIMINATE ia64_can_eliminate
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT ia64_trampoline_init
+
struct gcc_target targetm = TARGET_INITIALIZER;
typedef enum
@@ -3945,10 +3949,35 @@ ia64_dbx_register_number (int regno)
return regno;
}
-void
-ia64_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain)
+/* Implement TARGET_TRAMPOLINE_INIT.
+
+ The trampoline should set the static chain pointer to value placed
+ into the trampoline and should branch to the specified routine.
+ To make the normal indirect-subroutine calling convention work,
+ the trampoline must look like a function descriptor; the first
+ word being the target address and the second being the target's
+ global pointer.
+
+ We abuse the concept of a global pointer by arranging for it
+ to point to the data we need to load. The complete trampoline
+ has the following form:
+
+ +-------------------+ \
+ TRAMP: | __ia64_trampoline | |
+ +-------------------+ > fake function descriptor
+ | TRAMP+16 | |
+ +-------------------+ /
+ | target descriptor |
+ +-------------------+
+ | static link |
+ +-------------------+
+*/
+
+static void
+ia64_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
{
- rtx addr_reg, tramp, eight = GEN_INT (8);
+ rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+ rtx addr, addr_reg, tramp, eight = GEN_INT (8);
/* The Intel assembler requires that the global __ia64_trampoline symbol
be declared explicitly */
@@ -3965,13 +3994,13 @@ ia64_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain)
}
/* Make sure addresses are Pmode even if we are in ILP32 mode. */
- addr = convert_memory_address (Pmode, addr);
+ addr = convert_memory_address (Pmode, XEXP (m_tramp, 0));
fnaddr = convert_memory_address (Pmode, fnaddr);
static_chain = convert_memory_address (Pmode, static_chain);
/* Load up our iterator. */
- addr_reg = gen_reg_rtx (Pmode);
- emit_move_insn (addr_reg, addr);
+ addr_reg = copy_to_reg (addr);
+ m_tramp = adjust_automodify_address (m_tramp, Pmode, addr_reg, 0);
/* The first two words are the fake descriptor:
__ia64_trampoline, ADDR+16. */
@@ -3989,19 +4018,21 @@ ia64_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain)
emit_move_insn (reg, gen_rtx_MEM (Pmode, reg));
tramp = reg;
}
- emit_move_insn (gen_rtx_MEM (Pmode, addr_reg), tramp);
+ emit_move_insn (m_tramp, tramp);
emit_insn (gen_adddi3 (addr_reg, addr_reg, eight));
+ m_tramp = adjust_automodify_address (m_tramp, VOIDmode, NULL, 8);
- emit_move_insn (gen_rtx_MEM (Pmode, addr_reg),
- copy_to_reg (plus_constant (addr, 16)));
+ emit_move_insn (m_tramp, force_reg (Pmode, plus_constant (addr, 16)));
emit_insn (gen_adddi3 (addr_reg, addr_reg, eight));
+ m_tramp = adjust_automodify_address (m_tramp, VOIDmode, NULL, 8);
/* The third word is the target descriptor. */
- emit_move_insn (gen_rtx_MEM (Pmode, addr_reg), fnaddr);
+ emit_move_insn (m_tramp, force_reg (Pmode, fnaddr));
emit_insn (gen_adddi3 (addr_reg, addr_reg, eight));
+ m_tramp = adjust_automodify_address (m_tramp, VOIDmode, NULL, 8);
/* The fourth word is the static chain. */
- emit_move_insn (gen_rtx_MEM (Pmode, addr_reg), static_chain);
+ emit_move_insn (m_tramp, static_chain);
}
/* Do any needed setup for a variadic function. CUM has not been updated