Skip to content
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

Pulley: tail calls #9251

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

Kmeakin
Copy link
Contributor

@Kmeakin Kmeakin commented Sep 15, 2024

Sorry for the delay, I was on holiday.
The proof of concept works, but codegen for become is not actually implemented yet and so triggers an ICE:

error: internal compiler error: /rustc/9b72238eb813e9d06e9e9d270168512fbffd7ee7/compiler/rustc_codegen_ssa/src/mir/block.rs:1372:17: `TailCall` terminator is not yet supported by `rustc_codegen_ssa`
   --> pulley/src/interp/interp_loop.rs:85:25
    |
85  |                           become (next_handler.fun)($state, $pc);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

So for now return is used instead of become and we must hope that LLVM will be smart enough to recongize the tail call

@Kmeakin Kmeakin requested a review from a team as a code owner September 15, 2024 22:00
@Kmeakin Kmeakin requested review from fitzgen and removed request for a team September 15, 2024 22:00
@github-actions github-actions bot added the pulley Issues related to the Pulley interpreter label Sep 16, 2024
Copy link

Subscribe to Label Action

cc @fitzgen

This issue or pull request has been labeled: "pulley"

Thus the following users have been cc'd because of the following labels:

  • fitzgen: pulley

To subscribe or unsubscribe from this label, edit the .github/subscribe-to-label.json configuration file.

Learn more.

@alexcrichton
Copy link
Member

Thanks for this! I might jump in with a small recommendation on overall structure / CI here -- with a Cargo feature controlling this it unfortunately doesn't play well with our "test with all features enabled" in CI well because it enables the feature when a stable compiler is in use. To fix this I might recommend #[cfg(pulley_tail_call)] perhaps? That would require setting RUSTFLAGS in CI but that could be added to the "Monolith Checks" perhaps as a single cargo check of pulley on nightly? That would also enable this to land despite codegen support not being in upstream rust-lang/rust yet.

@fitzgen
Copy link
Member

fitzgen commented Sep 16, 2024

Thanks! I'll take a look either later today or tomorrow.

Mildly surprised about become not working anymore, as it was working when I did a few experiments around the time of the RFC. I guess rustc is doing a new ssa thing in the midend and hasn't extended support to become yet?

@fitzgen
Copy link
Member

fitzgen commented Sep 16, 2024

FWIW, it looks like rust-lang/rust#127520 was filed about this regression, but closed as WONTFIX, so I also cross-posted the bug to the explicit_tail_calls tracking issue: rust-lang/rust#112788 (comment)

@WaffleLapkin
Copy link

@fitzgen I'm not sure how it could have worked for you -- become was never fully implemented. (maybe you tried to use it when it was just an alternative syntax for return?)

either way the reason why rust-lang/rust#127520 was WONTFIXED is that tails calls are simply not implemented yet, they are an incomplete feature. The error even says as much:

TailCall terminator is not yet supported by rustc_codegen_ssa

there is no reason to bring any more awareness to this issue -- it will be fixed naturally once the implementation is complete.

Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Really happy with how this shaped up.

Feel free to split out subcommits if you want, but it isn't necessary. Not sure they will actually land first at this point, since the final commit doesn't have as much feedback. Probably good to do for future PRs tho, just to keep things nice and easy for reviewers 👍

Big thing needed to land this is integrating with our CI infrastructure and replacing the cargo feature, as Alex mentioned.

Thanks!

pulley/src/decode.rs Outdated Show resolved Hide resolved
pulley/src/interp.rs Outdated Show resolved Hide resolved
Comment on lines 616 to 610
fn pc_rel_jump(&mut self, offset: PcRelOffset, inst_size: isize) -> Continuation {
fn pc_rel_jump(&mut self, offset: PcRelOffset, inst_size: isize) {
let offset = isize::try_from(i32::from(offset)).unwrap();
self.pc = unsafe { self.pc.offset(offset - inst_size) };
Continuation::Continue
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For caller ergonomics, this could still return a ControlFlow::Continue(()). This way, we wouldn't need to update every call site to also return that value.

Comment on lines 600 to 594
enum Continuation {
Continue,
/// The reason the interpreter loop terminated.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Done {
/// A `ret` instruction was executed and the call stack was empty. This is
/// how the loop normally ends.
ReturnToHost,

/// a `trap` instruction was executed.
Trap,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, the size of ControlFlow<Done> is going to be bigger than the size of Continuation was, because there will be two enum discriminant tags instead of one. But that is fine, and we can measure performance down the line and see if this actually matters. I suspect it might matter if it crosses an ABI threshold where returning these values goes from being in a register to going through a return pointer to a caller-supplied, stack-allocated space. But, as I said, we can always measure later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=4536593481e0f790a4f2d31c969b7e19

ControlFlow<Done, ()> and Continuation are both 1 byte (it seems rustc is smart enough to use the "unused discriminants" from Done as niches for ControlFlow).

ControlFlow<Done, OpcodeHandler> is 2 words. The alternative would be to return ControlFlow<Done, ()> and set the next handler via an &mut OpcodeHandler parameter, but I expect that might be harder for LLVM to optimize. In the worst case, returning a large aggregate will be lowered to returning via an out-parameter anyway, so it shouldn't be any worse performance wise

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also squeeze ControlFlow<Done, OpcodeHandler> into a single word by using the lower 2 bits as the discriminant tag, since function pointers must be word aligned. I think there was a proposal for rustc to do this automatically but it has not yet been implemented.

pulley/src/decode.rs Outdated Show resolved Hide resolved
pulley/src/decode.rs Outdated Show resolved Hide resolved
pulley/src/interp/interp_loop.rs Show resolved Hide resolved
pulley/src/lib.rs Outdated Show resolved Hide resolved
pulley/src/interp/interp_loop.rs Outdated Show resolved Hide resolved
@Kmeakin Kmeakin force-pushed the km/pulley/tail-calls branch 6 times, most recently from 2228667 to 5c8e2f8 Compare September 18, 2024 00:16
@Kmeakin Kmeakin force-pushed the km/pulley/tail-calls branch 3 times, most recently from 51f2406 to 3d19204 Compare September 18, 2024 01:41
@fitzgen
Copy link
Member

fitzgen commented Sep 19, 2024

Once #9274 lands, is this ready to merge as well?

@fitzgen
Copy link
Member

fitzgen commented Oct 2, 2024

Once #9274 lands, is this ready to merge as well?

@Kmeakin, now that #9274 landed, is this ready to rebase and land as well, or are there still more things left to do first?

@Kmeakin
Copy link
Contributor Author

Kmeakin commented Oct 4, 2024

Once #9274 lands, is this ready to merge as well?

@Kmeakin, now that #9274 landed, is this ready to rebase and land as well, or are there still more things left to do first?

I think it is ready to land, I don't have anything else I want to add to it.

Copyright (c) 2024, Arm Limited.

Signed-off-by: Karl Meakin <karl.meakin@arm.com>
Copyright (c) 2024, Arm Limited.

Signed-off-by: Karl Meakin <karl.meakin@arm.com>
Copyright (c) 2024, Arm Limited.

Signed-off-by: Karl Meakin <karl.meakin@arm.com>
Copyright (c) 2024, Arm Limited.

Signed-off-by: Karl Meakin <karl.meakin@arm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pulley Issues related to the Pulley interpreter
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants