diff options
Diffstat (limited to 'gcc/config/rs6000/rs6000.c')
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 149 |
1 files changed, 145 insertions, 4 deletions
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index a87280c8ec4..65de2e3f2fd 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -130,6 +130,9 @@ typedef struct GTY(()) machine_function int ra_need_lr; /* Cache lr_save_p after expansion of builtin_eh_return. */ int lr_save_state; + /* Whether we need to save the TOC to the reserved stack location in the + function prologue. */ + bool save_toc_in_prologue; /* Offset from virtual_stack_vars_rtx to the start of the ABI_V4 varargs save area. */ HOST_WIDE_INT varargs_save_offset; @@ -20325,7 +20328,7 @@ rs6000_emit_prologue (void) JUMP_LABEL (jump) = toc_save_done; LABEL_NUSES (toc_save_done) += 1; - emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, 2, + emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, TOC_REGNUM, sp_offset + 5 * reg_size, info->total_size); emit_label (toc_save_done); if (using_static_chain_p) @@ -20516,6 +20519,11 @@ rs6000_emit_prologue (void) emit_move_insn (lr, gen_rtx_REG (Pmode, 0)); } #endif + + /* If we need to, save the TOC register after doing the stack setup. */ + if (rs6000_save_toc_in_prologue_p ()) + emit_frame_save (sp_reg_rtx, sp_reg_rtx, reg_mode, TOC_REGNUM, + 5 * reg_size, info->total_size); } /* Write function prologue. */ @@ -24469,9 +24477,14 @@ rs6000_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt) /* Under AIX, just build the 3 word function descriptor */ case ABI_AIX: { - rtx fnmem = gen_const_mem (Pmode, force_reg (Pmode, fnaddr)); - rtx fn_reg = gen_reg_rtx (Pmode); - rtx toc_reg = gen_reg_rtx (Pmode); + rtx fnmem, fn_reg, toc_reg; + + if (!TARGET_R11) + error ("-mno-r11 must not be used if you have trampolines"); + + fnmem = gen_const_mem (Pmode, force_reg (Pmode, fnaddr)); + fn_reg = gen_reg_rtx (Pmode); + toc_reg = gen_reg_rtx (Pmode); /* Macro to shorten the code expansions below. */ # define MEM_PLUS(MEM, OFFSET) adjust_address (MEM, Pmode, OFFSET) @@ -27760,4 +27773,132 @@ rs6000_legitimate_constant_p (enum machine_mode mode, rtx x) || easy_vector_constant (x, mode)); } + +/* A function pointer under AIX is a pointer to a data area whose first word + contains the actual address of the function, whose second word contains a + pointer to its TOC, and whose third word contains a value to place in the + static chain register (r11). Note that if we load the static chain, our + "trampoline" need not have any executable code. */ + +void +rs6000_call_indirect_aix (rtx value, rtx func_desc, rtx flag) +{ + rtx func_addr; + rtx toc_reg; + rtx sc_reg; + rtx stack_ptr; + rtx stack_toc_offset; + rtx stack_toc_mem; + rtx func_toc_offset; + rtx func_toc_mem; + rtx func_sc_offset; + rtx func_sc_mem; + rtx insn; + rtx (*call_func) (rtx, rtx, rtx, rtx); + rtx (*call_value_func) (rtx, rtx, rtx, rtx, rtx); + + stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); + toc_reg = gen_rtx_REG (Pmode, TOC_REGNUM); + + /* Load up address of the actual function. */ + func_desc = force_reg (Pmode, func_desc); + func_addr = gen_reg_rtx (Pmode); + emit_move_insn (func_addr, gen_rtx_MEM (Pmode, func_desc)); + + if (TARGET_32BIT) + { + + stack_toc_offset = GEN_INT (TOC_SAVE_OFFSET_32BIT); + func_toc_offset = GEN_INT (AIX_FUNC_DESC_TOC_32BIT); + func_sc_offset = GEN_INT (AIX_FUNC_DESC_SC_32BIT); + if (TARGET_R11) + { + call_func = gen_call_indirect_aix32bit; + call_value_func = gen_call_value_indirect_aix32bit; + } + else + { + call_func = gen_call_indirect_aix32bit_nor11; + call_value_func = gen_call_value_indirect_aix32bit_nor11; + } + } + else + { + stack_toc_offset = GEN_INT (TOC_SAVE_OFFSET_64BIT); + func_toc_offset = GEN_INT (AIX_FUNC_DESC_TOC_64BIT); + func_sc_offset = GEN_INT (AIX_FUNC_DESC_SC_64BIT); + if (TARGET_R11) + { + call_func = gen_call_indirect_aix64bit; + call_value_func = gen_call_value_indirect_aix64bit; + } + else + { + call_func = gen_call_indirect_aix64bit_nor11; + call_value_func = gen_call_value_indirect_aix64bit_nor11; + } + } + + /* Reserved spot to store the TOC. */ + stack_toc_mem = gen_frame_mem (Pmode, + gen_rtx_PLUS (Pmode, + stack_ptr, + stack_toc_offset)); + + gcc_assert (cfun); + gcc_assert (cfun->machine); + + /* Can we optimize saving the TOC in the prologue or do we need to do it at + every call? */ + if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca + && !cfun->calls_setjmp && !cfun->has_nonlocal_label + && !cfun->can_throw_non_call_exceptions + && ((flags_from_decl_or_type (cfun->decl) & ECF_NOTHROW) == ECF_NOTHROW)) + cfun->machine->save_toc_in_prologue = true; + + else + { + MEM_VOLATILE_P (stack_toc_mem) = 1; + emit_move_insn (stack_toc_mem, toc_reg); + } + + /* Calculate the address to load the TOC of the called function. We don't + actually load this until the split after reload. */ + func_toc_mem = gen_rtx_MEM (Pmode, + gen_rtx_PLUS (Pmode, + func_desc, + func_toc_offset)); + + /* If we have a static chain, load it up. */ + if (TARGET_R11) + { + func_sc_mem = gen_rtx_MEM (Pmode, + gen_rtx_PLUS (Pmode, + func_desc, + func_sc_offset)); + + sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM); + emit_move_insn (sc_reg, func_sc_mem); + } + + /* Create the call. */ + if (value) + insn = call_value_func (value, func_addr, flag, func_toc_mem, + stack_toc_mem); + else + insn = call_func (func_addr, flag, func_toc_mem, stack_toc_mem); + + emit_call_insn (insn); + return; +} + +/* Return whether we need to always update the saved TOC pointer when we update + the stack pointer. */ + +bool +rs6000_save_toc_in_prologue_p (void) +{ + return (cfun && cfun->machine && cfun->machine->save_toc_in_prologue); +} + #include "gt-rs6000.h" |