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