From: Stefan Schulze Frielinghaus <[email protected]>

Logical operations like *x &= -10 may be folded to a single
storage-and-immediate instruction NI which accesses only the least
significant byte of *x.

Similarly but still distinct operations like *x &= *y may be implemented
via storage-and-storage instruction NC which loads and stores one byte
after another of operands.

Since volatile objects must be accessed by a single load/store of the
entire object, those optimizations must be rejected in case of volatile
memory operands.  An exception to this are 16-byte load/stores which are
implemented by two operations (in case of non-atomic operands).

Previously, multi-letter constraints A[QRST] were intended to reject
volatile memory operands.  However, during LRA, if a memory constraint
is not satisfiable, as a last resort, LRA tries reloading the address.
This, of course, doesn't fix the issue and during checking we finally
bail out in case of a winning alternative.

Fixed by enforcing non-volatile memory operands via conditions of
instruction patterns which is done in s390_logical_operator_ok_p() for
all AND/IOR/XOR instructions by this patch.  By removing the volatile
check in constraints A[QRST] this fixes tests
gcc.dg/torture/float128-basic.c, float64x-basic.c,
fp-int-convert-float128-ieee.c, fp-int-convert-float64x.c,
fp-int-convert-long-double.c which started failing after r16-5947.

gcc/ChangeLog:

        * config/s390/s390.cc (s390_logical_operator_ok_p): Test for
        volatile memory.
        (s390_mem_constraint): Remove volatile condition.
        * config/s390/s390.md (*andc_split_<mode>): Test for volatile
        memory.

gcc/testsuite/ChangeLog:

        * gcc.target/s390/narrow-logical-op-1.c: New test.
---
 gcc/config/s390/s390.cc                       |  18 +-
 gcc/config/s390/s390.md                       |   2 +-
 .../gcc.target/s390/narrow-logical-op-1.c     | 497 ++++++++++++++++++
 3 files changed, 512 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/s390/narrow-logical-op-1.c

diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc
index 88827ca6170..28a025be4e8 100644
--- a/gcc/config/s390/s390.cc
+++ b/gcc/config/s390/s390.cc
@@ -3054,9 +3054,19 @@ s390_logical_operator_ok_p (rtx *operands)
   /* If the destination operand is in memory, it needs to coincide
      with one of the source operands.  After reload, it has to be
      the first source operand.  */
-  if (GET_CODE (operands[0]) == MEM)
-    return rtx_equal_p (operands[0], operands[1])
-          || (!reload_completed && rtx_equal_p (operands[0], operands[2]));
+  if (MEM_P (operands[0]))
+    {
+      /* Volatile loads/stores must be implemented via a single access of the
+        entire object.  Therefore, do not fold operations into instructions
+        like NI or NC.  */
+      if (GET_MODE (operands[0]) != QImode
+         && (MEM_VOLATILE_P (operands[0])
+             || (MEM_P (operands[1]) && MEM_VOLATILE_P (operands[1]))
+             || (MEM_P (operands[2]) && MEM_VOLATILE_P (operands[2]))))
+       return false;
+      return rtx_equal_p (operands[0], operands[1])
+            || (!reload_completed && rtx_equal_p (operands[0], operands[2]));
+    }
 
   return true;
 }
@@ -3700,7 +3710,7 @@ s390_mem_constraint (const char *str, rtx op)
     {
     case 'A':
       /* Check for offsettable variants of memory constraints.  */
-      if (!MEM_P (op) || MEM_VOLATILE_P (op))
+      if (!MEM_P (op))
        return 0;
       if ((reload_completed || reload_in_progress)
          ? !offsettable_memref_p (op) : !offsettable_nonstrict_memref_p (op))
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index c6fa6db3eca..21730950ede 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -8345,7 +8345,7 @@
    && (GET_CODE (operands[0]) != MEM
       /* Ensure that s390_logical_operator_ok_p will succeed even
         on the split xor if (b & a) is stored into a pseudo.  */
-       || rtx_equal_p (operands[0], operands[2]))"
+       || (rtx_equal_p (operands[0], operands[2]) && !MEM_VOLATILE_P 
(operands[0])))"
   "#"
   "&& 1"
   [
diff --git a/gcc/testsuite/gcc.target/s390/narrow-logical-op-1.c 
b/gcc/testsuite/gcc.target/s390/narrow-logical-op-1.c
new file mode 100644
index 00000000000..d69509f6ad1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/narrow-logical-op-1.c
@@ -0,0 +1,497 @@
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-O2 -march=z9-109" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+
+
+/************************************
+ * Storage-and-Immediate Operations *
+ ************************************/
+
+
+
+/*
+** and_char:
+**     ni      0\(%r2\),246
+**     br      %r14
+*/
+void and_char (char *x) { *x &= -10; }
+
+/*
+** and_char_v:
+**     ni      0\(%r2\),246
+**     br      %r14
+*/
+void and_char_v (volatile char *x) { *x &= -10; }
+
+/*
+** and_short:
+**     ni      1\(%r2\),246
+**     br      %r14
+*/
+void and_short (short *x) { *x &= -10; }
+
+/*
+** and_short_v:
+**     lh      (%r[0-9]+),0\(%r2\)
+**     nill    \1,65526
+**     sth     \1,0\(%r2\)
+**     br      %r14
+*/
+void and_short_v (volatile short *x) { *x &= -10; }
+
+/*
+** and_int:
+**     ni      3\(%r2\),246
+**     br      %r14
+*/
+void and_int (int *x) { *x &= -10; }
+
+/*
+** and_int_v:
+**     l       (%r[0-9]+),0\(%r2\)
+**     nill    \1,65526
+**     st      \1,0\(%r2\)
+**     br      %r14
+*/
+void and_int_v (volatile int *x) { *x &= -10; }
+
+/*
+** and_long:
+**     ni      7\(%r2\),246
+**     br      %r14
+*/
+void and_long (long *x) { *x &= -10; }
+
+/*
+** and_long_v:
+**     lg      (%r[0-9]+),0\(%r2\)
+**     nill    \1,65526
+**     stg     \1,0\(%r2\)
+**     br      %r14
+*/
+void and_long_v (volatile long *x) { *x &= -10; }
+
+/*
+** ior_char:
+**     oi      0\(%r2\),10
+**     br      %r14
+*/
+void ior_char (char *x) { *x |= 10; }
+
+/*
+** ior_char_v:
+**     oi      0\(%r2\),10
+**     br      %r14
+*/
+void ior_char_v (volatile char *x) { *x |= 10; }
+
+/*
+** ior_short:
+**     oi      1\(%r2\),10
+**     br      %r14
+*/
+void ior_short (short *x) { *x |= 10; }
+
+/*
+** ior_short_v:
+**     lh      (%r[0-9]+),0\(%r2\)
+**     oill    \1,10
+**     sth     \1,0\(%r2\)
+**     br      %r14
+*/
+void ior_short_v (volatile short *x) { *x |= 10; }
+
+/*
+** ior_int:
+**     oi      3\(%r2\),10
+**     br      %r14
+*/
+void ior_int (int *x) { *x |= 10; }
+
+/*
+** ior_int_v:
+**     l       (%r[0-9]+),0\(%r2\)
+**     oill    \1,10
+**     st      \1,0\(%r2\)
+**     br      %r14
+*/
+void ior_int_v (volatile int *x) { *x |= 10; }
+
+/*
+** ior_long:
+**     oi      7\(%r2\),10
+**     br      %r14
+*/
+void ior_long (long *x) { *x |= 10; }
+
+/*
+** ior_long_v:
+**     lg      (%r[0-9]+),0\(%r2\)
+**     oill    \1,10
+**     stg     \1,0\(%r2\)
+**     br      %r14
+*/
+void ior_long_v (volatile long *x) { *x |= 10; }
+
+/*
+** xor_char:
+**     xi      0\(%r2\),10
+**     br      %r14
+*/
+void xor_char (char *x) { *x ^= 10; }
+
+/*
+** xor_char_v:
+**     xi      0\(%r2\),10
+**     br      %r14
+*/
+void xor_char_v (volatile char *x) { *x ^= 10; }
+
+/*
+** xor_short:
+**     xi      1\(%r2\),10
+**     br      %r14
+*/
+void xor_short (short *x) { *x ^= 10; }
+
+/*
+** xor_short_v:
+**     lh      (%r[0-9]+),0\(%r2\)
+**     xilf    \1,10
+**     sth     \1,0\(%r2\)
+**     br      %r14
+*/
+void xor_short_v (volatile short *x) { *x ^= 10; }
+
+/*
+** xor_int:
+**     xi      3\(%r2\),10
+**     br      %r14
+*/
+void xor_int (int *x) { *x ^= 10; }
+
+/*
+** xor_int_v:
+**     l       (%r[0-9]+),0\(%r2\)
+**     xilf    \1,10
+**     st      \1,0\(%r2\)
+**     br      %r14
+*/
+void xor_int_v (volatile int *x) { *x ^= 10; }
+
+/*
+** xor_long:
+**     xi      7\(%r2\),10
+**     br      %r14
+*/
+void xor_long (long *x) { *x ^= 10; }
+
+/*
+** xor_long_v:
+**     lg      (%r[0-9]+),0\(%r2\)
+**     xilf    \1,10
+**     stg     \1,0\(%r2\)
+**     br      %r14
+*/
+void xor_long_v (volatile long *x) { *x ^= 10; }
+
+
+
+/**********************************
+ * Storage-and-Storage Operations *
+ **********************************/
+
+/* <OP>_<TYPE>_v0 zero volatile operands
+   <OP>_<TYPE>_v1 first operand is volatile
+   <OP>_<TYPE>_v2 second operand is volatile */
+
+
+
+/*
+** and_char_v0:
+**     nc      0\(1,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void and_char_v0 (char *x, char *y) { *x &= *y; }
+
+/*
+** and_char_v1:
+**     nc      0\(1,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void and_char_v1 (volatile char *x, char *y) { *x &= *y; }
+
+/*
+** and_char_v2:
+**     nc      0\(1,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void and_char_v2 (char *x, volatile char *y) { *x &= *y; }
+
+/*
+** and_short_v0:
+**     nc      0\(2,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void and_short_v0 (short *x, short *y) { *x &= *y; }
+
+/*
+** and_short_v1:
+**     lh      %r[0-9]+,0\(%r[23]\)
+**     lh      %r[0-9]+,0\(%r[23]\)
+**     nr      (%r[0-9]+),%r[0-9]+
+**     sth     \1,0\(%r2\)
+**     br      %r14
+*/
+void and_short_v1 (volatile short *x, short *y) { *x &= *y; }
+
+/*
+** and_short_v2:
+**     ...
+**     nc      0\(2,%r2\),166\(%r15\)
+**     ...
+*/
+void and_short_v2 (short *x, volatile short *y) { *x &= *y; }
+
+/*
+** and_int_v0:
+**     nc      0\(4,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void and_int_v0 (int *x, int *y) { *x &= *y; }
+
+/*
+** and_int_v1:
+**     l       (%r[0-9]+),0\(%r[23]\)
+**     n       \1,0\(%r[23]\)
+**     st      \1,0\(%r[23]\)
+**     br      %r14
+*/
+void and_int_v1 (volatile int *x, int *y) { *x &= *y; }
+
+/*
+** and_int_v2:
+**     l       (%r[0-9]+),0\(%r[23]\)
+**     n       \1,0\(%r[23]\)
+**     st      \1,0\(%r[23]\)
+**     br      %r14
+*/
+void and_int_v2 (int *x, volatile int *y) { *x &= *y; }
+
+/*
+** and_long_v0:
+**     nc      0\(8,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void and_long_v0 (long *x, long *y) { *x &= *y; }
+
+/*
+** and_long_v1:
+**     lg      (%r[0-9]+),0\(%r[23]\)
+**     ng      \1,0\(%r[23]\)
+**     stg     \1,0\(%r[23]\)
+**     br      %r14
+*/
+void and_long_v1 (volatile long *x, long *y) { *x &= *y; }
+
+/*
+** and_long_v2:
+**     lg      (%r[0-9]+),0\(%r[23]\)
+**     ng      \1,0\(%r[23]\)
+**     stg     \1,0\(%r[23]\)
+**     br      %r14
+*/
+void and_long_v2 (long *x, volatile long *y) { *x &= *y; }
+
+/*
+** ior_char_v0:
+**     oc      0\(1,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void ior_char_v0 (char *x, char *y) { *x |= *y; }
+
+/*
+** ior_char_v1:
+**     oc      0\(1,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void ior_char_v1 (volatile char *x, char *y) { *x |= *y; }
+
+/*
+** ior_char_v2:
+**     oc      0\(1,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void ior_char_v2 (char *x, volatile char *y) { *x |= *y; }
+
+/*
+** ior_short_v0:
+**     oc      0\(2,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void ior_short_v0 (short *x, short *y) { *x |= *y; }
+
+/*
+** ior_short_v1:
+**     lh      %r[0-9]+,0\(%r[23]\)
+**     lh      %r[0-9]+,0\(%r[23]\)
+**     or      (%r[0-9]+),%r[0-9]+
+**     sth     \1,0\(%r2\)
+**     br      %r14
+*/
+void ior_short_v1 (volatile short *x, short *y) { *x |= *y; }
+
+/*
+** ior_short_v2:
+**     ...
+**     oc      0\(2,%r2\),166\(%r15\)
+**     ...
+*/
+void ior_short_v2 (short *x, volatile short *y) { *x |= *y; }
+
+/*
+** ior_int_v0:
+**     oc      0\(4,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void ior_int_v0 (int *x, int *y) { *x |= *y; }
+
+/*
+** ior_int_v1:
+**     l       (%r[0-9]+),0\(%r[23]\)
+**     o       \1,0\(%r[23]\)
+**     st      \1,0\(%r[23]\)
+**     br      %r14
+*/
+void ior_int_v1 (volatile int *x, int *y) { *x |= *y; }
+
+/*
+** ior_int_v2:
+**     l       (%r[0-9]+),0\(%r[23]\)
+**     o       \1,0\(%r[23]\)
+**     st      \1,0\(%r[23]\)
+**     br      %r14
+*/
+void ior_int_v2 (int *x, volatile int *y) { *x |= *y; }
+
+/*
+** ior_long_v0:
+**     oc      0\(8,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void ior_long_v0 (long *x, long *y) { *x |= *y; }
+
+/*
+** ior_long_v1:
+**     lg      (%r[0-9]+),0\(%r[23]\)
+**     og      \1,0\(%r[23]\)
+**     stg     \1,0\(%r[23]\)
+**     br      %r14
+*/
+void ior_long_v1 (volatile long *x, long *y) { *x |= *y; }
+
+/*
+** ior_long_v2:
+**     lg      (%r[0-9]+),0\(%r[23]\)
+**     og      \1,0\(%r[23]\)
+**     stg     \1,0\(%r[23]\)
+**     br      %r14
+*/
+void ior_long_v2 (long *x, volatile long *y) { *x |= *y; }
+
+/*
+** xor_char_v0:
+**     xc      0\(1,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void xor_char_v0 (char *x, char *y) { *x ^= *y; }
+
+/*
+** xor_char_v1:
+**     xc      0\(1,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void xor_char_v1 (volatile char *x, char *y) { *x ^= *y; }
+
+/*
+** xor_char_v2:
+**     xc      0\(1,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void xor_char_v2 (char *x, volatile char *y) { *x ^= *y; }
+
+/*
+** xor_short_v0:
+**     xc      0\(2,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void xor_short_v0 (short *x, short *y) { *x ^= *y; }
+
+/*
+** xor_short_v1:
+**     lh      %r[0-9]+,0\(%r[23]\)
+**     lh      %r[0-9]+,0\(%r[23]\)
+**     xr      (%r[0-9]+),%r[0-9]+
+**     sth     \1,0\(%r2\)
+**     br      %r14
+*/
+void xor_short_v1 (volatile short *x, short *y) { *x ^= *y; }
+
+/*
+** xor_short_v2:
+**     ...
+**     xc      0\(2,%r2\),166\(%r15\)
+**     ...
+*/
+void xor_short_v2 (short *x, volatile short *y) { *x ^= *y; }
+
+/*
+** xor_int_v0:
+**     xc      0\(4,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void xor_int_v0 (int *x, int *y) { *x ^= *y; }
+
+/*
+** xor_int_v1:
+**     l       (%r[0-9]+),0\(%r[23]\)
+**     x       \1,0\(%r[23]\)
+**     st      \1,0\(%r[23]\)
+**     br      %r14
+*/
+void xor_int_v1 (volatile int *x, int *y) { *x ^= *y; }
+
+/*
+** xor_int_v2:
+**     l       (%r[0-9]+),0\(%r[23]\)
+**     x       \1,0\(%r[23]\)
+**     st      \1,0\(%r[23]\)
+**     br      %r14
+*/
+void xor_int_v2 (int *x, volatile int *y) { *x ^= *y; }
+
+/*
+** xor_long_v0:
+**     xc      0\(8,%r2\),0\(%r3\)
+**     br      %r14
+*/
+void xor_long_v0 (long *x, long *y) { *x ^= *y; }
+
+/*
+** xor_long_v1:
+**     lg      (%r[0-9]+),0\(%r[23]\)
+**     xg      \1,0\(%r[23]\)
+**     stg     \1,0\(%r[23]\)
+**     br      %r14
+*/
+void xor_long_v1 (volatile long *x, long *y) { *x ^= *y; }
+
+/*
+** xor_long_v2:
+**     lg      (%r[0-9]+),0\(%r[23]\)
+**     xg      \1,0\(%r[23]\)
+**     stg     \1,0\(%r[23]\)
+**     br      %r14
+*/
+void xor_long_v2 (long *x, volatile long *y) { *x ^= *y; }
-- 
2.52.0

Reply via email to