parent
04543ace47
commit
76594d5318
|
@ -1,3 +1,69 @@
|
|||
2011-07-06 Michael Meissner <meissner@linux.vnet.ibm.com>
|
||||
|
||||
* 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<ptrsize>): Ditto.
|
||||
(call_indirect_aix<ptrsize>_internal): Ditto.
|
||||
(call_indirect_aix<ptrsize>_internal2): Ditto.
|
||||
(call_indirect_aix<ptrsize>_nor11): Ditto.
|
||||
(call_value_indirect_aix<ptrsize>): Ditto.
|
||||
(call_value_indirect_aix<ptrsize>_internal): Ditto.
|
||||
(call_value_indirect_aix<ptrsize>_internal2): Ditto.
|
||||
(call_value_indirect_aix<ptrsize>_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 <jwakely.gcc@gmail.com>
|
||||
|
||||
PR other/49658
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,6 +12373,171 @@
|
|||
[(set_attr "type" "branch")
|
||||
(set_attr "length" "4,8")])
|
||||
|
||||
;; 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_aix<ptrsize>"
|
||||
[(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:P TOC_REGNUM) (match_dup 2))
|
||||
(parallel [(call (mem:SI (match_dup 0))
|
||||
(match_dup 1))
|
||||
(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_aix<ptrsize>_internal"
|
||||
[(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
|
||||
(match_operand 1 "" "g,g"))
|
||||
(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\;<ptrload> 2,%2"
|
||||
[(set_attr "type" "jmpreg")
|
||||
(set_attr "length" "8")])
|
||||
|
||||
;; Like call_indirect_aix<ptrsize>, 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<ptrsize>_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:P TOC_REGNUM) (match_dup 2))
|
||||
(parallel [(call (mem:SI (match_dup 0))
|
||||
(match_dup 1))
|
||||
(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_aix<ptrsize>_internal2"
|
||||
[(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
|
||||
(match_operand 1 "" "g,g"))
|
||||
(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\;<ptrload> 2,%2"
|
||||
[(set_attr "type" "jmpreg")
|
||||
(set_attr "length" "8")])
|
||||
|
||||
;; 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<ptrsize>"
|
||||
[(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<ptrsize>_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\;<ptrload> 2,%3"
|
||||
[(set_attr "type" "jmpreg")
|
||||
(set_attr "length" "8")])
|
||||
|
||||
;; Like call_value_indirect_aix<ptrsize>, 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<ptrsize>_nor11"
|
||||
[(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"))
|
||||
(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 (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<ptrsize>_internal2"
|
||||
[(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 (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\;<ptrload> 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
|
||||
|
@ -12454,42 +12545,6 @@
|
|||
;; variable argument function. It is > 0 if FP registers were passed
|
||||
;; and < 0 if they were not.
|
||||
|
||||
(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"
|
||||
"#"
|
||||
"&& reload_completed"
|
||||
[(set (reg:SI 2)
|
||||
(mem:SI (plus:SI (match_dup 2) (const_int 4))))
|
||||
(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))])]
|
||||
""
|
||||
[(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"))
|
||||
(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)"
|
||||
[(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"))
|
||||
|
@ -12502,43 +12557,6 @@
|
|||
[(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"
|
||||
"#"
|
||||
"&& reload_completed"
|
||||
[(set (reg:DI 2)
|
||||
(mem:DI (plus:DI (match_dup 2) (const_int 8))))
|
||||
(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))])]
|
||||
""
|
||||
[(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"))
|
||||
(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)"
|
||||
[(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"))
|
||||
|
@ -12551,45 +12569,6 @@
|
|||
[(set_attr "type" "branch")
|
||||
(set_attr "length" "8")])
|
||||
|
||||
(define_insn_and_split "*call_value_indirect_nonlocal_aix32_internal"
|
||||
[(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"
|
||||
"#"
|
||||
"&& 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_attr "type" "jmpreg")
|
||||
(set_attr "length" "12")])
|
||||
|
||||
(define_insn "*call_value_indirect_nonlocal_aix32"
|
||||
[(set (match_operand 0 "" "")
|
||||
(call (mem:SI (match_operand:SI 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)"
|
||||
[(set_attr "type" "jmpreg")
|
||||
(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"))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2011-07-06 Michael Meissner <meissner@linux.vnet.ibm.com>
|
||||
|
||||
* 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 <ubizjak@gmail.com>
|
||||
|
||||
* gcc.dg/stack-layout-2.c: Cleanup expand rtl dump.
|
||||
|
|
|
@ -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)" } } */
|
|
@ -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" } } */
|
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue