title: Why is the standard "abs" function faster than mine?
body: <p>I wanted to try making my own absolute value function. I figured that the fastest way to calculate absolute value would be to simply mask out the sign bit (the last bit in IEEE 754). I wanted to compare it's speed to the standard <code>abs</code> function. Here is my implementation:</p>
  <pre class="lang-cpp prettyprint-override"><code>// Union used for type punning
  union float_uint_u
  {
      float f_val;
      unsigned int ui_val;
  };
  
  // 'MASK' has all bits == 1 except the last one
  constexpr unsigned int MASK = ~(1 &lt;&lt; (sizeof(int) * 8 - 1));
  
  float abs_bitwise(float value)
  {
      float_uint_u ret;
      ret.f_val = value;
      ret.ui_val &amp;= MASK;
         
      return ret.f_val;
  }
  </code></pre>
  <p>For the record, I know that this sort of type punning is not standard C++. However, this is just for educational purposes, and according to the docs, <a href="https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#Type-punning" rel="nofollow noreferrer">this is supported in GCC</a>.</p>
  <p>I figured this should be the fastest way to calculate absolute value, so it should at the very least be as fast as the standard implementation. However, timing 100000000 iterations of random values, I got the following results:</p>
  <pre class="lang-none prettyprint-override"><code>Bitwise time: 5.47385 | STL time: 5.15662
  Ratio: 1.06152
  </code></pre>
  <p>My <code>abs</code> function is about 6% slower.</p>
  <h2>Assembly output</h2>
  <p>I compiled with <code>-O2</code> optimization and the <code>-S</code> option (assembly output) to help determine what was going on. I have extracted the relevant portions:</p>
  <pre class="lang-none prettyprint-override"><code>; 16(%rsp) is a value obtained from standard input
  movss   16(%rsp), %xmm0
  andps   .LC5(%rip), %xmm0 ; .LC5 == 2147483647
  movq    %rbp, %rdi
  cvtss2sd    %xmm0, %xmm0
  
  movl    16(%rsp), %eax
  movq    %rbp, %rdi
  andl    $2147483647, %eax
  movd    %eax, %xmm0
  cvtss2sd    %xmm0, %xmm0
  </code></pre>
  <h3>Observations</h3>
  <p>I'm not great at assembly, but the main thing I noticed is that the standard function operates directly on the <code>xmm0</code> register. But with mine, it first moves the value to <code>eax</code> (for some reason), performs the <code>and</code>, and then moves it into <code>xmm0</code>. I'm assuming the extra <code>mov</code> is where the slow down happens. I also noticed that, for the standard, it stores the bit mask elsewhere in the program vs an immediate. I'm guessing that's not significant, however. The two versions also use different instructions (e.g. <code>movl</code> vs <code>movss</code>).</p>
  <h3>System info</h3>
  <p>This was compiled with g++ on Debian Linux (unstable branch). <code>g++ --version</code> output:</p>
  <pre class="lang-none prettyprint-override"><code>g++ (Debian 10.2.1-6) 10.2.1 20210110
  </code></pre>
  <hr />
  <p>If these two versions of the code both calculate absolute value the same way (via an <code>and</code>), why doesn't the optimizer generate the same code? Specifically, why does it feel the need to include an extra <code>mov</code> when it optimizes my implementation?</p>