On Saturday, 2 April 2016 at 09:28:58 UTC, ZombineDev wrote:
On Wednesday, 23 March 2016 at 19:39:49 UTC, kinke wrote:
On Tuesday, 22 March 2016 at 07:35:49 UTC, ZombineDev wrote:
If the object is larger than the size of a register on the
target machine, it is implicitly passed by ref
That's incorrect. As Johan pointed out, this is somewhat true
for the Win64 ABI (but it firstly copies the argument before
passing a pointer to it!), but it's not for the 32-bit x86 and
x86_64 System V (used on all non-Windows platforms) ABIs.
System V is especially elaborate and may pass structs up to
twice the size of a register in 2 registers. Bigger structs
passed by value are blitted into the function arguments stack
in memory. They are then accessed by the callee via a stack
offset, that's correct, but I wouldn't call that
implicit-by-ref-passing, as copying does take place, unless
the optimizer decides it's unnecessary.
So passing structs > 64-bit by value on Win64 never pays off
(there's always an indirection); using `const ref(T)` where
possible makes sure you at least elide the copy. But then
again, you'll very soon find out that it's not really an
option as rvalues cannot be passed byref in D, something a lot
of people [including myself if not already obvious :)] hate
about D.
Thank you and Johan for the detailed explanation. You're
efforts on improving LDC are much appreciated.
My intentions were to say that taking structs by value
shouldn't be as expensive as in C++, because of the way D
handles copy construction, especially if there is no
user-defined postblit (which is quite common), and also because
separate compilation is used more rarely.
But probably I shouldn't have said that about the size of
registers as it depends very much on the ABI and it's not true
in general (as you pointed out).
BTW, how does LDC handle the `auto ref` and `in` parameter
attributes for templated functions (that obviously have their
source code available)? Can they be used to prevent indirection
when the structure can be passed in registers and to prevent
copying when passing by registers is not possible?
I find that (at least from a usability standpoint) auto ref works
quite well:
// UniqueRef has disabled this(this)
UniqueRef!Resource r;
void use()(auto ref UniqueRef!Resource r);
// borrows
use(r);
// passes ownership of rvalues
use(UniqueRef!Resource())
// transfers ownership
use(move(r));
// r == UniqueRef.init here
//=============
auto ref add(V)(auto ref V v1, auto ref V v2);
// default this(this)
Vec3f vec1;
// accepts both lvalues and rvalues
auto res = add(vec1, Vec3f(1, 2, 3.14));