aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Schmidt <wschmidt@linux.ibm.com>2019-05-29 21:50:09 +0000
committerWilliam Schmidt <wschmidt@gcc.gnu.org>2019-05-29 21:50:09 +0000
commite800d6dc2cb329a1b64bb3af136164910778a40c (patch)
treea01860addae26089649bb9282df8abd616887b77
parent874f88c43bc504d49228f53365d2fd565077ecdd (diff)
downloadgcc-e800d6dc2cb329a1b64bb3af136164910778a40c.zip
gcc-e800d6dc2cb329a1b64bb3af136164910778a40c.tar.gz
gcc-e800d6dc2cb329a1b64bb3af136164910778a40c.tar.bz2
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
-rw-r--r--gcc/ChangeLog30
-rw-r--r--gcc/config/rs6000/rs6000.c242
-rw-r--r--gcc/config/rs6000/rs6000.h9
-rw-r--r--gcc/config/rs6000/rs6000.md93
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.target/powerpc/notoc-direct-1.c41
-rw-r--r--gcc/testsuite/gcc.target/powerpc/pcrel-sibcall-1.c46
7 files changed, 368 insertions, 98 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9a97c91..cc1b6b4 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,33 @@
+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>
* config/i386/sse.md (*save_multiple<mode>): Rename from
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 5e861f2..cfc2a68 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -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
? "+32768" : ""));
- static char str[32]; /* 2 spare */
- if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
+ static char str[32]; /* 1 spare */
+ 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,
sibcall ? "" : "\n\tnop");
else if (DEFAULT_ABI == ABI_V4)
@@ -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
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:
. 9 ld 2,%3\n\t
. 27 .reloc .,R_PPC64_TLSGD,%2\n\t
@@ -21398,23 +21410,31 @@ rs6000_indirect_call_template_1 (rtx *operands, unsigned int funop,
gcc_unreachable ();
}
+ const char *notoc = rs6000_pcrel_p (cfun) ? "_NOTOC" : "";
const char *addend = (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT
&& flag_pic == 2 ? "+32768" : "");
if (!speculate)
{
s += sprintf (s,
- "%s.reloc .,R_PPC%s_PLTSEQ,%%z%u%s\n\t",
- tls, rel64, funop, addend);
+ "%s.reloc .,R_PPC%s_PLTSEQ%s,%%z%u%s\n\t",
+ tls, rel64, notoc, funop, addend);
s += sprintf (s, "crset 2\n\t");
}
s += sprintf (s,
- "%s.reloc .,R_PPC%s_PLTCALL,%%z%u%s\n\t",
- tls, rel64, funop, addend);
+ "%s.reloc .,R_PPC%s_PLTCALL%s,%%z%u%s\n\t",
+ tls, rel64, notoc, funop, addend);
}
else if (!speculate)
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)
sprintf (s,
@@ -21467,64 +21487,72 @@ rs6000_indirect_sibcall_template (rtx *operands, unsigned int funop)
}
#if HAVE_AS_PLTSEQ
-/* Output indirect call insns.
- WHICH is 0 for tocsave, 1 for plt16_ha, 2 for plt16_lo, 3 for mtctr. */
+/* Output indirect call insns. WHICH identifies the type of sequence. */
const char *
rs6000_pltseq_template (rtx *operands, int which)
{
const char *rel64 = TARGET_64BIT ? "64" : "";
- char tls[28];
+ char tls[30];
tls[0] = 0;
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)
- sprintf (tls, ".reloc .,R_PPC%s_TLSGD,%%3\n\t",
- rel64);
+ sprintf (tls, ".reloc .-%c,R_PPC%s_TLSGD,%%3\n\t",
+ off, rel64);
else if (XINT (operands[3], 1) == UNSPEC_TLSLD)
- sprintf (tls, ".reloc .,R_PPC%s_TLSLD,%%&\n\t",
- rel64);
+ sprintf (tls, ".reloc .-%c,R_PPC%s_TLSLD,%%&\n\t",
+ off, rel64);
else
gcc_unreachable ();
}
gcc_assert (DEFAULT_ABI == ABI_ELFv2 || DEFAULT_ABI == ABI_V4);
- static char str[96]; /* 15 spare */
- const char *off = WORDS_BIG_ENDIAN ? "+2" : "";
+ static char str[96]; /* 10 spare */
+ char off = WORDS_BIG_ENDIAN ? '2' : '4';
const char *addend = (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT
&& flag_pic == 2 ? "+32768" : "");
switch (which)
{
- case 0:
+ case RS6000_PLTSEQ_TOCSAVE:
sprintf (str,
- "%s.reloc .,R_PPC%s_PLTSEQ,%%z2\n\t"
- "st%s",
- tls, rel64, TARGET_64BIT ? "d 2,24(1)" : "w 2,12(1)");
+ "st%s\n\t"
+ "%s.reloc .-4,R_PPC%s_PLTSEQ,%%z2",
+ TARGET_64BIT ? "d 2,24(1)" : "w 2,12(1)",
+ tls, rel64);
break;
- case 1:
+ case RS6000_PLTSEQ_PLT16_HA:
if (DEFAULT_ABI == ABI_V4 && !flag_pic)
sprintf (str,
- "%s.reloc .%s,R_PPC%s_PLT16_HA,%%z2\n\t"
- "lis %%0,0",
+ "lis %%0,0\n\t"
+ "%s.reloc .-%c,R_PPC%s_PLT16_HA,%%z2",
tls, off, rel64);
else
sprintf (str,
- "%s.reloc .%s,R_PPC%s_PLT16_HA,%%z2%s\n\t"
- "addis %%0,%%1,0",
+ "addis %%0,%%1,0\n\t"
+ "%s.reloc .-%c,R_PPC%s_PLT16_HA,%%z2%s",
tls, off, rel64, addend);
break;
- case 2:
+ case RS6000_PLTSEQ_PLT16_LO:
sprintf (str,
- "%s.reloc .%s,R_PPC%s_PLT16_LO%s,%%z2%s\n\t"
- "l%s %%0,0(%%1)",
- tls, off, rel64, TARGET_64BIT ? "_DS" : "", addend,
- TARGET_64BIT ? "d" : "wz");
+ "l%s %%0,0(%%1)\n\t"
+ "%s.reloc .-%c,R_PPC%s_PLT16_LO%s,%%z2%s",
+ TARGET_64BIT ? "d" : "wz",
+ tls, off, rel64, TARGET_64BIT ? "_DS" : "", addend);
break;
- case 3:
+ case RS6000_PLTSEQ_MTCTR:
sprintf (str,
- "%s.reloc .,R_PPC%s_PLTSEQ,%%z2%s\n\t"
- "mtctr %%1",
+ "mtctr %%1\n\t"
+ "%s.reloc .-4,R_PPC%s_PLTSEQ,%%z2%s",
tls, rel64, addend);
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:
gcc_unreachable ();
}
@@ -24703,6 +24731,52 @@ rs6000_return_addr (int count, rtx frame)
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. */
static bool
@@ -24748,22 +24822,7 @@ rs6000_function_ok_for_sibcall (tree decl, tree exp)
return false;
}
- /* 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. 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)))))
+ if (rs6000_decl_ok_for_sibcall (decl))
{
tree attr_list = TYPE_ATTRIBUTES (fntype);
@@ -32591,12 +32650,18 @@ rs6000_longcall_ref (rtx call_ref, rtx arg)
if (TARGET_PLTSEQ)
{
rtx base = const0_rtx;
- int regno;
- if (DEFAULT_ABI == ABI_ELFv2)
+ int regno = 12;
+ if (rs6000_pcrel_p (cfun))
{
- base = gen_rtx_REG (Pmode, TOC_REGISTER);
- regno = 12;
+ rtx reg = gen_rtx_REG (Pmode, regno);
+ 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
{
if (flag_pic)
@@ -37705,37 +37770,38 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
if (!SYMBOL_REF_P (func)
|| (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (func)))
{
- /* Save the TOC into its reserved slot before the call,
- 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
+ if (!rs6000_pcrel_p (cfun))
{
- rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
- rtx stack_toc_mem = gen_frame_mem (Pmode,
- gen_rtx_PLUS (Pmode, stack_ptr,
- stack_toc_offset));
- MEM_VOLATILE_P (stack_toc_mem) = 1;
- if (is_pltseq_longcall)
+ /* Save the TOC into its reserved slot before the call,
+ 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
{
- /* Use USPEC_PLTSEQ here to emit every instruction in an
- inline PLT call sequence with a reloc, enabling the
- linker to edit the sequence back to a direct call
- when that makes sense. */
- 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));
+ rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
+ rtx stack_toc_mem = gen_frame_mem (Pmode,
+ gen_rtx_PLUS (Pmode, stack_ptr,
+ stack_toc_offset));
+ MEM_VOLATILE_P (stack_toc_mem) = 1;
+ if (HAVE_AS_PLTSEQ
+ && 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)
@@ -37812,10 +37878,12 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
}
else
{
- /* Direct calls use the TOC: for local calls, the callee will
- assume the TOC register is set; for non-local calls, the
- PLT stub needs the TOC register. */
- abi_reg = toc_reg;
+ /* No TOC register needed for calls from PC-relative callers. */
+ if (!rs6000_pcrel_p (cfun))
+ /* Direct calls use the TOC: for local calls, the callee will
+ assume the TOC register is set; for non-local calls, the
+ PLT stub needs the TOC register. */
+ abi_reg = toc_reg;
func_addr = func;
}
@@ -37865,7 +37933,9 @@ rs6000_sibcall_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
insn = emit_call_insn (insn);
/* 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. */
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 335d75a..f50ae94 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -1490,6 +1490,15 @@ extern enum reg_class rs6000_constraints[RS6000_CONSTRAINT_MAX];
#define CALL_LONG 0x00000008 /* always call indirect */
#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) \
((INTVAL (OP) & (CALL_V4_CLEAR_FP_ARGS | CALL_V4_SET_FP_ARGS)) != 0)
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 71613e2..47cbba8 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -147,6 +147,7 @@
UNSPEC_PLTSEQ
UNSPEC_PLT16_HA
UNSPEC_PLT16_LO
+ UNSPEC_PLT_PCREL
])
;;
@@ -10231,7 +10232,7 @@
"TARGET_PLTSEQ
&& DEFAULT_ABI == ABI_ELFv2"
{
- return rs6000_pltseq_template (operands, 0);
+ return rs6000_pltseq_template (operands, RS6000_PLTSEQ_TOCSAVE);
})
(define_insn "*pltseq_plt16_ha_<mode>"
@@ -10242,7 +10243,7 @@
UNSPEC_PLT16_HA))]
"TARGET_PLTSEQ"
{
- return rs6000_pltseq_template (operands, 1);
+ return rs6000_pltseq_template (operands, RS6000_PLTSEQ_PLT16_HA);
})
(define_insn "*pltseq_plt16_lo_<mode>"
@@ -10253,7 +10254,7 @@
UNSPEC_PLT16_LO))]
"TARGET_PLTSEQ"
{
- return rs6000_pltseq_template (operands, 2);
+ return rs6000_pltseq_template (operands, RS6000_PLTSEQ_PLT16_LO);
}
[(set_attr "type" "load")])
@@ -10265,8 +10266,22 @@
UNSPEC_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
;; For the purposes of expanding calls, Darwin is very similar to SYSV.
@@ -10582,7 +10597,11 @@
(match_operand 1))
(clobber (reg:P LR_REGNO))]
"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")])
(define_insn "*call_value_local_aix<mode>"
@@ -10592,7 +10611,11 @@
(clobber (reg:P LR_REGNO))]
"(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
&& !IS_NOMARK_TLSGETADDR (operands[2])"
- "bl %z1"
+{
+ if (rs6000_pcrel_p (cfun))
+ return "bl %z1@notoc";
+ return "bl %z1";
+}
[(set_attr "type" "branch")])
;; Call to AIX abi function which may be in another module.
@@ -10607,7 +10630,10 @@
return rs6000_call_template (operands, 0);
}
[(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>"
[(set (match_operand 0 "" "")
@@ -10623,11 +10649,14 @@
}
[(set_attr "type" "branch")
(set (attr "length")
- (if_then_else (match_test "IS_NOMARK_TLSGETADDR (operands[2])")
- (if_then_else (match_test "TARGET_CMODEL != CMODEL_SMALL")
- (const_int 16)
- (const_int 12))
- (const_int 8)))])
+ (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 (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.
;; Operand0 is the addresss of the function to call
@@ -10700,6 +10729,21 @@
(const_string "12")
(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>"
[(set (match_operand 0 "" "")
(call (mem:SI (match_operand:P 1 "indirect_call_operand" "c,*l,X"))
@@ -10728,6 +10772,31 @@
(const_string "12")
(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.
(define_expand "untyped_call"
[(parallel [(call (match_operand 0 "")
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index b8fdc2f..60dc282 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+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>
PR c++/90598
diff --git a/gcc/testsuite/gcc.target/powerpc/notoc-direct-1.c b/gcc/testsuite/gcc.target/powerpc/notoc-direct-1.c
new file mode 100644
index 0000000..3149726
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/notoc-direct-1.c
@@ -0,0 +1,41 @@
+/* { 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} } } */
+
diff --git a/gcc/testsuite/gcc.target/powerpc/pcrel-sibcall-1.c b/gcc/testsuite/gcc.target/powerpc/pcrel-sibcall-1.c
new file mode 100644
index 0000000..7c767e2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pcrel-sibcall-1.c
@@ -0,0 +1,46 @@
+/* { 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} } } */