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