title: Optimisation of a write out of a loop
body: <p>Moving a member variable to a local variable reduces the number of writes in this loop despite the presence of the __restrict keyword. This is using GCC -O3.  Clang and MSVC optimise the writes in both cases.   <em>[Note that since this question was posted we observed that adding __restrict to the calling function caused GCC to also move the store out of the loop. See the godbolt link below and the comments]</em></p>
  
  <pre><code>class X
  {
  public:
      void process(float * __restrict d, int size)
      {
          for (int i = 0; i &lt; size; ++i)
          {
              d[i] = v * c + d[i];
              v = d[i];
          }
      }
  
      void processFaster(float * __restrict d, int size)
      {
          float lv = v;
          for (int i = 0; i &lt; size; ++i)
          {
              d[i] = lv * c + d[i];
              lv = d[i];
          }
          v = lv;
      }
  
      float c{0.0f};
      float v{0.0f};
  };
  </code></pre>
  
  <p>With gcc -O3 the first one has an inner loop that looks like:</p>
  
  <pre><code>.L3:
    mulss xmm0, xmm1
    add rdi, 4
    addss xmm0, DWORD PTR [rdi-4]
    movss DWORD PTR [rdi-4], xmm0
    cmp rax, rdi
    movss DWORD PTR x[rip+4], xmm0        ;&lt;&lt;&lt; the extra store
    jne .L3
  .L1:
    rep ret
  </code></pre>
  
  <p>The second here:</p>
  
  <pre><code>.L8:
    mulss xmm0, xmm1
    add rdi, 4
    addss xmm0, DWORD PTR [rdi-4]
    movss DWORD PTR [rdi-4], xmm0
    cmp rdi, rax
    jne .L8
  .L7:
    movss DWORD PTR x[rip+4], xmm0
    ret
  </code></pre>
  
  <p>See <a href="https://godbolt.org/g/a9nCP2" rel="nofollow noreferrer">https://godbolt.org/g/a9nCP2</a> for the complete code.</p>
  
  <p>Why does the compiler not perform the lv optimisation here?  </p>
  
  <p>I'm assuming the 3 memory accesses per loop are worse than the 2 (assuming size is not a small number), though I've not measured this yet.</p>
  
  <p>Am I right to make that assumption?</p>
  
  <p>I think the observable behaviour should be the same in both cases.</p>