Skip to content

JIT: Opportunistically lower value & ((1 << k) - 1) to BMI2 bzhi - #131693

Closed
tcortega wants to merge 3 commits into
dotnet:mainfrom
tcortega:feat/jit-bzhi-lowering
Closed

JIT: Opportunistically lower value & ((1 << k) - 1) to BMI2 bzhi#131693
tcortega wants to merge 3 commits into
dotnet:mainfrom
tcortega:feat/jit-bzhi-lowering

Conversation

@tcortega

@tcortega tcortega commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Fixes #129368

Lowers value & ((1 << k) - 1) (and the ADD(..., -1) form) to BMI2 bzhi when available.

BZHI leaves the source alone when k >= width, IL shifts mask the count. If we can't prove k is in range, insert and k, width-1 so the behavior stays the same.

Based on @AndyAyersMS's prototype. Left out the IntegralRange fallback - it almost never fires in lowering, and the issue already calls that out as follow-up.

-       mov      r10d, 1
-       shlx     r10d, r10d, r15d
-       dec      r10d
-       and      r10d, eax
+       and      r15d, 31
+       bzhi     r10d, eax, r15d

SPMI windows-x64 Checked: 45 diffs, -315 bytes, 0 size regressions.

Test: Runtime_129368 sweeps edge k values against NoOptimization oracles.

Update: overflow-checked masks (checked((1 << k) - 1)) now bail instead of dropping the throw, and the existing blsr/blsmsk lowers turned out to have the same hole - guarded those too.

Copilot AI review requested due to automatic review settings August 1, 2026 08:16
@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 Aug 1, 2026
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Aug 1, 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.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

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.

Pull request overview

This PR adds an xarch JIT lowering pattern that recognizes value & ((1 << k) - 1)-style masks and opportunistically replaces the AND + (shift/dec) mask construction with HWIntrinsic::ZeroHighBits (emitting bzhi when supported), plus a regression test covering boundary shift-count semantics.

Changes:

  • Add Lowering::TryLowerAndOpToZeroHighBits and invoke it from LowerBinaryArithmetic for GT_AND.
  • Add a new JitBlue regression test Runtime_129368 and include it in the regression csproj.
  • Declare the new lowering helper in lower.h.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
src/coreclr/jit/lowerxarch.cpp Adds the new AND( value, (1<<k)-1 )ZeroHighBits lowering and wires it into lowering.
src/coreclr/jit/lower.h Declares TryLowerAndOpToZeroHighBits.
src/tests/JIT/Regression/Regression_ro_2.csproj Includes the new regression test source file.
src/tests/JIT/Regression/JitBlue/Runtime_129368/Runtime_129368.cs Adds coverage for shift-count edge cases and various shape variants.

Comment thread src/coreclr/jit/lowerxarch.cpp
Copilot AI review requested due to automatic review settings August 1, 2026 09:15
@tcortega
tcortega force-pushed the feat/jit-bzhi-lowering branch from 79c245c to ecef081 Compare August 1, 2026 09:15
@tcortega

tcortega commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

Good catch - this was real. v & checked((1 << k) - 1) lost its overflow check, so it silently stopped throwing for 1 << k == int.MinValue. Now bailing when the mask node has gtOverflow() set, and the test got checked variants that assert the throw.

Turns out the existing blsr/blsmsk lowers have the same hole (x & checked(x + (-1)) loses the check too), so I fixed those here as well. SPMI diffs unchanged.

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.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings August 1, 2026 09:28
@tcortega
tcortega force-pushed the feat/jit-bzhi-lowering branch from ecef081 to 5582b4b Compare August 1, 2026 09:28

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.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/coreclr/jit/lowerxarch.cpp:6699

  • This JITDUMP message refers only to the SUB form, but the transform also matches the ADD(..., -1) canonicalization. Consider wording it in terms of the source-level mask to keep diagnostics accurate.
    JITDUMP("Lower: optimize AND(X, SUB(LSH(1, CNT), 1))\n");

src/coreclr/jit/lowerxarch.cpp:6586

  • The header comment describes only the SUB form, but the implementation also accepts the morph-canonicalized ADD(..., -1) form. Updating the comment avoids misleading future readers/debugging.

This issue also appears on line 6699 of the same file.

// Lowering::TryLowerAndOpToZeroHighBits: Lowers a tree AND(X, SUB(LSH(1, CNT), 1)) to
// HWIntrinsic::ZeroHighBits

@EgorBo

EgorBo commented Aug 1, 2026

Copy link
Copy Markdown
Member

I'm not sure it's worth the extra complexity in JIT for very small diffs. Is it used in real-world or is there any benchmark?

@tcortega

tcortega commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

@EgorBo Fair question. The diffs undercount it a bit - constant k folds before lowering, so only variable-count sites show up. In the corpus that's BitArray.ClearHighExtraBits, BigInteger and FP parsing.

On the TP diff: it only shows up on the MSVC-built jit (clang linux-x64 is clean), and MinOpts regresses too even though this sits behind OptimizationEnabled(), so it looks like native inlining shift rather than the check itself.

No benchmark yet, happy to add one if that helps. Design is from #129368 so I'll defer to @AndyAyersMS on whether it clears the bar.

@tannergooding

Copy link
Copy Markdown
Member

This is already covered by #130481

Which is not only bzhi, but also bts, btr, btc, bt, and ensuring logic sharing with LA64 and other architectures where relevant.

That's just pending sign-off (@EgorBo) and is otherwise fine to be merged.

I'm not sure it's worth the extra complexity in JIT for very small diffs. Is it used in real-world or is there any benchmark?

Same general response as I gave on the other PR, which is that these are standard bit manipulation intrinsics supported by all 3 modern compilers when targeting hardware with such support; they are exposed because they are known to be faster/better, shortening dependency chains and reducing complexity.

Its also a bit of a chicken and egg problem; in many cases alternative patterns get used because we aren't accelerating these standard defaults. If we do accelerate them, its more likely people will use them and less likely they have to code complex or risky custom logic to accelerate to account for our lack of handling it.

@tcortega tcortega closed this Aug 1, 2026
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 community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JIT: opportunistically lower value & ((1 << k) - 1) to BMI2 BZHI

4 participants