Hi,

Please go ahead and review this.  In the test case
gcc.target/powerpc/notoc-direct-1.c, I accidentally left in '+'
characters in column 1 of the first three lines, which caused the test
case failure.

Bootstrapped and tested on powerpc64le-unknown-linux-gnu with that
fixed.  Is this okay for trunk?

Thanks,
Bill

On 5/24/19 9:06 AM, Bill Schmidt wrote:
> New test case ICEs, so consider this withdrawn.  Sorry again about this.
>
> Bill
>
> On 5/23/19 9:17 PM, Bill Schmidt wrote:
>> Hm, I got ahead of myself on this one.  I haven't done the regstrap yet,
>> so please hold off reviewing for now.
>>
>> Sorry for the noise.  I shouldn't post when I'm tired...
>>
>> Thanks,
>> Bill
>>
>> On 5/23/19 9:11 PM, Bill Schmidt wrote:
>>> 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} } } */
>>>

Reply via email to