S/390: Prohibit SYMBOL_REF in UNSPECV_CAS
authorIlya Leoshkevich <iii@linux.ibm.com>
Thu, 6 Sep 2018 07:38:42 +0000 (07:38 +0000)
committerAndreas Krebbel <krebbel@gcc.gnu.org>
Thu, 6 Sep 2018 07:38:42 +0000 (07:38 +0000)
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

gcc/ChangeLog
gcc/config/s390/predicates.md
gcc/config/s390/s390.c
gcc/config/s390/s390.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/s390/pr80080-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/s390/s390.exp

index 31f7778d63d6c9df4ecb923921369a05c3ff54e6..0191555aa9033f9542738877c6041079bf51b4b3 100644 (file)
@@ -1,3 +1,13 @@
+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
index a5b1fcbdd15d0f63fffdfed0f495434689023f38..98a824e77b7742096ea24ca3844d9c881984c196 100644 (file)
   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);
+})
index 30bf0292d8921b0bd123923eb2ee94c0254432e2..541b032ac639df2043221793e3f497af660d82e5 100644 (file)
@@ -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))
     {
index 0d0f2181bfd182f6cff6617799a20282be832a0f..ddf8608b2a2e6b2dce93feb341288f9ed1cf7dcf 100644 (file)
 ; 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)
 ; 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)
 ; 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)
index e22ede07c1507e4862fb01df2f54ee2fa7801d4e..677cfcf32fb5a9cc5f05d02c9973fe49f625b9b0 100644 (file)
@@ -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 (file)
index 0000000..9068b8d
--- /dev/null
@@ -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" } } */
index 93c570af2a61a1f519fd24b23d94303d861340fc..a9c428d65ced8c9b7b8b8986f9de9c30964181ee 100644 (file)
@@ -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