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