Commit e800d6dc by Bill Schmidt Committed by William Schmidt

rs6000.c (rs6000_call_template_1): Handle pcrel calls here...

[gcc]

2019-05-29  Bill Schmidt  <wschmidt@linux.ibm.com>
	    Alan Modra  <amodra@gmail.com>

	* config/rs6000/rs6000.c (rs6000_call_template_1): Handle pcrel
	calls here...
	(rs6000_indirect_call_template_1): ...and here.
	(rs6000_pltseq_template): Handle plt_pcrel34.  Rework tocsave,
	plt16_ha, plt16_lo, mtctr indirect calls.  Use
	rs6000_pltseq_enum.
	(rs6000_decl_ok_for_sibcall): New function.
	(rs6000_function_ok_for_sibcall): Refactor.
	(rs6000_longcall_ref): Use UNSPEC_PLT_PCREL when pcrel.
	(rs6000_call_aix): Don't emit toc restore rtl for indirect calls
	when pcrel.  Reorganize.
	(rs6000_sibcall_aix): Don't add r2 to function usage when pcrel.
	* rs6000.h (rs6000_pltseq_enum): New enum.
	* rs6000.md (UNSPEC_PLT_PCREL): New unspec.
	(*pltseq_tocsave): Use rs6000_pltseq_enum.
	(*pltseq_plt16_ha): Likewise.
	(*pltseq_plt16_lo): Likewise.
	(*pltseq_mtctr): Likewise.
	(*pltseq_plt_pcrel): New insn.
	(*call_local_aix): Handle @notoc calls.
	(*call_value_local_aix): Likewise.
	(*call_nonlocal_aix): Adjust lengths for pcrel calls.
	(*call_value_nonlocal_aix): Likewise.
	(*call_indirect_pcrel): New insn.
	(*call_value_indirect_pcrel): Likewise.


[gcc/testsuite]

2019-05-29  Bill Schmidt  <wschmidt@linux.ibm.com>

	* gcc.target/powerpc/notoc-direct-1.c: New.
	* gcc.target/powerpc/pcrel-sibcall-1.c: New.


Co-Authored-By: Alan Modra <amodra@gmail.com>

From-SVN: r271753
parent 874f88c4
2019-05-29 Bill Schmidt <wschmidt@linux.ibm.com>
Alan Modra <amodra@gmail.com>
* config/rs6000/rs6000.c (rs6000_call_template_1): Handle pcrel
calls here...
(rs6000_indirect_call_template_1): ...and here.
(rs6000_pltseq_template): Handle plt_pcrel34. Rework tocsave,
plt16_ha, plt16_lo, mtctr indirect calls. Use
rs6000_pltseq_enum.
(rs6000_decl_ok_for_sibcall): New function.
(rs6000_function_ok_for_sibcall): Refactor.
(rs6000_longcall_ref): Use UNSPEC_PLT_PCREL when pcrel.
(rs6000_call_aix): Don't emit toc restore rtl for indirect calls
when pcrel. Reorganize.
(rs6000_sibcall_aix): Don't add r2 to function usage when pcrel.
* rs6000.h (rs6000_pltseq_enum): New enum.
* rs6000.md (UNSPEC_PLT_PCREL): New unspec.
(*pltseq_tocsave): Use rs6000_pltseq_enum.
(*pltseq_plt16_ha): Likewise.
(*pltseq_plt16_lo): Likewise.
(*pltseq_mtctr): Likewise.
(*pltseq_plt_pcrel): New insn.
(*call_local_aix): Handle @notoc calls.
(*call_value_local_aix): Likewise.
(*call_nonlocal_aix): Adjust lengths for pcrel calls.
(*call_value_nonlocal_aix): Likewise.
(*call_indirect_pcrel): New insn.
(*call_value_indirect_pcrel): Likewise.
2019-05-29 Uroš Bizjak <ubizjak@gmail.com> 2019-05-29 Uroš Bizjak <ubizjak@gmail.com>
* config/i386/sse.md (*save_multiple<mode>): Rename from * config/i386/sse.md (*save_multiple<mode>): Rename from
......
...@@ -21267,8 +21267,10 @@ rs6000_call_template_1 (rtx *operands, unsigned int funop, bool sibcall) ...@@ -21267,8 +21267,10 @@ rs6000_call_template_1 (rtx *operands, unsigned int funop, bool sibcall)
(DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic == 2 (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic == 2
? "+32768" : "")); ? "+32768" : ""));
static char str[32]; /* 2 spare */ static char str[32]; /* 1 spare */
if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2) if (rs6000_pcrel_p (cfun))
sprintf (str, "b%s %s@notoc%s", sibcall ? "" : "l", z, arg);
else if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
sprintf (str, "b%s %s%s%s", sibcall ? "" : "l", z, arg, sprintf (str, "b%s %s%s%s", sibcall ? "" : "l", z, arg,
sibcall ? "" : "\n\tnop"); sibcall ? "" : "\n\tnop");
else if (DEFAULT_ABI == ABI_V4) else if (DEFAULT_ABI == ABI_V4)
...@@ -21333,6 +21335,16 @@ rs6000_indirect_call_template_1 (rtx *operands, unsigned int funop, ...@@ -21333,6 +21335,16 @@ rs6000_indirect_call_template_1 (rtx *operands, unsigned int funop,
/* Currently, funop is either 0 or 1. The maximum string is always /* Currently, funop is either 0 or 1. The maximum string is always
a !speculate 64-bit __tls_get_addr call. a !speculate 64-bit __tls_get_addr call.
ABI_ELFv2, pcrel:
. 27 .reloc .,R_PPC64_TLSGD,%2\n\t
. 35 .reloc .,R_PPC64_PLTSEQ_NOTOC,%z1\n\t
. 9 crset 2\n\t
. 27 .reloc .,R_PPC64_TLSGD,%2\n\t
. 36 .reloc .,R_PPC64_PLTCALL_NOTOC,%z1\n\t
. 8 beq%T1l-
.---
.142
ABI_AIX: ABI_AIX:
. 9 ld 2,%3\n\t . 9 ld 2,%3\n\t
. 27 .reloc .,R_PPC64_TLSGD,%2\n\t . 27 .reloc .,R_PPC64_TLSGD,%2\n\t
...@@ -21398,23 +21410,31 @@ rs6000_indirect_call_template_1 (rtx *operands, unsigned int funop, ...@@ -21398,23 +21410,31 @@ rs6000_indirect_call_template_1 (rtx *operands, unsigned int funop,
gcc_unreachable (); gcc_unreachable ();
} }
const char *notoc = rs6000_pcrel_p (cfun) ? "_NOTOC" : "";
const char *addend = (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT const char *addend = (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT
&& flag_pic == 2 ? "+32768" : ""); && flag_pic == 2 ? "+32768" : "");
if (!speculate) if (!speculate)
{ {
s += sprintf (s, s += sprintf (s,
"%s.reloc .,R_PPC%s_PLTSEQ,%%z%u%s\n\t", "%s.reloc .,R_PPC%s_PLTSEQ%s,%%z%u%s\n\t",
tls, rel64, funop, addend); tls, rel64, notoc, funop, addend);
s += sprintf (s, "crset 2\n\t"); s += sprintf (s, "crset 2\n\t");
} }
s += sprintf (s, s += sprintf (s,
"%s.reloc .,R_PPC%s_PLTCALL,%%z%u%s\n\t", "%s.reloc .,R_PPC%s_PLTCALL%s,%%z%u%s\n\t",
tls, rel64, funop, addend); tls, rel64, notoc, funop, addend);
} }
else if (!speculate) else if (!speculate)
s += sprintf (s, "crset 2\n\t"); s += sprintf (s, "crset 2\n\t");
if (DEFAULT_ABI == ABI_AIX) if (rs6000_pcrel_p (cfun))
{
if (speculate)
sprintf (s, "b%%T%ul", funop);
else
sprintf (s, "beq%%T%ul-", funop);
}
else if (DEFAULT_ABI == ABI_AIX)
{ {
if (speculate) if (speculate)
sprintf (s, sprintf (s,
...@@ -21467,64 +21487,72 @@ rs6000_indirect_sibcall_template (rtx *operands, unsigned int funop) ...@@ -21467,64 +21487,72 @@ rs6000_indirect_sibcall_template (rtx *operands, unsigned int funop)
} }
#if HAVE_AS_PLTSEQ #if HAVE_AS_PLTSEQ
/* Output indirect call insns. /* Output indirect call insns. WHICH identifies the type of sequence. */
WHICH is 0 for tocsave, 1 for plt16_ha, 2 for plt16_lo, 3 for mtctr. */
const char * const char *
rs6000_pltseq_template (rtx *operands, int which) rs6000_pltseq_template (rtx *operands, int which)
{ {
const char *rel64 = TARGET_64BIT ? "64" : ""; const char *rel64 = TARGET_64BIT ? "64" : "";
char tls[28]; char tls[30];
tls[0] = 0; tls[0] = 0;
if (TARGET_TLS_MARKERS && GET_CODE (operands[3]) == UNSPEC) if (TARGET_TLS_MARKERS && GET_CODE (operands[3]) == UNSPEC)
{ {
char off = which == RS6000_PLTSEQ_PLT_PCREL34 ? '8' : '4';
if (XINT (operands[3], 1) == UNSPEC_TLSGD) if (XINT (operands[3], 1) == UNSPEC_TLSGD)
sprintf (tls, ".reloc .,R_PPC%s_TLSGD,%%3\n\t", sprintf (tls, ".reloc .-%c,R_PPC%s_TLSGD,%%3\n\t",
rel64); off, rel64);
else if (XINT (operands[3], 1) == UNSPEC_TLSLD) else if (XINT (operands[3], 1) == UNSPEC_TLSLD)
sprintf (tls, ".reloc .,R_PPC%s_TLSLD,%%&\n\t", sprintf (tls, ".reloc .-%c,R_PPC%s_TLSLD,%%&\n\t",
rel64); off, rel64);
else else
gcc_unreachable (); gcc_unreachable ();
} }
gcc_assert (DEFAULT_ABI == ABI_ELFv2 || DEFAULT_ABI == ABI_V4); gcc_assert (DEFAULT_ABI == ABI_ELFv2 || DEFAULT_ABI == ABI_V4);
static char str[96]; /* 15 spare */ static char str[96]; /* 10 spare */
const char *off = WORDS_BIG_ENDIAN ? "+2" : ""; char off = WORDS_BIG_ENDIAN ? '2' : '4';
const char *addend = (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT const char *addend = (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT
&& flag_pic == 2 ? "+32768" : ""); && flag_pic == 2 ? "+32768" : "");
switch (which) switch (which)
{ {
case 0: case RS6000_PLTSEQ_TOCSAVE:
sprintf (str, sprintf (str,
"%s.reloc .,R_PPC%s_PLTSEQ,%%z2\n\t" "st%s\n\t"
"st%s", "%s.reloc .-4,R_PPC%s_PLTSEQ,%%z2",
tls, rel64, TARGET_64BIT ? "d 2,24(1)" : "w 2,12(1)"); TARGET_64BIT ? "d 2,24(1)" : "w 2,12(1)",
tls, rel64);
break; break;
case 1: case RS6000_PLTSEQ_PLT16_HA:
if (DEFAULT_ABI == ABI_V4 && !flag_pic) if (DEFAULT_ABI == ABI_V4 && !flag_pic)
sprintf (str, sprintf (str,
"%s.reloc .%s,R_PPC%s_PLT16_HA,%%z2\n\t" "lis %%0,0\n\t"
"lis %%0,0", "%s.reloc .-%c,R_PPC%s_PLT16_HA,%%z2",
tls, off, rel64); tls, off, rel64);
else else
sprintf (str, sprintf (str,
"%s.reloc .%s,R_PPC%s_PLT16_HA,%%z2%s\n\t" "addis %%0,%%1,0\n\t"
"addis %%0,%%1,0", "%s.reloc .-%c,R_PPC%s_PLT16_HA,%%z2%s",
tls, off, rel64, addend); tls, off, rel64, addend);
break; break;
case 2: case RS6000_PLTSEQ_PLT16_LO:
sprintf (str, sprintf (str,
"%s.reloc .%s,R_PPC%s_PLT16_LO%s,%%z2%s\n\t" "l%s %%0,0(%%1)\n\t"
"l%s %%0,0(%%1)", "%s.reloc .-%c,R_PPC%s_PLT16_LO%s,%%z2%s",
tls, off, rel64, TARGET_64BIT ? "_DS" : "", addend, TARGET_64BIT ? "d" : "wz",
TARGET_64BIT ? "d" : "wz"); tls, off, rel64, TARGET_64BIT ? "_DS" : "", addend);
break; break;
case 3: case RS6000_PLTSEQ_MTCTR:
sprintf (str, sprintf (str,
"%s.reloc .,R_PPC%s_PLTSEQ,%%z2%s\n\t" "mtctr %%1\n\t"
"mtctr %%1", "%s.reloc .-4,R_PPC%s_PLTSEQ,%%z2%s",
tls, rel64, addend); tls, rel64, addend);
break; break;
case RS6000_PLTSEQ_PLT_PCREL34:
sprintf (str,
"pl%s %%0,0(0),1\n\t"
"%s.reloc .-8,R_PPC%s_PLT_PCREL34_NOTOC,%%z2",
TARGET_64BIT ? "d" : "wz",
tls, rel64);
break;
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
...@@ -24703,6 +24731,52 @@ rs6000_return_addr (int count, rtx frame) ...@@ -24703,6 +24731,52 @@ rs6000_return_addr (int count, rtx frame)
return get_hard_reg_initial_val (Pmode, LR_REGNO); return get_hard_reg_initial_val (Pmode, LR_REGNO);
} }
/* Helper function for rs6000_function_ok_for_sibcall. */
static bool
rs6000_decl_ok_for_sibcall (tree decl)
{
/* Sibcalls are always fine for the Darwin ABI. */
if (DEFAULT_ABI == ABI_DARWIN)
return true;
if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
{
/* Under the AIX or ELFv2 ABIs we can't allow calls to non-local
functions, because the callee may have a different TOC pointer to
the caller and there's no way to ensure we restore the TOC when
we return. */
if (!decl || DECL_EXTERNAL (decl) || DECL_WEAK (decl)
|| !(*targetm.binds_local_p) (decl))
return false;
/* Similarly, if the caller preserves the TOC pointer and the callee
doesn't (or vice versa), proper TOC setup or restoration will be
missed. For example, suppose A, B, and C are in the same binary
and A -> B -> C. A and B preserve the TOC pointer but C does not,
and B -> C is eligible as a sibcall. A will call B through its
local entry point, so A will not restore its TOC itself. B calls
C with a sibcall, so it will not restore the TOC. C does not
preserve the TOC, so it may clobber r2 with impunity. Returning
from C will result in a corrupted TOC for A. */
else if (rs6000_fndecl_pcrel_p (decl) != rs6000_pcrel_p (cfun))
return false;
else
return true;
}
/* With the secure-plt SYSV ABI we can't make non-local calls when
-fpic/PIC because the plt call stubs use r30. */
if (DEFAULT_ABI != ABI_V4
|| (TARGET_SECURE_PLT
&& flag_pic
&& (!decl || !((*targetm.binds_local_p) (decl)))))
return false;
return true;
}
/* Say whether a function is a candidate for sibcall handling or not. */ /* Say whether a function is a candidate for sibcall handling or not. */
static bool static bool
...@@ -24748,22 +24822,7 @@ rs6000_function_ok_for_sibcall (tree decl, tree exp) ...@@ -24748,22 +24822,7 @@ rs6000_function_ok_for_sibcall (tree decl, tree exp)
return false; return false;
} }
/* Under the AIX or ELFv2 ABIs we can't allow calls to non-local if (rs6000_decl_ok_for_sibcall (decl))
functions, because the callee may have a different TOC pointer to
the caller and there's no way to ensure we restore the TOC when
we return. With the secure-plt SYSV ABI we can't make non-local
calls when -fpic/PIC because the plt call stubs use r30. */
if (DEFAULT_ABI == ABI_DARWIN
|| ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
&& decl
&& !DECL_EXTERNAL (decl)
&& !DECL_WEAK (decl)
&& (*targetm.binds_local_p) (decl))
|| (DEFAULT_ABI == ABI_V4
&& (!TARGET_SECURE_PLT
|| !flag_pic
|| (decl
&& (*targetm.binds_local_p) (decl)))))
{ {
tree attr_list = TYPE_ATTRIBUTES (fntype); tree attr_list = TYPE_ATTRIBUTES (fntype);
...@@ -32591,12 +32650,18 @@ rs6000_longcall_ref (rtx call_ref, rtx arg) ...@@ -32591,12 +32650,18 @@ rs6000_longcall_ref (rtx call_ref, rtx arg)
if (TARGET_PLTSEQ) if (TARGET_PLTSEQ)
{ {
rtx base = const0_rtx; rtx base = const0_rtx;
int regno; int regno = 12;
if (DEFAULT_ABI == ABI_ELFv2) if (rs6000_pcrel_p (cfun))
{ {
base = gen_rtx_REG (Pmode, TOC_REGISTER); rtx reg = gen_rtx_REG (Pmode, regno);
regno = 12; rtx u = gen_rtx_UNSPEC (Pmode, gen_rtvec (3, base, call_ref, arg),
UNSPEC_PLT_PCREL);
emit_insn (gen_rtx_SET (reg, u));
return reg;
} }
if (DEFAULT_ABI == ABI_ELFv2)
base = gen_rtx_REG (Pmode, TOC_REGISTER);
else else
{ {
if (flag_pic) if (flag_pic)
...@@ -37705,37 +37770,38 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie) ...@@ -37705,37 +37770,38 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
if (!SYMBOL_REF_P (func) if (!SYMBOL_REF_P (func)
|| (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (func))) || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (func)))
{ {
/* Save the TOC into its reserved slot before the call, if (!rs6000_pcrel_p (cfun))
and prepare to restore it after the call. */
rtx stack_toc_offset = GEN_INT (RS6000_TOC_SAVE_SLOT);
rtx stack_toc_unspec = gen_rtx_UNSPEC (Pmode,
gen_rtvec (1, stack_toc_offset),
UNSPEC_TOCSLOT);
toc_restore = gen_rtx_SET (toc_reg, stack_toc_unspec);
/* 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->machine->save_toc_in_prologue = true;
else
{ {
rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); /* Save the TOC into its reserved slot before the call,
rtx stack_toc_mem = gen_frame_mem (Pmode, and prepare to restore it after the call. */
gen_rtx_PLUS (Pmode, stack_ptr, rtx stack_toc_offset = GEN_INT (RS6000_TOC_SAVE_SLOT);
stack_toc_offset)); rtx stack_toc_unspec = gen_rtx_UNSPEC (Pmode,
MEM_VOLATILE_P (stack_toc_mem) = 1; gen_rtvec (1, stack_toc_offset),
if (is_pltseq_longcall) UNSPEC_TOCSLOT);
toc_restore = gen_rtx_SET (toc_reg, stack_toc_unspec);
/* 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->machine->save_toc_in_prologue = true;
else
{ {
/* Use USPEC_PLTSEQ here to emit every instruction in an rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
inline PLT call sequence with a reloc, enabling the rtx stack_toc_mem = gen_frame_mem (Pmode,
linker to edit the sequence back to a direct call gen_rtx_PLUS (Pmode, stack_ptr,
when that makes sense. */ stack_toc_offset));
rtvec v = gen_rtvec (3, toc_reg, func_desc, tlsarg); MEM_VOLATILE_P (stack_toc_mem) = 1;
rtx mark_toc_reg = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ); if (HAVE_AS_PLTSEQ
emit_insn (gen_rtx_SET (stack_toc_mem, mark_toc_reg)); && DEFAULT_ABI == ABI_ELFv2
&& GET_CODE (func_desc) == SYMBOL_REF)
{
rtvec v = gen_rtvec (3, toc_reg, func_desc, tlsarg);
rtx mark_toc_reg = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
emit_insn (gen_rtx_SET (stack_toc_mem, mark_toc_reg));
}
else
emit_move_insn (stack_toc_mem, toc_reg);
} }
else
emit_move_insn (stack_toc_mem, toc_reg);
} }
if (DEFAULT_ABI == ABI_ELFv2) if (DEFAULT_ABI == ABI_ELFv2)
...@@ -37812,10 +37878,12 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie) ...@@ -37812,10 +37878,12 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
} }
else else
{ {
/* Direct calls use the TOC: for local calls, the callee will /* No TOC register needed for calls from PC-relative callers. */
assume the TOC register is set; for non-local calls, the if (!rs6000_pcrel_p (cfun))
PLT stub needs the TOC register. */ /* Direct calls use the TOC: for local calls, the callee will
abi_reg = toc_reg; assume the TOC register is set; for non-local calls, the
PLT stub needs the TOC register. */
abi_reg = toc_reg;
func_addr = func; func_addr = func;
} }
...@@ -37865,7 +37933,9 @@ rs6000_sibcall_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie) ...@@ -37865,7 +37933,9 @@ rs6000_sibcall_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
insn = emit_call_insn (insn); insn = emit_call_insn (insn);
/* Note use of the TOC register. */ /* Note use of the TOC register. */
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (Pmode, TOC_REGNUM)); if (!rs6000_pcrel_p (cfun))
use_reg (&CALL_INSN_FUNCTION_USAGE (insn),
gen_rtx_REG (Pmode, TOC_REGNUM));
} }
/* Expand code to perform a call under the SYSV4 ABI. */ /* Expand code to perform a call under the SYSV4 ABI. */
...@@ -1490,6 +1490,15 @@ extern enum reg_class rs6000_constraints[RS6000_CONSTRAINT_MAX]; ...@@ -1490,6 +1490,15 @@ extern enum reg_class rs6000_constraints[RS6000_CONSTRAINT_MAX];
#define CALL_LONG 0x00000008 /* always call indirect */ #define CALL_LONG 0x00000008 /* always call indirect */
#define CALL_LIBCALL 0x00000010 /* libcall */ #define CALL_LIBCALL 0x00000010 /* libcall */
/* Identify PLT sequence for rs6000_pltseq_template. */
enum rs6000_pltseq_enum {
RS6000_PLTSEQ_TOCSAVE,
RS6000_PLTSEQ_PLT16_HA,
RS6000_PLTSEQ_PLT16_LO,
RS6000_PLTSEQ_MTCTR,
RS6000_PLTSEQ_PLT_PCREL34
};
#define IS_V4_FP_ARGS(OP) \ #define IS_V4_FP_ARGS(OP) \
((INTVAL (OP) & (CALL_V4_CLEAR_FP_ARGS | CALL_V4_SET_FP_ARGS)) != 0) ((INTVAL (OP) & (CALL_V4_CLEAR_FP_ARGS | CALL_V4_SET_FP_ARGS)) != 0)
......
...@@ -147,6 +147,7 @@ ...@@ -147,6 +147,7 @@
UNSPEC_PLTSEQ UNSPEC_PLTSEQ
UNSPEC_PLT16_HA UNSPEC_PLT16_HA
UNSPEC_PLT16_LO UNSPEC_PLT16_LO
UNSPEC_PLT_PCREL
]) ])
;; ;;
...@@ -10231,7 +10232,7 @@ ...@@ -10231,7 +10232,7 @@
"TARGET_PLTSEQ "TARGET_PLTSEQ
&& DEFAULT_ABI == ABI_ELFv2" && DEFAULT_ABI == ABI_ELFv2"
{ {
return rs6000_pltseq_template (operands, 0); return rs6000_pltseq_template (operands, RS6000_PLTSEQ_TOCSAVE);
}) })
(define_insn "*pltseq_plt16_ha_<mode>" (define_insn "*pltseq_plt16_ha_<mode>"
...@@ -10242,7 +10243,7 @@ ...@@ -10242,7 +10243,7 @@
UNSPEC_PLT16_HA))] UNSPEC_PLT16_HA))]
"TARGET_PLTSEQ" "TARGET_PLTSEQ"
{ {
return rs6000_pltseq_template (operands, 1); return rs6000_pltseq_template (operands, RS6000_PLTSEQ_PLT16_HA);
}) })
(define_insn "*pltseq_plt16_lo_<mode>" (define_insn "*pltseq_plt16_lo_<mode>"
...@@ -10253,7 +10254,7 @@ ...@@ -10253,7 +10254,7 @@
UNSPEC_PLT16_LO))] UNSPEC_PLT16_LO))]
"TARGET_PLTSEQ" "TARGET_PLTSEQ"
{ {
return rs6000_pltseq_template (operands, 2); return rs6000_pltseq_template (operands, RS6000_PLTSEQ_PLT16_LO);
} }
[(set_attr "type" "load")]) [(set_attr "type" "load")])
...@@ -10265,8 +10266,22 @@ ...@@ -10265,8 +10266,22 @@
UNSPEC_PLTSEQ))] UNSPEC_PLTSEQ))]
"TARGET_PLTSEQ" "TARGET_PLTSEQ"
{ {
return rs6000_pltseq_template (operands, 3); return rs6000_pltseq_template (operands, RS6000_PLTSEQ_MTCTR);
}) })
(define_insn "*pltseq_plt_pcrel<mode>"
[(set (match_operand:P 0 "gpc_reg_operand" "=r")
(unspec:P [(match_operand:P 1 "" "")
(match_operand:P 2 "symbol_ref_operand" "s")
(match_operand:P 3 "" "")]
UNSPEC_PLT_PCREL))]
"HAVE_AS_PLTSEQ && TARGET_TLS_MARKERS
&& rs6000_pcrel_p (cfun)"
{
return rs6000_pltseq_template (operands, RS6000_PLTSEQ_PLT_PCREL34);
}
[(set_attr "type" "load")
(set_attr "length" "12")])
;; Call and call_value insns ;; Call and call_value insns
;; For the purposes of expanding calls, Darwin is very similar to SYSV. ;; For the purposes of expanding calls, Darwin is very similar to SYSV.
...@@ -10582,7 +10597,11 @@ ...@@ -10582,7 +10597,11 @@
(match_operand 1)) (match_operand 1))
(clobber (reg:P LR_REGNO))] (clobber (reg:P LR_REGNO))]
"DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2" "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
"bl %z0" {
if (rs6000_pcrel_p (cfun))
return "bl %z0@notoc";
return "bl %z0";
}
[(set_attr "type" "branch")]) [(set_attr "type" "branch")])
(define_insn "*call_value_local_aix<mode>" (define_insn "*call_value_local_aix<mode>"
...@@ -10592,7 +10611,11 @@ ...@@ -10592,7 +10611,11 @@
(clobber (reg:P LR_REGNO))] (clobber (reg:P LR_REGNO))]
"(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2) "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
&& !IS_NOMARK_TLSGETADDR (operands[2])" && !IS_NOMARK_TLSGETADDR (operands[2])"
"bl %z1" {
if (rs6000_pcrel_p (cfun))
return "bl %z1@notoc";
return "bl %z1";
}
[(set_attr "type" "branch")]) [(set_attr "type" "branch")])
;; Call to AIX abi function which may be in another module. ;; Call to AIX abi function which may be in another module.
...@@ -10607,7 +10630,10 @@ ...@@ -10607,7 +10630,10 @@
return rs6000_call_template (operands, 0); return rs6000_call_template (operands, 0);
} }
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set_attr "length" "8")]) (set (attr "length")
(if_then_else (match_test "rs6000_pcrel_p (cfun)")
(const_int 4)
(const_int 8)))])
(define_insn "*call_value_nonlocal_aix<mode>" (define_insn "*call_value_nonlocal_aix<mode>"
[(set (match_operand 0 "" "") [(set (match_operand 0 "" "")
...@@ -10623,11 +10649,14 @@ ...@@ -10623,11 +10649,14 @@
} }
[(set_attr "type" "branch") [(set_attr "type" "branch")
(set (attr "length") (set (attr "length")
(if_then_else (match_test "IS_NOMARK_TLSGETADDR (operands[2])") (plus (if_then_else (match_test "IS_NOMARK_TLSGETADDR (operands[2])")
(if_then_else (match_test "TARGET_CMODEL != CMODEL_SMALL") (if_then_else (match_test "TARGET_CMODEL != CMODEL_SMALL")
(const_int 16) (const_int 8)
(const_int 12)) (const_int 4))
(const_int 8)))]) (const_int 0))
(if_then_else (match_test "rs6000_pcrel_p (cfun)")
(const_int 4)
(const_int 8))))])
;; Call to indirect functions with the AIX abi using a 3 word descriptor. ;; Call to indirect functions with the AIX abi using a 3 word descriptor.
;; Operand0 is the addresss of the function to call ;; Operand0 is the addresss of the function to call
...@@ -10700,6 +10729,21 @@ ...@@ -10700,6 +10729,21 @@
(const_string "12") (const_string "12")
(const_string "8")))]) (const_string "8")))])
(define_insn "*call_indirect_pcrel<mode>"
[(call (mem:SI (match_operand:P 0 "indirect_call_operand" "c,*l,X"))
(match_operand 1))
(clobber (reg:P LR_REGNO))]
"rs6000_pcrel_p (cfun)"
{
return rs6000_indirect_call_template (operands, 0);
}
[(set_attr "type" "jmpreg")
(set (attr "length")
(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
(match_test "which_alternative != 1"))
(const_string "8")
(const_string "4")))])
(define_insn "*call_value_indirect_elfv2<mode>" (define_insn "*call_value_indirect_elfv2<mode>"
[(set (match_operand 0 "" "") [(set (match_operand 0 "" "")
(call (mem:SI (match_operand:P 1 "indirect_call_operand" "c,*l,X")) (call (mem:SI (match_operand:P 1 "indirect_call_operand" "c,*l,X"))
...@@ -10728,6 +10772,31 @@ ...@@ -10728,6 +10772,31 @@
(const_string "12") (const_string "12")
(const_string "8"))))]) (const_string "8"))))])
(define_insn "*call_value_indirect_pcrel<mode>"
[(set (match_operand 0 "" "")
(call (mem:SI (match_operand:P 1 "indirect_call_operand" "c,*l,X"))
(match_operand:P 2 "unspec_tls" "")))
(clobber (reg:P LR_REGNO))]
"rs6000_pcrel_p (cfun)"
{
if (IS_NOMARK_TLSGETADDR (operands[2]))
rs6000_output_tlsargs (operands);
return rs6000_indirect_call_template (operands, 1);
}
[(set_attr "type" "jmpreg")
(set (attr "length")
(plus
(if_then_else (match_test "IS_NOMARK_TLSGETADDR (operands[2])")
(if_then_else (match_test "TARGET_CMODEL != CMODEL_SMALL")
(const_int 8)
(const_int 4))
(const_int 0))
(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
(match_test "which_alternative != 1"))
(const_string "8")
(const_string "4"))))])
;; Call subroutine returning any type. ;; Call subroutine returning any type.
(define_expand "untyped_call" (define_expand "untyped_call"
[(parallel [(call (match_operand 0 "") [(parallel [(call (match_operand 0 "")
......
2019-05-29 Bill Schmidt <wschmidt@linux.ibm.com>
* gcc.target/powerpc/notoc-direct-1.c: New.
* gcc.target/powerpc/pcrel-sibcall-1.c: New.
2019-05-29 Jakub Jelinek <jakub@redhat.com> 2019-05-29 Jakub Jelinek <jakub@redhat.com>
PR c++/90598 PR c++/90598
......
/* { dg-do compile } */
/* { dg-options "-mdejagnu-cpu=future -O2" } */
/* { dg-require-effective-target powerpc_elfv2 } */
/* Test that calls generated from PC-relative code are
annotated with @notoc. */
extern int yy0 (int);
extern void yy1 (int);
int zz0 (void) __attribute__((noinline));
void zz1 (int) __attribute__((noinline));
int xx (void)
{
yy1 (7);
return yy0 (5);
}
int zz0 ()
{
asm ("");
return 16;
};
void zz1 (int a __attribute__((__unused__)))
{
asm ("");
};
int ww (void)
{
zz1 (zz0 ());
return 4;
}
/* { dg-final { scan-assembler {yy1@notoc} } } */
/* { dg-final { scan-assembler {yy0@notoc} } } */
/* { dg-final { scan-assembler {zz1@notoc} } } */
/* { dg-final { scan-assembler {zz0@notoc} } } */
/* { dg-do compile } */
/* { dg-options "-mdejagnu-cpu=future -O2" } */
/* { dg-require-effective-target powerpc_elfv2 } */
/* Test that potential sibcalls are not generated when the caller preserves
the TOC and the callee doesn't, or vice versa. */
int x (void) __attribute__((noinline));
int y (void) __attribute__((noinline));
int xx (void) __attribute__((noinline));
int x (void)
{
return 1;
}
int y (void)
{
return 2;
}
int sib_call (void)
{
return x ();
}
#pragma GCC target ("cpu=power9")
int normal_call (void)
{
return y ();
}
int xx (void)
{
return 1;
}
#pragma GCC target ("cpu=future")
int notoc_call (void)
{
return xx ();
}
/* { dg-final { scan-assembler {\mb x@notoc\M} } } */
/* { dg-final { scan-assembler {\mbl y\M} } } */
/* { dg-final { scan-assembler {\mbl xx@notoc\M} } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment