<div class="gmail_quote">On 12 March 2012 00:58, Robert Jacques <span dir="ltr"><<a href="mailto:sandford@jhu.edu">sandford@jhu.edu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">That's an argument for using the right register for the job. And we can / will be doing this on x86-64, as other compilers have already done. Manu was arguing that MRV were somehow special and had mystical optimization potential. That's simply not true.</div>

</blockquote><div><br></div><div>Here's some tests for you:</div><div><br></div><div><font face="'courier new', monospace">// first test that the argument registers allocate as expected...</font></div><div><div>
<div><font face="'courier new', monospace">int gprtest(int x, int y, int z)</font></div><div><font face="'courier new', monospace">{</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">   </span>return x+y+z;</font></div>
<div><font face="'courier new', monospace">}</font></div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace">   Perfect, ints pass in register sequence, return in r0, no memory access</font></div>
<div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">     </span>add<span class="Apple-tab-span" style="white-space:pre"> </span>r0, r0, r1</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>add<span class="Apple-tab-span" style="white-space:pre"> </span>r0, r0, r2</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>bx<span class="Apple-tab-span" style="white-space:pre">  </span>lr</font></div></div><div><font face="'courier new', monospace"><br>
</font></div><div><font face="'courier new', monospace">float fptest(float x, float y, float z)</font></div><div><font face="'courier new', monospace">{</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">   </span>return x+y+z;</font></div>
<div><font face="'courier new', monospace">}</font></div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace">   Same for floats</font></div><div><div>
<font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">   </span>fadds<span class="Apple-tab-span" style="white-space:pre">       </span>s0, s0, s1</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>fadds<span class="Apple-tab-span" style="white-space:pre">       </span>s0, s0, s2</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>bx<span class="Apple-tab-span" style="white-space:pre">  </span>lr</font></div></div><div><font face="'courier new', monospace"><br>
</font></div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace">// Some MRV tests...</font></div><div><div><font face="'courier new', monospace">auto mrv1(int x, int z)</font></div>
<div><font face="'courier new', monospace">{</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">     </span>return Tuple!(int, int)(x, z);</font></div><div>
<font face="'courier new', monospace">}</font></div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace">  Simple case, 2 ints</font></div><div><font face="'courier new', monospace">  FAIL, stores the 2 arguments it received in regs straight to output struct pointer supplied</font></div>
<div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">     </span>stmia<span class="Apple-tab-span" style="white-space:pre">       </span>r0, {r1, r2}</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">      </span>bx<span class="Apple-tab-span" style="white-space:pre">  </span>lr</font></div>
</div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace">auto mrv2(int x, float y, byte z)</font></div>
<div><font face="'courier new', monospace">{</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">     </span>return Tuple!(int, float, byte)(x, y, z);</font></div>
<div><font face="'courier new', monospace">}</font></div></div></div></div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace">  Different typed things</font></div>
<div><font face="'courier new', monospace">  EPIC FAIL</font></div><div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">       </span>stmfd<span class="Apple-tab-span" style="white-space:pre">       </span>sp!, {r4, r5}</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>mov<span class="Apple-tab-span" style="white-space:pre"> </span>ip, #0</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">    </span>sub<span class="Apple-tab-span" style="white-space:pre"> </span>sp, sp, #24</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>mov<span class="Apple-tab-span" style="white-space:pre"> </span>r4, r2</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">    </span>str<span class="Apple-tab-span" style="white-space:pre"> </span>ip, [sp, #12]</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>str<span class="Apple-tab-span" style="white-space:pre"> </span>ip, [sp, #20]</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">     </span>ldr<span class="Apple-tab-span" style="white-space:pre"> </span>r2, .L27</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>add<span class="Apple-tab-span" style="white-space:pre"> </span>ip, sp, #24</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">       </span>mov<span class="Apple-tab-span" style="white-space:pre"> </span>r3, r0</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>mov<span class="Apple-tab-span" style="white-space:pre"> </span>r5, r1</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">    </span>str<span class="Apple-tab-span" style="white-space:pre"> </span>r2, [sp, #16]<span class="Apple-tab-span" style="white-space:pre">       </span>@ float</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>ldmdb<span class="Apple-tab-span" style="white-space:pre">       </span>ip, {r0, r1, r2}</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">  </span>stmia<span class="Apple-tab-span" style="white-space:pre">       </span>r3, {r0, r1, r2}</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>fsts<span class="Apple-tab-span" style="white-space:pre">        </span>s0, [r3, #4]</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">      </span>stmia<span class="Apple-tab-span" style="white-space:pre">       </span>sp, {r0, r1, r2}</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>str<span class="Apple-tab-span" style="white-space:pre"> </span>r5, [r3, #0]</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">      </span>strb<span class="Apple-tab-span" style="white-space:pre">        </span>r4, [r3, #8]</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>mov<span class="Apple-tab-span" style="white-space:pre"> </span>r0, r3</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">    </span>add<span class="Apple-tab-span" style="white-space:pre"> </span>sp, sp, #24</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>ldmfd<span class="Apple-tab-span" style="white-space:pre">       </span>sp!, {r4, r5}</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">     </span>bx<span class="Apple-tab-span" style="white-space:pre">  </span>lr</font></div>
</div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace"><br></font></div><div><div><font face="'courier new', monospace">auto range(int *p)</font></div>
<div><font face="'courier new', monospace">{</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">     </span>return p[0..1];</font></div><div><font face="'courier new', monospace">}</font></div>
</div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace">  Range</font></div><div><font face="'courier new', monospace">  SURPRISE FAIL, even a range is returned as a struct! O_O</font></div>
<div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">     </span>mov<span class="Apple-tab-span" style="white-space:pre"> </span>r2, #1</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">    </span>str<span class="Apple-tab-span" style="white-space:pre"> </span>r2, [r0, #0]</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>str<span class="Apple-tab-span" style="white-space:pre"> </span>r1, [r0, #4]</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">      </span>bx<span class="Apple-tab-span" style="white-space:pre">  </span>lr</font></div>
</div><div><br></div><div><br></div><div>So the D ABI is a complete shambles on ARM!</div><div>Unsurprisingly, it all just follows the return struct by-val ABI, which is to write it to the stack unconditionally. And sadly, it even thinks the internal types like range+delegate are just a struct by-val, and completely ruins those!</div>
<div><br></div><div>Let's try again with x86...</div><div><div><div><br></div><div><br></div><div><div><font face="'courier new', monospace">auto mrv1(int x, int z)</font></div><div><font face="'courier new', monospace">{</font></div>
<div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">        </span>return Tuple!(int, int)(x, z);</font></div><div><font face="'courier new', monospace">}</font></div><div>
<font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace">Returns in eax/edx as expected</font></div><div><font face="'courier new', monospace"> movl        4(%esp), %eax</font></div>
<div><div><font face="'courier new', monospace"> movl      8(%esp), %edx
</font></div></div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace">auto mrv2(int x, float y, int z)</font></div>
<div><font face="'courier new', monospace">{</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">     </span>return Tuple!(int, float, int)(x, y, z);</font></div>
<div><font face="'courier new', monospace">}</font></div></div></div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace">FAIL! All written to a struct rather than returning in eax,edx,st0 .. This is C ABI baggage, D can do better.</font></div>
<div><div><font face="'courier new', monospace"> movl      4(%esp), %eax</font></div><div><font face="'courier new', monospace"> movl   8(%esp), %edx</font></div><div><font face="'courier new', monospace"> movl   %edx, (%eax)</font></div>
<div><font face="'courier new', monospace"> movl 12(%esp), %edx</font></div><div><font face="'courier new', monospace"> movl  %edx, 4(%eax)</font></div><div><font face="'courier new', monospace"> movl   16(%esp), %edx</font></div>
<div><font face="'courier new', monospace"> movl %edx, 8(%eax)</font></div><div><font face="'courier new', monospace"> ret    $4
</font></div></div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace"><br></font></div><div><div><font face="'courier new', monospace">auto range(int *p)</font></div>
<div><font face="'courier new', monospace">{</font></div><div><font face="'courier new', monospace"><span class="Apple-tab-span" style="white-space:pre">     </span>return p[0..1];</font></div><div><font face="'courier new', monospace">}</font></div>
</div><div><font face="'courier new', monospace"><br></font></div><div><font face="'courier new', monospace">Obviously, the small struct optimisation allows this to work properly</font></div><div><div><font face="'courier new', monospace"> movl       $1, %eax</font></div>
<div><font face="'courier new', monospace"> movl 4(%esp), %edx</font></div><div><font face="'courier new', monospace"> ret</font></div></div></div><div><font face="'courier new', monospace"><br></font></div>
<div><br></div><div>All that said, x86 isn't a good test case, since all args are ALWAYS passed on the stack. x64 would be a much better test since it actually has arg registers, but I'm on windows, so no x64 for me...</div>
</div>