Filter param-env caller bounds to the goal-relevant subset in canonical queries - #101
Draft
xmakro wants to merge 1 commit into
Draft
Filter param-env caller bounds to the goal-relevant subset in canonical queries#101xmakro wants to merge 1 commit into
xmakro wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every canonical query (the type ops,
evaluate_obligation, query normalization,implied_outlives_bounds) keys its cache on the fullParamEnv. Two functions proving the literally identical goal get distinct cache keys whenever their where-clauses differ, even when none of those clauses can possibly influence the goal. The degenerate case is a trait method withwhere Self: 'static: every impl gets a distinct caller bound (S0: 'static,S1: 'static, ...), so the same MIR typeck goals re-run once per impl.This adds a relevance filter at a new
canonicalize_query_with_env_filterentry point, used by the trait-solving query family. For param-free goals it reduces the env to the subset of caller bounds that could participate in proving the goal:<Vec<u8> as X>::Out == Tpulls inT's clauses).S0: 'static) is vacuous inside a canonical query, since queries only collect region constraints and the env's outlives clauses are consulted caller-side against the unfiltered env.Goals mentioning inference vars, non-region bound vars (embedded canonical values, e.g. user type annotations), or generic params keep the full env. The gating to param-free goals keeps the per-call cost at a few flag checks plus one hash lookup on a
(caller_bounds, mask)cache; there is no goal walk on the hot path. Method probing intentionally stays on the unfilteredcanonicalize_query, since it manufactures inference vars that are matched against the env beyond what the goal itself requires.Clean A/B on the full local rustc-perf suite (from-scratch ThinLTO+jemalloc stage2, instructions:u, vs the 2026-08-09 base): mean -0.311% over 551 cells, 191 significant wins, 0 regressions. Highlights:
Microbenchmark and validation detail (stage1, same-binary on/off via
RUSTC_ENV_FILTER_DISABLE):where Self: 'static, identical concrete method bodies): 3.034G -> 2.650G instructions, -12.65%; the control without the where-clause is unchanged, i.e. the filter recovers about two thirds of the pure fragmentation excess.RUSTC_ENV_FILTER_STATS): 377k canonical queries, 90% served from the filtered-env cache, ~8k distinct filtered envs; executions drop across the family (evaluate_obligation -25%, type_op_prove_predicate -20%, dropck_outlives hits 5x) and the dep graph loses 28k nodes on this crate.Follow-ups worth exploring: extending filtering to goals that mention params (needs a cheap per-goal param mask, e.g. collected during canonicalization itself; a full-relevance prototype deduped substantially more but the per-call goal walk cost more than it saved), applying the same relevance test to the global selection/evaluation cache keys, and dropping region-outlives clauses once their in-query uses are audited.