From 76594d53186a78667bbb7b25f9231c396509a0a2 Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Wed, 6 Jul 2011 23:09:20 +0000 Subject: [PATCH] Add -mno-r11 support to PowerPC 64 From-SVN: r175943 --- gcc/ChangeLog | 66 +++++ gcc/config/rs6000/rs6000-protos.h | 2 + gcc/config/rs6000/rs6000.c | 149 +++++++++- gcc/config/rs6000/rs6000.md | 424 ++++++++++++---------------- gcc/config/rs6000/rs6000.opt | 6 + gcc/doc/invoke.texi | 15 +- gcc/testsuite/ChangeLog | 6 + gcc/testsuite/gcc.target/powerpc/no-r11-1.c | 11 + gcc/testsuite/gcc.target/powerpc/no-r11-2.c | 11 + gcc/testsuite/gcc.target/powerpc/no-r11-3.c | 20 ++ 10 files changed, 463 insertions(+), 247 deletions(-) create mode 100644 gcc/testsuite/gcc.target/powerpc/no-r11-1.c create mode 100644 gcc/testsuite/gcc.target/powerpc/no-r11-2.c create mode 100644 gcc/testsuite/gcc.target/powerpc/no-r11-3.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 147b828facf..c9bcc574ec8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,69 @@ +2011-07-06 Michael Meissner + + * config/rs6000/rs6000-protos.h (rs6000_call_indirect_aix): New + declaration. + (rs6000_save_toc_in_prologue_p): Ditto. + + * config/rs6000/rs6000.opt (-mr11): New switch to disable loading + up the static chain (r11) during indirect function calls. + (-msave-toc-indirect): New undocumented debug switch. + + * config/rs6000/rs6000.c (struct machine_function): Add + save_toc_in_prologue field to note whether the prologue needs to + save the TOC value in the reserved stack location. + (rs6000_emit_prologue): Use TOC_REGNUM instead of 2. If we need + to save the TOC in the prologue, do so. + (rs6000_trampoline_init): Don't allow creating AIX style + trampolines if -mno-r11 is in effect. + (rs6000_call_indirect_aix): New function to create AIX style + indirect calls, adding support for -mno-r11 to suppress loading + the static chain, and saving the TOC in the prologue instead of + the call body. + (rs6000_save_toc_in_prologue_p): Return true if we are saving the + TOC in the prologue. + + * config/rs6000/rs6000.md (STACK_POINTER_REGNUM): Add more fixed + register numbers. + (TOC_REGNUM): Ditto. + (STATIC_CHAIN_REGNUM): Ditto. + (ARG_POINTER_REGNUM): Ditto. + (SFP_REGNO): Delete, unused. + (TOC_SAVE_OFFSET_32BIT): Add constants for AIX TOC save and + function descriptor offsets. + (TOC_SAVE_OFFSET_64BIT): Ditto. + (AIX_FUNC_DESC_TOC_32BIT): Ditto. + (AIX_FUNC_DESC_TOC_64BIT): Ditto. + (AIX_FUNC_DESC_SC_32BIT): Ditto. + (AIX_FUNC_DESC_SC_64BIT): Ditto. + (ptrload): New mode attribute for the appropriate load of a + pointer. + (call_indirect_aix32): Delete, rewrite AIX indirect function + calls. + (call_indirect_aix64): Ditto. + (call_value_indirect_aix32): Ditto. + (call_value_indirect_aix64): Ditto. + (call_indirect_nonlocal_aix32_internal): Ditto. + (call_indirect_nonlocal_aix32): Ditto. + (call_indirect_nonlocal_aix64_internal): Ditto. + (call_indirect_nonlocal_aix64): Ditto. + (call): Rewrite AIX indirect function calls. Add support for + eliminating the static chain, and for moving the save of the TOC + to the function prologue. + (call_value): Ditto. + (call_indirect_aix): Ditto. + (call_indirect_aix_internal): Ditto. + (call_indirect_aix_internal2): Ditto. + (call_indirect_aix_nor11): Ditto. + (call_value_indirect_aix): Ditto. + (call_value_indirect_aix_internal): Ditto. + (call_value_indirect_aix_internal2): Ditto. + (call_value_indirect_aix_nor11): Ditto. + (call_nonlocal_aix32): Relocate in the rs6000.md file. + (call_nonlocal_aix64): Ditto. + + * doc/invoke.texi (RS/6000 and PowerPC Options): Add -mr11 and + -mno-r11 documentation. + 2011-07-06 Jonathan Wakely PR other/49658 diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 36f2a4c124a..357f7e72005 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -171,6 +171,8 @@ extern unsigned int rs6000_dbx_register_number (unsigned int); extern void rs6000_emit_epilogue (int); extern void rs6000_emit_eh_reg_restore (rtx, rtx); extern const char * output_isel (rtx *); +extern void rs6000_call_indirect_aix (rtx, rtx, rtx); +extern bool rs6000_save_toc_in_prologue_p (void); extern void rs6000_aix_asm_output_dwarf_table_ref (char *); 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" diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index e70598d9f3e..8c0e299a2e7 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -27,9 +27,14 @@ ;; (define_constants - [(MQ_REGNO 64) + [(STACK_POINTER_REGNUM 1) + (TOC_REGNUM 2) + (STATIC_CHAIN_REGNUM 11) + (HARD_FRAME_POINTER_REGNUM 31) + (MQ_REGNO 64) (LR_REGNO 65) (CTR_REGNO 66) + (ARG_POINTER_REGNUM 67) (CR0_REGNO 68) (CR1_REGNO 69) (CR2_REGNO 70) @@ -46,7 +51,19 @@ (VSCR_REGNO 110) (SPE_ACC_REGNO 111) (SPEFSCR_REGNO 112) - (SFP_REGNO 113) + (FRAME_POINTER_REGNUM 113) + + ; ABI defined stack offsets for storing the TOC pointer with AIX calls. + (TOC_SAVE_OFFSET_32BIT 20) + (TOC_SAVE_OFFSET_64BIT 40) + + ; Function TOC offset in the AIX function descriptor. + (AIX_FUNC_DESC_TOC_32BIT 4) + (AIX_FUNC_DESC_TOC_64BIT 8) + + ; Static chain offset in the AIX function descriptor. + (AIX_FUNC_DESC_SC_32BIT 8) + (AIX_FUNC_DESC_SC_64BIT 16) ]) ;; @@ -267,6 +284,9 @@ (define_mode_attr mptrsize [(SI "si") (DI "di")]) +(define_mode_attr ptrload [(SI "{l|lwz}") + (DI "ld")]) + (define_mode_attr rreg [(SF "f") (DF "ws") (V4SF "wf") @@ -12178,87 +12198,7 @@ "TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL" "{cal %0,%2@l(%1)|addi %0,%1,%2@l}") -;; 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. - -(define_expand "call_indirect_aix32" - [(set (match_dup 2) - (mem:SI (match_operand:SI 0 "gpc_reg_operand" ""))) - (set (mem:SI (plus:SI (reg:SI 1) (const_int 20))) - (reg:SI 2)) - (set (reg:SI 11) - (mem:SI (plus:SI (match_dup 0) - (const_int 8)))) - (parallel [(call (mem:SI (match_dup 2)) - (match_operand 1 "" "")) - (use (mem:SI (plus:SI (match_dup 0) (const_int 4)))) - (use (reg:SI 11)) - (use (mem:SI (plus:SI (reg:SI 1) (const_int 20)))) - (clobber (reg:SI LR_REGNO))])] - "TARGET_32BIT" - " -{ operands[2] = gen_reg_rtx (SImode); }") - -(define_expand "call_indirect_aix64" - [(set (match_dup 2) - (mem:DI (match_operand:DI 0 "gpc_reg_operand" ""))) - (set (mem:DI (plus:DI (reg:DI 1) (const_int 40))) - (reg:DI 2)) - (set (reg:DI 11) - (mem:DI (plus:DI (match_dup 0) - (const_int 16)))) - (parallel [(call (mem:SI (match_dup 2)) - (match_operand 1 "" "")) - (use (mem:DI (plus:DI (match_dup 0) (const_int 8)))) - (use (reg:DI 11)) - (use (mem:DI (plus:DI (reg:DI 1) (const_int 40)))) - (clobber (reg:SI LR_REGNO))])] - "TARGET_64BIT" - " -{ operands[2] = gen_reg_rtx (DImode); }") - -(define_expand "call_value_indirect_aix32" - [(set (match_dup 3) - (mem:SI (match_operand:SI 1 "gpc_reg_operand" ""))) - (set (mem:SI (plus:SI (reg:SI 1) (const_int 20))) - (reg:SI 2)) - (set (reg:SI 11) - (mem:SI (plus:SI (match_dup 1) - (const_int 8)))) - (parallel [(set (match_operand 0 "" "") - (call (mem:SI (match_dup 3)) - (match_operand 2 "" ""))) - (use (mem:SI (plus:SI (match_dup 1) (const_int 4)))) - (use (reg:SI 11)) - (use (mem:SI (plus:SI (reg:SI 1) (const_int 20)))) - (clobber (reg:SI LR_REGNO))])] - "TARGET_32BIT" - " -{ operands[3] = gen_reg_rtx (SImode); }") - -(define_expand "call_value_indirect_aix64" - [(set (match_dup 3) - (mem:DI (match_operand:DI 1 "gpc_reg_operand" ""))) - (set (mem:DI (plus:DI (reg:DI 1) (const_int 40))) - (reg:DI 2)) - (set (reg:DI 11) - (mem:DI (plus:DI (match_dup 1) - (const_int 16)))) - (parallel [(set (match_operand 0 "" "") - (call (mem:SI (match_dup 3)) - (match_operand 2 "" ""))) - (use (mem:DI (plus:DI (match_dup 1) (const_int 8)))) - (use (reg:DI 11)) - (use (mem:DI (plus:DI (reg:DI 1) (const_int 40)))) - (clobber (reg:SI LR_REGNO))])] - "TARGET_64BIT" - " -{ operands[3] = gen_reg_rtx (DImode); }") - -;; Now the definitions for the call and call_value insns +;; Call and call_value insns (define_expand "call" [(parallel [(call (mem:SI (match_operand 0 "address_operand" "")) (match_operand 1 "" "")) @@ -12294,13 +12234,7 @@ case ABI_AIX: /* AIX function pointers are really pointers to a three word area. */ - emit_call_insn (TARGET_32BIT - ? gen_call_indirect_aix32 (force_reg (SImode, - operands[0]), - operands[1]) - : gen_call_indirect_aix64 (force_reg (DImode, - operands[0]), - operands[1])); + rs6000_call_indirect_aix (NULL_RTX, operands[0], operands[1]); DONE; default: @@ -12345,15 +12279,7 @@ case ABI_AIX: /* AIX function pointers are really pointers to a three word area. */ - emit_call_insn (TARGET_32BIT - ? gen_call_value_indirect_aix32 (operands[0], - force_reg (SImode, - operands[1]), - operands[2]) - : gen_call_value_indirect_aix64 (operands[0], - force_reg (DImode, - operands[1]), - operands[2])); + rs6000_call_indirect_aix (operands[0], operands[1], operands[2]); DONE; default: @@ -12447,149 +12373,202 @@ [(set_attr "type" "branch") (set_attr "length" "4,8")]) -;; Call to function which may be in another module. Restore the TOC -;; pointer (r2) after the call unless this is System V. -;; Operand2 is nonzero if we are using the V.4 calling sequence and -;; either the function was not prototyped, or it was prototyped as a -;; variable argument function. It is > 0 if FP registers were passed -;; and < 0 if they were not. +;; Call to indirect functions with the AIX abi using a 3 word descriptor. +;; Operand0 is the addresss of the function to call +;; Operand1 is the flag for System V.4 for unprototyped or FP registers +;; Operand2 is the location in the function descriptor to load r2 from +;; Operand3 is the stack location to hold the current TOC pointer -(define_insn_and_split "*call_indirect_nonlocal_aix32_internal" - [(call (mem:SI (match_operand:SI 0 "register_operand" "c,*l")) - (match_operand 1 "" "g,g")) - (use (mem:SI (plus:SI (match_operand:SI 2 "register_operand" "b,b") (const_int 4)))) - (use (reg:SI 11)) - (use (mem:SI (plus:SI (reg:SI 1) (const_int 20)))) - (clobber (reg:SI LR_REGNO))] - "TARGET_32BIT && DEFAULT_ABI == ABI_AIX" +(define_insn_and_split "call_indirect_aix" + [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l")) + (match_operand 1 "" "g,g")) + (use (match_operand:P 2 "memory_operand" "m,m")) + (use (match_operand:P 3 "memory_operand" "m,m")) + (use (reg:P STATIC_CHAIN_REGNUM)) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_AIX && TARGET_R11" "#" "&& reload_completed" - [(set (reg:SI 2) - (mem:SI (plus:SI (match_dup 2) (const_int 4)))) + [(set (reg:P TOC_REGNUM) (match_dup 2)) (parallel [(call (mem:SI (match_dup 0)) (match_dup 1)) - (use (reg:SI 2)) - (use (reg:SI 11)) - (set (reg:SI 2) - (mem:SI (plus:SI (reg:SI 1) (const_int 20)))) - (clobber (reg:SI LR_REGNO))])] + (use (reg:P TOC_REGNUM)) + (use (reg:P STATIC_CHAIN_REGNUM)) + (use (match_dup 3)) + (set (reg:P TOC_REGNUM) (match_dup 3)) + (clobber (reg:P LR_REGNO))])] "" [(set_attr "type" "jmpreg") (set_attr "length" "12")]) -(define_insn "*call_indirect_nonlocal_aix32" - [(call (mem:SI (match_operand:SI 0 "register_operand" "c,*l")) +(define_insn "*call_indirect_aix_internal" + [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l")) (match_operand 1 "" "g,g")) - (use (reg:SI 2)) - (use (reg:SI 11)) - (set (reg:SI 2) - (mem:SI (plus:SI (reg:SI 1) (const_int 20)))) - (clobber (reg:SI LR_REGNO))] - "TARGET_32BIT && DEFAULT_ABI == ABI_AIX && reload_completed" - "b%T0l\;{l|lwz} 2,20(1)" + (use (reg:P TOC_REGNUM)) + (use (reg:P STATIC_CHAIN_REGNUM)) + (use (match_operand:P 2 "memory_operand" "m,m")) + (set (reg:P TOC_REGNUM) (match_dup 2)) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_AIX && reload_completed && TARGET_R11" + "b%T0l\; 2,%2" [(set_attr "type" "jmpreg") (set_attr "length" "8")]) -(define_insn "*call_nonlocal_aix32" - [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "s")) - (match_operand 1 "" "g")) - (use (match_operand:SI 2 "immediate_operand" "O")) - (clobber (reg:SI LR_REGNO))] - "TARGET_32BIT - && DEFAULT_ABI == ABI_AIX - && (INTVAL (operands[2]) & CALL_LONG) == 0" - "bl %z0\;%." - [(set_attr "type" "branch") - (set_attr "length" "8")]) - -(define_insn_and_split "*call_indirect_nonlocal_aix64_internal" - [(call (mem:SI (match_operand:DI 0 "register_operand" "c,*l")) - (match_operand 1 "" "g,g")) - (use (mem:DI (plus:DI (match_operand:DI 2 "register_operand" "b,b") - (const_int 8)))) - (use (reg:DI 11)) - (use (mem:DI (plus:DI (reg:DI 1) (const_int 40)))) - (clobber (reg:SI LR_REGNO))] - "TARGET_64BIT && DEFAULT_ABI == ABI_AIX" +;; Like call_indirect_aix, except don't load the static chain +;; Operand0 is the addresss of the function to call +;; Operand1 is the flag for System V.4 for unprototyped or FP registers +;; Operand2 is the location in the function descriptor to load r2 from +;; Operand3 is the stack location to hold the current TOC pointer + +(define_insn_and_split "call_indirect_aix_nor11" + [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l")) + (match_operand 1 "" "g,g")) + (use (match_operand:P 2 "memory_operand" "m,m")) + (use (match_operand:P 3 "memory_operand" "m,m")) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_AIX && !TARGET_R11" "#" "&& reload_completed" - [(set (reg:DI 2) - (mem:DI (plus:DI (match_dup 2) (const_int 8)))) + [(set (reg:P TOC_REGNUM) (match_dup 2)) (parallel [(call (mem:SI (match_dup 0)) (match_dup 1)) - (use (reg:DI 2)) - (use (reg:DI 11)) - (set (reg:DI 2) - (mem:DI (plus:DI (reg:DI 1) (const_int 40)))) - (clobber (reg:SI LR_REGNO))])] + (use (reg:P TOC_REGNUM)) + (use (match_dup 3)) + (set (reg:P TOC_REGNUM) (match_dup 3)) + (clobber (reg:P LR_REGNO))])] "" [(set_attr "type" "jmpreg") (set_attr "length" "12")]) -(define_insn "*call_indirect_nonlocal_aix64" - [(call (mem:SI (match_operand:DI 0 "register_operand" "c,*l")) +(define_insn "*call_indirect_aix_internal2" + [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l")) (match_operand 1 "" "g,g")) - (use (reg:DI 2)) - (use (reg:DI 11)) - (set (reg:DI 2) - (mem:DI (plus:DI (reg:DI 1) (const_int 40)))) - (clobber (reg:SI LR_REGNO))] - "TARGET_64BIT && DEFAULT_ABI == ABI_AIX && reload_completed" - "b%T0l\;ld 2,40(1)" + (use (reg:P TOC_REGNUM)) + (use (match_operand:P 2 "memory_operand" "m,m")) + (set (reg:P TOC_REGNUM) (match_dup 2)) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_AIX && reload_completed && !TARGET_R11" + "b%T0l\; 2,%2" [(set_attr "type" "jmpreg") (set_attr "length" "8")]) -(define_insn "*call_nonlocal_aix64" - [(call (mem:SI (match_operand:DI 0 "symbol_ref_operand" "s")) - (match_operand 1 "" "g")) - (use (match_operand:SI 2 "immediate_operand" "O")) - (clobber (reg:SI LR_REGNO))] - "TARGET_64BIT - && DEFAULT_ABI == ABI_AIX - && (INTVAL (operands[2]) & CALL_LONG) == 0" - "bl %z0\;%." - [(set_attr "type" "branch") +;; Operand0 is the return result of the function +;; Operand1 is the addresss of the function to call +;; Operand2 is the flag for System V.4 for unprototyped or FP registers +;; Operand3 is the location in the function descriptor to load r2 from +;; Operand4 is the stack location to hold the current TOC pointer + +(define_insn_and_split "call_value_indirect_aix" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:P 1 "register_operand" "c,*l")) + (match_operand 2 "" "g,g"))) + (use (match_operand:P 3 "memory_operand" "m,m")) + (use (match_operand:P 4 "memory_operand" "m,m")) + (use (reg:P STATIC_CHAIN_REGNUM)) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_AIX && TARGET_R11" + "#" + "&& reload_completed" + [(set (reg:P TOC_REGNUM) (match_dup 3)) + (parallel [(set (match_dup 0) + (call (mem:SI (match_dup 1)) + (match_dup 2))) + (use (reg:P TOC_REGNUM)) + (use (reg:P STATIC_CHAIN_REGNUM)) + (use (match_dup 4)) + (set (reg:P TOC_REGNUM) (match_dup 4)) + (clobber (reg:P LR_REGNO))])] + "" + [(set_attr "type" "jmpreg") + (set_attr "length" "12")]) + +(define_insn "*call_value_indirect_aix_internal" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:P 1 "register_operand" "c,*l")) + (match_operand 2 "" "g,g"))) + (use (reg:P TOC_REGNUM)) + (use (reg:P STATIC_CHAIN_REGNUM)) + (use (match_operand:P 3 "memory_operand" "m,m")) + (set (reg:P TOC_REGNUM) (match_dup 3)) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_AIX && reload_completed && TARGET_R11" + "b%T1l\; 2,%3" + [(set_attr "type" "jmpreg") (set_attr "length" "8")]) -(define_insn_and_split "*call_value_indirect_nonlocal_aix32_internal" +;; Like call_value_indirect_aix, but don't load the static chain +;; Operand0 is the return result of the function +;; Operand1 is the addresss of the function to call +;; Operand2 is the flag for System V.4 for unprototyped or FP registers +;; Operand3 is the location in the function descriptor to load r2 from +;; Operand4 is the stack location to hold the current TOC pointer + +(define_insn_and_split "call_value_indirect_aix_nor11" [(set (match_operand 0 "" "") - (call (mem:SI (match_operand:SI 1 "register_operand" "c,*l")) - (match_operand 2 "" "g,g"))) - (use (mem:SI (plus:SI (match_operand:SI 3 "register_operand" "b,b") - (const_int 4)))) - (use (reg:SI 11)) - (use (mem:SI (plus:SI (reg:SI 1) (const_int 20)))) - (clobber (reg:SI LR_REGNO))] - "TARGET_32BIT && DEFAULT_ABI == ABI_AIX" + (call (mem:SI (match_operand:P 1 "register_operand" "c,*l")) + (match_operand 2 "" "g,g"))) + (use (match_operand:P 3 "memory_operand" "m,m")) + (use (match_operand:P 4 "memory_operand" "m,m")) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_AIX && !TARGET_R11" "#" "&& reload_completed" - [(set (reg:SI 2) - (mem:SI (plus:SI (match_dup 3) (const_int 4)))) - (parallel [(set (match_dup 0) (call (mem:SI (match_dup 1)) - (match_dup 2))) - (use (reg:SI 2)) - (use (reg:SI 11)) - (set (reg:SI 2) - (mem:SI (plus:SI (reg:SI 1) (const_int 20)))) - (clobber (reg:SI LR_REGNO))])] + [(set (reg:P TOC_REGNUM) (match_dup 3)) + (parallel [(set (match_dup 0) + (call (mem:SI (match_dup 1)) + (match_dup 2))) + (use (reg:P TOC_REGNUM)) + (use (match_dup 4)) + (set (reg:P TOC_REGNUM) (match_dup 4)) + (clobber (reg:P LR_REGNO))])] "" [(set_attr "type" "jmpreg") (set_attr "length" "12")]) -(define_insn "*call_value_indirect_nonlocal_aix32" +(define_insn "*call_value_indirect_aix_internal2" [(set (match_operand 0 "" "") - (call (mem:SI (match_operand:SI 1 "register_operand" "c,*l")) + (call (mem:SI (match_operand:P 1 "register_operand" "c,*l")) (match_operand 2 "" "g,g"))) - (use (reg:SI 2)) - (use (reg:SI 11)) - (set (reg:SI 2) - (mem:SI (plus:SI (reg:SI 1) (const_int 20)))) - (clobber (reg:SI LR_REGNO))] - "TARGET_32BIT && DEFAULT_ABI == ABI_AIX && reload_completed" - "b%T1l\;{l|lwz} 2,20(1)" + (use (reg:P TOC_REGNUM)) + (use (match_operand:P 3 "memory_operand" "m,m")) + (set (reg:P TOC_REGNUM) (match_dup 3)) + (clobber (reg:P LR_REGNO))] + "DEFAULT_ABI == ABI_AIX && reload_completed && !TARGET_R11" + "b%T1l\; 2,%3" [(set_attr "type" "jmpreg") (set_attr "length" "8")]) +;; Call to function which may be in another module. Restore the TOC +;; pointer (r2) after the call unless this is System V. +;; Operand2 is nonzero if we are using the V.4 calling sequence and +;; either the function was not prototyped, or it was prototyped as a +;; variable argument function. It is > 0 if FP registers were passed +;; and < 0 if they were not. + +(define_insn "*call_nonlocal_aix32" + [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "s")) + (match_operand 1 "" "g")) + (use (match_operand:SI 2 "immediate_operand" "O")) + (clobber (reg:SI LR_REGNO))] + "TARGET_32BIT + && DEFAULT_ABI == ABI_AIX + && (INTVAL (operands[2]) & CALL_LONG) == 0" + "bl %z0\;%." + [(set_attr "type" "branch") + (set_attr "length" "8")]) + +(define_insn "*call_nonlocal_aix64" + [(call (mem:SI (match_operand:DI 0 "symbol_ref_operand" "s")) + (match_operand 1 "" "g")) + (use (match_operand:SI 2 "immediate_operand" "O")) + (clobber (reg:SI LR_REGNO))] + "TARGET_64BIT + && DEFAULT_ABI == ABI_AIX + && (INTVAL (operands[2]) & CALL_LONG) == 0" + "bl %z0\;%." + [(set_attr "type" "branch") + (set_attr "length" "8")]) + (define_insn "*call_value_nonlocal_aix32" [(set (match_operand 0 "" "") (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "s")) @@ -12603,45 +12582,6 @@ [(set_attr "type" "branch") (set_attr "length" "8")]) -(define_insn_and_split "*call_value_indirect_nonlocal_aix64_internal" - [(set (match_operand 0 "" "") - (call (mem:SI (match_operand:DI 1 "register_operand" "c,*l")) - (match_operand 2 "" "g,g"))) - (use (mem:DI (plus:DI (match_operand:DI 3 "register_operand" "b,b") - (const_int 8)))) - (use (reg:DI 11)) - (use (mem:DI (plus:DI (reg:DI 1) (const_int 40)))) - (clobber (reg:SI LR_REGNO))] - "TARGET_64BIT && DEFAULT_ABI == ABI_AIX" - "#" - "&& reload_completed" - [(set (reg:DI 2) - (mem:DI (plus:DI (match_dup 3) (const_int 8)))) - (parallel [(set (match_dup 0) (call (mem:SI (match_dup 1)) - (match_dup 2))) - (use (reg:DI 2)) - (use (reg:DI 11)) - (set (reg:DI 2) - (mem:DI (plus:DI (reg:DI 1) (const_int 40)))) - (clobber (reg:SI LR_REGNO))])] - "" - [(set_attr "type" "jmpreg") - (set_attr "length" "12")]) - -(define_insn "*call_value_indirect_nonlocal_aix64" - [(set (match_operand 0 "" "") - (call (mem:SI (match_operand:DI 1 "register_operand" "c,*l")) - (match_operand 2 "" "g,g"))) - (use (reg:DI 2)) - (use (reg:DI 11)) - (set (reg:DI 2) - (mem:DI (plus:DI (reg:DI 1) (const_int 40)))) - (clobber (reg:SI LR_REGNO))] - "TARGET_64BIT && DEFAULT_ABI == ABI_AIX && reload_completed" - "b%T1l\;ld 2,40(1)" - [(set_attr "type" "jmpreg") - (set_attr "length" "8")]) - (define_insn "*call_value_nonlocal_aix64" [(set (match_operand 0 "" "") (call (mem:SI (match_operand:DI 1 "symbol_ref_operand" "s")) diff --git a/gcc/config/rs6000/rs6000.opt b/gcc/config/rs6000/rs6000.opt index 35c936fe53e..329104c441c 100644 --- a/gcc/config/rs6000/rs6000.opt +++ b/gcc/config/rs6000/rs6000.opt @@ -521,4 +521,10 @@ mxilinx-fpu Target Var(rs6000_xilinx_fpu) Save Specify Xilinx FPU. +mr11 +Target Report Var(TARGET_R11) Init(1) Save +Use/do not use r11 to hold the static link in calls. +msave-toc-indirect +Target Undocumented Var(TARGET_SAVE_TOC_INDIRECT) Save Init(1) +; Control whether we save the TOC in the prologue for indirect calls or generate the save inline diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index c5e369ac6f8..223a9d525ab 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -807,7 +807,7 @@ See RS/6000 and PowerPC Options. -msdata=@var{opt} -mvxworks -G @var{num} -pthread @gol -mrecip -mrecip=@var{opt} -mno-recip -mrecip-precision @gol -mno-recip-precision @gol --mveclibabi=@var{type} -mfriz -mno-friz} +-mveclibabi=@var{type} -mfriz -mno-friz -mr11 -mno-r11} @emph{RX Options} @gccoptlist{-m64bit-doubles -m32bit-doubles -fpu -nofpu@gol @@ -16325,6 +16325,19 @@ Generate (do not generate) the @code{friz} instruction when the rounding a floating point value to 64-bit integer and back to floating point. The @code{friz} instruction does not return the same value if the floating point number is too large to fit in an integer. + +@item -mr11 +@itemx -mno-r11 +@opindex mr11 +Generate (do not generate) code to load up the static chain register +(@var{r11}) when calling through a pointer on AIX and 64-bit Linux +systems where a function pointer points to a 3 word descriptor giving +the function address, TOC value to be loaded in register @var{r2}, and +static chain value to be loaded in register @var{r11}. The +@option{-mr11} is on by default. You will not be able to call through +pointers to nested functions or pointers to functions compiled in +other languages that use the static chain if you use the +@option{-mno-r11}. @end table @node RX Options diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 6ca307d68ed..f176a448cb5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2011-07-06 Michael Meissner + + * gcc.target/powerpc/no-r11-1.c: New test for -mr11, -mno-r11. + * gcc.target/powerpc/no-r11-2.c: Ditto. + * gcc.target/powerpc/no-r11-3.c: Ditto. + 2011-07-06 Uros Bizjak * gcc.dg/stack-layout-2.c: Cleanup expand rtl dump. diff --git a/gcc/testsuite/gcc.target/powerpc/no-r11-1.c b/gcc/testsuite/gcc.target/powerpc/no-r11-1.c new file mode 100644 index 00000000000..7e880e7d861 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/no-r11-1.c @@ -0,0 +1,11 @@ +/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */ +/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */ +/* { dg-options "-O2 -mno-r11" } */ + +int +call_ptr (int (func) (void)) +{ + return func () + 1; +} + +/* { dg-final { scan-assembler-not "ld 11,16(3)" } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/no-r11-2.c b/gcc/testsuite/gcc.target/powerpc/no-r11-2.c new file mode 100644 index 00000000000..981bc0c954c --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/no-r11-2.c @@ -0,0 +1,11 @@ +/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */ +/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */ +/* { dg-options "-O2 -mr11" } */ + +int +call_ptr (int (func) (void)) +{ + return func () + 1; +} + +/* { dg-final { scan-assembler "ld 11,16" } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/no-r11-3.c b/gcc/testsuite/gcc.target/powerpc/no-r11-3.c new file mode 100644 index 00000000000..bc57385ca4e --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/no-r11-3.c @@ -0,0 +1,20 @@ +/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */ +/* { dg-skip-if "" { *-*-darwin* } { "*" } { "" } } */ +/* { dg-options "-O2 -mno-r11" } */ + +extern void ext_call (int (func) (void)); + +int +outer_func (int init) /* { dg-error "-mno-r11 must not be used if you have trampolines" "" } */ +{ + int value = init; + + int inner (void) + { + return ++value; + } + + ext_call (inner); + return value; +} + -- 2.11.4.GIT