https://gcc.gnu.org/g:8ee36c421829a12858f1333008e5df2b52146aff
commit r16-6573-g8ee36c421829a12858f1333008e5df2b52146aff Author: Stefan Schulze Frielinghaus <[email protected]> Date: Thu Jan 8 11:20:54 2026 +0100 s390: Remove volatile check from constraints A[QRST] 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. Diff: --- 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(-) diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc index 88827ca6170a..28a025be4e8d 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 c6fa6db3ecae..21730950edeb 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 000000000000..d69509f6ad10 --- /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; }
