public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/6] [RS6000] inline plt call support
@ 2018-11-07  5:33 Alan Modra
  2018-11-07  5:37 ` [PATCH 1/6] [RS6000] rs6000_output_call for external call insn assembly output Alan Modra
                   ` (5 more replies)
  0 siblings, 6 replies; 34+ messages in thread
From: Alan Modra @ 2018-11-07  5:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: Segher Boessenkool

Hi Segher,
This is the patch series you already saw earlier this year, rebased
to recent gcc, and with a comment or two fixed.  The first five
patches tidy and rearrange the function call code in order to support
inline plt calls without a huge increase in rs6000.md.  As is, inline
plt calls are supported for powerpc-linux and powerpc64le-linux
ELFv2.  I don't support them for powerpc64-linux ELFv1 due to the
extra read barriers needed there, but it wouldn't be too difficult to
support if there was demand.

I've regression tested again on powerpc64le-linux.  Earlier testing
went to some lengths with old and new binutils on powerpc-linux,
powerpc64le-linux and powerpc64-linux.  I also tested using -fno-plt
in bootstrap and regression tests, which unsurprisingly showed
numerous fails due to wrong counts of symbols (inline plt references a
function symbol multiple times to make a call), wrong "bl" counts
(none with inline call) or similar.  I didn't see anything
frightening, and I expect that people generally won't regression test
with -fno-plt, so I haven't modified any tests.

One benefit of the inline plt support is that gcc will now use the new
sequences and relocs to support -mlongcall.  This allows lazy dynamic
resolution of the plt entries so it is now possible to dlopen
libraries and have -mlongcall code call functions in those libraries.
That wasn't possible before.  See
https://bugzilla.redhat.com/show_bug.cgi?id=1633721

Alan Modra (6):
  [RS6000] rs6000_output_call for external call insn assembly output
  [RS6000] rs6000_output_indirect_call
  [RS6000] Replace TLSmode with P, and correct tls call mems
  [RS6000] Remove constraints on call rounded_stack_size_rtx arg
  [RS6000] Use standard call patterns for __tls_get_addr calls
  [RS6000] inline plt call sequences

 gcc/config.in                     |    6 +
 gcc/config/rs6000/darwin.md       |    8 +-
 gcc/config/rs6000/predicates.md   |   25 +
 gcc/config/rs6000/rs6000-protos.h |    8 +-
 gcc/config/rs6000/rs6000.c        |  617 ++++++++++++++---
 gcc/config/rs6000/rs6000.h        |    4 +
 gcc/config/rs6000/rs6000.md       | 1023 +++++++++++++----------------
 gcc/configure                     |   36 +
 gcc/configure.ac                  |    6 +
 9 files changed, 1065 insertions(+), 668 deletions(-)

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 1/6] [RS6000] rs6000_output_call for external call insn assembly output
  2018-11-07  5:33 [PATCH 0/6] [RS6000] inline plt call support Alan Modra
@ 2018-11-07  5:37 ` Alan Modra
  2018-11-08  0:09   ` Segher Boessenkool
  2018-11-07  5:38 ` [PATCH 2/6] [RS6000] rs6000_output_indirect_call Alan Modra
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 34+ messages in thread
From: Alan Modra @ 2018-11-07  5:37 UTC (permalink / raw)
  To: gcc-patches; +Cc: Segher Boessenkool

This is a first step in tidying rs6000 call patterns, in preparation
to support inline plt calls.

	* config/rs6000/rs6000-protos.h (rs6000_output_call): Declare.
	(macho_output_call): Rename from output_call.
	* config/rs6000/rs6000.c (rs6000_output_call): New function.
	(macho_output_call): Rename from output_call.
	* config/rs6000/rs6000.md (tls_gd_aix): Use rs6000_output_call
	to emit call.
	(tls_gd_sysv, tls_gd_call_aix, tls_gd_call_sysv): Likewise.
	(tls_ld_aix, tls_ld_sysv, tls_ld_call_aix): Likewise.
	(tls_ld_call_sysv, call_nonlocal_sysv): Likewise.
	(call_nonlocal_sysv_secure, call_value_nonlocal_sysv): Likewise.
	(call_value_nonlocal_sysv_secure, call_nonlocal_aix): Likewise.
	(call_value_nonlocal_aix, sibcall_nonlocal_sysv): Likewise.
	(sibcall_value_nonlocal_sysv, sibcall_aix): Likewise.
	(sibcall_value_aix): Likewise.

diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index fb69019c47c..f1a421dde16 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -111,6 +111,7 @@ extern int ccr_bit (rtx, int);
 extern void rs6000_output_function_entry (FILE *, const char *);
 extern void print_operand (FILE *, rtx, int);
 extern void print_operand_address (FILE *, rtx);
+extern const char *rs6000_output_call (rtx *, unsigned int, bool, const char *);
 extern enum rtx_code rs6000_reverse_condition (machine_mode,
 					       enum rtx_code);
 extern rtx rs6000_emit_eqne (machine_mode, rtx, rtx, rtx);
@@ -228,7 +229,7 @@ extern void (*rs6000_target_modify_macros_ptr) (bool, HOST_WIDE_INT,
 extern void rs6000_d_target_versions (void);
 
 #if TARGET_MACHO
-char *output_call (rtx_insn *, rtx *, int, int);
+char *macho_output_call (rtx_insn *, rtx *, int, int);
 #endif
 
 #ifdef NO_DOLLAR_IN_LABEL
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 75b197f458c..b22cae55a0d 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -21380,6 +21380,37 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
   return default_assemble_integer (x, size, aligned_p);
 }
 
+/* Return a template string for assembly to emit when making an
+   external call.  FUN is the %z argument, ARG is either NULL or
+   a @TLSGD or @TLSLD __tls_get_addr argument specifier.  */
+
+const char *
+rs6000_output_call (rtx *operands, unsigned int fun, bool sibcall,
+		    const char *arg)
+{
+  /* -Wformat-overflow workaround, without which gcc thinks that %u
+      might produce 10 digits.  FUN is 0 or 1 as of 2018-03.  */
+  gcc_assert (fun <= 6);
+
+  /* The magic 32768 offset here corresponds to the offset of
+     r30 in .got2, as given by LCTOC1.  See sysv4.h:toc_section.  */
+  char z[10];
+  sprintf (z, "%%z%u%s", fun,
+	   (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic == 2
+	    ? "+32768" : ""));
+
+  static char str[32];  /* 5 spare */
+  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
+    sprintf (str, "b%s %s%s%s", "l" + sibcall, z, arg,
+	     sibcall ? "" : "\n\tnop");
+  else if (DEFAULT_ABI == ABI_V4)
+    sprintf (str, "b%s %s%s%s", "l" + sibcall, z, arg,
+	     flag_pic ? "@plt" : "");
+  else
+    gcc_unreachable ();
+  return str;
+}
+
 #if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO
 /* Emit an assembler directive to set symbol visibility for DECL to
    VISIBILITY_TYPE.  */
@@ -32818,8 +32849,8 @@ get_prev_label (tree function_name)
    CALL_DEST is the routine we are calling.  */
 
 char *
-output_call (rtx_insn *insn, rtx *operands, int dest_operand_number,
-	     int cookie_operand_number)
+macho_output_call (rtx_insn *insn, rtx *operands, int dest_operand_number,
+		      int cookie_operand_number)
 {
   static char buf[256];
   if (darwin_emit_branch_islands
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 66742f66a89..52088fdfbdb 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -9454,10 +9454,11 @@ (define_insn_and_split "tls_gd_aix<TLSmode:tls_abi_suffix>"
   "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
 {
   if (TARGET_CMODEL != CMODEL_SMALL)
-    return "addis %0,%1,%2@got@tlsgd@ha\;addi %0,%0,%2@got@tlsgd@l\;"
-	   "bl %z3\;nop";
+    output_asm_insn ("addis %0,%1,%2@got@tlsgd@ha\;"
+		     "addi %0,%0,%2@got@tlsgd@l", operands);
   else
-    return "addi %0,%1,%2@got@tlsgd\;bl %z3\;nop";
+    output_asm_insn ("addi %0,%1,%2@got@tlsgd", operands);
+  return rs6000_output_call (operands, 3, false, "");
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
@@ -9486,15 +9487,8 @@ (define_insn_and_split "tls_gd_sysv<TLSmode:tls_sysv_suffix>"
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
 {
-  if (flag_pic)
-    {
-      if (TARGET_SECURE_PLT && flag_pic == 2)
-	return "addi %0,%1,%2@got@tlsgd\;bl %z3+32768@plt";
-      else
-	return "addi %0,%1,%2@got@tlsgd\;bl %z3@plt";
-    }
-  else
-    return "addi %0,%1,%2@got@tlsgd\;bl %z3";
+  output_asm_insn ("addi %0,%1,%2@got@tlsgd", operands);
+  return rs6000_output_call (operands, 3, false, "");
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
@@ -9559,7 +9553,9 @@ (define_insn "*tls_gd_call_aix<TLSmode:tls_abi_suffix>"
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS
    && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
-  "bl %z1(%3@tlsgd)\;nop"
+{
+  return rs6000_output_call (operands, 1, false, "(%3@tlsgd)");
+}
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
@@ -9572,13 +9568,7 @@ (define_insn "*tls_gd_call_sysv<TLSmode:tls_abi_suffix>"
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
 {
-  if (flag_pic)
-    {
-      if (TARGET_SECURE_PLT && flag_pic == 2)
-	return "bl %z1+32768(%3@tlsgd)@plt";
-      return "bl %z1(%3@tlsgd)@plt";
-    }
-  return "bl %z1(%3@tlsgd)";
+  return rs6000_output_call (operands, 1, false, "(%3@tlsgd)");
 }
   [(set_attr "type" "branch")])
 
@@ -9592,10 +9582,11 @@ (define_insn_and_split "tls_ld_aix<TLSmode:tls_abi_suffix>"
   "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
 {
   if (TARGET_CMODEL != CMODEL_SMALL)
-    return "addis %0,%1,%&@got@tlsld@ha\;addi %0,%0,%&@got@tlsld@l\;"
-	   "bl %z2\;nop";
+    output_asm_insn ("addis %0,%1,%&@got@tlsld@ha\;"
+		     "addi %0,%0,%&@got@tlsld@l", operands);
   else
-    return "addi %0,%1,%&@got@tlsld\;bl %z2\;nop";
+    output_asm_insn ("addi %0,%1,%&@got@tlsld", operands);
+  return rs6000_output_call (operands, 2, false, "");
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
@@ -9622,15 +9613,8 @@ (define_insn_and_split "tls_ld_sysv<TLSmode:tls_sysv_suffix>"
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
 {
-  if (flag_pic)
-    {
-      if (TARGET_SECURE_PLT && flag_pic == 2)
-	return "addi %0,%1,%&@got@tlsld\;bl %z2+32768@plt";
-      else
-	return "addi %0,%1,%&@got@tlsld\;bl %z2@plt";
-    }
-  else
-    return "addi %0,%1,%&@got@tlsld\;bl %z2";
+  output_asm_insn ("addi %0,%1,%&@got@tlsld", operands);
+  return rs6000_output_call (operands, 2, false, "");
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
@@ -9691,7 +9675,9 @@ (define_insn "*tls_ld_call_aix<TLSmode:tls_abi_suffix>"
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS
    && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
-  "bl %z1(%&@tlsld)\;nop"
+{
+  return rs6000_output_call (operands, 1, false, "(%&@tlsld)");
+}
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
@@ -9703,13 +9689,7 @@ (define_insn "*tls_ld_call_sysv<TLSmode:tls_abi_suffix>"
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
 {
-  if (flag_pic)
-    {
-      if (TARGET_SECURE_PLT && flag_pic == 2)
-	return "bl %z1+32768(%&@tlsld)@plt";
-      return "bl %z1(%&@tlsld)@plt";
-    }
-  return "bl %z1(%&@tlsld)";
+  return rs6000_output_call (operands, 1, false, "(%&@tlsld)");
 }
   [(set_attr "type" "branch")])
 
@@ -10595,15 +10575,9 @@ (define_insn_and_split "*call_nonlocal_sysv<mode>"
     output_asm_insn ("creqv 6,6,6", operands);
 
 #if TARGET_MACHO
-  return output_call(insn, operands, 0, 2);
+  return macho_output_call(insn, operands, 0, 2);
 #else
-  if (DEFAULT_ABI == ABI_V4 && flag_pic)
-    {
-      gcc_assert (!TARGET_SECURE_PLT);
-      return "bl %z0@plt";
-    }
-  else
-    return "bl %z0";
+  return rs6000_output_call (operands, 0, false, "");
 #endif
 }
   "DEFAULT_ABI == ABI_V4
@@ -10636,13 +10610,7 @@ (define_insn "*call_nonlocal_sysv_secure<mode>"
   else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  if (flag_pic == 2)
-    /* The magic 32768 offset here and in the other sysv call insns
-       corresponds to the offset of r30 in .got2, as given by LCTOC1.
-       See sysv4.h:toc_section.  */
-    return "bl %z0+32768@plt";
-  else
-    return "bl %z0@plt";
+  return rs6000_output_call (operands, 0, false, "");
 }
   [(set_attr "type" "branch,branch")
    (set_attr "length" "4,8")])
@@ -10698,15 +10666,9 @@ (define_insn_and_split "*call_value_nonlocal_sysv<mode>"
     output_asm_insn ("creqv 6,6,6", operands);
 
 #if TARGET_MACHO
-  return output_call(insn, operands, 1, 3);
+  return macho_output_call(insn, operands, 1, 3);
 #else
-  if (DEFAULT_ABI == ABI_V4 && flag_pic)
-    {
-      gcc_assert (!TARGET_SECURE_PLT);
-      return "bl %z1@plt";
-    }
-  else
-    return "bl %z1";
+  return rs6000_output_call (operands, 1, false, "");
 #endif
 }
   "DEFAULT_ABI == ABI_V4
@@ -10741,10 +10703,7 @@ (define_insn "*call_value_nonlocal_sysv_secure<mode>"
   else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  if (flag_pic == 2)
-    return "bl %z1+32768@plt";
-  else
-    return "bl %z1@plt";
+  return rs6000_output_call (operands, 1, false, "");
 }
   [(set_attr "type" "branch,branch")
    (set_attr "length" "4,8")])
@@ -10777,7 +10736,9 @@ (define_insn "*call_nonlocal_aix<mode>"
 	 (match_operand 1 "" "g"))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
-  "bl %z0\;nop"
+{
+  return rs6000_output_call (operands, 0, false, "");
+}
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
@@ -10787,7 +10748,9 @@ (define_insn "*call_value_nonlocal_aix<mode>"
 	      (match_operand 2 "" "g")))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
-  "bl %z1\;nop"
+{
+  return rs6000_output_call (operands, 1, false, "");
+}
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
@@ -11064,13 +11027,8 @@ (define_insn "*sibcall_nonlocal_sysv<mode>"
 	/* Can use CR0 since it is volatile across sibcalls.  */
 	return "crset 2\;beq%T0-\;b $";
     }
-  else if (DEFAULT_ABI == ABI_V4 && flag_pic)
-    {
-      gcc_assert (!TARGET_SECURE_PLT);
-      return "b %z0@plt";
-    }
   else
-    return "b %z0";
+    return rs6000_output_call (operands, 0, true, "");
 }
   [(set_attr "type" "branch")
    (set_attr_alternative "length"
@@ -11109,13 +11067,8 @@ (define_insn "*sibcall_value_nonlocal_sysv<mode>"
 	/* Can use CR0 since it is volatile across sibcalls.  */
 	return "crset 2\;beq%T1-\;b $";
     }
-  else if (DEFAULT_ABI == ABI_V4 && flag_pic)
-    {
-      gcc_assert (!TARGET_SECURE_PLT);
-      return "b %z1@plt";
-    }
   else
-    return "b %z1";
+    return rs6000_output_call (operands, 1, true, "");
 }
   [(set_attr "type" "branch")
    (set_attr_alternative "length"
@@ -11137,9 +11090,12 @@ (define_insn "*sibcall_aix<mode>"
 	 (match_operand 1 "" "g,g"))
    (simple_return)]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
-  "@
-   b %z0
-   b%T0"
+{
+  if (which_alternative == 0)
+    return rs6000_output_call (operands, 0, true, "");
+  else
+    return "b%T0";
+}
   [(set_attr "type" "branch")])
 
 (define_insn "*sibcall_value_aix<mode>"
@@ -11148,9 +11104,12 @@ (define_insn "*sibcall_value_aix<mode>"
 	      (match_operand 2 "" "g,g")))
    (simple_return)]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
-  "@
-   b %z1
-   b%T1"
+{
+  if (which_alternative == 0)
+    return rs6000_output_call (operands, 1, true, "");
+  else
+    return "b%T1";
+}
   [(set_attr "type" "branch")])
 
 (define_expand "sibcall_epilogue"

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 2/6] [RS6000] rs6000_output_indirect_call
  2018-11-07  5:33 [PATCH 0/6] [RS6000] inline plt call support Alan Modra
  2018-11-07  5:37 ` [PATCH 1/6] [RS6000] rs6000_output_call for external call insn assembly output Alan Modra
@ 2018-11-07  5:38 ` Alan Modra
  2018-11-12 19:44   ` Bill Schmidt
  2018-11-07  5:38 ` [PATCH 3/6] [RS6000] Replace TLSmode with P, and correct tls call mems Alan Modra
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 34+ messages in thread
From: Alan Modra @ 2018-11-07  5:38 UTC (permalink / raw)
  To: gcc-patches; +Cc: Segher Boessenkool

Like the last patch for external calls, now handle most assembly code
for indirect calls in one place.  The patch also merges some insns,
correcting some !rs6000_speculate_indirect_jumps cases branching to
LR, which don't require a speculation barrier.

	* config/rs6000/rs6000-protos.h (rs6000_output_indirect_call): Declare.
	* config/rs6000/rs6000.c (rs6000_output_indirect_call): New function.
	* config/rs6000/rs6000.md (call_indirect_nonlocal_sysv): Use
	rs6000_output_indirect_call.
	(call_value_indirect_nonlocal_sysv, sibcall_nonlocal_sysv): Likewise.
	(call_indirect_aix, call_value_indirect_aix,
	call_indirect_elfv2, call_value_indirect_elfv2): Likewise, and
	handle both speculation and non-speculation cases.
	(call_indirect_aix_nospec, call_value_indirect_aix_nospec): Delete.
	(call_indirect_elfv2_nospec, call_value_indirect_elfv2_nospec): Delete.

diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index f1a421dde16..493cfe6ba2b 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -112,6 +112,7 @@ extern void rs6000_output_function_entry (FILE *, const char *);
 extern void print_operand (FILE *, rtx, int);
 extern void print_operand_address (FILE *, rtx);
 extern const char *rs6000_output_call (rtx *, unsigned int, bool, const char *);
+extern const char *rs6000_output_indirect_call (rtx *, unsigned int, bool);
 extern enum rtx_code rs6000_reverse_condition (machine_mode,
 					       enum rtx_code);
 extern rtx rs6000_emit_eqne (machine_mode, rtx, rtx, rtx);
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index b22cae55a0d..bf1551746d5 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -21411,6 +21411,69 @@ rs6000_output_call (rtx *operands, unsigned int fun, bool sibcall,
   return str;
 }
 
+/* As above, for indirect calls.  */
+
+const char *
+rs6000_output_indirect_call (rtx *operands, unsigned int fun, bool sibcall)
+{
+  /* -Wformat-overflow workaround, without which gcc thinks that %u
+      might produce 10 digits.  FUN is 0 or 1 as of 2018-03.  */
+  gcc_assert (fun <= 6);
+
+  static char str[144];
+  const char *ptrload = TARGET_64BIT ? "d" : "wz";
+
+  bool speculate = (rs6000_speculate_indirect_jumps
+		    || (REG_P (operands[fun])
+			&& REGNO (operands[fun]) == LR_REGNO));
+
+  if (DEFAULT_ABI == ABI_AIX)
+    {
+      if (speculate)
+	sprintf (str,
+		 "l%s 2,%%%u\n\t"
+		 "b%%T%ul\n\t"
+		 "l%s 2,%%%u(1)",
+		 ptrload, fun + 2, fun, ptrload, fun + 3);
+      else
+	sprintf (str,
+		 "crset 2\n\t"
+		 "l%s 2,%%%u\n\t"
+		 "beq%%T%ul-\n\t"
+		 "l%s 2,%%%u(1)",
+		 ptrload, fun + 2, fun, ptrload, fun + 3);
+    }
+  else if (DEFAULT_ABI == ABI_ELFv2)
+    {
+      if (speculate)
+	sprintf (str,
+		 "b%%T%ul\n\t"
+		 "l%s 2,%%%u(1)",
+		 fun, ptrload, fun + 2);
+      else
+	sprintf (str,
+		 "crset 2\n\t"
+		 "beq%%T%ul-\n\t"
+		 "l%s 2,%%%u(1)",
+		 fun, ptrload, fun + 2);
+    }
+  else if (DEFAULT_ABI == ABI_V4)
+    {
+      if (speculate)
+	sprintf (str,
+		 "b%%T%u%s",
+		 fun, "l" + sibcall);
+      else
+	sprintf (str,
+		 "crset 2\n\t"
+		 "beq%%T%u%s-%s",
+		 fun, "l" + sibcall, sibcall ? "\n\tb $" : "");
+    }
+  else
+    gcc_unreachable ();
+  return str;
+}
+
 #if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO
 /* Emit an assembler directive to set symbol visibility for DECL to
    VISIBILITY_TYPE.  */
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 52088fdfbdb..9d9e29d12eb 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -10540,11 +10540,7 @@ (define_insn "*call_indirect_nonlocal_sysv<mode>"
   else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  if (rs6000_speculate_indirect_jumps
-      || which_alternative == 1 || which_alternative == 3)
-    return "b%T0l";
-  else
-    return "crset 2\;beq%T0l-";
+  return rs6000_output_indirect_call (operands, 0, false);
 }
   [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
    (set_attr_alternative "length"
@@ -10630,11 +10626,7 @@ (define_insn "*call_value_indirect_nonlocal_sysv<mode>"
   else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  if (rs6000_speculate_indirect_jumps
-      || which_alternative == 1 || which_alternative == 3)
-    return "b%T1l";
-  else
-    return "crset 2\;beq%T1l-";
+  return rs6000_output_indirect_call (operands, 1, false);
 }
   [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
    (set_attr_alternative "length"
@@ -10765,21 +10757,16 @@ (define_insn "*call_indirect_aix<mode>"
    (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_AIX && rs6000_speculate_indirect_jumps"
-  "<ptrload> 2,%2\;b%T0l\;<ptrload> 2,%3(1)"
-  [(set_attr "type" "jmpreg")
-   (set_attr "length" "12")])
-
-(define_insn "*call_indirect_aix<mode>_nospec"
-  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
-	 (match_operand 1 "" "g,g"))
-   (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
-   (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_AIX && !rs6000_speculate_indirect_jumps"
-  "crset 2\;<ptrload> 2,%2\;beq%T0l-\;<ptrload> 2,%3(1)"
+  "DEFAULT_ABI == ABI_AIX"
+{
+  return rs6000_output_indirect_call (operands, 0, false);
+}
   [(set_attr "type" "jmpreg")
-   (set_attr "length" "16")])
+   (set (attr "length")
+	(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
+			   (match_test "which_alternative != 1"))
+		      (const_string "16")
+		      (const_string "12")))])
 
 (define_insn "*call_value_indirect_aix<mode>"
   [(set (match_operand 0 "" "")
@@ -10788,22 +10775,16 @@ (define_insn "*call_value_indirect_aix<mode>"
    (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_AIX && rs6000_speculate_indirect_jumps"
-  "<ptrload> 2,%3\;b%T1l\;<ptrload> 2,%4(1)"
-  [(set_attr "type" "jmpreg")
-   (set_attr "length" "12")])
-
-(define_insn "*call_value_indirect_aix<mode>_nospec"
-  [(set (match_operand 0 "" "")
-	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
-	      (match_operand 2 "" "g,g")))
-   (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
-   (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_AIX && !rs6000_speculate_indirect_jumps"
-  "crset 2\;<ptrload> 2,%3\;beq%T1l-\;<ptrload> 2,%4(1)"
+  "DEFAULT_ABI == ABI_AIX"
+{
+  return rs6000_output_indirect_call (operands, 1, false);
+}
   [(set_attr "type" "jmpreg")
-   (set_attr "length" "16")])
+   (set (attr "length")
+	(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
+			   (match_test "which_alternative != 1"))
+		      (const_string "16")
+		      (const_string "12")))])
 
 ;; Call to indirect functions with the ELFv2 ABI.
 ;; Operand0 is the addresss of the function to call
@@ -10814,21 +10795,16 @@ (define_insn "*call_indirect_elfv2<mode>"
 	 (match_operand 1 "" "g,g"))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_ELFv2 && rs6000_speculate_indirect_jumps"
-  "b%T0l\;<ptrload> 2,%2(1)"
-  [(set_attr "type" "jmpreg")
-   (set_attr "length" "8")])
-
-;; Variant with deliberate misprediction.
-(define_insn "*call_indirect_elfv2<mode>_nospec"
-  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
-	 (match_operand 1 "" "g,g"))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
-   (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_ELFv2 && !rs6000_speculate_indirect_jumps"
-  "crset 2\;beq%T0l-\;<ptrload> 2,%2(1)"
+  "DEFAULT_ABI == ABI_ELFv2"
+{
+  return rs6000_output_indirect_call (operands, 0, false);
+}
   [(set_attr "type" "jmpreg")
-   (set_attr "length" "12")])
+   (set (attr "length")
+	(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
+			   (match_test "which_alternative != 1"))
+		      (const_string "12")
+		      (const_string "8")))])
 
 (define_insn "*call_value_indirect_elfv2<mode>"
   [(set (match_operand 0 "" "")
@@ -10836,22 +10812,16 @@ (define_insn "*call_value_indirect_elfv2<mode>"
 	      (match_operand 2 "" "g,g")))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_ELFv2 && rs6000_speculate_indirect_jumps"
-  "b%T1l\;<ptrload> 2,%3(1)"
-  [(set_attr "type" "jmpreg")
-   (set_attr "length" "8")])
-
-; Variant with deliberate misprediction.
-(define_insn "*call_value_indirect_elfv2<mode>_nospec"
-  [(set (match_operand 0 "" "")
-	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
-	      (match_operand 2 "" "g,g")))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
-   (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_ELFv2 && !rs6000_speculate_indirect_jumps"
-  "crset 2\;beq%T1l-\;<ptrload> 2,%3(1)"
+  "DEFAULT_ABI == ABI_ELFv2"
+{
+  return rs6000_output_indirect_call (operands, 1, false);
+}
   [(set_attr "type" "jmpreg")
-   (set_attr "length" "12")])
+   (set (attr "length")
+	(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
+			   (match_test "which_alternative != 1"))
+		      (const_string "12")
+		      (const_string "8")))])
 
 ;; Call subroutine returning any type.
 (define_expand "untyped_call"
@@ -11020,13 +10990,7 @@ (define_insn "*sibcall_nonlocal_sysv<mode>"
     output_asm_insn ("creqv 6,6,6", operands);
 
   if (which_alternative >= 2)
-    {
-      if (rs6000_speculate_indirect_jumps)
-	return "b%T0";
-      else
-	/* Can use CR0 since it is volatile across sibcalls.  */
-	return "crset 2\;beq%T0-\;b $";
-    }
+    return rs6000_output_indirect_call (operands, 0, true);
   else
     return rs6000_output_call (operands, 0, true, "");
 }

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 3/6] [RS6000] Replace TLSmode with P, and correct tls call mems
  2018-11-07  5:33 [PATCH 0/6] [RS6000] inline plt call support Alan Modra
  2018-11-07  5:37 ` [PATCH 1/6] [RS6000] rs6000_output_call for external call insn assembly output Alan Modra
  2018-11-07  5:38 ` [PATCH 2/6] [RS6000] rs6000_output_indirect_call Alan Modra
@ 2018-11-07  5:38 ` Alan Modra
  2018-11-08  1:11   ` Segher Boessenkool
  2018-11-07  5:39 ` [PATCH 4/6] [RS6000] Remove constraints on call rounded_stack_size_rtx arg Alan Modra
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 34+ messages in thread
From: Alan Modra @ 2018-11-07  5:38 UTC (permalink / raw)
  To: gcc-patches; +Cc: Segher Boessenkool

There is really no need to define a TLSmode mode iterator that is
identical (since !TARGET_64BIT == TARGET_32BIT) to the much used P
mode iterator.  It's nonsense to think we might ever want to support
32-bit TLS on 64-bit or vice versa!  The patch also fixes a minor
error in the call mems.  All other direct calls use (call (mem:SI ..)).

	* config/rs6000/rs6000.md (TLSmode): Delete mode iterator.  Replace
	with P throughout except for call mems which should use SI.

diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 9d9e29d12eb..3f9830bc743 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -9438,18 +9438,17 @@ (define_peephole2
 ;; TLS support.
 
 ;; Mode attributes for different ABIs.
-(define_mode_iterator TLSmode [(SI "! TARGET_64BIT") (DI "TARGET_64BIT")])
 (define_mode_attr tls_abi_suffix [(SI "32") (DI "64")])
 (define_mode_attr tls_sysv_suffix [(SI "si") (DI "di")])
 (define_mode_attr tls_insn_suffix [(SI "wz") (DI "d")])
 
-(define_insn_and_split "tls_gd_aix<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 3 "symbol_ref_operand" "s"))
+(define_insn_and_split "tls_gd_aix<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
 	      (match_operand 4 "" "g")))
-   (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-	 	    (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-		   UNSPEC_TLSGD)
+   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+	      (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+	     UNSPEC_TLSGD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
 {
@@ -9462,28 +9461,28 @@ (define_insn_and_split "tls_gd_aix<TLSmode:tls_abi_suffix>"
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
-	(unspec:TLSmode [(match_dup 1)
-			 (match_dup 2)]
-			UNSPEC_TLSGD))
+	(unspec:P [(match_dup 1)
+		   (match_dup 2)]
+		  UNSPEC_TLSGD))
    (parallel [(set (match_dup 0)
-   	     	   (call (mem:TLSmode (match_dup 3))
-		   	 (match_dup 4)))
-	      (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD)
+		   (call (mem:SI (match_dup 3))
+			 (match_dup 4)))
+	      (unspec:P [(match_dup 2)] UNSPEC_TLSGD)
 	      (clobber (reg:SI LR_REGNO))])]
   ""
   [(set_attr "type" "two")
    (set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-     		   (const_int 16)
-     		   (const_int 12)))])
+		   (const_int 16)
+		   (const_int 12)))])
 
-(define_insn_and_split "tls_gd_sysv<TLSmode:tls_sysv_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 3 "symbol_ref_operand" "s"))
+(define_insn_and_split "tls_gd_sysv<P:tls_sysv_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
 	      (match_operand 4 "" "g")))
-   (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-	 	    (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-		   UNSPEC_TLSGD)
+   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+	      (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+	     UNSPEC_TLSGD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
 {
@@ -9492,64 +9491,64 @@ (define_insn_and_split "tls_gd_sysv<TLSmode:tls_sysv_suffix>"
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
-	(unspec:TLSmode [(match_dup 1)
-			 (match_dup 2)]
-			UNSPEC_TLSGD))
+	(unspec:P [(match_dup 1)
+		   (match_dup 2)]
+		  UNSPEC_TLSGD))
    (parallel [(set (match_dup 0)
-   	     	   (call (mem:TLSmode (match_dup 3))
-		   	 (match_dup 4)))
-	      (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD)
+		   (call (mem:SI (match_dup 3))
+			 (match_dup 4)))
+	      (unspec:P [(match_dup 2)] UNSPEC_TLSGD)
 	      (clobber (reg:SI LR_REGNO))])]
   ""
   [(set_attr "type" "two")
    (set_attr "length" "8")])
 
-(define_insn_and_split "*tls_gd<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSGD))]
+(define_insn_and_split "*tls_gd<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSGD))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS"
   "addi %0,%1,%2@got@tlsgd"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 3)
-  	(high:TLSmode
-	    (unspec:TLSmode [(match_dup 1) (match_dup 2)] UNSPEC_TLSGD)))
+	(high:P
+	    (unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGD)))
    (set (match_dup 0)
-   	(lo_sum:TLSmode (match_dup 3)
-	    (unspec:TLSmode [(match_dup 1) (match_dup 2)] UNSPEC_TLSGD)))]
+	(lo_sum:P (match_dup 3)
+	    (unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGD)))]
 {
   operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
 }
   [(set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-     		   (const_int 8)
-     		   (const_int 4)))])
-
-(define_insn "*tls_gd_high<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (high:TLSmode
-       (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-		       UNSPEC_TLSGD)))]
+		   (const_int 8)
+		   (const_int 4)))])
+
+(define_insn "*tls_gd_high<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+     (high:P
+       (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		  (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		 UNSPEC_TLSGD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addis %0,%1,%2@got@tlsgd@ha")
 
-(define_insn "*tls_gd_low<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
-       (unspec:TLSmode [(match_operand:TLSmode 3 "gpc_reg_operand" "b")
-			(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-		       UNSPEC_TLSGD)))]
+(define_insn "*tls_gd_low<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+     (lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
+       (unspec:P [(match_operand:P 3 "gpc_reg_operand" "b")
+		  (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		 UNSPEC_TLSGD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addi %0,%1,%2@got@tlsgd@l")
 
-(define_insn "*tls_gd_call_aix<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s"))
+(define_insn "*tls_gd_call_aix<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
 	      (match_operand 2 "" "g")))
-   (unspec:TLSmode [(match_operand:TLSmode 3 "rs6000_tls_symbol_ref" "")]
-		   UNSPEC_TLSGD)
+   (unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
+	     UNSPEC_TLSGD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS
    && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
@@ -9559,12 +9558,12 @@ (define_insn "*tls_gd_call_aix<TLSmode:tls_abi_suffix>"
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
-(define_insn "*tls_gd_call_sysv<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s"))
+(define_insn "*tls_gd_call_sysv<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
 	      (match_operand 2 "" "g")))
-   (unspec:TLSmode [(match_operand:TLSmode 3 "rs6000_tls_symbol_ref" "")]
-		   UNSPEC_TLSGD)
+   (unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
+	     UNSPEC_TLSGD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
 {
@@ -9572,12 +9571,12 @@ (define_insn "*tls_gd_call_sysv<TLSmode:tls_abi_suffix>"
 }
   [(set_attr "type" "branch")])
 
-(define_insn_and_split "tls_ld_aix<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 2 "symbol_ref_operand" "s"))
+(define_insn_and_split "tls_ld_aix<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
 	      (match_operand 3 "" "g")))
-   (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")]
-		   UNSPEC_TLSLD)
+   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
+	     UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
 {
@@ -9590,26 +9589,26 @@ (define_insn_and_split "tls_ld_aix<TLSmode:tls_abi_suffix>"
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
-	(unspec:TLSmode [(match_dup 1)]
-			UNSPEC_TLSLD))
+	(unspec:P [(match_dup 1)]
+		  UNSPEC_TLSLD))
    (parallel [(set (match_dup 0)
-   	     	   (call (mem:TLSmode (match_dup 2))
-		   	 (match_dup 3)))
-	      (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)
+		   (call (mem:SI (match_dup 2))
+			 (match_dup 3)))
+	      (unspec:P [(const_int 0)] UNSPEC_TLSLD)
 	      (clobber (reg:SI LR_REGNO))])]
   ""
   [(set_attr "type" "two")
    (set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-     		   (const_int 16)
-     		   (const_int 12)))])
+		   (const_int 16)
+		   (const_int 12)))])
 
-(define_insn_and_split "tls_ld_sysv<TLSmode:tls_sysv_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 2 "symbol_ref_operand" "s"))
+(define_insn_and_split "tls_ld_sysv<P:tls_sysv_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
 	      (match_operand 3 "" "g")))
-   (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")]
-		   UNSPEC_TLSLD)
+   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
+	     UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
 {
@@ -9618,60 +9617,60 @@ (define_insn_and_split "tls_ld_sysv<TLSmode:tls_sysv_suffix>"
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
-	(unspec:TLSmode [(match_dup 1)]
-			UNSPEC_TLSLD))
+	(unspec:P [(match_dup 1)]
+		  UNSPEC_TLSLD))
    (parallel [(set (match_dup 0)
-   	     	   (call (mem:TLSmode (match_dup 2))
-		   	 (match_dup 3)))
-	      (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)
+		   (call (mem:SI (match_dup 2))
+			 (match_dup 3)))
+	      (unspec:P [(const_int 0)] UNSPEC_TLSLD)
 	      (clobber (reg:SI LR_REGNO))])]
   ""
   [(set_attr "length" "8")])
 
-(define_insn_and_split "*tls_ld<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")]
-			UNSPEC_TLSLD))]
+(define_insn_and_split "*tls_ld<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
+		  UNSPEC_TLSLD))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS"
   "addi %0,%1,%&@got@tlsld"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 2)
-  	(high:TLSmode
-	    (unspec:TLSmode [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))
+	(high:P
+	    (unspec:P [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))
    (set (match_dup 0)
-   	(lo_sum:TLSmode (match_dup 2)
-	    (unspec:TLSmode [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))]
+	(lo_sum:P (match_dup 2)
+	    (unspec:P [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))]
 {
   operands[2] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
 }
   [(set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-     		   (const_int 8)
-     		   (const_int 4)))])
-
-(define_insn "*tls_ld_high<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (high:TLSmode
-       (unspec:TLSmode [(const_int 0)
-			(match_operand:TLSmode 1 "gpc_reg_operand" "b")]
-		       UNSPEC_TLSLD)))]
+		   (const_int 8)
+		   (const_int 4)))])
+
+(define_insn "*tls_ld_high<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+     (high:P
+       (unspec:P [(const_int 0)
+		  (match_operand:P 1 "gpc_reg_operand" "b")]
+		 UNSPEC_TLSLD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addis %0,%1,%&@got@tlsld@ha")
 
-(define_insn "*tls_ld_low<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
-       (unspec:TLSmode [(const_int 0)
-                        (match_operand:TLSmode 2 "gpc_reg_operand" "b")]
-                       UNSPEC_TLSLD)))]
+(define_insn "*tls_ld_low<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+     (lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
+       (unspec:P [(const_int 0)
+		  (match_operand:P 2 "gpc_reg_operand" "b")]
+		 UNSPEC_TLSLD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addi %0,%1,%&@got@tlsld@l")
 
-(define_insn "*tls_ld_call_aix<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s"))
+(define_insn "*tls_ld_call_aix<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
 	      (match_operand 2 "" "g")))
-   (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)
+   (unspec:P [(const_int 0)] UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS
    && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
@@ -9681,11 +9680,11 @@ (define_insn "*tls_ld_call_aix<TLSmode:tls_abi_suffix>"
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
-(define_insn "*tls_ld_call_sysv<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s"))
+(define_insn "*tls_ld_call_sysv<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
 	      (match_operand 2 "" "g")))
-   (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)
+   (unspec:P [(const_int 0)] UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
 {
@@ -9693,142 +9692,142 @@ (define_insn "*tls_ld_call_sysv<TLSmode:tls_abi_suffix>"
 }
   [(set_attr "type" "branch")])
 
-(define_insn "tls_dtprel_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSDTPREL))]
+(define_insn "tls_dtprel_<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSDTPREL))]
   "HAVE_AS_TLS"
   "addi %0,%1,%2@dtprel")
 
-(define_insn "tls_dtprel_ha_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSDTPRELHA))]
+(define_insn "tls_dtprel_ha_<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSDTPRELHA))]
   "HAVE_AS_TLS"
   "addis %0,%1,%2@dtprel@ha")
 
-(define_insn "tls_dtprel_lo_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSDTPRELLO))]
+(define_insn "tls_dtprel_lo_<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSDTPRELLO))]
   "HAVE_AS_TLS"
   "addi %0,%1,%2@dtprel@l")
 
-(define_insn_and_split "tls_got_dtprel_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSGOTDTPREL))]
+(define_insn_and_split "tls_got_dtprel_<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSGOTDTPREL))]
   "HAVE_AS_TLS"
-  "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel(%1)"
+  "l<P:tls_insn_suffix> %0,%2@got@dtprel(%1)"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 3)
-	(high:TLSmode
-	    (unspec:TLSmode [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTDTPREL)))
+	(high:P
+	    (unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTDTPREL)))
    (set (match_dup 0)
-	(lo_sum:TLSmode (match_dup 3)
-	    (unspec:TLSmode [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTDTPREL)))]
+	(lo_sum:P (match_dup 3)
+	    (unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTDTPREL)))]
 {
   operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
 }
   [(set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-     		   (const_int 8)
-     		   (const_int 4)))])
-
-(define_insn "*tls_got_dtprel_high<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (high:TLSmode
-       (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-		       UNSPEC_TLSGOTDTPREL)))]
+		   (const_int 8)
+		   (const_int 4)))])
+
+(define_insn "*tls_got_dtprel_high<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+     (high:P
+       (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		  (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		 UNSPEC_TLSGOTDTPREL)))]
   "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
   "addis %0,%1,%2@got@dtprel@ha")
 
-(define_insn "*tls_got_dtprel_low<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-     (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
-	 (unspec:TLSmode [(match_operand:TLSmode 3 "gpc_reg_operand" "b")
-			  (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			 UNSPEC_TLSGOTDTPREL)))]
+(define_insn "*tls_got_dtprel_low<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+     (lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
+	 (unspec:P [(match_operand:P 3 "gpc_reg_operand" "b")
+		    (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSGOTDTPREL)))]
   "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
-  "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel@l(%1)")
+  "l<P:tls_insn_suffix> %0,%2@got@dtprel@l(%1)")
 
-(define_insn "tls_tprel_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSTPREL))]
+(define_insn "tls_tprel_<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSTPREL))]
   "HAVE_AS_TLS"
   "addi %0,%1,%2@tprel")
 
-(define_insn "tls_tprel_ha_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSTPRELHA))]
+(define_insn "tls_tprel_ha_<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSTPRELHA))]
   "HAVE_AS_TLS"
   "addis %0,%1,%2@tprel@ha")
 
-(define_insn "tls_tprel_lo_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSTPRELLO))]
+(define_insn "tls_tprel_lo_<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSTPRELLO))]
   "HAVE_AS_TLS"
   "addi %0,%1,%2@tprel@l")
 
 ;; "b" output constraint here and on tls_tls input to support linker tls
 ;; optimization.  The linker may edit the instructions emitted by a
 ;; tls_got_tprel/tls_tls pair to addis,addi.
-(define_insn_and_split "tls_got_tprel_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSGOTTPREL))]
+(define_insn_and_split "tls_got_tprel_<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSGOTTPREL))]
   "HAVE_AS_TLS"
-  "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel(%1)"
+  "l<P:tls_insn_suffix> %0,%2@got@tprel(%1)"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 3)
-	(high:TLSmode
-	    (unspec:TLSmode [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTTPREL)))
+	(high:P
+	    (unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTTPREL)))
    (set (match_dup 0)
-	(lo_sum:TLSmode (match_dup 3)
-	    (unspec:TLSmode [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTTPREL)))]
+	(lo_sum:P (match_dup 3)
+	    (unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTTPREL)))]
 {
   operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
 }
   [(set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-     		   (const_int 8)
-     		   (const_int 4)))])
-
-(define_insn "*tls_got_tprel_high<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (high:TLSmode
-       (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-		       UNSPEC_TLSGOTTPREL)))]
+		   (const_int 8)
+		   (const_int 4)))])
+
+(define_insn "*tls_got_tprel_high<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+     (high:P
+       (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		  (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		 UNSPEC_TLSGOTTPREL)))]
   "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
   "addis %0,%1,%2@got@tprel@ha")
 
-(define_insn "*tls_got_tprel_low<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-     (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
-	 (unspec:TLSmode [(match_operand:TLSmode 3 "gpc_reg_operand" "b")
-			  (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			 UNSPEC_TLSGOTTPREL)))]
+(define_insn "*tls_got_tprel_low<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+     (lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
+	 (unspec:P [(match_operand:P 3 "gpc_reg_operand" "b")
+		    (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSGOTTPREL)))]
   "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
-  "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel@l(%1)")
+  "l<P:tls_insn_suffix> %0,%2@got@tprel@l(%1)")
 
-(define_insn "tls_tls_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSTLS))]
+(define_insn "tls_tls_<P:tls_abi_suffix>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSTLS))]
   "TARGET_ELF && HAVE_AS_TLS"
   "add %0,%1,%2@tls")
 

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 4/6] [RS6000] Remove constraints on call rounded_stack_size_rtx arg
  2018-11-07  5:33 [PATCH 0/6] [RS6000] inline plt call support Alan Modra
                   ` (2 preceding siblings ...)
  2018-11-07  5:38 ` [PATCH 3/6] [RS6000] Replace TLSmode with P, and correct tls call mems Alan Modra
@ 2018-11-07  5:39 ` Alan Modra
  2018-11-08  1:19   ` Segher Boessenkool
  2018-11-07  5:39 ` [PATCH 5/6] [RS6000] Use standard call patterns for __tls_get_addr calls Alan Modra
  2018-11-07  5:40 ` [PATCH 6/6] [RS6000] inline plt call sequences Alan Modra
  5 siblings, 1 reply; 34+ messages in thread
From: Alan Modra @ 2018-11-07  5:39 UTC (permalink / raw)
  To: gcc-patches; +Cc: Segher Boessenkool

This call arg is unused on rs6000.

	* config/rs6000/darwin.md (call_indirect_nonlocal_darwin64,
	call_nonlocal_darwin64, call_value_indirect_nonlocal_darwin64,
	call_value_nonlocal_darwin64): Remove constraints from second call
	arg, the rounded_stack_size_rtx arg.
	* config/rs6000/rs6000.md (tls_gd_aix, tls_gd_sysv,
	tls_gd_call_aix, tls_gd_call_sysv, tls_ld_aix, tls_ld_sysv,
	tls_ld_call_aix, tls_ld_call_sysv, call_local32, call_local64,
	call_value_local32, call_value_local64, call_indirect_nonlocal_sysv,
	call_nonlocal_sysv, call_nonlocal_sysv_secure,
	call_value_indirect_nonlocal_sysv, call_value_nonlocal_sysv,
	call_value_nonlocal_sysv_secure, call_local_aix,
	call_value_local_aix, call_nonlocal_aix, call_value_nonlocal_aix,
	call_indirect_aix, call_value_indirect_aix, call_indirect_elfv2,
	call_value_indirect_elfv2, sibcall_local32, sibcall_local64,
	sibcall_value_local32, sibcall_value_local64, sibcall_aix,
	sibcall_value_aix): Likewise.

diff --git a/gcc/config/rs6000/darwin.md b/gcc/config/rs6000/darwin.md
index 2d6d1ca57dd..a1c07702d6f 100644
--- a/gcc/config/rs6000/darwin.md
+++ b/gcc/config/rs6000/darwin.md
@@ -302,7 +302,7 @@ (define_insn "macho_correct_pic_di"
 
 (define_insn "*call_indirect_nonlocal_darwin64"
   [(call (mem:SI (match_operand:DI 0 "register_operand" "c,*l,c,*l"))
-	 (match_operand 1 "" "g,g,g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,O,n,n"))
    (clobber (reg:SI LR_REGNO))]
   "DEFAULT_ABI == ABI_DARWIN && TARGET_64BIT"
@@ -314,7 +314,7 @@ (define_insn "*call_indirect_nonlocal_darwin64"
 
 (define_insn "*call_nonlocal_darwin64"
   [(call (mem:SI (match_operand:DI 0 "symbol_ref_operand" "s,s"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "(DEFAULT_ABI == ABI_DARWIN)
@@ -332,7 +332,7 @@ (define_insn "*call_nonlocal_darwin64"
 (define_insn "*call_value_indirect_nonlocal_darwin64"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:DI 1 "register_operand" "c,*l,c,*l"))
-	      (match_operand 2 "" "g,g,g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,O,n,n"))
    (clobber (reg:SI LR_REGNO))]
   "DEFAULT_ABI == ABI_DARWIN"
@@ -345,7 +345,7 @@ (define_insn "*call_value_indirect_nonlocal_darwin64"
 (define_insn "*call_value_nonlocal_darwin64"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:DI 1 "symbol_ref_operand" "s,s"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "(DEFAULT_ABI == ABI_DARWIN)
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 3f9830bc743..bed4c6c48fa 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -9445,7 +9445,7 @@ (define_mode_attr tls_insn_suffix [(SI "wz") (DI "d")])
 (define_insn_and_split "tls_gd_aix<P:tls_abi_suffix>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
-	      (match_operand 4 "" "g")))
+	      (match_operand 4)))
    (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
 	      (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
 	     UNSPEC_TLSGD)
@@ -9479,7 +9479,7 @@ (define_insn_and_split "tls_gd_aix<P:tls_abi_suffix>"
 (define_insn_and_split "tls_gd_sysv<P:tls_sysv_suffix>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
-	      (match_operand 4 "" "g")))
+	      (match_operand 4)))
    (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
 	      (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
 	     UNSPEC_TLSGD)
@@ -9546,7 +9546,7 @@ (define_insn "*tls_gd_low<P:tls_abi_suffix>"
 (define_insn "*tls_gd_call_aix<P:tls_abi_suffix>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2 "" "g")))
+	      (match_operand 2)))
    (unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
 	     UNSPEC_TLSGD)
    (clobber (reg:SI LR_REGNO))]
@@ -9561,7 +9561,7 @@ (define_insn "*tls_gd_call_aix<P:tls_abi_suffix>"
 (define_insn "*tls_gd_call_sysv<P:tls_abi_suffix>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2 "" "g")))
+	      (match_operand 2)))
    (unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
 	     UNSPEC_TLSGD)
    (clobber (reg:SI LR_REGNO))]
@@ -9574,7 +9574,7 @@ (define_insn "*tls_gd_call_sysv<P:tls_abi_suffix>"
 (define_insn_and_split "tls_ld_aix<P:tls_abi_suffix>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
-	      (match_operand 3 "" "g")))
+	      (match_operand 3)))
    (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
 	     UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
@@ -9606,7 +9606,7 @@ (define_insn_and_split "tls_ld_aix<P:tls_abi_suffix>"
 (define_insn_and_split "tls_ld_sysv<P:tls_sysv_suffix>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
-	      (match_operand 3 "" "g")))
+	      (match_operand 3)))
    (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
 	     UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
@@ -9669,7 +9669,7 @@ (define_insn "*tls_ld_low<P:tls_abi_suffix>"
 (define_insn "*tls_ld_call_aix<P:tls_abi_suffix>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2 "" "g")))
+	      (match_operand 2)))
    (unspec:P [(const_int 0)] UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS
@@ -9683,7 +9683,7 @@ (define_insn "*tls_ld_call_aix<P:tls_abi_suffix>"
 (define_insn "*tls_ld_call_sysv<P:tls_abi_suffix>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2 "" "g")))
+	      (match_operand 2)))
    (unspec:P [(const_int 0)] UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
@@ -10445,7 +10445,7 @@ (define_expand "call_value"
 
 (define_insn "*call_local32"
   [(call (mem:SI (match_operand:SI 0 "current_file_function_operand" "s,s"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "(INTVAL (operands[2]) & CALL_LONG) == 0"
@@ -10463,7 +10463,7 @@ (define_insn "*call_local32"
 
 (define_insn "*call_local64"
   [(call (mem:SI (match_operand:DI 0 "current_file_function_operand" "s,s"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "TARGET_64BIT && (INTVAL (operands[2]) & CALL_LONG) == 0"
@@ -10482,7 +10482,7 @@ (define_insn "*call_local64"
 (define_insn "*call_value_local32"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "current_file_function_operand" "s,s"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "(INTVAL (operands[3]) & CALL_LONG) == 0"
@@ -10502,7 +10502,7 @@ (define_insn "*call_value_local32"
 (define_insn "*call_value_local64"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:DI 1 "current_file_function_operand" "s,s"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "TARGET_64BIT && (INTVAL (operands[3]) & CALL_LONG) == 0"
@@ -10527,7 +10527,7 @@ (define_insn "*call_value_local64"
 
 (define_insn "*call_indirect_nonlocal_sysv<mode>"
   [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l,c,*l"))
-	 (match_operand 1 "" "g,g,g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,O,n,n"))
    (clobber (reg:SI LR_REGNO))]
   "DEFAULT_ABI == ABI_V4
@@ -10556,7 +10556,7 @@ (define_insn "*call_indirect_nonlocal_sysv<mode>"
 
 (define_insn_and_split "*call_nonlocal_sysv<mode>"
   [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "(DEFAULT_ABI == ABI_DARWIN
@@ -10591,7 +10591,7 @@ (define_insn_and_split "*call_nonlocal_sysv<mode>"
 
 (define_insn "*call_nonlocal_sysv_secure<mode>"
   [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
    (use (match_operand:SI 3 "register_operand" "r,r"))
    (clobber (reg:SI LR_REGNO))]
@@ -10613,7 +10613,7 @@ (define_insn "*call_nonlocal_sysv_secure<mode>"
 (define_insn "*call_value_indirect_nonlocal_sysv<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l,c,*l"))
-	      (match_operand 2 "" "g,g,g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,O,n,n"))
    (clobber (reg:SI LR_REGNO))]
   "DEFAULT_ABI == ABI_V4
@@ -10643,7 +10643,7 @@ (define_insn "*call_value_indirect_nonlocal_sysv<mode>"
 (define_insn_and_split "*call_value_nonlocal_sysv<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "(DEFAULT_ABI == ABI_DARWIN
@@ -10680,7 +10680,7 @@ (define_insn_and_split "*call_value_nonlocal_sysv<mode>"
 (define_insn "*call_value_nonlocal_sysv_secure<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (use (match_operand:SI 4 "register_operand" "r,r"))
    (clobber (reg:SI LR_REGNO))]
@@ -10704,7 +10704,7 @@ (define_insn "*call_value_nonlocal_sysv_secure<mode>"
 
 (define_insn "*call_local_aix<mode>"
   [(call (mem:SI (match_operand:P 0 "current_file_function_operand" "s"))
-	 (match_operand 1 "" "g"))
+	 (match_operand 1))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
   "bl %z0"
@@ -10713,7 +10713,7 @@ (define_insn "*call_local_aix<mode>"
 (define_insn "*call_value_local_aix<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "current_file_function_operand" "s"))
-	      (match_operand 2 "" "g")))
+	      (match_operand 2)))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
   "bl %z1"
@@ -10724,7 +10724,7 @@ (define_insn "*call_value_local_aix<mode>"
 
 (define_insn "*call_nonlocal_aix<mode>"
   [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s"))
-	 (match_operand 1 "" "g"))
+	 (match_operand 1))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
@@ -10736,7 +10736,7 @@ (define_insn "*call_nonlocal_aix<mode>"
 (define_insn "*call_value_nonlocal_aix<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2 "" "g")))
+	      (match_operand 2)))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
@@ -10752,7 +10752,7 @@ (define_insn "*call_value_nonlocal_aix<mode>"
 
 (define_insn "*call_indirect_aix<mode>"
   [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
@@ -10770,7 +10770,7 @@ (define_insn "*call_indirect_aix<mode>"
 (define_insn "*call_value_indirect_aix<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
@@ -10791,7 +10791,7 @@ (define_insn "*call_value_indirect_aix<mode>"
 
 (define_insn "*call_indirect_elfv2<mode>"
   [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_ELFv2"
@@ -10808,7 +10808,7 @@ (define_insn "*call_indirect_elfv2<mode>"
 (define_insn "*call_value_indirect_elfv2<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_ELFv2"
@@ -10901,7 +10901,7 @@ (define_expand "sibcall_value"
 
 (define_insn "*sibcall_local32"
   [(call (mem:SI (match_operand:SI 0 "current_file_function_operand" "s,s"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
    (simple_return)]
   "(INTVAL (operands[2]) & CALL_LONG) == 0"
@@ -10919,7 +10919,7 @@ (define_insn "*sibcall_local32"
 
 (define_insn "*sibcall_local64"
   [(call (mem:SI (match_operand:DI 0 "current_file_function_operand" "s,s"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
    (simple_return)]
   "TARGET_64BIT && (INTVAL (operands[2]) & CALL_LONG) == 0"
@@ -10938,7 +10938,7 @@ (define_insn "*sibcall_local64"
 (define_insn "*sibcall_value_local32"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "current_file_function_operand" "s,s"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (simple_return)]
   "(INTVAL (operands[3]) & CALL_LONG) == 0"
@@ -10957,7 +10957,7 @@ (define_insn "*sibcall_value_local32"
 (define_insn "*sibcall_value_local64"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:DI 1 "current_file_function_operand" "s,s"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (simple_return)]
   "TARGET_64BIT && (INTVAL (operands[3]) & CALL_LONG) == 0"
@@ -11050,7 +11050,7 @@ (define_insn "*sibcall_value_nonlocal_sysv<mode>"
 
 (define_insn "*sibcall_aix<mode>"
   [(call (mem:SI (match_operand:P 0 "call_operand" "s,c"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (simple_return)]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
@@ -11064,7 +11064,7 @@ (define_insn "*sibcall_aix<mode>"
 (define_insn "*sibcall_value_aix<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "call_operand" "s,c"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (simple_return)]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 5/6] [RS6000] Use standard call patterns for __tls_get_addr calls
  2018-11-07  5:33 [PATCH 0/6] [RS6000] inline plt call support Alan Modra
                   ` (3 preceding siblings ...)
  2018-11-07  5:39 ` [PATCH 4/6] [RS6000] Remove constraints on call rounded_stack_size_rtx arg Alan Modra
@ 2018-11-07  5:39 ` Alan Modra
  2018-11-07  5:40 ` [PATCH 6/6] [RS6000] inline plt call sequences Alan Modra
  5 siblings, 0 replies; 34+ messages in thread
From: Alan Modra @ 2018-11-07  5:39 UTC (permalink / raw)
  To: gcc-patches; +Cc: Segher Boessenkool

The current code handling __tls_get_addr calls for powerpc*-linux
generates a call then overwrites the call insn with a special
tls_{gd,ld}_{aix,sysv} pattern.  It's done that way to support
!TARGET_TLS_MARKERS, where the arg setup insns need to be emitted
immediately before the branch and link.  When TARGET_TLS_MARKERS, the
arg setup insns are split from the actual call, but we then have a
non-standard call pattern that needs to be carried through to output.

This patch changes that scheme, to instead use the standard call
patterns for __tls_get_addr calls, except for the now rare
!TARGET_TLS_MARKERS case.  Doing it this way should be better for
maintenance as the !TARGET_TLS_MARKERS code can eventually disappear.
It also makes it possible to support longcalls (and in following
patches, inline plt calls) for __tls_get_addr without introducing yet
more special call patterns.

__tls_get_addr calls do however need to be different to standard
calls, because when TARGET_TLS_MARKERS the calls are decorated with an
argument specifier, eg. "bl __tls_get_addr(thread_var@tlsgd)" that
causes a reloc to be emitted by the assembler tying the call to its
arg setup insns.  I chose to smuggle the arg in the currently unused
stack size rtl.

I've also introduced rs6000_call_sysv to generate rtl for sysv calls,
as rs6000_call_aix does for aix and elfv2 calls.  This allows
rs6000_longcall_ref to be local to rs6000.c since the calls in the
expanders never did anything for darwin.

	* config/rs6000/predicates.md (unspec_tls): New.
	* config/rs6000/rs6000-protos.h (rs6000_output_call): Update proto.
	(rs6000_longcall_ref): Delete.
	(rs6000_call_sysv): Declare.
	* config/rs6000/rs6000.c (edit_tls_call_insn): New function.
	(global_tlsarg): New variable.
	(rs6000_legitimize_tls_address): Rewrite __tls_get_addr call
	handling.
	(print_operand): Extract UNSPEC_TLSGD address operand.
	(rs6000_output_call): Remove arg parameter, extract from second
	call operand instead.
	(rs6000_longcall_ref): Make static, localize vars.
	(rs6000_call_aix): Rename parameter to reflect new usage.  Take
	tlsarg from global_tlsarg.  Don't create unused rtl or nop insns.
	(rs6000_sibcall_aix): Rename parameter to reflect new usage.  Take
	tlsarg from global_tlsarg.
	(rs6000_call_sysv): New function.
	* config/rs6000/rs6000.md: Adjust rs6000_output_call throughout.
	(tls_sysv_suffix): Delete.
	(tls_gd_aix, tls_gd_sysv, tls_gd_call_aix, tls_gd_call_sysv): Delete.
	(tls_ld_aix, tls_ld_sysv, tls_ld_call_aix, tls_ld_call_sysv): Delete.
	(tls_gdld_aix, tls_gdld_sysv): New insns, replacing above.
	(tls_gd): Swap operand order.  Simplify mode selection.
	(tls_gd_high, tls_gd_low): Swap operand order.
	(tls_ld): Remove const_int 0 vector element from UNSPEC_TLSLD.
	Simplify mode selection.
	(tls_ld_high, tls_ld_low): Similarly adjust UNSPEC_TLSLD.
	(call, call_value): Don't assert for second call operand.
	Use rs6000_call_sysv.

diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index 40b0114a64f..8f13c1457e4 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -1039,6 +1039,13 @@ (define_predicate "rs6000_tls_symbol_ref"
   (and (match_code "symbol_ref")
        (match_test "RS6000_SYMBOL_REF_TLS_P (op)")))
 
+;; Return 1 for the UNSPEC used in TLS call operands
+(define_predicate "unspec_tls"
+  (match_code "unspec")
+{
+  return XINT (op, 1) == UNSPEC_TLSGD || XINT (op, 1) == UNSPEC_TLSLD;
+})
+
 ;; Return 1 if the operand, used inside a MEM, is a valid first argument
 ;; to CALL.  This is a SYMBOL_REF, a pseudo-register, LR or CTR.
 (define_predicate "call_operand"
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 493cfe6ba2b..9e84c692a9b 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -111,7 +111,7 @@ extern int ccr_bit (rtx, int);
 extern void rs6000_output_function_entry (FILE *, const char *);
 extern void print_operand (FILE *, rtx, int);
 extern void print_operand_address (FILE *, rtx);
-extern const char *rs6000_output_call (rtx *, unsigned int, bool, const char *);
+extern const char *rs6000_output_call (rtx *, unsigned int, bool);
 extern const char *rs6000_output_indirect_call (rtx *, unsigned int, bool);
 extern enum rtx_code rs6000_reverse_condition (machine_mode,
 					       enum rtx_code);
@@ -134,7 +134,6 @@ extern void rs6000_expand_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx);
 extern void rs6000_emit_swdiv (rtx, rtx, rtx, bool);
 extern void rs6000_emit_swsqrt (rtx, rtx, bool);
 extern void output_toc (FILE *, rtx, int, machine_mode);
-extern rtx rs6000_longcall_ref (rtx);
 extern void rs6000_fatal_bad_address (rtx);
 extern rtx create_TOC_reference (rtx, rtx);
 extern void rs6000_split_multireg_move (rtx, rtx);
@@ -202,6 +201,7 @@ extern void rs6000_split_stack_space_check (rtx, rtx);
 extern void rs6000_emit_eh_reg_restore (rtx, rtx);
 extern void rs6000_call_aix (rtx, rtx, rtx, rtx);
 extern void rs6000_sibcall_aix (rtx, rtx, rtx, rtx);
+extern void rs6000_call_sysv (rtx, rtx, rtx, rtx);
 extern void rs6000_aix_asm_output_dwarf_table_ref (char *);
 extern void get_ppc476_thunk_name (char name[32]);
 extern bool rs6000_overloaded_builtin_p (enum rs6000_builtins);
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index bf1551746d5..36e59692793 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -8583,6 +8583,43 @@ rs6000_legitimize_tls_address_aix (rtx addr, enum tls_model model)
   return dest;
 }
 
+/* Mess with a call, to make it look like the tls_gdld insns when
+   !TARGET_TLS_MARKERS.  These insns have an extra unspec to
+   differentiate them from standard calls, because they need to emit
+   the arg setup insns as well as the actual call.  That keeps the
+   arg setup insns immediately adjacent to the branch and link.  */
+
+static void
+edit_tls_call_insn (rtx arg)
+{
+  rtx call_insn = last_call_insn ();
+  if (!TARGET_TLS_MARKERS)
+    {
+      rtx patt = PATTERN (call_insn);
+      gcc_assert (GET_CODE (patt) == PARALLEL);
+      rtvec orig = XVEC (patt, 0);
+      rtvec v = rtvec_alloc (GET_NUM_ELEM (orig) + 1);
+      gcc_assert (GET_NUM_ELEM (orig) > 0);
+      /* The (set (..) (call (mem ..))).  */
+      RTVEC_ELT (v, 0) = RTVEC_ELT (orig, 0);
+      /* The extra unspec.  */
+      RTVEC_ELT (v, 1) = arg;
+      /* All other assorted call pattern pieces.  */
+      for (int i = 1; i < GET_NUM_ELEM (orig); i++)
+	RTVEC_ELT (v, i + 1) = RTVEC_ELT (orig, i);
+      XVEC (patt, 0) = v;
+    }
+  if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
+    use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
+	     pic_offset_table_rtx);
+}
+
+/* Passes the tls arg value for global dynamic and local dynamic
+   emit_library_call_value in rs6000_legitimize_Tls_address to
+   rs6000_call_aix and rs6000_call_sysv.  This is used to emit the
+   marker relocs put on __tls_get_addr calls.  */
+static rtx global_tlsarg;
+
 /* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
    this (thread-local) address.  */
 
@@ -8635,7 +8672,7 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
     }
   else
     {
-      rtx r3, got, tga, tmp1, tmp2, call_insn;
+      rtx got, tga, tmp1, tmp2;
 
       /* We currently use relocations like @got@tlsgd for tls, which
 	 means the linker will handle allocation of tls entries, placing
@@ -8675,52 +8712,42 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
 
       if (model == TLS_MODEL_GLOBAL_DYNAMIC)
 	{
+	  rtx arg = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, addr, got),
+				    UNSPEC_TLSGD);
+	  global_tlsarg = arg;
+	  rtx argreg = const0_rtx;
+	  if (TARGET_TLS_MARKERS)
+	    {
+	      argreg = gen_rtx_REG (Pmode, 3);
+	      emit_insn (gen_rtx_SET (argreg, arg));
+	    }
+
 	  tga = rs6000_tls_get_addr ();
 	  emit_library_call_value (tga, dest, LCT_CONST, Pmode,
-				   const0_rtx, Pmode);
+				   argreg, Pmode);
+	  global_tlsarg = NULL_RTX;
 
-	  r3 = gen_rtx_REG (Pmode, 3);
-	  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
-	    {
-	      if (TARGET_64BIT)
-		insn = gen_tls_gd_aix64 (r3, got, addr, tga, const0_rtx);
-	      else
-		insn = gen_tls_gd_aix32 (r3, got, addr, tga, const0_rtx);
-	    }
-	  else if (DEFAULT_ABI == ABI_V4)
-	    insn = gen_tls_gd_sysvsi (r3, got, addr, tga, const0_rtx);
-	  else
-	    gcc_unreachable ();
-	  call_insn = last_call_insn ();
-	  PATTERN (call_insn) = insn;
-	  if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
-	    use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
-		     pic_offset_table_rtx);
+	  edit_tls_call_insn (arg);
 	}
       else if (model == TLS_MODEL_LOCAL_DYNAMIC)
 	{
+	  rtx arg = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, got),
+				    UNSPEC_TLSLD);
+	  global_tlsarg = arg;
+	  rtx argreg = const0_rtx;
+	  if (TARGET_TLS_MARKERS)
+	    {
+	      argreg = gen_rtx_REG (Pmode, 3);
+	      emit_insn (gen_rtx_SET (argreg, arg));
+	    }
+
 	  tga = rs6000_tls_get_addr ();
 	  tmp1 = gen_reg_rtx (Pmode);
 	  emit_library_call_value (tga, tmp1, LCT_CONST, Pmode,
-				   const0_rtx, Pmode);
+				   argreg, Pmode);
+	  global_tlsarg = NULL_RTX;
 
-	  r3 = gen_rtx_REG (Pmode, 3);
-	  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
-	    {
-	      if (TARGET_64BIT)
-		insn = gen_tls_ld_aix64 (r3, got, tga, const0_rtx);
-	      else
-		insn = gen_tls_ld_aix32 (r3, got, tga, const0_rtx);
-	    }
-	  else if (DEFAULT_ABI == ABI_V4)
-	    insn = gen_tls_ld_sysvsi (r3, got, tga, const0_rtx);
-	  else
-	    gcc_unreachable ();
-	  call_insn = last_call_insn ();
-	  PATTERN (call_insn) = insn;
-	  if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
-	    use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
-		     pic_offset_table_rtx);
+	  edit_tls_call_insn (arg);
 
 	  if (rs6000_tls_size == 16)
 	    {
@@ -21183,19 +21210,19 @@ print_operand (FILE *file, rtx x, int code)
 	  else
 	    output_address (GET_MODE (x), XEXP (x, 0));
 	}
+      else if (toc_relative_expr_p (x, false,
+				    &tocrel_base_oac, &tocrel_offset_oac))
+	/* This hack along with a corresponding hack in
+	   rs6000_output_addr_const_extra arranges to output addends
+	   where the assembler expects to find them.  eg.
+	   (plus (unspec [(symbol_ref ("x")) (reg 2)] tocrel) 4)
+	   without this hack would be output as "x@toc+4".  We
+	   want "x+4@toc".  */
+	output_addr_const (file, CONST_CAST_RTX (tocrel_base_oac));
+      else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSGD)
+	output_addr_const (file, XVECEXP (x, 0, 0));
       else
-	{
-	  if (toc_relative_expr_p (x, false, &tocrel_base_oac, &tocrel_offset_oac))
-	    /* This hack along with a corresponding hack in
-	       rs6000_output_addr_const_extra arranges to output addends
-	       where the assembler expects to find them.  eg.
-	       (plus (unspec [(symbol_ref ("x")) (reg 2)] tocrel) 4)
-	       without this hack would be output as "x@toc+4".  We
-	       want "x+4@toc".  */
-	    output_addr_const (file, CONST_CAST_RTX (tocrel_base_oac));
-	  else
-	    output_addr_const (file, x);
-	}
+	output_addr_const (file, x);
       return;
 
     case '&':
@@ -21381,17 +21408,27 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
 }
 
 /* Return a template string for assembly to emit when making an
-   external call.  FUN is the %z argument, ARG is either NULL or
-   a @TLSGD or @TLSLD __tls_get_addr argument specifier.  */
+   external call.  FUN is the %z argument.  */
 
 const char *
-rs6000_output_call (rtx *operands, unsigned int fun, bool sibcall,
-		    const char *arg)
+rs6000_output_call (rtx *operands, unsigned int fun, bool sibcall)
 {
   /* -Wformat-overflow workaround, without which gcc thinks that %u
       might produce 10 digits.  FUN is 0 or 1 as of 2018-03.  */
   gcc_assert (fun <= 6);
 
+  char arg[11];
+  arg[0] = 0;
+  if (GET_CODE (operands[fun + 1]) == UNSPEC)
+    {
+      if (XINT (operands[fun + 1], 1) == UNSPEC_TLSGD)
+	sprintf (arg, "(%%%u@tlsgd)", fun + 1);
+      else if (XINT (operands[fun + 1], 1) == UNSPEC_TLSLD)
+	sprintf (arg, "(%%&@tlsld)");
+      else
+	gcc_unreachable ();
+    }
+
   /* The magic 32768 offset here corresponds to the offset of
      r30 in .got2, as given by LCTOC1.  See sysv4.h:toc_section.  */
   char z[10];
@@ -32484,23 +32521,20 @@ rs6000_set_default_type_attributes (tree type)
 /* Return a reference suitable for calling a function with the
    longcall attribute.  */
 
-rtx
+static rtx
 rs6000_longcall_ref (rtx call_ref)
 {
-  const char *call_name;
-  tree node;
-
   if (GET_CODE (call_ref) != SYMBOL_REF)
     return call_ref;
 
   /* System V adds '.' to the internal name, so skip them.  */
-  call_name = XSTR (call_ref, 0);
+  const char *call_name = XSTR (call_ref, 0);
   if (*call_name == '.')
     {
       while (*call_name == '.')
 	call_name++;
 
-      node = get_identifier (call_name);
+      tree node = get_identifier (call_name);
       call_ref = gen_rtx_SYMBOL_REF (VOIDmode, IDENTIFIER_POINTER (node));
     }
 
@@ -37472,7 +37506,7 @@ chain_already_loaded (rtx_insn *last)
 /* Expand code to perform a call under the AIX or ELFv2 ABI.  */
 
 void
-rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
+rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 {
   const bool direct_call_p
     = GET_CODE (func_desc) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (func_desc);
@@ -37485,6 +37519,9 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
   int n_call;
   rtx insn;
 
+  if (global_tlsarg)
+    tlsarg = global_tlsarg;
+
   /* Handle longcall attributes.  */
   if (INTVAL (cookie) & CALL_LONG)
     func_desc = rs6000_longcall_ref (func_desc);
@@ -37495,11 +37532,7 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
     {
       /* Save the TOC into its reserved slot before the call,
 	 and prepare to restore it after the call.  */
-      rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
       rtx stack_toc_offset = GEN_INT (RS6000_TOC_SAVE_SLOT);
-      rtx stack_toc_mem = gen_frame_mem (Pmode,
-					 gen_rtx_PLUS (Pmode, stack_ptr,
-						       stack_toc_offset));
       rtx stack_toc_unspec = gen_rtx_UNSPEC (Pmode,
 					     gen_rtvec (1, stack_toc_offset),
 					     UNSPEC_TOCSLOT);
@@ -37511,6 +37544,10 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
 	cfun->machine->save_toc_in_prologue = true;
       else
 	{
+	  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;
 	  emit_move_insn (stack_toc_mem, toc_reg);
 	}
@@ -37520,7 +37557,8 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
 	  /* A function pointer in the ELFv2 ABI is just a plain address, but
 	     the ABI requires it to be loaded into r12 before the call.  */
 	  func_addr = gen_rtx_REG (Pmode, 12);
-	  emit_move_insn (func_addr, func_desc);
+	  if (!rtx_equal_p (func_addr, func_desc))
+	    emit_move_insn (func_addr, func_desc);
 	  abi_reg = func_addr;
 	}
       else
@@ -37575,7 +37613,7 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
     }
 
   /* Create the call.  */
-  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), flag);
+  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), tlsarg);
   if (value != NULL_RTX)
     call[0] = gen_rtx_SET (value, call[0]);
   n_call = 1;
@@ -37599,15 +37637,18 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
 /* Expand code to perform a sibling call under the AIX or ELFv2 ABI.  */
 
 void
-rs6000_sibcall_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
+rs6000_sibcall_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 {
   rtx call[2];
   rtx insn;
 
   gcc_assert (INTVAL (cookie) == 0);
 
+  if (global_tlsarg)
+    tlsarg = global_tlsarg;
+
   /* Create the call.  */
-  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_desc), flag);
+  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_desc), tlsarg);
   if (value != NULL_RTX)
     call[0] = gen_rtx_SET (value, call[0]);
 
@@ -37620,6 +37661,42 @@ rs6000_sibcall_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
   use_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (Pmode, TOC_REGNUM));
 }
 
+/* Expand code to perform a call under the SYSV4 ABI.  */
+
+void
+rs6000_call_sysv (rtx value, rtx func, rtx tlsarg, rtx cookie)
+{
+  rtx func_addr;
+  rtx call[3];
+  rtx insn;
+
+  if (global_tlsarg)
+    tlsarg = global_tlsarg;
+
+  /* Handle longcall attributes.  */
+  if (INTVAL (cookie) & CALL_LONG)
+    func = rs6000_longcall_ref (func);
+
+  /* Handle indirect calls.  */
+  if (GET_CODE (func) != SYMBOL_REF)
+    func_addr = force_reg (Pmode, func);
+  else
+    func_addr = func;
+
+  /* Create the call.  */
+  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), tlsarg);
+  if (value != NULL_RTX)
+    call[0] = gen_rtx_SET (value, call[0]);
+
+  unsigned int mask = CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS;
+  call[1] = gen_rtx_USE (VOIDmode, GEN_INT (INTVAL (cookie) & mask));
+
+  call[2] = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
+
+  insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
+  insn = emit_call_insn (insn);
+}
+
 /* Return whether we need to always update the saved TOC pointer when we update
    the stack pointer.  */
 
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index bed4c6c48fa..d1451509aa7 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -9439,77 +9439,75 @@ (define_peephole2
 
 ;; Mode attributes for different ABIs.
 (define_mode_attr tls_abi_suffix [(SI "32") (DI "64")])
-(define_mode_attr tls_sysv_suffix [(SI "si") (DI "di")])
 (define_mode_attr tls_insn_suffix [(SI "wz") (DI "d")])
 
-(define_insn_and_split "tls_gd_aix<P:tls_abi_suffix>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
-	      (match_operand 4)))
-   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
-	      (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
-	     UNSPEC_TLSGD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
+(define_insn "*tls_gdld_aix<P:tls_abi_suffix>"
+  [(match_parallel 3 ""
+    [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+	  (call (mem:SI (match_operand:P 1))
+		(match_operand:P 2 "unspec_tls")))
+     (match_dup 2)])]
+  "HAVE_AS_TLS && !TARGET_TLS_MARKERS
+   && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
 {
-  if (TARGET_CMODEL != CMODEL_SMALL)
-    output_asm_insn ("addis %0,%1,%2@got@tlsgd@ha\;"
-		     "addi %0,%0,%2@got@tlsgd@l", operands);
+  rtx op[3];
+  op[0] = operands[0];
+  op[1] = XVECEXP (operands[2], 0, 0);
+  if (XINT (operands[2], 1) == UNSPEC_TLSGD)
+    {
+      op[2] = XVECEXP (operands[2], 0, 1);
+      if (TARGET_CMODEL != CMODEL_SMALL)
+	output_asm_insn ("addis %0,%2,%1@got@tlsgd@ha\;"
+			 "addi %0,%0,%1@got@tlsgd@l", op);
+      else
+	output_asm_insn ("addi %0,%2,%1@got@tlsgd", op);
+    }
   else
-    output_asm_insn ("addi %0,%1,%2@got@tlsgd", operands);
-  return rs6000_output_call (operands, 3, false, "");
+    {
+      if (TARGET_CMODEL != CMODEL_SMALL)
+	output_asm_insn ("addis %0,%1,%&@got@tlsld@ha\;"
+			 "addi %0,%0,%&@got@tlsld@l", op);
+      else
+	output_asm_insn ("addi %0,%1,%&@got@tlsld", op);
+    }
+  return rs6000_output_call (operands, 1, false);
 }
-  "&& TARGET_TLS_MARKERS"
-  [(set (match_dup 0)
-	(unspec:P [(match_dup 1)
-		   (match_dup 2)]
-		  UNSPEC_TLSGD))
-   (parallel [(set (match_dup 0)
-		   (call (mem:SI (match_dup 3))
-			 (match_dup 4)))
-	      (unspec:P [(match_dup 2)] UNSPEC_TLSGD)
-	      (clobber (reg:SI LR_REGNO))])]
-  ""
   [(set_attr "type" "two")
    (set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
 		   (const_int 16)
 		   (const_int 12)))])
 
-(define_insn_and_split "tls_gd_sysv<P:tls_sysv_suffix>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
-	      (match_operand 4)))
-   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
-	      (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
-	     UNSPEC_TLSGD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
+(define_insn "*tls_gdld_sysv<P:tls_abi_suffix>"
+  [(match_parallel 3 ""
+    [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+	  (call (mem:SI (match_operand:P 1))
+		(match_operand:P 2 "unspec_tls")))
+     (match_dup 2)])]
+  "HAVE_AS_TLS && !TARGET_TLS_MARKERS && DEFAULT_ABI == ABI_V4"
 {
-  output_asm_insn ("addi %0,%1,%2@got@tlsgd", operands);
-  return rs6000_output_call (operands, 3, false, "");
+  rtx op[3];
+  op[0] = operands[0];
+  op[1] = XVECEXP (operands[2], 0, 0);
+  if (XINT (operands[2], 1) == UNSPEC_TLSGD)
+    {
+      op[2] = XVECEXP (operands[2], 0, 1);
+      output_asm_insn ("addi %0,%2,%1@got@tlsgd", op);
+    }
+  else
+    output_asm_insn ("addi %0,%1,%&@got@tlsld", op);
+  return rs6000_output_call (operands, 1, false);
 }
-  "&& TARGET_TLS_MARKERS"
-  [(set (match_dup 0)
-	(unspec:P [(match_dup 1)
-		   (match_dup 2)]
-		  UNSPEC_TLSGD))
-   (parallel [(set (match_dup 0)
-		   (call (mem:SI (match_dup 3))
-			 (match_dup 4)))
-	      (unspec:P [(match_dup 2)] UNSPEC_TLSGD)
-	      (clobber (reg:SI LR_REGNO))])]
-  ""
   [(set_attr "type" "two")
    (set_attr "length" "8")])
 
 (define_insn_and_split "*tls_gd<P:tls_abi_suffix>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
-		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+	(unspec:P [(match_operand:P 1 "rs6000_tls_symbol_ref" "")
+		   (match_operand:P 2 "gpc_reg_operand" "b")]
 		  UNSPEC_TLSGD))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS"
-  "addi %0,%1,%2@got@tlsgd"
+  "addi %0,%2,%1@got@tlsgd"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 3)
 	(high:P
@@ -9518,7 +9516,7 @@ (define_insn_and_split "*tls_gd<P:tls_abi_suffix>"
 	(lo_sum:P (match_dup 3)
 	    (unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGD)))]
 {
-  operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
+  operands[3] = gen_reg_rtx (<MODE>mode);
 }
   [(set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
@@ -9528,105 +9526,21 @@ (define_insn_and_split "*tls_gd<P:tls_abi_suffix>"
 (define_insn "*tls_gd_high<P:tls_abi_suffix>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
      (high:P
-       (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
-		  (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+       (unspec:P [(match_operand:P 1 "rs6000_tls_symbol_ref" "")
+		  (match_operand:P 2 "gpc_reg_operand" "b")]
 		 UNSPEC_TLSGD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
-  "addis %0,%1,%2@got@tlsgd@ha")
+  "addis %0,%2,%1@got@tlsgd@ha")
 
 (define_insn "*tls_gd_low<P:tls_abi_suffix>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
      (lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
-       (unspec:P [(match_operand:P 3 "gpc_reg_operand" "b")
-		  (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+       (unspec:P [(match_operand:P 2 "rs6000_tls_symbol_ref" "")
+		  (match_operand:P 3 "gpc_reg_operand" "b")]
 		 UNSPEC_TLSGD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addi %0,%1,%2@got@tlsgd@l")
 
-(define_insn "*tls_gd_call_aix<P:tls_abi_suffix>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2)))
-   (unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
-	     UNSPEC_TLSGD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && TARGET_TLS_MARKERS
-   && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
-{
-  return rs6000_output_call (operands, 1, false, "(%3@tlsgd)");
-}
-  [(set_attr "type" "branch")
-   (set_attr "length" "8")])
-
-(define_insn "*tls_gd_call_sysv<P:tls_abi_suffix>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2)))
-   (unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
-	     UNSPEC_TLSGD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
-{
-  return rs6000_output_call (operands, 1, false, "(%3@tlsgd)");
-}
-  [(set_attr "type" "branch")])
-
-(define_insn_and_split "tls_ld_aix<P:tls_abi_suffix>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
-	      (match_operand 3)))
-   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
-	     UNSPEC_TLSLD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
-{
-  if (TARGET_CMODEL != CMODEL_SMALL)
-    output_asm_insn ("addis %0,%1,%&@got@tlsld@ha\;"
-		     "addi %0,%0,%&@got@tlsld@l", operands);
-  else
-    output_asm_insn ("addi %0,%1,%&@got@tlsld", operands);
-  return rs6000_output_call (operands, 2, false, "");
-}
-  "&& TARGET_TLS_MARKERS"
-  [(set (match_dup 0)
-	(unspec:P [(match_dup 1)]
-		  UNSPEC_TLSLD))
-   (parallel [(set (match_dup 0)
-		   (call (mem:SI (match_dup 2))
-			 (match_dup 3)))
-	      (unspec:P [(const_int 0)] UNSPEC_TLSLD)
-	      (clobber (reg:SI LR_REGNO))])]
-  ""
-  [(set_attr "type" "two")
-   (set (attr "length")
-     (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-		   (const_int 16)
-		   (const_int 12)))])
-
-(define_insn_and_split "tls_ld_sysv<P:tls_sysv_suffix>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
-	      (match_operand 3)))
-   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
-	     UNSPEC_TLSLD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
-{
-  output_asm_insn ("addi %0,%1,%&@got@tlsld", operands);
-  return rs6000_output_call (operands, 2, false, "");
-}
-  "&& TARGET_TLS_MARKERS"
-  [(set (match_dup 0)
-	(unspec:P [(match_dup 1)]
-		  UNSPEC_TLSLD))
-   (parallel [(set (match_dup 0)
-		   (call (mem:SI (match_dup 2))
-			 (match_dup 3)))
-	      (unspec:P [(const_int 0)] UNSPEC_TLSLD)
-	      (clobber (reg:SI LR_REGNO))])]
-  ""
-  [(set_attr "length" "8")])
-
 (define_insn_and_split "*tls_ld<P:tls_abi_suffix>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
 	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
@@ -9636,12 +9550,12 @@ (define_insn_and_split "*tls_ld<P:tls_abi_suffix>"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 2)
 	(high:P
-	    (unspec:P [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))
+	    (unspec:P [(match_dup 1)] UNSPEC_TLSLD)))
    (set (match_dup 0)
 	(lo_sum:P (match_dup 2)
-	    (unspec:P [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))]
+	    (unspec:P [(match_dup 1)] UNSPEC_TLSLD)))]
 {
-  operands[2] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
+  operands[2] = gen_reg_rtx (<MODE>mode);
 }
   [(set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
@@ -9651,8 +9565,7 @@ (define_insn_and_split "*tls_ld<P:tls_abi_suffix>"
 (define_insn "*tls_ld_high<P:tls_abi_suffix>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
      (high:P
-       (unspec:P [(const_int 0)
-		  (match_operand:P 1 "gpc_reg_operand" "b")]
+       (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
 		 UNSPEC_TLSLD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addis %0,%1,%&@got@tlsld@ha")
@@ -9660,38 +9573,11 @@ (define_insn "*tls_ld_high<P:tls_abi_suffix>"
 (define_insn "*tls_ld_low<P:tls_abi_suffix>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
      (lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
-       (unspec:P [(const_int 0)
-		  (match_operand:P 2 "gpc_reg_operand" "b")]
+       (unspec:P [(match_operand:P 2 "gpc_reg_operand" "b")]
 		 UNSPEC_TLSLD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addi %0,%1,%&@got@tlsld@l")
 
-(define_insn "*tls_ld_call_aix<P:tls_abi_suffix>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2)))
-   (unspec:P [(const_int 0)] UNSPEC_TLSLD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && TARGET_TLS_MARKERS
-   && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
-{
-  return rs6000_output_call (operands, 1, false, "(%&@tlsld)");
-}
-  [(set_attr "type" "branch")
-   (set_attr "length" "8")])
-
-(define_insn "*tls_ld_call_sysv<P:tls_abi_suffix>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2)))
-   (unspec:P [(const_int 0)] UNSPEC_TLSLD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
-{
-  return rs6000_output_call (operands, 1, false, "(%&@tlsld)");
-}
-  [(set_attr "type" "branch")])
-
 (define_insn "tls_dtprel_<P:tls_abi_suffix>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=r")
 	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
@@ -10365,7 +10251,6 @@ (define_expand "call"
 #endif
 
   gcc_assert (GET_CODE (operands[0]) == MEM);
-  gcc_assert (GET_CODE (operands[1]) == CONST_INT);
 
   operands[0] = XEXP (operands[0], 0);
 
@@ -10375,23 +10260,14 @@ (define_expand "call"
       DONE;
     }
 
-  if (GET_CODE (operands[0]) != SYMBOL_REF
-      || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[2]) & CALL_LONG) != 0))
+  if (DEFAULT_ABI == ABI_V4)
     {
-      if (INTVAL (operands[2]) & CALL_LONG)
-	operands[0] = rs6000_longcall_ref (operands[0]);
-
-      switch (DEFAULT_ABI)
-        {
-	case ABI_V4:
-	case ABI_DARWIN:
-	  operands[0] = force_reg (Pmode, operands[0]);
-	  break;
-
-	default:
-	  gcc_unreachable ();
-	}
+      rs6000_call_sysv (NULL_RTX, operands[0], operands[1], operands[2]);
+      DONE;
     }
+
+  if (GET_CODE (operands[0]) != SYMBOL_REF)
+    operands[0] = force_reg (Pmode, operands[0]);
 })
 
 (define_expand "call_value"
@@ -10408,7 +10284,6 @@ (define_expand "call_value"
 #endif
 
   gcc_assert (GET_CODE (operands[1]) == MEM);
-  gcc_assert (GET_CODE (operands[2]) == CONST_INT);
 
   operands[1] = XEXP (operands[1], 0);
 
@@ -10418,23 +10293,14 @@ (define_expand "call_value"
       DONE;
     }
 
-  if (GET_CODE (operands[1]) != SYMBOL_REF
-      || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[3]) & CALL_LONG) != 0))
+  if (DEFAULT_ABI == ABI_V4)
     {
-      if (INTVAL (operands[3]) & CALL_LONG)
-	operands[1] = rs6000_longcall_ref (operands[1]);
-
-      switch (DEFAULT_ABI)
-        {
-	case ABI_V4:
-	case ABI_DARWIN:
-	  operands[1] = force_reg (Pmode, operands[1]);
-	  break;
-
-	default:
-	  gcc_unreachable ();
-	}
+      rs6000_call_sysv (operands[0], operands[1], operands[2], operands[3]);
+      DONE;
     }
+
+  if (GET_CODE (operands[1]) != SYMBOL_REF)
+    operands[1] = force_reg (Pmode, operands[1]);
 })
 
 ;; Call to function in current module.  No TOC pointer reload needed.
@@ -10521,7 +10387,7 @@ (define_insn "*call_value_local64"
 
 ;; A function pointer under System V is just a normal pointer
 ;; operands[0] is the function pointer
-;; operands[1] is the stack size to clean up
+;; operands[1] is the tls call arg
 ;; operands[2] is the value FUNCTION_ARG returns for the VOID argument
 ;; which indicates how to set cr1
 
@@ -10572,7 +10438,7 @@ (define_insn_and_split "*call_nonlocal_sysv<mode>"
 #if TARGET_MACHO
   return macho_output_call(insn, operands, 0, 2);
 #else
-  return rs6000_output_call (operands, 0, false, "");
+  return rs6000_output_call (operands, 0, false);
 #endif
 }
   "DEFAULT_ABI == ABI_V4
@@ -10605,7 +10471,7 @@ (define_insn "*call_nonlocal_sysv_secure<mode>"
   else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  return rs6000_output_call (operands, 0, false, "");
+  return rs6000_output_call (operands, 0, false);
 }
   [(set_attr "type" "branch,branch")
    (set_attr "length" "4,8")])
@@ -10659,7 +10525,7 @@ (define_insn_and_split "*call_value_nonlocal_sysv<mode>"
 #if TARGET_MACHO
   return macho_output_call(insn, operands, 1, 3);
 #else
-  return rs6000_output_call (operands, 1, false, "");
+  return rs6000_output_call (operands, 1, false);
 #endif
 }
   "DEFAULT_ABI == ABI_V4
@@ -10694,7 +10560,7 @@ (define_insn "*call_value_nonlocal_sysv_secure<mode>"
   else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  return rs6000_output_call (operands, 1, false, "");
+  return rs6000_output_call (operands, 1, false);
 }
   [(set_attr "type" "branch,branch")
    (set_attr "length" "4,8")])
@@ -10728,7 +10594,7 @@ (define_insn "*call_nonlocal_aix<mode>"
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
-  return rs6000_output_call (operands, 0, false, "");
+  return rs6000_output_call (operands, 0, false);
 }
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
@@ -10740,7 +10606,7 @@ (define_insn "*call_value_nonlocal_aix<mode>"
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
-  return rs6000_output_call (operands, 1, false, "");
+  return rs6000_output_call (operands, 1, false);
 }
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
@@ -10991,7 +10857,7 @@ (define_insn "*sibcall_nonlocal_sysv<mode>"
   if (which_alternative >= 2)
     return rs6000_output_indirect_call (operands, 0, true);
   else
-    return rs6000_output_call (operands, 0, true, "");
+    return rs6000_output_call (operands, 0, true);
 }
   [(set_attr "type" "branch")
    (set_attr_alternative "length"
@@ -11031,7 +10897,7 @@ (define_insn "*sibcall_value_nonlocal_sysv<mode>"
 	return "crset 2\;beq%T1-\;b $";
     }
   else
-    return rs6000_output_call (operands, 1, true, "");
+    return rs6000_output_call (operands, 1, true);
 }
   [(set_attr "type" "branch")
    (set_attr_alternative "length"
@@ -11055,7 +10921,7 @@ (define_insn "*sibcall_aix<mode>"
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
   if (which_alternative == 0)
-    return rs6000_output_call (operands, 0, true, "");
+    return rs6000_output_call (operands, 0, true);
   else
     return "b%T0";
 }
@@ -11069,7 +10935,7 @@ (define_insn "*sibcall_value_aix<mode>"
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
   if (which_alternative == 0)
-    return rs6000_output_call (operands, 1, true, "");
+    return rs6000_output_call (operands, 1, true);
   else
     return "b%T1";
 }

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 6/6] [RS6000] inline plt call sequences
  2018-11-07  5:33 [PATCH 0/6] [RS6000] inline plt call support Alan Modra
                   ` (4 preceding siblings ...)
  2018-11-07  5:39 ` [PATCH 5/6] [RS6000] Use standard call patterns for __tls_get_addr calls Alan Modra
@ 2018-11-07  5:40 ` Alan Modra
  5 siblings, 0 replies; 34+ messages in thread
From: Alan Modra @ 2018-11-07  5:40 UTC (permalink / raw)
  To: gcc-patches; +Cc: Segher Boessenkool

Finally, the point of the previous patches in this series, support for
inline PLT calls, keyed off -fno-plt.  This emits code using new
relocations that tie all insns in the sequence together, so that the
linker can edit the sequence back to a direct call should the call
target turn out to be local.  An example of ELFv2 code to call puts is
as follows:

     .reloc .,R_PPC64_PLTSEQ,puts
        std 2,24(1)
     .reloc .,R_PPC64_PLT16_HA,puts
        addis 12,2,0
     .reloc .,R_PPC64_PLT16_LO_DS,puts
        ld 12,0(12)
     .reloc .,R_PPC64_PLTSEQ,puts
        mtctr 12
     .reloc .,R_PPC64_PLTCALL,puts
        bctrl
        ld 2,24(1)

"addis 12,2,puts@plt@ha" and "ld 12,puts@plt@l(12)" are also supported
by the assembler.  gcc instead uses the explicit R_PPC64_PLT16_HA and
R_PPC64_PLT16_LO_DS relocs because when the call is to __tls_get_addr
an extra reloc is emitted at every place where one is shown above, to
specify the __tls_get_addr arg.  The linker expects the extra reloc to
come first.  .reloc enforces that ordering.

The patch also changes code emitted for longcalls if the assembler
supports the new marker relocs, so that these too can be edited.  One
side effect of longcalls using PLT16 relocs is that they can now be
resolved lazily by ld.so.

I don't support lazy inline PLT calls for ELFv1, because ELFv1 would
need barriers to reliably load both the function address and toc
pointer from the PLT.  ELFv1 -fno-plt uses the longcall sequence
instead, which isn't edited by GNU ld.

	* config.in (HAVE_AS_PLTSEQ): Add.
	* config/rs6000/predicates.md (indirect_call_operand): New.
	* config/rs6000/rs6000-protos.h (rs6000_output_pltseq): Declare.
	* config/rs6000/rs6000.c (init_cumulative_args): Set cookie
	CALL_LONG for -fno-plt.
	(print_operand <T, z, 0>): Handle UNSPEC_PLTSEQ.
	(rs6000_output_indirect_call): Emit .reloc directives for
	UNSPEC_PLTSEQ calls.
	(rs6000_output_pltseq): New function.
	(rs6000_longcall_ref): Add arg parameter.  Use PLT16 insns if
	relocs supported by assembler.  Move SYMBOL_REF test to callers.
	(rs6000_call_aix): Adjust rs6000_longcall_ref call.  Package
	insns in UNSPEC_PLTSEQ, preserving original func_desc.
	(rs6000_call_sysv): Likewise.
	(rs6000_sibcall_sysv): New function.
	* config/rs6000/rs6000-protos.h (rs6000_sibcall_sysv): Declare.
	* config/rs6000/rs6000.h (HAVE_AS_PLTSEQ): Provide default.
	* config/rs6000/rs6000.md (UNSPEC_PLTSEQ, UNSPEC_PLT16_HA,
	UNSPEC_PLT16_LO): New.
	(pltseq_tocsave, pltseq_plt16_ha, pltseq_plt16_lo, pltseq_mtctr): New.
	(call_indirect_nonlocal_sysv): Don't differentiate zero from non-zero
	cookie in constraints.  Test explicitly for flags in length attr.
	Handle unspec operand 1.
	(call_value_indirect_nonlocal_sysv): Likewise.
	(call_indirect_aix, call_value_indirect_aix): Handle unspec operand 1.
	(call_indirect_elfv2, call_value_indirect_elfv2): Likewise.
	(sibcall, sibcall_value): Use rs6000_sibcall_sysv.
	(sibcall_indirect_nonlocal_sysv): New pattern.
	(sibcall_value_indirect_nonlocal_sysv): Likewise.
	(sibcall_nonlocal_sysv, sibcall_value_nonlocal_sysv): Remove indirect
	call alternatives.
	* configure.ac: Check for gas plt sequence marker support.
	* configure: Regenerate.

diff --git a/gcc/config.in b/gcc/config.in
index 67a1e6cfc4c..86ff5e8636b 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -577,6 +577,12 @@
 #endif
 
 
+/* Define if your assembler supports R_PPC*_PLTSEQ relocations. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_PLTSEQ
+#endif
+
+
 /* Define if your assembler supports .ref */
 #ifndef USED_FOR_TARGET
 #undef HAVE_AS_REF
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index 8f13c1457e4..805d92ea1f1 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -1055,6 +1055,24 @@ (define_predicate "call_operand"
 		  || REGNO (op) >= FIRST_PSEUDO_REGISTER")
      (match_code "symbol_ref")))
 
+;; Return 1 if the operand, used inside a MEM, is a valid first argument
+;; to an indirect CALL.  This is LR, CTR, or a PLTSEQ unspec using CTR.
+(define_predicate "indirect_call_operand"
+  (match_code "reg,unspec")
+{
+  if (REG_P (op))
+    return (REGNO (op) == LR_REGNO
+	    || REGNO (op) == CTR_REGNO);
+  if (GET_CODE (op) == UNSPEC)
+    {
+      if (XINT (op, 1) != UNSPEC_PLTSEQ)
+	return false;
+      op = XVECEXP (op, 0, 0);
+      return REG_P (op) && REGNO (op) == CTR_REGNO;
+    }
+  return false;
+})
+
 ;; Return 1 if the operand is a SYMBOL_REF for a function known to be in
 ;; this file.
 (define_predicate "current_file_function_operand"
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 9e84c692a9b..27a161983da 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -113,6 +113,7 @@ extern void print_operand (FILE *, rtx, int);
 extern void print_operand_address (FILE *, rtx);
 extern const char *rs6000_output_call (rtx *, unsigned int, bool);
 extern const char *rs6000_output_indirect_call (rtx *, unsigned int, bool);
+extern const char *rs6000_output_pltseq (rtx *, int);
 extern enum rtx_code rs6000_reverse_condition (machine_mode,
 					       enum rtx_code);
 extern rtx rs6000_emit_eqne (machine_mode, rtx, rtx, rtx);
@@ -202,6 +203,7 @@ extern void rs6000_emit_eh_reg_restore (rtx, rtx);
 extern void rs6000_call_aix (rtx, rtx, rtx, rtx);
 extern void rs6000_sibcall_aix (rtx, rtx, rtx, rtx);
 extern void rs6000_call_sysv (rtx, rtx, rtx, rtx);
+extern void rs6000_sibcall_sysv (rtx, rtx, rtx, rtx);
 extern void rs6000_aix_asm_output_dwarf_table_ref (char *);
 extern void get_ppc476_thunk_name (char name[32]);
 extern bool rs6000_overloaded_builtin_p (enum rs6000_builtins);
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 36e59692793..d90d9823943 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -10706,7 +10706,7 @@ void
 init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
 		      rtx libname ATTRIBUTE_UNUSED, int incoming,
 		      int libcall, int n_named_args,
-		      tree fndecl ATTRIBUTE_UNUSED,
+		      tree fndecl,
 		      machine_mode return_mode ATTRIBUTE_UNUSED)
 {
   static CUMULATIVE_ARGS zero_cumulative;
@@ -10727,10 +10727,20 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
     cum->nargs_prototype = n_named_args;
 
   /* Check for a longcall attribute.  */
-  if ((!fntype && rs6000_default_long_calls)
-      || (fntype
-	  && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
-	  && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))))
+  if (((!fntype && rs6000_default_long_calls)
+       || (fntype
+	   && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
+	   && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))))
+      || (DEFAULT_ABI != ABI_DARWIN
+	  && !(fndecl
+	       && !DECL_EXTERNAL (fndecl)
+	       && !DECL_WEAK (fndecl)
+	       && (*targetm.binds_local_p) (fndecl))
+	  && (flag_plt
+	      ? (fntype
+		 && lookup_attribute ("noplt", TYPE_ATTRIBUTES (fntype)))
+	      : !(fntype
+		  && lookup_attribute ("plt", TYPE_ATTRIBUTES (fntype))))))
     cum->call_cookie |= CALL_LONG;
 
   if (TARGET_DEBUG_ARG)
@@ -20963,6 +20973,8 @@ print_operand (FILE *file, rtx x, int code)
 
     case 'T':
       /* Print the symbolic name of a branch target register.  */
+      if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_PLTSEQ)
+	x = XVECEXP (x, 0, 0);
       if (GET_CODE (x) != REG || (REGNO (x) != LR_REGNO
 				  && REGNO (x) != CTR_REGNO))
 	output_operand_lossage ("invalid %%T value");
@@ -21106,6 +21118,8 @@ print_operand (FILE *file, rtx x, int code)
       return;
 
     case 'z':
+      if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_PLTSEQ)
+	x = XVECEXP (x, 0, 1);
       /* X is a SYMBOL_REF.  Write out the name preceded by a
 	 period and without any trailing data in brackets.  Used for function
 	 names.  If we are configured for System V (or the embedded ABI) on
@@ -21221,6 +21235,8 @@ print_operand (FILE *file, rtx x, int code)
 	output_addr_const (file, CONST_CAST_RTX (tocrel_base_oac));
       else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSGD)
 	output_addr_const (file, XVECEXP (x, 0, 0));
+      else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_PLTSEQ)
+	output_addr_const (file, XVECEXP (x, 0, 1));
       else
 	output_addr_const (file, x);
       return;
@@ -21457,60 +21473,158 @@ rs6000_output_indirect_call (rtx *operands, unsigned int fun, bool sibcall)
       might produce 10 digits.  FUN is 0 or 1 as of 2018-03.  */
   gcc_assert (fun <= 6);
 
-  static char str[144];
+  static char str[144];  /* 1 spare */
+  char *s = str;
   const char *ptrload = TARGET_64BIT ? "d" : "wz";
 
+  if (DEFAULT_ABI == ABI_AIX)
+    s += sprintf (s,
+		  "l%s 2,%%%u\n\t",
+		  ptrload, fun + 2);
+
   bool speculate = (rs6000_speculate_indirect_jumps
 		    || (REG_P (operands[fun])
 			&& REGNO (operands[fun]) == LR_REGNO));
 
+  if (HAVE_AS_PLTSEQ && GET_CODE (operands[fun]) == UNSPEC)
+    {
+      const char *rel64 = TARGET_64BIT ? "64" : "";
+      char tls[28];
+      tls[0] = 0;
+      if (GET_CODE (operands[fun + 1]) == UNSPEC)
+	{
+	  if (XINT (operands[fun + 1], 1) == UNSPEC_TLSGD)
+	    sprintf (tls, ".reloc .,R_PPC%s_TLSGD,%%%u\n\t",
+		     rel64, fun + 1);
+	  else if (XINT (operands[fun + 1], 1) == UNSPEC_TLSLD)
+	    sprintf (tls, ".reloc .,R_PPC%s_TLSLD,%%&\n\t",
+		     rel64);
+	  else
+	    gcc_unreachable ();
+	}
+
+      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, fun, addend);
+	  s += sprintf (s, "crset 2\n\t");
+	}
+      s += sprintf (s,
+		    "%s.reloc .,R_PPC%s_PLTCALL,%%z%u%s\n\t",
+		    tls, rel64, fun, addend);
+    }
+  else if (!speculate)
+    s += sprintf (s, "crset 2\n\t");
+
   if (DEFAULT_ABI == ABI_AIX)
     {
       if (speculate)
-	sprintf (str,
-		 "l%s 2,%%%u\n\t"
+	sprintf (s,
 		 "b%%T%ul\n\t"
 		 "l%s 2,%%%u(1)",
-		 ptrload, fun + 2, fun, ptrload, fun + 3);
+		 fun, ptrload, fun + 3);
       else
-	sprintf (str,
-		 "crset 2\n\t"
-		 "l%s 2,%%%u\n\t"
+	sprintf (s,
 		 "beq%%T%ul-\n\t"
 		 "l%s 2,%%%u(1)",
-		 ptrload, fun + 2, fun, ptrload, fun + 3);
+		 fun, ptrload, fun + 3);
     }
   else if (DEFAULT_ABI == ABI_ELFv2)
     {
       if (speculate)
-	sprintf (str,
+	sprintf (s,
 		 "b%%T%ul\n\t"
 		 "l%s 2,%%%u(1)",
 		 fun, ptrload, fun + 2);
       else
-	sprintf (str,
-		 "crset 2\n\t"
+	sprintf (s,
 		 "beq%%T%ul-\n\t"
 		 "l%s 2,%%%u(1)",
 		 fun, ptrload, fun + 2);
     }
-  else if (DEFAULT_ABI == ABI_V4)
+  else
     {
       if (speculate)
-	sprintf (str,
+	sprintf (s,
 		 "b%%T%u%s",
 		 fun, "l" + sibcall);
       else
-	sprintf (str,
-		 "crset 2\n\t"
+	sprintf (s,
 		 "beq%%T%u%s-%s",
 		 fun, "l" + sibcall, sibcall ? "\n\tb $" : "");
     }
-  else
-    gcc_unreachable ();
   return str;
 }
 
+#if HAVE_AS_PLTSEQ
+/* Output indirect call insns.
+   WHICH is 0 for tocsave, 1 for plt16_ha, 2 for plt16_lo, 3 for mtctr.  */
+const char *
+rs6000_output_pltseq (rtx *operands, int which)
+{
+  const char *rel64 = TARGET_64BIT ? "64" : "";
+  char tls[28];
+  tls[0] = 0;
+  if (GET_CODE (operands[3]) == UNSPEC)
+    {
+      if (XINT (operands[3], 1) == UNSPEC_TLSGD)
+	sprintf (tls, ".reloc .,R_PPC%s_TLSGD,%%3\n\t",
+		 rel64);
+      else if (XINT (operands[3], 1) == UNSPEC_TLSLD)
+	sprintf (tls, ".reloc .,R_PPC%s_TLSLD,%%&\n\t",
+		 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" : "";
+  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)");
+      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",
+		 tls, off, rel64);
+      else
+	sprintf (str,
+		 "%s.reloc .%s,R_PPC%s_PLT16_HA,%%z2%s\n\t"
+		 "addis %%0,%%1,0",
+		 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");
+      break;
+    case 3:
+      sprintf (str,
+	       "%s.reloc .,R_PPC%s_PLTSEQ,%%z2%s\n\t"
+	       "mtctr %%1",
+	       tls, rel64, addend);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  return str;
+}
+#endif
+
 #if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO
 /* Emit an assembler directive to set symbol visibility for DECL to
    VISIBILITY_TYPE.  */
@@ -32522,11 +32636,8 @@ rs6000_set_default_type_attributes (tree type)
    longcall attribute.  */
 
 static rtx
-rs6000_longcall_ref (rtx call_ref)
+rs6000_longcall_ref (rtx call_ref, rtx arg)
 {
-  if (GET_CODE (call_ref) != SYMBOL_REF)
-    return call_ref;
-
   /* System V adds '.' to the internal name, so skip them.  */
   const char *call_name = XSTR (call_ref, 0);
   if (*call_name == '.')
@@ -32538,6 +32649,36 @@ rs6000_longcall_ref (rtx call_ref)
       call_ref = gen_rtx_SYMBOL_REF (VOIDmode, IDENTIFIER_POINTER (node));
     }
 
+  if (HAVE_AS_PLTSEQ
+      && TARGET_TLS_MARKERS
+      && (DEFAULT_ABI == ABI_ELFv2 || DEFAULT_ABI == ABI_V4))
+    {
+      rtx base = const0_rtx;
+      int regno;
+      if (DEFAULT_ABI == ABI_ELFv2)
+	{
+	  base = gen_rtx_REG (Pmode, TOC_REGISTER);
+	  regno = 12;
+	}
+      else
+	{
+	  if (flag_pic)
+	    base = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
+	  regno = 11;
+	}
+      /* Reg must match that used by linker PLT stubs.  For ELFv2, r12
+	 may be used by a function global entry point.  For SysV4, r11
+	 is used by __glink_PLTresolve lazy resolver entry.  */
+      rtx reg = gen_rtx_REG (Pmode, regno);
+      rtx hi = gen_rtx_UNSPEC (Pmode, gen_rtvec (3, base, call_ref, arg),
+			       UNSPEC_PLT16_HA);
+      rtx lo = gen_rtx_UNSPEC (Pmode, gen_rtvec (3, reg, call_ref, arg),
+			       UNSPEC_PLT16_LO);
+      emit_insn (gen_rtx_SET (reg, hi));
+      emit_insn (gen_rtx_SET (reg, lo));
+      return reg;
+    }
+
   return force_reg (Pmode, call_ref);
 }
 \f
@@ -37508,8 +37649,7 @@ chain_already_loaded (rtx_insn *last)
 void
 rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 {
-  const bool direct_call_p
-    = GET_CODE (func_desc) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (func_desc);
+  rtx func = func_desc;
   rtx toc_reg = gen_rtx_REG (Pmode, TOC_REGNUM);
   rtx toc_load = NULL_RTX;
   rtx toc_restore = NULL_RTX;
@@ -37523,12 +37663,13 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
     tlsarg = global_tlsarg;
 
   /* Handle longcall attributes.  */
-  if (INTVAL (cookie) & CALL_LONG)
-    func_desc = rs6000_longcall_ref (func_desc);
+  if ((INTVAL (cookie) & CALL_LONG) != 0
+      && GET_CODE (func_desc) == SYMBOL_REF)
+    func = rs6000_longcall_ref (func_desc, tlsarg);
 
   /* Handle indirect calls.  */
-  if (GET_CODE (func_desc) != SYMBOL_REF
-      || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (func_desc)))
+  if (GET_CODE (func) != SYMBOL_REF
+      || (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.  */
@@ -37549,7 +37690,17 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 					     gen_rtx_PLUS (Pmode, stack_ptr,
 							   stack_toc_offset));
 	  MEM_VOLATILE_P (stack_toc_mem) = 1;
-	  emit_move_insn (stack_toc_mem, toc_reg);
+	  if (HAVE_AS_PLTSEQ
+	      && TARGET_TLS_MARKERS
+	      && 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);
 	}
 
       if (DEFAULT_ABI == ABI_ELFv2)
@@ -37557,9 +37708,25 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 	  /* A function pointer in the ELFv2 ABI is just a plain address, but
 	     the ABI requires it to be loaded into r12 before the call.  */
 	  func_addr = gen_rtx_REG (Pmode, 12);
-	  if (!rtx_equal_p (func_addr, func_desc))
-	    emit_move_insn (func_addr, func_desc);
+	  if (!rtx_equal_p (func_addr, func))
+	    emit_move_insn (func_addr, func);
 	  abi_reg = func_addr;
+	  /* Indirect calls via CTR are strongly preferred over indirect
+	     calls via LR, so move the address there.  Needed to mark
+	     this insn for linker plt sequence editing too.  */
+	  func_addr = gen_rtx_REG (Pmode, CTR_REGNO);
+	  if (HAVE_AS_PLTSEQ
+	      && TARGET_TLS_MARKERS
+	      && GET_CODE (func_desc) == SYMBOL_REF)
+	    {
+	      rtvec v = gen_rtvec (3, abi_reg, func_desc, tlsarg);
+	      rtx mark_func = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
+	      emit_insn (gen_rtx_SET (func_addr, mark_func));
+	      v = gen_rtvec (2, func_addr, func_desc);
+	      func_addr = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
+	    }
+	  else
+	    emit_move_insn (func_addr, abi_reg);
 	}
       else
 	{
@@ -37571,9 +37738,15 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 	     not have any executable code.  */
 
 	  /* Load up address of the actual function.  */
-	  func_desc = force_reg (Pmode, func_desc);
+	  func = force_reg (Pmode, func);
 	  func_addr = gen_reg_rtx (Pmode);
-	  emit_move_insn (func_addr, gen_rtx_MEM (Pmode, func_desc));
+	  emit_move_insn (func_addr, gen_rtx_MEM (Pmode, func));
+
+	  /* Indirect calls via CTR are strongly preferred over indirect
+	     calls via LR, so move the address there.  */
+	  rtx ctr_reg = gen_rtx_REG (Pmode, CTR_REGNO);
+	  emit_move_insn (ctr_reg, func_addr);
+	  func_addr = ctr_reg;
 
 	  /* Prepare to load the TOC of the called function.  Note that the
 	     TOC load must happen immediately before the actual call so
@@ -37581,7 +37754,7 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 	     comment in frob_update_context.  */
 	  rtx func_toc_offset = GEN_INT (GET_MODE_SIZE (Pmode));
 	  rtx func_toc_mem = gen_rtx_MEM (Pmode,
-					  gen_rtx_PLUS (Pmode, func_desc,
+					  gen_rtx_PLUS (Pmode, func,
 							func_toc_offset));
 	  toc_load = gen_rtx_USE (VOIDmode, func_toc_mem);
 
@@ -37589,14 +37762,15 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 	     originally direct, the 3rd word has not been written since no
 	     trampoline has been built, so we ought not to load it, lest we
 	     override a static chain value.  */
-	  if (!direct_call_p
+	  if (!(GET_CODE (func_desc) == SYMBOL_REF
+		&& SYMBOL_REF_FUNCTION_P (func_desc))
 	      && TARGET_POINTERS_TO_NESTED_FUNCTIONS
 	      && !chain_already_loaded (get_current_sequence ()->next->last))
 	    {
 	      rtx sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
 	      rtx func_sc_offset = GEN_INT (2 * GET_MODE_SIZE (Pmode));
 	      rtx func_sc_mem = gen_rtx_MEM (Pmode,
-					     gen_rtx_PLUS (Pmode, func_desc,
+					     gen_rtx_PLUS (Pmode, func,
 							   func_sc_offset));
 	      emit_move_insn (sc_reg, func_sc_mem);
 	      abi_reg = sc_reg;
@@ -37609,7 +37783,7 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 	 assume the TOC register is set; for non-local calls, the
 	 PLT stub needs the TOC register.  */
       abi_reg = toc_reg;
-      func_addr = func_desc;
+      func_addr = func;
     }
 
   /* Create the call.  */
@@ -37664,22 +37838,51 @@ rs6000_sibcall_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 /* Expand code to perform a call under the SYSV4 ABI.  */
 
 void
-rs6000_call_sysv (rtx value, rtx func, rtx tlsarg, rtx cookie)
+rs6000_call_sysv (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 {
+  rtx func = func_desc;
   rtx func_addr;
   rtx call[3];
   rtx insn;
+  rtx abi_reg = NULL_RTX;
 
   if (global_tlsarg)
     tlsarg = global_tlsarg;
 
   /* Handle longcall attributes.  */
-  if (INTVAL (cookie) & CALL_LONG)
-    func = rs6000_longcall_ref (func);
+  if ((INTVAL (cookie) & CALL_LONG) != 0
+      && GET_CODE (func_desc) == SYMBOL_REF)
+    {
+      func = rs6000_longcall_ref (func_desc, tlsarg);
+      /* If the longcall was implemented using PLT16 relocs, then r11
+	 needs to be valid at the call for lazy linking.  */
+      if (HAVE_AS_PLTSEQ
+	  && TARGET_TLS_MARKERS)
+	abi_reg = func;
+    }
 
   /* Handle indirect calls.  */
   if (GET_CODE (func) != SYMBOL_REF)
-    func_addr = force_reg (Pmode, func);
+    {
+      func = force_reg (Pmode, func);
+
+      /* Indirect calls via CTR are strongly preferred over indirect
+	 calls via LR, so move the address there.  Needed to mark
+	 this insn for linker plt sequence editing too.  */
+      func_addr = gen_rtx_REG (Pmode, CTR_REGNO);
+      if (HAVE_AS_PLTSEQ
+	  && TARGET_TLS_MARKERS
+	  && GET_CODE (func_desc) == SYMBOL_REF)
+	{
+	  rtvec v = gen_rtvec (3, func, func_desc, tlsarg);
+	  rtx mark_func = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
+	  emit_insn (gen_rtx_SET (func_addr, mark_func));
+	  v = gen_rtvec (2, func_addr, func_desc);
+	  func_addr = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
+	}
+      else
+	emit_move_insn (func_addr, func);
+    }
   else
     func_addr = func;
 
@@ -37695,6 +37898,73 @@ rs6000_call_sysv (rtx value, rtx func, rtx tlsarg, rtx cookie)
 
   insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
   insn = emit_call_insn (insn);
+  if (abi_reg)
+    use_reg (&CALL_INSN_FUNCTION_USAGE (insn), abi_reg);
+}
+
+/* Expand code to perform a sibling call under the SysV4 ABI.  */
+
+void
+rs6000_sibcall_sysv (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
+{
+  rtx func = func_desc;
+  rtx func_addr;
+  rtx call[3];
+  rtx insn;
+  rtx abi_reg = NULL_RTX;
+
+  if (global_tlsarg)
+    tlsarg = global_tlsarg;
+
+  /* Handle longcall attributes.  */
+  if ((INTVAL (cookie) & CALL_LONG) != 0
+      && GET_CODE (func_desc) == SYMBOL_REF)
+    {
+      func = rs6000_longcall_ref (func_desc, tlsarg);
+      /* If the longcall was implemented using PLT16 relocs, then r11
+	 needs to be valid at the call for lazy linking.  */
+      if (HAVE_AS_PLTSEQ
+	  && TARGET_TLS_MARKERS)
+	abi_reg = func;
+    }
+
+  /* Handle indirect calls.  */
+  if (GET_CODE (func) != SYMBOL_REF)
+    {
+      func = force_reg (Pmode, func);
+
+      /* Indirect sibcalls must go via CTR.  Needed to mark
+	 this insn for linker plt sequence editing too.  */
+      func_addr = gen_rtx_REG (Pmode, CTR_REGNO);
+      if (HAVE_AS_PLTSEQ
+	  && TARGET_TLS_MARKERS
+	  && GET_CODE (func_desc) == SYMBOL_REF)
+	{
+	  rtvec v = gen_rtvec (3, func, func_desc, tlsarg);
+	  rtx mark_func = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
+	  emit_insn (gen_rtx_SET (func_addr, mark_func));
+	  v = gen_rtvec (2, func_addr, func_desc);
+	  func_addr = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
+	}
+      else
+	emit_move_insn (func_addr, func);
+    }
+  else
+    func_addr = func;
+
+  /* Create the call.  */
+  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), tlsarg);
+  if (value != NULL_RTX)
+    call[0] = gen_rtx_SET (value, call[0]);
+
+  unsigned int mask = CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS;
+  call[1] = gen_rtx_USE (VOIDmode, GEN_INT (INTVAL (cookie) & mask));
+  call[2] = simple_return_rtx;
+
+  insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
+  insn = emit_call_insn (insn);
+  if (abi_reg)
+    use_reg (&CALL_INSN_FUNCTION_USAGE (insn), abi_reg);
 }
 
 /* Return whether we need to always update the saved TOC pointer when we update
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index f59c0b6b685..c7934c601ed 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -224,6 +224,10 @@ extern const char *host_detect_local_cpu (int argc, const char **argv);
 #define HAVE_AS_TLS 0
 #endif
 
+#ifndef HAVE_AS_PLTSEQ
+#define HAVE_AS_PLTSEQ 0
+#endif
+
 #ifndef TARGET_LINK_STACK
 #define TARGET_LINK_STACK 0
 #endif
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index d1451509aa7..849a100e2c5 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -147,6 +147,9 @@ (define_c_enum "unspec"
    UNSPEC_SIGNBIT
    UNSPEC_SF_FROM_SI
    UNSPEC_SI_FROM_SF
+   UNSPEC_PLTSEQ
+   UNSPEC_PLT16_HA
+   UNSPEC_PLT16_LO
   ])
 
 ;;
@@ -10236,6 +10239,55 @@ (define_insn "elf_low"
 		   (match_operand 2 "" "")))]
    "TARGET_ELF && !TARGET_64BIT && !flag_pic"
    "la %0,%2@l(%1)")
+
+(define_insn "*pltseq_tocsave_<mode>"
+  [(set (match_operand:P 0 "memory_operand" "=m")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "symbol_ref_operand" "s")
+		   (match_operand:P 3 "" "")]
+		  UNSPEC_PLTSEQ))]
+  "HAVE_AS_PLTSEQ && TARGET_TLS_MARKERS
+   && DEFAULT_ABI == ABI_ELFv2"
+{
+  return rs6000_output_pltseq (operands, 0);
+})
+
+(define_insn "*pltseq_plt16_ha_<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_PLT16_HA))]
+  "HAVE_AS_PLTSEQ && TARGET_TLS_MARKERS
+   && (DEFAULT_ABI == ABI_ELFv2 || DEFAULT_ABI == ABI_V4)"
+{
+  return rs6000_output_pltseq (operands, 1);
+})
+
+(define_insn "*pltseq_plt16_lo_<mode>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "symbol_ref_operand" "s")
+		   (match_operand:P 3 "" "")]
+		  UNSPEC_PLT16_LO))]
+  "HAVE_AS_PLTSEQ && TARGET_TLS_MARKERS
+   && (DEFAULT_ABI == ABI_ELFv2 || DEFAULT_ABI == ABI_V4)"
+{
+  return rs6000_output_pltseq (operands, 2);
+}
+  [(set_attr "type" "load")])
+
+(define_insn "*pltseq_mtctr_<mode>"
+  [(set (match_operand:P 0 "register_operand" "=c")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "r")
+		   (match_operand:P 2 "symbol_ref_operand" "s")
+		   (match_operand:P 3 "" "")]
+		  UNSPEC_PLTSEQ))]
+  "HAVE_AS_PLTSEQ && TARGET_TLS_MARKERS
+   && (DEFAULT_ABI == ABI_ELFv2 || DEFAULT_ABI == ABI_V4)"
+{
+  return rs6000_output_pltseq (operands, 3);
+})
 \f
 ;; Call and call_value insns
 (define_expand "call"
@@ -10392,9 +10444,9 @@ (define_insn "*call_value_local64"
 ;; which indicates how to set cr1
 
 (define_insn "*call_indirect_nonlocal_sysv<mode>"
-  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l,c,*l"))
+  [(call (mem:SI (match_operand:P 0 "indirect_call_operand" "c,*l,X"))
 	 (match_operand 1))
-   (use (match_operand:SI 2 "immediate_operand" "O,O,n,n"))
+   (use (match_operand:SI 2 "immediate_operand" "n,n,n"))
    (clobber (reg:SI LR_REGNO))]
   "DEFAULT_ABI == ABI_V4
    || DEFAULT_ABI == ABI_DARWIN"
@@ -10407,18 +10459,17 @@ (define_insn "*call_indirect_nonlocal_sysv<mode>"
 
   return rs6000_output_indirect_call (operands, 0, false);
 }
-  [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
-   (set_attr_alternative "length"
-     [(if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "8")
-		    (const_string "4"))
-      (const_string "4")
-      (if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "12")
-		    (const_string "8"))
-      (const_string "8")])])
+  [(set_attr "type" "jmpreg")
+   (set (attr "length")
+	(cond [(and (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		    (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "12")
+	       (ior (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		    (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "8")]
+	      (const_string "4")))])
 
 (define_insn_and_split "*call_nonlocal_sysv<mode>"
   [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s"))
@@ -10478,9 +10529,9 @@ (define_insn "*call_nonlocal_sysv_secure<mode>"
 
 (define_insn "*call_value_indirect_nonlocal_sysv<mode>"
   [(set (match_operand 0 "" "")
-	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l,c,*l"))
+	(call (mem:SI (match_operand:P 1 "indirect_call_operand" "c,*l,X"))
 	      (match_operand 2)))
-   (use (match_operand:SI 3 "immediate_operand" "O,O,n,n"))
+   (use (match_operand:SI 3 "immediate_operand" "n,n,n"))
    (clobber (reg:SI LR_REGNO))]
   "DEFAULT_ABI == ABI_V4
    || DEFAULT_ABI == ABI_DARWIN"
@@ -10493,18 +10544,17 @@ (define_insn "*call_value_indirect_nonlocal_sysv<mode>"
 
   return rs6000_output_indirect_call (operands, 1, false);
 }
-  [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
-   (set_attr_alternative "length"
-     [(if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "8")
-		    (const_string "4"))
-      (const_string "4")
-      (if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "12")
-		    (const_string "8"))
-      (const_string "8")])])
+  [(set_attr "type" "jmpreg")
+   (set (attr "length")
+	(cond [(and (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		    (match_test "(INTVAL (operands[3]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "12")
+	       (ior (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		   (match_test "(INTVAL (operands[3]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "8")]
+	      (const_string "4")))])
 
 (define_insn_and_split "*call_value_nonlocal_sysv<mode>"
   [(set (match_operand 0 "" "")
@@ -10617,10 +10667,10 @@ (define_insn "*call_value_nonlocal_aix<mode>"
 ;; Operand3 is the offset of the stack location holding the current TOC pointer
 
 (define_insn "*call_indirect_aix<mode>"
-  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
+  [(call (mem:SI (match_operand:P 0 "indirect_call_operand" "c,*l,X"))
 	 (match_operand 1))
-   (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+   (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>,<ptrm>"))
+   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX"
 {
@@ -10635,10 +10685,10 @@ (define_insn "*call_indirect_aix<mode>"
 
 (define_insn "*call_value_indirect_aix<mode>"
   [(set (match_operand 0 "" "")
-	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
+	(call (mem:SI (match_operand:P 1 "indirect_call_operand" "c,*l,X"))
 	      (match_operand 2)))
-   (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+   (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>,<ptrm>"))
+   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX"
 {
@@ -10656,9 +10706,9 @@ (define_insn "*call_value_indirect_aix<mode>"
 ;; Operand2 is the offset of the stack location holding the current TOC pointer
 
 (define_insn "*call_indirect_elfv2<mode>"
-  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
+  [(call (mem:SI (match_operand:P 0 "indirect_call_operand" "c,*l,X"))
 	 (match_operand 1))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_ELFv2"
 {
@@ -10673,9 +10723,9 @@ (define_insn "*call_indirect_elfv2<mode>"
 
 (define_insn "*call_value_indirect_elfv2<mode>"
   [(set (match_operand 0 "" "")
-	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
+	(call (mem:SI (match_operand:P 1 "indirect_call_operand" "c,*l,X"))
 	      (match_operand 2)))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_ELFv2"
 {
@@ -10738,6 +10788,12 @@ (define_expand "sibcall"
       rs6000_sibcall_aix (NULL_RTX, operands[0], operands[1], operands[2]);
       DONE;
     }
+
+  if (DEFAULT_ABI == ABI_V4)
+    {
+      rs6000_sibcall_sysv (NULL_RTX, operands[0], operands[1], operands[2]);
+      DONE;
+    }
 })
 
 (define_expand "sibcall_value"
@@ -10763,6 +10819,12 @@ (define_expand "sibcall_value"
       rs6000_sibcall_aix (operands[0], operands[1], operands[2], operands[3]);
       DONE;
     }
+
+  if (DEFAULT_ABI == ABI_V4)
+    {
+      rs6000_sibcall_sysv (operands[0], operands[1], operands[2], operands[3]);
+      DONE;
+    }
 })
 
 (define_insn "*sibcall_local32"
@@ -10839,10 +10901,38 @@ (define_insn "*sibcall_value_local64"
   [(set_attr "type" "branch")
    (set_attr "length" "4,8")])
 
+(define_insn "*sibcall_indirect_nonlocal_sysv<mode>"
+  [(call (mem:SI (match_operand:P 0 "indirect_call_operand" "c,*l,X"))
+	 (match_operand 1))
+   (use (match_operand:SI 2 "immediate_operand" "n,n,n"))
+   (simple_return)]
+  "DEFAULT_ABI == ABI_V4
+   || DEFAULT_ABI == ABI_DARWIN"
+{
+  if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+    output_asm_insn ("crxor 6,6,6", operands);
+
+  else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+    output_asm_insn ("creqv 6,6,6", operands);
+
+  return rs6000_output_indirect_call (operands, 0, true);
+}
+  [(set_attr "type" "jmpreg")
+   (set (attr "length")
+	(cond [(and (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		    (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "12")
+	       (ior (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		   (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "8")]
+	      (const_string "4")))])
+
 (define_insn "*sibcall_nonlocal_sysv<mode>"
-  [(call (mem:SI (match_operand:P 0 "call_operand" "s,s,c,c"))
-	 (match_operand 1 "" ""))
-   (use (match_operand 2 "immediate_operand" "O,n,O,n"))
+  [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s"))
+	 (match_operand 1))
+   (use (match_operand 2 "immediate_operand" "O,n"))
    (simple_return)]
   "(DEFAULT_ABI == ABI_DARWIN
     || DEFAULT_ABI == ABI_V4)
@@ -10854,29 +10944,45 @@ (define_insn "*sibcall_nonlocal_sysv<mode>"
   else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  if (which_alternative >= 2)
-    return rs6000_output_indirect_call (operands, 0, true);
-  else
-    return rs6000_output_call (operands, 0, true);
+  return rs6000_output_call (operands, 0, true);
 }
   [(set_attr "type" "branch")
-   (set_attr_alternative "length"
-     [(const_string "4")
-      (const_string "8")
-      (if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "12")
-		    (const_string "4"))
-      (if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "16")
-		    (const_string "8"))])])
+   (set_attr "length" "4,8")])
+
+(define_insn "*sibcall_value_indirect_nonlocal_sysv<mode>"
+  [(set (match_operand 0 "" "")
+	(call (mem:SI (match_operand:P 1 "indirect_call_operand" "c,*l,X"))
+	      (match_operand 2)))
+   (use (match_operand:SI 3 "immediate_operand" "n,n,n"))
+   (simple_return)]
+  "DEFAULT_ABI == ABI_V4
+   || DEFAULT_ABI == ABI_DARWIN"
+{
+  if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+    output_asm_insn ("crxor 6,6,6", operands);
+
+  else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+    output_asm_insn ("creqv 6,6,6", operands);
+
+  return rs6000_output_indirect_call (operands, 1, true);
+}
+  [(set_attr "type" "jmpreg")
+   (set (attr "length")
+	(cond [(and (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		    (match_test "(INTVAL (operands[3]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "12")
+	       (ior (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		   (match_test "(INTVAL (operands[3]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "8")]
+	      (const_string "4")))])
 
 (define_insn "*sibcall_value_nonlocal_sysv<mode>"
   [(set (match_operand 0 "" "")
-	(call (mem:SI (match_operand:P 1 "call_operand" "s,s,c,c"))
-	      (match_operand 2 "" "")))
-   (use (match_operand:SI 3 "immediate_operand" "O,n,O,n"))
+	(call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s"))
+	      (match_operand 2)))
+   (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (simple_return)]
   "(DEFAULT_ABI == ABI_DARWIN
     || DEFAULT_ABI == ABI_V4)
@@ -10888,29 +10994,10 @@ (define_insn "*sibcall_value_nonlocal_sysv<mode>"
   else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  if (which_alternative >= 2)
-    {
-      if (rs6000_speculate_indirect_jumps)
-	return "b%T1";
-      else
-	/* Can use CR0 since it is volatile across sibcalls.  */
-	return "crset 2\;beq%T1-\;b $";
-    }
-  else
-    return rs6000_output_call (operands, 1, true);
+  return rs6000_output_call (operands, 1, true);
 }
   [(set_attr "type" "branch")
-   (set_attr_alternative "length"
-     [(const_string "4")
-      (const_string "8")
-      (if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "12")
-		    (const_string "4"))
-      (if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "16")
-		    (const_string "8"))])])
+   (set_attr "length" "4,8")])
 
 ;; AIX ABI sibling call patterns.
 
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 59585912556..5b81faa95eb 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -4636,6 +4636,12 @@ LCF0:
       [AC_DEFINE(HAVE_AS_ENTRY_MARKERS, 1,
 	  [Define if your assembler supports the R_PPC64_ENTRY relocation.])])
 
+    gcc_GAS_CHECK_FEATURE([plt sequence marker support],
+      gcc_cv_as_powerpc_pltseq_markers, [2,31,0],-a32 --fatal-warnings,
+      [ .reloc .,R_PPC_PLTSEQ; nop],,
+      [AC_DEFINE(HAVE_AS_PLTSEQ, 1,
+	  [Define if your assembler supports R_PPC*_PLTSEQ relocations.])])
+
     case $target in
       *-*-aix*)
 	gcc_GAS_CHECK_FEATURE([AIX .ref support],

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/6] [RS6000] rs6000_output_call for external call insn assembly output
  2018-11-07  5:37 ` [PATCH 1/6] [RS6000] rs6000_output_call for external call insn assembly output Alan Modra
@ 2018-11-08  0:09   ` Segher Boessenkool
  2018-11-08 13:21     ` Alan Modra
  0 siblings, 1 reply; 34+ messages in thread
From: Segher Boessenkool @ 2018-11-08  0:09 UTC (permalink / raw)
  To: Alan Modra; +Cc: gcc-patches

On Wed, Nov 07, 2018 at 04:07:15PM +1030, Alan Modra wrote:
> +extern const char *rs6000_output_call (rtx *, unsigned int, bool, const char *);

Maybe have a separate rs6000_output_call and rs6000_output_sibcall?  Bare
boolean function parameters aren't great.  (They can of course both call
rs6000_output_call_1 or whatever, if that makes sense).

> --- a/gcc/config/rs6000/rs6000.c
> +++ b/gcc/config/rs6000/rs6000.c
> @@ -21380,6 +21380,37 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
>    return default_assemble_integer (x, size, aligned_p);
>  }
>  
> +/* Return a template string for assembly to emit when making an
> +   external call.  FUN is the %z argument, ARG is either NULL or
> +   a @TLSGD or @TLSLD __tls_get_addr argument specifier.  */
> +
> +const char *
> +rs6000_output_call (rtx *operands, unsigned int fun, bool sibcall,
> +		    const char *arg)
> +{
> +  /* -Wformat-overflow workaround, without which gcc thinks that %u
> +      might produce 10 digits.  FUN is 0 or 1 as of 2018-03.  */
> +  gcc_assert (fun <= 6);

So "fun" is the operand number.  Rename it, and use MAX_RECOG_OPERANDS
instead of 6?  And allow for it to take 2 or 3 chars to print :-)

"operands" is unused here, compiling this will warn.

"output" is a lie, this function doesn't output anything.  Hardly the
only case of this in the rs6000 port, but it is annoying.  What would be
a good name for this...  "rs6000_template_for_call"?


Are there some patterns that can be collapsed to one after this?


Segher

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/6] [RS6000] Replace TLSmode with P, and correct tls call mems
  2018-11-07  5:38 ` [PATCH 3/6] [RS6000] Replace TLSmode with P, and correct tls call mems Alan Modra
@ 2018-11-08  1:11   ` Segher Boessenkool
  2018-11-08 13:27     ` Alan Modra
  0 siblings, 1 reply; 34+ messages in thread
From: Segher Boessenkool @ 2018-11-08  1:11 UTC (permalink / raw)
  To: Alan Modra; +Cc: gcc-patches

On Wed, Nov 07, 2018 at 04:08:26PM +1030, Alan Modra wrote:
> There is really no need to define a TLSmode mode iterator that is
> identical (since !TARGET_64BIT == TARGET_32BIT) to the much used P
> mode iterator.

Nice :-)

> It's nonsense to think we might ever want to support
> 32-bit TLS on 64-bit or vice versa!  The patch also fixes a minor
> error in the call mems.  All other direct calls use (call (mem:SI ..)).

You can also replace <tls_abi_suffix> with <bits>, <tls_sysv_suffix> with
<mode>, and l<tls_insn_suffix> with <ptrload>.  Also, was "TLSmode:"
needed anywhere?  I don't see any other iterator used in those patterns.

> 	* config/rs6000/rs6000.md (TLSmode): Delete mode iterator.  Replace
> 	with P throughout except for call mems which should use SI.

Approved for trunk.  Further cleanup as above pre-approved.  Thanks!


Segher

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 4/6] [RS6000] Remove constraints on call rounded_stack_size_rtx arg
  2018-11-07  5:39 ` [PATCH 4/6] [RS6000] Remove constraints on call rounded_stack_size_rtx arg Alan Modra
@ 2018-11-08  1:19   ` Segher Boessenkool
  0 siblings, 0 replies; 34+ messages in thread
From: Segher Boessenkool @ 2018-11-08  1:19 UTC (permalink / raw)
  To: Alan Modra; +Cc: gcc-patches

On Wed, Nov 07, 2018 at 04:09:06PM +1030, Alan Modra wrote:
> This call arg is unused on rs6000.

This is fine.  Okay for trunk.  Thank you!


Segher


> 	* config/rs6000/darwin.md (call_indirect_nonlocal_darwin64,
> 	call_nonlocal_darwin64, call_value_indirect_nonlocal_darwin64,
> 	call_value_nonlocal_darwin64): Remove constraints from second call
> 	arg, the rounded_stack_size_rtx arg.
> 	* config/rs6000/rs6000.md (tls_gd_aix, tls_gd_sysv,
> 	tls_gd_call_aix, tls_gd_call_sysv, tls_ld_aix, tls_ld_sysv,
> 	tls_ld_call_aix, tls_ld_call_sysv, call_local32, call_local64,
> 	call_value_local32, call_value_local64, call_indirect_nonlocal_sysv,
> 	call_nonlocal_sysv, call_nonlocal_sysv_secure,
> 	call_value_indirect_nonlocal_sysv, call_value_nonlocal_sysv,
> 	call_value_nonlocal_sysv_secure, call_local_aix,
> 	call_value_local_aix, call_nonlocal_aix, call_value_nonlocal_aix,
> 	call_indirect_aix, call_value_indirect_aix, call_indirect_elfv2,
> 	call_value_indirect_elfv2, sibcall_local32, sibcall_local64,
> 	sibcall_value_local32, sibcall_value_local64, sibcall_aix,
> 	sibcall_value_aix): Likewise.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/6] [RS6000] rs6000_output_call for external call insn assembly output
  2018-11-08  0:09   ` Segher Boessenkool
@ 2018-11-08 13:21     ` Alan Modra
  0 siblings, 0 replies; 34+ messages in thread
From: Alan Modra @ 2018-11-08 13:21 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: gcc-patches

On Wed, Nov 07, 2018 at 06:08:33PM -0600, Segher Boessenkool wrote:
> On Wed, Nov 07, 2018 at 04:07:15PM +1030, Alan Modra wrote:
> > +extern const char *rs6000_output_call (rtx *, unsigned int, bool, const char *);
> 
> Maybe have a separate rs6000_output_call and rs6000_output_sibcall?  Bare
> boolean function parameters aren't great.  (They can of course both call
> rs6000_output_call_1 or whatever, if that makes sense).
> 
> > --- a/gcc/config/rs6000/rs6000.c
> > +++ b/gcc/config/rs6000/rs6000.c
> > @@ -21380,6 +21380,37 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
> >    return default_assemble_integer (x, size, aligned_p);
> >  }
> >  
> > +/* Return a template string for assembly to emit when making an
> > +   external call.  FUN is the %z argument, ARG is either NULL or
> > +   a @TLSGD or @TLSLD __tls_get_addr argument specifier.  */
> > +
> > +const char *
> > +rs6000_output_call (rtx *operands, unsigned int fun, bool sibcall,
> > +		    const char *arg)
> > +{
> > +  /* -Wformat-overflow workaround, without which gcc thinks that %u
> > +      might produce 10 digits.  FUN is 0 or 1 as of 2018-03.  */
> > +  gcc_assert (fun <= 6);
> 
> So "fun" is the operand number.  Rename it, and use MAX_RECOG_OPERANDS
> instead of 6?  And allow for it to take 2 or 3 chars to print :-)

Eh, so I can't have a little fun?  funop then?  (It's the index of the
call operand that has the function symref or whatever to call.)

> "operands" is unused here, compiling this will warn.

Oops, I did bootstrap each patch individually at one stage..
Probably happened when I edited the patchset, to reduce the size of
later changes.  rs6000_output_call didn't have "operands" to start
with.

> "output" is a lie, this function doesn't output anything.  Hardly the
> only case of this in the rs6000 port, but it is annoying.  What would be
> a good name for this...  "rs6000_template_for_call"?

OK, I went with rs6000_call_template and rs6000_sibcall_template.
Next patch also changed to use rs6000_indirect_call_template and
rs6000_indirect_sibcall_template.  Final patch uses
rs6000_pltseq_template.

> Are there some patterns that can be collapsed to one after this?

No, I don't think so.  Patch 5/6 does some of that for TLS calls.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/6] [RS6000] Replace TLSmode with P, and correct tls call mems
  2018-11-08  1:11   ` Segher Boessenkool
@ 2018-11-08 13:27     ` Alan Modra
  2018-11-08 18:09       ` Segher Boessenkool
  0 siblings, 1 reply; 34+ messages in thread
From: Alan Modra @ 2018-11-08 13:27 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: gcc-patches

On Wed, Nov 07, 2018 at 07:11:28PM -0600, Segher Boessenkool wrote:
> On Wed, Nov 07, 2018 at 04:08:26PM +1030, Alan Modra wrote:
> > There is really no need to define a TLSmode mode iterator that is
> > identical (since !TARGET_64BIT == TARGET_32BIT) to the much used P
> > mode iterator.
> 
> Nice :-)
> 
> > It's nonsense to think we might ever want to support
> > 32-bit TLS on 64-bit or vice versa!  The patch also fixes a minor
> > error in the call mems.  All other direct calls use (call (mem:SI ..)).
> 
> You can also replace <tls_abi_suffix> with <bits>, <tls_sysv_suffix> with
> <mode>, and l<tls_insn_suffix> with <ptrload>.  Also, was "TLSmode:"
> needed anywhere?  I don't see any other iterator used in those patterns.

OK, done.  TLSmode: was used in the tls insn pattern names and in the
output templates that now use ptrload.  P: does just as well.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/6] [RS6000] Replace TLSmode with P, and correct tls call mems
  2018-11-08 13:27     ` Alan Modra
@ 2018-11-08 18:09       ` Segher Boessenkool
  0 siblings, 0 replies; 34+ messages in thread
From: Segher Boessenkool @ 2018-11-08 18:09 UTC (permalink / raw)
  To: Alan Modra; +Cc: gcc-patches

On Thu, Nov 08, 2018 at 11:57:13PM +1030, Alan Modra wrote:
> On Wed, Nov 07, 2018 at 07:11:28PM -0600, Segher Boessenkool wrote:
> > On Wed, Nov 07, 2018 at 04:08:26PM +1030, Alan Modra wrote:
> > > There is really no need to define a TLSmode mode iterator that is
> > > identical (since !TARGET_64BIT == TARGET_32BIT) to the much used P
> > > mode iterator.
> > 
> > Nice :-)
> > 
> > > It's nonsense to think we might ever want to support
> > > 32-bit TLS on 64-bit or vice versa!  The patch also fixes a minor
> > > error in the call mems.  All other direct calls use (call (mem:SI ..)).
> > 
> > You can also replace <tls_abi_suffix> with <bits>, <tls_sysv_suffix> with
> > <mode>, and l<tls_insn_suffix> with <ptrload>.  Also, was "TLSmode:"
> > needed anywhere?  I don't see any other iterator used in those patterns.
> 
> OK, done.  TLSmode: was used in the tls insn pattern names and in the
> output templates that now use ptrload.  P: does just as well.

I mean that <P:xxx> is exactly the same as just <xxx> if there is only
one iterator in the pattern.  Doesn't matter as much with P as it did
with a long name like TLSmode, of course :-)


Segher

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 2/6] [RS6000] rs6000_output_indirect_call
  2018-11-07  5:38 ` [PATCH 2/6] [RS6000] rs6000_output_indirect_call Alan Modra
@ 2018-11-12 19:44   ` Bill Schmidt
  2018-11-13  0:14     ` Alan Modra
  0 siblings, 1 reply; 34+ messages in thread
From: Bill Schmidt @ 2018-11-12 19:44 UTC (permalink / raw)
  To: gcc-patches, Alan Modra; +Cc: Segher Boessenkool

On 11/6/18 11:37 PM, Alan Modra wrote:
> Like the last patch for external calls, now handle most assembly code
> for indirect calls in one place.  The patch also merges some insns,
> correcting some !rs6000_speculate_indirect_jumps cases branching to
> LR, which don't require a speculation barrier.
>
> 	* config/rs6000/rs6000-protos.h (rs6000_output_indirect_call): Declare.
> 	* config/rs6000/rs6000.c (rs6000_output_indirect_call): New function.
> 	* config/rs6000/rs6000.md (call_indirect_nonlocal_sysv): Use
> 	rs6000_output_indirect_call.
> 	(call_value_indirect_nonlocal_sysv, sibcall_nonlocal_sysv): Likewise.
> 	(call_indirect_aix, call_value_indirect_aix,
> 	call_indirect_elfv2, call_value_indirect_elfv2): Likewise, and
> 	handle both speculation and non-speculation cases.
> 	(call_indirect_aix_nospec, call_value_indirect_aix_nospec): Delete.
> 	(call_indirect_elfv2_nospec, call_value_indirect_elfv2_nospec): Delete.
>
> diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
> index f1a421dde16..493cfe6ba2b 100644
> --- a/gcc/config/rs6000/rs6000-protos.h
> +++ b/gcc/config/rs6000/rs6000-protos.h
> @@ -112,6 +112,7 @@ extern void rs6000_output_function_entry (FILE *, const char *);
>  extern void print_operand (FILE *, rtx, int);
>  extern void print_operand_address (FILE *, rtx);
>  extern const char *rs6000_output_call (rtx *, unsigned int, bool, const char *);
> +extern const char *rs6000_output_indirect_call (rtx *, unsigned int, bool);
>  extern enum rtx_code rs6000_reverse_condition (machine_mode,
>  					       enum rtx_code);
>  extern rtx rs6000_emit_eqne (machine_mode, rtx, rtx, rtx);
> diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
> index b22cae55a0d..bf1551746d5 100644
> --- a/gcc/config/rs6000/rs6000.c
> +++ b/gcc/config/rs6000/rs6000.c
> @@ -21411,6 +21411,69 @@ rs6000_output_call (rtx *operands, unsigned int fun, bool sibcall,
>    return str;
>  }
>
> +/* As above, for indirect calls.  */
> +
> +const char *
> +rs6000_output_indirect_call (rtx *operands, unsigned int fun, bool sibcall)
> +{
> +  /* -Wformat-overflow workaround, without which gcc thinks that %u
> +      might produce 10 digits.  FUN is 0 or 1 as of 2018-03.  */
> +  gcc_assert (fun <= 6);
> +
> +  static char str[144];
> +  const char *ptrload = TARGET_64BIT ? "d" : "wz";
> +
> +  bool speculate = (rs6000_speculate_indirect_jumps
> +		    || (REG_P (operands[fun])
> +			&& REGNO (operands[fun]) == LR_REGNO));

Wouldn't hurt to have a comment here, indicating that we only have to generate
inefficient, speculation-inhibiting code when speculation via the count cache
has been disabled by switch, and this doesn't apply to indirect calls via the
link register.  This changes behavior of the code from before, but appears to
be safe and more correct.

> +
> +  if (DEFAULT_ABI == ABI_AIX)
> +    {
> +      if (speculate)
> +	sprintf (str,
> +		 "l%s 2,%%%u\n\t"
> +		 "b%%T%ul\n\t"
> +		 "l%s 2,%%%u(1)",
> +		 ptrload, fun + 2, fun, ptrload, fun + 3);
> +      else
> +	sprintf (str,
> +		 "crset 2\n\t"
> +		 "l%s 2,%%%u\n\t"
> +		 "beq%%T%ul-\n\t"
> +		 "l%s 2,%%%u(1)",
> +		 ptrload, fun + 2, fun, ptrload, fun + 3);
> +    }
> +  else if (DEFAULT_ABI == ABI_ELFv2)
> +    {
> +      if (speculate)
> +	sprintf (str,
> +		 "b%%T%ul\n\t"
> +		 "l%s 2,%%%u(1)",
> +		 fun, ptrload, fun + 2);
> +      else
> +	sprintf (str,
> +		 "crset 2\n\t"
> +		 "beq%%T%ul-\n\t"
> +		 "l%s 2,%%%u(1)",
> +		 fun, ptrload, fun + 2);
> +    }
> +  else if (DEFAULT_ABI == ABI_V4)
> +    {
> +      if (speculate)
> +	sprintf (str,
> +		 "b%%T%u%s",
> +		 fun, "l" + sibcall);

It's not at all clear to me what {"l" + sibcall} is doing here.
Whatever it is, it's clever enough that it warrants a comment... :-)
Does adding "l" to false result in the null string?  Is that
standard?

> +      else
> +	sprintf (str,
> +		 "crset 2\n\t"
> +		 "beq%%T%u%s-%s",
> +		 fun, "l" + sibcall, sibcall ? "\n\tb $" : "");

And similar...

> +    }
> +  else
> +    gcc_unreachable ();
> +  return str;
> +}
> +
>  #if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO
>  /* Emit an assembler directive to set symbol visibility for DECL to
>     VISIBILITY_TYPE.  */
> diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
> index 52088fdfbdb..9d9e29d12eb 100644
> --- a/gcc/config/rs6000/rs6000.md
> +++ b/gcc/config/rs6000/rs6000.md
> @@ -10540,11 +10540,7 @@ (define_insn "*call_indirect_nonlocal_sysv<mode>"
>    else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
>      output_asm_insn ("creqv 6,6,6", operands);
>
> -  if (rs6000_speculate_indirect_jumps
> -      || which_alternative == 1 || which_alternative == 3)
> -    return "b%T0l";
> -  else
> -    return "crset 2\;beq%T0l-";
> +  return rs6000_output_indirect_call (operands, 0, false);

Looks like this breaks Darwin?  This pattern matches for DEFAULT_ABI == ABI_DARWIN
but rs6000_output_indirect_call will hit gcc_unreachable() for that ABI.  

>  }
>    [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
>     (set_attr_alternative "length"
> @@ -10630,11 +10626,7 @@ (define_insn "*call_value_indirect_nonlocal_sysv<mode>"
>    else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
>      output_asm_insn ("creqv 6,6,6", operands);
>
> -  if (rs6000_speculate_indirect_jumps
> -      || which_alternative == 1 || which_alternative == 3)
> -    return "b%T1l";
> -  else
> -    return "crset 2\;beq%T1l-";
> +  return rs6000_output_indirect_call (operands, 1, false);

Here also...

Otherwise this looks correct to me, though I can't approve it.  It's a nice cleanup!

Thanks,
Bill

>  }
>    [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
>     (set_attr_alternative "length"
> @@ -10765,21 +10757,16 @@ (define_insn "*call_indirect_aix<mode>"
>     (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
>     (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
>     (clobber (reg:P LR_REGNO))]
> -  "DEFAULT_ABI == ABI_AIX && rs6000_speculate_indirect_jumps"
> -  "<ptrload> 2,%2\;b%T0l\;<ptrload> 2,%3(1)"
> -  [(set_attr "type" "jmpreg")
> -   (set_attr "length" "12")])
> -
> -(define_insn "*call_indirect_aix<mode>_nospec"
> -  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
> -	 (match_operand 1 "" "g,g"))
> -   (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
> -   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
> -   (clobber (reg:P LR_REGNO))]
> -  "DEFAULT_ABI == ABI_AIX && !rs6000_speculate_indirect_jumps"
> -  "crset 2\;<ptrload> 2,%2\;beq%T0l-\;<ptrload> 2,%3(1)"
> +  "DEFAULT_ABI == ABI_AIX"
> +{
> +  return rs6000_output_indirect_call (operands, 0, false);
> +}
>    [(set_attr "type" "jmpreg")
> -   (set_attr "length" "16")])
> +   (set (attr "length")
> +	(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
> +			   (match_test "which_alternative != 1"))
> +		      (const_string "16")
> +		      (const_string "12")))])
>
>  (define_insn "*call_value_indirect_aix<mode>"
>    [(set (match_operand 0 "" "")
> @@ -10788,22 +10775,16 @@ (define_insn "*call_value_indirect_aix<mode>"
>     (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
>     (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
>     (clobber (reg:P LR_REGNO))]
> -  "DEFAULT_ABI == ABI_AIX && rs6000_speculate_indirect_jumps"
> -  "<ptrload> 2,%3\;b%T1l\;<ptrload> 2,%4(1)"
> -  [(set_attr "type" "jmpreg")
> -   (set_attr "length" "12")])
> -
> -(define_insn "*call_value_indirect_aix<mode>_nospec"
> -  [(set (match_operand 0 "" "")
> -	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
> -	      (match_operand 2 "" "g,g")))
> -   (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
> -   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
> -   (clobber (reg:P LR_REGNO))]
> -  "DEFAULT_ABI == ABI_AIX && !rs6000_speculate_indirect_jumps"
> -  "crset 2\;<ptrload> 2,%3\;beq%T1l-\;<ptrload> 2,%4(1)"
> +  "DEFAULT_ABI == ABI_AIX"
> +{
> +  return rs6000_output_indirect_call (operands, 1, false);
> +}
>    [(set_attr "type" "jmpreg")
> -   (set_attr "length" "16")])
> +   (set (attr "length")
> +	(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
> +			   (match_test "which_alternative != 1"))
> +		      (const_string "16")
> +		      (const_string "12")))])
>
>  ;; Call to indirect functions with the ELFv2 ABI.
>  ;; Operand0 is the addresss of the function to call
> @@ -10814,21 +10795,16 @@ (define_insn "*call_indirect_elfv2<mode>"
>  	 (match_operand 1 "" "g,g"))
>     (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
>     (clobber (reg:P LR_REGNO))]
> -  "DEFAULT_ABI == ABI_ELFv2 && rs6000_speculate_indirect_jumps"
> -  "b%T0l\;<ptrload> 2,%2(1)"
> -  [(set_attr "type" "jmpreg")
> -   (set_attr "length" "8")])
> -
> -;; Variant with deliberate misprediction.
> -(define_insn "*call_indirect_elfv2<mode>_nospec"
> -  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
> -	 (match_operand 1 "" "g,g"))
> -   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
> -   (clobber (reg:P LR_REGNO))]
> -  "DEFAULT_ABI == ABI_ELFv2 && !rs6000_speculate_indirect_jumps"
> -  "crset 2\;beq%T0l-\;<ptrload> 2,%2(1)"
> +  "DEFAULT_ABI == ABI_ELFv2"
> +{
> +  return rs6000_output_indirect_call (operands, 0, false);
> +}
>    [(set_attr "type" "jmpreg")
> -   (set_attr "length" "12")])
> +   (set (attr "length")
> +	(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
> +			   (match_test "which_alternative != 1"))
> +		      (const_string "12")
> +		      (const_string "8")))])
>
>  (define_insn "*call_value_indirect_elfv2<mode>"
>    [(set (match_operand 0 "" "")
> @@ -10836,22 +10812,16 @@ (define_insn "*call_value_indirect_elfv2<mode>"
>  	      (match_operand 2 "" "g,g")))
>     (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
>     (clobber (reg:P LR_REGNO))]
> -  "DEFAULT_ABI == ABI_ELFv2 && rs6000_speculate_indirect_jumps"
> -  "b%T1l\;<ptrload> 2,%3(1)"
> -  [(set_attr "type" "jmpreg")
> -   (set_attr "length" "8")])
> -
> -; Variant with deliberate misprediction.
> -(define_insn "*call_value_indirect_elfv2<mode>_nospec"
> -  [(set (match_operand 0 "" "")
> -	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
> -	      (match_operand 2 "" "g,g")))
> -   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
> -   (clobber (reg:P LR_REGNO))]
> -  "DEFAULT_ABI == ABI_ELFv2 && !rs6000_speculate_indirect_jumps"
> -  "crset 2\;beq%T1l-\;<ptrload> 2,%3(1)"
> +  "DEFAULT_ABI == ABI_ELFv2"
> +{
> +  return rs6000_output_indirect_call (operands, 1, false);
> +}
>    [(set_attr "type" "jmpreg")
> -   (set_attr "length" "12")])
> +   (set (attr "length")
> +	(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
> +			   (match_test "which_alternative != 1"))
> +		      (const_string "12")
> +		      (const_string "8")))])
>
>  ;; Call subroutine returning any type.
>  (define_expand "untyped_call"
> @@ -11020,13 +10990,7 @@ (define_insn "*sibcall_nonlocal_sysv<mode>"
>      output_asm_insn ("creqv 6,6,6", operands);
>
>    if (which_alternative >= 2)
> -    {
> -      if (rs6000_speculate_indirect_jumps)
> -	return "b%T0";
> -      else
> -	/* Can use CR0 since it is volatile across sibcalls.  */
> -	return "crset 2\;beq%T0-\;b $";
> -    }
> +    return rs6000_output_indirect_call (operands, 0, true);
>    else
>      return rs6000_output_call (operands, 0, true, "");
>  }
>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 2/6] [RS6000] rs6000_output_indirect_call
  2018-11-12 19:44   ` Bill Schmidt
@ 2018-11-13  0:14     ` Alan Modra
  2018-11-13 11:14       ` Segher Boessenkool
  0 siblings, 1 reply; 34+ messages in thread
From: Alan Modra @ 2018-11-13  0:14 UTC (permalink / raw)
  To: Bill Schmidt; +Cc: gcc-patches, Segher Boessenkool

On Mon, Nov 12, 2018 at 01:44:08PM -0600, Bill Schmidt wrote:
> On 11/6/18 11:37 PM, Alan Modra wrote:
> > +		 fun, "l" + sibcall);
> 
> It's not at all clear to me what {"l" + sibcall} is doing here.

It's an ancient C programmer's trick, from the days when most
compilers didn't optimize too well.  I think I found it first in the
nethack sources.  :-)

> Whatever it is, it's clever enough that it warrants a comment... :-)
> Does adding "l" to false result in the null string?  Is that
> standard?

"l" results in a "const char*" pointing at 0x6c,0 bytes in memory
(assuming ascii).  Adding "true" to that implicitly converts "true" to
1 and thus a "const char*" pointing at a NUL byte.  All completely
standard, even in that new fangled C++ thingy.

A comment is as much needed as count++; needs /* add one to count. */.
If it bothers people I'll write:  sibcall ? "" : "l".

Hah, even the latest gcc doesn't optimize the conditional expression
down to "l" + sibcall.  Check out the code generated for

const char *
f1 (bool x)
{
  return "a" + x;
}

const char *
f2 (bool x)
{
  return x ? "" : "b";
}

> > --- a/gcc/config/rs6000/rs6000.md
> > +++ b/gcc/config/rs6000/rs6000.md
> > @@ -10540,11 +10540,7 @@ (define_insn "*call_indirect_nonlocal_sysv<mode>"
> >    else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
> >      output_asm_insn ("creqv 6,6,6", operands);
> >
> > -  if (rs6000_speculate_indirect_jumps
> > -      || which_alternative == 1 || which_alternative == 3)
> > -    return "b%T0l";
> > -  else
> > -    return "crset 2\;beq%T0l-";
> > +  return rs6000_output_indirect_call (operands, 0, false);
> 
> Looks like this breaks Darwin?  This pattern matches for DEFAULT_ABI == ABI_DARWIN
> but rs6000_output_indirect_call will hit gcc_unreachable() for that ABI.  

Hmm, yes, thanks for pointing that one out.  I took too much notice of
the pattern name.

Segher, would you like me to repost the series with accumulated fixes,
I mean before you review the rest of the series?

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 2/6] [RS6000] rs6000_output_indirect_call
  2018-11-13  0:14     ` Alan Modra
@ 2018-11-13 11:14       ` Segher Boessenkool
  2018-11-13 12:48         ` [PATCH 1/6] [RS6000] rs6000_call_template for external call insn assembly output Alan Modra
                           ` (5 more replies)
  0 siblings, 6 replies; 34+ messages in thread
From: Segher Boessenkool @ 2018-11-13 11:14 UTC (permalink / raw)
  To: Alan Modra; +Cc: Bill Schmidt, gcc-patches

On Tue, Nov 13, 2018 at 10:44:24AM +1030, Alan Modra wrote:
> On Mon, Nov 12, 2018 at 01:44:08PM -0600, Bill Schmidt wrote:
> > On 11/6/18 11:37 PM, Alan Modra wrote:
> > > +		 fun, "l" + sibcall);
> > 
> > It's not at all clear to me what {"l" + sibcall} is doing here.
> 
> It's an ancient C programmer's trick, from the days when most
> compilers didn't optimize too well.  I think I found it first in the
> nethack sources.  :-)
> 
> > Whatever it is, it's clever enough that it warrants a comment... :-)
> > Does adding "l" to false result in the null string?  Is that
> > standard?
> 
> "l" results in a "const char*" pointing at 0x6c,0 bytes in memory
> (assuming ascii).  Adding "true" to that implicitly converts "true" to
> 1 and thus a "const char*" pointing at a NUL byte.  All completely
> standard, even in that new fangled C++ thingy.
> 
> A comment is as much needed as count++; needs /* add one to count. */.
> If it bothers people I'll write:  sibcall ? "" : "l".

That is nicer, esp. if you can propagate it a bit, simplify the separate
cases.

> Hah, even the latest gcc doesn't optimize the conditional expression
> down to "l" + sibcall.  Check out the code generated for
> 
> const char *
> f1 (bool x)
> {
>   return "a" + x;
> }
> 
> const char *
> f2 (bool x)
> {
>   return x ? "" : "b";
> }

It also doesn't do the opposite: it doesn't optimise

const char *f(_Bool x) { fputs("x" + x, stdout); }

(if x is true this does nothing).

> Segher, would you like me to repost the series with accumulated fixes,
> I mean before you review the rest of the series?

Yes please.


Segher

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 1/6] [RS6000] rs6000_call_template for external call insn assembly output
  2018-11-13 11:14       ` Segher Boessenkool
@ 2018-11-13 12:48         ` Alan Modra
  2018-11-20 15:59           ` Segher Boessenkool
  2018-11-13 12:49         ` [PATCH 2/6] [RS6000] rs6000_indirect_call_template Alan Modra
                           ` (4 subsequent siblings)
  5 siblings, 1 reply; 34+ messages in thread
From: Alan Modra @ 2018-11-13 12:48 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: gcc-patches

Version 2.

This is a first step in tidying rs6000 call patterns, in preparation
to support inline plt calls.

	* config/rs6000/rs6000-protos.h (rs6000_call_template): Declare.
	(rs6000_sibcall_template): Declare.
	(macho_call_template): Rename from output_call.
	* config/rs6000/rs6000.c (rs6000_call_template_1): New function.
	(rs6000_call_template, rs6000_sibcall_template): Likewise.
	(macho_call_template): Rename from output_call.
	* config/rs6000/rs6000.md (tls_gd_aix, tls_gd_sysv),
	(tls_gd_call_aix, tls_gd_call_sysv, tls_ld_aix, tls_ld_sysv),
	(tls_ld_call_aix, tls_ld_call_sysv, call_nonlocal_sysv),
	(call_nonlocal_sysv_secure, call_value_nonlocal_sysv),
	(call_value_nonlocal_sysv_secure, call_nonlocal_aix),
	(call_value_nonlocal_aix): Use rs6000_call_template and update
	occurrences of output_call to macho_call_template.
	(sibcall_nonlocal_sysv, sibcall_value_nonlocal_sysv, sibcall_aix),
	(sibcall_value_aix): Use rs6000_sibcall_template.

diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index fb69019c47c..303ba7b91c3 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -111,6 +111,8 @@ extern int ccr_bit (rtx, int);
 extern void rs6000_output_function_entry (FILE *, const char *);
 extern void print_operand (FILE *, rtx, int);
 extern void print_operand_address (FILE *, rtx);
+extern const char *rs6000_call_template (rtx *, unsigned int, const char *);
+extern const char *rs6000_sibcall_template (rtx *, unsigned int, const char *);
 extern enum rtx_code rs6000_reverse_condition (machine_mode,
 					       enum rtx_code);
 extern rtx rs6000_emit_eqne (machine_mode, rtx, rtx, rtx);
@@ -228,7 +230,7 @@ extern void (*rs6000_target_modify_macros_ptr) (bool, HOST_WIDE_INT,
 extern void rs6000_d_target_versions (void);
 
 #if TARGET_MACHO
-char *output_call (rtx_insn *, rtx *, int, int);
+char *macho_call_template (rtx_insn *, rtx *, int, int);
 #endif
 
 #ifdef NO_DOLLAR_IN_LABEL
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 516e69724cc..6e84f5053c2 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -21372,6 +21372,50 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
   return default_assemble_integer (x, size, aligned_p);
 }
 
+/* Return a template string for assembly to emit when making an
+   external call.  FUNOP is the call mem argument operand number,
+   ARG is either NULL or a @TLSGD or @TLSLD __tls_get_addr argument
+   specifier.  */
+
+static const char *
+rs6000_call_template_1 (rtx *operands ATTRIBUTE_UNUSED, unsigned int funop,
+			bool sibcall, const char *arg)
+{
+  /* -Wformat-overflow workaround, without which gcc thinks that %u
+      might produce 10 digits.  */
+  gcc_assert (funop <= MAX_RECOG_OPERANDS);
+
+  /* The magic 32768 offset here corresponds to the offset of
+     r30 in .got2, as given by LCTOC1.  See sysv4.h:toc_section.  */
+  char z[11];
+  sprintf (z, "%%z%u%s", funop,
+	   (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic == 2
+	    ? "+32768" : ""));
+
+  static char str[32];  /* 4 spare */
+  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)
+    sprintf (str, "b%s %s%s%s", sibcall ? "" : "l", z, arg,
+	     flag_pic ? "@plt" : "");
+  else
+    gcc_unreachable ();
+  return str;
+}
+
+const char *
+rs6000_call_template (rtx *operands, unsigned int funop, const char *arg)
+{
+  return rs6000_call_template_1 (operands, funop, false, arg);
+}
+
+const char *
+rs6000_sibcall_template (rtx *operands, unsigned int funop, const char *arg)
+{
+  return rs6000_call_template_1 (operands, funop, true, arg);
+}
+
 #if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO
 /* Emit an assembler directive to set symbol visibility for DECL to
    VISIBILITY_TYPE.  */
@@ -32810,8 +32854,8 @@ get_prev_label (tree function_name)
    CALL_DEST is the routine we are calling.  */
 
 char *
-output_call (rtx_insn *insn, rtx *operands, int dest_operand_number,
-	     int cookie_operand_number)
+macho_call_template (rtx_insn *insn, rtx *operands, int dest_operand_number,
+		     int cookie_operand_number)
 {
   static char buf[256];
   if (darwin_emit_branch_islands
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 65f5fa6e66b..db9cfe92c72 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -9453,10 +9453,11 @@ (define_insn_and_split "tls_gd_aix<TLSmode:tls_abi_suffix>"
   "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
 {
   if (TARGET_CMODEL != CMODEL_SMALL)
-    return "addis %0,%1,%2@got@tlsgd@ha\;addi %0,%0,%2@got@tlsgd@l\;"
-	   "bl %z3\;nop";
+    output_asm_insn ("addis %0,%1,%2@got@tlsgd@ha\;"
+		     "addi %0,%0,%2@got@tlsgd@l", operands);
   else
-    return "addi %0,%1,%2@got@tlsgd\;bl %z3\;nop";
+    output_asm_insn ("addi %0,%1,%2@got@tlsgd", operands);
+  return rs6000_call_template (operands, 3, "");
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
@@ -9485,15 +9486,8 @@ (define_insn_and_split "tls_gd_sysv<TLSmode:tls_sysv_suffix>"
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
 {
-  if (flag_pic)
-    {
-      if (TARGET_SECURE_PLT && flag_pic == 2)
-	return "addi %0,%1,%2@got@tlsgd\;bl %z3+32768@plt";
-      else
-	return "addi %0,%1,%2@got@tlsgd\;bl %z3@plt";
-    }
-  else
-    return "addi %0,%1,%2@got@tlsgd\;bl %z3";
+  output_asm_insn ("addi %0,%1,%2@got@tlsgd", operands);
+  return rs6000_call_template (operands, 3, "");
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
@@ -9558,7 +9552,9 @@ (define_insn "*tls_gd_call_aix<TLSmode:tls_abi_suffix>"
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS
    && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
-  "bl %z1(%3@tlsgd)\;nop"
+{
+  return rs6000_call_template (operands, 1, "(%3@tlsgd)");
+}
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
@@ -9571,13 +9567,7 @@ (define_insn "*tls_gd_call_sysv<TLSmode:tls_abi_suffix>"
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
 {
-  if (flag_pic)
-    {
-      if (TARGET_SECURE_PLT && flag_pic == 2)
-	return "bl %z1+32768(%3@tlsgd)@plt";
-      return "bl %z1(%3@tlsgd)@plt";
-    }
-  return "bl %z1(%3@tlsgd)";
+  return rs6000_call_template (operands, 1, "(%3@tlsgd)");
 }
   [(set_attr "type" "branch")])
 
@@ -9591,10 +9581,11 @@ (define_insn_and_split "tls_ld_aix<TLSmode:tls_abi_suffix>"
   "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
 {
   if (TARGET_CMODEL != CMODEL_SMALL)
-    return "addis %0,%1,%&@got@tlsld@ha\;addi %0,%0,%&@got@tlsld@l\;"
-	   "bl %z2\;nop";
+    output_asm_insn ("addis %0,%1,%&@got@tlsld@ha\;"
+		     "addi %0,%0,%&@got@tlsld@l", operands);
   else
-    return "addi %0,%1,%&@got@tlsld\;bl %z2\;nop";
+    output_asm_insn ("addi %0,%1,%&@got@tlsld", operands);
+  return rs6000_call_template (operands, 2, "");
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
@@ -9621,15 +9612,8 @@ (define_insn_and_split "tls_ld_sysv<TLSmode:tls_sysv_suffix>"
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
 {
-  if (flag_pic)
-    {
-      if (TARGET_SECURE_PLT && flag_pic == 2)
-	return "addi %0,%1,%&@got@tlsld\;bl %z2+32768@plt";
-      else
-	return "addi %0,%1,%&@got@tlsld\;bl %z2@plt";
-    }
-  else
-    return "addi %0,%1,%&@got@tlsld\;bl %z2";
+  output_asm_insn ("addi %0,%1,%&@got@tlsld", operands);
+  return rs6000_call_template (operands, 2, "");
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
@@ -9690,7 +9674,9 @@ (define_insn "*tls_ld_call_aix<TLSmode:tls_abi_suffix>"
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS
    && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
-  "bl %z1(%&@tlsld)\;nop"
+{
+  return rs6000_call_template (operands, 1, "(%&@tlsld)");
+}
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
@@ -9702,13 +9688,7 @@ (define_insn "*tls_ld_call_sysv<TLSmode:tls_abi_suffix>"
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
 {
-  if (flag_pic)
-    {
-      if (TARGET_SECURE_PLT && flag_pic == 2)
-	return "bl %z1+32768(%&@tlsld)@plt";
-      return "bl %z1(%&@tlsld)@plt";
-    }
-  return "bl %z1(%&@tlsld)";
+  return rs6000_call_template (operands, 1, "(%&@tlsld)");
 }
   [(set_attr "type" "branch")])
 
@@ -10594,15 +10574,9 @@ (define_insn_and_split "*call_nonlocal_sysv<mode>"
     output_asm_insn ("creqv 6,6,6", operands);
 
 #if TARGET_MACHO
-  return output_call(insn, operands, 0, 2);
+  return macho_call_template (insn, operands, 0, 2);
 #else
-  if (DEFAULT_ABI == ABI_V4 && flag_pic)
-    {
-      gcc_assert (!TARGET_SECURE_PLT);
-      return "bl %z0@plt";
-    }
-  else
-    return "bl %z0";
+  return rs6000_call_template (operands, 0, "");
 #endif
 }
   "DEFAULT_ABI == ABI_V4
@@ -10635,13 +10609,7 @@ (define_insn "*call_nonlocal_sysv_secure<mode>"
   else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  if (flag_pic == 2)
-    /* The magic 32768 offset here and in the other sysv call insns
-       corresponds to the offset of r30 in .got2, as given by LCTOC1.
-       See sysv4.h:toc_section.  */
-    return "bl %z0+32768@plt";
-  else
-    return "bl %z0@plt";
+  return rs6000_call_template (operands, 0, "");
 }
   [(set_attr "type" "branch,branch")
    (set_attr "length" "4,8")])
@@ -10697,15 +10665,9 @@ (define_insn_and_split "*call_value_nonlocal_sysv<mode>"
     output_asm_insn ("creqv 6,6,6", operands);
 
 #if TARGET_MACHO
-  return output_call(insn, operands, 1, 3);
+  return macho_call_template (insn, operands, 1, 3);
 #else
-  if (DEFAULT_ABI == ABI_V4 && flag_pic)
-    {
-      gcc_assert (!TARGET_SECURE_PLT);
-      return "bl %z1@plt";
-    }
-  else
-    return "bl %z1";
+  return rs6000_call_template (operands, 1, "");
 #endif
 }
   "DEFAULT_ABI == ABI_V4
@@ -10740,10 +10702,7 @@ (define_insn "*call_value_nonlocal_sysv_secure<mode>"
   else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  if (flag_pic == 2)
-    return "bl %z1+32768@plt";
-  else
-    return "bl %z1@plt";
+  return rs6000_call_template (operands, 1, "");
 }
   [(set_attr "type" "branch,branch")
    (set_attr "length" "4,8")])
@@ -10776,7 +10735,9 @@ (define_insn "*call_nonlocal_aix<mode>"
 	 (match_operand 1 "" "g"))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
-  "bl %z0\;nop"
+{
+  return rs6000_call_template (operands, 0, "");
+}
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
@@ -10786,7 +10747,9 @@ (define_insn "*call_value_nonlocal_aix<mode>"
 	      (match_operand 2 "" "g")))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
-  "bl %z1\;nop"
+{
+  return rs6000_call_template (operands, 1, "");
+}
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
@@ -11063,13 +11026,8 @@ (define_insn "*sibcall_nonlocal_sysv<mode>"
 	/* Can use CR0 since it is volatile across sibcalls.  */
 	return "crset 2\;beq%T0-\;b $";
     }
-  else if (DEFAULT_ABI == ABI_V4 && flag_pic)
-    {
-      gcc_assert (!TARGET_SECURE_PLT);
-      return "b %z0@plt";
-    }
   else
-    return "b %z0";
+    return rs6000_sibcall_template (operands, 0, "");
 }
   [(set_attr "type" "branch")
    (set_attr_alternative "length"
@@ -11108,13 +11066,8 @@ (define_insn "*sibcall_value_nonlocal_sysv<mode>"
 	/* Can use CR0 since it is volatile across sibcalls.  */
 	return "crset 2\;beq%T1-\;b $";
     }
-  else if (DEFAULT_ABI == ABI_V4 && flag_pic)
-    {
-      gcc_assert (!TARGET_SECURE_PLT);
-      return "b %z1@plt";
-    }
   else
-    return "b %z1";
+    return rs6000_sibcall_template (operands, 1, "");
 }
   [(set_attr "type" "branch")
    (set_attr_alternative "length"
@@ -11136,9 +11089,12 @@ (define_insn "*sibcall_aix<mode>"
 	 (match_operand 1 "" "g,g"))
    (simple_return)]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
-  "@
-   b %z0
-   b%T0"
+{
+  if (which_alternative == 0)
+    return rs6000_sibcall_template (operands, 0, "");
+  else
+    return "b%T0";
+}
   [(set_attr "type" "branch")])
 
 (define_insn "*sibcall_value_aix<mode>"
@@ -11147,9 +11103,12 @@ (define_insn "*sibcall_value_aix<mode>"
 	      (match_operand 2 "" "g,g")))
    (simple_return)]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
-  "@
-   b %z1
-   b%T1"
+{
+  if (which_alternative == 0)
+    return rs6000_sibcall_template (operands, 1, "");
+  else
+    return "b%T1";
+}
   [(set_attr "type" "branch")])
 
 (define_expand "sibcall_epilogue"

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 2/6] [RS6000] rs6000_indirect_call_template
  2018-11-13 11:14       ` Segher Boessenkool
  2018-11-13 12:48         ` [PATCH 1/6] [RS6000] rs6000_call_template for external call insn assembly output Alan Modra
@ 2018-11-13 12:49         ` Alan Modra
  2018-11-20 16:23           ` Segher Boessenkool
  2018-11-13 12:50         ` [PATCH 3/6] [RS6000] Replace TLSmode with P, and correct tls call mems Alan Modra
                           ` (3 subsequent siblings)
  5 siblings, 1 reply; 34+ messages in thread
From: Alan Modra @ 2018-11-13 12:49 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: gcc-patches

Version 2.

Like the last patch for external calls, now handle most assembly code
for indirect calls in one place.  The patch also merges some insns,
correcting some !rs6000_speculate_indirect_jumps cases branching to
LR, which don't require a speculation barrier.

	* config/rs6000/rs6000-protos.h (rs6000_indirect_call_template),
	(rs6000_indirect_sibcall_template): Declare.
	* config/rs6000/rs6000.c (rs6000_indirect_call_template_1),
	(rs6000_indirect_call_template, rs6000_indirect_sibcall_template):
	New functions.
	* config/rs6000/rs6000.md (call_indirect_nonlocal_sysv),
	(call_value_indirect_nonlocal_sysv, sibcall_nonlocal_sysv),
	(call_indirect_aix, call_value_indirect_aix): Use
	rs6000_indirect_call_template and rs6000_indirect_sibcall_template.
	call_indirect_elfv2, call_value_indirect_elfv2): Likewise, and
	handle both speculation and non-speculation cases.
	(call_indirect_aix_nospec, call_value_indirect_aix_nospec): Delete.
	(call_indirect_elfv2_nospec, call_value_indirect_elfv2_nospec): Delete.

diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 303ba7b91c3..967f65e2d94 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -113,6 +113,8 @@ extern void print_operand (FILE *, rtx, int);
 extern void print_operand_address (FILE *, rtx);
 extern const char *rs6000_call_template (rtx *, unsigned int, const char *);
 extern const char *rs6000_sibcall_template (rtx *, unsigned int, const char *);
+extern const char *rs6000_indirect_call_template (rtx *, unsigned int);
+extern const char *rs6000_indirect_sibcall_template (rtx *, unsigned int);
 extern enum rtx_code rs6000_reverse_condition (machine_mode,
 					       enum rtx_code);
 extern rtx rs6000_emit_eqne (machine_mode, rtx, rtx, rtx);
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 6e84f5053c2..cd1ab95166e 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -21416,6 +21416,83 @@ rs6000_sibcall_template (rtx *operands, unsigned int funop, const char *arg)
   return rs6000_call_template_1 (operands, funop, true, arg);
 }
 
+/* As above, for indirect calls.  */
+
+static const char *
+rs6000_indirect_call_template_1 (rtx *operands, unsigned int funop,
+				 bool sibcall)
+{
+  /* -Wformat-overflow workaround, without which gcc thinks that %u
+      might produce 10 digits.  */
+  gcc_assert (funop <= MAX_RECOG_OPERANDS);
+
+  static char str[144];
+  const char *ptrload = TARGET_64BIT ? "d" : "wz";
+
+  /* We don't need the extra code to stop indirect call speculation if
+     calling via LR.  */
+  bool speculate = (TARGET_MACHO
+		    || rs6000_speculate_indirect_jumps
+		    || (REG_P (operands[funop])
+			&& REGNO (operands[funop]) == LR_REGNO));
+
+  if (DEFAULT_ABI == ABI_AIX)
+    {
+      if (speculate)
+	sprintf (str,
+		 "l%s 2,%%%u\n\t"
+		 "b%%T%ul\n\t"
+		 "l%s 2,%%%u(1)",
+		 ptrload, funop + 2, funop, ptrload, funop + 3);
+      else
+	sprintf (str,
+		 "crset 2\n\t"
+		 "l%s 2,%%%u\n\t"
+		 "beq%%T%ul-\n\t"
+		 "l%s 2,%%%u(1)",
+		 ptrload, funop + 2, funop, ptrload, funop + 3);
+    }
+  else if (DEFAULT_ABI == ABI_ELFv2)
+    {
+      if (speculate)
+	sprintf (str,
+		 "b%%T%ul\n\t"
+		 "l%s 2,%%%u(1)",
+		 funop, ptrload, funop + 2);
+      else
+	sprintf (str,
+		 "crset 2\n\t"
+		 "beq%%T%ul-\n\t"
+		 "l%s 2,%%%u(1)",
+		 funop, ptrload, funop + 2);
+    }
+  else
+    {
+      if (speculate)
+	sprintf (str,
+		 "b%%T%u%s",
+		 funop, sibcall ? "" : "l");
+      else
+	sprintf (str,
+		 "crset 2\n\t"
+		 "beq%%T%u%s-%s",
+		 funop, sibcall ? "" : "l", sibcall ? "\n\tb $" : "");
+    }
+  return str;
+}
+
+const char *
+rs6000_indirect_call_template (rtx *operands, unsigned int funop)
+{
+  return rs6000_indirect_call_template_1 (operands, funop, false);
+}
+
+const char *
+rs6000_indirect_sibcall_template (rtx *operands, unsigned int funop)
+{
+  return rs6000_indirect_call_template_1 (operands, funop, true);
+}
+
 #if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO
 /* Emit an assembler directive to set symbol visibility for DECL to
    VISIBILITY_TYPE.  */
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index db9cfe92c72..fe904b1966b 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -10539,11 +10539,7 @@ (define_insn "*call_indirect_nonlocal_sysv<mode>"
   else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  if (rs6000_speculate_indirect_jumps
-      || which_alternative == 1 || which_alternative == 3)
-    return "b%T0l";
-  else
-    return "crset 2\;beq%T0l-";
+  return rs6000_indirect_call_template (operands, 0);
 }
   [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
    (set_attr_alternative "length"
@@ -10629,11 +10625,7 @@ (define_insn "*call_value_indirect_nonlocal_sysv<mode>"
   else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  if (rs6000_speculate_indirect_jumps
-      || which_alternative == 1 || which_alternative == 3)
-    return "b%T1l";
-  else
-    return "crset 2\;beq%T1l-";
+  return rs6000_indirect_call_template (operands, 1);
 }
   [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
    (set_attr_alternative "length"
@@ -10764,21 +10756,16 @@ (define_insn "*call_indirect_aix<mode>"
    (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_AIX && rs6000_speculate_indirect_jumps"
-  "<ptrload> 2,%2\;b%T0l\;<ptrload> 2,%3(1)"
-  [(set_attr "type" "jmpreg")
-   (set_attr "length" "12")])
-
-(define_insn "*call_indirect_aix<mode>_nospec"
-  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
-	 (match_operand 1 "" "g,g"))
-   (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
-   (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_AIX && !rs6000_speculate_indirect_jumps"
-  "crset 2\;<ptrload> 2,%2\;beq%T0l-\;<ptrload> 2,%3(1)"
+  "DEFAULT_ABI == ABI_AIX"
+{
+  return rs6000_indirect_call_template (operands, 0);
+}
   [(set_attr "type" "jmpreg")
-   (set_attr "length" "16")])
+   (set (attr "length")
+	(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
+			   (match_test "which_alternative != 1"))
+		      (const_string "16")
+		      (const_string "12")))])
 
 (define_insn "*call_value_indirect_aix<mode>"
   [(set (match_operand 0 "" "")
@@ -10787,22 +10774,16 @@ (define_insn "*call_value_indirect_aix<mode>"
    (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_AIX && rs6000_speculate_indirect_jumps"
-  "<ptrload> 2,%3\;b%T1l\;<ptrload> 2,%4(1)"
-  [(set_attr "type" "jmpreg")
-   (set_attr "length" "12")])
-
-(define_insn "*call_value_indirect_aix<mode>_nospec"
-  [(set (match_operand 0 "" "")
-	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
-	      (match_operand 2 "" "g,g")))
-   (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
-   (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_AIX && !rs6000_speculate_indirect_jumps"
-  "crset 2\;<ptrload> 2,%3\;beq%T1l-\;<ptrload> 2,%4(1)"
+  "DEFAULT_ABI == ABI_AIX"
+{
+  return rs6000_indirect_call_template (operands, 1);
+}
   [(set_attr "type" "jmpreg")
-   (set_attr "length" "16")])
+   (set (attr "length")
+	(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
+			   (match_test "which_alternative != 1"))
+		      (const_string "16")
+		      (const_string "12")))])
 
 ;; Call to indirect functions with the ELFv2 ABI.
 ;; Operand0 is the addresss of the function to call
@@ -10813,21 +10794,16 @@ (define_insn "*call_indirect_elfv2<mode>"
 	 (match_operand 1 "" "g,g"))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_ELFv2 && rs6000_speculate_indirect_jumps"
-  "b%T0l\;<ptrload> 2,%2(1)"
-  [(set_attr "type" "jmpreg")
-   (set_attr "length" "8")])
-
-;; Variant with deliberate misprediction.
-(define_insn "*call_indirect_elfv2<mode>_nospec"
-  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
-	 (match_operand 1 "" "g,g"))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
-   (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_ELFv2 && !rs6000_speculate_indirect_jumps"
-  "crset 2\;beq%T0l-\;<ptrload> 2,%2(1)"
+  "DEFAULT_ABI == ABI_ELFv2"
+{
+  return rs6000_indirect_call_template (operands, 0);
+}
   [(set_attr "type" "jmpreg")
-   (set_attr "length" "12")])
+   (set (attr "length")
+	(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
+			   (match_test "which_alternative != 1"))
+		      (const_string "12")
+		      (const_string "8")))])
 
 (define_insn "*call_value_indirect_elfv2<mode>"
   [(set (match_operand 0 "" "")
@@ -10835,22 +10811,16 @@ (define_insn "*call_value_indirect_elfv2<mode>"
 	      (match_operand 2 "" "g,g")))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_ELFv2 && rs6000_speculate_indirect_jumps"
-  "b%T1l\;<ptrload> 2,%3(1)"
-  [(set_attr "type" "jmpreg")
-   (set_attr "length" "8")])
-
-; Variant with deliberate misprediction.
-(define_insn "*call_value_indirect_elfv2<mode>_nospec"
-  [(set (match_operand 0 "" "")
-	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
-	      (match_operand 2 "" "g,g")))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
-   (clobber (reg:P LR_REGNO))]
-  "DEFAULT_ABI == ABI_ELFv2 && !rs6000_speculate_indirect_jumps"
-  "crset 2\;beq%T1l-\;<ptrload> 2,%3(1)"
+  "DEFAULT_ABI == ABI_ELFv2"
+{
+  return rs6000_indirect_call_template (operands, 1);
+}
   [(set_attr "type" "jmpreg")
-   (set_attr "length" "12")])
+   (set (attr "length")
+	(if_then_else (and (match_test "!rs6000_speculate_indirect_jumps")
+			   (match_test "which_alternative != 1"))
+		      (const_string "12")
+		      (const_string "8")))])
 
 ;; Call subroutine returning any type.
 (define_expand "untyped_call"
@@ -11019,13 +10989,7 @@ (define_insn "*sibcall_nonlocal_sysv<mode>"
     output_asm_insn ("creqv 6,6,6", operands);
 
   if (which_alternative >= 2)
-    {
-      if (rs6000_speculate_indirect_jumps)
-	return "b%T0";
-      else
-	/* Can use CR0 since it is volatile across sibcalls.  */
-	return "crset 2\;beq%T0-\;b $";
-    }
+    return rs6000_indirect_sibcall_template (operands, 0);
   else
     return rs6000_sibcall_template (operands, 0, "");
 }

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 3/6] [RS6000] Replace TLSmode with P, and correct tls call mems
  2018-11-13 11:14       ` Segher Boessenkool
  2018-11-13 12:48         ` [PATCH 1/6] [RS6000] rs6000_call_template for external call insn assembly output Alan Modra
  2018-11-13 12:49         ` [PATCH 2/6] [RS6000] rs6000_indirect_call_template Alan Modra
@ 2018-11-13 12:50         ` Alan Modra
  2018-11-20 17:10           ` Segher Boessenkool
  2018-11-13 12:51         ` [PATCH 4/6] [RS6000] Remove constraints on call rounded_stack_size_rtx arg Alan Modra
                           ` (2 subsequent siblings)
  5 siblings, 1 reply; 34+ messages in thread
From: Alan Modra @ 2018-11-13 12:50 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: gcc-patches

Version 2.

There is really no need to define a TLSmode mode iterator that is
identical (since !TARGET_64BIT == TARGET_32BIT) to the much used P
mode iterator.  It's nonsense to think we might ever want to support
32-bit TLS on 64-bit or vice versa!  The patch also fixes a minor
error in the call mems.  All other direct calls use (call (mem:SI ..)).

	* config/rs6000/rs6000.md (TLSmode): Delete mode iterator.  Replace
	with P throughout except for call mems which should use SI.
	(tls_abi_suffix, tls_sysv_suffix, tls_insn_suffix): Delete mode
	iterators.  Replace with bits, mode and ptrload respectively.

diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index fe904b1966b..793a0a9d840 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -9436,19 +9436,13 @@ (define_peephole2
 \f
 ;; TLS support.
 
-;; Mode attributes for different ABIs.
-(define_mode_iterator TLSmode [(SI "! TARGET_64BIT") (DI "TARGET_64BIT")])
-(define_mode_attr tls_abi_suffix [(SI "32") (DI "64")])
-(define_mode_attr tls_sysv_suffix [(SI "si") (DI "di")])
-(define_mode_attr tls_insn_suffix [(SI "wz") (DI "d")])
-
-(define_insn_and_split "tls_gd_aix<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 3 "symbol_ref_operand" "s"))
+(define_insn_and_split "tls_gd_aix<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
 	      (match_operand 4 "" "g")))
-   (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-	 	    (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-		   UNSPEC_TLSGD)
+   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+	      (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+	     UNSPEC_TLSGD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
 {
@@ -9461,28 +9455,28 @@ (define_insn_and_split "tls_gd_aix<TLSmode:tls_abi_suffix>"
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
-	(unspec:TLSmode [(match_dup 1)
-			 (match_dup 2)]
-			UNSPEC_TLSGD))
+	(unspec:P [(match_dup 1)
+		   (match_dup 2)]
+		  UNSPEC_TLSGD))
    (parallel [(set (match_dup 0)
-   	     	   (call (mem:TLSmode (match_dup 3))
-		   	 (match_dup 4)))
-	      (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD)
+		   (call (mem:SI (match_dup 3))
+			 (match_dup 4)))
+	      (unspec:P [(match_dup 2)] UNSPEC_TLSGD)
 	      (clobber (reg:SI LR_REGNO))])]
   ""
   [(set_attr "type" "two")
    (set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-     		   (const_int 16)
-     		   (const_int 12)))])
+		   (const_int 16)
+		   (const_int 12)))])
 
-(define_insn_and_split "tls_gd_sysv<TLSmode:tls_sysv_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 3 "symbol_ref_operand" "s"))
+(define_insn_and_split "tls_gd_sysv<P:mode>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
 	      (match_operand 4 "" "g")))
-   (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-	 	    (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-		   UNSPEC_TLSGD)
+   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+	      (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+	     UNSPEC_TLSGD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
 {
@@ -9491,64 +9485,64 @@ (define_insn_and_split "tls_gd_sysv<TLSmode:tls_sysv_suffix>"
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
-	(unspec:TLSmode [(match_dup 1)
-			 (match_dup 2)]
-			UNSPEC_TLSGD))
+	(unspec:P [(match_dup 1)
+		   (match_dup 2)]
+		  UNSPEC_TLSGD))
    (parallel [(set (match_dup 0)
-   	     	   (call (mem:TLSmode (match_dup 3))
-		   	 (match_dup 4)))
-	      (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD)
+		   (call (mem:SI (match_dup 3))
+			 (match_dup 4)))
+	      (unspec:P [(match_dup 2)] UNSPEC_TLSGD)
 	      (clobber (reg:SI LR_REGNO))])]
   ""
   [(set_attr "type" "two")
    (set_attr "length" "8")])
 
-(define_insn_and_split "*tls_gd<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSGD))]
+(define_insn_and_split "*tls_gd<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSGD))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS"
   "addi %0,%1,%2@got@tlsgd"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 3)
-  	(high:TLSmode
-	    (unspec:TLSmode [(match_dup 1) (match_dup 2)] UNSPEC_TLSGD)))
+	(high:P
+	    (unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGD)))
    (set (match_dup 0)
-   	(lo_sum:TLSmode (match_dup 3)
-	    (unspec:TLSmode [(match_dup 1) (match_dup 2)] UNSPEC_TLSGD)))]
+	(lo_sum:P (match_dup 3)
+	    (unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGD)))]
 {
   operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
 }
   [(set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-     		   (const_int 8)
-     		   (const_int 4)))])
-
-(define_insn "*tls_gd_high<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (high:TLSmode
-       (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-		       UNSPEC_TLSGD)))]
+		   (const_int 8)
+		   (const_int 4)))])
+
+(define_insn "*tls_gd_high<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+     (high:P
+       (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		  (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		 UNSPEC_TLSGD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addis %0,%1,%2@got@tlsgd@ha")
 
-(define_insn "*tls_gd_low<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
-       (unspec:TLSmode [(match_operand:TLSmode 3 "gpc_reg_operand" "b")
-			(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-		       UNSPEC_TLSGD)))]
+(define_insn "*tls_gd_low<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+     (lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
+       (unspec:P [(match_operand:P 3 "gpc_reg_operand" "b")
+		  (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		 UNSPEC_TLSGD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addi %0,%1,%2@got@tlsgd@l")
 
-(define_insn "*tls_gd_call_aix<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s"))
+(define_insn "*tls_gd_call_aix<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
 	      (match_operand 2 "" "g")))
-   (unspec:TLSmode [(match_operand:TLSmode 3 "rs6000_tls_symbol_ref" "")]
-		   UNSPEC_TLSGD)
+   (unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
+	     UNSPEC_TLSGD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS
    && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
@@ -9558,12 +9552,12 @@ (define_insn "*tls_gd_call_aix<TLSmode:tls_abi_suffix>"
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
-(define_insn "*tls_gd_call_sysv<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s"))
+(define_insn "*tls_gd_call_sysv<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
 	      (match_operand 2 "" "g")))
-   (unspec:TLSmode [(match_operand:TLSmode 3 "rs6000_tls_symbol_ref" "")]
-		   UNSPEC_TLSGD)
+   (unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
+	     UNSPEC_TLSGD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
 {
@@ -9571,12 +9565,12 @@ (define_insn "*tls_gd_call_sysv<TLSmode:tls_abi_suffix>"
 }
   [(set_attr "type" "branch")])
 
-(define_insn_and_split "tls_ld_aix<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 2 "symbol_ref_operand" "s"))
+(define_insn_and_split "tls_ld_aix<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
 	      (match_operand 3 "" "g")))
-   (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")]
-		   UNSPEC_TLSLD)
+   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
+	     UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
 {
@@ -9589,26 +9583,26 @@ (define_insn_and_split "tls_ld_aix<TLSmode:tls_abi_suffix>"
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
-	(unspec:TLSmode [(match_dup 1)]
-			UNSPEC_TLSLD))
+	(unspec:P [(match_dup 1)]
+		  UNSPEC_TLSLD))
    (parallel [(set (match_dup 0)
-   	     	   (call (mem:TLSmode (match_dup 2))
-		   	 (match_dup 3)))
-	      (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)
+		   (call (mem:SI (match_dup 2))
+			 (match_dup 3)))
+	      (unspec:P [(const_int 0)] UNSPEC_TLSLD)
 	      (clobber (reg:SI LR_REGNO))])]
   ""
   [(set_attr "type" "two")
    (set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-     		   (const_int 16)
-     		   (const_int 12)))])
+		   (const_int 16)
+		   (const_int 12)))])
 
-(define_insn_and_split "tls_ld_sysv<TLSmode:tls_sysv_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 2 "symbol_ref_operand" "s"))
+(define_insn_and_split "tls_ld_sysv<P:mode>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
 	      (match_operand 3 "" "g")))
-   (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")]
-		   UNSPEC_TLSLD)
+   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
+	     UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
 {
@@ -9617,60 +9611,60 @@ (define_insn_and_split "tls_ld_sysv<TLSmode:tls_sysv_suffix>"
 }
   "&& TARGET_TLS_MARKERS"
   [(set (match_dup 0)
-	(unspec:TLSmode [(match_dup 1)]
-			UNSPEC_TLSLD))
+	(unspec:P [(match_dup 1)]
+		  UNSPEC_TLSLD))
    (parallel [(set (match_dup 0)
-   	     	   (call (mem:TLSmode (match_dup 2))
-		   	 (match_dup 3)))
-	      (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)
+		   (call (mem:SI (match_dup 2))
+			 (match_dup 3)))
+	      (unspec:P [(const_int 0)] UNSPEC_TLSLD)
 	      (clobber (reg:SI LR_REGNO))])]
   ""
   [(set_attr "length" "8")])
 
-(define_insn_and_split "*tls_ld<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")]
-			UNSPEC_TLSLD))]
+(define_insn_and_split "*tls_ld<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
+		  UNSPEC_TLSLD))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS"
   "addi %0,%1,%&@got@tlsld"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 2)
-  	(high:TLSmode
-	    (unspec:TLSmode [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))
+	(high:P
+	    (unspec:P [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))
    (set (match_dup 0)
-   	(lo_sum:TLSmode (match_dup 2)
-	    (unspec:TLSmode [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))]
+	(lo_sum:P (match_dup 2)
+	    (unspec:P [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))]
 {
   operands[2] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
 }
   [(set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-     		   (const_int 8)
-     		   (const_int 4)))])
-
-(define_insn "*tls_ld_high<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (high:TLSmode
-       (unspec:TLSmode [(const_int 0)
-			(match_operand:TLSmode 1 "gpc_reg_operand" "b")]
-		       UNSPEC_TLSLD)))]
+		   (const_int 8)
+		   (const_int 4)))])
+
+(define_insn "*tls_ld_high<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+     (high:P
+       (unspec:P [(const_int 0)
+		  (match_operand:P 1 "gpc_reg_operand" "b")]
+		 UNSPEC_TLSLD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addis %0,%1,%&@got@tlsld@ha")
 
-(define_insn "*tls_ld_low<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
-       (unspec:TLSmode [(const_int 0)
-                        (match_operand:TLSmode 2 "gpc_reg_operand" "b")]
-                       UNSPEC_TLSLD)))]
+(define_insn "*tls_ld_low<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+     (lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
+       (unspec:P [(const_int 0)
+		  (match_operand:P 2 "gpc_reg_operand" "b")]
+		 UNSPEC_TLSLD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addi %0,%1,%&@got@tlsld@l")
 
-(define_insn "*tls_ld_call_aix<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s"))
+(define_insn "*tls_ld_call_aix<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
 	      (match_operand 2 "" "g")))
-   (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)
+   (unspec:P [(const_int 0)] UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS
    && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
@@ -9680,11 +9674,11 @@ (define_insn "*tls_ld_call_aix<TLSmode:tls_abi_suffix>"
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
 
-(define_insn "*tls_ld_call_sysv<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-        (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s"))
+(define_insn "*tls_ld_call_sysv<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
 	      (match_operand 2 "" "g")))
-   (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)
+   (unspec:P [(const_int 0)] UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
 {
@@ -9692,142 +9686,142 @@ (define_insn "*tls_ld_call_sysv<TLSmode:tls_abi_suffix>"
 }
   [(set_attr "type" "branch")])
 
-(define_insn "tls_dtprel_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSDTPREL))]
+(define_insn "tls_dtprel_<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSDTPREL))]
   "HAVE_AS_TLS"
   "addi %0,%1,%2@dtprel")
 
-(define_insn "tls_dtprel_ha_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSDTPRELHA))]
+(define_insn "tls_dtprel_ha_<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSDTPRELHA))]
   "HAVE_AS_TLS"
   "addis %0,%1,%2@dtprel@ha")
 
-(define_insn "tls_dtprel_lo_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSDTPRELLO))]
+(define_insn "tls_dtprel_lo_<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSDTPRELLO))]
   "HAVE_AS_TLS"
   "addi %0,%1,%2@dtprel@l")
 
-(define_insn_and_split "tls_got_dtprel_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSGOTDTPREL))]
+(define_insn_and_split "tls_got_dtprel_<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSGOTDTPREL))]
   "HAVE_AS_TLS"
-  "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel(%1)"
+  "<P:ptrload> %0,%2@got@dtprel(%1)"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 3)
-	(high:TLSmode
-	    (unspec:TLSmode [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTDTPREL)))
+	(high:P
+	    (unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTDTPREL)))
    (set (match_dup 0)
-	(lo_sum:TLSmode (match_dup 3)
-	    (unspec:TLSmode [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTDTPREL)))]
+	(lo_sum:P (match_dup 3)
+	    (unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTDTPREL)))]
 {
   operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
 }
   [(set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-     		   (const_int 8)
-     		   (const_int 4)))])
-
-(define_insn "*tls_got_dtprel_high<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (high:TLSmode
-       (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-		       UNSPEC_TLSGOTDTPREL)))]
+		   (const_int 8)
+		   (const_int 4)))])
+
+(define_insn "*tls_got_dtprel_high<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+     (high:P
+       (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		  (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		 UNSPEC_TLSGOTDTPREL)))]
   "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
   "addis %0,%1,%2@got@dtprel@ha")
 
-(define_insn "*tls_got_dtprel_low<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-     (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
-	 (unspec:TLSmode [(match_operand:TLSmode 3 "gpc_reg_operand" "b")
-			  (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			 UNSPEC_TLSGOTDTPREL)))]
+(define_insn "*tls_got_dtprel_low<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+     (lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
+	 (unspec:P [(match_operand:P 3 "gpc_reg_operand" "b")
+		    (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSGOTDTPREL)))]
   "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
-  "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel@l(%1)")
+  "<P:ptrload> %0,%2@got@dtprel@l(%1)")
 
-(define_insn "tls_tprel_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSTPREL))]
+(define_insn "tls_tprel_<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSTPREL))]
   "HAVE_AS_TLS"
   "addi %0,%1,%2@tprel")
 
-(define_insn "tls_tprel_ha_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSTPRELHA))]
+(define_insn "tls_tprel_ha_<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSTPRELHA))]
   "HAVE_AS_TLS"
   "addis %0,%1,%2@tprel@ha")
 
-(define_insn "tls_tprel_lo_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSTPRELLO))]
+(define_insn "tls_tprel_lo_<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSTPRELLO))]
   "HAVE_AS_TLS"
   "addi %0,%1,%2@tprel@l")
 
 ;; "b" output constraint here and on tls_tls input to support linker tls
 ;; optimization.  The linker may edit the instructions emitted by a
 ;; tls_got_tprel/tls_tls pair to addis,addi.
-(define_insn_and_split "tls_got_tprel_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSGOTTPREL))]
+(define_insn_and_split "tls_got_tprel_<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSGOTTPREL))]
   "HAVE_AS_TLS"
-  "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel(%1)"
+  "<P:ptrload> %0,%2@got@tprel(%1)"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 3)
-	(high:TLSmode
-	    (unspec:TLSmode [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTTPREL)))
+	(high:P
+	    (unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTTPREL)))
    (set (match_dup 0)
-	(lo_sum:TLSmode (match_dup 3)
-	    (unspec:TLSmode [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTTPREL)))]
+	(lo_sum:P (match_dup 3)
+	    (unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGOTTPREL)))]
 {
   operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
 }
   [(set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-     		   (const_int 8)
-     		   (const_int 4)))])
-
-(define_insn "*tls_got_tprel_high<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
-     (high:TLSmode
-       (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-		       UNSPEC_TLSGOTTPREL)))]
+		   (const_int 8)
+		   (const_int 4)))])
+
+(define_insn "*tls_got_tprel_high<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+     (high:P
+       (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		  (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		 UNSPEC_TLSGOTTPREL)))]
   "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
   "addis %0,%1,%2@got@tprel@ha")
 
-(define_insn "*tls_got_tprel_low<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-     (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
-	 (unspec:TLSmode [(match_operand:TLSmode 3 "gpc_reg_operand" "b")
-			  (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			 UNSPEC_TLSGOTTPREL)))]
+(define_insn "*tls_got_tprel_low<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+     (lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
+	 (unspec:P [(match_operand:P 3 "gpc_reg_operand" "b")
+		    (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		   UNSPEC_TLSGOTTPREL)))]
   "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
-  "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel@l(%1)")
+  "<P:ptrload> %0,%2@got@tprel@l(%1)")
 
-(define_insn "tls_tls_<TLSmode:tls_abi_suffix>"
-  [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
-	(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
-			 (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
-			UNSPEC_TLSTLS))]
+(define_insn "tls_tls_<P:bits>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+		  UNSPEC_TLSTLS))]
   "TARGET_ELF && HAVE_AS_TLS"
   "add %0,%1,%2@tls")
 

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 4/6] [RS6000] Remove constraints on call rounded_stack_size_rtx arg
  2018-11-13 11:14       ` Segher Boessenkool
                           ` (2 preceding siblings ...)
  2018-11-13 12:50         ` [PATCH 3/6] [RS6000] Replace TLSmode with P, and correct tls call mems Alan Modra
@ 2018-11-13 12:51         ` Alan Modra
  2018-11-27 15:27           ` Segher Boessenkool
  2018-11-13 12:52         ` [PATCH 5/6] [RS6000] Use standard call patterns for __tls_get_addr calls Alan Modra
  2018-11-13 12:53         ` [PATCH 6/6] [RS6000] inline plt call sequences Alan Modra
  5 siblings, 1 reply; 34+ messages in thread
From: Alan Modra @ 2018-11-13 12:51 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: gcc-patches

Version 2.  (Same as before, here for completeness.)

This call arg is unused on rs6000.

	* config/rs6000/darwin.md (call_indirect_nonlocal_darwin64),
	(call_nonlocal_darwin64, call_value_indirect_nonlocal_darwin64),
	(call_value_nonlocal_darwin64): Remove constraints from second call
	arg, the rounded_stack_size_rtx arg.
	* config/rs6000/rs6000.md (tls_gd_aix, tls_gd_sysv, tls_gd_call_aix),
	(tls_gd_call_sysv, tls_ld_aix, tls_ld_sysv, tls_ld_call_aix),
	(tls_ld_call_sysv, call_local32, call_local64, call_value_local32),
	(call_value_local64, call_indirect_nonlocal_sysv),
	(call_nonlocal_sysv, call_nonlocal_sysv_secure),
	(call_value_indirect_nonlocal_sysv, call_value_nonlocal_sysv),
	(call_value_nonlocal_sysv_secure, call_local_aix),
	(call_value_local_aix, call_nonlocal_aix, call_value_nonlocal_aix),
	(call_indirect_aix, call_value_indirect_aix, call_indirect_elfv2),
	(call_value_indirect_elfv2, sibcall_local32, sibcall_local64),
	(sibcall_value_local32, sibcall_value_local64, sibcall_aix),
	(sibcall_value_aix): Likewise.

diff --git a/gcc/config/rs6000/darwin.md b/gcc/config/rs6000/darwin.md
index 2d6d1ca57dd..a1c07702d6f 100644
--- a/gcc/config/rs6000/darwin.md
+++ b/gcc/config/rs6000/darwin.md
@@ -302,7 +302,7 @@ (define_insn "macho_correct_pic_di"
 
 (define_insn "*call_indirect_nonlocal_darwin64"
   [(call (mem:SI (match_operand:DI 0 "register_operand" "c,*l,c,*l"))
-	 (match_operand 1 "" "g,g,g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,O,n,n"))
    (clobber (reg:SI LR_REGNO))]
   "DEFAULT_ABI == ABI_DARWIN && TARGET_64BIT"
@@ -314,7 +314,7 @@ (define_insn "*call_indirect_nonlocal_darwin64"
 
 (define_insn "*call_nonlocal_darwin64"
   [(call (mem:SI (match_operand:DI 0 "symbol_ref_operand" "s,s"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "(DEFAULT_ABI == ABI_DARWIN)
@@ -332,7 +332,7 @@ (define_insn "*call_nonlocal_darwin64"
 (define_insn "*call_value_indirect_nonlocal_darwin64"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:DI 1 "register_operand" "c,*l,c,*l"))
-	      (match_operand 2 "" "g,g,g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,O,n,n"))
    (clobber (reg:SI LR_REGNO))]
   "DEFAULT_ABI == ABI_DARWIN"
@@ -345,7 +345,7 @@ (define_insn "*call_value_indirect_nonlocal_darwin64"
 (define_insn "*call_value_nonlocal_darwin64"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:DI 1 "symbol_ref_operand" "s,s"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "(DEFAULT_ABI == ABI_DARWIN)
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 793a0a9d840..c261c8bb9c1 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -9439,7 +9439,7 @@ (define_peephole2
 (define_insn_and_split "tls_gd_aix<P:bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
-	      (match_operand 4 "" "g")))
+	      (match_operand 4)))
    (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
 	      (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
 	     UNSPEC_TLSGD)
@@ -9473,7 +9473,7 @@ (define_insn_and_split "tls_gd_aix<P:bits>"
 (define_insn_and_split "tls_gd_sysv<P:mode>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
-	      (match_operand 4 "" "g")))
+	      (match_operand 4)))
    (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
 	      (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
 	     UNSPEC_TLSGD)
@@ -9540,7 +9540,7 @@ (define_insn "*tls_gd_low<P:bits>"
 (define_insn "*tls_gd_call_aix<P:bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2 "" "g")))
+	      (match_operand 2)))
    (unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
 	     UNSPEC_TLSGD)
    (clobber (reg:SI LR_REGNO))]
@@ -9555,7 +9555,7 @@ (define_insn "*tls_gd_call_aix<P:bits>"
 (define_insn "*tls_gd_call_sysv<P:bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2 "" "g")))
+	      (match_operand 2)))
    (unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
 	     UNSPEC_TLSGD)
    (clobber (reg:SI LR_REGNO))]
@@ -9568,7 +9568,7 @@ (define_insn "*tls_gd_call_sysv<P:bits>"
 (define_insn_and_split "tls_ld_aix<P:bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
-	      (match_operand 3 "" "g")))
+	      (match_operand 3)))
    (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
 	     UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
@@ -9600,7 +9600,7 @@ (define_insn_and_split "tls_ld_aix<P:bits>"
 (define_insn_and_split "tls_ld_sysv<P:mode>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
-	      (match_operand 3 "" "g")))
+	      (match_operand 3)))
    (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
 	     UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
@@ -9663,7 +9663,7 @@ (define_insn "*tls_ld_low<P:bits>"
 (define_insn "*tls_ld_call_aix<P:bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2 "" "g")))
+	      (match_operand 2)))
    (unspec:P [(const_int 0)] UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS
@@ -9677,7 +9677,7 @@ (define_insn "*tls_ld_call_aix<P:bits>"
 (define_insn "*tls_ld_call_sysv<P:bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
         (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2 "" "g")))
+	      (match_operand 2)))
    (unspec:P [(const_int 0)] UNSPEC_TLSLD)
    (clobber (reg:SI LR_REGNO))]
   "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
@@ -10439,7 +10439,7 @@ (define_expand "call_value"
 
 (define_insn "*call_local32"
   [(call (mem:SI (match_operand:SI 0 "current_file_function_operand" "s,s"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "(INTVAL (operands[2]) & CALL_LONG) == 0"
@@ -10457,7 +10457,7 @@ (define_insn "*call_local32"
 
 (define_insn "*call_local64"
   [(call (mem:SI (match_operand:DI 0 "current_file_function_operand" "s,s"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "TARGET_64BIT && (INTVAL (operands[2]) & CALL_LONG) == 0"
@@ -10476,7 +10476,7 @@ (define_insn "*call_local64"
 (define_insn "*call_value_local32"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "current_file_function_operand" "s,s"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "(INTVAL (operands[3]) & CALL_LONG) == 0"
@@ -10496,7 +10496,7 @@ (define_insn "*call_value_local32"
 (define_insn "*call_value_local64"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:DI 1 "current_file_function_operand" "s,s"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "TARGET_64BIT && (INTVAL (operands[3]) & CALL_LONG) == 0"
@@ -10521,7 +10521,7 @@ (define_insn "*call_value_local64"
 
 (define_insn "*call_indirect_nonlocal_sysv<mode>"
   [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l,c,*l"))
-	 (match_operand 1 "" "g,g,g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,O,n,n"))
    (clobber (reg:SI LR_REGNO))]
   "DEFAULT_ABI == ABI_V4
@@ -10550,7 +10550,7 @@ (define_insn "*call_indirect_nonlocal_sysv<mode>"
 
 (define_insn_and_split "*call_nonlocal_sysv<mode>"
   [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "(DEFAULT_ABI == ABI_DARWIN
@@ -10585,7 +10585,7 @@ (define_insn_and_split "*call_nonlocal_sysv<mode>"
 
 (define_insn "*call_nonlocal_sysv_secure<mode>"
   [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
    (use (match_operand:SI 3 "register_operand" "r,r"))
    (clobber (reg:SI LR_REGNO))]
@@ -10607,7 +10607,7 @@ (define_insn "*call_nonlocal_sysv_secure<mode>"
 (define_insn "*call_value_indirect_nonlocal_sysv<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l,c,*l"))
-	      (match_operand 2 "" "g,g,g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,O,n,n"))
    (clobber (reg:SI LR_REGNO))]
   "DEFAULT_ABI == ABI_V4
@@ -10637,7 +10637,7 @@ (define_insn "*call_value_indirect_nonlocal_sysv<mode>"
 (define_insn_and_split "*call_value_nonlocal_sysv<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (clobber (reg:SI LR_REGNO))]
   "(DEFAULT_ABI == ABI_DARWIN
@@ -10674,7 +10674,7 @@ (define_insn_and_split "*call_value_nonlocal_sysv<mode>"
 (define_insn "*call_value_nonlocal_sysv_secure<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (use (match_operand:SI 4 "register_operand" "r,r"))
    (clobber (reg:SI LR_REGNO))]
@@ -10698,7 +10698,7 @@ (define_insn "*call_value_nonlocal_sysv_secure<mode>"
 
 (define_insn "*call_local_aix<mode>"
   [(call (mem:SI (match_operand:P 0 "current_file_function_operand" "s"))
-	 (match_operand 1 "" "g"))
+	 (match_operand 1))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
   "bl %z0"
@@ -10707,7 +10707,7 @@ (define_insn "*call_local_aix<mode>"
 (define_insn "*call_value_local_aix<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "current_file_function_operand" "s"))
-	      (match_operand 2 "" "g")))
+	      (match_operand 2)))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
   "bl %z1"
@@ -10718,7 +10718,7 @@ (define_insn "*call_value_local_aix<mode>"
 
 (define_insn "*call_nonlocal_aix<mode>"
   [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s"))
-	 (match_operand 1 "" "g"))
+	 (match_operand 1))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
@@ -10730,7 +10730,7 @@ (define_insn "*call_nonlocal_aix<mode>"
 (define_insn "*call_value_nonlocal_aix<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2 "" "g")))
+	      (match_operand 2)))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
@@ -10746,7 +10746,7 @@ (define_insn "*call_value_nonlocal_aix<mode>"
 
 (define_insn "*call_indirect_aix<mode>"
   [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
@@ -10764,7 +10764,7 @@ (define_insn "*call_indirect_aix<mode>"
 (define_insn "*call_value_indirect_aix<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
@@ -10785,7 +10785,7 @@ (define_insn "*call_value_indirect_aix<mode>"
 
 (define_insn "*call_indirect_elfv2<mode>"
   [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_ELFv2"
@@ -10802,7 +10802,7 @@ (define_insn "*call_indirect_elfv2<mode>"
 (define_insn "*call_value_indirect_elfv2<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_ELFv2"
@@ -10895,7 +10895,7 @@ (define_expand "sibcall_value"
 
 (define_insn "*sibcall_local32"
   [(call (mem:SI (match_operand:SI 0 "current_file_function_operand" "s,s"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
    (simple_return)]
   "(INTVAL (operands[2]) & CALL_LONG) == 0"
@@ -10913,7 +10913,7 @@ (define_insn "*sibcall_local32"
 
 (define_insn "*sibcall_local64"
   [(call (mem:SI (match_operand:DI 0 "current_file_function_operand" "s,s"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
    (simple_return)]
   "TARGET_64BIT && (INTVAL (operands[2]) & CALL_LONG) == 0"
@@ -10932,7 +10932,7 @@ (define_insn "*sibcall_local64"
 (define_insn "*sibcall_value_local32"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "current_file_function_operand" "s,s"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (simple_return)]
   "(INTVAL (operands[3]) & CALL_LONG) == 0"
@@ -10951,7 +10951,7 @@ (define_insn "*sibcall_value_local32"
 (define_insn "*sibcall_value_local64"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:DI 1 "current_file_function_operand" "s,s"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (simple_return)]
   "TARGET_64BIT && (INTVAL (operands[3]) & CALL_LONG) == 0"
@@ -11044,7 +11044,7 @@ (define_insn "*sibcall_value_nonlocal_sysv<mode>"
 
 (define_insn "*sibcall_aix<mode>"
   [(call (mem:SI (match_operand:P 0 "call_operand" "s,c"))
-	 (match_operand 1 "" "g,g"))
+	 (match_operand 1))
    (simple_return)]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
@@ -11058,7 +11058,7 @@ (define_insn "*sibcall_aix<mode>"
 (define_insn "*sibcall_value_aix<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "call_operand" "s,c"))
-	      (match_operand 2 "" "g,g")))
+	      (match_operand 2)))
    (simple_return)]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 5/6] [RS6000] Use standard call patterns for __tls_get_addr calls
  2018-11-13 11:14       ` Segher Boessenkool
                           ` (3 preceding siblings ...)
  2018-11-13 12:51         ` [PATCH 4/6] [RS6000] Remove constraints on call rounded_stack_size_rtx arg Alan Modra
@ 2018-11-13 12:52         ` Alan Modra
  2018-11-27 16:29           ` Segher Boessenkool
  2018-11-13 12:53         ` [PATCH 6/6] [RS6000] inline plt call sequences Alan Modra
  5 siblings, 1 reply; 34+ messages in thread
From: Alan Modra @ 2018-11-13 12:52 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: gcc-patches

Version 2.

The current code handling __tls_get_addr calls for powerpc*-linux
generates a call then overwrites the call insn with a special
tls_{gd,ld}_{aix,sysv} pattern.  It's done that way to support
!TARGET_TLS_MARKERS, where the arg setup insns need to be emitted
immediately before the branch and link.  When TARGET_TLS_MARKERS, the
arg setup insns are split from the actual call, but we then have a
non-standard call pattern that needs to be carried through to output.

This patch changes that scheme, to instead use the standard call
patterns for __tls_get_addr calls, except for the now rare
!TARGET_TLS_MARKERS case.  Doing it this way should be better for
maintenance as the !TARGET_TLS_MARKERS code can eventually disappear.
It also makes it possible to support longcalls (and in following
patches, inline plt calls) for __tls_get_addr without introducing yet
more special call patterns.

__tls_get_addr calls do however need to be different to standard
calls, because when TARGET_TLS_MARKERS the calls are decorated with an
argument specifier, eg. "bl __tls_get_addr(thread_var@tlsgd)" that
causes a reloc to be emitted by the assembler tying the call to its
arg setup insns.  I chose to smuggle the arg in the currently unused
stack size rtl.

I've also introduced rs6000_call_sysv to generate rtl for sysv calls,
as rs6000_call_aix does for aix and elfv2 calls.  This allows
rs6000_longcall_ref to be local to rs6000.c since the calls in the
expanders never did anything for darwin.

	* config/rs6000/predicates.md (unspec_tls): New.
	* config/rs6000/rs6000-protos.h (rs6000_call_template),
	(rs6000_sibcall_template): Update prototype.
	(rs6000_longcall_ref): Delete.
	(rs6000_call_sysv): Declare.
	* config/rs6000/rs6000.c (edit_tls_call_insn): New function.
	(global_tlsarg): New variable.
	(rs6000_legitimize_tls_address): Rewrite __tls_get_addr call
	handling.
	(print_operand): Extract UNSPEC_TLSGD address operand.
	(rs6000_call_template, rs6000_sibcall_template): Remove arg
	parameter, extract from second call operand instead.
	(rs6000_longcall_ref): Make static, localize vars.
	(rs6000_call_aix): Rename parameter to reflect new usage.  Take
	tlsarg from global_tlsarg.  Don't create unused rtl or nop insns.
	(rs6000_sibcall_aix): Rename parameter to reflect new usage.  Take
	tlsarg from global_tlsarg.
	(rs6000_call_sysv): New function.
	* config/rs6000/rs6000.md: Adjust rs6000_call_template and
	rs6000_sibcall_template throughout.
	(tls_gd_aix, tls_gd_sysv, tls_gd_call_aix, tls_gd_call_sysv): Delete.
	(tls_ld_aix, tls_ld_sysv, tls_ld_call_aix, tls_ld_call_sysv): Delete.
	(tls_gdld_aix, tls_gdld_sysv): New insns, replacing above.
	(tls_gd): Swap operand order.  Simplify mode selection.
	(tls_gd_high, tls_gd_low): Swap operand order.
	(tls_ld): Remove const_int 0 vector element from UNSPEC_TLSLD.
	Simplify mode selection.
	(tls_ld_high, tls_ld_low): Similarly adjust UNSPEC_TLSLD.
	(call, call_value): Don't assert for second call operand.
	Use rs6000_call_sysv.

diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index b80c278d742..7e45d2f0371 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -1039,6 +1039,13 @@ (define_predicate "rs6000_tls_symbol_ref"
   (and (match_code "symbol_ref")
        (match_test "RS6000_SYMBOL_REF_TLS_P (op)")))
 
+;; Return 1 for the UNSPEC used in TLS call operands
+(define_predicate "unspec_tls"
+  (match_code "unspec")
+{
+  return XINT (op, 1) == UNSPEC_TLSGD || XINT (op, 1) == UNSPEC_TLSLD;
+})
+
 ;; Return 1 if the operand, used inside a MEM, is a valid first argument
 ;; to CALL.  This is a SYMBOL_REF, a pseudo-register, LR or CTR.
 (define_predicate "call_operand"
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 967f65e2d94..3fd89dc20db 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -111,8 +111,8 @@ extern int ccr_bit (rtx, int);
 extern void rs6000_output_function_entry (FILE *, const char *);
 extern void print_operand (FILE *, rtx, int);
 extern void print_operand_address (FILE *, rtx);
-extern const char *rs6000_call_template (rtx *, unsigned int, const char *);
-extern const char *rs6000_sibcall_template (rtx *, unsigned int, const char *);
+extern const char *rs6000_call_template (rtx *, unsigned int);
+extern const char *rs6000_sibcall_template (rtx *, unsigned int);
 extern const char *rs6000_indirect_call_template (rtx *, unsigned int);
 extern const char *rs6000_indirect_sibcall_template (rtx *, unsigned int);
 extern enum rtx_code rs6000_reverse_condition (machine_mode,
@@ -136,7 +136,6 @@ extern void rs6000_expand_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx);
 extern void rs6000_emit_swdiv (rtx, rtx, rtx, bool);
 extern void rs6000_emit_swsqrt (rtx, rtx, bool);
 extern void output_toc (FILE *, rtx, int, machine_mode);
-extern rtx rs6000_longcall_ref (rtx);
 extern void rs6000_fatal_bad_address (rtx);
 extern rtx create_TOC_reference (rtx, rtx);
 extern void rs6000_split_multireg_move (rtx, rtx);
@@ -204,6 +203,7 @@ extern void rs6000_split_stack_space_check (rtx, rtx);
 extern void rs6000_emit_eh_reg_restore (rtx, rtx);
 extern void rs6000_call_aix (rtx, rtx, rtx, rtx);
 extern void rs6000_sibcall_aix (rtx, rtx, rtx, rtx);
+extern void rs6000_call_sysv (rtx, rtx, rtx, rtx);
 extern void rs6000_aix_asm_output_dwarf_table_ref (char *);
 extern void get_ppc476_thunk_name (char name[32]);
 extern bool rs6000_overloaded_builtin_p (enum rs6000_builtins);
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index cd1ab95166e..5fd6e17bdda 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -8583,6 +8583,43 @@ rs6000_legitimize_tls_address_aix (rtx addr, enum tls_model model)
   return dest;
 }
 
+/* Mess with a call, to make it look like the tls_gdld insns when
+   !TARGET_TLS_MARKERS.  These insns have an extra unspec to
+   differentiate them from standard calls, because they need to emit
+   the arg setup insns as well as the actual call.  That keeps the
+   arg setup insns immediately adjacent to the branch and link.  */
+
+static void
+edit_tls_call_insn (rtx arg)
+{
+  rtx call_insn = last_call_insn ();
+  if (!TARGET_TLS_MARKERS)
+    {
+      rtx patt = PATTERN (call_insn);
+      gcc_assert (GET_CODE (patt) == PARALLEL);
+      rtvec orig = XVEC (patt, 0);
+      rtvec v = rtvec_alloc (GET_NUM_ELEM (orig) + 1);
+      gcc_assert (GET_NUM_ELEM (orig) > 0);
+      /* The (set (..) (call (mem ..))).  */
+      RTVEC_ELT (v, 0) = RTVEC_ELT (orig, 0);
+      /* The extra unspec.  */
+      RTVEC_ELT (v, 1) = arg;
+      /* All other assorted call pattern pieces.  */
+      for (int i = 1; i < GET_NUM_ELEM (orig); i++)
+	RTVEC_ELT (v, i + 1) = RTVEC_ELT (orig, i);
+      XVEC (patt, 0) = v;
+    }
+  if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
+    use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
+	     pic_offset_table_rtx);
+}
+
+/* Passes the tls arg value for global dynamic and local dynamic
+   emit_library_call_value in rs6000_legitimize_Tls_address to
+   rs6000_call_aix and rs6000_call_sysv.  This is used to emit the
+   marker relocs put on __tls_get_addr calls.  */
+static rtx global_tlsarg;
+
 /* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
    this (thread-local) address.  */
 
@@ -8635,7 +8672,7 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
     }
   else
     {
-      rtx r3, got, tga, tmp1, tmp2, call_insn;
+      rtx got, tga, tmp1, tmp2;
 
       /* We currently use relocations like @got@tlsgd for tls, which
 	 means the linker will handle allocation of tls entries, placing
@@ -8675,52 +8712,42 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
 
       if (model == TLS_MODEL_GLOBAL_DYNAMIC)
 	{
+	  rtx arg = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, addr, got),
+				    UNSPEC_TLSGD);
+	  global_tlsarg = arg;
+	  rtx argreg = const0_rtx;
+	  if (TARGET_TLS_MARKERS)
+	    {
+	      argreg = gen_rtx_REG (Pmode, 3);
+	      emit_insn (gen_rtx_SET (argreg, arg));
+	    }
+
 	  tga = rs6000_tls_get_addr ();
 	  emit_library_call_value (tga, dest, LCT_CONST, Pmode,
-				   const0_rtx, Pmode);
+				   argreg, Pmode);
+	  global_tlsarg = NULL_RTX;
 
-	  r3 = gen_rtx_REG (Pmode, 3);
-	  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
-	    {
-	      if (TARGET_64BIT)
-		insn = gen_tls_gd_aix64 (r3, got, addr, tga, const0_rtx);
-	      else
-		insn = gen_tls_gd_aix32 (r3, got, addr, tga, const0_rtx);
-	    }
-	  else if (DEFAULT_ABI == ABI_V4)
-	    insn = gen_tls_gd_sysvsi (r3, got, addr, tga, const0_rtx);
-	  else
-	    gcc_unreachable ();
-	  call_insn = last_call_insn ();
-	  PATTERN (call_insn) = insn;
-	  if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
-	    use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
-		     pic_offset_table_rtx);
+	  edit_tls_call_insn (arg);
 	}
       else if (model == TLS_MODEL_LOCAL_DYNAMIC)
 	{
+	  rtx arg = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, got),
+				    UNSPEC_TLSLD);
+	  global_tlsarg = arg;
+	  rtx argreg = const0_rtx;
+	  if (TARGET_TLS_MARKERS)
+	    {
+	      argreg = gen_rtx_REG (Pmode, 3);
+	      emit_insn (gen_rtx_SET (argreg, arg));
+	    }
+
 	  tga = rs6000_tls_get_addr ();
 	  tmp1 = gen_reg_rtx (Pmode);
 	  emit_library_call_value (tga, tmp1, LCT_CONST, Pmode,
-				   const0_rtx, Pmode);
+				   argreg, Pmode);
+	  global_tlsarg = NULL_RTX;
 
-	  r3 = gen_rtx_REG (Pmode, 3);
-	  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
-	    {
-	      if (TARGET_64BIT)
-		insn = gen_tls_ld_aix64 (r3, got, tga, const0_rtx);
-	      else
-		insn = gen_tls_ld_aix32 (r3, got, tga, const0_rtx);
-	    }
-	  else if (DEFAULT_ABI == ABI_V4)
-	    insn = gen_tls_ld_sysvsi (r3, got, tga, const0_rtx);
-	  else
-	    gcc_unreachable ();
-	  call_insn = last_call_insn ();
-	  PATTERN (call_insn) = insn;
-	  if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
-	    use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
-		     pic_offset_table_rtx);
+	  edit_tls_call_insn (arg);
 
 	  if (rs6000_tls_size == 16)
 	    {
@@ -21175,19 +21202,19 @@ print_operand (FILE *file, rtx x, int code)
 	  else
 	    output_address (GET_MODE (x), XEXP (x, 0));
 	}
+      else if (toc_relative_expr_p (x, false,
+				    &tocrel_base_oac, &tocrel_offset_oac))
+	/* This hack along with a corresponding hack in
+	   rs6000_output_addr_const_extra arranges to output addends
+	   where the assembler expects to find them.  eg.
+	   (plus (unspec [(symbol_ref ("x")) (reg 2)] tocrel) 4)
+	   without this hack would be output as "x@toc+4".  We
+	   want "x+4@toc".  */
+	output_addr_const (file, CONST_CAST_RTX (tocrel_base_oac));
+      else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSGD)
+	output_addr_const (file, XVECEXP (x, 0, 0));
       else
-	{
-	  if (toc_relative_expr_p (x, false, &tocrel_base_oac, &tocrel_offset_oac))
-	    /* This hack along with a corresponding hack in
-	       rs6000_output_addr_const_extra arranges to output addends
-	       where the assembler expects to find them.  eg.
-	       (plus (unspec [(symbol_ref ("x")) (reg 2)] tocrel) 4)
-	       without this hack would be output as "x@toc+4".  We
-	       want "x+4@toc".  */
-	    output_addr_const (file, CONST_CAST_RTX (tocrel_base_oac));
-	  else
-	    output_addr_const (file, x);
-	}
+	output_addr_const (file, x);
       return;
 
     case '&':
@@ -21373,18 +21400,27 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
 }
 
 /* Return a template string for assembly to emit when making an
-   external call.  FUNOP is the call mem argument operand number,
-   ARG is either NULL or a @TLSGD or @TLSLD __tls_get_addr argument
-   specifier.  */
+   external call.  FUNOP is the call mem argument operand number.  */
 
 static const char *
-rs6000_call_template_1 (rtx *operands ATTRIBUTE_UNUSED, unsigned int funop,
-			bool sibcall, const char *arg)
+rs6000_call_template_1 (rtx *operands, unsigned int funop, bool sibcall)
 {
   /* -Wformat-overflow workaround, without which gcc thinks that %u
       might produce 10 digits.  */
   gcc_assert (funop <= MAX_RECOG_OPERANDS);
 
+  char arg[12];
+  arg[0] = 0;
+  if (GET_CODE (operands[funop + 1]) == UNSPEC)
+    {
+      if (XINT (operands[funop + 1], 1) == UNSPEC_TLSGD)
+	sprintf (arg, "(%%%u@tlsgd)", funop + 1);
+      else if (XINT (operands[funop + 1], 1) == UNSPEC_TLSLD)
+	sprintf (arg, "(%%&@tlsld)");
+      else
+	gcc_unreachable ();
+    }
+
   /* The magic 32768 offset here corresponds to the offset of
      r30 in .got2, as given by LCTOC1.  See sysv4.h:toc_section.  */
   char z[11];
@@ -21392,7 +21428,7 @@ rs6000_call_template_1 (rtx *operands ATTRIBUTE_UNUSED, unsigned int funop,
 	   (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic == 2
 	    ? "+32768" : ""));
 
-  static char str[32];  /* 4 spare */
+  static char str[32];  /* 2 spare */
   if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
     sprintf (str, "b%s %s%s%s", sibcall ? "" : "l", z, arg,
 	     sibcall ? "" : "\n\tnop");
@@ -21405,15 +21441,15 @@ rs6000_call_template_1 (rtx *operands ATTRIBUTE_UNUSED, unsigned int funop,
 }
 
 const char *
-rs6000_call_template (rtx *operands, unsigned int funop, const char *arg)
+rs6000_call_template (rtx *operands, unsigned int funop)
 {
-  return rs6000_call_template_1 (operands, funop, false, arg);
+  return rs6000_call_template_1 (operands, funop, false);
 }
 
 const char *
-rs6000_sibcall_template (rtx *operands, unsigned int funop, const char *arg)
+rs6000_sibcall_template (rtx *operands, unsigned int funop)
 {
-  return rs6000_call_template_1 (operands, funop, true, arg);
+  return rs6000_call_template_1 (operands, funop, true);
 }
 
 /* As above, for indirect calls.  */
@@ -32503,23 +32539,20 @@ rs6000_set_default_type_attributes (tree type)
 /* Return a reference suitable for calling a function with the
    longcall attribute.  */
 
-rtx
+static rtx
 rs6000_longcall_ref (rtx call_ref)
 {
-  const char *call_name;
-  tree node;
-
   if (GET_CODE (call_ref) != SYMBOL_REF)
     return call_ref;
 
   /* System V adds '.' to the internal name, so skip them.  */
-  call_name = XSTR (call_ref, 0);
+  const char *call_name = XSTR (call_ref, 0);
   if (*call_name == '.')
     {
       while (*call_name == '.')
 	call_name++;
 
-      node = get_identifier (call_name);
+      tree node = get_identifier (call_name);
       call_ref = gen_rtx_SYMBOL_REF (VOIDmode, IDENTIFIER_POINTER (node));
     }
 
@@ -37491,7 +37524,7 @@ chain_already_loaded (rtx_insn *last)
 /* Expand code to perform a call under the AIX or ELFv2 ABI.  */
 
 void
-rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
+rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 {
   const bool direct_call_p
     = GET_CODE (func_desc) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (func_desc);
@@ -37504,6 +37537,9 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
   int n_call;
   rtx insn;
 
+  if (global_tlsarg)
+    tlsarg = global_tlsarg;
+
   /* Handle longcall attributes.  */
   if (INTVAL (cookie) & CALL_LONG)
     func_desc = rs6000_longcall_ref (func_desc);
@@ -37514,11 +37550,7 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
     {
       /* Save the TOC into its reserved slot before the call,
 	 and prepare to restore it after the call.  */
-      rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
       rtx stack_toc_offset = GEN_INT (RS6000_TOC_SAVE_SLOT);
-      rtx stack_toc_mem = gen_frame_mem (Pmode,
-					 gen_rtx_PLUS (Pmode, stack_ptr,
-						       stack_toc_offset));
       rtx stack_toc_unspec = gen_rtx_UNSPEC (Pmode,
 					     gen_rtvec (1, stack_toc_offset),
 					     UNSPEC_TOCSLOT);
@@ -37530,6 +37562,10 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
 	cfun->machine->save_toc_in_prologue = true;
       else
 	{
+	  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;
 	  emit_move_insn (stack_toc_mem, toc_reg);
 	}
@@ -37539,7 +37575,8 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
 	  /* A function pointer in the ELFv2 ABI is just a plain address, but
 	     the ABI requires it to be loaded into r12 before the call.  */
 	  func_addr = gen_rtx_REG (Pmode, 12);
-	  emit_move_insn (func_addr, func_desc);
+	  if (!rtx_equal_p (func_addr, func_desc))
+	    emit_move_insn (func_addr, func_desc);
 	  abi_reg = func_addr;
 	}
       else
@@ -37594,7 +37631,7 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
     }
 
   /* Create the call.  */
-  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), flag);
+  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), tlsarg);
   if (value != NULL_RTX)
     call[0] = gen_rtx_SET (value, call[0]);
   n_call = 1;
@@ -37618,15 +37655,18 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
 /* Expand code to perform a sibling call under the AIX or ELFv2 ABI.  */
 
 void
-rs6000_sibcall_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
+rs6000_sibcall_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 {
   rtx call[2];
   rtx insn;
 
   gcc_assert (INTVAL (cookie) == 0);
 
+  if (global_tlsarg)
+    tlsarg = global_tlsarg;
+
   /* Create the call.  */
-  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_desc), flag);
+  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_desc), tlsarg);
   if (value != NULL_RTX)
     call[0] = gen_rtx_SET (value, call[0]);
 
@@ -37639,6 +37679,42 @@ rs6000_sibcall_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
   use_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (Pmode, TOC_REGNUM));
 }
 
+/* Expand code to perform a call under the SYSV4 ABI.  */
+
+void
+rs6000_call_sysv (rtx value, rtx func, rtx tlsarg, rtx cookie)
+{
+  rtx func_addr;
+  rtx call[3];
+  rtx insn;
+
+  if (global_tlsarg)
+    tlsarg = global_tlsarg;
+
+  /* Handle longcall attributes.  */
+  if (INTVAL (cookie) & CALL_LONG)
+    func = rs6000_longcall_ref (func);
+
+  /* Handle indirect calls.  */
+  if (GET_CODE (func) != SYMBOL_REF)
+    func_addr = force_reg (Pmode, func);
+  else
+    func_addr = func;
+
+  /* Create the call.  */
+  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), tlsarg);
+  if (value != NULL_RTX)
+    call[0] = gen_rtx_SET (value, call[0]);
+
+  unsigned int mask = CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS;
+  call[1] = gen_rtx_USE (VOIDmode, GEN_INT (INTVAL (cookie) & mask));
+
+  call[2] = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
+
+  insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
+  insn = emit_call_insn (insn);
+}
+
 /* Return whether we need to always update the saved TOC pointer when we update
    the stack pointer.  */
 
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index c261c8bb9c1..336d42335cb 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -9436,74 +9436,73 @@ (define_peephole2
 \f
 ;; TLS support.
 
-(define_insn_and_split "tls_gd_aix<P:bits>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
-	      (match_operand 4)))
-   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
-	      (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
-	     UNSPEC_TLSGD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
+(define_insn "*tls_gdld_aix<P:bits>"
+  [(match_parallel 3 ""
+    [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+	  (call (mem:SI (match_operand:P 1))
+		(match_operand:P 2 "unspec_tls")))
+     (match_dup 2)])]
+  "HAVE_AS_TLS && !TARGET_TLS_MARKERS
+   && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
 {
-  if (TARGET_CMODEL != CMODEL_SMALL)
-    output_asm_insn ("addis %0,%1,%2@got@tlsgd@ha\;"
-		     "addi %0,%0,%2@got@tlsgd@l", operands);
+  rtx op[3];
+  op[0] = operands[0];
+  op[1] = XVECEXP (operands[2], 0, 0);
+  if (XINT (operands[2], 1) == UNSPEC_TLSGD)
+    {
+      op[2] = XVECEXP (operands[2], 0, 1);
+      if (TARGET_CMODEL != CMODEL_SMALL)
+	output_asm_insn ("addis %0,%2,%1@got@tlsgd@ha\;"
+			 "addi %0,%0,%1@got@tlsgd@l", op);
+      else
+	output_asm_insn ("addi %0,%2,%1@got@tlsgd", op);
+    }
   else
-    output_asm_insn ("addi %0,%1,%2@got@tlsgd", operands);
-  return rs6000_call_template (operands, 3, "");
+    {
+      if (TARGET_CMODEL != CMODEL_SMALL)
+	output_asm_insn ("addis %0,%1,%&@got@tlsld@ha\;"
+			 "addi %0,%0,%&@got@tlsld@l", op);
+      else
+	output_asm_insn ("addi %0,%1,%&@got@tlsld", op);
+    }
+  return rs6000_call_template (operands, 1);
 }
-  "&& TARGET_TLS_MARKERS"
-  [(set (match_dup 0)
-	(unspec:P [(match_dup 1)
-		   (match_dup 2)]
-		  UNSPEC_TLSGD))
-   (parallel [(set (match_dup 0)
-		   (call (mem:SI (match_dup 3))
-			 (match_dup 4)))
-	      (unspec:P [(match_dup 2)] UNSPEC_TLSGD)
-	      (clobber (reg:SI LR_REGNO))])]
-  ""
   [(set_attr "type" "two")
    (set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
 		   (const_int 16)
 		   (const_int 12)))])
 
-(define_insn_and_split "tls_gd_sysv<P:mode>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
-	      (match_operand 4)))
-   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
-	      (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
-	     UNSPEC_TLSGD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
+(define_insn "*tls_gdld_sysv<P:bits>"
+  [(match_parallel 3 ""
+    [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+	  (call (mem:SI (match_operand:P 1))
+		(match_operand:P 2 "unspec_tls")))
+     (match_dup 2)])]
+  "HAVE_AS_TLS && !TARGET_TLS_MARKERS && DEFAULT_ABI == ABI_V4"
 {
-  output_asm_insn ("addi %0,%1,%2@got@tlsgd", operands);
-  return rs6000_call_template (operands, 3, "");
+  rtx op[3];
+  op[0] = operands[0];
+  op[1] = XVECEXP (operands[2], 0, 0);
+  if (XINT (operands[2], 1) == UNSPEC_TLSGD)
+    {
+      op[2] = XVECEXP (operands[2], 0, 1);
+      output_asm_insn ("addi %0,%2,%1@got@tlsgd", op);
+    }
+  else
+    output_asm_insn ("addi %0,%1,%&@got@tlsld", op);
+  return rs6000_call_template (operands, 1);
 }
-  "&& TARGET_TLS_MARKERS"
-  [(set (match_dup 0)
-	(unspec:P [(match_dup 1)
-		   (match_dup 2)]
-		  UNSPEC_TLSGD))
-   (parallel [(set (match_dup 0)
-		   (call (mem:SI (match_dup 3))
-			 (match_dup 4)))
-	      (unspec:P [(match_dup 2)] UNSPEC_TLSGD)
-	      (clobber (reg:SI LR_REGNO))])]
-  ""
   [(set_attr "type" "two")
    (set_attr "length" "8")])
 
 (define_insn_and_split "*tls_gd<P:bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
-		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+	(unspec:P [(match_operand:P 1 "rs6000_tls_symbol_ref" "")
+		   (match_operand:P 2 "gpc_reg_operand" "b")]
 		  UNSPEC_TLSGD))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS"
-  "addi %0,%1,%2@got@tlsgd"
+  "addi %0,%2,%1@got@tlsgd"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 3)
 	(high:P
@@ -9512,7 +9511,7 @@ (define_insn_and_split "*tls_gd<P:bits>"
 	(lo_sum:P (match_dup 3)
 	    (unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGD)))]
 {
-  operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
+  operands[3] = gen_reg_rtx (<MODE>mode);
 }
   [(set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
@@ -9522,105 +9521,21 @@ (define_insn_and_split "*tls_gd<P:bits>"
 (define_insn "*tls_gd_high<P:bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
      (high:P
-       (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
-		  (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+       (unspec:P [(match_operand:P 1 "rs6000_tls_symbol_ref" "")
+		  (match_operand:P 2 "gpc_reg_operand" "b")]
 		 UNSPEC_TLSGD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
-  "addis %0,%1,%2@got@tlsgd@ha")
+  "addis %0,%2,%1@got@tlsgd@ha")
 
 (define_insn "*tls_gd_low<P:bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
      (lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
-       (unspec:P [(match_operand:P 3 "gpc_reg_operand" "b")
-		  (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+       (unspec:P [(match_operand:P 2 "rs6000_tls_symbol_ref" "")
+		  (match_operand:P 3 "gpc_reg_operand" "b")]
 		 UNSPEC_TLSGD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addi %0,%1,%2@got@tlsgd@l")
 
-(define_insn "*tls_gd_call_aix<P:bits>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2)))
-   (unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
-	     UNSPEC_TLSGD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && TARGET_TLS_MARKERS
-   && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
-{
-  return rs6000_call_template (operands, 1, "(%3@tlsgd)");
-}
-  [(set_attr "type" "branch")
-   (set_attr "length" "8")])
-
-(define_insn "*tls_gd_call_sysv<P:bits>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2)))
-   (unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
-	     UNSPEC_TLSGD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
-{
-  return rs6000_call_template (operands, 1, "(%3@tlsgd)");
-}
-  [(set_attr "type" "branch")])
-
-(define_insn_and_split "tls_ld_aix<P:bits>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
-	      (match_operand 3)))
-   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
-	     UNSPEC_TLSLD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
-{
-  if (TARGET_CMODEL != CMODEL_SMALL)
-    output_asm_insn ("addis %0,%1,%&@got@tlsld@ha\;"
-		     "addi %0,%0,%&@got@tlsld@l", operands);
-  else
-    output_asm_insn ("addi %0,%1,%&@got@tlsld", operands);
-  return rs6000_call_template (operands, 2, "");
-}
-  "&& TARGET_TLS_MARKERS"
-  [(set (match_dup 0)
-	(unspec:P [(match_dup 1)]
-		  UNSPEC_TLSLD))
-   (parallel [(set (match_dup 0)
-		   (call (mem:SI (match_dup 2))
-			 (match_dup 3)))
-	      (unspec:P [(const_int 0)] UNSPEC_TLSLD)
-	      (clobber (reg:SI LR_REGNO))])]
-  ""
-  [(set_attr "type" "two")
-   (set (attr "length")
-     (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-		   (const_int 16)
-		   (const_int 12)))])
-
-(define_insn_and_split "tls_ld_sysv<P:mode>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
-	      (match_operand 3)))
-   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
-	     UNSPEC_TLSLD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
-{
-  output_asm_insn ("addi %0,%1,%&@got@tlsld", operands);
-  return rs6000_call_template (operands, 2, "");
-}
-  "&& TARGET_TLS_MARKERS"
-  [(set (match_dup 0)
-	(unspec:P [(match_dup 1)]
-		  UNSPEC_TLSLD))
-   (parallel [(set (match_dup 0)
-		   (call (mem:SI (match_dup 2))
-			 (match_dup 3)))
-	      (unspec:P [(const_int 0)] UNSPEC_TLSLD)
-	      (clobber (reg:SI LR_REGNO))])]
-  ""
-  [(set_attr "length" "8")])
-
 (define_insn_and_split "*tls_ld<P:bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
 	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
@@ -9630,12 +9545,12 @@ (define_insn_and_split "*tls_ld<P:bits>"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 2)
 	(high:P
-	    (unspec:P [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))
+	    (unspec:P [(match_dup 1)] UNSPEC_TLSLD)))
    (set (match_dup 0)
 	(lo_sum:P (match_dup 2)
-	    (unspec:P [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))]
+	    (unspec:P [(match_dup 1)] UNSPEC_TLSLD)))]
 {
-  operands[2] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
+  operands[2] = gen_reg_rtx (<MODE>mode);
 }
   [(set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
@@ -9645,8 +9560,7 @@ (define_insn_and_split "*tls_ld<P:bits>"
 (define_insn "*tls_ld_high<P:bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
      (high:P
-       (unspec:P [(const_int 0)
-		  (match_operand:P 1 "gpc_reg_operand" "b")]
+       (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
 		 UNSPEC_TLSLD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addis %0,%1,%&@got@tlsld@ha")
@@ -9654,38 +9568,11 @@ (define_insn "*tls_ld_high<P:bits>"
 (define_insn "*tls_ld_low<P:bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
      (lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
-       (unspec:P [(const_int 0)
-		  (match_operand:P 2 "gpc_reg_operand" "b")]
+       (unspec:P [(match_operand:P 2 "gpc_reg_operand" "b")]
 		 UNSPEC_TLSLD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addi %0,%1,%&@got@tlsld@l")
 
-(define_insn "*tls_ld_call_aix<P:bits>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2)))
-   (unspec:P [(const_int 0)] UNSPEC_TLSLD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && TARGET_TLS_MARKERS
-   && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
-{
-  return rs6000_call_template (operands, 1, "(%&@tlsld)");
-}
-  [(set_attr "type" "branch")
-   (set_attr "length" "8")])
-
-(define_insn "*tls_ld_call_sysv<P:bits>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2)))
-   (unspec:P [(const_int 0)] UNSPEC_TLSLD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
-{
-  return rs6000_call_template (operands, 1, "(%&@tlsld)");
-}
-  [(set_attr "type" "branch")])
-
 (define_insn "tls_dtprel_<P:bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=r")
 	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
@@ -10359,7 +10246,6 @@ (define_expand "call"
 #endif
 
   gcc_assert (GET_CODE (operands[0]) == MEM);
-  gcc_assert (GET_CODE (operands[1]) == CONST_INT);
 
   operands[0] = XEXP (operands[0], 0);
 
@@ -10369,23 +10255,14 @@ (define_expand "call"
       DONE;
     }
 
-  if (GET_CODE (operands[0]) != SYMBOL_REF
-      || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[2]) & CALL_LONG) != 0))
+  if (DEFAULT_ABI == ABI_V4)
     {
-      if (INTVAL (operands[2]) & CALL_LONG)
-	operands[0] = rs6000_longcall_ref (operands[0]);
-
-      switch (DEFAULT_ABI)
-        {
-	case ABI_V4:
-	case ABI_DARWIN:
-	  operands[0] = force_reg (Pmode, operands[0]);
-	  break;
-
-	default:
-	  gcc_unreachable ();
-	}
+      rs6000_call_sysv (NULL_RTX, operands[0], operands[1], operands[2]);
+      DONE;
     }
+
+  if (GET_CODE (operands[0]) != SYMBOL_REF)
+    operands[0] = force_reg (Pmode, operands[0]);
 })
 
 (define_expand "call_value"
@@ -10402,7 +10279,6 @@ (define_expand "call_value"
 #endif
 
   gcc_assert (GET_CODE (operands[1]) == MEM);
-  gcc_assert (GET_CODE (operands[2]) == CONST_INT);
 
   operands[1] = XEXP (operands[1], 0);
 
@@ -10412,23 +10288,14 @@ (define_expand "call_value"
       DONE;
     }
 
-  if (GET_CODE (operands[1]) != SYMBOL_REF
-      || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[3]) & CALL_LONG) != 0))
+  if (DEFAULT_ABI == ABI_V4)
     {
-      if (INTVAL (operands[3]) & CALL_LONG)
-	operands[1] = rs6000_longcall_ref (operands[1]);
-
-      switch (DEFAULT_ABI)
-        {
-	case ABI_V4:
-	case ABI_DARWIN:
-	  operands[1] = force_reg (Pmode, operands[1]);
-	  break;
-
-	default:
-	  gcc_unreachable ();
-	}
+      rs6000_call_sysv (operands[0], operands[1], operands[2], operands[3]);
+      DONE;
     }
+
+  if (GET_CODE (operands[1]) != SYMBOL_REF)
+    operands[1] = force_reg (Pmode, operands[1]);
 })
 
 ;; Call to function in current module.  No TOC pointer reload needed.
@@ -10515,7 +10382,7 @@ (define_insn "*call_value_local64"
 
 ;; A function pointer under System V is just a normal pointer
 ;; operands[0] is the function pointer
-;; operands[1] is the stack size to clean up
+;; operands[1] is the tls call arg
 ;; operands[2] is the value FUNCTION_ARG returns for the VOID argument
 ;; which indicates how to set cr1
 
@@ -10566,7 +10433,7 @@ (define_insn_and_split "*call_nonlocal_sysv<mode>"
 #if TARGET_MACHO
   return macho_call_template (insn, operands, 0, 2);
 #else
-  return rs6000_call_template (operands, 0, "");
+  return rs6000_call_template (operands, 0);
 #endif
 }
   "DEFAULT_ABI == ABI_V4
@@ -10599,7 +10466,7 @@ (define_insn "*call_nonlocal_sysv_secure<mode>"
   else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  return rs6000_call_template (operands, 0, "");
+  return rs6000_call_template (operands, 0);
 }
   [(set_attr "type" "branch,branch")
    (set_attr "length" "4,8")])
@@ -10653,7 +10520,7 @@ (define_insn_and_split "*call_value_nonlocal_sysv<mode>"
 #if TARGET_MACHO
   return macho_call_template (insn, operands, 1, 3);
 #else
-  return rs6000_call_template (operands, 1, "");
+  return rs6000_call_template (operands, 1);
 #endif
 }
   "DEFAULT_ABI == ABI_V4
@@ -10688,7 +10555,7 @@ (define_insn "*call_value_nonlocal_sysv_secure<mode>"
   else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  return rs6000_call_template (operands, 1, "");
+  return rs6000_call_template (operands, 1);
 }
   [(set_attr "type" "branch,branch")
    (set_attr "length" "4,8")])
@@ -10722,7 +10589,7 @@ (define_insn "*call_nonlocal_aix<mode>"
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
-  return rs6000_call_template (operands, 0, "");
+  return rs6000_call_template (operands, 0);
 }
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
@@ -10734,7 +10601,7 @@ (define_insn "*call_value_nonlocal_aix<mode>"
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
-  return rs6000_call_template (operands, 1, "");
+  return rs6000_call_template (operands, 1);
 }
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
@@ -10985,7 +10852,7 @@ (define_insn "*sibcall_nonlocal_sysv<mode>"
   if (which_alternative >= 2)
     return rs6000_indirect_sibcall_template (operands, 0);
   else
-    return rs6000_sibcall_template (operands, 0, "");
+    return rs6000_sibcall_template (operands, 0);
 }
   [(set_attr "type" "branch")
    (set_attr_alternative "length"
@@ -11025,7 +10892,7 @@ (define_insn "*sibcall_value_nonlocal_sysv<mode>"
 	return "crset 2\;beq%T1-\;b $";
     }
   else
-    return rs6000_sibcall_template (operands, 1, "");
+    return rs6000_sibcall_template (operands, 1);
 }
   [(set_attr "type" "branch")
    (set_attr_alternative "length"
@@ -11049,7 +10916,7 @@ (define_insn "*sibcall_aix<mode>"
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
   if (which_alternative == 0)
-    return rs6000_sibcall_template (operands, 0, "");
+    return rs6000_sibcall_template (operands, 0);
   else
     return "b%T0";
 }
@@ -11063,7 +10930,7 @@ (define_insn "*sibcall_value_aix<mode>"
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
   if (which_alternative == 0)
-    return rs6000_sibcall_template (operands, 1, "");
+    return rs6000_sibcall_template (operands, 1);
   else
     return "b%T1";
 }

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 6/6] [RS6000] inline plt call sequences
  2018-11-13 11:14       ` Segher Boessenkool
                           ` (4 preceding siblings ...)
  2018-11-13 12:52         ` [PATCH 5/6] [RS6000] Use standard call patterns for __tls_get_addr calls Alan Modra
@ 2018-11-13 12:53         ` Alan Modra
  2018-11-27 17:18           ` Segher Boessenkool
  5 siblings, 1 reply; 34+ messages in thread
From: Alan Modra @ 2018-11-13 12:53 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: gcc-patches

Version 2.

Finally, the point of the previous patches in this series, support for
inline PLT calls, keyed off -fno-plt.  This emits code using new
relocations that tie all insns in the sequence together, so that the
linker can edit the sequence back to a direct call should the call
target turn out to be local.  An example of ELFv2 code to call puts is
as follows:

     .reloc .,R_PPC64_PLTSEQ,puts
        std 2,24(1)
     .reloc .,R_PPC64_PLT16_HA,puts
        addis 12,2,0
     .reloc .,R_PPC64_PLT16_LO_DS,puts
        ld 12,0(12)
     .reloc .,R_PPC64_PLTSEQ,puts
        mtctr 12
     .reloc .,R_PPC64_PLTCALL,puts
        bctrl
        ld 2,24(1)

"addis 12,2,puts@plt@ha" and "ld 12,puts@plt@l(12)" are also supported
by the assembler.  gcc instead uses the explicit R_PPC64_PLT16_HA and
R_PPC64_PLT16_LO_DS relocs because when the call is to __tls_get_addr
an extra reloc is emitted at every place where one is shown above, to
specify the __tls_get_addr arg.  The linker expects the extra reloc to
come first.  .reloc enforces that ordering.

The patch also changes code emitted for longcalls if the assembler
supports the new marker relocs, so that these too can be edited.  One
side effect of longcalls using PLT16 relocs is that they can now be
resolved lazily by ld.so.

I don't support lazy inline PLT calls for ELFv1, because ELFv1 would
need barriers to reliably load both the function address and toc
pointer from the PLT.  ELFv1 -fno-plt uses the longcall sequence
instead, which isn't edited by GNU ld.

	* config.in (HAVE_AS_PLTSEQ): Add.
	* config/rs6000/predicates.md (indirect_call_operand): New.
	* config/rs6000/rs6000-protos.h (rs6000_pltseq_template),
	(rs6000_sibcall_sysv): Declare.
	* config/rs6000/rs6000.c (init_cumulative_args): Set cookie
	CALL_LONG for -fno-plt.
	(print_operand <T, z, 0>): Handle UNSPEC_PLTSEQ.
	(rs6000_indirect_call_template_1): Emit .reloc directives for
	UNSPEC_PLTSEQ calls.
	(rs6000_pltseq_template): New function.
	(rs6000_longcall_ref): Add arg parameter.  Use PLT16 insns if
	relocs supported by assembler.  Move SYMBOL_REF test to callers.
	(rs6000_call_aix): Adjust rs6000_longcall_ref call.  Package
	insns in UNSPEC_PLTSEQ, preserving original func_desc.
	(rs6000_call_sysv): Likewise.
	(rs6000_sibcall_sysv): New function.
	* config/rs6000/rs6000.h (HAVE_AS_PLTSEQ): Provide default.
	* config/rs6000/rs6000.md (UNSPEC_PLTSEQ, UNSPEC_PLT16_HA,
	UNSPEC_PLT16_LO): New.
	(pltseq_tocsave, pltseq_plt16_ha, pltseq_plt16_lo, pltseq_mtctr): New.
	(call_indirect_nonlocal_sysv): Don't differentiate zero from non-zero
	cookie in constraints.  Test explicitly for flags in length attr.
	Handle unspec operand 1.
	(call_value_indirect_nonlocal_sysv): Likewise.
	(call_indirect_aix, call_value_indirect_aix): Handle unspec operand 1.
	(call_indirect_elfv2, call_value_indirect_elfv2): Likewise.
	(sibcall, sibcall_value): Use rs6000_sibcall_sysv.
	(sibcall_indirect_nonlocal_sysv): New pattern.
	(sibcall_value_indirect_nonlocal_sysv): Likewise.
	(sibcall_nonlocal_sysv, sibcall_value_nonlocal_sysv): Remove indirect
	call alternatives.
	* configure.ac: Check for gas plt sequence marker support.
	* configure: Regenerate.

diff --git a/gcc/config.in b/gcc/config.in
index 67a1e6cfc4c..86ff5e8636b 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -577,6 +577,12 @@
 #endif
 
 
+/* Define if your assembler supports R_PPC*_PLTSEQ relocations. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_PLTSEQ
+#endif
+
+
 /* Define if your assembler supports .ref */
 #ifndef USED_FOR_TARGET
 #undef HAVE_AS_REF
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index 7e45d2f0371..1af01935b5e 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -1055,6 +1055,24 @@ (define_predicate "call_operand"
 		  || REGNO (op) >= FIRST_PSEUDO_REGISTER")
      (match_code "symbol_ref")))
 
+;; Return 1 if the operand, used inside a MEM, is a valid first argument
+;; to an indirect CALL.  This is LR, CTR, or a PLTSEQ unspec using CTR.
+(define_predicate "indirect_call_operand"
+  (match_code "reg,unspec")
+{
+  if (REG_P (op))
+    return (REGNO (op) == LR_REGNO
+	    || REGNO (op) == CTR_REGNO);
+  if (GET_CODE (op) == UNSPEC)
+    {
+      if (XINT (op, 1) != UNSPEC_PLTSEQ)
+	return false;
+      op = XVECEXP (op, 0, 0);
+      return REG_P (op) && REGNO (op) == CTR_REGNO;
+    }
+  return false;
+})
+
 ;; Return 1 if the operand is a SYMBOL_REF for a function known to be in
 ;; this file.
 (define_predicate "current_file_function_operand"
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 3fd89dc20db..35209d4525d 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -115,6 +115,7 @@ extern const char *rs6000_call_template (rtx *, unsigned int);
 extern const char *rs6000_sibcall_template (rtx *, unsigned int);
 extern const char *rs6000_indirect_call_template (rtx *, unsigned int);
 extern const char *rs6000_indirect_sibcall_template (rtx *, unsigned int);
+extern const char *rs6000_pltseq_template (rtx *, int);
 extern enum rtx_code rs6000_reverse_condition (machine_mode,
 					       enum rtx_code);
 extern rtx rs6000_emit_eqne (machine_mode, rtx, rtx, rtx);
@@ -204,6 +205,7 @@ extern void rs6000_emit_eh_reg_restore (rtx, rtx);
 extern void rs6000_call_aix (rtx, rtx, rtx, rtx);
 extern void rs6000_sibcall_aix (rtx, rtx, rtx, rtx);
 extern void rs6000_call_sysv (rtx, rtx, rtx, rtx);
+extern void rs6000_sibcall_sysv (rtx, rtx, rtx, rtx);
 extern void rs6000_aix_asm_output_dwarf_table_ref (char *);
 extern void get_ppc476_thunk_name (char name[32]);
 extern bool rs6000_overloaded_builtin_p (enum rs6000_builtins);
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 5fd6e17bdda..c4008a87ed7 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -10706,7 +10706,7 @@ void
 init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
 		      rtx libname ATTRIBUTE_UNUSED, int incoming,
 		      int libcall, int n_named_args,
-		      tree fndecl ATTRIBUTE_UNUSED,
+		      tree fndecl,
 		      machine_mode return_mode ATTRIBUTE_UNUSED)
 {
   static CUMULATIVE_ARGS zero_cumulative;
@@ -10727,10 +10727,20 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
     cum->nargs_prototype = n_named_args;
 
   /* Check for a longcall attribute.  */
-  if ((!fntype && rs6000_default_long_calls)
-      || (fntype
-	  && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
-	  && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))))
+  if (((!fntype && rs6000_default_long_calls)
+       || (fntype
+	   && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
+	   && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))))
+      || (DEFAULT_ABI != ABI_DARWIN
+	  && !(fndecl
+	       && !DECL_EXTERNAL (fndecl)
+	       && !DECL_WEAK (fndecl)
+	       && (*targetm.binds_local_p) (fndecl))
+	  && (flag_plt
+	      ? (fntype
+		 && lookup_attribute ("noplt", TYPE_ATTRIBUTES (fntype)))
+	      : !(fntype
+		  && lookup_attribute ("plt", TYPE_ATTRIBUTES (fntype))))))
     cum->call_cookie |= CALL_LONG;
 
   if (TARGET_DEBUG_ARG)
@@ -20955,6 +20965,8 @@ print_operand (FILE *file, rtx x, int code)
 
     case 'T':
       /* Print the symbolic name of a branch target register.  */
+      if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_PLTSEQ)
+	x = XVECEXP (x, 0, 0);
       if (GET_CODE (x) != REG || (REGNO (x) != LR_REGNO
 				  && REGNO (x) != CTR_REGNO))
 	output_operand_lossage ("invalid %%T value");
@@ -21098,6 +21110,8 @@ print_operand (FILE *file, rtx x, int code)
       return;
 
     case 'z':
+      if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_PLTSEQ)
+	x = XVECEXP (x, 0, 1);
       /* X is a SYMBOL_REF.  Write out the name preceded by a
 	 period and without any trailing data in brackets.  Used for function
 	 names.  If we are configured for System V (or the embedded ABI) on
@@ -21213,6 +21227,8 @@ print_operand (FILE *file, rtx x, int code)
 	output_addr_const (file, CONST_CAST_RTX (tocrel_base_oac));
       else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSGD)
 	output_addr_const (file, XVECEXP (x, 0, 0));
+      else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_PLTSEQ)
+	output_addr_const (file, XVECEXP (x, 0, 1));
       else
 	output_addr_const (file, x);
       return;
@@ -21462,9 +21478,15 @@ rs6000_indirect_call_template_1 (rtx *operands, unsigned int funop,
       might produce 10 digits.  */
   gcc_assert (funop <= MAX_RECOG_OPERANDS);
 
-  static char str[144];
+  static char str[144];  /* 1 spare */
+  char *s = str;
   const char *ptrload = TARGET_64BIT ? "d" : "wz";
 
+  if (DEFAULT_ABI == ABI_AIX)
+    s += sprintf (s,
+		  "l%s 2,%%%u\n\t",
+		  ptrload, funop + 2);
+
   /* We don't need the extra code to stop indirect call speculation if
      calling via LR.  */
   bool speculate = (TARGET_MACHO
@@ -21472,32 +21494,61 @@ rs6000_indirect_call_template_1 (rtx *operands, unsigned int funop,
 		    || (REG_P (operands[funop])
 			&& REGNO (operands[funop]) == LR_REGNO));
 
+  if (!TARGET_MACHO && HAVE_AS_PLTSEQ && GET_CODE (operands[funop]) == UNSPEC)
+    {
+      const char *rel64 = TARGET_64BIT ? "64" : "";
+      char tls[29];
+      tls[0] = 0;
+      if (GET_CODE (operands[funop + 1]) == UNSPEC)
+	{
+	  if (XINT (operands[funop + 1], 1) == UNSPEC_TLSGD)
+	    sprintf (tls, ".reloc .,R_PPC%s_TLSGD,%%%u\n\t",
+		     rel64, funop + 1);
+	  else if (XINT (operands[funop + 1], 1) == UNSPEC_TLSLD)
+	    sprintf (tls, ".reloc .,R_PPC%s_TLSLD,%%&\n\t",
+		     rel64);
+	  else
+	    gcc_unreachable ();
+	}
+
+      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 += sprintf (s, "crset 2\n\t");
+	}
+      s += sprintf (s,
+		    "%s.reloc .,R_PPC%s_PLTCALL,%%z%u%s\n\t",
+		    tls, rel64, funop, addend);
+    }
+  else if (!speculate)
+    s += sprintf (s, "crset 2\n\t");
+
   if (DEFAULT_ABI == ABI_AIX)
     {
       if (speculate)
-	sprintf (str,
-		 "l%s 2,%%%u\n\t"
+	sprintf (s,
 		 "b%%T%ul\n\t"
 		 "l%s 2,%%%u(1)",
-		 ptrload, funop + 2, funop, ptrload, funop + 3);
+		 funop, ptrload, funop + 3);
       else
-	sprintf (str,
-		 "crset 2\n\t"
-		 "l%s 2,%%%u\n\t"
+	sprintf (s,
 		 "beq%%T%ul-\n\t"
 		 "l%s 2,%%%u(1)",
-		 ptrload, funop + 2, funop, ptrload, funop + 3);
+		 funop, ptrload, funop + 3);
     }
   else if (DEFAULT_ABI == ABI_ELFv2)
     {
       if (speculate)
-	sprintf (str,
+	sprintf (s,
 		 "b%%T%ul\n\t"
 		 "l%s 2,%%%u(1)",
 		 funop, ptrload, funop + 2);
       else
-	sprintf (str,
-		 "crset 2\n\t"
+	sprintf (s,
 		 "beq%%T%ul-\n\t"
 		 "l%s 2,%%%u(1)",
 		 funop, ptrload, funop + 2);
@@ -21505,12 +21556,11 @@ rs6000_indirect_call_template_1 (rtx *operands, unsigned int funop,
   else
     {
       if (speculate)
-	sprintf (str,
+	sprintf (s,
 		 "b%%T%u%s",
 		 funop, sibcall ? "" : "l");
       else
-	sprintf (str,
-		 "crset 2\n\t"
+	sprintf (s,
 		 "beq%%T%u%s-%s",
 		 funop, sibcall ? "" : "l", sibcall ? "\n\tb $" : "");
     }
@@ -21529,6 +21579,72 @@ rs6000_indirect_sibcall_template (rtx *operands, unsigned int funop)
   return rs6000_indirect_call_template_1 (operands, funop, true);
 }
 
+#if HAVE_AS_PLTSEQ
+/* Output indirect call insns.
+   WHICH is 0 for tocsave, 1 for plt16_ha, 2 for plt16_lo, 3 for mtctr.  */
+const char *
+rs6000_pltseq_template (rtx *operands, int which)
+{
+  const char *rel64 = TARGET_64BIT ? "64" : "";
+  char tls[28];
+  tls[0] = 0;
+  if (GET_CODE (operands[3]) == UNSPEC)
+    {
+      if (XINT (operands[3], 1) == UNSPEC_TLSGD)
+	sprintf (tls, ".reloc .,R_PPC%s_TLSGD,%%3\n\t",
+		 rel64);
+      else if (XINT (operands[3], 1) == UNSPEC_TLSLD)
+	sprintf (tls, ".reloc .,R_PPC%s_TLSLD,%%&\n\t",
+		 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" : "";
+  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)");
+      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",
+		 tls, off, rel64);
+      else
+	sprintf (str,
+		 "%s.reloc .%s,R_PPC%s_PLT16_HA,%%z2%s\n\t"
+		 "addis %%0,%%1,0",
+		 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");
+      break;
+    case 3:
+      sprintf (str,
+	       "%s.reloc .,R_PPC%s_PLTSEQ,%%z2%s\n\t"
+	       "mtctr %%1",
+	       tls, rel64, addend);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  return str;
+}
+#endif
+
 #if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO
 /* Emit an assembler directive to set symbol visibility for DECL to
    VISIBILITY_TYPE.  */
@@ -32540,11 +32656,8 @@ rs6000_set_default_type_attributes (tree type)
    longcall attribute.  */
 
 static rtx
-rs6000_longcall_ref (rtx call_ref)
+rs6000_longcall_ref (rtx call_ref, rtx arg)
 {
-  if (GET_CODE (call_ref) != SYMBOL_REF)
-    return call_ref;
-
   /* System V adds '.' to the internal name, so skip them.  */
   const char *call_name = XSTR (call_ref, 0);
   if (*call_name == '.')
@@ -32556,6 +32669,36 @@ rs6000_longcall_ref (rtx call_ref)
       call_ref = gen_rtx_SYMBOL_REF (VOIDmode, IDENTIFIER_POINTER (node));
     }
 
+  if (HAVE_AS_PLTSEQ
+      && TARGET_TLS_MARKERS
+      && (DEFAULT_ABI == ABI_ELFv2 || DEFAULT_ABI == ABI_V4))
+    {
+      rtx base = const0_rtx;
+      int regno;
+      if (DEFAULT_ABI == ABI_ELFv2)
+	{
+	  base = gen_rtx_REG (Pmode, TOC_REGISTER);
+	  regno = 12;
+	}
+      else
+	{
+	  if (flag_pic)
+	    base = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
+	  regno = 11;
+	}
+      /* Reg must match that used by linker PLT stubs.  For ELFv2, r12
+	 may be used by a function global entry point.  For SysV4, r11
+	 is used by __glink_PLTresolve lazy resolver entry.  */
+      rtx reg = gen_rtx_REG (Pmode, regno);
+      rtx hi = gen_rtx_UNSPEC (Pmode, gen_rtvec (3, base, call_ref, arg),
+			       UNSPEC_PLT16_HA);
+      rtx lo = gen_rtx_UNSPEC (Pmode, gen_rtvec (3, reg, call_ref, arg),
+			       UNSPEC_PLT16_LO);
+      emit_insn (gen_rtx_SET (reg, hi));
+      emit_insn (gen_rtx_SET (reg, lo));
+      return reg;
+    }
+
   return force_reg (Pmode, call_ref);
 }
 \f
@@ -37526,8 +37669,7 @@ chain_already_loaded (rtx_insn *last)
 void
 rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 {
-  const bool direct_call_p
-    = GET_CODE (func_desc) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (func_desc);
+  rtx func = func_desc;
   rtx toc_reg = gen_rtx_REG (Pmode, TOC_REGNUM);
   rtx toc_load = NULL_RTX;
   rtx toc_restore = NULL_RTX;
@@ -37541,12 +37683,13 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
     tlsarg = global_tlsarg;
 
   /* Handle longcall attributes.  */
-  if (INTVAL (cookie) & CALL_LONG)
-    func_desc = rs6000_longcall_ref (func_desc);
+  if ((INTVAL (cookie) & CALL_LONG) != 0
+      && GET_CODE (func_desc) == SYMBOL_REF)
+    func = rs6000_longcall_ref (func_desc, tlsarg);
 
   /* Handle indirect calls.  */
-  if (GET_CODE (func_desc) != SYMBOL_REF
-      || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (func_desc)))
+  if (GET_CODE (func) != SYMBOL_REF
+      || (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.  */
@@ -37567,7 +37710,17 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 					     gen_rtx_PLUS (Pmode, stack_ptr,
 							   stack_toc_offset));
 	  MEM_VOLATILE_P (stack_toc_mem) = 1;
-	  emit_move_insn (stack_toc_mem, toc_reg);
+	  if (HAVE_AS_PLTSEQ
+	      && TARGET_TLS_MARKERS
+	      && 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);
 	}
 
       if (DEFAULT_ABI == ABI_ELFv2)
@@ -37575,9 +37728,25 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 	  /* A function pointer in the ELFv2 ABI is just a plain address, but
 	     the ABI requires it to be loaded into r12 before the call.  */
 	  func_addr = gen_rtx_REG (Pmode, 12);
-	  if (!rtx_equal_p (func_addr, func_desc))
-	    emit_move_insn (func_addr, func_desc);
+	  if (!rtx_equal_p (func_addr, func))
+	    emit_move_insn (func_addr, func);
 	  abi_reg = func_addr;
+	  /* Indirect calls via CTR are strongly preferred over indirect
+	     calls via LR, so move the address there.  Needed to mark
+	     this insn for linker plt sequence editing too.  */
+	  func_addr = gen_rtx_REG (Pmode, CTR_REGNO);
+	  if (HAVE_AS_PLTSEQ
+	      && TARGET_TLS_MARKERS
+	      && GET_CODE (func_desc) == SYMBOL_REF)
+	    {
+	      rtvec v = gen_rtvec (3, abi_reg, func_desc, tlsarg);
+	      rtx mark_func = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
+	      emit_insn (gen_rtx_SET (func_addr, mark_func));
+	      v = gen_rtvec (2, func_addr, func_desc);
+	      func_addr = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
+	    }
+	  else
+	    emit_move_insn (func_addr, abi_reg);
 	}
       else
 	{
@@ -37589,9 +37758,15 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 	     not have any executable code.  */
 
 	  /* Load up address of the actual function.  */
-	  func_desc = force_reg (Pmode, func_desc);
+	  func = force_reg (Pmode, func);
 	  func_addr = gen_reg_rtx (Pmode);
-	  emit_move_insn (func_addr, gen_rtx_MEM (Pmode, func_desc));
+	  emit_move_insn (func_addr, gen_rtx_MEM (Pmode, func));
+
+	  /* Indirect calls via CTR are strongly preferred over indirect
+	     calls via LR, so move the address there.  */
+	  rtx ctr_reg = gen_rtx_REG (Pmode, CTR_REGNO);
+	  emit_move_insn (ctr_reg, func_addr);
+	  func_addr = ctr_reg;
 
 	  /* Prepare to load the TOC of the called function.  Note that the
 	     TOC load must happen immediately before the actual call so
@@ -37599,7 +37774,7 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 	     comment in frob_update_context.  */
 	  rtx func_toc_offset = GEN_INT (GET_MODE_SIZE (Pmode));
 	  rtx func_toc_mem = gen_rtx_MEM (Pmode,
-					  gen_rtx_PLUS (Pmode, func_desc,
+					  gen_rtx_PLUS (Pmode, func,
 							func_toc_offset));
 	  toc_load = gen_rtx_USE (VOIDmode, func_toc_mem);
 
@@ -37607,14 +37782,15 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 	     originally direct, the 3rd word has not been written since no
 	     trampoline has been built, so we ought not to load it, lest we
 	     override a static chain value.  */
-	  if (!direct_call_p
+	  if (!(GET_CODE (func_desc) == SYMBOL_REF
+		&& SYMBOL_REF_FUNCTION_P (func_desc))
 	      && TARGET_POINTERS_TO_NESTED_FUNCTIONS
 	      && !chain_already_loaded (get_current_sequence ()->next->last))
 	    {
 	      rtx sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
 	      rtx func_sc_offset = GEN_INT (2 * GET_MODE_SIZE (Pmode));
 	      rtx func_sc_mem = gen_rtx_MEM (Pmode,
-					     gen_rtx_PLUS (Pmode, func_desc,
+					     gen_rtx_PLUS (Pmode, func,
 							   func_sc_offset));
 	      emit_move_insn (sc_reg, func_sc_mem);
 	      abi_reg = sc_reg;
@@ -37627,7 +37803,7 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 	 assume the TOC register is set; for non-local calls, the
 	 PLT stub needs the TOC register.  */
       abi_reg = toc_reg;
-      func_addr = func_desc;
+      func_addr = func;
     }
 
   /* Create the call.  */
@@ -37682,22 +37858,51 @@ rs6000_sibcall_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 /* Expand code to perform a call under the SYSV4 ABI.  */
 
 void
-rs6000_call_sysv (rtx value, rtx func, rtx tlsarg, rtx cookie)
+rs6000_call_sysv (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 {
+  rtx func = func_desc;
   rtx func_addr;
   rtx call[3];
   rtx insn;
+  rtx abi_reg = NULL_RTX;
 
   if (global_tlsarg)
     tlsarg = global_tlsarg;
 
   /* Handle longcall attributes.  */
-  if (INTVAL (cookie) & CALL_LONG)
-    func = rs6000_longcall_ref (func);
+  if ((INTVAL (cookie) & CALL_LONG) != 0
+      && GET_CODE (func_desc) == SYMBOL_REF)
+    {
+      func = rs6000_longcall_ref (func_desc, tlsarg);
+      /* If the longcall was implemented using PLT16 relocs, then r11
+	 needs to be valid at the call for lazy linking.  */
+      if (HAVE_AS_PLTSEQ
+	  && TARGET_TLS_MARKERS)
+	abi_reg = func;
+    }
 
   /* Handle indirect calls.  */
   if (GET_CODE (func) != SYMBOL_REF)
-    func_addr = force_reg (Pmode, func);
+    {
+      func = force_reg (Pmode, func);
+
+      /* Indirect calls via CTR are strongly preferred over indirect
+	 calls via LR, so move the address there.  Needed to mark
+	 this insn for linker plt sequence editing too.  */
+      func_addr = gen_rtx_REG (Pmode, CTR_REGNO);
+      if (HAVE_AS_PLTSEQ
+	  && TARGET_TLS_MARKERS
+	  && GET_CODE (func_desc) == SYMBOL_REF)
+	{
+	  rtvec v = gen_rtvec (3, func, func_desc, tlsarg);
+	  rtx mark_func = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
+	  emit_insn (gen_rtx_SET (func_addr, mark_func));
+	  v = gen_rtvec (2, func_addr, func_desc);
+	  func_addr = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
+	}
+      else
+	emit_move_insn (func_addr, func);
+    }
   else
     func_addr = func;
 
@@ -37713,6 +37918,73 @@ rs6000_call_sysv (rtx value, rtx func, rtx tlsarg, rtx cookie)
 
   insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
   insn = emit_call_insn (insn);
+  if (abi_reg)
+    use_reg (&CALL_INSN_FUNCTION_USAGE (insn), abi_reg);
+}
+
+/* Expand code to perform a sibling call under the SysV4 ABI.  */
+
+void
+rs6000_sibcall_sysv (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
+{
+  rtx func = func_desc;
+  rtx func_addr;
+  rtx call[3];
+  rtx insn;
+  rtx abi_reg = NULL_RTX;
+
+  if (global_tlsarg)
+    tlsarg = global_tlsarg;
+
+  /* Handle longcall attributes.  */
+  if ((INTVAL (cookie) & CALL_LONG) != 0
+      && GET_CODE (func_desc) == SYMBOL_REF)
+    {
+      func = rs6000_longcall_ref (func_desc, tlsarg);
+      /* If the longcall was implemented using PLT16 relocs, then r11
+	 needs to be valid at the call for lazy linking.  */
+      if (HAVE_AS_PLTSEQ
+	  && TARGET_TLS_MARKERS)
+	abi_reg = func;
+    }
+
+  /* Handle indirect calls.  */
+  if (GET_CODE (func) != SYMBOL_REF)
+    {
+      func = force_reg (Pmode, func);
+
+      /* Indirect sibcalls must go via CTR.  Needed to mark
+	 this insn for linker plt sequence editing too.  */
+      func_addr = gen_rtx_REG (Pmode, CTR_REGNO);
+      if (HAVE_AS_PLTSEQ
+	  && TARGET_TLS_MARKERS
+	  && GET_CODE (func_desc) == SYMBOL_REF)
+	{
+	  rtvec v = gen_rtvec (3, func, func_desc, tlsarg);
+	  rtx mark_func = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
+	  emit_insn (gen_rtx_SET (func_addr, mark_func));
+	  v = gen_rtvec (2, func_addr, func_desc);
+	  func_addr = gen_rtx_UNSPEC (Pmode, v, UNSPEC_PLTSEQ);
+	}
+      else
+	emit_move_insn (func_addr, func);
+    }
+  else
+    func_addr = func;
+
+  /* Create the call.  */
+  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), tlsarg);
+  if (value != NULL_RTX)
+    call[0] = gen_rtx_SET (value, call[0]);
+
+  unsigned int mask = CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS;
+  call[1] = gen_rtx_USE (VOIDmode, GEN_INT (INTVAL (cookie) & mask));
+  call[2] = simple_return_rtx;
+
+  insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
+  insn = emit_call_insn (insn);
+  if (abi_reg)
+    use_reg (&CALL_INSN_FUNCTION_USAGE (insn), abi_reg);
 }
 
 /* Return whether we need to always update the saved TOC pointer when we update
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index f59c0b6b685..c7934c601ed 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -224,6 +224,10 @@ extern const char *host_detect_local_cpu (int argc, const char **argv);
 #define HAVE_AS_TLS 0
 #endif
 
+#ifndef HAVE_AS_PLTSEQ
+#define HAVE_AS_PLTSEQ 0
+#endif
+
 #ifndef TARGET_LINK_STACK
 #define TARGET_LINK_STACK 0
 #endif
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 336d42335cb..02f194c7d33 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -147,6 +147,9 @@ (define_c_enum "unspec"
    UNSPEC_SIGNBIT
    UNSPEC_SF_FROM_SI
    UNSPEC_SI_FROM_SF
+   UNSPEC_PLTSEQ
+   UNSPEC_PLT16_HA
+   UNSPEC_PLT16_LO
   ])
 
 ;;
@@ -10231,6 +10234,55 @@ (define_insn "elf_low"
 		   (match_operand 2 "" "")))]
    "TARGET_ELF && !TARGET_64BIT && !flag_pic"
    "la %0,%2@l(%1)")
+
+(define_insn "*pltseq_tocsave_<mode>"
+  [(set (match_operand:P 0 "memory_operand" "=m")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "symbol_ref_operand" "s")
+		   (match_operand:P 3 "" "")]
+		  UNSPEC_PLTSEQ))]
+  "HAVE_AS_PLTSEQ && TARGET_TLS_MARKERS
+   && DEFAULT_ABI == ABI_ELFv2"
+{
+  return rs6000_pltseq_template (operands, 0);
+})
+
+(define_insn "*pltseq_plt16_ha_<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_PLT16_HA))]
+  "HAVE_AS_PLTSEQ && TARGET_TLS_MARKERS
+   && (DEFAULT_ABI == ABI_ELFv2 || DEFAULT_ABI == ABI_V4)"
+{
+  return rs6000_pltseq_template (operands, 1);
+})
+
+(define_insn "*pltseq_plt16_lo_<mode>"
+  [(set (match_operand:P 0 "gpc_reg_operand" "=r")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
+		   (match_operand:P 2 "symbol_ref_operand" "s")
+		   (match_operand:P 3 "" "")]
+		  UNSPEC_PLT16_LO))]
+  "HAVE_AS_PLTSEQ && TARGET_TLS_MARKERS
+   && (DEFAULT_ABI == ABI_ELFv2 || DEFAULT_ABI == ABI_V4)"
+{
+  return rs6000_pltseq_template (operands, 2);
+}
+  [(set_attr "type" "load")])
+
+(define_insn "*pltseq_mtctr_<mode>"
+  [(set (match_operand:P 0 "register_operand" "=c")
+	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "r")
+		   (match_operand:P 2 "symbol_ref_operand" "s")
+		   (match_operand:P 3 "" "")]
+		  UNSPEC_PLTSEQ))]
+  "HAVE_AS_PLTSEQ && TARGET_TLS_MARKERS
+   && (DEFAULT_ABI == ABI_ELFv2 || DEFAULT_ABI == ABI_V4)"
+{
+  return rs6000_pltseq_template (operands, 3);
+})
 \f
 ;; Call and call_value insns
 (define_expand "call"
@@ -10387,9 +10439,9 @@ (define_insn "*call_value_local64"
 ;; which indicates how to set cr1
 
 (define_insn "*call_indirect_nonlocal_sysv<mode>"
-  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l,c,*l"))
+  [(call (mem:SI (match_operand:P 0 "indirect_call_operand" "c,*l,X"))
 	 (match_operand 1))
-   (use (match_operand:SI 2 "immediate_operand" "O,O,n,n"))
+   (use (match_operand:SI 2 "immediate_operand" "n,n,n"))
    (clobber (reg:SI LR_REGNO))]
   "DEFAULT_ABI == ABI_V4
    || DEFAULT_ABI == ABI_DARWIN"
@@ -10402,18 +10454,17 @@ (define_insn "*call_indirect_nonlocal_sysv<mode>"
 
   return rs6000_indirect_call_template (operands, 0);
 }
-  [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
-   (set_attr_alternative "length"
-     [(if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "8")
-		    (const_string "4"))
-      (const_string "4")
-      (if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "12")
-		    (const_string "8"))
-      (const_string "8")])])
+  [(set_attr "type" "jmpreg")
+   (set (attr "length")
+	(cond [(and (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		    (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "12")
+	       (ior (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		    (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "8")]
+	      (const_string "4")))])
 
 (define_insn_and_split "*call_nonlocal_sysv<mode>"
   [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s"))
@@ -10473,9 +10524,9 @@ (define_insn "*call_nonlocal_sysv_secure<mode>"
 
 (define_insn "*call_value_indirect_nonlocal_sysv<mode>"
   [(set (match_operand 0 "" "")
-	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l,c,*l"))
+	(call (mem:SI (match_operand:P 1 "indirect_call_operand" "c,*l,X"))
 	      (match_operand 2)))
-   (use (match_operand:SI 3 "immediate_operand" "O,O,n,n"))
+   (use (match_operand:SI 3 "immediate_operand" "n,n,n"))
    (clobber (reg:SI LR_REGNO))]
   "DEFAULT_ABI == ABI_V4
    || DEFAULT_ABI == ABI_DARWIN"
@@ -10488,18 +10539,17 @@ (define_insn "*call_value_indirect_nonlocal_sysv<mode>"
 
   return rs6000_indirect_call_template (operands, 1);
 }
-  [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg")
-   (set_attr_alternative "length"
-     [(if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "8")
-		    (const_string "4"))
-      (const_string "4")
-      (if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "12")
-		    (const_string "8"))
-      (const_string "8")])])
+  [(set_attr "type" "jmpreg")
+   (set (attr "length")
+	(cond [(and (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		    (match_test "(INTVAL (operands[3]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "12")
+	       (ior (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		   (match_test "(INTVAL (operands[3]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "8")]
+	      (const_string "4")))])
 
 (define_insn_and_split "*call_value_nonlocal_sysv<mode>"
   [(set (match_operand 0 "" "")
@@ -10612,10 +10662,10 @@ (define_insn "*call_value_nonlocal_aix<mode>"
 ;; Operand3 is the offset of the stack location holding the current TOC pointer
 
 (define_insn "*call_indirect_aix<mode>"
-  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
+  [(call (mem:SI (match_operand:P 0 "indirect_call_operand" "c,*l,X"))
 	 (match_operand 1))
-   (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+   (use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>,<ptrm>"))
+   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX"
 {
@@ -10630,10 +10680,10 @@ (define_insn "*call_indirect_aix<mode>"
 
 (define_insn "*call_value_indirect_aix<mode>"
   [(set (match_operand 0 "" "")
-	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
+	(call (mem:SI (match_operand:P 1 "indirect_call_operand" "c,*l,X"))
 	      (match_operand 2)))
-   (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+   (use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>,<ptrm>"))
+   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX"
 {
@@ -10651,9 +10701,9 @@ (define_insn "*call_value_indirect_aix<mode>"
 ;; Operand2 is the offset of the stack location holding the current TOC pointer
 
 (define_insn "*call_indirect_elfv2<mode>"
-  [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
+  [(call (mem:SI (match_operand:P 0 "indirect_call_operand" "c,*l,X"))
 	 (match_operand 1))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_ELFv2"
 {
@@ -10668,9 +10718,9 @@ (define_insn "*call_indirect_elfv2<mode>"
 
 (define_insn "*call_value_indirect_elfv2<mode>"
   [(set (match_operand 0 "" "")
-	(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
+	(call (mem:SI (match_operand:P 1 "indirect_call_operand" "c,*l,X"))
 	      (match_operand 2)))
-   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+   (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n,n")] UNSPEC_TOCSLOT))
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_ELFv2"
 {
@@ -10733,6 +10783,12 @@ (define_expand "sibcall"
       rs6000_sibcall_aix (NULL_RTX, operands[0], operands[1], operands[2]);
       DONE;
     }
+
+  if (DEFAULT_ABI == ABI_V4)
+    {
+      rs6000_sibcall_sysv (NULL_RTX, operands[0], operands[1], operands[2]);
+      DONE;
+    }
 })
 
 (define_expand "sibcall_value"
@@ -10758,6 +10814,12 @@ (define_expand "sibcall_value"
       rs6000_sibcall_aix (operands[0], operands[1], operands[2], operands[3]);
       DONE;
     }
+
+  if (DEFAULT_ABI == ABI_V4)
+    {
+      rs6000_sibcall_sysv (operands[0], operands[1], operands[2], operands[3]);
+      DONE;
+    }
 })
 
 (define_insn "*sibcall_local32"
@@ -10834,10 +10896,38 @@ (define_insn "*sibcall_value_local64"
   [(set_attr "type" "branch")
    (set_attr "length" "4,8")])
 
+(define_insn "*sibcall_indirect_nonlocal_sysv<mode>"
+  [(call (mem:SI (match_operand:P 0 "indirect_call_operand" "c,*l,X"))
+	 (match_operand 1))
+   (use (match_operand:SI 2 "immediate_operand" "n,n,n"))
+   (simple_return)]
+  "DEFAULT_ABI == ABI_V4
+   || DEFAULT_ABI == ABI_DARWIN"
+{
+  if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+    output_asm_insn ("crxor 6,6,6", operands);
+
+  else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+    output_asm_insn ("creqv 6,6,6", operands);
+
+  return rs6000_indirect_sibcall_template (operands, 0);
+}
+  [(set_attr "type" "jmpreg")
+   (set (attr "length")
+	(cond [(and (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		    (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "12")
+	       (ior (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		   (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "8")]
+	      (const_string "4")))])
+
 (define_insn "*sibcall_nonlocal_sysv<mode>"
-  [(call (mem:SI (match_operand:P 0 "call_operand" "s,s,c,c"))
-	 (match_operand 1 "" ""))
-   (use (match_operand 2 "immediate_operand" "O,n,O,n"))
+  [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s"))
+	 (match_operand 1))
+   (use (match_operand 2 "immediate_operand" "O,n"))
    (simple_return)]
   "(DEFAULT_ABI == ABI_DARWIN
     || DEFAULT_ABI == ABI_V4)
@@ -10849,29 +10939,45 @@ (define_insn "*sibcall_nonlocal_sysv<mode>"
   else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  if (which_alternative >= 2)
-    return rs6000_indirect_sibcall_template (operands, 0);
-  else
-    return rs6000_sibcall_template (operands, 0);
+  return rs6000_sibcall_template (operands, 0);
 }
   [(set_attr "type" "branch")
-   (set_attr_alternative "length"
-     [(const_string "4")
-      (const_string "8")
-      (if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "12")
-		    (const_string "4"))
-      (if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "16")
-		    (const_string "8"))])])
+   (set_attr "length" "4,8")])
+
+(define_insn "*sibcall_value_indirect_nonlocal_sysv<mode>"
+  [(set (match_operand 0 "" "")
+	(call (mem:SI (match_operand:P 1 "indirect_call_operand" "c,*l,X"))
+	      (match_operand 2)))
+   (use (match_operand:SI 3 "immediate_operand" "n,n,n"))
+   (simple_return)]
+  "DEFAULT_ABI == ABI_V4
+   || DEFAULT_ABI == ABI_DARWIN"
+{
+  if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+    output_asm_insn ("crxor 6,6,6", operands);
+
+  else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+    output_asm_insn ("creqv 6,6,6", operands);
+
+  return rs6000_indirect_sibcall_template (operands, 1);
+}
+  [(set_attr "type" "jmpreg")
+   (set (attr "length")
+	(cond [(and (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		    (match_test "(INTVAL (operands[3]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "12")
+	       (ior (and (match_test "!rs6000_speculate_indirect_jumps")
+			 (match_test "which_alternative != 1"))
+		   (match_test "(INTVAL (operands[3]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
+		  (const_string "8")]
+	      (const_string "4")))])
 
 (define_insn "*sibcall_value_nonlocal_sysv<mode>"
   [(set (match_operand 0 "" "")
-	(call (mem:SI (match_operand:P 1 "call_operand" "s,s,c,c"))
-	      (match_operand 2 "" "")))
-   (use (match_operand:SI 3 "immediate_operand" "O,n,O,n"))
+	(call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s"))
+	      (match_operand 2)))
+   (use (match_operand:SI 3 "immediate_operand" "O,n"))
    (simple_return)]
   "(DEFAULT_ABI == ABI_DARWIN
     || DEFAULT_ABI == ABI_V4)
@@ -10883,29 +10989,10 @@ (define_insn "*sibcall_value_nonlocal_sysv<mode>"
   else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  if (which_alternative >= 2)
-    {
-      if (rs6000_speculate_indirect_jumps)
-	return "b%T1";
-      else
-	/* Can use CR0 since it is volatile across sibcalls.  */
-	return "crset 2\;beq%T1-\;b $";
-    }
-  else
-    return rs6000_sibcall_template (operands, 1);
+  return rs6000_sibcall_template (operands, 1);
 }
   [(set_attr "type" "branch")
-   (set_attr_alternative "length"
-     [(const_string "4")
-      (const_string "8")
-      (if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "12")
-		    (const_string "4"))
-      (if_then_else (eq (symbol_ref "rs6000_speculate_indirect_jumps")
-			(const_int 0))
-		    (const_string "16")
-		    (const_string "8"))])])
+   (set_attr "length" "4,8")])
 
 ;; AIX ABI sibling call patterns.
 
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 260d987dadd..c0043469aeb 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -4648,6 +4648,12 @@ LCF0:
       [AC_DEFINE(HAVE_AS_ENTRY_MARKERS, 1,
 	  [Define if your assembler supports the R_PPC64_ENTRY relocation.])])
 
+    gcc_GAS_CHECK_FEATURE([plt sequence marker support],
+      gcc_cv_as_powerpc_pltseq_markers, [2,31,0],-a32 --fatal-warnings,
+      [ .reloc .,R_PPC_PLTSEQ; nop],,
+      [AC_DEFINE(HAVE_AS_PLTSEQ, 1,
+	  [Define if your assembler supports R_PPC*_PLTSEQ relocations.])])
+
     case $target in
       *-*-aix*)
 	gcc_GAS_CHECK_FEATURE([AIX .ref support],

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/6] [RS6000] rs6000_call_template for external call insn assembly output
  2018-11-13 12:48         ` [PATCH 1/6] [RS6000] rs6000_call_template for external call insn assembly output Alan Modra
@ 2018-11-20 15:59           ` Segher Boessenkool
  0 siblings, 0 replies; 34+ messages in thread
From: Segher Boessenkool @ 2018-11-20 15:59 UTC (permalink / raw)
  To: Alan Modra; +Cc: gcc-patches

On Tue, Nov 13, 2018 at 11:17:55PM +1030, Alan Modra wrote:
> Version 2.
> 
> This is a first step in tidying rs6000 call patterns, in preparation
> to support inline plt calls.

Okay for trunk.  Thanks for the patch, and for the rework!


Segher


> 	* config/rs6000/rs6000-protos.h (rs6000_call_template): Declare.
> 	(rs6000_sibcall_template): Declare.
> 	(macho_call_template): Rename from output_call.
> 	* config/rs6000/rs6000.c (rs6000_call_template_1): New function.
> 	(rs6000_call_template, rs6000_sibcall_template): Likewise.
> 	(macho_call_template): Rename from output_call.
> 	* config/rs6000/rs6000.md (tls_gd_aix, tls_gd_sysv),
> 	(tls_gd_call_aix, tls_gd_call_sysv, tls_ld_aix, tls_ld_sysv),
> 	(tls_ld_call_aix, tls_ld_call_sysv, call_nonlocal_sysv),
> 	(call_nonlocal_sysv_secure, call_value_nonlocal_sysv),
> 	(call_value_nonlocal_sysv_secure, call_nonlocal_aix),
> 	(call_value_nonlocal_aix): Use rs6000_call_template and update
> 	occurrences of output_call to macho_call_template.
> 	(sibcall_nonlocal_sysv, sibcall_value_nonlocal_sysv, sibcall_aix),
> 	(sibcall_value_aix): Use rs6000_sibcall_template.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 2/6] [RS6000] rs6000_indirect_call_template
  2018-11-13 12:49         ` [PATCH 2/6] [RS6000] rs6000_indirect_call_template Alan Modra
@ 2018-11-20 16:23           ` Segher Boessenkool
  0 siblings, 0 replies; 34+ messages in thread
From: Segher Boessenkool @ 2018-11-20 16:23 UTC (permalink / raw)
  To: Alan Modra; +Cc: gcc-patches

Hi Alan,

On Tue, Nov 13, 2018 at 11:19:03PM +1030, Alan Modra wrote:
> Like the last patch for external calls, now handle most assembly code
> for indirect calls in one place.  The patch also merges some insns,
> correcting some !rs6000_speculate_indirect_jumps cases branching to
> LR, which don't require a speculation barrier.

Okay for trunk.  Thanks!


Segher


> 	* config/rs6000/rs6000-protos.h (rs6000_indirect_call_template),
> 	(rs6000_indirect_sibcall_template): Declare.
> 	* config/rs6000/rs6000.c (rs6000_indirect_call_template_1),
> 	(rs6000_indirect_call_template, rs6000_indirect_sibcall_template):
> 	New functions.
> 	* config/rs6000/rs6000.md (call_indirect_nonlocal_sysv),
> 	(call_value_indirect_nonlocal_sysv, sibcall_nonlocal_sysv),
> 	(call_indirect_aix, call_value_indirect_aix): Use
> 	rs6000_indirect_call_template and rs6000_indirect_sibcall_template.
> 	call_indirect_elfv2, call_value_indirect_elfv2): Likewise, and
> 	handle both speculation and non-speculation cases.
> 	(call_indirect_aix_nospec, call_value_indirect_aix_nospec): Delete.
> 	(call_indirect_elfv2_nospec, call_value_indirect_elfv2_nospec): Delete.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/6] [RS6000] Replace TLSmode with P, and correct tls call mems
  2018-11-13 12:50         ` [PATCH 3/6] [RS6000] Replace TLSmode with P, and correct tls call mems Alan Modra
@ 2018-11-20 17:10           ` Segher Boessenkool
  0 siblings, 0 replies; 34+ messages in thread
From: Segher Boessenkool @ 2018-11-20 17:10 UTC (permalink / raw)
  To: Alan Modra; +Cc: gcc-patches

On Tue, Nov 13, 2018 at 11:20:08PM +1030, Alan Modra wrote:
> There is really no need to define a TLSmode mode iterator that is
> identical (since !TARGET_64BIT == TARGET_32BIT) to the much used P
> mode iterator.  It's nonsense to think we might ever want to support
> 32-bit TLS on 64-bit or vice versa!  The patch also fixes a minor
> error in the call mems.  All other direct calls use (call (mem:SI ..)).
> 
> 	* config/rs6000/rs6000.md (TLSmode): Delete mode iterator.  Replace
> 	with P throughout except for call mems which should use SI.
> 	(tls_abi_suffix, tls_sysv_suffix, tls_insn_suffix): Delete mode
> 	iterators.  Replace with bits, mode and ptrload respectively.

(mode attributes, not iterators, in that last line)

> +(define_insn_and_split "tls_gd_aix<P:bits>"

Instead of <P:bits> you can just say <bits>, because P is the only (mode)
iterator used here.  Similar throughout the patch.

Okay for trunk (with that change if you can easily make it).  Thanks!


Segher

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 4/6] [RS6000] Remove constraints on call rounded_stack_size_rtx arg
  2018-11-13 12:51         ` [PATCH 4/6] [RS6000] Remove constraints on call rounded_stack_size_rtx arg Alan Modra
@ 2018-11-27 15:27           ` Segher Boessenkool
  0 siblings, 0 replies; 34+ messages in thread
From: Segher Boessenkool @ 2018-11-27 15:27 UTC (permalink / raw)
  To: Alan Modra; +Cc: gcc-patches

On Tue, Nov 13, 2018 at 11:21:30PM +1030, Alan Modra wrote:
> Version 2.  (Same as before, here for completeness.)
> 
> This call arg is unused on rs6000.
> 
> 	* config/rs6000/darwin.md (call_indirect_nonlocal_darwin64),
> 	(call_nonlocal_darwin64, call_value_indirect_nonlocal_darwin64),
> 	(call_value_nonlocal_darwin64): Remove constraints from second call
> 	arg, the rounded_stack_size_rtx arg.
> 	* config/rs6000/rs6000.md (tls_gd_aix, tls_gd_sysv, tls_gd_call_aix),
> 	(tls_gd_call_sysv, tls_ld_aix, tls_ld_sysv, tls_ld_call_aix),
> 	(tls_ld_call_sysv, call_local32, call_local64, call_value_local32),
> 	(call_value_local64, call_indirect_nonlocal_sysv),
> 	(call_nonlocal_sysv, call_nonlocal_sysv_secure),
> 	(call_value_indirect_nonlocal_sysv, call_value_nonlocal_sysv),
> 	(call_value_nonlocal_sysv_secure, call_local_aix),
> 	(call_value_local_aix, call_nonlocal_aix, call_value_nonlocal_aix),
> 	(call_indirect_aix, call_value_indirect_aix, call_indirect_elfv2),
> 	(call_value_indirect_elfv2, sibcall_local32, sibcall_local64),
> 	(sibcall_value_local32, sibcall_value_local64, sibcall_aix),
> 	(sibcall_value_aix): Likewise.

This is still OK for trunk.  Thanks!


Segher

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 5/6] [RS6000] Use standard call patterns for __tls_get_addr calls
  2018-11-13 12:52         ` [PATCH 5/6] [RS6000] Use standard call patterns for __tls_get_addr calls Alan Modra
@ 2018-11-27 16:29           ` Segher Boessenkool
  2018-11-28  1:07             ` Alan Modra
  0 siblings, 1 reply; 34+ messages in thread
From: Segher Boessenkool @ 2018-11-27 16:29 UTC (permalink / raw)
  To: Alan Modra; +Cc: gcc-patches

Hi!

On Tue, Nov 13, 2018 at 11:22:43PM +1030, Alan Modra wrote:
> Version 2.
> 
> The current code handling __tls_get_addr calls for powerpc*-linux
> generates a call then overwrites the call insn with a special
> tls_{gd,ld}_{aix,sysv} pattern.  It's done that way to support
> !TARGET_TLS_MARKERS, where the arg setup insns need to be emitted
> immediately before the branch and link.  When TARGET_TLS_MARKERS, the
> arg setup insns are split from the actual call, but we then have a
> non-standard call pattern that needs to be carried through to output.
> 
> This patch changes that scheme, to instead use the standard call
> patterns for __tls_get_addr calls, except for the now rare
> !TARGET_TLS_MARKERS case.  Doing it this way should be better for
> maintenance as the !TARGET_TLS_MARKERS code can eventually disappear.
> It also makes it possible to support longcalls (and in following
> patches, inline plt calls) for __tls_get_addr without introducing yet
> more special call patterns.
> 
> __tls_get_addr calls do however need to be different to standard
> calls, because when TARGET_TLS_MARKERS the calls are decorated with an
> argument specifier, eg. "bl __tls_get_addr(thread_var@tlsgd)" that
> causes a reloc to be emitted by the assembler tying the call to its
> arg setup insns.  I chose to smuggle the arg in the currently unused
> stack size rtl.
> 
> I've also introduced rs6000_call_sysv to generate rtl for sysv calls,
> as rs6000_call_aix does for aix and elfv2 calls.  This allows
> rs6000_longcall_ref to be local to rs6000.c since the calls in the
> expanders never did anything for darwin.
> 
> 	* config/rs6000/predicates.md (unspec_tls): New.
> 	* config/rs6000/rs6000-protos.h (rs6000_call_template),
> 	(rs6000_sibcall_template): Update prototype.
> 	(rs6000_longcall_ref): Delete.
> 	(rs6000_call_sysv): Declare.
> 	* config/rs6000/rs6000.c (edit_tls_call_insn): New function.
> 	(global_tlsarg): New variable.
> 	(rs6000_legitimize_tls_address): Rewrite __tls_get_addr call
> 	handling.
> 	(print_operand): Extract UNSPEC_TLSGD address operand.
> 	(rs6000_call_template, rs6000_sibcall_template): Remove arg
> 	parameter, extract from second call operand instead.
> 	(rs6000_longcall_ref): Make static, localize vars.
> 	(rs6000_call_aix): Rename parameter to reflect new usage.  Take
> 	tlsarg from global_tlsarg.  Don't create unused rtl or nop insns.
> 	(rs6000_sibcall_aix): Rename parameter to reflect new usage.  Take
> 	tlsarg from global_tlsarg.
> 	(rs6000_call_sysv): New function.
> 	* config/rs6000/rs6000.md: Adjust rs6000_call_template and
> 	rs6000_sibcall_template throughout.
> 	(tls_gd_aix, tls_gd_sysv, tls_gd_call_aix, tls_gd_call_sysv): Delete.
> 	(tls_ld_aix, tls_ld_sysv, tls_ld_call_aix, tls_ld_call_sysv): Delete.
> 	(tls_gdld_aix, tls_gdld_sysv): New insns, replacing above.
> 	(tls_gd): Swap operand order.  Simplify mode selection.
> 	(tls_gd_high, tls_gd_low): Swap operand order.
> 	(tls_ld): Remove const_int 0 vector element from UNSPEC_TLSLD.
> 	Simplify mode selection.
> 	(tls_ld_high, tls_ld_low): Similarly adjust UNSPEC_TLSLD.
> 	(call, call_value): Don't assert for second call operand.
> 	Use rs6000_call_sysv.


> +/* Passes the tls arg value for global dynamic and local dynamic
> +   emit_library_call_value in rs6000_legitimize_Tls_address to
> +   rs6000_call_aix and rs6000_call_sysv.  This is used to emit the
> +   marker relocs put on __tls_get_addr calls.  */
> +static rtx global_tlsarg;

Typo (s/_Tls/_tls/).

> +(define_insn "*tls_gdld_aix<P:bits>"
> +  [(match_parallel 3 ""

A match_parallel without predicate...  Does this work?!  Does this not
accidentally pick up the wrong things?

Do you think we should to deprecate -mtls-markers in GCC 9?

Please test with -mtls-markers, too, if you can, and test on AIX.

Looks fine.  Thank you for the cleanup!  Okay for trunk, but please do the
extra testing.


Segher

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 6/6] [RS6000] inline plt call sequences
  2018-11-13 12:53         ` [PATCH 6/6] [RS6000] inline plt call sequences Alan Modra
@ 2018-11-27 17:18           ` Segher Boessenkool
  2018-11-28  1:34             ` Alan Modra
  0 siblings, 1 reply; 34+ messages in thread
From: Segher Boessenkool @ 2018-11-27 17:18 UTC (permalink / raw)
  To: Alan Modra; +Cc: gcc-patches

Hi Alan,

On Tue, Nov 13, 2018 at 11:23:43PM +1030, Alan Modra wrote:
> Finally, the point of the previous patches in this series, support for
> inline PLT calls, keyed off -fno-plt.  This emits code using new
> relocations that tie all insns in the sequence together, so that the
> linker can edit the sequence back to a direct call should the call
> target turn out to be local.  An example of ELFv2 code to call puts is
> as follows:
> 
>      .reloc .,R_PPC64_PLTSEQ,puts
>         std 2,24(1)
>      .reloc .,R_PPC64_PLT16_HA,puts
>         addis 12,2,0
>      .reloc .,R_PPC64_PLT16_LO_DS,puts
>         ld 12,0(12)
>      .reloc .,R_PPC64_PLTSEQ,puts
>         mtctr 12
>      .reloc .,R_PPC64_PLTCALL,puts
>         bctrl
>         ld 2,24(1)
> 
> "addis 12,2,puts@plt@ha" and "ld 12,puts@plt@l(12)" are also supported
> by the assembler.  gcc instead uses the explicit R_PPC64_PLT16_HA and
> R_PPC64_PLT16_LO_DS relocs because when the call is to __tls_get_addr
> an extra reloc is emitted at every place where one is shown above, to
> specify the __tls_get_addr arg.  The linker expects the extra reloc to
> come first.  .reloc enforces that ordering.
> 
> The patch also changes code emitted for longcalls if the assembler
> supports the new marker relocs, so that these too can be edited.  One
> side effect of longcalls using PLT16 relocs is that they can now be
> resolved lazily by ld.so.
> 
> I don't support lazy inline PLT calls for ELFv1, because ELFv1 would
> need barriers to reliably load both the function address and toc
> pointer from the PLT.  ELFv1 -fno-plt uses the longcall sequence
> instead, which isn't edited by GNU ld.

That all sounds great :-)  Has this been tested with older binutils, too?


> 	* config.in (HAVE_AS_PLTSEQ): Add.
> 	* config/rs6000/predicates.md (indirect_call_operand): New.
> 	* config/rs6000/rs6000-protos.h (rs6000_pltseq_template),
> 	(rs6000_sibcall_sysv): Declare.
> 	* config/rs6000/rs6000.c (init_cumulative_args): Set cookie
> 	CALL_LONG for -fno-plt.
> 	(print_operand <T, z, 0>): Handle UNSPEC_PLTSEQ.
> 	(rs6000_indirect_call_template_1): Emit .reloc directives for
> 	UNSPEC_PLTSEQ calls.
> 	(rs6000_pltseq_template): New function.
> 	(rs6000_longcall_ref): Add arg parameter.  Use PLT16 insns if
> 	relocs supported by assembler.  Move SYMBOL_REF test to callers.
> 	(rs6000_call_aix): Adjust rs6000_longcall_ref call.  Package
> 	insns in UNSPEC_PLTSEQ, preserving original func_desc.
> 	(rs6000_call_sysv): Likewise.
> 	(rs6000_sibcall_sysv): New function.
> 	* config/rs6000/rs6000.h (HAVE_AS_PLTSEQ): Provide default.
> 	* config/rs6000/rs6000.md (UNSPEC_PLTSEQ, UNSPEC_PLT16_HA,
> 	UNSPEC_PLT16_LO): New.
> 	(pltseq_tocsave, pltseq_plt16_ha, pltseq_plt16_lo, pltseq_mtctr): New.
> 	(call_indirect_nonlocal_sysv): Don't differentiate zero from non-zero
> 	cookie in constraints.  Test explicitly for flags in length attr.
> 	Handle unspec operand 1.
> 	(call_value_indirect_nonlocal_sysv): Likewise.
> 	(call_indirect_aix, call_value_indirect_aix): Handle unspec operand 1.
> 	(call_indirect_elfv2, call_value_indirect_elfv2): Likewise.
> 	(sibcall, sibcall_value): Use rs6000_sibcall_sysv.
> 	(sibcall_indirect_nonlocal_sysv): New pattern.
> 	(sibcall_value_indirect_nonlocal_sysv): Likewise.
> 	(sibcall_nonlocal_sysv, sibcall_value_nonlocal_sysv): Remove indirect
> 	call alternatives.
> 	* configure.ac: Check for gas plt sequence marker support.
> 	* configure: Regenerate.


> @@ -10727,10 +10727,20 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
>      cum->nargs_prototype = n_named_args;
>  
>    /* Check for a longcall attribute.  */
> -  if ((!fntype && rs6000_default_long_calls)
> -      || (fntype
> -	  && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
> -	  && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))))
> +  if (((!fntype && rs6000_default_long_calls)
> +       || (fntype
> +	   && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
> +	   && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))))
> +      || (DEFAULT_ABI != ABI_DARWIN
> +	  && !(fndecl
> +	       && !DECL_EXTERNAL (fndecl)
> +	       && !DECL_WEAK (fndecl)
> +	       && (*targetm.binds_local_p) (fndecl))
> +	  && (flag_plt
> +	      ? (fntype
> +		 && lookup_attribute ("noplt", TYPE_ATTRIBUTES (fntype)))
> +	      : !(fntype
> +		  && lookup_attribute ("plt", TYPE_ATTRIBUTES (fntype))))))
>      cum->call_cookie |= CALL_LONG;

Could you split this into a few cases?  Maybe with some extra locals.  It
is hard to understand the code as it is.

I mean like

  if (...)
    cum->call_cookie |= CALL_LONG;
  if (...)
    cum->call_cookie |= CALL_LONG;
  if (...)
    cum->call_cookie |= CALL_LONG;


> +(define_insn "*sibcall_indirect_nonlocal_sysv<mode>"

> +   (set (attr "length")
> +	(cond [(and (and (match_test "!rs6000_speculate_indirect_jumps")
> +			 (match_test "which_alternative != 1"))
> +		    (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
> +		  (const_string "12")
> +	       (ior (and (match_test "!rs6000_speculate_indirect_jumps")
> +			 (match_test "which_alternative != 1"))
> +		   (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
> +		  (const_string "8")]
> +	      (const_string "4")))])

Please use set_attr_alternative for these.


Looks fine modulo those nits.  Okay for trunk.  Thanks!


Segher

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 5/6] [RS6000] Use standard call patterns for __tls_get_addr calls
  2018-11-27 16:29           ` Segher Boessenkool
@ 2018-11-28  1:07             ` Alan Modra
  2018-11-28 13:33               ` Segher Boessenkool
  0 siblings, 1 reply; 34+ messages in thread
From: Alan Modra @ 2018-11-28  1:07 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: gcc-patches

On Tue, Nov 27, 2018 at 10:29:29AM -0600, Segher Boessenkool wrote:
> Hi!

Thanks for the review!

> > +(define_insn "*tls_gdld_aix<P:bits>"
> > +  [(match_parallel 3 ""
> 
> A match_parallel without predicate...  Does this work?!

Yes.  In fact, rs6000/predicates.md any_parallel_operand is useless
except as documentation.  The only thing it checks is that its operand
is a parallel, but that has already been checked.

>  Does this not
> accidentally pick up the wrong things?

No.  The purpose of the predicate is to match anything beyond the
vector of expressions.  So tls_gdld_aix* matches insns that look like:

     (set (match_operand:P 0 "gpc_reg_operand" "=b")
	  (call (mem:SI (match_operand:P 1))
		(match_operand:P 2 "unspec_tls")))
     (match_dup 2)
     ...

This is sufficiently different from other calls, by virtue of the
"(match_dup 2)".

Incidentally, I think tls_gdld_aix and tls_gdld_sysv could be merged
at the expense of complicating the length attribute expression.

> Do you think we should to deprecate -mtls-markers in GCC 9?

Support for the TLS marker relocs was added to binutils in 2009 (git
commit 727fc41e077), so yes, the option is not likely to be useful
nowadays.

> Please test with -mtls-markers, too, if you can, and test on AIX.

Presumably you mean -mno-tls-markers.  -mtls-markers is the default.

> Looks fine.  Thank you for the cleanup!  Okay for trunk, but please do the
> extra testing.

Huh, local testing of -mno-tls-markers showed a lack of a
TARGET_TLS_MARKERS check in rs6000_call_template_1.  Likely this would
blow up on AIX.  I'll test with the following delta.

diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 56ca117a0a0..5f4fcee3b33 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -8622,7 +8622,7 @@ edit_tls_call_insn (rtx arg)
 }
 
 /* Passes the tls arg value for global dynamic and local dynamic
-   emit_library_call_value in rs6000_legitimize_Tls_address to
+   emit_library_call_value in rs6000_legitimize_tls_address to
    rs6000_call_aix and rs6000_call_sysv.  This is used to emit the
    marker relocs put on __tls_get_addr calls.  */
 static rtx global_tlsarg;
@@ -21429,7 +21429,7 @@ rs6000_call_template_1 (rtx *operands, unsigned int funop, bool sibcall)
 
   char arg[12];
   arg[0] = 0;
-  if (GET_CODE (operands[funop + 1]) == UNSPEC)
+  if (TARGET_TLS_MARKERS && GET_CODE (operands[funop + 1]) == UNSPEC)
     {
       if (XINT (operands[funop + 1], 1) == UNSPEC_TLSGD)
 	sprintf (arg, "(%%%u@tlsgd)", funop + 1);

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 6/6] [RS6000] inline plt call sequences
  2018-11-27 17:18           ` Segher Boessenkool
@ 2018-11-28  1:34             ` Alan Modra
  2018-11-28 13:39               ` Segher Boessenkool
  0 siblings, 1 reply; 34+ messages in thread
From: Alan Modra @ 2018-11-28  1:34 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: gcc-patches

On Tue, Nov 27, 2018 at 11:17:48AM -0600, Segher Boessenkool wrote:
> That all sounds great :-)  Has this been tested with older binutils, too?

Yes, lots of times.  Sometimes by accident when I forgot to install
a new binutils.  :-)

> > +(define_insn "*sibcall_indirect_nonlocal_sysv<mode>"
> 
> > +   (set (attr "length")
> > +	(cond [(and (and (match_test "!rs6000_speculate_indirect_jumps")
> > +			 (match_test "which_alternative != 1"))
> > +		    (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
> > +		  (const_string "12")
> > +	       (ior (and (match_test "!rs6000_speculate_indirect_jumps")
> > +			 (match_test "which_alternative != 1"))
> > +		   (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
> > +		  (const_string "8")]
> > +	      (const_string "4")))])
> 
> Please use set_attr_alternative for these.

Are you sure about that?  The expression blows out to something like
(completely untested):

   (set_attr_alternative "length"
     [(cond [(and (match_test "!rs6000_speculate_indirect_jumps")
		  (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
		(const_string "12")
	     (ior (match_test "!rs6000_speculate_indirect_jumps")
		  (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
		(const_string "8")]
	   (const_string "4"))
      (cond [(match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))")
		(const_string "8")]
	   (const_string "4"))
      (cond [(and (match_test "!rs6000_speculate_indirect_jumps")
		  (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
		(const_string "12")
	     (ior (match_test "!rs6000_speculate_indirect_jumps")
		  (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
		(const_string "8")]
	   (const_string "4"))])


-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 5/6] [RS6000] Use standard call patterns for __tls_get_addr calls
  2018-11-28  1:07             ` Alan Modra
@ 2018-11-28 13:33               ` Segher Boessenkool
  2018-11-28 23:08                 ` Alan Modra
  2018-11-29  6:11                 ` Alan Modra
  0 siblings, 2 replies; 34+ messages in thread
From: Segher Boessenkool @ 2018-11-28 13:33 UTC (permalink / raw)
  To: Alan Modra; +Cc: gcc-patches

On Wed, Nov 28, 2018 at 11:37:42AM +1030, Alan Modra wrote:
> On Tue, Nov 27, 2018 at 10:29:29AM -0600, Segher Boessenkool wrote:
> > Hi!
> 
> Thanks for the review!
> 
> > > +(define_insn "*tls_gdld_aix<P:bits>"
> > > +  [(match_parallel 3 ""
> > 
> > A match_parallel without predicate...  Does this work?!
> 
> Yes.  In fact, rs6000/predicates.md any_parallel_operand is useless
> except as documentation.  The only thing it checks is that its operand
> is a parallel, but that has already been checked.

Right.  I grepped if there were other parallels without predicate, not
finding any, but I did not notice that half of the predicates used are
any_parallel_operand.

> >  Does this not
> > accidentally pick up the wrong things?
> 
> No.  The purpose of the predicate is to match anything beyond the
> vector of expressions.  So tls_gdld_aix* matches insns that look like:
> 
>      (set (match_operand:P 0 "gpc_reg_operand" "=b")
> 	  (call (mem:SI (match_operand:P 1))
> 		(match_operand:P 2 "unspec_tls")))
>      (match_dup 2)
>      ...
> 
> This is sufficiently different from other calls, by virtue of the
> "(match_dup 2)".

And the "unspec_tls".  Right.

> Incidentally, I think tls_gdld_aix and tls_gdld_sysv could be merged
> at the expense of complicating the length attribute expression.
> 
> > Do you think we should to deprecate -mtls-markers in GCC 9?
> 
> Support for the TLS marker relocs was added to binutils in 2009 (git
> commit 727fc41e077), so yes, the option is not likely to be useful
> nowadays.

Well, but do we gain anything if it is eventually deleted?  Simpler code?

> > Please test with -mtls-markers, too, if you can, and test on AIX.
> 
> Presumably you mean -mno-tls-markers.  -mtls-markers is the default.

Yeah, the ! case.

> > Looks fine.  Thank you for the cleanup!  Okay for trunk, but please do the
> > extra testing.
> 
> Huh, local testing of -mno-tls-markers showed a lack of a
> TARGET_TLS_MARKERS check in rs6000_call_template_1.  Likely this would
> blow up on AIX.  I'll test with the following delta.

Sounds good.


Segher

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 6/6] [RS6000] inline plt call sequences
  2018-11-28  1:34             ` Alan Modra
@ 2018-11-28 13:39               ` Segher Boessenkool
  0 siblings, 0 replies; 34+ messages in thread
From: Segher Boessenkool @ 2018-11-28 13:39 UTC (permalink / raw)
  To: Alan Modra; +Cc: gcc-patches

On Wed, Nov 28, 2018 at 12:04:01PM +1030, Alan Modra wrote:
> On Tue, Nov 27, 2018 at 11:17:48AM -0600, Segher Boessenkool wrote:
> > That all sounds great :-)  Has this been tested with older binutils, too?
> 
> Yes, lots of times.  Sometimes by accident when I forgot to install
> a new binutils.  :-)
> 
> > > +(define_insn "*sibcall_indirect_nonlocal_sysv<mode>"
> > 
> > > +   (set (attr "length")
> > > +	(cond [(and (and (match_test "!rs6000_speculate_indirect_jumps")
> > > +			 (match_test "which_alternative != 1"))
> > > +		    (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
> > > +		  (const_string "12")
> > > +	       (ior (and (match_test "!rs6000_speculate_indirect_jumps")
> > > +			 (match_test "which_alternative != 1"))
> > > +		   (match_test "(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))"))
> > > +		  (const_string "8")]
> > > +	      (const_string "4")))])
> > 
> > Please use set_attr_alternative for these.
> 
> Are you sure about that?  The expression blows out to something like
> (completely untested):

But you don't need "cond", something with if_then_else is simpler.  And
(INTVAL (operands[2]) & (CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS))
could be put into a macro or inline or even a predicate.

Those apply to both with set_attr_alternative and without, of course;
please use what is easiest to read and understand.

(Just committing without changes is fine as well of course).

Thanks,


Segher

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 5/6] [RS6000] Use standard call patterns for __tls_get_addr calls
  2018-11-28 13:33               ` Segher Boessenkool
@ 2018-11-28 23:08                 ` Alan Modra
  2018-11-29  6:11                 ` Alan Modra
  1 sibling, 0 replies; 34+ messages in thread
From: Alan Modra @ 2018-11-28 23:08 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: gcc-patches

On Wed, Nov 28, 2018 at 07:32:50AM -0600, Segher Boessenkool wrote:
> On Wed, Nov 28, 2018 at 11:37:42AM +1030, Alan Modra wrote:
> > On Tue, Nov 27, 2018 at 10:29:29AM -0600, Segher Boessenkool wrote:
> > > Do you think we should to deprecate -mtls-markers in GCC 9?
> > 
> > Support for the TLS marker relocs was added to binutils in 2009 (git
> > commit 727fc41e077), so yes, the option is not likely to be useful
> > nowadays.
> 
> Well, but do we gain anything if it is eventually deleted?  Simpler code?

Not much.  Unfortunately we still need to keep TARGET_TLS_MARKERS (or
replace throughout with !HAVE_AS_TLS_MARKERS) for AIX.  Deprecate AIX
perhaps?  :-)

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 5/6] [RS6000] Use standard call patterns for __tls_get_addr calls
  2018-11-28 13:33               ` Segher Boessenkool
  2018-11-28 23:08                 ` Alan Modra
@ 2018-11-29  6:11                 ` Alan Modra
  1 sibling, 0 replies; 34+ messages in thread
From: Alan Modra @ 2018-11-29  6:11 UTC (permalink / raw)
  To: Segher Boessenkool; +Cc: gcc-patches

On Wed, Nov 28, 2018 at 07:32:50AM -0600, Segher Boessenkool wrote:
> On Wed, Nov 28, 2018 at 11:37:42AM +1030, Alan Modra wrote:
> > On Tue, Nov 27, 2018 at 10:29:29AM -0600, Segher Boessenkool wrote:
> > > Looks fine.  Thank you for the cleanup!  Okay for trunk, but please do the
> > > extra testing.
> > 
> > Huh, local testing of -mno-tls-markers showed a lack of a
> > TARGET_TLS_MARKERS check in rs6000_call_template_1.  Likely this would
> > blow up on AIX.  I'll test with the following delta.
> 
> Sounds good.

For the record, this is the patch I committed.  Besides the delta
posted previously, I managed to combine the tls_gdld_aix and
tls_gdld_sysv insns into a single insn, tls_gdld_nomark.

	* config/rs6000/predicates.md (unspec_tls): New.
	* config/rs6000/rs6000-protos.h (rs6000_call_template),
	(rs6000_sibcall_template): Update prototype.
	(rs6000_longcall_ref): Delete.
	(rs6000_call_sysv): Declare.
	* config/rs6000/rs6000.c (edit_tls_call_insn): New function.
	(global_tlsarg): New variable.
	(rs6000_legitimize_tls_address): Rewrite __tls_get_addr call
	handling.
	(print_operand): Extract UNSPEC_TLSGD address operand.
	(rs6000_call_template, rs6000_sibcall_template): Remove arg
	parameter, extract from second call operand instead.
	(rs6000_longcall_ref): Make static, localize vars.
	(rs6000_call_aix): Rename parameter to reflect new usage.  Take
	tlsarg from global_tlsarg.  Don't create unused rtl or nop insns.
	(rs6000_sibcall_aix): Rename parameter to reflect new usage.  Take
	tlsarg from global_tlsarg.
	(rs6000_call_sysv): New function.
	* config/rs6000/rs6000.md: Adjust rs6000_call_template and
	rs6000_sibcall_template throughout.
	(tls_gd_aix, tls_gd_sysv, tls_gd_call_aix, tls_gd_call_sysv): Delete.
	(tls_ld_aix, tls_ld_sysv, tls_ld_call_aix, tls_ld_call_sysv): Delete.
	(tls_gdld_nomark): New insn.
	(tls_gd): Swap operand order.  Simplify mode selection.
	(tls_gd_high, tls_gd_low): Swap operand order.
	(tls_ld): Remove const_int 0 vector element from UNSPEC_TLSLD.
	Simplify mode selection.
	(tls_ld_high, tls_ld_low): Similarly adjust UNSPEC_TLSLD.
	(call, call_value): Don't assert for second call operand.
	Use rs6000_call_sysv.

diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index 5589ea19519..2c297fc45e8 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -997,6 +997,13 @@ (define_predicate "rs6000_tls_symbol_ref"
   (and (match_code "symbol_ref")
        (match_test "RS6000_SYMBOL_REF_TLS_P (op)")))
 
+;; Return 1 for the UNSPEC used in TLS call operands
+(define_predicate "unspec_tls"
+  (match_code "unspec")
+{
+  return XINT (op, 1) == UNSPEC_TLSGD || XINT (op, 1) == UNSPEC_TLSLD;
+})
+
 ;; Return 1 if the operand, used inside a MEM, is a valid first argument
 ;; to CALL.  This is a SYMBOL_REF, a pseudo-register, LR or CTR.
 (define_predicate "call_operand"
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index f1a294a3617..dd930bb2da6 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -105,8 +105,8 @@ extern int ccr_bit (rtx, int);
 extern void rs6000_output_function_entry (FILE *, const char *);
 extern void print_operand (FILE *, rtx, int);
 extern void print_operand_address (FILE *, rtx);
-extern const char *rs6000_call_template (rtx *, unsigned int, const char *);
-extern const char *rs6000_sibcall_template (rtx *, unsigned int, const char *);
+extern const char *rs6000_call_template (rtx *, unsigned int);
+extern const char *rs6000_sibcall_template (rtx *, unsigned int);
 extern const char *rs6000_indirect_call_template (rtx *, unsigned int);
 extern const char *rs6000_indirect_sibcall_template (rtx *, unsigned int);
 extern enum rtx_code rs6000_reverse_condition (machine_mode,
@@ -130,7 +130,6 @@ extern void rs6000_expand_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx);
 extern void rs6000_emit_swdiv (rtx, rtx, rtx, bool);
 extern void rs6000_emit_swsqrt (rtx, rtx, bool);
 extern void output_toc (FILE *, rtx, int, machine_mode);
-extern rtx rs6000_longcall_ref (rtx);
 extern void rs6000_fatal_bad_address (rtx);
 extern rtx create_TOC_reference (rtx, rtx);
 extern void rs6000_split_multireg_move (rtx, rtx);
@@ -198,6 +197,7 @@ extern void rs6000_split_stack_space_check (rtx, rtx);
 extern void rs6000_emit_eh_reg_restore (rtx, rtx);
 extern void rs6000_call_aix (rtx, rtx, rtx, rtx);
 extern void rs6000_sibcall_aix (rtx, rtx, rtx, rtx);
+extern void rs6000_call_sysv (rtx, rtx, rtx, rtx);
 extern void rs6000_aix_asm_output_dwarf_table_ref (char *);
 extern void get_ppc476_thunk_name (char name[32]);
 extern bool rs6000_overloaded_builtin_p (enum rs6000_builtins);
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 497a157b89c..f3376065ee1 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -8566,6 +8566,43 @@ rs6000_legitimize_tls_address_aix (rtx addr, enum tls_model model)
   return dest;
 }
 
+/* Mess with a call, to make it look like the tls_gdld insns when
+   !TARGET_TLS_MARKERS.  These insns have an extra unspec to
+   differentiate them from standard calls, because they need to emit
+   the arg setup insns as well as the actual call.  That keeps the
+   arg setup insns immediately adjacent to the branch and link.  */
+
+static void
+edit_tls_call_insn (rtx arg)
+{
+  rtx call_insn = last_call_insn ();
+  if (!TARGET_TLS_MARKERS)
+    {
+      rtx patt = PATTERN (call_insn);
+      gcc_assert (GET_CODE (patt) == PARALLEL);
+      rtvec orig = XVEC (patt, 0);
+      rtvec v = rtvec_alloc (GET_NUM_ELEM (orig) + 1);
+      gcc_assert (GET_NUM_ELEM (orig) > 0);
+      /* The (set (..) (call (mem ..))).  */
+      RTVEC_ELT (v, 0) = RTVEC_ELT (orig, 0);
+      /* The extra unspec.  */
+      RTVEC_ELT (v, 1) = arg;
+      /* All other assorted call pattern pieces.  */
+      for (int i = 1; i < GET_NUM_ELEM (orig); i++)
+	RTVEC_ELT (v, i + 1) = RTVEC_ELT (orig, i);
+      XVEC (patt, 0) = v;
+    }
+  if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
+    use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
+	     pic_offset_table_rtx);
+}
+
+/* Passes the tls arg value for global dynamic and local dynamic
+   emit_library_call_value in rs6000_legitimize_tls_address to
+   rs6000_call_aix and rs6000_call_sysv.  This is used to emit the
+   marker relocs put on __tls_get_addr calls.  */
+static rtx global_tlsarg;
+
 /* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
    this (thread-local) address.  */
 
@@ -8618,7 +8655,7 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
     }
   else
     {
-      rtx r3, got, tga, tmp1, tmp2, call_insn;
+      rtx got, tga, tmp1, tmp2;
 
       /* We currently use relocations like @got@tlsgd for tls, which
 	 means the linker will handle allocation of tls entries, placing
@@ -8658,52 +8695,42 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
 
       if (model == TLS_MODEL_GLOBAL_DYNAMIC)
 	{
+	  rtx arg = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, addr, got),
+				    UNSPEC_TLSGD);
+	  global_tlsarg = arg;
+	  rtx argreg = const0_rtx;
+	  if (TARGET_TLS_MARKERS)
+	    {
+	      argreg = gen_rtx_REG (Pmode, 3);
+	      emit_insn (gen_rtx_SET (argreg, arg));
+	    }
+
 	  tga = rs6000_tls_get_addr ();
 	  emit_library_call_value (tga, dest, LCT_CONST, Pmode,
-				   const0_rtx, Pmode);
+				   argreg, Pmode);
+	  global_tlsarg = NULL_RTX;
 
-	  r3 = gen_rtx_REG (Pmode, 3);
-	  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
-	    {
-	      if (TARGET_64BIT)
-		insn = gen_tls_gd_aix64 (r3, got, addr, tga, const0_rtx);
-	      else
-		insn = gen_tls_gd_aix32 (r3, got, addr, tga, const0_rtx);
-	    }
-	  else if (DEFAULT_ABI == ABI_V4)
-	    insn = gen_tls_gd_sysvsi (r3, got, addr, tga, const0_rtx);
-	  else
-	    gcc_unreachable ();
-	  call_insn = last_call_insn ();
-	  PATTERN (call_insn) = insn;
-	  if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
-	    use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
-		     pic_offset_table_rtx);
+	  edit_tls_call_insn (arg);
 	}
       else if (model == TLS_MODEL_LOCAL_DYNAMIC)
 	{
+	  rtx arg = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, got),
+				    UNSPEC_TLSLD);
+	  global_tlsarg = arg;
+	  rtx argreg = const0_rtx;
+	  if (TARGET_TLS_MARKERS)
+	    {
+	      argreg = gen_rtx_REG (Pmode, 3);
+	      emit_insn (gen_rtx_SET (argreg, arg));
+	    }
+
 	  tga = rs6000_tls_get_addr ();
 	  tmp1 = gen_reg_rtx (Pmode);
 	  emit_library_call_value (tga, tmp1, LCT_CONST, Pmode,
-				   const0_rtx, Pmode);
+				   argreg, Pmode);
+	  global_tlsarg = NULL_RTX;
 
-	  r3 = gen_rtx_REG (Pmode, 3);
-	  if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
-	    {
-	      if (TARGET_64BIT)
-		insn = gen_tls_ld_aix64 (r3, got, tga, const0_rtx);
-	      else
-		insn = gen_tls_ld_aix32 (r3, got, tga, const0_rtx);
-	    }
-	  else if (DEFAULT_ABI == ABI_V4)
-	    insn = gen_tls_ld_sysvsi (r3, got, tga, const0_rtx);
-	  else
-	    gcc_unreachable ();
-	  call_insn = last_call_insn ();
-	  PATTERN (call_insn) = insn;
-	  if (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
-	    use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn),
-		     pic_offset_table_rtx);
+	  edit_tls_call_insn (arg);
 
 	  if (rs6000_tls_size == 16)
 	    {
@@ -21170,19 +21197,19 @@ print_operand (FILE *file, rtx x, int code)
 	  else
 	    output_address (GET_MODE (x), XEXP (x, 0));
 	}
+      else if (toc_relative_expr_p (x, false,
+				    &tocrel_base_oac, &tocrel_offset_oac))
+	/* This hack along with a corresponding hack in
+	   rs6000_output_addr_const_extra arranges to output addends
+	   where the assembler expects to find them.  eg.
+	   (plus (unspec [(symbol_ref ("x")) (reg 2)] tocrel) 4)
+	   without this hack would be output as "x@toc+4".  We
+	   want "x+4@toc".  */
+	output_addr_const (file, CONST_CAST_RTX (tocrel_base_oac));
+      else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSGD)
+	output_addr_const (file, XVECEXP (x, 0, 0));
       else
-	{
-	  if (toc_relative_expr_p (x, false, &tocrel_base_oac, &tocrel_offset_oac))
-	    /* This hack along with a corresponding hack in
-	       rs6000_output_addr_const_extra arranges to output addends
-	       where the assembler expects to find them.  eg.
-	       (plus (unspec [(symbol_ref ("x")) (reg 2)] tocrel) 4)
-	       without this hack would be output as "x@toc+4".  We
-	       want "x+4@toc".  */
-	    output_addr_const (file, CONST_CAST_RTX (tocrel_base_oac));
-	  else
-	    output_addr_const (file, x);
-	}
+	output_addr_const (file, x);
       return;
 
     case '&':
@@ -21368,18 +21395,27 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
 }
 
 /* Return a template string for assembly to emit when making an
-   external call.  FUNOP is the call mem argument operand number,
-   ARG is either NULL or a @TLSGD or @TLSLD __tls_get_addr argument
-   specifier.  */
+   external call.  FUNOP is the call mem argument operand number.  */
 
 static const char *
-rs6000_call_template_1 (rtx *operands ATTRIBUTE_UNUSED, unsigned int funop,
-			bool sibcall, const char *arg)
+rs6000_call_template_1 (rtx *operands, unsigned int funop, bool sibcall)
 {
   /* -Wformat-overflow workaround, without which gcc thinks that %u
       might produce 10 digits.  */
   gcc_assert (funop <= MAX_RECOG_OPERANDS);
 
+  char arg[12];
+  arg[0] = 0;
+  if (TARGET_TLS_MARKERS && GET_CODE (operands[funop + 1]) == UNSPEC)
+    {
+      if (XINT (operands[funop + 1], 1) == UNSPEC_TLSGD)
+	sprintf (arg, "(%%%u@tlsgd)", funop + 1);
+      else if (XINT (operands[funop + 1], 1) == UNSPEC_TLSLD)
+	sprintf (arg, "(%%&@tlsld)");
+      else
+	gcc_unreachable ();
+    }
+
   /* The magic 32768 offset here corresponds to the offset of
      r30 in .got2, as given by LCTOC1.  See sysv4.h:toc_section.  */
   char z[11];
@@ -21387,7 +21423,7 @@ rs6000_call_template_1 (rtx *operands ATTRIBUTE_UNUSED, unsigned int funop,
 	   (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic == 2
 	    ? "+32768" : ""));
 
-  static char str[32];  /* 4 spare */
+  static char str[32];  /* 2 spare */
   if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
     sprintf (str, "b%s %s%s%s", sibcall ? "" : "l", z, arg,
 	     sibcall ? "" : "\n\tnop");
@@ -21400,15 +21436,15 @@ rs6000_call_template_1 (rtx *operands ATTRIBUTE_UNUSED, unsigned int funop,
 }
 
 const char *
-rs6000_call_template (rtx *operands, unsigned int funop, const char *arg)
+rs6000_call_template (rtx *operands, unsigned int funop)
 {
-  return rs6000_call_template_1 (operands, funop, false, arg);
+  return rs6000_call_template_1 (operands, funop, false);
 }
 
 const char *
-rs6000_sibcall_template (rtx *operands, unsigned int funop, const char *arg)
+rs6000_sibcall_template (rtx *operands, unsigned int funop)
 {
-  return rs6000_call_template_1 (operands, funop, true, arg);
+  return rs6000_call_template_1 (operands, funop, true);
 }
 
 /* As above, for indirect calls.  */
@@ -32498,23 +32534,20 @@ rs6000_set_default_type_attributes (tree type)
 /* Return a reference suitable for calling a function with the
    longcall attribute.  */
 
-rtx
+static rtx
 rs6000_longcall_ref (rtx call_ref)
 {
-  const char *call_name;
-  tree node;
-
   if (GET_CODE (call_ref) != SYMBOL_REF)
     return call_ref;
 
   /* System V adds '.' to the internal name, so skip them.  */
-  call_name = XSTR (call_ref, 0);
+  const char *call_name = XSTR (call_ref, 0);
   if (*call_name == '.')
     {
       while (*call_name == '.')
 	call_name++;
 
-      node = get_identifier (call_name);
+      tree node = get_identifier (call_name);
       call_ref = gen_rtx_SYMBOL_REF (VOIDmode, IDENTIFIER_POINTER (node));
     }
 
@@ -37485,7 +37518,7 @@ chain_already_loaded (rtx_insn *last)
 /* Expand code to perform a call under the AIX or ELFv2 ABI.  */
 
 void
-rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
+rs6000_call_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 {
   const bool direct_call_p
     = GET_CODE (func_desc) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (func_desc);
@@ -37498,6 +37531,9 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
   int n_call;
   rtx insn;
 
+  if (global_tlsarg)
+    tlsarg = global_tlsarg;
+
   /* Handle longcall attributes.  */
   if (INTVAL (cookie) & CALL_LONG)
     func_desc = rs6000_longcall_ref (func_desc);
@@ -37508,11 +37544,7 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
     {
       /* Save the TOC into its reserved slot before the call,
 	 and prepare to restore it after the call.  */
-      rtx stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
       rtx stack_toc_offset = GEN_INT (RS6000_TOC_SAVE_SLOT);
-      rtx stack_toc_mem = gen_frame_mem (Pmode,
-					 gen_rtx_PLUS (Pmode, stack_ptr,
-						       stack_toc_offset));
       rtx stack_toc_unspec = gen_rtx_UNSPEC (Pmode,
 					     gen_rtvec (1, stack_toc_offset),
 					     UNSPEC_TOCSLOT);
@@ -37524,6 +37556,10 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
 	cfun->machine->save_toc_in_prologue = true;
       else
 	{
+	  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;
 	  emit_move_insn (stack_toc_mem, toc_reg);
 	}
@@ -37533,7 +37569,8 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
 	  /* A function pointer in the ELFv2 ABI is just a plain address, but
 	     the ABI requires it to be loaded into r12 before the call.  */
 	  func_addr = gen_rtx_REG (Pmode, 12);
-	  emit_move_insn (func_addr, func_desc);
+	  if (!rtx_equal_p (func_addr, func_desc))
+	    emit_move_insn (func_addr, func_desc);
 	  abi_reg = func_addr;
 	}
       else
@@ -37588,7 +37625,7 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
     }
 
   /* Create the call.  */
-  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), flag);
+  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), tlsarg);
   if (value != NULL_RTX)
     call[0] = gen_rtx_SET (value, call[0]);
   n_call = 1;
@@ -37612,15 +37649,18 @@ rs6000_call_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
 /* Expand code to perform a sibling call under the AIX or ELFv2 ABI.  */
 
 void
-rs6000_sibcall_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
+rs6000_sibcall_aix (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 {
   rtx call[2];
   rtx insn;
 
   gcc_assert (INTVAL (cookie) == 0);
 
+  if (global_tlsarg)
+    tlsarg = global_tlsarg;
+
   /* Create the call.  */
-  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_desc), flag);
+  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_desc), tlsarg);
   if (value != NULL_RTX)
     call[0] = gen_rtx_SET (value, call[0]);
 
@@ -37633,6 +37673,42 @@ rs6000_sibcall_aix (rtx value, rtx func_desc, rtx flag, rtx cookie)
   use_reg (&CALL_INSN_FUNCTION_USAGE (insn), gen_rtx_REG (Pmode, TOC_REGNUM));
 }
 
+/* Expand code to perform a call under the SYSV4 ABI.  */
+
+void
+rs6000_call_sysv (rtx value, rtx func, rtx tlsarg, rtx cookie)
+{
+  rtx func_addr;
+  rtx call[3];
+  rtx insn;
+
+  if (global_tlsarg)
+    tlsarg = global_tlsarg;
+
+  /* Handle longcall attributes.  */
+  if (INTVAL (cookie) & CALL_LONG)
+    func = rs6000_longcall_ref (func);
+
+  /* Handle indirect calls.  */
+  if (GET_CODE (func) != SYMBOL_REF)
+    func_addr = force_reg (Pmode, func);
+  else
+    func_addr = func;
+
+  /* Create the call.  */
+  call[0] = gen_rtx_CALL (VOIDmode, gen_rtx_MEM (SImode, func_addr), tlsarg);
+  if (value != NULL_RTX)
+    call[0] = gen_rtx_SET (value, call[0]);
+
+  unsigned int mask = CALL_V4_SET_FP_ARGS | CALL_V4_CLEAR_FP_ARGS;
+  call[1] = gen_rtx_USE (VOIDmode, GEN_INT (INTVAL (cookie) & mask));
+
+  call[2] = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
+
+  insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
+  insn = emit_call_insn (insn);
+}
+
 /* Return whether we need to always update the saved TOC pointer when we update
    the stack pointer.  */
 
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index b223e0b266d..ac87bb96436 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -9422,74 +9422,51 @@ (define_peephole2
 \f
 ;; TLS support.
 
-(define_insn_and_split "tls_gd_aix<bits>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
-	      (match_operand 4)))
-   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
-	      (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
-	     UNSPEC_TLSGD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
-{
-  if (TARGET_CMODEL != CMODEL_SMALL)
-    output_asm_insn ("addis %0,%1,%2@got@tlsgd@ha\;"
-		     "addi %0,%0,%2@got@tlsgd@l", operands);
+(define_insn "*tls_gdld_nomark<bits>"
+  [(match_parallel 3 ""
+    [(set (match_operand:P 0 "gpc_reg_operand" "=b")
+	  (call (mem:SI (match_operand:P 1))
+		(match_operand:P 2 "unspec_tls")))
+     (match_dup 2)])]
+  "HAVE_AS_TLS && !TARGET_TLS_MARKERS && DEFAULT_ABI != ABI_DARWIN"
+{
+  rtx op[3];
+  op[0] = operands[0];
+  op[1] = XVECEXP (operands[2], 0, 0);
+  if (XINT (operands[2], 1) == UNSPEC_TLSGD)
+    {
+      op[2] = XVECEXP (operands[2], 0, 1);
+      if (TARGET_CMODEL != CMODEL_SMALL)
+	output_asm_insn ("addis %0,%2,%1@got@tlsgd@ha\;"
+			 "addi %0,%0,%1@got@tlsgd@l", op);
+      else
+	output_asm_insn ("addi %0,%2,%1@got@tlsgd", op);
+    }
   else
-    output_asm_insn ("addi %0,%1,%2@got@tlsgd", operands);
-  return rs6000_call_template (operands, 3, "");
+    {
+      if (TARGET_CMODEL != CMODEL_SMALL)
+	output_asm_insn ("addis %0,%1,%&@got@tlsld@ha\;"
+			 "addi %0,%0,%&@got@tlsld@l", op);
+      else
+	output_asm_insn ("addi %0,%1,%&@got@tlsld", op);
+    }
+  return rs6000_call_template (operands, 1);
 }
-  "&& TARGET_TLS_MARKERS"
-  [(set (match_dup 0)
-	(unspec:P [(match_dup 1)
-		   (match_dup 2)]
-		  UNSPEC_TLSGD))
-   (parallel [(set (match_dup 0)
-		   (call (mem:SI (match_dup 3))
-			 (match_dup 4)))
-	      (unspec:P [(match_dup 2)] UNSPEC_TLSGD)
-	      (clobber (reg:SI LR_REGNO))])]
-  ""
   [(set_attr "type" "two")
    (set (attr "length")
-     (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-		   (const_int 16)
-		   (const_int 12)))])
-
-(define_insn_and_split "tls_gd_sysv<mode>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 3 "symbol_ref_operand" "s"))
-	      (match_operand 4)))
-   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
-	      (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
-	     UNSPEC_TLSGD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
-{
-  output_asm_insn ("addi %0,%1,%2@got@tlsgd", operands);
-  return rs6000_call_template (operands, 3, "");
-}
-  "&& TARGET_TLS_MARKERS"
-  [(set (match_dup 0)
-	(unspec:P [(match_dup 1)
-		   (match_dup 2)]
-		  UNSPEC_TLSGD))
-   (parallel [(set (match_dup 0)
-		   (call (mem:SI (match_dup 3))
-			 (match_dup 4)))
-	      (unspec:P [(match_dup 2)] UNSPEC_TLSGD)
-	      (clobber (reg:SI LR_REGNO))])]
-  ""
-  [(set_attr "type" "two")
-   (set_attr "length" "8")])
+     (cond [(match_test "TARGET_CMODEL != CMODEL_SMALL")
+		(const_int 16)
+	    (match_test "DEFAULT_ABI != ABI_V4")
+		(const_int 12)]
+	(const_int 8)))])
 
 (define_insn_and_split "*tls_gd<bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
-		   (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+	(unspec:P [(match_operand:P 1 "rs6000_tls_symbol_ref" "")
+		   (match_operand:P 2 "gpc_reg_operand" "b")]
 		  UNSPEC_TLSGD))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS"
-  "addi %0,%1,%2@got@tlsgd"
+  "addi %0,%2,%1@got@tlsgd"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 3)
 	(high:P
@@ -9498,7 +9475,7 @@ (define_insn_and_split "*tls_gd<bits>"
 	(lo_sum:P (match_dup 3)
 	    (unspec:P [(match_dup 1) (match_dup 2)] UNSPEC_TLSGD)))]
 {
-  operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
+  operands[3] = gen_reg_rtx (<MODE>mode);
 }
   [(set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
@@ -9508,105 +9485,21 @@ (define_insn_and_split "*tls_gd<bits>"
 (define_insn "*tls_gd_high<bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
      (high:P
-       (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
-		  (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+       (unspec:P [(match_operand:P 1 "rs6000_tls_symbol_ref" "")
+		  (match_operand:P 2 "gpc_reg_operand" "b")]
 		 UNSPEC_TLSGD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
-  "addis %0,%1,%2@got@tlsgd@ha")
+  "addis %0,%2,%1@got@tlsgd@ha")
 
 (define_insn "*tls_gd_low<bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
      (lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
-       (unspec:P [(match_operand:P 3 "gpc_reg_operand" "b")
-		  (match_operand:P 2 "rs6000_tls_symbol_ref" "")]
+       (unspec:P [(match_operand:P 2 "rs6000_tls_symbol_ref" "")
+		  (match_operand:P 3 "gpc_reg_operand" "b")]
 		 UNSPEC_TLSGD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addi %0,%1,%2@got@tlsgd@l")
 
-(define_insn "*tls_gd_call_aix<bits>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2)))
-   (unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
-	     UNSPEC_TLSGD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && TARGET_TLS_MARKERS
-   && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
-{
-  return rs6000_call_template (operands, 1, "(%3@tlsgd)");
-}
-  [(set_attr "type" "branch")
-   (set_attr "length" "8")])
-
-(define_insn "*tls_gd_call_sysv<bits>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2)))
-   (unspec:P [(match_operand:P 3 "rs6000_tls_symbol_ref" "")]
-	     UNSPEC_TLSGD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
-{
-  return rs6000_call_template (operands, 1, "(%3@tlsgd)");
-}
-  [(set_attr "type" "branch")])
-
-(define_insn_and_split "tls_ld_aix<bits>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
-	      (match_operand 3)))
-   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
-	     UNSPEC_TLSLD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
-{
-  if (TARGET_CMODEL != CMODEL_SMALL)
-    output_asm_insn ("addis %0,%1,%&@got@tlsld@ha\;"
-		     "addi %0,%0,%&@got@tlsld@l", operands);
-  else
-    output_asm_insn ("addi %0,%1,%&@got@tlsld", operands);
-  return rs6000_call_template (operands, 2, "");
-}
-  "&& TARGET_TLS_MARKERS"
-  [(set (match_dup 0)
-	(unspec:P [(match_dup 1)]
-		  UNSPEC_TLSLD))
-   (parallel [(set (match_dup 0)
-		   (call (mem:SI (match_dup 2))
-			 (match_dup 3)))
-	      (unspec:P [(const_int 0)] UNSPEC_TLSLD)
-	      (clobber (reg:SI LR_REGNO))])]
-  ""
-  [(set_attr "type" "two")
-   (set (attr "length")
-     (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
-		   (const_int 16)
-		   (const_int 12)))])
-
-(define_insn_and_split "tls_ld_sysv<mode>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 2 "symbol_ref_operand" "s"))
-	      (match_operand 3)))
-   (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
-	     UNSPEC_TLSLD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4"
-{
-  output_asm_insn ("addi %0,%1,%&@got@tlsld", operands);
-  return rs6000_call_template (operands, 2, "");
-}
-  "&& TARGET_TLS_MARKERS"
-  [(set (match_dup 0)
-	(unspec:P [(match_dup 1)]
-		  UNSPEC_TLSLD))
-   (parallel [(set (match_dup 0)
-		   (call (mem:SI (match_dup 2))
-			 (match_dup 3)))
-	      (unspec:P [(const_int 0)] UNSPEC_TLSLD)
-	      (clobber (reg:SI LR_REGNO))])]
-  ""
-  [(set_attr "length" "8")])
-
 (define_insn_and_split "*tls_ld<bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
 	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
@@ -9616,12 +9509,12 @@ (define_insn_and_split "*tls_ld<bits>"
   "&& TARGET_CMODEL != CMODEL_SMALL"
   [(set (match_dup 2)
 	(high:P
-	    (unspec:P [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))
+	    (unspec:P [(match_dup 1)] UNSPEC_TLSLD)))
    (set (match_dup 0)
 	(lo_sum:P (match_dup 2)
-	    (unspec:P [(const_int 0) (match_dup 1)] UNSPEC_TLSLD)))]
+	    (unspec:P [(match_dup 1)] UNSPEC_TLSLD)))]
 {
-  operands[2] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
+  operands[2] = gen_reg_rtx (<MODE>mode);
 }
   [(set (attr "length")
      (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
@@ -9631,8 +9524,7 @@ (define_insn_and_split "*tls_ld<bits>"
 (define_insn "*tls_ld_high<bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
      (high:P
-       (unspec:P [(const_int 0)
-		  (match_operand:P 1 "gpc_reg_operand" "b")]
+       (unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")]
 		 UNSPEC_TLSLD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addis %0,%1,%&@got@tlsld@ha")
@@ -9640,38 +9532,11 @@ (define_insn "*tls_ld_high<bits>"
 (define_insn "*tls_ld_low<bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
      (lo_sum:P (match_operand:P 1 "gpc_reg_operand" "b")
-       (unspec:P [(const_int 0)
-		  (match_operand:P 2 "gpc_reg_operand" "b")]
+       (unspec:P [(match_operand:P 2 "gpc_reg_operand" "b")]
 		 UNSPEC_TLSLD)))]
   "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
   "addi %0,%1,%&@got@tlsld@l")
 
-(define_insn "*tls_ld_call_aix<bits>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2)))
-   (unspec:P [(const_int 0)] UNSPEC_TLSLD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && TARGET_TLS_MARKERS
-   && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)"
-{
-  return rs6000_call_template (operands, 1, "(%&@tlsld)");
-}
-  [(set_attr "type" "branch")
-   (set_attr "length" "8")])
-
-(define_insn "*tls_ld_call_sysv<bits>"
-  [(set (match_operand:P 0 "gpc_reg_operand" "=b")
-        (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s"))
-	      (match_operand 2)))
-   (unspec:P [(const_int 0)] UNSPEC_TLSLD)
-   (clobber (reg:SI LR_REGNO))]
-  "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS"
-{
-  return rs6000_call_template (operands, 1, "(%&@tlsld)");
-}
-  [(set_attr "type" "branch")])
-
 (define_insn "tls_dtprel_<bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=r")
 	(unspec:P [(match_operand:P 1 "gpc_reg_operand" "b")
@@ -10345,7 +10210,6 @@ (define_expand "call"
 #endif
 
   gcc_assert (GET_CODE (operands[0]) == MEM);
-  gcc_assert (GET_CODE (operands[1]) == CONST_INT);
 
   operands[0] = XEXP (operands[0], 0);
 
@@ -10355,23 +10219,14 @@ (define_expand "call"
       DONE;
     }
 
-  if (GET_CODE (operands[0]) != SYMBOL_REF
-      || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[2]) & CALL_LONG) != 0))
+  if (DEFAULT_ABI == ABI_V4)
     {
-      if (INTVAL (operands[2]) & CALL_LONG)
-	operands[0] = rs6000_longcall_ref (operands[0]);
-
-      switch (DEFAULT_ABI)
-        {
-	case ABI_V4:
-	case ABI_DARWIN:
-	  operands[0] = force_reg (Pmode, operands[0]);
-	  break;
-
-	default:
-	  gcc_unreachable ();
-	}
+      rs6000_call_sysv (NULL_RTX, operands[0], operands[1], operands[2]);
+      DONE;
     }
+
+  if (GET_CODE (operands[0]) != SYMBOL_REF)
+    operands[0] = force_reg (Pmode, operands[0]);
 })
 
 (define_expand "call_value"
@@ -10388,7 +10243,6 @@ (define_expand "call_value"
 #endif
 
   gcc_assert (GET_CODE (operands[1]) == MEM);
-  gcc_assert (GET_CODE (operands[2]) == CONST_INT);
 
   operands[1] = XEXP (operands[1], 0);
 
@@ -10398,23 +10252,14 @@ (define_expand "call_value"
       DONE;
     }
 
-  if (GET_CODE (operands[1]) != SYMBOL_REF
-      || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[3]) & CALL_LONG) != 0))
+  if (DEFAULT_ABI == ABI_V4)
     {
-      if (INTVAL (operands[3]) & CALL_LONG)
-	operands[1] = rs6000_longcall_ref (operands[1]);
-
-      switch (DEFAULT_ABI)
-        {
-	case ABI_V4:
-	case ABI_DARWIN:
-	  operands[1] = force_reg (Pmode, operands[1]);
-	  break;
-
-	default:
-	  gcc_unreachable ();
-	}
+      rs6000_call_sysv (operands[0], operands[1], operands[2], operands[3]);
+      DONE;
     }
+
+  if (GET_CODE (operands[1]) != SYMBOL_REF)
+    operands[1] = force_reg (Pmode, operands[1]);
 })
 
 ;; Call to function in current module.  No TOC pointer reload needed.
@@ -10501,7 +10346,7 @@ (define_insn "*call_value_local64"
 
 ;; A function pointer under System V is just a normal pointer
 ;; operands[0] is the function pointer
-;; operands[1] is the stack size to clean up
+;; operands[1] is the tls call arg
 ;; operands[2] is the value FUNCTION_ARG returns for the VOID argument
 ;; which indicates how to set cr1
 
@@ -10552,7 +10397,7 @@ (define_insn_and_split "*call_nonlocal_sysv<mode>"
 #if TARGET_MACHO
   return macho_call_template (insn, operands, 0, 2);
 #else
-  return rs6000_call_template (operands, 0, "");
+  return rs6000_call_template (operands, 0);
 #endif
 }
   "DEFAULT_ABI == ABI_V4
@@ -10585,7 +10430,7 @@ (define_insn "*call_nonlocal_sysv_secure<mode>"
   else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  return rs6000_call_template (operands, 0, "");
+  return rs6000_call_template (operands, 0);
 }
   [(set_attr "type" "branch,branch")
    (set_attr "length" "4,8")])
@@ -10639,7 +10484,7 @@ (define_insn_and_split "*call_value_nonlocal_sysv<mode>"
 #if TARGET_MACHO
   return macho_call_template (insn, operands, 1, 3);
 #else
-  return rs6000_call_template (operands, 1, "");
+  return rs6000_call_template (operands, 1);
 #endif
 }
   "DEFAULT_ABI == ABI_V4
@@ -10674,7 +10519,7 @@ (define_insn "*call_value_nonlocal_sysv_secure<mode>"
   else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
     output_asm_insn ("creqv 6,6,6", operands);
 
-  return rs6000_call_template (operands, 1, "");
+  return rs6000_call_template (operands, 1);
 }
   [(set_attr "type" "branch,branch")
    (set_attr "length" "4,8")])
@@ -10708,7 +10553,7 @@ (define_insn "*call_nonlocal_aix<mode>"
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
-  return rs6000_call_template (operands, 0, "");
+  return rs6000_call_template (operands, 0);
 }
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
@@ -10720,7 +10565,7 @@ (define_insn "*call_value_nonlocal_aix<mode>"
    (clobber (reg:P LR_REGNO))]
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
-  return rs6000_call_template (operands, 1, "");
+  return rs6000_call_template (operands, 1);
 }
   [(set_attr "type" "branch")
    (set_attr "length" "8")])
@@ -10971,7 +10816,7 @@ (define_insn "*sibcall_nonlocal_sysv<mode>"
   if (which_alternative >= 2)
     return rs6000_indirect_sibcall_template (operands, 0);
   else
-    return rs6000_sibcall_template (operands, 0, "");
+    return rs6000_sibcall_template (operands, 0);
 }
   [(set_attr "type" "branch")
    (set_attr_alternative "length"
@@ -11011,7 +10856,7 @@ (define_insn "*sibcall_value_nonlocal_sysv<mode>"
 	return "crset 2\;beq%T1-\;b $";
     }
   else
-    return rs6000_sibcall_template (operands, 1, "");
+    return rs6000_sibcall_template (operands, 1);
 }
   [(set_attr "type" "branch")
    (set_attr_alternative "length"
@@ -11035,7 +10880,7 @@ (define_insn "*sibcall_aix<mode>"
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
   if (which_alternative == 0)
-    return rs6000_sibcall_template (operands, 0, "");
+    return rs6000_sibcall_template (operands, 0);
   else
     return "b%T0";
 }
@@ -11049,7 +10894,7 @@ (define_insn "*sibcall_value_aix<mode>"
   "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2"
 {
   if (which_alternative == 0)
-    return rs6000_sibcall_template (operands, 1, "");
+    return rs6000_sibcall_template (operands, 1);
   else
     return "b%T1";
 }


-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2018-11-29  6:11 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-07  5:33 [PATCH 0/6] [RS6000] inline plt call support Alan Modra
2018-11-07  5:37 ` [PATCH 1/6] [RS6000] rs6000_output_call for external call insn assembly output Alan Modra
2018-11-08  0:09   ` Segher Boessenkool
2018-11-08 13:21     ` Alan Modra
2018-11-07  5:38 ` [PATCH 2/6] [RS6000] rs6000_output_indirect_call Alan Modra
2018-11-12 19:44   ` Bill Schmidt
2018-11-13  0:14     ` Alan Modra
2018-11-13 11:14       ` Segher Boessenkool
2018-11-13 12:48         ` [PATCH 1/6] [RS6000] rs6000_call_template for external call insn assembly output Alan Modra
2018-11-20 15:59           ` Segher Boessenkool
2018-11-13 12:49         ` [PATCH 2/6] [RS6000] rs6000_indirect_call_template Alan Modra
2018-11-20 16:23           ` Segher Boessenkool
2018-11-13 12:50         ` [PATCH 3/6] [RS6000] Replace TLSmode with P, and correct tls call mems Alan Modra
2018-11-20 17:10           ` Segher Boessenkool
2018-11-13 12:51         ` [PATCH 4/6] [RS6000] Remove constraints on call rounded_stack_size_rtx arg Alan Modra
2018-11-27 15:27           ` Segher Boessenkool
2018-11-13 12:52         ` [PATCH 5/6] [RS6000] Use standard call patterns for __tls_get_addr calls Alan Modra
2018-11-27 16:29           ` Segher Boessenkool
2018-11-28  1:07             ` Alan Modra
2018-11-28 13:33               ` Segher Boessenkool
2018-11-28 23:08                 ` Alan Modra
2018-11-29  6:11                 ` Alan Modra
2018-11-13 12:53         ` [PATCH 6/6] [RS6000] inline plt call sequences Alan Modra
2018-11-27 17:18           ` Segher Boessenkool
2018-11-28  1:34             ` Alan Modra
2018-11-28 13:39               ` Segher Boessenkool
2018-11-07  5:38 ` [PATCH 3/6] [RS6000] Replace TLSmode with P, and correct tls call mems Alan Modra
2018-11-08  1:11   ` Segher Boessenkool
2018-11-08 13:27     ` Alan Modra
2018-11-08 18:09       ` Segher Boessenkool
2018-11-07  5:39 ` [PATCH 4/6] [RS6000] Remove constraints on call rounded_stack_size_rtx arg Alan Modra
2018-11-08  1:19   ` Segher Boessenkool
2018-11-07  5:39 ` [PATCH 5/6] [RS6000] Use standard call patterns for __tls_get_addr calls Alan Modra
2018-11-07  5:40 ` [PATCH 6/6] [RS6000] inline plt call sequences Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).