-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid unnecessary copies of arguments that are simple bindings #45380
Conversation
r? @arielb1 (rust_highfive has picked a reviewer for you, use r? to override) |
@Mark-Simulacrum what do I need to get perf results for this? |
@bors try Ping me when this completes, either here or on IRC and I'll run perf and get back to you. |
Avoid unnecessary copies of arguments that are simple bindings Initially MIR differentiated between arguments and locals, which introduced a need to add extra copies assigning the argument to a local, even for simple bindings. This differentiation no longer exists, but we're still creating those copies, bloating the MIR and LLVM IR we emit. Additionally, the current approach means that we create debug info for both the incoming argument (marking it as an argument), and then immediately shadow it a local that goes by the same name. This can be confusing when using e.g. "info args" in gdb, or when e.g. a debugger with a GUI displays the function arguments separately from the local variables, especially when the binding is mutable, because the argument doesn't change, while the local variable does.
☀️ Test successful - status-travis |
Solid wins across the board timing-wise, though some of the memory use benchmarks increased by 5-15%: http://perf.rust-lang.org/compare.html?start=b7960878ba77124505aabe7dc99d0a898354c326&end=0d4910029c828c95069d88768882a0a46a19220d&stat=instructions%3Au. |
Those performance improvements look awesome, @dotdash! |
So this doesn't break By that, I mean this code: rust/src/librustc_trans/mir/block.rs Lines 513 to 525 in a789fa0
Which is tested in https://github.com/rust-lang/rust/blob/a789fa0440214347e1bf6228fdb8fd36bf2f4520/src/test/run-pass/simd-intrinsic-generic-elements.rs |
So there's a test, so let's @bors r+ and if this bounces, we'll have our reason |
📌 Commit ac99309 has been approved by |
@@ -247,7 +247,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | |||
} else { | |||
let args: Vec<_> = | |||
args.into_iter() | |||
.map(|arg| unpack!(block = this.as_local_operand(block, arg))) | |||
.map(|arg| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, can we have a comment here that says that we must copy the argument to a temp, because functions are allowed to mutate arguments passed to them by-reference on the ABI level? And add a similar comment to librustc/mir/mod.rs
so that there is no confusion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I like the resulting state from this... I think that Call
should either take Local
s instead of Operand
s, or trans
should generate the copy out of non-immediate constants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, do we really want ABI concerns to shape MIR itself, as opposed to the ability to analyze it? I came back to this because I noticed that calls no longer had constants directly in them and thus copy propagation is incorrect into calls, and, without it, certain analyses would now need a bit more dataflow to even observe plain constants in function arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Talked this over with @arielb1 on IRC and I'm leaning towards "Operand::Constant
is caller-owned, Operand::Consume
is callee-owned", which would remove the temporaries for constant arguments and facilitate
Furthermore, we can skip some copies (for !Copy
arguments) during MIR construction and have MIR borrowck enforce the soundness of Call
s (lock the return destination and move in all the arguments).
And reading this again, I think that the "ABI detail" of function arguments belonging to the callee should be documented, at least at @bors r- |
rust/src/librustc_mir/transform/promote_consts.rs Lines 70 to 77 in a789fa0
|
Added some comments to clarify the ownership of function arguments. |
@bors r+ |
📌 Commit 1cc57cd has been approved by |
☔ The latest upstream changes (presumably #45476) made this pull request unmergeable. Please resolve the merge conflicts. |
@bors r=arielb1 |
Initially MIR differentiated between arguments and locals, which introduced a need to add extra copies assigning the argument to a local, even for simple bindings. This differentiation no longer exists, but we're still creating those copies, bloating the MIR and LLVM IR we emit. Additionally, the current approach means that we create debug info for both the incoming argument (marking it as an argument), and then immediately shadow it a local that goes by the same name. This can be confusing when using e.g. "info args" in gdb, or when e.g. a debugger with a GUI displays the function arguments separately from the local variables, especially when the binding is mutable, because the argument doesn't change, while the local variable does.
@bors r=arielb1 |
📌 Commit 8ad7c28 has been approved by |
Avoid unnecessary copies of arguments that are simple bindings Initially MIR differentiated between arguments and locals, which introduced a need to add extra copies assigning the argument to a local, even for simple bindings. This differentiation no longer exists, but we're still creating those copies, bloating the MIR and LLVM IR we emit. Additionally, the current approach means that we create debug info for both the incoming argument (marking it as an argument), and then immediately shadow it a local that goes by the same name. This can be confusing when using e.g. "info args" in gdb, or when e.g. a debugger with a GUI displays the function arguments separately from the local variables, especially when the binding is mutable, because the argument doesn't change, while the local variable does.
💔 Test failed - status-appveyor |
@bors retry
Edit: Looks like this spurious bug has been fixed in BurntSushi/xsv@92de288. We just need to update our cargotest hash. |
This fixes a flaky test which caused spurious failures in rust-lang#45348 and rust-lang#45380
Avoid unnecessary copies of arguments that are simple bindings Initially MIR differentiated between arguments and locals, which introduced a need to add extra copies assigning the argument to a local, even for simple bindings. This differentiation no longer exists, but we're still creating those copies, bloating the MIR and LLVM IR we emit. Additionally, the current approach means that we create debug info for both the incoming argument (marking it as an argument), and then immediately shadow it a local that goes by the same name. This can be confusing when using e.g. "info args" in gdb, or when e.g. a debugger with a GUI displays the function arguments separately from the local variables, especially when the binding is mutable, because the argument doesn't change, while the local variable does.
☀️ Test successful - status-appveyor, status-travis |
This improved the debug compilation time of the |
MIR: hide .rodata constants vs by-ref ABI clash in trans. Back in #45380, constants were copied into locals during MIR creation to ensure that arguments ' memory can be used by the callee, if the constant is placed in `.rodata` and the ABI passes it by-ref. However, there are several drawbacks (see #45380 (comment)), most importantly the complication of constant propagation (UB if a constant ends up in `Call` arguments) and inconveniencing analyses. Instead, I've modified the `rustc_trans` implementation of calls to copy an `Operand::Constant` argument locally if it's not immediate, and added a test that segfaults without the copy. cc @dotdash @arielb1
Fix CopyPropagation regression (2) Remaining part of MIR copyprop regression by (I think) rust-lang#45380, which I missed in rust-lang#45753. ```rust fn foo(mut x: i32) -> i32 { let y = x; x = 123; // `x` is assigned only once in MIR, but cannot be propagated to `y` y } ``` So any assignment to an argument cannot be propagated.
Initially MIR differentiated between arguments and locals, which
introduced a need to add extra copies assigning the argument to a
local, even for simple bindings. This differentiation no longer exists,
but we're still creating those copies, bloating the MIR and LLVM IR we
emit.
Additionally, the current approach means that we create debug info for
both the incoming argument (marking it as an argument), and then
immediately shadow it a local that goes by the same name. This can be
confusing when using e.g. "info args" in gdb, or when e.g. a debugger
with a GUI displays the function arguments separately from the local
variables, especially when the binding is mutable, because the argument
doesn't change, while the local variable does.