title: Possible GCC bug when returning struct from a function
body: <p>I believe I found a bug in GCC while implementing O'Neill's PCG PRNG. (<a href="https://c.godbolt.org/z/jzKUgG" rel="noreferrer">Initial code on Godbolt's Compiler Explorer</a>)</p>
  
  <p>After multiplying <code>oldstate</code> by <code>MULTIPLIER</code>, (result stored in rdi), GCC doesn't add that result to <code>INCREMENT</code>, movabs'ing <code>INCREMENT</code> to rdx instead, which then gets used as the return value of rand32_ret.state</p>
  
  <p>A minimum reproducible example (<a href="https://gcc.godbolt.org/z/FCuEsg" rel="noreferrer">Compiler Explorer</a>):</p>
  
  <pre class="lang-c prettyprint-override"><code>#include &lt;stdint.h&gt;
  
  struct retstruct {
      uint32_t a;
      uint64_t b;
  };
  
  struct retstruct fn(uint64_t input)
  {
      struct retstruct ret;
  
      ret.a = 0;
      ret.b = input * 11111111111 + 111111111111;
  
      return ret;
  }
  </code></pre>
  
  <p>Generated assembly (GCC 9.2, x86_64, -O3):</p>
  
  <pre><code>fn:
    movabs rdx, 11111111111     # multiplier constant (doesn't fit in imm32)
    xor eax, eax                # ret.a = 0
    imul rdi, rdx
    movabs rdx, 111111111111    # add constant; one more 1 than multiplier
       # missing   add rdx, rdi   # ret.b=... that we get with clang or older gcc
    ret
  # returns RDX:RAX = constant 111111111111 : 0
  # independent of input RDI, and not using the imul result it just computed
  </code></pre>
  
  <p>Interestingly, modifying the struct to have the uint64_t as the first member <a href="https://gcc.godbolt.org/z/dZsF4v" rel="noreferrer">produces correct code</a>, as does <a href="https://gcc.godbolt.org/z/w6zxZU" rel="noreferrer">changing both members to be uint64_t</a></p>
  
  <p>x86-64 System V does return structs smaller than 16 bytes in RDX:RAX, when they're trivially copyable.  In this case the 2nd member is in RDX because the high half of RAX is the padding for alignment or <code>.b</code> when <code>.a</code> is a narrower type.  (<code>sizeof(retstruct)</code> is 16 either way; we're not using <code>__attribute__((packed))</code> so it respects alignof(uint64_t) = 8.)</p>
  
  <p><strong>Does this code contain any undefined behaviour that would allow GCC to emit the "incorrect" assembly?</strong></p>
  
  <p>If not, this should get reported on <a href="https://gcc.gnu.org/bugzilla/" rel="noreferrer">https://gcc.gnu.org/bugzilla/</a></p>