title: GCC -O3 generates strange assembly for std::uninitialized_default_construct
body: <p>I'm looking at the assembly generated by GCC 9.1 for the new (C++17) function std::uninitialized_default_construct. In most cases (MSVC, Clang, even older GCC) it's what you would expect: a loop with calling (or inlining) the default constructor of the type T. </p>
  
  <p>For some reason, the GCC from 7 to current run with -03 generates assembly that I do not fully understand. Especially the part that looks like hashing at the beginning.</p>
  
  <p>I'm compiling with "-O3 -std=c++17 -fno-stack-protector -fno-exceptions -fomit-frame-pointer -fno-unroll-loops". Am I missing something here?</p>
  
  <p>Tested the same code on various compilers. None behaves this strangely. There's no explanation I could find for the hashing thing. </p>
  
  <p>Test code (run via godbolt.org):</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;algorithm&gt;
  #include &lt;memory&gt;
  #include &lt;string&gt;
  #include &lt;stdio.h&gt;
  
  struct Vector3 {
      float x=0,y=0,z=0; 
  };
  
  template&lt; typename T &gt;
  static int init(T* mem, size_t len)
  {
      std::uninitialized_default_construct(mem, mem+len);     
      return 0;
  }
  
  template&lt; typename T &gt;
  static int init2(T* mem, size_t len)
  {
      auto end = mem + len;
      while (mem &lt; end)
          new (mem++) T();
      return 0;
  }
  
  int main(int argc, char** argv)
  {
      Vector3 mem[100];
      auto funcPtr = (argc &gt; 2) ? &amp;init&lt;Vector3&gt; : &amp;init2&lt;Vector3&gt;;
  
      if (0 != funcPtr(mem, (int)atoi(argv[1])))
          return -1;
      printf("%f\n", mem[0].x);
      return 0;
  }
  </code></pre>
  
  <p>Generated disassembly for function "init" (brace yourself):</p>
  
  <pre><code>int init&lt;Vector3&gt;(Vector3*, unsigned long):
          lea     rax, [rsi+rsi*2]
          lea     rcx, [rdi+rax*4]
          cmp     rcx, rdi
          je      .L2
          movabs  rsi, 3074457345618258603
          mov     rdx, rcx
          mov     rax, rdi
          sub     rdx, rdi
          sub     rdx, 12
          shr     rdx, 2
          imul    rdx, rsi
          movabs  rsi, 4611686018427387903
          and     rdx, rsi
          lea     rsi, [rdx+1]
          cmp     rdx, 2
          jbe     .L3
          mov     rdx, rsi
          pxor    xmm0, xmm0
          shr     rdx, 2
          lea     rdx, [rdx+rdx*2]
          sal     rdx, 4
          add     rdx, rdi
  .L4:
          movups  XMMWORD PTR [rax], xmm0
          add     rax, 48
          movups  XMMWORD PTR [rax-32], xmm0
          movups  XMMWORD PTR [rax-16], xmm0
          cmp     rax, rdx
          jne     .L4
          mov     rax, rsi
          and     rax, -4
          lea     rdx, [rax+rax*2]
          lea     rdi, [rdi+rdx*4]
          cmp     rsi, rax
          je      .L2
  .L3:
          lea     rax, [rdi+12]
          mov     QWORD PTR [rdi], 0
          mov     DWORD PTR [rdi+8], 0x00000000
          cmp     rcx, rax
          je      .L2
          lea     rax, [rdi+24]
          mov     QWORD PTR [rdi+12], 0
          mov     DWORD PTR [rdi+20], 0x00000000
          cmp     rcx, rax
          je      .L2
          mov     QWORD PTR [rdi+24], 0
          mov     DWORD PTR [rdi+32], 0x00000000
  .L2:
          xor     eax, eax
          ret
  </code></pre>
  
  <p>For comparison, this is what MSVC generates for the same code:</p>
  
  <pre><code>int init&lt;Vector3&gt;(Vector3 *,unsigned __int64) PROC         ; init&lt;Vector3&gt;, COMDAT
          lea     rax, QWORD PTR [rdx+rdx*2]
          lea     rdx, QWORD PTR [rcx+rax*4]
          xor     eax, eax
          cmp     rcx, rdx
          je      SHORT $LN5@init
          npad    1
  $LL6@init:
          mov     QWORD PTR [rcx], rax
          mov     DWORD PTR [rcx+8], eax
          add     rcx, 12
          cmp     rcx, rdx
          jne     SHORT $LL6@init
  $LN5@init:
          ret     0
  </code></pre>
  
  <p>Is there a way to make GCC behave properly?</p>