Skip to content

JIT: skip live-across-call CSEs with big footprint and few uses - #130931

Open
AndyAyersMS wants to merge 1 commit into
dotnet:mainfrom
AndyAyersMS:jit-cse-laco-veto
Open

JIT: skip live-across-call CSEs with big footprint and few uses#130931
AndyAyersMS wants to merge 1 commit into
dotnet:mainfrom
AndyAyersMS:jit-cse-laco-veto

Conversation

@AndyAyersMS

Copy link
Copy Markdown
Member

The default CSE heuristic is overly aggressive for live-across-call CSE candidates with high size cost and very cold uses.

This change is the outcome of back-propagating information from various RL-derived and oracular models for CSEs onto our existing heuristic, along with benchmark-derived validations for x64/arm64.

The majority of CSEs blocked (on xArch) are large immediates. Note we generally don't CSE these on xArch (see eg #129941) but some handle kinds are allowed. These are fairly "cheap" to rematerialize. Other cases are some indirs and CSE-able calls.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI review requested due to automatic review settings July 16, 2026 22:23
@github-actions github-actions Bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jul 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Note

This error may be related to your runner configuration. You can now configure runners for Copilot code review separately from Copilot cloud agent by creating a copilot-code-review.yml file with your setup steps. Read the docs for details.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 6 pipeline(s).
10 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

The default CSE heuristic is overly aggressive for live-across-call
CSE candidates with high size cost and very cold uses.

This change is the outcome of back-propagating information from various
RL-derived and oracular models for CSEs onto our existing heuristic,
along with benchmark-derived validations for x64/arm64.

The majority of CSEs blocked (on xArch) are large immediates. Note
we generally don't CSE these on xArch (see eg dotnet#129941) but some
handle kinds are allowed. These are fairly "cheap" to rematerialize.
Other cases are some indirs and CSE-able calls.

    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 16, 2026 22:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@AndyAyersMS

Copy link
Copy Markdown
Member Author

@EgorBot -intel -amd -arm -linux_arm64 --filter "Perf_Regex_Cache.IsMatch_Multithreading"

@AndyAyersMS

Copy link
Copy Markdown
Member Author

@EgorBot -intel -amd -arm -linux_arm64 --filter "Perf_Regex_Cache.IsMatch_Multithreading"

@AndyAyersMS

Copy link
Copy Markdown
Member Author

@EgorBot -intel -amd -arm -linux_arm64 --filter 'Perf_Regex_Cache.IsMatch_Multithreading'

@AndyAyersMS

Copy link
Copy Markdown
Member Author

@EgorBot -intel -amd -arm -linux_arm64 --filter 'Perf_Deep'

@AndyAyersMS

Copy link
Copy Markdown
Member Author

@EgorBot -intel -amd -arm -linux_arm64 --filter 'TryGetValueTrueDictionary' --filter 'TryGetValueFalseDictionary'

@EgorBo

EgorBo commented Jul 17, 2026

Copy link
Copy Markdown
Member

@EgorBot -intel -amd -arm -linux_arm64 --filter '_TryGetValueTrue_Dictionary' --filter '_TryGetValueFalse_Dictionary'

tip: you can ask ai to setup dotnet/performance locally to come up with filters that definitely work

// Reject CSE candidates that live across a call, have a non-trivial
// code footprint, and only a small (weighted) number of uses.
//
if ((CodeOptKind() != Compiler::SMALL_CODE) && candidate->LiveAcrossCall() && (candidate->Size() >= 8) &&

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should it depend on ABI/platform. I assume platforms with plenty of callee-saved regs would like to keep CSEing things like that?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I had the modelling work on both x64 and arm64, and there didn't seem to be a big benefit to separate heuristics.

@AndyAyersMS

Copy link
Copy Markdown
Member Author

@EgorBot -intel -amd -arm -linux_arm64 --filter 'TryGetValueTrue.Dictionary' 'TryGetValueFalse.Dictionary'

@AndyAyersMS

Copy link
Copy Markdown
Member Author

@EgorBot -intel -amd -arm -linux_arm64 --filter 'Collections.SortLinq*'

@github-actions

github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Workflow state for the Holistic Review Orchestrator.

{
  "version": 5,
  "last_dispatched_commit": "d0ecf0d431dbdd47ea3d9b8c4cd82693be3110ac",
  "last_dispatched_base_ref": "main",
  "last_dispatched_base_sha": "0bc487c793526e0ff826a57596e1d37e46c633d9",
  "last_reviewed_commit": "d0ecf0d431dbdd47ea3d9b8c4cd82693be3110ac",
  "last_reviewed_base_ref": "main",
  "last_reviewed_base_sha": "0bc487c793526e0ff826a57596e1d37e46c633d9",
  "last_recorded_worker_run_id": "29687175153",
  "review_attempt_commit": "",
  "review_attempt_base_ref": "",
  "review_attempt_count": 0,
  "max_review_attempts": 5,
  "review_history_format": "holistic-review-disclosure-v1",
  "review_history": [
    {
      "commit": "d0ecf0d431dbdd47ea3d9b8c4cd82693be3110ac",
      "review_id": 4730770515
    }
  ]
}

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Holistic Review

Motivation: The default CSE heuristic is overly aggressive for CSE candidates that live across a call, have a large code footprint, and only a few (weighted) uses. Such candidates add register pressure across calls (forcing spills/reloads) yet save little, and on xArch many are large immediates that are cheap to rematerialize. The change back-propagates insight from RL-derived/oracular CSE models onto the existing hand-written heuristic, validated by x64/arm64 benchmarks.

Approach: Adds an early rejection in CSE_Heuristic::PromotionCheck that returns false when CodeOptKind() != SMALL_CODE, the candidate is live across a call, its Size() (GetCostSz footprint) is >= 8, and its weighted UseCount() is <= 3. The guard is placed before the cost-model computation, so it purely narrows what gets promoted; it does not alter the subsequent cost math.

Summary: The change is small, self-contained, and correctly targeted. It only affects the default CSE_Heuristic (line 4359), not the Random/Replay/Parameterized (RL) variants, which have their own ConsiderCandidates/PromotionCheck paths — so experimental/policy-driven CSE flows are unaffected. Gating on != SMALL_CODE is appropriate because in SMALL_CODE mode UseCount()/Size() carry different (unweighted) semantics and the goal is size, not the register-pressure tradeoff this guard targets. The >= 8 and <= 3 thresholds are empirically derived magic constants; this matches the surrounding heuristic's established style, though it does mean future tuning requires re-derivation. No correctness risk: skipping a CSE is always semantically safe. The main risk is throughput/codegen quality regressions in edge cases, which the author states were validated against benchmarks and are covered by JIT CI (SPMI/asmdiffs). No test changes are needed for a pure heuristic tuning of this kind. LGTM.

Note

This review was generated by this repository's Holistic Review agentic workflow to complement the built-in Copilot review.

Generated by Holistic Review · 79 AIC · ⌖ 10.4 AIC · ⊞ 10K

Comment on lines +4373 to +4374
if ((CodeOptKind() != Compiler::SMALL_CODE) && candidate->LiveAcrossCall() && (candidate->Size() >= 8) &&
(candidate->UseCount() <= 3))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM.
Nit: the thresholds Size() >= 8 and UseCount() <= 3 came from the RL model and x64/arm64 sweep, a one-line comment on their derivation would help future re-tuning.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants