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

[mir-opt] optimization idea: bubble return terminators to predecessor blocks #72022

Closed
oli-obk opened this issue May 8, 2020 · 7 comments · Fixed by #74839
Closed

[mir-opt] optimization idea: bubble return terminators to predecessor blocks #72022

oli-obk opened this issue May 8, 2020 · 7 comments · Fixed by #74839
Labels
A-mir-opt Area: MIR optimizations C-enhancement Category: An issue proposing an enhancement or a PR with one. E-medium Call for participation: Medium difficulty. Experience needed to fix: Intermediate. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@oli-obk
Copy link
Contributor

oli-obk commented May 8, 2020

cc @rust-lang/wg-mir-opt

if we have a basic block with no statements and just a return terminator, any other basic block that just gotos into that block could just as well call return itself. Or do we have some rule that we can only have a single return terminator per mir::Body?

Maybe we can generalize this and bubble any terminator of a statement-less block into its predecessor terminators iff that predecessor terminator is a goto.

As an example take

which is a basic block with no statements and just a return terminator, and both predecessor blocks have a goto to this block.

@oli-obk oli-obk added E-medium Call for participation: Medium difficulty. Experience needed to fix: Intermediate. A-mir-opt Area: MIR optimizations labels May 8, 2020
@jonas-schievink jonas-schievink added C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 8, 2020
@hanna-kruppe
Copy link
Contributor

if we have a basic block with no statements and just a return terminator, any other basic block that just gotos into that block could just as well call return itself. Or do we have some rule that we can only have a single return terminator per mir::Body?

I don't know if we have such a rule in (any part of) rustc, but in my experience this is a convenient assumption for some analyses and transforms. So depending on the expected value of "bubbling up" returns (at a glance, it seems low to me), I'd be cautious about doing it just because we can.

@ecstatic-morse
Copy link
Contributor

ecstatic-morse commented May 15, 2020

The docs for TerminatorKind::Return do say that "this should occur at most once". I don't know how many places depend on this, however, and it shouldn't be too hard to fix up the ones that do.

@matthewjasper
Copy link
Contributor

The built MIR only contains a single Return terminator. However the generator transform code appears to output MIR with multiple return terminators in src/test/mir-opt/generator-drop-cleanup/rustc.main-{{closure}}.generator_drop.0.mir

@nagisa
Copy link
Member

nagisa commented Jun 4, 2020

this should occur at most once

I recall this being motivated by LLVM liking a singular return better than multiple returns. "Should" is not a "must", so it isn’t incorrect that we generate (sometimes) multiple returns. But it is still a guidance that stands.

As thus I don’t love what #72563 did /me shrugs.

@ecstatic-morse
Copy link
Contributor

ecstatic-morse commented Jun 4, 2020

I concur with @nagisa. Canonicalizing a mistake made in the generator transform is wrongheaded IMO. If we want to do this, we should make a conscious decision. There's probably code that relies on only one Return terminator existing; we just haven't found those bugs yet.

@bjorn3
Copy link
Member

bjorn3 commented Jun 4, 2020

Cranelift likes multiple returns better than single returns. It never duplicates ret instructions, even when it would decrease the amount of register moves and jumps.

@oli-obk
Copy link
Contributor Author

oli-obk commented Oct 1, 2020

This was only added under mir-opt-level 3, in case anyone is wondering why this is closed. We haven't finished the discussion on whether we want multiple return terminators per body or whether we should fix generators

bors added a commit to rust-lang-ci/rust that referenced this issue Mar 7, 2025
Use multiple returns in MIR if it saves a block; still have only one in LLVM

This is still an open question whether it's desired, per rust-lang#72022 (comment), so opening as a draft.

Given that cranelift prefers multiple returns and we use optimized MIR for MIR inlining, it seems at least plausible that MIR shouldn't have the "one return" rule (the validator doesn't enforce it currently either) so we can have fewer total blocks, and then targets like LLVM can enforce it if they so choose (as this PR does).

r? ghost
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-mir-opt Area: MIR optimizations C-enhancement Category: An issue proposing an enhancement or a PR with one. E-medium Call for participation: Medium difficulty. Experience needed to fix: Intermediate. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants