From e800d6dc2cb329a1b64bb3af136164910778a40c Mon Sep 17 00:00:00 2001 From: Bill Schmidt Date: Wed, 29 May 2019 21:50:09 +0000 Subject: [PATCH] rs6000.c (rs6000_call_template_1): Handle pcrel calls here... [gcc] 2019-05-29 Bill Schmidt Alan Modra * 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 * gcc.target/powerpc/notoc-direct-1.c: New. * gcc.target/powerpc/pcrel-sibcall-1.c: New. Co-Authored-By: Alan Modra From-SVN: r271753 --- gcc/ChangeLog | 30 +++ gcc/config/rs6000/rs6000.c | 242 +++++++++++------- gcc/config/rs6000/rs6000.h | 9 + gcc/config/rs6000/rs6000.md | 93 ++++++- gcc/testsuite/ChangeLog | 5 + .../gcc.target/powerpc/notoc-direct-1.c | 41 +++ .../gcc.target/powerpc/pcrel-sibcall-1.c | 46 ++++ 7 files changed, 368 insertions(+), 98 deletions(-) create mode 100644 gcc/testsuite/gcc.target/powerpc/notoc-direct-1.c create mode 100644 gcc/testsuite/gcc.target/powerpc/pcrel-sibcall-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9a97c91ccd2..cc1b6b4d9fa 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,33 @@ +2019-05-29 Bill Schmidt + Alan Modra + + * 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 * config/i386/sse.md (*save_multiple): Rename from diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 5e861f21bb0..cfc2a6853c1 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 335d75ae85f..f50ae946b32 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 71613e21384..47cbba89443 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_" @@ -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_" @@ -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" + [(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" @@ -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" [(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" + [(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" [(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" + [(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 b8fdc2fae1c..60dc28209e9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-05-29 Bill Schmidt + + * gcc.target/powerpc/notoc-direct-1.c: New. + * gcc.target/powerpc/pcrel-sibcall-1.c: New. + 2019-05-29 Jakub Jelinek 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 00000000000..31497261ddf --- /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 00000000000..7c767e2ba32 --- /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} } } */ -- 2.30.2