[Bug c++/78778] New: non-atomic load moved to before atomic load with std::memory_order_acquire

erik at rigtorp dot se gcc-bugzilla@gcc.gnu.org
Mon Dec 12 16:37:00 GMT 2016


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78778

            Bug ID: 78778
           Summary: non-atomic load moved to before atomic load with
                    std::memory_order_acquire
           Product: gcc
           Version: 5.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: erik at rigtorp dot se
  Target Milestone: ---

Compiling this with GCC 5.1 and up with -O2 or higher for x86_64:

#include <atomic>
#include <cstdint>

int seqlock_load(std::atomic<std::size_t> &seq, double &value) {
  double copy;
  std::size_t seq0, seq1;
  do {
    seq0 = seq.load(std::memory_order_acquire);
    copy = value;
    seq1 = seq.load(std::memory_order_acquire);
  } while (seq0 != seq1 || seq0 & 1);
  return copy;
}

Yields the following assembly:

seqlock_load(std::atomic<unsigned long>&, double&):
        movsd   xmm0, QWORD PTR [rsi] // copy = value;
.L3:
        mov     rdx, QWORD PTR [rdi] // seq0 = seq.load(...)
        mov     rax, QWORD PTR [rdi] // seq1 = seq.load(...)
        cmp     rax, rdx
        jne     .L3
        test    al, 1
        jne     .L3
        cvttsd2si       eax, xmm0
        ret


In GCC Explorer: https://godbolt.org/g/0X8nUC

As I understand this operation:

copy = value;

Is guaranteed to happen after:

seq0 = seq.load(std::memory_order_acquire);

But it's moved to before the loop. A valid optimization would be to move it
after the loop, but not before. This came up when I was implementing seqlocks:
https://github.com/rigtorp/Seqlock


More information about the Gcc-bugs mailing list