From bdb57bcb548f493107d0701a88da0cdcfa122e24 Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Thu, 6 Sep 2018 07:38:42 +0000 Subject: [PATCH] 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 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 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 --- gcc/ChangeLog | 10 ++++++++++ gcc/config/s390/predicates.md | 12 ++++++++++++ gcc/config/s390/s390.c | 16 ++++++++++++++++ gcc/config/s390/s390.md | 6 +++--- gcc/testsuite/ChangeLog | 7 +++++++ gcc/testsuite/gcc.target/s390/pr80080-3.c | 10 ++++++++++ gcc/testsuite/gcc.target/s390/s390.exp | 9 +++++++++ 7 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.target/s390/pr80080-3.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 31f7778d63d..0191555aa90 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2018-09-06 Ilya Leoshkevich + + 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 PR target/80080 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 30bf0292d89..541b032ac63 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 0d0f2181bfd..ddf8608b2a2 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_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 e22ede07c15..677cfcf32fb 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2018-09-06 Ilya Leoshkevich + + 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 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 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.30.2