[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