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

Prune unreachable variants of coroutines #135471

Conversation

compiler-errors
Copy link
Member

@compiler-errors compiler-errors commented Jan 14, 2025

Fixes #135468

SimplifyCfg doesn't detect cases where coroutine variants are effectively unreachable since they'll never reach a specific variant if we repeatedly poll the coroutine from the "uninitialized" variant 0. This PR attempts to implement that, since otherwise futures suffer from dead code problems across await points.

I gotta explain a bunch about why this is so weird, sitll. But, anyone have a vibe-check about the approach?

r? mir-opt

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jan 14, 2025
@compiler-errors
Copy link
Member Author

I guess one thing that this PR doesn't do but it could is actually remove the variants from the CoroutineLayout, too. That would be really nice, since it would make futures smaller too.

@rust-log-analyzer

This comment has been minimized.

// This is preceded by a read of the discriminant. If we don't find this, then
// we must have optimized away the switch, so bail.
let StatementKind::Assign(box (discr_place, Rvalue::Discriminant(discr_local))) =
&bb0.statements[if is_pinned { 1 } else { 0 }].kind
Copy link
Contributor

Choose a reason for hiding this comment

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

If we optimize out too much, we may not even have a statement left.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, but we already check that there's at least 1 statement in https://github.com/rust-lang/rust/pull/135471/files#diff-2b899097018634da368ec3c772523e10def01aef54b950e07c125a49e374a3e3R329. I don't know if there will ever be a case where that succeeds but this fails.

}
// The derefer may have inserted a local to access the variant.
// Make sure we keep track of it here.
StatementKind::Assign(box (place, Rvalue::CopyForDeref(deref_place))) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

This could be a Rvalue::Operand too.

Copy link
Member Author

Choose a reason for hiding this comment

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

Rvalue::Operand(RValue::Copy(_)) would mean that GVN has passed by, and I think GVN would've collapsed all of them into this one: https://github.com/rust-lang/rust/pull/135471/files#diff-2b899097018634da368ec3c772523e10def01aef54b950e07c125a49e374a3e3R332

I can probably assert against it I guess :)

@compiler-errors
Copy link
Member Author

Also, I'm really not certain whether this PR is worth landing. I can't really seem to find production code where this functionality even gets triggered :)

@saethlin
Copy link
Member

Did you try it on the codebase that the issue was reported from? https://github.com/chipsalliance/caliptra-mcu-sw

@compiler-errors
Copy link
Member Author

compiler-errors commented Jan 15, 2025

I mean, yes, that codebase does trigger the optimization (well, I didn't check but I would expect it to given the mir-opt test I wrote).

I just mean in practice, I'm not totally certain how many coroutine variants we'd actually be pruning -- I assume most people aren't writing trivially optimizable (well, trivially optimized-out) yield points in their async code.

That is to say, I'm not good at doing the type of analysis that indicates whether this logic (which is fairly nontrivial) is warranted.

@saethlin
Copy link
Member

But, anyone have a vibe-check about the approach?

Overall I do not think the vibes are very good. This is a lot of complexity for an optimization that seems usually ineffectual, and from my perspective of knowing a bit about generator lowering, doesn't seem like a common-sense optimization (in the same sense that we expect LLVM to find the optimal instruction sequence for some bit-twiddling operation).

@compiler-errors compiler-errors deleted the coroutine-unreachable branch January 24, 2025 01:59
@compiler-errors
Copy link
Member Author

I do not expect LLVM to be able to approximate anything near to this optimization, especially if it were extended to totally drop the unreachable variants from the coroutine layout (i.e. make the coroutine smaller)

But also I don't want to carry this forward anyways so idgaf

@saethlin
Copy link
Member

Yeah I also don't expect LLVM to figure this out. I just think there are two reasons to do an optimization, "it's useful" (which this is not demonstrated to be) and "we've educated our users to expect this" (which I do not think this fits either).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Async function calls not optimized out
5 participants