<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>Weaselab - C++</title>
      <link>https://blog.weaselab.dev/</link>
      <description>Ideas and projects from former FoundationDB contributor Andrew Noyes</description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://blog.weaselab.dev/tags/c/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Fri, 21 Aug 2026 00:00:00 +0000</lastBuildDate>
      <item>
          <title>Make clangd check your asserts even with -DNDEBUG</title>
          <pubDate>Fri, 21 Aug 2026 00:00:00 +0000</pubDate>
          <author>Andrew Noyes</author>
          <link>https://blog.weaselab.dev/clangd-asserts-ndebug/</link>
          <guid>https://blog.weaselab.dev/clangd-asserts-ndebug/</guid>
          <description xml:base="https://blog.weaselab.dev/clangd-asserts-ndebug/">&lt;p&gt;When you configure a CMake project with &lt;code&gt;-DCMAKE_BUILD_TYPE=Release&lt;&#x2F;code&gt;, CMake adds &lt;code&gt;-DNDEBUG&lt;&#x2F;code&gt; to every compile command, and that flag lands in your &lt;code&gt;compile_commands.json&lt;&#x2F;code&gt;. &lt;code&gt;assert&lt;&#x2F;code&gt; is a no-op when &lt;code&gt;NDEBUG&lt;&#x2F;code&gt; is defined, so clangd treats the body of every &lt;code&gt;assert(...)&lt;&#x2F;code&gt; as dead code: no autocomplete, no type checking, no diagnostics. But when you&#x27;re editing code, you want asserts typechecked no matter what build type you have configured.&lt;&#x2F;p&gt;
&lt;p&gt;The fix is a &lt;code&gt;.clangd&lt;&#x2F;code&gt; file at the root of your project that strips &lt;code&gt;-DNDEBUG&lt;&#x2F;code&gt; for clangd only, without touching your actual build:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#22863A, #85E89D);&quot;&gt;C&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#22863A, #85E89D);&quot;&gt;ompileFlags&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#22863A, #85E89D);&quot;&gt;  R&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#22863A, #85E89D);&quot;&gt;emove&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;-D&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;NDEBUG&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;toy-example&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;clangd-asserts-ndebug&#x2F;#toy-example&quot; aria-label=&quot;Anchor link for: toy-example&quot;&gt;&amp;#x1f517;&lt;&#x2F;a&gt;
Toy example&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;CMakeLists.txt&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot;&gt;&lt;code data-lang=&quot;cmake&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;cmake_minimum_required&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;VERSION&lt;&#x2F;span&gt;&lt;span&gt; 3.20)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;project&lt;&#x2F;span&gt;&lt;span&gt;(toy CXX)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;set&lt;&#x2F;span&gt;&lt;span&gt;(CMAKE_CXX_STANDARD 17)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;set&lt;&#x2F;span&gt;&lt;span&gt;(CMAKE_EXPORT_COMPILE_COMMANDS &lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;ON&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;add_executable&lt;&#x2F;span&gt;&lt;span&gt;(toy main.cpp)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;main.cpp&lt;&#x2F;code&gt; contains a deliberate type error &lt;em&gt;inside&lt;&#x2F;em&gt; an assert:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot;&gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;#&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;include&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;cassert&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;#&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;include&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;vector&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; main&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;    std&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span&gt;vector&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; v&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;    assert&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;v&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;size&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;oops&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Configure a Release build so the compile database carries &lt;code&gt;-DNDEBUG&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;cmake&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; -&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;S&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; .&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; -&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;B&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; build&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; -&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;G&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; Ninja&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; -&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;DCMAKE_BUILD_TYPE=Release&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;before&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;clangd-asserts-ndebug&#x2F;#before&quot; aria-label=&quot;Anchor link for: before&quot;&gt;&amp;#x1f517;&lt;&#x2F;a&gt;
Before&lt;&#x2F;h2&gt;
&lt;p&gt;With no &lt;code&gt;.clangd&lt;&#x2F;code&gt; file, clangd picks up &lt;code&gt;-DNDEBUG&lt;&#x2F;code&gt; from the compile database, skips the assert body, and reports zero errors:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ clangd --check=main.cpp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;I Compile command from CDB is: ... -O3 -DNDEBUG -std=gnu++17 ... -c main.cpp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;I All checks completed, 0 errors&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;after&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;clangd-asserts-ndebug&#x2F;#after&quot; aria-label=&quot;Anchor link for: after&quot;&gt;&amp;#x1f517;&lt;&#x2F;a&gt;
After&lt;&#x2F;h2&gt;
&lt;p&gt;Add the &lt;code&gt;.clangd&lt;&#x2F;code&gt; file above. clangd now drops &lt;code&gt;-DNDEBUG&lt;&#x2F;code&gt; from the compile command, the assert becomes live, and the type error surfaces:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ clangd --check=main.cpp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;I Loading config file at ...&#x2F;.clangd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;I Compile command from CDB is: ... -O3 -std=gnu++17 ... -c main.cpp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;E [typecheck_comparison_of_pointer_integer] Line 6: comparison between pointer and integer (&amp;#39;size_type&amp;#39; (aka &amp;#39;unsigned long&amp;#39;) and &amp;#39;const char *&amp;#39;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;I All checks completed, 1 errors&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The Release build is unchanged; only the editor now sees the code you actually wrote inside asserts.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>If a sentence about C++ starts with &quot;On x86,&quot;, stop listening.</title>
          <pubDate>Mon, 03 Aug 2026 00:00:00 +0000</pubDate>
          <author>Andrew Noyes</author>
          <link>https://blog.weaselab.dev/on-x86-stop-listening/</link>
          <guid>https://blog.weaselab.dev/on-x86-stop-listening/</guid>
          <description xml:base="https://blog.weaselab.dev/on-x86-stop-listening/">&lt;p&gt;When someone starts a sentence with &quot;On x86,&quot; whatever follows is almost always a justification for writing code that the C++ abstract machine does not permit.&lt;&#x2F;p&gt;
&lt;p&gt;The intent is usually innocent. The speaker knows that x86 has a strong memory model, that aligned stores up to a certain size are atomic in hardware, that signed integers use two&#x27;s complement, and so on. They are appealing to real facts about a real CPU. Their compiler&#x27;s output for their suggestion may very well be correct. The trouble is that we&#x27;re not writing x86.&lt;&#x2F;p&gt;
&lt;p&gt;I recently caught myself doing a version of this. I had written some SIMD code that loads a full 16-element array, masks off the unused slots, and only uses the results from the valid ones. The unused lanes are read, masked out, and discarded. Valgrind doesn&#x27;t complain, since it tracks &quot;initializedness&quot; the way you&#x27;d expect. The compiler was generating correct assembly for it. But reading uninitialized memory is undefined behavior in C++ even if the value is never used (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git.weaselab.dev&#x2F;weaselab&#x2F;conflict-set&#x2F;issues&#x2F;68&quot;&gt;issue #68&lt;&#x2F;a&gt;). I had been reasoning from &quot;what the chip does&quot; and &quot;what valgrind tracks&quot; instead of from the standard. The assembly was correct, but I do want to upgrade my compiler someday.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-abstract-machine-is-the-only-machine-that-matters-for-correctness&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#the-abstract-machine-is-the-only-machine-that-matters-for-correctness&quot; aria-label=&quot;Anchor link for: the-abstract-machine-is-the-only-machine-that-matters-for-correctness&quot;&gt;&amp;#x1f517;&lt;&#x2F;a&gt;
The abstract machine is the only machine that matters for correctness&lt;&#x2F;h1&gt;
&lt;p&gt;C++ gives you a precise set of rules for what a well-formed program means. Objects have lifetimes. Reads and writes to the same object have ordering constraints. Some operations are atomic; others are not. Signed integer overflow is undefined. The compiler is allowed to assume your program follows these rules.&lt;&#x2F;p&gt;
&lt;p&gt;x86 is one possible target for that compiler. It is a good target, with many helpful properties, but none of those properties are part of the C++ contract unless the standard explicitly says so, or unless you opt into an implementation-specific extension that documents them.&lt;&#x2F;p&gt;
&lt;p&gt;This matters because compilers optimize in terms of the abstract machine, not the physical one. If your program has undefined behavior, the compiler can do whatever it wants&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-compiler-1&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#fn-compiler&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, and &quot;whatever it wants&quot; often includes producing code that does the opposite of what you intend.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;examples&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#examples&quot; aria-label=&quot;Anchor link for: examples&quot;&gt;&amp;#x1f517;&lt;&#x2F;a&gt;
Examples&lt;&#x2F;h1&gt;
&lt;p&gt;The following snippets were compiled with &lt;code&gt;clang++ --target=x86_64-linux-gnu -fno-pic -O2 -S&lt;&#x2F;code&gt; (Ubuntu clang 21.1.8). The generated assembly is exactly what you get from a real compiler, and it is precisely the kind of output that &quot;On x86&quot; reasoning fails to predict.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;on-x86-signed-overflow-wraps-around&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#on-x86-signed-overflow-wraps-around&quot; aria-label=&quot;Anchor link for: on-x86-signed-overflow-wraps-around&quot;&gt;&amp;#x1f517;&lt;&#x2F;a&gt;
&quot;On x86, signed overflow wraps around&quot;&lt;&#x2F;h2&gt;
&lt;p&gt;x86 arithmetic instructions use two&#x27;s complement, so an overflowing signed addition leaves a wrapped value in the register. C++ does not care. Signed integer overflow is undefined behavior, and the compiler is entitled to assume it cannot happen.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot;&gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; incr_is_greater&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#E36209, #FFAB70);&quot;&gt; x&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; x&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot;&gt;&lt;code data-lang=&quot;asm&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;incr_is_greater(&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    movb    &lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;$1&lt;&#x2F;span&gt;&lt;span&gt;, %&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;al&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    retq&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You might expect this to translate to an &lt;code&gt;add&lt;&#x2F;code&gt; somewhere in the output — x86 has an &lt;code&gt;add&lt;&#x2F;code&gt; instruction, and the source says &lt;code&gt;x + 1&lt;&#x2F;code&gt;. It doesn&#x27;t appear. The compiler assumes the overflow never happens, so &lt;code&gt;x + 1 &amp;gt; x&lt;&#x2F;code&gt; is always true and the whole thing collapses to &lt;code&gt;movb $1&lt;&#x2F;code&gt;. If you were reasoning &quot;On x86, &lt;code&gt;INT_MAX + 1&lt;&#x2F;code&gt; wraps to &lt;code&gt;INT_MIN&lt;&#x2F;code&gt;, and &lt;code&gt;INT_MIN &amp;gt; INT_MAX&lt;&#x2F;code&gt; is false,&quot; you&#x27;re picturing an &lt;code&gt;add&lt;&#x2F;code&gt; that executes and wraps in the register — but, as established, we&#x27;re not writing x86.&lt;&#x2F;p&gt;
&lt;p&gt;If you actually want wraparound, use an unsigned type (which is defined to wrap in C++) or a compiler extension such as &lt;code&gt;-fwrapv&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;on-x86-reads-and-writes-don-t-get-reordered&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#on-x86-reads-and-writes-don-t-get-reordered&quot; aria-label=&quot;Anchor link for: on-x86-reads-and-writes-don-t-get-reordered&quot;&gt;&amp;#x1f517;&lt;&#x2F;a&gt;
&quot;On x86, reads and writes don&#x27;t get reordered&quot;&lt;&#x2F;h2&gt;
&lt;p&gt;The x86 memory model is Total Store Order, which is famously strong. At the chip level, ordinary aligned stores really do appear to happen in program order to each observer. That does not help you at the C++ level. The compiler is allowed to reorder ordinary reads and writes, keep them in registers, or eliminate them, as long as it does not change the observable behavior of the abstract machine. Since it can assume the absence of data races it may also assume no other thread writes to a non-atomic object being accessed in the current thread.&lt;&#x2F;p&gt;
&lt;p&gt;Once your program contains a data race, the program is undefined and none of these guarantees constrain the compiler.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot;&gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;extern&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; int&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;extern&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; bool&lt;&#x2F;span&gt;&lt;span&gt; ready&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; writer&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    data &lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 42&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ready &lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; reader&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    while&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;ready&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot;&gt;&lt;code data-lang=&quot;asm&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;writer():&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    movl    &lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;$42&lt;&#x2F;span&gt;&lt;span&gt;, data(%&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;rip&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    movb    &lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;$1&lt;&#x2F;span&gt;&lt;span&gt;, ready(%&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;rip&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    retq&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;reader():&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    movl    data(%&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;rip&lt;&#x2F;span&gt;&lt;span&gt;), %&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;eax&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    retq&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;reader()&lt;&#x2F;code&gt; contains no synchronization. Its loop body performs no observable operation — no &lt;code&gt;volatile&lt;&#x2F;code&gt; access, no I&#x2F;O, nothing — so under the forward-progress rule&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-forward-progress-1&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#fn-forward-progress&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; the compiler may assume the thread will eventually do something observable. Since nothing in the abstract machine can ever change &lt;code&gt;ready&lt;&#x2F;code&gt;, the compiler concludes that &lt;code&gt;ready&lt;&#x2F;code&gt; must be true already: it drops the spin loop, reads &lt;code&gt;data&lt;&#x2F;code&gt; once, and returns. The &lt;code&gt;while (!ready)&lt;&#x2F;code&gt; loop is gone. The x86 chip will not reorder the stores that survive, but by then the program has already been transformed into one that does not mean what you think it means.&lt;&#x2F;p&gt;
&lt;p&gt;Use atomics and the memory-ordering tools the standard gives you:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot;&gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;#&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;include&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;atomic&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;extern&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; int&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;extern&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; std&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span&gt;atomic&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; ready&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;void&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; writer&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    data &lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 42&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ready&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;store&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; std&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span&gt;memory_order_release&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;int&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; reader&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    while&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;ready&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;load&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;std&lt;&#x2F;span&gt;&lt;span&gt;::&lt;&#x2F;span&gt;&lt;span&gt;memory_order_acquire&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Only &lt;code&gt;ready&lt;&#x2F;code&gt; needs to be atomic. The release store on &lt;code&gt;ready&lt;&#x2F;code&gt; and the acquire load on it create a happens-before edge: once the reader observes &lt;code&gt;ready == true&lt;&#x2F;code&gt;, the write to &lt;code&gt;data&lt;&#x2F;code&gt; is complete. &lt;code&gt;data&lt;&#x2F;code&gt; itself can stay a plain &lt;code&gt;int&lt;&#x2F;code&gt; since it&#x27;s not being accessed concurrently.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;on-x86-an-unaligned-access-is-just-a-slower-access&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#on-x86-an-unaligned-access-is-just-a-slower-access&quot; aria-label=&quot;Anchor link for: on-x86-an-unaligned-access-is-just-a-slower-access&quot;&gt;&amp;#x1f517;&lt;&#x2F;a&gt;
&quot;On x86, an unaligned access is just a slower access&quot;&lt;&#x2F;h2&gt;
&lt;p&gt;The x86 ISA will handle many unaligned accesses in hardware; they are slow, not fatal. But that is only true of scalar loads. The aligned move &lt;code&gt;movdqa&lt;&#x2F;code&gt; requires 16-byte alignment and the hardware faults on a misaligned address. C++ allows the compiler to assume a pointer is aligned for the type it points to, and that assumption can lead it to emit one of the faulting instructions. &lt;code&gt;__m128i&lt;&#x2F;code&gt; is a 128-bit, 16-byte-aligned type, so loading it lets the compiler emit an aligned move:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot;&gt;&lt;code data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;#&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;include&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;immintrin.h&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;#&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;include&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;cstdint&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#032F62, #9ECBFF);&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;uint64_t&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; sumv&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt; __m128i&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#E36209, #FFAB70);&quot;&gt; p&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    __m128i v &lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; *&lt;&#x2F;span&gt;&lt;span&gt;p&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;uint64_t&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;_mm_cvtsi128_si64&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;v&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt; +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           (&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;uint64_t&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;_mm_cvtsi128_si64&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#6F42C1, #B392F0);&quot;&gt;_mm_srli_si128&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;v&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#24292E, #E1E4E8); background-color: light-dark(#FFFFFF, #24292E);&quot;&gt;&lt;code data-lang=&quot;asm&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sumv(__m128i const*):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    movdqa&lt;&#x2F;span&gt;&lt;span&gt;  (%&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span&gt;), %&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;xmm0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    pshufd&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;  $238&lt;&#x2F;span&gt;&lt;span&gt;, %&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;xmm0&lt;&#x2F;span&gt;&lt;span&gt;, %&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;xmm1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    paddq&lt;&#x2F;span&gt;&lt;span&gt;   %&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;xmm0&lt;&#x2F;span&gt;&lt;span&gt;, %&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;xmm1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#D73A49, #F97583);&quot;&gt;    movq&lt;&#x2F;span&gt;&lt;span&gt;    %&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;xmm1&lt;&#x2F;span&gt;&lt;span&gt;, %&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#005CC5, #79B8FF);&quot;&gt;rax&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    retq&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Both GCC and Clang emit &lt;code&gt;movdqa&lt;&#x2F;code&gt; here. If you pass a pointer that is only, say, 4-byte aligned, that &lt;code&gt;movdqa&lt;&#x2F;code&gt; faults — the x86 hardware requires the aligned move&#x27;s operand to be 16-byte aligned and refuses to perform it on a misaligned address. A misaligned load is undefined behavior in C++, and the compiler is entitled to emit the alignment-requiring instruction on the strength of that assumption.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-unaligned-1&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#fn-unaligned&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;is-on-x86-ever-ok&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#is-on-x86-ever-ok&quot; aria-label=&quot;Anchor link for: is-on-x86-ever-ok&quot;&gt;&amp;#x1f517;&lt;&#x2F;a&gt;
Is &quot;On x86,&quot; ever OK?&lt;&#x2F;h1&gt;
&lt;p&gt;Yes. The sentence is fine when it is about performance, not correctness.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&quot;On x86, the L1 cache line is 64 bytes&quot; is a useful thing to know when laying out hot structures.&lt;&#x2F;li&gt;
&lt;li&gt;&quot;On x86, &lt;code&gt;popcnt&lt;&#x2F;code&gt; has three-cycle latency on this microarchitecture&quot; is relevant to microbenchmarks.&lt;&#x2F;li&gt;
&lt;li&gt;&quot;On x86, this loop compiles to one load, one add, and one branch per iteration&quot; is an observation about emitted code, which you can verify and measure.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-codegen-1&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#fn-codegen&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These statements do not make any claim about what the program &lt;em&gt;means&lt;&#x2F;em&gt;. They are engineering details about how a particular machine executes a particular binary. You can use them to make code faster; you cannot use them to make undefined behavior defined.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;what-to-do-instead&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#what-to-do-instead&quot; aria-label=&quot;Anchor link for: what-to-do-instead&quot;&gt;&amp;#x1f517;&lt;&#x2F;a&gt;
What to do instead&lt;&#x2F;h1&gt;
&lt;p&gt;For correctness, reason from the C++ abstract machine:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;std::atomic&lt;&#x2F;code&gt; for shared mutable state across threads.&lt;&#x2F;li&gt;
&lt;li&gt;Use the standard library synchronization primitives.&lt;&#x2F;li&gt;
&lt;li&gt;Avoid signed overflow, null pointer dereferences, and out-of-bounds access.&lt;&#x2F;li&gt;
&lt;li&gt;Treat &lt;code&gt;volatile&lt;&#x2F;code&gt; as a tool for memory-mapped IO and signal handlers, not for thread communication.&lt;&#x2F;li&gt;
&lt;li&gt;When in doubt, check with ThreadSanitizer and UBSan.&lt;&#x2F;li&gt;
&lt;li&gt;Do not treat a particular compiler&#x27;s generated code as a correctness argument — that only holds for that compiler and that version. You do want to upgrade your compiler someday, right?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you want x86 semantics, you can also just write x86. Put it in its own &lt;code&gt;.s&lt;&#x2F;code&gt; file, obey the calling convention, and call it as an ordinary function. Then &quot;On x86&quot; is not a claim about how the compiler &lt;em&gt;might&lt;&#x2F;em&gt; compile your C++; it is a statement about the assembly you wrote. You can also try intrinsics, but be aware that the compiler is not obligated to generate the corresponding instructions. You can also try inline assembly, but it&#x27;s more difficult to get right than a standalone &lt;code&gt;.s&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;anchor&quot; href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#conclusion&quot; aria-label=&quot;Anchor link for: conclusion&quot;&gt;&amp;#x1f517;&lt;&#x2F;a&gt;
Conclusion&lt;&#x2F;h1&gt;
&lt;p&gt;If a sentence about C++ starts with &quot;On x86,&quot; it is almost certainly about to confuse hardware behavior with program semantics. That is a mistake for correctness discussions. The only legitimate uses are performance tuning, measurements on a specific target, or literally writing x86.&lt;&#x2F;p&gt;
&lt;p&gt;So in practice: if the topic is correctness, stop listening.&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-compiler&quot;&gt;
&lt;p&gt;People seem to anthropomorphize the compiler as an insufferable pedant who hates their code. The truth is that an optimizing compiler is a complex piece of software that performs a pipeline of hundreds of semantically-valid-according-to-the-abstract-machine transformations on your code, and upsetting codegen is an emergent property of interactions among these transformations. There is no line of code anywhere that says &quot;Your code is bad, and you must suffer.&quot; &lt;a href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#fr-compiler-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-forward-progress&quot;&gt;
&lt;p&gt;The forward-progress rule ([intro.progress]) lets the implementation assume a thread will eventually perform an observable action or terminate. A spin loop whose body has no observable side effects may therefore be assumed to exit; here that means &lt;code&gt;while (!ready) {}&lt;&#x2F;code&gt; gets dropped entirely. (Other standard editions have phrased or scoped this rule differently.) &lt;a href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#fr-forward-progress-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-unaligned&quot;&gt;
&lt;p&gt;Constructing this example took some trial and error. This is also a known phenomenon in the wild: a checksum routine that summed &lt;code&gt;uint32_t&lt;&#x2F;code&gt; words crashed with SIGSEGV when GCC assumed four-byte alignment and used an aligned SSE load — see Peter Zemskov, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pzemtsov.github.io&#x2F;2016&#x2F;11&#x2F;06&#x2F;bug-story-alignment-on-x86.html&quot;&gt;&quot;A bug story: data alignment on x86&quot;&lt;&#x2F;a&gt;. &lt;a href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#fr-unaligned-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-codegen&quot;&gt;
&lt;p&gt;The compiler is not &lt;em&gt;required&lt;&#x2F;em&gt; to generate the particular codegen you are picturing. The point is that, when you are only discussing performance, a missed-optimization bug report won&#x27;t be dismissed on the grounds that your code has undefined behavior. &lt;a href=&quot;https:&#x2F;&#x2F;blog.weaselab.dev&#x2F;on-x86-stop-listening&#x2F;#fr-codegen-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</description>
      </item>
    </channel>
</rss>
