I'm not sure I follow all of your comments.
For the rest my comments, let's assume that the compiler may assume that
__move_post_blt is a no-op if hasElaborateMove returns false.
On 17/05/18 14:33, kinke wrote:
3. When deciding to move a struct instance, the compiler MUST emit a
call to the struct's __move_post_blt after blitting the instance and
before releasing the memory containing the old instance.
__move_post_blt MUST receive references to both the pre- and post-move
instances.
This implies that such structs must not be considered PODs, i.e., cannot
be passed in registers and must be passed on the stack.
I'm not familiar with passing structs in registers. I am familiar with
passing pointer to the structs in registers, which should not be
affected by this.
If actual (I'm assuming short) structs can be passed in registers, then,
yes, structs with elaborate move are not PoDs.
It also means
that the compiler will have to insert a __move_post_blt call right
before the call (as the callee has no idea about the old address),
Again, as far as I know, structs are not copied when passed as
arguments. They are allocated on the caller's stack and a reference is
passed to the callee. If that's the case, no move (of any kind) is done.
I might be missing something. Can you write a code snippet to which you
are referring?
after
blitting the arg to the callee params stack; this may be tricky to
implement for LDC, as that last blit is implicit in LLVM IR (LLVM byval
attribute).
And yet, C++ clang managed to do it in classes with && constructors.
As a side note, when passing a postblit-struct lvalue arg by value,
Just to be clear, are we talking about passing by reference an instance
of a struct that has postblit?
the
compiler first copies the lvalue
to a temporary on the caller's stack,
incl. postblit call, and then moves that copy to the callee. So this
requires either a postblit+postmove combo on the caller side before the
actual call, or a single postblit call for the final address (callee's
param).
Again, that does not align with my familiarity of the ABI. If I do:
struct S {
...
this(this) {
// some code
}
void opPostMove(ref S new, const ref S old) {
// some code
}
}
void func1(ref S arg) {
}
void func2(S arg) {
}
As far as I know the ABI, in func1, a pointer to S is passed. In func2,
a pointer to caller stack allocate instance is passed, and the original
is copied in. It sounds to me like you are talking about the case of:
S s;
func2(s);
in which case you need to copy s to a temporary, and then pass a pointer
to that temporary to func2. I don't see where a move enters here.
However, if a move does enter here (and one is necessary if, for
example, func2's frame needs to be dynamically allocated because an
escaping delegate references it), then, yes, an opPostMove will also
need to be called.
Again, if hasElaborateMove returns false, then no change from current
behavior is needed.
Shachar