-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
inliner: Break inlining cycles #78580
Conversation
LTGM, r? @oli-obk for final approval |
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.
Hi! I am really new to the rust community so I am not sure if it's okay to review things that you aren't assigned to so feel free to ignore my comment if you want to.
It's totally ok. I found it especially good that your review was asking whether a change would be good, instead of saying "do XYZ". |
Hmm... will #68828 automatically prevent these situations? Or could we somehow extend that to also catch this case? |
This addresses inlining cycles that become apparent only after the substitution or between functions from a different crate. For #68828 to address this issue, it would have to never inline a body where Instance::resolve had failed (including both local and non-local crates). |
We could also list generic params which are used in function calls together with concrete function calls. This way the inliner can decide directly whether to inline, and not do it "after the fact". The main reason I'm asking this is src/test/mir-opt/inline/inline_cycle.one.Inline.diff which has - _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle.rs:14:5: 14:24
+ _1 = <C as Call>::call() -> bb1; // scope 3 at $DIR/inline-cycle.rs:36:9: 36:28 which, imo should never happen. |
What exactly should never happen? |
Isn't this already the case since let callee =
Instance::resolve(self.tcx, self.param_env, callee_def_id, normalized_substs)
.ok()
.flatten()?; |
In this case we are inlining a function call, only to end up with the exact same function call again. All this does is to change the spans and debug info on the call, which will make the debugging experience weird |
Yes, it this case decision to inline is a bad one. We could prevent such direct self-recursion by looking ahead in the callee body (the body is already optimized, so it is self-recursion after applying the substs). Generally speaking the aspiration of this PR is to stop the inlining cycles, rather than modify the inlining heuristic, but I can modify the heuristic as well. |
Instead of doing both, could just modifying the heuristic to detect inlining cycles also fix the infinite loop? |
☔ The latest upstream changes (presumably #78697) made this pull request unmergeable. Please resolve the merge conflicts. Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:
|
I can modify the approach to look for self-recursive calls and calls to instances that are already part of inlining history one step ahead in |
063dff5
to
018fd86
Compare
☔ The latest upstream changes (presumably #78889) made this pull request unmergeable. Please resolve the merge conflicts. Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:
|
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.
I like this approach much better. Thanks!
Just a nit, then this lgtm
The inliner does not support inlining of divering calls. Reject them early on and turn `inline_call` into an infallible operation.
When examining candidates for inlining, reject those that are determined to be recursive either because of self-recursive calls or calls to any instances already inlined.
@bors r+ |
📌 Commit dc4d74d has been approved by |
Rollup of 12 pull requests Successful merges: - rust-lang#74754 (Add `#[cfg(panic = '...')]`) - rust-lang#76468 (Improve lifetime name annotations for closures & async functions) - rust-lang#77016 (Test clippy on PR CI on changes) - rust-lang#78480 (BTreeMap: fix pointer provenance rules) - rust-lang#78502 (Update Chalk to 0.36.0) - rust-lang#78513 (Infer the default host target from the host toolchain if possible) - rust-lang#78566 (Enable LLVM Polly via llvm-args.) - rust-lang#78580 (inliner: Break inlining cycles) - rust-lang#78710 (rustc_ast: Do not panic by default when visiting macro calls) - rust-lang#78746 (Demote i686-unknown-freebsd to tier 2 compiler target) - rust-lang#78830 (fix `super_visit_with` for `Terminator`) - rust-lang#78844 (Monomorphize a type argument of size-of operation during codegen) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
Keep track of all instances inlined so far. When examining a new call
sites from an inlined body, skip those where callee had been inlined
already to avoid potential inlining cycles.
Fixes #78573.