On 12 March 2012 01:37, Andrew Wiley <wiley.andre...@gmail.com> wrote: > On Sun, Mar 11, 2012 at 7:44 PM, Manu <turkey...@gmail.com> wrote: >> On 12 March 2012 00:58, Robert Jacques <sandf...@jhu.edu> wrote: >>> >>> 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. >> >> >> Here's some tests for you: >> >> // first test that the argument registers allocate as expected... >> int gprtest(int x, int y, int z) >> { >> return x+y+z; >> } >> >> Perfect, ints pass in register sequence, return in r0, no memory access >> add r0, r0, r1 >> add r0, r0, r2 >> bx lr >> >> float fptest(float x, float y, float z) >> { >> return x+y+z; >> } >> >> Same for floats >> fadds s0, s0, s1 >> fadds s0, s0, s2 >> bx lr >> >> >> // Some MRV tests... >> auto mrv1(int x, int z) >> { >> return Tuple!(int, int)(x, z); >> } >> >> Simple case, 2 ints >> FAIL, stores the 2 arguments it received in regs straight to output struct >> pointer supplied >> stmia r0, {r1, r2} >> bx lr >> >> >> auto mrv2(int x, float y, byte z) >> { >> return Tuple!(int, float, byte)(x, y, z); >> } >> >> Different typed things >> EPIC FAIL >> stmfd sp!, {r4, r5} >> mov ip, #0 >> sub sp, sp, #24 >> mov r4, r2 >> str ip, [sp, #12] >> str ip, [sp, #20] >> ldr r2, .L27 >> add ip, sp, #24 >> mov r3, r0 >> mov r5, r1 >> str r2, [sp, #16] @ float >> ldmdb ip, {r0, r1, r2} >> stmia r3, {r0, r1, r2} >> fsts s0, [r3, #4] >> stmia sp, {r0, r1, r2} >> str r5, [r3, #0] >> strb r4, [r3, #8] >> mov r0, r3 >> add sp, sp, #24 >> ldmfd sp!, {r4, r5} >> bx lr >> >> >> auto range(int *p) >> { >> return p[0..1]; >> } >> >> Range >> SURPRISE FAIL, even a range is returned as a struct! O_O >> mov r2, #1 >> str r2, [r0, #0] >> str r1, [r0, #4] >> bx lr >> >> >> So the D ABI is a complete shambles on ARM! >> 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! >> >> Let's try again with x86... >> >> >> auto mrv1(int x, int z) >> { >> return Tuple!(int, int)(x, z); >> } >> >> Returns in eax/edx as expected >> movl 4(%esp), %eax >> movl 8(%esp), %edx >> >> >> auto mrv2(int x, float y, int z) >> { >> return Tuple!(int, float, int)(x, y, z); >> } >> >> FAIL! All written to a struct rather than returning in eax,edx,st0 .. This >> is C ABI baggage, D can do better. >> movl 4(%esp), %eax >> movl 8(%esp), %edx >> movl %edx, (%eax) >> movl 12(%esp), %edx >> movl %edx, 4(%eax) >> movl 16(%esp), %edx >> movl %edx, 8(%eax) >> ret $4 >> >> >> auto range(int *p) >> { >> return p[0..1]; >> } >> >> Obviously, the small struct optimisation allows this to work properly >> movl $1, %eax >> movl 4(%esp), %edx >> ret >> >> >> 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... > > I assume this is with GDC? Pretty sure GDC doesn't match D's official > ABI anyway because Iain didn't want to try to push D ABI support into > GCC along with GDC. > You're probably still right, but be aware that GDC is a bit different here.
Well, this is taken off the D ABI documentation. The extern (C) and extern (D) calling convention matches the C calling convention used by the supported C compiler on the host system. Except that the extern (D) calling convention for Windows x86 is described here. Examining it in a literal sense, I can say that GDC is compliant with the spec (except on x86 Windows, which it uses stdcall rather than the calling convention described on the page). -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0';