-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Added llvm lifetime annotations to function call argument temporaries. #98377
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
Added llvm lifetime annotations to function call argument temporaries. #98377
Conversation
The goal of this change is to ensure that llvm will do stack slot optimization on these temporaries. This ensures that in code like: ```rust const A: [u8; 1024] = [0; 1024]; fn copy_const() { f(A); f(A); } ``` we only use 1024 bytes of stack space, instead of 2048 bytes.
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @davidtwco (or someone else) soon. Please see the contribution instructions for more information. |
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.
This looks good to me. I think a mir-opt
test might be appropriate, as that should observe the addition of the StorageLive
and StorageDead
statements for the copy.
There are no (An alternative way to solve this would be to change MIR semantics so that isn't the case, e.g. by removing the ability to have constant arguments, requiring all arguments to be places, and thus making argument copies explicit in MIR. This might allow additional optimizations [perhaps removing unnecessary copies? I haven't really thought about it]. But I think that would be much more complex than this change.) The following codegen test should work (maybe with some tweaks, haven't tried it locally), e.g. as // This test checks that temporaries for indirectly-passed arguments get lifetime markers.
// compile-flags: -O -C no-prepopulate-passes -Zmir-opt-level=0
#![crate_type = "lib"]
extern "Rust" {
fn f(x: [u8; 1024]);
}
const A: [u8; 1024] = [0; 1024];
// CHECK-LABEL: @const_arg_indirect
#[no_mangle]
pub unsafe fn const_arg_indirect() {
// Ensure that the live ranges for the two argument temporaries don't overlap.
// CHECK: call void @llvm.lifetime.start
// CHECK: call void @f
// CHECK: call void @llvm.lifetime.end
// CHECK: call void @llvm.lifetime.start
// CHECK: call void @f
// CHECK: call void @llvm.lifetime.end
f(A);
f(A);
} |
6898411
to
259a7a7
Compare
On the suggestion of changing MIR semantics, that would make the temporaries available for optimization in MIR, but at the cost of a move that might make things more difficult around constant folding. And changing MIR semantics this way would make it necessary for all constants, even those which are small and currently passed by value instead of by reference. I'm not sure whether that trade-off is worth it. |
@rustbot label -S-waiting-on-author +S-waiting-on-review |
r? @oli-obk Seems like this needs someone more recently familiar with MIR than me :) |
@bors try @rust-timer queue |
Awaiting bors try build completion. @rustbot label: +S-waiting-on-perf |
⌛ Trying commit 259a7a7 with merge e63015e2cd9d6ff835d4ea545bf9bac4f90cea49... |
I have played with the thought of storing all constants in locals and thus massively simplifying |
☀️ Try build successful - checks-actions |
Queued e63015e2cd9d6ff835d4ea545bf9bac4f90cea49 with parent 493c960, future comparison URL. |
Finished benchmarking commit (e63015e2cd9d6ff835d4ea545bf9bac4f90cea49): comparison url. Instruction countThis benchmark run did not return any relevant results for this metric. Max RSS (memory usage)Results
CyclesResults
If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf. Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf. @bors rollup=never Footnotes |
Yea this seems like the best impl for now to me. We can only make a decision here if we know how the argument will get passed, and that requires asking the backend, which is not information we have or want to have available during mir opts @bors r+ |
📌 Commit 259a7a7 has been approved by |
☀️ Test successful - checks-actions |
Finished benchmarking commit (7425fb2): comparison url. Instruction count
Max RSS (memory usage)Results
CyclesResults
If you disagree with this performance assessment, please file an issue in rust-lang/rustc-perf. @rustbot label: -perf-regression Footnotes |
The goal of this change is to ensure that llvm will do stack slot
optimization on these temporaries. This ensures that in code like:
we only use 1024 bytes of stack space, instead of 2048 bytes.
I am new to developing for the rust compiler, and as such not entirely sure, but I believe this should be sufficient to close #98156.
Also, this does not contain a test case to ensure this keeps working, primarily because I am not sure how to go about testing this. I would love some suggestions as to how that could be approached.