Bug in __sync_bool_compare_and_swap at O0

Debugging a runtime failure with our ARM 32-bit application (at O0),
we narrowed it down to a bug in the return values for
__sync_bool_compare_and_swap. While it works fine at O1 and above, we
sometimes need O0 version to have a better debugging experience.

Here is a test case:

cat test.c

#include <stdio.h>
typedef unsigned long long uint64_t;
uint64_t x = 10;
uint64_t y = 20;
uint64_t z = 20;

int main() {
printf("\nx = %llu y= %llu z=%llu ",x, y, z);
int a = __sync_bool_compare_and_swap(&y, z, x);
printf("\nx = %llu y= %llu z=%llu result = %d",x, y, z,a);
return 0;

The compilation flags used are: --target=armeb-linux-gnueabi
-march=armv8-a+crc -mfloat-abi=hard -mfpu=vfp

With O0, the expected (y=x) assignment is not done.
x = 10 y= 20 z=20
x = 10 y= 20 z=20 result = 0

With O1, it works fine as expected.

x = 10 y= 20 z=20
x = 10 y= 10 z=20 result = 1

Both clang4 and trunk have this issue. clang 3.8 did not have this
issue. The problem seems to be in how cmpxchg is handled.

%2 = cmpxchg i64* @y, i64 %0, i64 %1 seq_cst seq_cst

The cmpxchg is left untouched after the atomic-expand pass, which I
believe is intentional. I also see several related commits, but with
my limited understanding of the backend, I haven't been successful in
localizing the problem. Could some one give me pointers with regards
to what might be the likely cause or where to look further ?


Hi Bharathi,