https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122368
Bug ID: 122368
Summary: [16 Regression] gcc.target/s390/md/atomic_exchange-1.c
fails since r16-4081-g966cdec2b23b80
Product: gcc
Version: 16.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: middle-end
Assignee: unassigned at gcc dot gnu.org
Reporter: stefansf at gcc dot gnu.org
Target Milestone: ---
Target: s390*-*-*
If gcc itself is build with CFLAGS="-O0" CXXFLAGS="-O0", then the tests pass
and fail when CFLAGS="-O1" CXXFLAGS="-O1" is used:
FAIL: gcc.target/s390/md/atomic_exchange-1.c -O0 execution test
FAIL: gcc.target/s390/md/atomic_exchange-1.c -O0 -march=z13 execution test
FAIL: gcc.target/s390/md/atomic_exchange-1.c -O0 -march=z900 execution test
FAIL: gcc.target/s390/md/atomic_exchange-1.c -O1 execution test
FAIL: gcc.target/s390/md/atomic_exchange-1.c -O1 -march=z13 execution test
FAIL: gcc.target/s390/md/atomic_exchange-1.c -O1 -march=z900 execution test
FAIL: gcc.target/s390/md/atomic_exchange-1.c -O2 execution test
FAIL: gcc.target/s390/md/atomic_exchange-1.c -O2 -march=z13 execution test
FAIL: gcc.target/s390/md/atomic_exchange-1.c -O2 -march=z900 execution test
FAIL: gcc.target/s390/md/atomic_exchange-1.c -O3 execution test
FAIL: gcc.target/s390/md/atomic_exchange-1.c -O3 -march=z13 execution test
FAIL: gcc.target/s390/md/atomic_exchange-1.c -O3 -march=z900 execution test
WARNING: gcc.target/s390/md/atomic_exchange-1.c -Os execution test program
timed out.
FAIL: gcc.target/s390/md/atomic_exchange-1.c -Os execution test
FAIL: gcc.target/s390/md/atomic_exchange-1.c -Os -march=z13 execution test
FAIL: gcc.target/s390/md/atomic_exchange-1.c -Os -march=z900 execution test
FAIL: gcc.target/s390/md/atomic_exchange-1.c execution test
The failing part of the test is:
__int128 g128;
int main (void)
{
__atomic_exchange_n (&g128, 0, 2);
if (g128 != 0)
__builtin_abort ();
return 0;
}
In libatomic/config/s390/exch_n.c we have some special casing since on s390 a
TI value has an alignment of 8 byte and in case the compiler can prove that a
TI value is actually 16 byte aligned, we can exploit instruction
compare-and-swap in a loop:
#if !DONE && N == 16
UTYPE
SIZE(libat_exchange) (UTYPE *mptr, UTYPE newval, int smodel UNUSED)
{
if (!((uintptr_t)mptr & 0xf))
{
/* Use the builtin only if the memory operand is 16 byte
aligned. */
return __atomic_exchange_n ((UTYPE *)__builtin_assume_aligned (mptr, 16),
newval, __ATOMIC_SEQ_CST);
}
else
{
UTYPE oldval;
UWORD magic;
pre_seq_barrier (smodel);
magic = protect_start (mptr);
oldval = *mptr;
*mptr = newval;
protect_end (mptr, magic);
post_seq_barrier (smodel);
return oldval;
}
}
#define DONE 1
#endif /* N == 16 */
The then-case is, after r16-4081, compiled into an endless recursion, i.e.,
return __atomic_exchange_n ((UTYPE *)__builtin_assume_aligned (mptr, 16),
newval, __ATOMIC_SEQ_CST);
is turned into a call of __atomic_exchange_16 whereas previously it was
expanded via atomic_exchangeti. The latter is no more the case since the
alignment information is lost and we fail in the expander:
if (<MODE>mode != QImode
&& MEM_ALIGN (operands[1]) < GET_MODE_BITSIZE (<MODE>mode))
FAIL;
The loss of the alignment must have happened prior expand_builtin where we have
(gdb) call get_pointer_alignment (TREE_OPERAND (exp, 3))
$1 = 8
after r16-4081 and
(gdb) call get_pointer_alignment (TREE_OPERAND (exp, 3))
$1 = 128
prior r16-4081.