On Thu, Mar 24, 2022 at 09:28:15AM +0100, Tom de Vries via Gcc-patches wrote:
> Hi,
>
> On nvptx (using a Quadro K2000 with driver 470.103.01) I ran into this:
> ...
> FAIL: gcc.dg/atomic/stdatomic-flag-2.c -O1 execution test
> ...
> which mimimized to:
> ...
> #include <stdatomic.h>
> atomic_flag a = ATOMIC_FLAG_INIT;
> int main () {
> if ((atomic_flag_test_and_set) (&a))
> __builtin_abort ();
> return 0;
> }
> ...
>
> The atomic_flag_test_and_set is implemented using __atomic_test_and_set_1,
> which corresponds to the "word-sized compare-and-swap loop" version of
> libat_test_and_set in libatomic/tas_n.c.
>
> The semantics of a test-and-set is that the return value is "true if and only
> if the previous contents were 'set'".
>
> But the code uses:
> ...
> return woldval != 0;
> ...
> which means it doesn't look only at the byte that was either set or not set,
> but at the entire word.
>
> Fix this by using instead:
> ...
> return (woldval & wval) == wval;
Shouldn't that be instead
return (woldval & ((UWORD) -1 << shift)) != 0;
or
return (woldval & ((UWORD) ~(UWORD) 0 << shift)) != 0;
?
The exact __GCC_ATOMIC_TEST_AND_SET_TRUEVAL varies (the most usual
value is 1, but sparc uses 0xff and m68k/sh use 0x80), falseval is
always 0 though and (woldval & wval) == wval
is testing whether some bits of the oldval are all set rather than
whether the old byte was 0.
Say for trueval 1 it tests whether the least significant bit is set,
for 0x80 if the most significant bit of the byte is set, for
0xff whether all bits are set.
Jakub