rs6000.c (rs6000_call_template_1): Handle pcrel calls here...
authorBill Schmidt <wschmidt@linux.ibm.com>
Wed, 29 May 2019 21:50:09 +0000 (21:50 +0000)
committerWilliam Schmidt <wschmidt@gcc.gnu.org>
Wed, 29 May 2019 21:50:09 +0000 (21:50 +0000)
[gcc]

2019-05-29  Bill Schmidt  <wschmidt@linux.ibm.com>
    Alan Modra  <amodra@gmail.com>

* config/rs6000/rs6000.c (rs6000_call_template_1): Handle pcrel
calls here...
(rs6000_indirect_call_template_1): ...and here.
(rs6000_pltseq_template): Handle plt_pcrel34.  Rework tocsave,
plt16_ha, plt16_lo, mtctr indirect calls.  Use
rs6000_pltseq_enum.
(rs6000_decl_ok_for_sibcall): New function.
(rs6000_function_ok_for_sibcall): Refactor.
(rs6000_longcall_ref): Use UNSPEC_PLT_PCREL when pcrel.
(rs6000_call_aix): Don't emit toc restore rtl for indirect calls
when pcrel.  Reorganize.
(rs6000_sibcall_aix): Don't add r2 to function usage when pcrel.
* rs6000.h (rs6000_pltseq_enum): New enum.
* rs6000.md (UNSPEC_PLT_PCREL): New unspec.
(*pltseq_tocsave): Use rs6000_pltseq_enum.
(*pltseq_plt16_ha): Likewise.
(*pltseq_plt16_lo): Likewise.
(*pltseq_mtctr): Likewise.
(*pltseq_plt_pcrel): New insn.
(*call_local_aix): Handle @notoc calls.
(*call_value_local_aix): Likewise.
(*call_nonlocal_aix): Adjust lengths for pcrel calls.
(*call_value_nonlocal_aix): Likewise.
(*call_indirect_pcrel): New insn.
(*call_value_indirect_pcrel): Likewise.

[gcc/testsuite]

2019-05-29  Bill Schmidt  <wschmidt@linux.ibm.com>

* gcc.target/powerpc/notoc-direct-1.c: New.
* gcc.target/powerpc/pcrel-sibcall-1.c: New.

Co-Authored-By: Alan Modra <amodra@gmail.com>
From-SVN: r271753

gcc/ChangeLog
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h
gcc/config/rs6000/rs6000.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/powerpc/notoc-direct-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/pcrel-sibcall-1.c [new file with mode: 0644]

index 9a97c91ccd2918b2fedc69834002a1bd369b6ba3..cc1b6b4d9fa6b4e4344915239a2a58c8c56b275f 100644 (file)
@@ -1,3 +1,33 @@
+2019-05-29  Bill Schmidt  <wschmidt@linux.ibm.com>
+           Alan Modra  <amodra@gmail.com>
+
+       * config/rs6000/rs6000.c (rs6000_call_template_1): Handle pcrel
+       calls here...
+       (rs6000_indirect_call_template_1): ...and here.
+       (rs6000_pltseq_template): Handle plt_pcrel34.  Rework tocsave,
+       plt16_ha, plt16_lo, mtctr indirect calls.  Use
+       rs6000_pltseq_enum.
+       (rs6000_decl_ok_for_sibcall): New function.
+       (rs6000_function_ok_for_sibcall): Refactor.
+       (rs6000_longcall_ref): Use UNSPEC_PLT_PCREL when pcrel.
+       (rs6000_call_aix): Don't emit toc restore rtl for indirect calls
+       when pcrel.  Reorganize.
+       (rs6000_sibcall_aix): Don't add r2 to function usage when pcrel.
+       * rs6000.h (rs6000_pltseq_enum): New enum.
+       * rs6000.md (UNSPEC_PLT_PCREL): New unspec.
+       (*pltseq_tocsave): Use rs6000_pltseq_enum.
+       (*pltseq_plt16_ha): Likewise.
+       (*pltseq_plt16_lo): Likewise.
+       (*pltseq_mtctr): Likewise.
+       (*pltseq_plt_pcrel): New insn.
+       (*call_local_aix): Handle @notoc calls.
+       (*call_value_local_aix): Likewise.
+       (*call_nonlocal_aix): Adjust lengths for pcrel calls.
+       (*call_value_nonlocal_aix): Likewise.
+       (*call_indirect_pcrel): New insn.
+       (*call_value_indirect_pcrel): Likewise.
+
+
 2019-05-29  Uroš Bizjak  <ubizjak@gmail.com>
 
        * config/i386/sse.md (*save_multiple<mode>): Rename from
index 5e861f21bb06382d66f48fa0e461b1eb3c0813e0..cfc2a6853c1fb0ee15fd66daf128de19fea60cf5 100644 (file)
@@ -21267,8 +21267,10 @@ rs6000_call_template_1 (rtx *operands, unsigned int funop, bool sibcall)
           (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic == 2
            ? "+32768" : ""));
 
-  static char str[32];  /* 2 spare */
-  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
+  static char str[32];  /* 1 spare */
+  if (rs6000_pcrel_p (cfun))
+    sprintf (str, "b%s %s@notoc%s", sibcall ? "" : "l", z, arg);
+  else if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
     sprintf (str, "b%s %s%s%s", sibcall ? "" : "l", z, arg,
             sibcall ? "" : "\n\tnop");
   else if (DEFAULT_ABI == ABI_V4)
@@ -21333,6 +21335,16 @@ rs6000_indirect_call_template_1 (rtx *operands, unsigned int funop,
   /* Currently, funop is either 0 or 1.  The maximum string is always
      a !speculate 64-bit __tls_get_addr call.
 
+     ABI_ELFv2, pcrel:
+     . 27      .reloc .,R_PPC64_TLSGD,%2\n\t
+     . 35      .reloc .,R_PPC64_PLTSEQ_NOTOC,%z1\n\t
+     .  9      crset 2\n\t
+     . 27      .reloc .,R_PPC64_TLSGD,%2\n\t
+     . 36      .reloc .,R_PPC64_PLTCALL_NOTOC,%z1\n\t
+     .  8      beq%T1l-
+     .---
+     .142
+
      ABI_AIX:
      .  9      ld 2,%3\n\t
      . 27      .reloc .,R_PPC64_TLSGD,%2\n\t
@@ -21398,23 +21410,31 @@ rs6000_indirect_call_template_1 (rtx *operands, unsigned int funop,
            gcc_unreachable ();
        }
 
+      const char *notoc = rs6000_pcrel_p (cfun) ? "_NOTOC" : "";
       const char *addend = (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT
                            && flag_pic == 2 ? "+32768" : "");
       if (!speculate)
        {
          s += sprintf (s,
-                       "%s.reloc .,R_PPC%s_PLTSEQ,%%z%u%s\n\t",
-                       tls, rel64, funop, addend);
+                       "%s.reloc .,R_PPC%s_PLTSEQ%s,%%z%u%s\n\t",
+                       tls, rel64, notoc, funop, addend);
          s += sprintf (s, "crset 2\n\t");
        }
       s += sprintf (s,
-                   "%s.reloc .,R_PPC%s_PLTCALL,%%z%u%s\n\t",
-                   tls, rel64, funop, addend);
+                   "%s.reloc .,R_PPC%s_PLTCALL%s,%%z%u%s\n\t",
+                   tls, rel64, notoc, funop, addend);
     }
   else if (!speculate)
     s += sprintf (s, "crset 2\n\t");
 
-  if (DEFAULT_ABI == ABI_AIX)
+  if (rs6000_pcrel_p (cfun))
+    {
+      if (speculate)
+       sprintf (s, "b%%T%ul", funop);
+      else
+       sprintf (s, "beq%%T%ul-", funop);
+    }
+  else if (DEFAULT_ABI == ABI_AIX)
     {
       if (speculate)
        sprintf (s,
@@ -21467,64 +21487,72 @@ rs6000_indirect_sibcall_template (rtx *operands, unsigned int funop)
 }
 
 #if HAVE_AS_PLTSEQ
-/* Output indirect call insns.
-   WHICH is 0 for tocsave, 1 for plt16_ha, 2 for plt16_lo, 3 for mtctr.  */
+/* Output indirect call insns.  WHICH identifies the type of sequence.  */
 const char *
 rs6000_pltseq_template (rtx *operands, int which)
 {
   const char *rel64 = TARGET_64BIT ? "64" : "";
-  char tls[28];
+  char tls[30];
   tls[0] = 0;
   if (TARGET_TLS_MARKERS && GET_CODE (operands[3]) == UNSPEC)
     {
+      char off = which == RS6000_PLTSEQ_PLT_PCREL34 ? '8' : '4';
       if (XINT (operands[3], 1) == UNSPEC_TLSGD)
-       sprintf (tls, ".reloc .,R_PPC%s_TLSGD,%%3\n\t",
-                rel64);
+       sprintf (tls, ".reloc .-%c,R_PPC%s_TLSGD,%%3\n\t",
+                off, rel64);
       else if (XINT (operands[3], 1) == UNSPEC_TLSLD)
-       sprintf (tls, ".reloc .,R_PPC%s_TLSLD,%%&\n\t",
-                rel64);
+       sprintf (tls, ".reloc .-%c,R_PPC%s_TLSLD,%%&\n\t",
+                off, rel64);
       else
        gcc_unreachable ();
     }
 
   gcc_assert (DEFAULT_ABI == ABI_ELFv2 || DEFAULT_ABI == ABI_V4);
-  static char str[96];  /* 15 spare */
-  const char *off = WORDS_BIG_ENDIAN ? "+2" : "";
+  static char str[96];  /* 10 spare */
+  char off = WORDS_BIG_ENDIAN ? '2' : '4';
   const char *addend = (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT
                        && flag_pic == 2 ? "+32768" : "");
   switch (which)
     {
-    case 0:
+    case RS6000_PLTSEQ_TOCSAVE:
       sprintf (str,
-              "%s.reloc .,R_PPC%s_PLTSEQ,%%z2\n\t"
-              "st%s",
-              tls, rel64, TARGET_64BIT ? "d 2,24(1)" : "w 2,12(1)");
+              "st%s\n\t"
+              "%s.reloc .-4,R_PPC%s_PLTSEQ,%%z2",
+              TARGET_64BIT ? "d 2,24(1)" : "w 2,12(1)",
+              tls, rel64);
       break;
-    case 1:
+    case RS6000_PLTSEQ_PLT16_HA:
       if (DEFAULT_ABI == ABI_V4 && !flag_pic)
        sprintf (str,
-                "%s.reloc .%s,R_PPC%s_PLT16_HA,%%z2\n\t"
-                "lis %%0,0",
+                "lis %%0,0\n\t"
+                "%s.reloc .-%c,R_PPC%s_PLT16_HA,%%z2",
                 tls, off, rel64);
       else
        sprintf (str,
-                "%s.reloc .%s,R_PPC%s_PLT16_HA,%%z2%s\n\t"
-                "addis %%0,%%1,0",
+                "addis %%0,%%1,0\n\t"
+                "%s.reloc .-%c,R_PPC%s_PLT16_HA,%%z2%s",
                 tls, off, rel64, addend);
       break;
-    case 2:
+    case RS6000_PLTSEQ_PLT16_LO:
       sprintf (str,
-              "%s.reloc .%s,R_PPC%s_PLT16_LO%s,%%z2%s\n\t"
-              "l%s %%0,0(%%1)",
-              tls, off, rel64, TARGET_64BIT ? "_DS" : "", addend,
-              TARGET_64BIT ? "d" : "wz");
+              "l%s %%0,0(%%1)\n\t"
+              "%s.reloc .-%c,R_PPC%s_PLT16_LO%s,%%z2%s",
+              TARGET_64BIT ? "d" : "wz",
+              tls, off, rel64, TARGET_64BIT ? "_DS" : "", addend);
       break;
-    case 3:
+    case RS6000_PLTSEQ_MTCTR:
       sprintf (str,
-              "%s.reloc .,R_PPC%s_PLTSEQ,%%z2%s\n\t"
-              "mtctr %%1",
+              "mtctr %%1\n\t"
+              "%s.reloc .-4,R_PPC%s_PLTSEQ,%%z2%s",
               tls, rel64, addend);
       break;
+    case RS6000_PLTSEQ_PLT_PCREL34:
+      sprintf (str,
+              "pl%s %%0,0(0),1\n\t"
+              "%s.reloc .-8,R_PPC%s_PLT_PCREL34_NOTOC,%%z2",
+              TARGET_64BIT ? "d" : "wz",
+              tls, rel64);
+      break;
     default:
       gcc_unreachable ();
     }
@@ -24703,6 +24731,52 @@ rs6000_return_addr (int count, rtx frame)
   return get_hard_reg_initial_val (Pmode, LR_REGNO);
 }
 
+/* Helper function for rs6000_function_ok_for_sibcall.  */
+
+static bool
+rs6000_decl_ok_for_sibcall (tree decl)
+{
+  /* Sibcalls are always fine for the Darwin ABI.  */
+  if (DEFAULT_ABI == ABI_DARWIN)
+    return true;
+
+  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
+    {
+      /* Under the AIX or ELFv2 ABIs we can't allow calls to non-local
+        functions, because the callee may have a different TOC pointer to
+        the caller and there's no way to ensure we restore the TOC when
+        we return.  */
+      if (!decl || DECL_EXTERNAL (decl) || DECL_WEAK (decl)
+         || !(*targetm.binds_local_p) (decl))
+       return false;
+
+      /* Similarly, if the caller preserves the TOC pointer and the callee
+        doesn't (or vice versa), proper TOC setup or restoration will be
+        missed.  For example, suppose A, B, and C are in the same binary
+        and A -> B -> C.  A and B preserve the TOC pointer but C does not,
+        and B -> C is eligible as a sibcall.  A will call B through its
+        local entry point, so A will not restore its TOC itself.  B calls
+        C with a sibcall, so it will not restore the TOC.  C does not
+        preserve the TOC, so it may clobber r2 with impunity.  Returning
+        from C will result in a corrupted TOC for A.  */
+      else if (rs6000_fndecl_pcrel_p (decl) != rs6000_pcrel_p (cfun))
+       return false;
+
+      else
+       return true;
+    }
+
+  /*  With the secure-plt SYSV ABI we can't make non-local calls when
+      -fpic/PIC because the plt call stubs use r30.  */
+  if (DEFAULT_ABI != ABI_V4
+      || (TARGET_SECURE_PLT
+         && flag_pic
+         && (!decl || !((*targetm.binds_local_p) (decl)))))
+    return false;
+
+  return true;
+}
+
 /* Say whether a function is a candidate for sibcall handling or not.  */
 
 static bool
@@ -24748,22 +24822,7 @@ rs6000_function_ok_for_sibcall (tree decl, tree exp)
        return false;
     }
 
-  /* Under the AIX or ELFv2 ABIs we can't allow calls to non-local
-     functions, because the callee may have a different TOC pointer to
-     the caller and there's no way to ensure we restore the TOC when
-     we return.  With the secure-plt SYSV ABI we can't make non-local
-     calls when -fpic/PIC because the plt call stubs use r30.  */
-  if (DEFAULT_ABI == ABI_DARWIN
-      || ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
-         && decl
-         && !DECL_EXTERNAL (decl)
-         && !DECL_WEAK (decl)
-         && (*targetm.binds_local_p) (decl))
-      || (DEFAULT_ABI == ABI_V4
-         && (!TARGET_SECURE_PLT
-             || !flag_pic
-             || (decl
-                 && (*targetm.binds_local_p) (decl)))))
+  if (rs6000_decl_ok_for_sibcall (decl))
     {
       tree attr_list = TYPE_ATTRIBUTES (fntype);
 
@@ -32591,12 +32650,18 @@ rs6000_longcall_ref (rtx call_ref, rtx arg)
   if (TARGET_PLTSEQ)
     {
       rtx base = const0_rtx;
-      int regno;
-      if (DEFAULT_ABI == ABI_ELFv2)
+      int regno = 12;
+      if (rs6000_pcrel_p (cfun))
        {
-         base = gen_rtx_REG (Pmode, TOC_REGISTER);
-         regno = 12;
+         rtx reg = gen_rtx_REG (Pmode, regno);
+         rtx u = gen_rtx_UNSPEC (Pmode, gen_rtvec (3, base, call_ref, arg),
+                                 UNSPEC_PLT_PCREL);
+         emit_insn (gen_rtx_SET (reg, u));
+         return reg;
        }
+
+      if (DEFAULT_ABI == ABI_ELFv2)
+       base = gen_rtx_REG (Pmode, TOC_REGISTER);
       else
        {
          if (flag_pic)
@@ -37705,37 +37770,38 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
   if (!SYMBOL_REF_P (func)
       || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (func)))
     {
-      /* Save the TOC into its reserved slot before the call,
-        and prepare to restore it after the call.  */
-      rtx stack_toc_offset = GEN_INT (RS6000_TOC_SAVE_SLOT);
-      rtx stack_toc_unspec = gen_rtx_UNSPEC (Pmode,
-                                            gen_rtvec (1, stack_toc_offset),
-                                            UNSPEC_TOCSLOT);
-      toc_restore = gen_rtx_SET (toc_reg, stack_toc_unspec);
-
-      /* Can we optimize saving the TOC in the prologue or
-        do we need to do it at every call?  */
-      if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca)
-       cfun->machine->save_toc_in_prologue = true;
-      else
+      if (!rs6000_pcrel_p (cfun))
        {
-         rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
-         rtx stack_toc_mem = gen_frame_mem (Pmode,
-                                            gen_rtx_PLUS (Pmode, stack_ptr,
-                                                          stack_toc_offset));
-         MEM_VOLATILE_P (stack_toc_mem) = 1;
-         if (is_pltseq_longcall)
+         /* Save the TOC into its reserved slot before the call,
+            and prepare to restore it after the call.  */
+         rtx stack_toc_offset = GEN_INT (RS6000_TOC_SAVE_SLOT);
+         rtx stack_toc_unspec = gen_rtx_UNSPEC (Pmode,
+                                                gen_rtvec (1, stack_toc_offset),
+                                                UNSPEC_TOCSLOT);
+         toc_restore = gen_rtx_SET (toc_reg, stack_toc_unspec);
+
+         /* Can we optimize saving the TOC in the prologue or
+            do we need to do it at every call?  */
+         if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca)
+           cfun->machine->save_toc_in_prologue = true;
+         else
            {
-             /* Use USPEC_PLTSEQ here to emit every instruction in an
-                inline PLT call sequence with a reloc, enabling the
-                linker to edit the sequence back to a direct call
-                when that makes sense.  */
-             rtvec v = gen_rtvec (3, toc_reg, func_desc, tlsarg);
-             rtx mark_toc_reg = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
-             emit_insn (gen_rtx_SET (stack_toc_mem, mark_toc_reg));
+             rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
+             rtx stack_toc_mem = gen_frame_mem (Pmode,
+                                                gen_rtx_PLUS (Pmode, stack_ptr,
+                                                              stack_toc_offset));
+             MEM_VOLATILE_P (stack_toc_mem) = 1;
+             if (HAVE_AS_PLTSEQ
+                 && DEFAULT_ABI == ABI_ELFv2
+                 && GET_CODE (func_desc) == SYMBOL_REF)
+               {
+                 rtvec v = gen_rtvec (3, toc_reg, func_desc, tlsarg);
+                 rtx mark_toc_reg = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
+                 emit_insn (gen_rtx_SET (stack_toc_mem, mark_toc_reg));
+               }
+             else
+               emit_move_insn (stack_toc_mem, toc_reg);
            }
-         else
-           emit_move_insn (stack_toc_mem, toc_reg);
        }
 
       if (DEFAULT_ABI == ABI_ELFv2)
@@ -37812,10 +37878,12 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
     }
   else
     {
-      /* Direct calls use the TOC: for local calls, the callee will
-        assume the TOC register is set; for non-local calls, the
-        PLT stub needs the TOC register.  */
-      abi_reg = toc_reg;
+      /* No TOC register needed for calls from PC-relative callers.  */
+      if (!rs6000_pcrel_p (cfun))
+       /* Direct calls use the TOC: for local calls, the callee will
+          assume the TOC register is set; for non-local calls, the
+          PLT stub needs the TOC register.  */
+       abi_reg = toc_reg;
       func_addr = func;
     }
 
@@ -37865,7 +37933,9 @@ rs6000_sibcall_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
   insn = emit_call_insn (insn);
 
   /* Note use of the TOC register.  */
-  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (Pmode, TOC_REGNUM));
+  if (!rs6000_pcrel_p (cfun))
+    use_reg (&CALL_INSN_FUNCTION_USAGE (insn),
+            gen_rtx_REG (Pmode, TOC_REGNUM));
 }
 
 /* Expand code to perform a call under the SYSV4 ABI.  */
index 335d75ae85fec93835f455da73dde0128beba963..f50ae946b322442c024932e37a194c09aa64cbc7 100644 (file)
@@ -1490,6 +1490,15 @@ extern enum reg_class rs6000_constraints[RS6000_CONSTRAINT_MAX];
 #define CALL_LONG              0x00000008      /* always call indirect */
 #define CALL_LIBCALL           0x00000010      /* libcall */
 
+/* Identify PLT sequence for rs6000_pltseq_template.  */
+enum rs6000_pltseq_enum {
+  RS6000_PLTSEQ_TOCSAVE,
+  RS6000_PLTSEQ_PLT16_HA,
+  RS6000_PLTSEQ_PLT16_LO,
+  RS6000_PLTSEQ_MTCTR,
+  RS6000_PLTSEQ_PLT_PCREL34
+};
+
 #define IS_V4_FP_ARGS(OP) \
   ((INTVAL (OP) & (CALL_V4_CLEAR_FP_ARGS | CALL_V4_SET_FP_ARGS)) != 0)
 
index 71613e213843d97335eb750114d7ae32bc28b799..47cbba8944398da38036cbb378aa0473902e8b8f 100644 (file)
    UNSPEC_PLTSEQ
    UNSPEC_PLT16_HA
    UNSPEC_PLT16_LO
+   UNSPEC_PLT_PCREL
   ])
 
 ;;
   "TARGET_PLTSEQ
    && DEFAULT_ABI == ABI_ELFv2"
 {
-  return rs6000_pltseq_template (operands, 0);
+  return rs6000_pltseq_template (operands, RS6000_PLTSEQ_TOCSAVE);
 })
 
 (define_insn "*pltseq_plt16_ha_<mode>"
                  UNSPEC_PLT16_HA))]
   "TARGET_PLTSEQ"
 {
-  return rs6000_pltseq_template (operands, 1);
+  return rs6000_pltseq_template (operands, RS6000_PLTSEQ_PLT16_HA);
 })
 
 (define_insn "*pltseq_plt16_lo_<mode>"
                  UNSPEC_PLT16_LO))]
   "TARGET_PLTSEQ"
 {
-  return rs6000_pltseq_template (operands, 2);
+  return rs6000_pltseq_template (operands, RS6000_PLTSEQ_PLT16_LO);
 }
   [(set_attr "type" "load")])
 
                  UNSPEC_PLTSEQ))]
   "TARGET_PLTSEQ"
 {
-  return rs6000_pltseq_template (operands, 3);
+  return rs6000_pltseq_template (operands, RS6000_PLTSEQ_MTCTR);
 })
+
+(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, RS6000_PLTSEQ_PLT_PCREL34);
+}
+  [(set_attr "type" "load")
+   (set_attr "length" "12")])
 \f
 ;; Call and call_value insns
 ;; For the purposes of expanding calls, Darwin is very similar to SYSV.
         (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>"
    (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.
   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 "" "")
 }
   [(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
                      (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"))
            (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 "")
index b8fdc2fae1cd6d6ddf0926c3408ef95c813baf32..60dc28209e927c6cf5d5e60010d36dbc868e4e62 100644 (file)
@@ -1,3 +1,8 @@
+2019-05-29  Bill Schmidt  <wschmidt@linux.ibm.com>
+
+       * gcc.target/powerpc/notoc-direct-1.c: New.
+       * gcc.target/powerpc/pcrel-sibcall-1.c: New.
+
 2019-05-29  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/90598
diff --git a/gcc/testsuite/gcc.target/powerpc/notoc-direct-1.c b/gcc/testsuite/gcc.target/powerpc/notoc-direct-1.c
new file mode 100644 (file)
index 0000000..3149726
--- /dev/null
@@ -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 (file)
index 0000000..7c767e2
--- /dev/null
@@ -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} } } */