Studio 12.5 C++ compiler generates incorrect code for fetch_add method in std::atomic
The problem occurs at optimization level -xO3 and higher
#include <atomic>
std::atomic<int> counter = ATOMIC_VAR_INIT(0);
int main()
{
if (counter.fetch_add(1, std::memory_order_release) == 0)
counter.fetch_sub(1, std::memory_order_release);
return counter;
}
The if generates following assembly:
{ 514 } movl $1,%eax
{ 514 } lock xaddl %eax,counter
{ } movl %eax,-12(%ebp) / sym=.CV0
{ 514 } jne .L77000030.57
{ 524 } .L77000028.58:
{ 524 } movl $-1,%eax
{ 524 } lock xaddl %eax,counter
{ 396 } .L77000030.57:
{ 396 } movl counter,%eax
The jump (514) suggests that the optimizer assumes xaddl setting flags for the original value (i.e. result of function fetch_add) which is wrong - xaddl sets the flags to represent result of addition, i.e. the new value
The bug causes QMutex class of Qt 5.9 to get into infinite loop, there is code which tests result of fetch_add against 0 like in my example.