-
-
Notifications
You must be signed in to change notification settings - Fork 14.4k
abi: add a rust-preserve-none calling convention #151065
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
Conversation
|
This PR changes rustc_public cc @oli-obk, @celinval, @ouz-a, @makai410 rust-analyzer is developed in its own repository. If possible, consider making this change to rust-lang/rust-analyzer instead. cc @rust-lang/rust-analyzer |
This comment was marked as outdated.
This comment was marked as outdated.
ecf300a to
6d27ba9
Compare
This comment has been minimized.
This comment has been minimized.
|
This seems somewhat related: I believe that there is no way to make tail calls work with ABIs that pass values using This calling convention is probably still useful, but adding another calling convention that uses the (unstable!) rust ABI won't actually help with moving tail call support forward. So maybe there is a possible design of an Also for completeness, using |
|
I don't intend this PR to be a solution to the indirect argument passing problem, although I see how having a calling convention with more registers available would help with indirectly passed arguments. My primary incentive is really just performance – spilling registers in the top level caller once is much more efficient than spilling and reloading on every jump. Normally I would probably look for a solution that is transparent to the user, but unfortunately in this case the decision is callee's and it cannot know if it'll be become'd or called regularly in the general case. That reminds me, I guess I'll have to verify if I don't need to change the abi computation code here... |
|
I should update this with that I was wrong, and there does appear to be a way to support Also you may have seen this but there was some recent discussion on better tail call calling conventions recently:
So adding this calling convention as an experiment seems useful, and modulo the test formatting issue it appears to work? |
This comment has been minimized.
This comment has been minimized.
fd925bf to
8631e52
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
f08a413 to
940b4d7
Compare
This comment has been minimized.
This comment has been minimized.
940b4d7 to
664c1fc
Compare
|
Some changes occurred in compiler/rustc_codegen_cranelift cc @bjorn3 Some changes occurred in compiler/rustc_codegen_gcc |
|
Ideally for both rust-cold and rust-preserve-none there would be a check that prevents cross-backend calls that use those abis. And there would be a lint to avoid using them in the standard library as rustup distributed cg_clif uses a cg_llvm compiled standard library. |
This comment has been minimized.
This comment has been minimized.
I wouldn't object to such a check, but at the same time, is this really necessary for an unstable feature that's added chiefly to enable experimentation (in my case with explicit_tail_call?) We can figure these issues as we work out stabilization of it. Lint is probably not too hard to add though… I feel like it could even be deny-by-default and unconditional, and if you want to use for experiments, you allow it. But at the same time, that's exactly what feature gate does already, no? |
664c1fc to
b46772b
Compare
|
I'm fine with landing this PR without such checks. Doesn't make things that much worse as we already have rust-cold. |
This comment has been minimized.
This comment has been minimized.
…trochenkov
abi: add a rust-preserve-none calling convention
This is the conceptual opposite of the rust-cold calling convention and is particularly useful in combination with the new `explicit_tail_calls` feature.
For relatively tight loops implemented with tail calling (`become`) each of the function with the regular calling convention is still responsible for restoring the initial value of the preserved registers. So it is not unusual to end up with a situation where each step in the tail call loop is spilling and reloading registers, along the lines of:
foo:
push r12
; do things
pop r12
jmp next_step
This adds up quickly, especially when most of the clobberable registers are already used to pass arguments or other uses.
I was thinking of making the name of this ABI a little less LLVM-derived and more like a conceptual inverse of `rust-cold`, but could not come with a great name (`rust-cold` is itself not a great name: cold in what context? from which perspective? is it supposed to mean that the function is rarely called?)
|
Commit e1ec059 has been unapproved. |
e1ec059 to
18b8ea2
Compare
|
Hm, looks like LLVM doesn't support anything other than x86_64 or aarch64 for this ABI. I opted to emit a default ABI for targets outside of these for now... For what it is worth PreserveMost (used for "rust-cold") also has this problem, although the target support for that one is a little wider… I also prototyped a PR for upstream LLVM at llvm/llvm-project#177714 while investigating the crash… |
This comment has been minimized.
This comment has been minimized.
18b8ea2 to
fdf0fbd
Compare
This comment has been minimized.
This comment has been minimized.
This is the conceptual opposite of the rust-cold calling convention and
is particularly useful in combination with the new `explicit_tail_calls`
feature.
For relatively tight loops implemented with tail calling (`become`) each
of the function with the regular calling convention is still responsible
for restoring the initial value of the preserved registers. So it is not
unusual to end up with a situation where each step in the tail call loop
is spilling and reloading registers, along the lines of:
foo:
push r12
; do things
pop r12
jmp next_step
This adds up quickly, especially when most of the clobberable registers
are already used to pass arguments or other uses.
I was thinking of making the name of this ABI a little less LLVM-derived
and more like a conceptual inverse of `rust-cold`, but could not come
with a great name (`rust-cold` is itself not a great name: cold in what
context? from which perspective? is it supposed to mean that the
function is rarely called?)
fdf0fbd to
6db94db
Compare
|
@bors r=petrochenkov rollup=never |
|
Scheduling: Encourage a mixture of rollup and non-rollup PRs. @bors p=5 |
This comment has been minimized.
This comment has been minimized.
What is this?This is an experimental post-merge analysis report that shows differences in test outcomes between the merged PR and its parent PR.Comparing 5a07626 (parent) -> 75963ce (this PR) Test differencesShow 14 test diffsStage 1
Stage 2
Additionally, 4 doctest diffs were found. These are ignored, as they are noisy. Job group index
Test dashboardRun cargo run --manifest-path src/ci/citool/Cargo.toml -- \
test-dashboard 75963ce795666bc1f961e5d60060809809f6bc68 --output-dir test-dashboardAnd then open Job duration changes
How to interpret the job duration changes?Job durations can vary a lot, based on the actual runner instance |
|
Finished benchmarking commit (75963ce): comparison URL. Overall result: ❌ regressions - no action needed@rustbot label: -perf-regression Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)This benchmark run did not return any relevant results for this metric. CyclesThis benchmark run did not return any relevant results for this metric. Binary sizeResults (primary 0.0%, secondary 0.0%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 472.363s -> 471.746s (-0.13%) |
This is the conceptual opposite of the rust-cold calling convention and is particularly useful in combination with the new
explicit_tail_callsfeature.For relatively tight loops implemented with tail calling (
become) each of the function with the regular calling convention is still responsible for restoring the initial value of the preserved registers. So it is not unusual to end up with a situation where each step in the tail call loop is spilling and reloading registers, along the lines of:This adds up quickly, especially when most of the clobberable registers are already used to pass arguments or other uses.
I was thinking of making the name of this ABI a little less LLVM-derived and more like a conceptual inverse of
rust-cold, but could not come with a great name (rust-coldis itself not a great name: cold in what context? from which perspective? is it supposed to mean that the function is rarely called?)