[dmd-internals] non-PODs again

Johannes Pfau johannespfau at googlemail.com
Thu Mar 7 09:36:42 PST 2013


I'm sorry I have to pester you with this again, but I still have some 
questions regarding POD types and I'd like to fix this in GDC.

So from last discussion:
 >> Wouldn't it be legal to still pass non-PODs in registers when 
calling functions and only copying them back to
 >> the stack if the address is needed? As we pass structs by value 
anyway, how could this be problematic?
 >
 > No, not allowed. Consider why there are copy constructors, and what 
they do.

I compiled some test programs with dmd and dmd _does_ pass non-POD 
values in registers as I suggested above.
See this example:
https://gist.github.com/jpf91/5064703 (D)
https://gist.github.com/jpf91/5064764 (ASM)

I also don't understand how a copy ctor could break this. I asked on 
D.learn and there was no answer. Of course in C++ where structs have 
identity and interior pointers are allowed passing in register could be 
bad as it changes the address. But in D this is explicitly allowed. So I 
take it that this is actually allowed?

What is weird then is that dmd passes non-PODs in registers for normal 
functions, but for varargs functions they're always passed on the stack. 
I don't think there's a reason to make this difference. I know the SysV 
ABI specifies that non-PODs are never passed in registers, but that's 
only true for C++ PODs*, I don't  see why D non-PODs (no identity, 
internal pointers) couldn't be passed in registers for varargs functions 
as well.


DMD also uses the "invisible reference" trick described in the SysV ABI 
for all non-PODs. But again, I don't see why returning in a register 
would be problematic. In pseudo-asm:

What we have now in DMD:
--------
lea -0x4(%ebp),%edi
call <function>

<function>:
mov <returnvalue>, (%edi)
ret
--------

Why would returning in a register be illegal?
Especially considering that we pass parameters in registers, why not do 
the same for return values?
--------
call <function>
mov %eax, -0x4(%ebp)

<function>:
mov <returnvalue>, %eax
ret
--------


 > Whenever you make a copy of a non-POD value, you have to (for 
example) build an exception handling frame to destruct it if, in
 > the meantime, an exception is thrown. This is not only expensive, but 
it doesn't work if the value lives in registers.

But if the copy is only a temporary bitcopy, i.e the copy constructor & 
postblit wasn't called (and this should be valid as D structs don't have 
identity/internal pointers) then there's no need to call the destructor? 
Maybe I should rather talk about "moving" than copying as in C++s move 
semantics.



* There's actually an explanation in the ABI pdf:
--------
A non-POD object cannot be passed in registers because such objects must 
have well defined
addresses; the address at which an object is constructed (by the caller) 
and the address at which
the object is destroyed (by the callee) must be the same. Similar issues 
apply when returning a
non-POD object from a function.
--------
However, with the current DMD implementation this is not the case. There 
is also no documentation stating that D non-PODs are 
constructed/destructed at the same address. http://dlang.org/struct.html 
says "A struct is defined to _not have an identity_; that is, the 
implementation is free to make bit copies of the struct as convenient."

-- 
Johannes Pfau



More information about the dmd-internals mailing list