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