[PATCH] S/390: Prohibit SYMBOL_REF in UNSPECV_CAS

Ilya Leoshkevich iii@linux.ibm.com
Wed Sep 5 20:22:00 GMT 2018


Inhibit constant propagation inlining SYMBOL_REF loads into
UNSPECV_CAS.  Even though reload can later undo it, the resulting
code will be less efficient.

gcc/ChangeLog:

2018-09-05  Ilya Leoshkevich  <iii@linux.ibm.com>

	PR target/80080
	* config/s390/predicates.md: Add nonsym_memory_operand.
	* config/s390/s390.c (s390_legitimize_cs_operand): If operand
	contains a SYMBOL_REF, load it into an intermediate pseudo.
	(s390_emit_compare_and_swap): Legitimize operand.
	* config/s390/s390.md: Use the new nonsym_memory_operand
	with UNSPECV_CAS patterns.

gcc/testsuite/ChangeLog:

2018-09-05  Ilya Leoshkevich  <iii@linux.ibm.com>

	PR target/80080
	* gcc.target/s390/pr80080-3.c: New test.
	* gcc.target/s390/s390.exp: Make sure the new test passes
	on all optimization levels.
---
 gcc/config/s390/predicates.md             | 12 ++++++++++++
 gcc/config/s390/s390.c                    | 16 ++++++++++++++++
 gcc/config/s390/s390.md                   |  6 +++---
 gcc/testsuite/gcc.target/s390/pr80080-3.c | 10 ++++++++++
 gcc/testsuite/gcc.target/s390/s390.exp    |  9 +++++++++
 5 files changed, 50 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/s390/pr80080-3.c

diff --git a/gcc/config/s390/predicates.md b/gcc/config/s390/predicates.md
index a5b1fcbdd15..98a824e77b7 100644
--- a/gcc/config/s390/predicates.md
+++ b/gcc/config/s390/predicates.md
@@ -534,3 +534,15 @@
   unsigned HOST_WIDE_INT val = INTVAL (op);
   return val <= 128 && val % 8 == 0;
 })
+
+;; Certain operations (e.g. CS) cannot access SYMBOL_REF directly, it needs to
+;; be loaded into some register first.  In theory, if we put a SYMBOL_REF into
+;; a corresponding insn anyway, reload will generate a load for it, but, when
+;; coupled with constant propagation, this will lead to an inefficient code
+;; (see PR 80080).
+
+(define_predicate "nonsym_memory_operand"
+  (match_code "mem")
+{
+  return memory_operand (op, mode) && !contains_symbol_ref_p (op);
+})
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 5c2a8cb2c6c..39fb99e885a 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -1825,6 +1825,21 @@ s390_emit_compare (enum rtx_code code, rtx op0, rtx op1)
   return gen_rtx_fmt_ee (code, VOIDmode, cc, const0_rtx);
 }
 
+/* If MEM is not a legitimate compare-and-swap memory operand, return a new
+   MEM, whose address is a pseudo containing the original MEM's address.  */
+
+static rtx
+s390_legitimize_cs_operand (rtx mem)
+{
+  rtx tmp;
+
+  if (!contains_symbol_ref_p (mem))
+    return mem;
+  tmp = gen_reg_rtx (Pmode);
+  emit_move_insn (tmp, copy_rtx (XEXP (mem, 0)));
+  return change_address (mem, VOIDmode, tmp);
+}
+
 /* Emit a SImode compare and swap instruction setting MEM to NEW_RTX if OLD
    matches CMP.
    Return the correct condition RTL to be placed in the IF_THEN_ELSE of the
@@ -1836,6 +1851,7 @@ s390_emit_compare_and_swap (enum rtx_code code, rtx old, rtx mem,
 {
   rtx cc;
 
+  mem = s390_legitimize_cs_operand (mem);
   cc = gen_rtx_REG (ccmode, CC_REGNUM);
   switch (GET_MODE (mem))
     {
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index db260e41bfd..0a535eb8328 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -10339,7 +10339,7 @@
 ; cdsg, csg
 (define_insn "*atomic_compare_and_swap<mode>_1"
   [(set (match_operand:TDI 0 "register_operand" "=r")
-	(match_operand:TDI 1 "memory_operand" "+S"))
+	(match_operand:TDI 1 "nonsym_memory_operand" "+S"))
    (set (match_dup 1)
 	(unspec_volatile:TDI
 	  [(match_dup 1)
@@ -10357,7 +10357,7 @@
 ; cds, cdsy
 (define_insn "*atomic_compare_and_swapdi_2"
   [(set (match_operand:DI 0 "register_operand" "=r,r")
-	(match_operand:DI 1 "memory_operand" "+Q,S"))
+	(match_operand:DI 1 "nonsym_memory_operand" "+Q,S"))
    (set (match_dup 1)
 	(unspec_volatile:DI
 	  [(match_dup 1)
@@ -10378,7 +10378,7 @@
 ; cs, csy
 (define_insn "*atomic_compare_and_swapsi_3"
   [(set (match_operand:SI 0 "register_operand" "=r,r")
-	(match_operand:SI 1 "memory_operand" "+Q,S"))
+	(match_operand:SI 1 "nonsym_memory_operand" "+Q,S"))
    (set (match_dup 1)
 	(unspec_volatile:SI
 	  [(match_dup 1)
diff --git a/gcc/testsuite/gcc.target/s390/pr80080-3.c b/gcc/testsuite/gcc.target/s390/pr80080-3.c
new file mode 100644
index 00000000000..9068b8d30c2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/pr80080-3.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=z10" } */
+
+extern int foo3_mem;
+int foo3 (void)
+{
+  return __atomic_exchange_n (&foo3_mem, 5, __ATOMIC_ACQUIRE);
+}
+
+/* { dg-final { scan-assembler "\n\(\\.L\\d+):\n\tcs\t.*\n\tjne\t\\1\n" } } */
diff --git a/gcc/testsuite/gcc.target/s390/s390.exp b/gcc/testsuite/gcc.target/s390/s390.exp
index 93c570af2a6..a9c428d65ce 100644
--- a/gcc/testsuite/gcc.target/s390/s390.exp
+++ b/gcc/testsuite/gcc.target/s390/s390.exp
@@ -252,5 +252,14 @@ set-torture-options $MD_TEST_OPTS
 gcc-dg-runtest [lsort [glob -nocomplain $md_tests]] "" "$DEFAULT_CFLAGS"
 torture-finish
 
+# Tests that should pass on all optimization levels.
+foreach t [list $srcdir/$subdir/pr80080-3.c] {
+	torture-init
+	set-torture-options [list -O1 -O2 -O3 -O0 -Os -Ofast -Og]
+	gcc-dg-runtest [list $t] \
+		"" $DEFAULT_CFLAGS
+	torture-finish
+}
+
 # All done.
 dg-finish
-- 
2.18.0



More information about the Gcc-patches mailing list