public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [RS6000] PR88614, output_operand: invalid %z value
@ 2019-01-06 22:59 Alan Modra
  2019-01-18 22:02 ` Segher Boessenkool
  0 siblings, 1 reply; 7+ messages in thread
From: Alan Modra @ 2019-01-06 22:59 UTC (permalink / raw)
  To: gcc-patches; +Cc: Segher Boessenkool

The direct cause of this PR is the fact that tls_gdld_nomark didn't
handle indirect calls.  Adding the missing support revealed that most
indirect calls were being optimised back to direct calls anyway, due
to tls_gdld_nomark not checking any of the parallel elements except
the first (plus the extra element that distinguishes this call from
normal calls).  Just checking the number of elements is enough to
separate the indirect calls from direct for ABI_ELFv2 and ABI_AIX,
while checking for the LONG_CALL bit in the cookie works for ABI_V4.
Direct calls being substituted for indirect calls is not the only
unwanted substitution.  See the tls_nomark_call comment.  I also saw a
_GLOBAL_OFFSET_TABLE_ symbol_ref being substituted for the GOT reg,
hence the unspec_tls change.

Bootstrap and regression testing on powerpc64le-linux and
powerpc64-linux in progress.  Note that the patch requires
https://gcc.gnu.org/ml/gcc-patches/2019-01/msg00252.html or the
earlier version for the attribute support.

	PR 88614
	* config/rs6000/predicates.md (unspec_tls): Ensure GOT reg
	stays a reg.
	(tls_nomark_call): New.
	* config/rs6000/rs6000.c (rs6000_call_sysv): Generate sysv4 secure
	plt call pattern here..
	* config/rs6000/rs6000.md (call_nonlocal_sysv): ..rather than here,
	delete split..
	(call_value_nonlocal_sysv): ..or here, delete split.
	(tls_gdld_nomark): Use tls_nomark_call predicate.  Set up operands
	for indirect calls and correct length attr.

diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index 21791c51f2f..246452879a8 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -988,7 +988,12 @@ (define_predicate "rs6000_tls_symbol_ref"
 (define_predicate "unspec_tls"
   (match_code "unspec")
 {
-  return XINT (op, 1) == UNSPEC_TLSGD || XINT (op, 1) == UNSPEC_TLSLD;
+  if (XINT (op, 1) == UNSPEC_TLSGD)
+    return REG_P (XVECEXP (op, 0, 1));
+  else if (XINT (op, 1) == UNSPEC_TLSLD)
+    return REG_P (XVECEXP (op, 0, 0));
+  else
+    return 0;
 })
 
 ;; Return 1 if the operand, used inside a MEM, is a valid first argument
@@ -1018,6 +1023,86 @@ (define_predicate "indirect_call_operand"
   return false;
 })
 
+;; Verify that elements of the tls_gdld_nomark call insn parallel past the
+;; second element (added to distinguish this call from normal calls) match
+;; the normal contours of a call insn.  This is necessary to prevent
+;; substitutions we don't want, for example, an indirect call being
+;; optimised to a direct call, or (set (reg:r2) (unspec [] UNSPEC_TOCSLOT))
+;; being cleverly optimised to (set (reg:r2) (reg:r2)) because gcc
+;; "knows" that r2 hasn't changed from a previous call.
+(define_predicate "tls_nomark_call"
+  (match_code "parallel")
+{
+  int n = XVECLEN (op, 0);
+  rtvec v = XVEC (op, 0);
+  rtx set = RTVEC_ELT (v, 0);
+  if (GET_CODE (set) != SET)
+    return 0;
+  rtx call = XEXP (set, 1);
+  if (GET_CODE (call) != CALL)
+    return 0;
+  rtx mem = XEXP (call, 0);
+  if (GET_CODE (mem) != MEM)
+    return 0;
+  rtx addr = XEXP (mem, 0);
+  if (GET_CODE (addr) == SYMBOL_REF)
+    {
+      if (DEFAULT_ABI == ABI_ELFv2 || DEFAULT_ABI == ABI_AIX)
+	return (n == 3 && GET_CODE (RTVEC_ELT (v, 2)) == CLOBBER
+		&& REG_P (XEXP (RTVEC_ELT (v, 2), 0))
+		&& REGNO (XEXP (RTVEC_ELT (v, 2), 0)) == LR_REGNO);
+      else if (DEFAULT_ABI == ABI_V4)
+	return (n >= 4 && n <= 5 && GET_CODE (RTVEC_ELT (v, 2)) == USE
+		&& CONST_INT_P (XEXP (RTVEC_ELT (v, 2), 0))
+		&& (INTVAL (XEXP (RTVEC_ELT (v, 2), 0)) & CALL_LONG) == 0
+		&& (n == 4
+		    || (GET_CODE (RTVEC_ELT (v, 3)) == USE
+			&& REG_P (XEXP (RTVEC_ELT (v, 3), 0))))
+		&& GET_CODE (RTVEC_ELT (v, n - 1)) == CLOBBER
+		&& REG_P (XEXP (RTVEC_ELT (v, n - 1), 0))
+		&& REGNO (XEXP (RTVEC_ELT (v, n - 1), 0)) == LR_REGNO);
+      else
+	gcc_unreachable ();
+    }
+  else if (indirect_call_operand (addr, mode))
+    {
+      if (DEFAULT_ABI == ABI_ELFv2)
+	return (n == 4 && GET_CODE (RTVEC_ELT (v, 2)) == SET
+		&& REG_P (XEXP (RTVEC_ELT (v, 2), 0))
+		&& REGNO (XEXP (RTVEC_ELT (v, 2), 0)) == TOC_REGNUM
+		&& GET_CODE (XEXP (RTVEC_ELT (v, 2), 1)) == UNSPEC
+		&& XINT (XEXP (RTVEC_ELT (v, 2), 1), 1) == UNSPEC_TOCSLOT
+		&& XVECLEN (XEXP (RTVEC_ELT (v, 2), 1), 0) == 1
+		&& CONST_INT_P (XVECEXP (XEXP (RTVEC_ELT (v, 2), 1), 0, 0))
+		&& GET_CODE (RTVEC_ELT (v, 3)) == CLOBBER
+		&& REG_P (XEXP (RTVEC_ELT (v, 3), 0))
+		&& REGNO (XEXP (RTVEC_ELT (v, 3), 0)) == LR_REGNO);
+      else if (DEFAULT_ABI == ABI_AIX)
+	return (n == 5 && GET_CODE (RTVEC_ELT (v, 2)) == USE
+		&& GET_CODE (XEXP (RTVEC_ELT (v, 2), 0)) == MEM
+		&& GET_CODE (RTVEC_ELT (v, 3)) == SET
+		&& REG_P (XEXP (RTVEC_ELT (v, 3), 0))
+		&& REGNO (XEXP (RTVEC_ELT (v, 3), 0)) == TOC_REGNUM
+		&& GET_CODE (XEXP (RTVEC_ELT (v, 3), 1)) == UNSPEC
+		&& XINT (XEXP (RTVEC_ELT (v, 3), 1), 1) == UNSPEC_TOCSLOT
+		&& XVECLEN (XEXP (RTVEC_ELT (v, 3), 1), 0) == 1
+		&& CONST_INT_P (XVECEXP (XEXP (RTVEC_ELT (v, 3), 1), 0, 0))
+		&& GET_CODE (RTVEC_ELT (v, 4)) == CLOBBER
+		&& REG_P (XEXP (RTVEC_ELT (v, 4), 0))
+		&& REGNO (XEXP (RTVEC_ELT (v, 4), 0)) == LR_REGNO);
+      else if (DEFAULT_ABI == ABI_V4)
+	return (n == 4 && GET_CODE (RTVEC_ELT (v, 2)) == USE
+		&& CONST_INT_P (XEXP (RTVEC_ELT (v, 2), 0))
+		&& GET_CODE (RTVEC_ELT (v, 3)) == CLOBBER
+		&& REG_P (XEXP (RTVEC_ELT (v, 3), 0))
+		&& REGNO (XEXP (RTVEC_ELT (v, 3), 0)) == LR_REGNO);
+      else
+	gcc_unreachable ();
+    }
+  else
+    return 0;
+})
+
 ;; 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.c b/gcc/config/rs6000/rs6000.c
index a25755418ea..4e3c5fc135f 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -37918,9 +37918,10 @@ rs6000_call_sysv (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
 {
   rtx func = func_desc;
   rtx func_addr;
-  rtx call[3];
+  rtx call[4];
   rtx insn;
   rtx abi_reg = NULL_RTX;
+  int n;
 
   if (global_tlsarg)
     tlsarg = global_tlsarg;
@@ -37968,9 +37969,16 @@ rs6000_call_sysv (rtx value, rtx func_desc, rtx tlsarg, rtx cookie)
     call[0] = gen_rtx_SET (value, call[0]);
 
   call[1] = gen_rtx_USE (VOIDmode, cookie);
-  call[2] = gen_hard_reg_clobber (Pmode, LR_REGNO);
+  n = 2;
+  if (TARGET_SECURE_PLT
+      && flag_pic
+      && GET_CODE (func_addr) == SYMBOL_REF
+      && !SYMBOL_REF_LOCAL_P (func_addr))
+    call[n++] = gen_rtx_USE (VOIDmode, pic_offset_table_rtx);
 
-  insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (3, call));
+  call[n++] = gen_hard_reg_clobber (Pmode, LR_REGNO);
+
+  insn = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (n, call));
   insn = emit_call_insn (insn);
   if (abi_reg)
     use_reg (&CALL_INSN_FUNCTION_USAGE (insn), abi_reg);
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 56364e0e43b..0d5ef31f9f2 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -9443,7 +9443,7 @@ (define_peephole2
 ;; TLS support.
 
 (define_insn "*tls_gdld_nomark<bits>"
-  [(match_parallel 3 ""
+  [(match_parallel 3 "tls_nomark_call"
     [(set (match_operand:P 0 "gpc_reg_operand" "=b")
 	  (call (mem:SI (match_operand:P 1))
 		(match_operand:P 2 "unspec_tls")))
@@ -9470,15 +9470,43 @@ (define_insn "*tls_gdld_nomark<bits>"
       else
 	output_asm_insn ("addi %0,%1,%&@got@tlsld", op);
     }
-  return rs6000_call_template (operands, 1);
+  if (GET_CODE (operands[1]) == SYMBOL_REF)
+    return rs6000_call_template (operands, 1);
+
+  /* Indirect calls need to recog a few more operands.  See the various
+     call_value_indirect patterns, and note that edit_tls_call_insn
+     added an extra element to the parallel.  */
+  rtx par = operands[3];
+  rtvec v = XVEC (par, 0);
+  if (DEFAULT_ABI == ABI_ELFv2)
+    operands[3] = XVECEXP (XEXP (RTVEC_ELT (v, 2), 1), 0, 0);
+  else if (DEFAULT_ABI == ABI_AIX)
+    {
+      operands[3] = XEXP (RTVEC_ELT (v, 2), 0);
+      operands[4] = XVECEXP (XEXP (RTVEC_ELT (v, 3), 1), 0, 0);
+    }
+  else if (DEFAULT_ABI == ABI_V4)
+    operands[3] = XEXP (RTVEC_ELT (v, 2), 0);
+  else
+    gcc_unreachable ();
+  return rs6000_indirect_call_template (operands, 1);
 }
   [(set_attr "type" "two")
    (set (attr "length")
-     (cond [(match_test "TARGET_CMODEL != CMODEL_SMALL")
-		(const_int 16)
-	    (match_test "DEFAULT_ABI != ABI_V4")
-		(const_int 12)]
-	(const_int 8)))])
+     (plus (if_then_else (match_test "TARGET_CMODEL != CMODEL_SMALL")
+			 (const_int 8)
+			 (const_int 4))
+	   (plus (if_then_else (match_test "GET_CODE (operands[1]) != SYMBOL_REF")
+			       (plus (if_then_else (match_test "!rs6000_speculate_indirect_jumps")
+						   (const_int 4)
+						   (const_int 0))
+				     (if_then_else (match_test "DEFAULT_ABI == ABI_AIX")
+						   (const_int 4)
+						   (const_int 0)))
+			       (const_int 0))
+		 (if_then_else (match_test "DEFAULT_ABI != ABI_V4")
+			       (const_int 8)
+			       (const_int 4)))))])
 
 (define_insn_and_split "*tls_gd<bits>"
   [(set (match_operand:P 0 "gpc_reg_operand" "=b")
@@ -10440,7 +10468,7 @@ (define_insn "*call_indirect_nonlocal_sysv<mode>"
 		  (const_string "8")]
 	      (const_string "4")))])
 
-(define_insn_and_split "*call_nonlocal_sysv<mode>"
+(define_insn "*call_nonlocal_sysv<mode>"
   [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s"))
 	 (match_operand 1))
    (use (match_operand:SI 2 "immediate_operand" "O,n"))
@@ -10456,17 +10484,6 @@ (define_insn_and_split "*call_nonlocal_sysv<mode>"
     output_asm_insn ("creqv 6,6,6", operands);
 
   return rs6000_call_template (operands, 0);
-}
-  "DEFAULT_ABI == ABI_V4
-   && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[0])
-   && (INTVAL (operands[2]) & CALL_LONG) == 0"
-  [(parallel [(call (mem:SI (match_dup 0))
-		    (match_dup 1))
-	      (use (match_dup 2))
-	      (use (match_dup 3))
-	      (clobber (reg:SI LR_REGNO))])]
-{
-  operands[3] = pic_offset_table_rtx;
 }
   [(set_attr "type" "branch,branch")
    (set_attr "length" "4,8")])
@@ -10521,7 +10538,7 @@ (define_insn "*call_value_indirect_nonlocal_sysv<mode>"
 		  (const_string "8")]
 	      (const_string "4")))])
 
-(define_insn_and_split "*call_value_nonlocal_sysv<mode>"
+(define_insn "*call_value_nonlocal_sysv<mode>"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s"))
 	      (match_operand 2)))
@@ -10538,18 +10555,6 @@ (define_insn_and_split "*call_value_nonlocal_sysv<mode>"
     output_asm_insn ("creqv 6,6,6", operands);
 
   return rs6000_call_template (operands, 1);
-}
-  "DEFAULT_ABI == ABI_V4
-   && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[1])
-   && (INTVAL (operands[3]) & CALL_LONG) == 0"
-  [(parallel [(set (match_dup 0)
-		   (call (mem:SI (match_dup 1))
-			 (match_dup 2)))
-	      (use (match_dup 3))
-	      (use (match_dup 4))
-	      (clobber (reg:SI LR_REGNO))])]
-{
-  operands[4] = pic_offset_table_rtx;
 }
   [(set_attr "type" "branch,branch")
    (set_attr "length" "4,8")])

-- 
Alan Modra
Australia Development Lab, IBM

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

end of thread, other threads:[~2019-01-22  0:35 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-06 22:59 [RS6000] PR88614, output_operand: invalid %z value Alan Modra
2019-01-18 22:02 ` Segher Boessenkool
2019-01-20 13:38   ` Alan Modra
2019-01-21 12:19     ` Alan Modra
2019-01-21 14:23       ` Segher Boessenkool
2019-01-22  0:30         ` Alan Modra
2019-01-22  0:35           ` Segher Boessenkool

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).