Skip to content

8389111: C2: Use BMI2 BZHI for variable int low-bit masks on x86 - #32048

Open
aprilivy wants to merge 2 commits into
openjdk:masterfrom
aprilivy:8389111-use-bzhi-variable-int-bitmasks-x86
Open

8389111: C2: Use BMI2 BZHI for variable int low-bit masks on x86#32048
aprilivy wants to merge 2 commits into
openjdk:masterfrom
aprilivy:8389111-use-bzhi-variable-int-bitmasks-x86

Conversation

@aprilivy

@aprilivy aprilivy commented Jul 25, 2026

Copy link
Copy Markdown
Member

C2 currently lowers variable int low-bit masks of the form:

value & ((1 << bits) - 1)

to a five-instruction sequence on x86. This change adds a BMI2 matcher rule that uses BZHI, reducing it to three instructions.

The shift count is explicitly masked with 31 because Java shift distances wrap modulo 32, while BZHI treats counts greater than or equal to 32 differently.

A scalar JMH throughput benchmark on a Ryzen 9 9950X3D improved from approximately 0.199 ns/op to 0.185 ns/op (6.9%).

Testing:

  • HotSpot release and fastdebug builds
  • compiler/intrinsics/bmi: 26/26 tests passed
  • Verified generated assembly with UseBMI2Instructions enabled and disabled


Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change must be properly reviewed (2 reviews required, with at least 1 Reviewer, 1 Author)

Issue

  • JDK-8389111: C2: Use BMI2 BZHI for variable int low-bit masks on x86 (Enhancement - P4)

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/32048/head:pull/32048
$ git checkout pull/32048

Update a local copy of the PR:
$ git checkout pull/32048
$ git pull https://git.openjdk.org/jdk.git pull/32048/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 32048

View PR using the GUI difftool:
$ git pr show -t 32048

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/32048.diff

Using Webrev

Link to Webrev Comment

@bridgekeeper

bridgekeeper Bot commented Jul 25, 2026

Copy link
Copy Markdown

👋 Welcome back aivy! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk

openjdk Bot commented Jul 25, 2026

Copy link
Copy Markdown

❗ This change is not yet ready to be integrated.
See the Progress checklist in the description for automated requirements.

@aprilivy

Copy link
Copy Markdown
Member Author

Hi @sviswa7 and @jatin-bhateja, would either of you be willing to take a look at this? Thanks!

@openjdk openjdk Bot added the hotspot-compiler hotspot-compiler-dev@openjdk.org label Jul 25, 2026
@openjdk

openjdk Bot commented Jul 25, 2026

Copy link
Copy Markdown

@aprilivy The following label will be automatically applied to this pull request:

  • hotspot-compiler

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@openjdk

openjdk Bot commented Jul 25, 2026

Copy link
Copy Markdown

The total number of required reviews for this PR has been set to 2 based on the presence of this label: hotspot-compiler. This can be overridden with the /reviewers command.

@openjdk openjdk Bot added the rfr Pull request is ready for review label Jul 25, 2026
@mlbridge

mlbridge Bot commented Jul 25, 2026

Copy link
Copy Markdown

Webrevs

@SirYwell

Copy link
Copy Markdown
Member

Two questions:

  1. This should also work with long, right? Is there a specific reason why this change is int only?
  2. Would it make sense to only emit the and instruction if necessary?

@aprilivy

Copy link
Copy Markdown
Member Author

Two questions:

  1. This should also work with long, right? Is there a specific reason why this change is int only?
  2. Would it make sense to only emit the and instruction if necessary?

Thanks!

  1. Yes, the analogous long rule is semantically valid, using a count mask of 63. I prototyped it, but it regressed the scalar benchmark on my system, so I left it out rather than include a rule without a demonstrated improvement. It could be investigated separately though.

  2. Yes. The andl 31 is required for an unrestricted count to preserve shift semantics, but it can be omitted when C2 proves that the count is already in [0, 31]. I’ll investigate adding a range-guarded form for that case.

@aprilivy

Copy link
Copy Markdown
Member Author

I’ve now added the bounded-count form discussed above. When C2 proves the count is within [0, 31], it selects a BZHI rule without the extra mask, unrestricted counts retain the andl 31 fallback. I also added IR coverage for both paths. The bounded benchmark improved from 0.207 to 0.197 ns/op (~4.8%)

// Generate a low-bits mask with BZHI when the shift count is known to be in
// [0, 31].
instruct bzhiI_rReg_rReg_bounded(rRegI dst, rRegI src, immI_1 one,
immI_M1 minus_one, rFlagsReg cr)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Better to change to

instruct bzhiI_rReg_rReg_bounded(rRegI dst, rRegI src, immI_1 one, rRegI shift,
                                 immI_M1 minus_one, rFlagsReg cr)
  ...
  match(Set dst (AndI src (AddI (LShiftI one shift) minus_one)));

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

Labels

hotspot-compiler hotspot-compiler-dev@openjdk.org rfr Pull request is ready for review

Development

Successfully merging this pull request may close these issues.

3 participants