title: Why is GCC std::atomic increment generating inefficient non-atomic assembly?
body: <p>I've been using gcc's Intel-compatible builtins (like <code>__sync_fetch_and_add</code>) for quite some time, using my own <code>atomic</code> template. The "<code>__sync</code>" functions are now officially considered "legacy".</p>
  
  <p>C++11 supports <code>std::atomic&lt;&gt;</code> and its descendants, so it seems reasonable to use that instead, since it makes my code standard compliant, and the compiler will produce the best code either way, in a platform independent manner, that is almost too good to be true.<br>
  Incidentally, I'd only have to text-replace <code>atomic</code> with <code>std::atomic</code>, too. There's a lot in <code>std::atomic</code> (re: memory models) that I don't really need, but default parameters take care of that.</p>
  
  <p>Now for the bad news. As it turns out, the generated code is, from what I can tell, ... utter crap, and not even atomic at all. Even a minimum example that increments a single atomic variable and outputs it has no fewer than 5 non-inlined function calls to <code>___atomic_flag_for_address</code>, <code>___atomic_flag_wait_explicit</code>, and <code>__atomic_flag_clear_explicit</code> (fully optimized), and on the other hand, there is not a single atomic instruction in the generated executable.  </p>
  
  <p>What gives? There is of course always the possibility of a compiler bug, but with the huge number of reviewers and users, such rather drastic things are generally unlikely to go unnoticed. Which means, this is probably not a bug, but intended behaviour.</p>
  
  <p>What is the "rationale" behind so many function calls, and how is atomicity implemented <em>without</em> atomicity?</p>
  
  <p>As-simple-as-it-can-get example:
  </p>
  
  <pre><code>#include &lt;atomic&gt;
  
  int main()
  {
      std::atomic_int a(5);
      ++a;
      __builtin_printf("%d", (int)a);
      return 0;
  }
  </code></pre>
  
  <p>produces the following <code>.s</code>:
  </p>
  
  <pre><code>movl    $5, 28(%esp)     #, a._M_i
  movl    %eax, (%esp)     # tmp64,
  call    ___atomic_flag_for_address   #
  movl    $5, 4(%esp)  #,
  movl    %eax, %ebx   #, __g
  movl    %eax, (%esp)     # __g,
  call    ___atomic_flag_wait_explicit     #
  movl    %ebx, (%esp)     # __g,
  addl    $1, 28(%esp)     #, MEM[(__i_type *)&amp;a]
  movl    $5, 4(%esp)  #,
  call    _atomic_flag_clear_explicit  #
  movl    %ebx, (%esp)     # __g,
  movl    $5, 4(%esp)  #,
  call    ___atomic_flag_wait_explicit     #
  movl    28(%esp), %esi   # MEM[(const __i_type *)&amp;a], __r
  movl    %ebx, (%esp)     # __g,
  movl    $5, 4(%esp)  #,
  call    _atomic_flag_clear_explicit  #
  movl    $LC0, (%esp)     #,
  movl    %esi, 4(%esp)    # __r,
  call    _printf  #
  (...)
  .def    ___atomic_flag_for_address; .scl    2;  .type   32; .endef
  .def    ___atomic_flag_wait_explicit;   .scl    2;  .type   32; .endef
  .def    _atomic_flag_clear_explicit;    .scl    2;  .type   32; .endef
  </code></pre>
  
  <p>... and the mentioned functions look e.g. like this in <code>objdump</code>:</p>
  
  <pre><code>004013c4 &lt;__atomic_flag_for_address&gt;:
  mov    0x4(%esp),%edx
  mov    %edx,%ecx
  shr    $0x2,%ecx
  mov    %edx,%eax
  shl    $0x4,%eax
  add    %ecx,%eax
  add    %edx,%eax
  mov    %eax,%ecx
  shr    $0x7,%ecx
  mov    %eax,%edx
  shl    $0x5,%edx
  add    %ecx,%edx
  add    %edx,%eax
  mov    %eax,%edx
  shr    $0x11,%edx
  add    %edx,%eax
  and    $0xf,%eax
  add    $0x405020,%eax
  ret    
  </code></pre>
  
  <p>The others are somewhat simpler, but I don't find a single instruction that would really be atomic (other than some spurious <code>xchg</code> which <em>are</em> atomic on X86, but these seem to be rather NOP/padding, since it's <code>xchg   %ax,%ax</code> following <code>ret</code>).</p>
  
  <p>I'm absolutely not sure what such a rather complicated function is needed for, and how it's meant to make anything atomic.</p>