Hi, This patch contains the changes to implement call flow for PC-relative addressing. It's an amalgam of several internal patches that Alan and I worked on, and as a result it's hard to tease apart individual pieces much further. So I apologize that this patch is a little larger than the others. Also, I've CC'd Alan so he can help answer questions about the patch, particularly the PLT bits I'm not very familiar with.
Following are descriptions of the individual patches that are combined here. (1) When a function uses PC-relative code generation, all direct calls (other than sibcalls) that the function makes to local or external callees should appear as "bl sym@notoc" and should not be followed by a nop instruction. @notoc indicates that the assembler should annotate the call with R_PPC64_REL24_NOTOC, meaning that the caller does not guarantee that r2 contains a valid TOC pointer. Thus the linker should not try to replace a subsequent "nop" with a TOC restore instruction. I've added a test case for the four cases handled here: local calls with/without a return value, and external cases with/without a return value. (2) If a caller preserves the TOC pointer and the callee does not, or vice versa, then a sibcall will cause an inconsistency. Don't allow that. (3) The linker needs a @notoc directive on sibcall targets when the caller does not provide or preserve a TOC pointer. This patch provides for that. In creating the new sibcall patterns, I did not duplicate the "c" alternatives that allow for bctr or blr sibcalls. I don't think there's a way to generate those currently. The bctr would be legitimate for PC-relative sibcalls if you can prove that the target function is in the same binary, but we don't appear to detect that possibility today. (4) This patch deletes all the extra insns added to handle pcrel calls, instead opting to use existing insns but making their output conditional on rs6000_pcrel_p(cfun). There isn't a need to differentiate between pcrel and non-pcrel calls at the point rtl is created; rs6000_pcrel_p is valid right up to the final pass, as evidenced by use of rs6000_pcrel_p to emit .localentry. There is one case however where we do need new insns: The existing nonlocal indirect call insns mention r2 in their rtl. That isn't correct for pcrel indirect calls, and may cause problems when/if r2 is allocated as any other volatile gpr in pcrel code. The patch also fixes pcrel inline PLT calls (which are used for -fno-plt and -mlongcall) to use a pcrel load from the PLT rather than attempting (and failing) to use TOC-relative loads. This requires some changes in the way relocs are emitted. For prefix insns we can't write .reloc .,R_PPC64_PLT_PCREL34_NOTOC,foo pld 12,0(0),1 since the pld may require a padding nop. Instead it's necessary to put the .reloc after the instruction or use a label on the insn. Like this (which is what the patch does): pld 12,0(0),1 .reloc .-8,R_PPC64_PLT_PCREL34_NOTOC,foo or this: .reloc 0f,R_PPC64_PLT_PCREL34_NOTOC,foo 0: pld 12,0(0),1 Bootstrapped and tested on powerpc64le-unknown-linux-gnu with no regressions. Is this okay for trunk? Thanks! Bill [gcc] 2019-05-23 Bill Schmidt <wschm...@linux.ibm.com> Alan Modra <amo...@gmail.com> * config/rs6000/rs6000.c (rs6000_call_template_1): Handle pcrel calls here... (rs6000_indirect_call_template_1): ...and here. (rs6000_indirect_sibcall_template): Handle plt_pcrel34. Rework tocsave, plt16_ha, plt16_lo, mtctr indirect calls. (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.md (UNSPEC_PLT_PCREL): New unspec. (*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-23 Bill Schmidt <wschm...@linux.ibm.com> * gcc.target/powerpc/notoc-direct-1.c: New. * gcc.target/powerpc/pcrel-sibcall-1.c: New. diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 3d5cf9e4ece..9229bad6acc 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -21268,7 +21268,9 @@ rs6000_call_template_1 (rtx *operands, unsigned int funop, bool sibcall) ? "+32768" : "")); static char str[32]; /* 2 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, 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, @@ -21468,63 +21488,73 @@ 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. */ + WHICH is 0 for tocsave, 1 for plt16_ha, 2 for plt16_lo, 3 for mtctr, + 4 for plt_pcrel34. */ 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 == 4 ? '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: 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: 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: 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: 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 4: + 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 +24733,53 @@ 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 true; + + return false; +} + /* Say whether a function is a candidate for sibcall handling or not. */ static bool @@ -24748,22 +24825,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); @@ -32592,12 +32654,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) @@ -37706,37 +37774,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) @@ -37813,10 +37882,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; } @@ -37866,7 +37937,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.md b/gcc/config/rs6000/rs6000.md index 71613e21384..e1d9045c5bb 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 ]) ;; @@ -10267,6 +10268,20 @@ { return rs6000_pltseq_template (operands, 3); }) + +(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, 4); +} + [(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/gcc.target/powerpc/notoc-direct-1.c b/gcc/testsuite/gcc.target/powerpc/notoc-direct-1.c new file mode 100644 index 00000000000..c7d322c1c96 --- /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} } } */