aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlya Leoshkevich <iii@linux.ibm.com>2018-09-06 07:38:42 +0000
committerAndreas Krebbel <krebbel@gcc.gnu.org>2018-09-06 07:38:42 +0000
commitbdb57bcb548f493107d0701a88da0cdcfa122e24 (patch)
tree00482d32624436f3e7a7d7285ed9b6bb98de6bf8
parentd7252499463a4fe2c073d8a28c6c0c966e20755f (diff)
downloadgcc-bdb57bcb548f493107d0701a88da0cdcfa122e24.zip
gcc-bdb57bcb548f493107d0701a88da0cdcfa122e24.tar.gz
gcc-bdb57bcb548f493107d0701a88da0cdcfa122e24.tar.bz2
S/390: Prohibit SYMBOL_REF in UNSPECV_CAS
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-06 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-06 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. From-SVN: r264143
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/config/s390/predicates.md12
-rw-r--r--gcc/config/s390/s390.c16
-rw-r--r--gcc/config/s390/s390.md6
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/gcc.target/s390/pr80080-3.c10
-rw-r--r--gcc/testsuite/gcc.target/s390/s390.exp9
7 files changed, 67 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 31f7778..0191555 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,6 +1,16 @@
2018-09-06 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.
+
+2018-09-06 Ilya Leoshkevich <iii@linux.ibm.com>
+
+ PR target/80080
* config/s390/s390-passes.def: New file.
* config/s390/s390-protos.h (class rtl_opt_pass): Add forward
declaration.
diff --git a/gcc/config/s390/predicates.md b/gcc/config/s390/predicates.md
index a5b1fcb..98a824e 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 30bf029..541b032 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 0d0f218..ddf8608 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -10338,7 +10338,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)
@@ -10356,7 +10356,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)
@@ -10377,7 +10377,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/ChangeLog b/gcc/testsuite/ChangeLog
index e22ede0..677cfcf 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2018-09-06 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.
+
2018-09-05 Marek Polacek <polacek@redhat.com>
PR c++/86982, -Wreturn-local-addr and std::move and std::forward.
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 0000000..9068b8d
--- /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 93c570a..a9c428d 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