You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Can we allow opportunistic in-place argument passing? #614
@nikic suggested to me at the all-hands that sometimes it would be nice to allow function arguments to "opportunistically" be passed in-place: even if the argument is copy, which usually guarantees the caller will see the value at a different address than the callee, it could sometimes be useful to avoid the copy and just pass the value in-place.
@nikic do you have a concrete example of that? @Amanieu do you think your MIR move semantics proposal could help with this?
We already have this which turns copy into move in MIR call terminators: rust-lang/rust#113758
This transformation is not quite correct as far as current semantics is concerned. It ignores the fact that address of a local might be captured when it is passed in place (as an argument or a destination, although I am not sure if the latter is an issue). For example:
--- a.f.3-2-029.DeadStoreElimination-final.before.mir 2026-06-07 00:19:24.265982702 +0200+++ a.f.3-2-029.DeadStoreElimination-final.after.mir 2026-06-07 00:19:24.266036594 +0200@@ -1,15 +1,15 @@-// MIR for `f` before DeadStoreElimination-final+// MIR for `f` after DeadStoreElimination-final
fn f(_1: [u8; 1024]) -> () {
debug a => _1;
let mut _0: ();
let _2: ();
bb0: {
- _2 = g(copy _1) -> [return: bb1, unwind continue];+ _2 = g(move _1) -> [return: bb1, unwind continue];
}
bb1: {
return;
}
}
The change from copy to move potentially introduces behavior which wasn't possible before, since address _1 might be observed before a call to f and inside g.
It probably makes more sense under semantics from "MIR move elimination".
This is actually completely independent from the "MIR move elimination" semantics. See minirust/minirust#65 (comment) for the semantics that I have in mind for move operands to calls. Effectively, passing a place by move "donates" that place to an allocation pool for the duration of the call, and locals (including argument/return place locals) in callees may be allocated from this pool. This gives us the needed flexibility to do all of the optimizations we want.
Activity
Amanieu commentedon Jun 6, 2026
We already have this which turns
copyintomovein MIR call terminators: rust-lang/rust#113758RalfJung commentedon Jun 6, 2026
And how is that justified opsem-wise? Does it check that the address is not observed, or something like that?
Amanieu commentedon Jun 6, 2026
It only applies to locals whose address is never taken.
tmiasko commentedon Jun 6, 2026
This transformation is not quite correct as far as current semantics is concerned. It ignores the fact that address of a local might be captured when it is passed in place (as an argument or a destination, although I am not sure if the latter is an issue). For example:
The change from copy to move potentially introduces behavior which wasn't possible before, since address
_1might be observed before a call tofand insideg.It probably makes more sense under semantics from "MIR move elimination".
Amanieu commentedon Jun 7, 2026
This is actually completely independent from the "MIR move elimination" semantics. See minirust/minirust#65 (comment) for the semantics that I have in mind for move operands to calls. Effectively, passing a place by move "donates" that place to an allocation pool for the duration of the call, and locals (including argument/return place locals) in callees may be allocated from this pool. This gives us the needed flexibility to do all of the optimizations we want.