Skip to content

Avoid repeated SIMD mask proof traversal in value numbering - #134530

Merged
tannergooding merged 2 commits into
dotnet:mainfrom
tannergooding:tannergooding-vector-mask-jit-cost
Sep 25, 2026
Merged

tannergooding merged 2 commits into
dotnet:mainfrom
tannergooding:tannergooding-vector-mask-jit-cost

Conversation

@tannergooding

Copy link
Copy Markdown
Member

Summary

Avoid exponential traversal of shared value-number graphs when proving that a SIMD value is a per-element mask. A short unrolled chain can repeatedly reference the same mask VN along multiple paths, causing the old proof to revisit the same subgraphs exponentially.

Cache successful compound mask proofs within each query and retain a 64-level recursion cutoff. Check the cache before the cutoff so already-proven values remain usable at the depth boundary. Also check the comparison constant before attempting the mask proof.

A separate follow-up commit reuses intrinsic evaluation results when every operand has identical liberal and conservative VNs. This follows the existing VNPairForFunc pattern for scalar math and unary/binary/ternary hardware intrinsics; distinct operand pairs still receive separate evaluations.

Performance

Windows x64 Release JIT, AVX-512 disabled. Fresh methods are compiled with RuntimeHelpers.PrepareMethod; IL generation and execution are outside the timed region. Execution afterward checks the result.

For the 25-step mask chain, median compilation time drops from 5.59 seconds to approximately 0.29 ms. The original proof expands roughly 134 million calls over just 52 relevant unique VNs (analytically derived counts).

The separate liberal/conservative reuse change showed no additional improvement distinguishable from noise in repeated local measurements.

Validation

  • Built Release CoreCLR/libraries/host and rebuilt both Release and Checked JITs after the changes.
  • The minimal 40-step regression exceeded a 30-second observation bound with the original JIT and passed with the fixed Release and Checked JITs.
  • Ran existing optimized scalar math, bit-operation, HWI value-numbering/side-effect, and Vector128 tests with the final Checked JIT, including HWI runs with AVX-512 disabled.
  • Ran Windows x64 JIT formatting successfully.

No ARM64 execution, full JIT test suite, or SuperPMI validation was performed.

Resolves #134487

Note

This PR description was drafted with GitHub Copilot.

tannergooding and others added 2 commits September 23, 2026 08:10
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Skip repeated scalar math and hardware-intrinsic evaluation when all operand VN pairs match, following VNPairForFunc.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings September 23, 2026 15:46
@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 Sep 23, 2026
@azure-pipelines

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

Comment thread src/coreclr/jit/valuenum.cpp
Comment thread src/coreclr/jit/valuenum.cpp
Comment on lines -14237 to +14272
ValueNum normalCVN = vnStore->EvalHWIntrinsicFunUnary(tree, func, op1vnp.GetConservative(),
resultTypeVNPair.GetConservative());
ValueNum normalCVN;

if (op1vnp.BothEqual())
{
normalCVN = normalLVN;
}
else
{
normalCVN = vnStore->EvalHWIntrinsicFunUnary(tree, func, op1vnp.GetConservative(),
resultTypeVNPair.GetConservative());
}

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.

Finally, this is other redundant work we were doing, where most other VN functions have a similar BothEqual check to avoid such redundancy

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.

We do this everywhere else I think, feels weird to expand only for rarely used stuff. You already added the budget check, do we still need these verbose fast paths?

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.

We do this everywhere else I think, feels weird to expand only for rarely used stuff

Not sure what you mean? We pretty consistently use BothEqual() to avoid duplicating work and you can see it in all the VNPairFor* helpers, including VNPairForFunc. HWIntrinsics were the odd one out by doing the work twice instead.

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 review overview

🔵 Needs a closer look

Core JIT changes lack full JIT, ARM64, and SuperPMI validation.

Review effort: Lite
Findings: None

What changed in this PR

Improves JIT SIMD value-numbering performance by caching mask proofs, bounding recursion, and reusing intrinsic evaluations.

Changes:

  • Adds per-query SIMD mask-proof caching and depth limiting.
  • Avoids unnecessary mask analysis for mismatched constants.
  • Reuses intrinsic evaluations when operand VNs match.
  • Adds a regression test for exponential traversal.
File Description
src/​tests/​JIT/​Regression_2/​Runtime_134487/​Runtime_134487.csproj Configures the regression test and disables AVX-512.
src/​tests/​JIT/​Regression_2/​Runtime_134487/​Runtime_134487.cs Adds the unrolled SIMD mask-chain regression test.
src/​coreclr/​jit/​valuenum.h Declares cached mask analysis and VN-pair evaluation logic.
src/​coreclr/​jit/​valuenum.cpp Implements mask caching, depth limiting, constant gating, and evaluation reuse.

Comment thread src/tests/JIT/Regression_2/Runtime_134487/Runtime_134487.csproj

@EgorBo EgorBo left a comment

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 with a few nits

@tannergooding
tannergooding merged commit 81d3e24 into dotnet:main Sep 25, 2026
143 of 146 checks passed
@tannergooding
tannergooding deleted the tannergooding-vector-mask-jit-cost branch September 25, 2026 01:41
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.

JIT: (bug) exponential compile time in ValueNumStore::IsVectorPerElementMask

3 participants