Skip to content

8382713: [VectorAPI] Perform late inlining of failed vector intrinsics - #30876

Open
jatin-bhateja wants to merge 20 commits into
openjdk:masterfrom
jatin-bhateja:JDK-8382713
Open

8382713: [VectorAPI] Perform late inlining of failed vector intrinsics#30876
jatin-bhateja wants to merge 20 commits into
openjdk:masterfrom
jatin-bhateja:JDK-8382713

Conversation

@jatin-bhateja

@jatin-bhateja jatin-bhateja commented Apr 22, 2026

Copy link
Copy Markdown
Member

Currently, we attempt lazy intrinsification of vector intrinsics during incremental inlining stage, in case intrinsification fail due to non-constant context expected by the inline expander, a static call is generated, this incurs a call overhead penalty.

As per following comments from @iwanowww on JDK-8303762 pull request
#24104 (comment)

We should attempt procedure inlining of failed vector intrinsics to avoid penalties associated with call overhead, for vector operations whose fall back implementation uses other vector APIs it will also save boxing penalty.

Patch address this concern by adding a new hybrid call generator (LateInlineVectorCallGenerator ) which encapsulates both intrinsic and parser call generator. During incremental inlining, the intrinsic gets multiple chances to succeed. If all attempts fail, the fallback implementation is inlined instead, absorbing call over head penalties.

I modified BackSholes benchmark to use FloatVector.SPECIES_512, and then explicitly passed -XX:UseAVX=2 to force intrinsic failure. Following are the performance numbers with and without InlineVectorFallback

CommandLine: java -jar target/benchmarks.jar -f 1 -i 5 -wi 1 -w 30 -jvmArgs "-XX:UseAVX=2 --add-modules=jdk.incubator.vector -XX:+UnlockDiagnosticVMOptions -XX:+InlineVectorFallback" BlackScholes.vector_black_scholes


With -XX:-InlineVectorFallback
Benchmark                          (size)   Mode  Cnt     Score      Error  Units
BlackScholes.vector_black_scholes    1024  thrpt    2  7100.820          ops/s

With -XX:+InlineVectorFallback
Benchmark                          (size)   Mode  Cnt     Score      Error  Units
BlackScholes.vector_black_scholes    1024  thrpt    2  8154.163          ops/s

Please review and share your feedback.

Best Regards,
Jatin



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-8382713: [VectorAPI] Perform late inlining of failed vector intrinsics (Enhancement - P4)

Reviewers

Reviewing

Using git

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

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

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 30876

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

Using diff file

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

Using Webrev

Link to Webrev Comment

@jatin-bhateja

Copy link
Copy Markdown
Member Author

/label add hotspot-compiler-dev

@bridgekeeper

bridgekeeper Bot commented Apr 22, 2026

Copy link
Copy Markdown

👋 Welcome back jbhateja! 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 Apr 22, 2026

Copy link
Copy Markdown

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

@openjdk openjdk Bot added the hotspot-compiler hotspot-compiler-dev@openjdk.org label Apr 22, 2026
@openjdk

openjdk Bot commented Apr 22, 2026

Copy link
Copy Markdown

@jatin-bhateja
The hotspot-compiler label was successfully added.

@openjdk

openjdk Bot commented Apr 22, 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 commented Apr 22, 2026

Copy link
Copy Markdown

@jatin-bhateja To determine the appropriate audience for reviewing this pull request, one or more labels corresponding to different subsystems will normally be applied automatically. However, no automatic labelling rule matches the changes in this pull request. In order to have an "RFR" email sent to the correct mailing list, you will need to add one or more applicable labels manually using the /label pull request command.

Applicable Labels
  • build
  • client
  • compiler
  • core-libs
  • hotspot
  • hotspot-compiler
  • hotspot-gc
  • hotspot-jfr
  • hotspot-runtime
  • i18n
  • ide-support
  • javadoc
  • jdk
  • net
  • nio
  • security
  • serviceability
  • shenandoah

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

mlbridge Bot commented Apr 22, 2026

Copy link
Copy Markdown

@iwanowww iwanowww 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.

Thanks, Jatin!

}
};

bool LateInlineVectorCallGenerator::inline_fallback() const {

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.

What's the purpose of this method? All vector intrinsics do have fallback implementation. If there are any cases added later, then they don't have to rely on LateInlineVectorCallGenerator.

Comment thread src/hotspot/share/opto/compile.cpp Outdated
Comment thread src/hotspot/share/opto/compile.cpp Outdated
Comment thread src/hotspot/share/opto/compile.cpp Outdated
Comment thread src/hotspot/share/opto/doCall.cpp Outdated
@jatin-bhateja

Copy link
Copy Markdown
Member Author

Hi @iwanowww , your comments have been addressed.

Comment thread src/hotspot/share/opto/compile.cpp Outdated
Comment thread src/hotspot/share/opto/compile.cpp Outdated
Comment thread src/hotspot/share/opto/callGenerator.cpp Outdated
@jatin-bhateja

jatin-bhateja commented Apr 29, 2026

Copy link
Copy Markdown
Member Author

I modified BackSholes benchmark to use FloatVector.SPECIES_512, and then explicitly passed
-XX:UseAVX=2 to force intrinsic failure. Following are the performance numbers with and without
InlineVectorFallback, we see some improvements despite of error margins.

CommandLine: java -jar target/benchmarks.jar -f 1 -i 5 -wi 1 -w 30 -jvmArgs "-XX:UseAVX=2 --add-modules=jdk.incubator.vector -XX:+UnlockDiagnosticVMOptions -XX:+InlineVectorFallback" BlackScholes.vector_black_scholes


With -XX:-InlineVectorFallback
Benchmark                          (size)   Mode  Cnt     Score      Error  Units
BlackScholes.vector_black_scholes    1024  thrpt    5  7460.391 ± 1412.273  ops/s

With -XX:+InlineVectorFallback
Benchmark                          (size)   Mode  Cnt     Score      Error  Units
BlackScholes.vector_black_scholes    1024  thrpt    5  7851.062 ± 1765.271  ops/s

@jatin-bhateja

Copy link
Copy Markdown
Member Author

Hi @iwanowww , your comments have been addressed.

@iwanowww iwanowww 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.

Overall, looks good. Minor suggestions follow.

Comment thread src/hotspot/share/opto/c2_globals.hpp Outdated
product(bool, EnableVectorAggressiveReboxing, false, EXPERIMENTAL, \
"Enables aggressive reboxing of vectors") \
\
product(bool, InlineVectorFallback, true, DIAGNOSTIC, \

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.

Let's call it IncrementalInlineVector and put it next to IncrementalInline et al.

Comment thread src/hotspot/share/opto/callGenerator.cpp Outdated
Comment thread src/hotspot/share/opto/compile.cpp Outdated
Comment thread src/hotspot/share/opto/compile.cpp Outdated
@jatin-bhateja

Copy link
Copy Markdown
Member Author

Hi @iwanowww , your comments have been addressed, please share the results of your test run.

@iwanowww

iwanowww commented May 6, 2026

Copy link
Copy Markdown
Contributor

Unfortunately, I see multiple failures in Vector API-related tests. They failed mostly on linux-aarch64, but there were few linux-x64 failures [1] as well. I'll take a closer look, but it seems the problem on linux-aarch64 is that fallback implementations are unconditionally inlined and it causes problems (multiple tests on 512-bit vectors fail due memory exhaustion [2]).

[1] In particular:

  • compiler/vectorapi/TestVectorTest.java (w/ -XX:UseAVX=0)
Failed IR Rules (3) of Methods (2)
----------------------------------
1) Method "compiler.vectorapi.TestVectorTest::branch" - [Failed IR rules: 1]:
   * @IR rule 1: "@compiler.lib.ir_framework.IR(phase={DEFAULT}, applyIfPlatformAnd={}, applyIfCPUFeatureOr={}, counts={}, failOn={"_#CMP_I#_", "_#CMOVE_I#_"}, applyIfPlatform={}, applyIfPlatformOr={}, applyIfOr={}, applyIfCPUFeatureAnd={}, applyIf={}, applyIfCPUFeature={}, applyIfAnd={}, applyIfNot={})"
     > Phase "PrintIdeal":
       - failOn: Graph contains forbidden nodes:
         * Constraint 1: "(\\d+(\\s){2}(CmpI.*)+(\\s){2}===.*)"

         * Constraint 2: "(\\d+(\\s){2}(CMoveI.*)+(\\s){2}===.*)"

2) Method "compiler.vectorapi.TestVectorTest::cmove" - [Failed IR rules: 2]:
   * @IR rule 1: "@compiler.lib.ir_framework.IR(phase={DEFAULT}, applyIfPlatformAnd={}, applyIfCPUFeatureOr={}, counts={}, failOn={"_#CMP_I#_"}, applyIfPlatform={}, applyIfPlatformOr={}, applyIfOr={}, applyIfCPUFeatureAnd={}, applyIf={}, applyIfCPUFeature={}, applyIfAnd={}, applyIfNot={})"
     > Phase "PrintIdeal":
       - failOn: Graph contains forbidden nodes:
         * Constraint 1: "(\\d+(\\s){2}(CmpI.*)+(\\s){2}===.*)"

   * @IR rule 2: "@compiler.lib.ir_framework.IR(phase={DEFAULT}, applyIfPlatformAnd={}, applyIfCPUFeatureOr={}, counts={"_#VECTOR_TEST#_", "1", "_#CMOVE_I#_", "1"}, failOn={}, applyIfPlatform={}, applyIfPlatformOr={}, applyIfOr={}, applyIfCPUFeatureAnd={}, applyIf={}, applyIfCPUFeature={}, applyIfAnd={}, applyIfNot={})"
     > Phase "PrintIdeal":
       - counts: Graph contains wrong number of nodes:
         * Constraint 2: "(\\d+(\\s){2}(CMoveI.*)+(\\s){2}===.*)"
           - Failed comparison: [found] 7 = 1 [given]
  • compiler/vectorapi/VectorMaskCompareNotTest.java (w/ -ea -esa -XX:CompileThreshold=100 -XX:+UnlockExperimentalVMOptions -server -XX:-TieredCompilation)
Failed IR Rules (1) of Methods (1)
----------------------------------
1) Method "compiler.vectorapi.VectorMaskCompareNotTest::testCompareULEMaskNotByte" - [Failed IR rules: 1]:
   * @IR rule 1: "@compiler.lib.ir_framework.IR(phase={DEFAULT}, applyIfPlatformAnd={}, applyIfCPUFeatureOr={"asimd", "true", "avx", "true", "rvv", "true"}, counts={"_#XOR_V_MASK#_", "= 0", "_#XOR_V#_", "= 0", "_#VECTOR_MASK_CAST#_", "= 1", "_#VECTOR_MASK_CMP#_", "= 3"}, applyIfPlatform={}, applyIfPlatformOr={}, failOn={}, applyIfOr={}, applyIfCPUFeatureAnd={}, applyIf={}, applyIfCPUFeature={}, applyIfAnd={}, applyIfNot={})"
     > Phase "PrintIdeal":
       - counts: Graph contains wrong number of nodes:
         * Constraint 1: "(\\d+(\\s){2}(XorVMask.*)+(\\s){2}===.*)"
           - Failed comparison: [found] 3 = 0 [given]
         
         * Constraint 2: "(\\d+(\\s){2}(XorV.*)+(\\s){2}===.*)"
           - Failed comparison: [found] 3 = 0 [given]

[2] jdk/incubator/vector/ByteVector512LoadStoreTests.java

    --- Allocation timelime by phase ---
        Phase seq. number                             Bytes                  Nodes
                 (380 older entries lost)
          >4                  incrementalInline 157724064 (+0)        32839 (+0) 
...
           >227          incrementalInline_igvn 174587184 (+261984)   34935 (-18) 
          <4 (cont.)          incrementalInline 174587184 (+0)        34935 (+0) 
         <2 (cont.)                   optimizer 180612856 (+6025672)  34697 (-238) 
...
         <295 (cont.)                  regalloc 177447520 (+0)        83805 (+0) 
          >305                         buildIFG 221892144 (+44444624)  83398 (-407) 
...
         <295 (cont.)                  regalloc 299650328 (+0)        81331 (+0) 
          >318                    regAllocSplit 1073764680 (+774114352)  81331 (+0) 
    ---

#  Internal Error (.../src/hotspot/share/compiler/compilationMemoryStatistic.cpp:935), pid=1510298, tid=1510316
#  fatal error: c2 (1695) jdk/incubator/vector/ByteVector512$ByteShuffle512::intoMemorySegment((Ljava/lang/foreign/MemorySegment;JLjava/nio/ByteOrder;)V): Hit MemLimit - limit: 1073741824 now: 1073764680

@jatin-bhateja

Copy link
Copy Markdown
Member Author

[1] In particular:

  • compiler/vectorapi/TestVectorTest.java (w/ -XX:UseAVX=0)
Failed IR Rules (3) of Methods (2)
----------------------------------
1) Method "compiler.vectorapi.TestVectorTest::branch" - [Failed IR rules: 1]:
   * @IR rule 1: "@compiler.lib.ir_framework.IR(phase={DEFAULT}, applyIfPlatformAnd={}, applyIfCPUFeatureOr={}, counts={}, failOn={"_#CMP_I#_", "_#CMOVE_I#_"}, applyIfPlatform={}, applyIfPlatformOr={}, applyIfOr={}, applyIfCPUFeatureAnd={}, applyIf={}, applyIfCPUFeature={}, applyIfAnd={}, applyIfNot={})"
     > Phase "PrintIdeal":
       - failOn: Graph contains forbidden nodes:
         * Constraint 1: "(\\d+(\\s){2}(CmpI.*)+(\\s){2}===.*)"

         * Constraint 2: "(\\d+(\\s){2}(CMoveI.*)+(\\s){2}===.*)"

2) Method "compiler.vectorapi.TestVectorTest::cmove" - [Failed IR rules: 2]:
   * @IR rule 1: "@compiler.lib.ir_framework.IR(phase={DEFAULT}, applyIfPlatformAnd={}, applyIfCPUFeatureOr={}, counts={}, failOn={"_#CMP_I#_"}, applyIfPlatform={}, applyIfPlatformOr={}, applyIfOr={}, applyIfCPUFeatureAnd={}, applyIf={}, applyIfCPUFeature={}, applyIfAnd={}, applyIfNot={})"
     > Phase "PrintIdeal":
       - failOn: Graph contains forbidden nodes:
         * Constraint 1: "(\\d+(\\s){2}(CmpI.*)+(\\s){2}===.*)"

   * @IR rule 2: "@compiler.lib.ir_framework.IR(phase={DEFAULT}, applyIfPlatformAnd={}, applyIfCPUFeatureOr={}, counts={"_#VECTOR_TEST#_", "1", "_#CMOVE_I#_", "1"}, failOn={}, applyIfPlatform={}, applyIfPlatformOr={}, applyIfOr={}, applyIfCPUFeatureAnd={}, applyIf={}, applyIfCPUFeature={}, applyIfAnd={}, applyIfNot={})"
     > Phase "PrintIdeal":
       - counts: Graph contains wrong number of nodes:
         * Constraint 2: "(\\d+(\\s){2}(CMoveI.*)+(\\s){2}===.*)"
           - Failed comparison: [found] 7 = 1 [given]

Hi @iwanowww , this failure is related to use of UseAVX=0, here fromBitsCoerced is not intrinsified, earlier it remained as CallStaticJavaNode but now it gets inlined, new inlined context has graph shape which infers CMoveI and CmpI and test failed since IR rule don't expect these nodes, one target agnostic fix is to guard these IR rules with -XX:-IncrementalInlineVector flag, but it will defeat the purpose of this test since IncrementalInlineVector is default on. Since test runs on multiple targets guarding by UseAVX > 0 may not be desirable.

Let me know what do you think ?


* compiler/vectorapi/VectorMaskCompareNotTest.java (w/ `-ea -esa -XX:CompileThreshold=100 -XX:+UnlockExperimentalVMOptions -server -XX:-TieredCompilation`)

Failed IR Rules (1) of Methods (1)

  1. Method "compiler.vectorapi.VectorMaskCompareNotTest::testCompareULEMaskNotByte" - [Failed IR rules: 1]:
    • @ir rule 1: "@compiler.lib.ir_framework.IR(phase={DEFAULT}, applyIfPlatformAnd={}, applyIfCPUFeatureOr={"asimd", "true", "avx", "true", "rvv", "true"}, counts={"#XOR_V_MASK#", "= 0", "#XOR_V#", "= 0", "#VECTOR_MASK_CAST#", "= 1", "#VECTOR_MASK_CMP#", "= 3"}, applyIfPlatform={}, applyIfPlatformOr={}, failOn={}, applyIfOr={}, applyIfCPUFeatureAnd={}, applyIf={}, applyIfCPUFeature={}, applyIfAnd={}, applyIfNot={})"

      Phase "PrintIdeal":

      • counts: Graph contains wrong number of nodes:
        • Constraint 1: "(\d+(\s){2}(XorVMask.)+(\s){2}===.)"

          • Failed comparison: [found] 3 = 0 [given]
        • Constraint 2: "(\d+(\s){2}(XorV.)+(\s){2}===.)"

          • Failed comparison: [found] 3 = 0 [given]

With the patch, the vector intrinsic fallback inlining generates more code in the compilation unit, this effects inlining of
other methods, e.g. AbstractMask::intoArray. When intoArray is NOT inlined, the mask must be boxed before passing to a non-inline method, as a result of this VectorMaskCmp encapsulated in VectorBoxNode get addition user which is VectorStoreMask created at https://github.com/openjdk/jdk/blob/master/src/hotspot/share/opto/vector.cpp#L270 during VectorBoxNode scalarization.

This increase the outcout of VectorMaskCmpNode and inhabits optimization which folds XorVMask (VectorMaskCmp, maskAll(true)
https://github.com/openjdk/jdk/blob/master/src/hotspot/share/opto/vectornode.cpp#L2366

Increasing InlineSmallCode to 10000 allows intoArray to be inlined, mask is not boxed, VectorMaskCmp has outcnt=1, XorVMask is folded and Test Passes

[2] jdk/incubator/vector/ByteVector512LoadStoreTests.java

    --- Allocation timelime by phase ---
        Phase seq. number                             Bytes                  Nodes
                 (380 older entries lost)
          >4                  incrementalInline 157724064 (+0)        32839 (+0) 
...
           >227          incrementalInline_igvn 174587184 (+261984)   34935 (-18) 
          <4 (cont.)          incrementalInline 174587184 (+0)        34935 (+0) 
         <2 (cont.)                   optimizer 180612856 (+6025672)  34697 (-238) 
...
         <295 (cont.)                  regalloc 177447520 (+0)        83805 (+0) 
          >305                         buildIFG 221892144 (+44444624)  83398 (-407) 
...
         <295 (cont.)                  regalloc 299650328 (+0)        81331 (+0) 
          >318                    regAllocSplit 1073764680 (+774114352)  81331 (+0) 
    ---

#  Internal Error (.../src/hotspot/share/compiler/compilationMemoryStatistic.cpp:935), pid=1510298, tid=1510316
#  fatal error: c2 (1695) jdk/incubator/vector/ByteVector512$ByteShuffle512::intoMemorySegment((Ljava/lang/foreign/MemorySegment;JLjava/nio/ByteOrder;)V): Hit MemLimit - limit: 1073741824 now: 1073764680

Over all there is a tradeoff of unconditionally inlining vector intrinsic since most of them a bulky and it may impact inlining decisions within their calling context.

Do you think its beneficial to limit the scope of inlining to only few intrinsics initially e.g.
https://github.com/jatin-bhateja/jdk/blob/46fcc9acc05bdef5fd01f4972ed9a66de5f07198/src/hotspot/share/opto/callGenerator.cpp#L463

Please let me know your views.

@openjdk

openjdk Bot commented May 8, 2026

Copy link
Copy Markdown

@jatin-bhateja Please do not rebase or force-push to an active PR as it invalidates existing review comments. Note for future reference, the bots always squash all changes into a single commit automatically as part of the integration. See OpenJDK Developers’ Guide for more information.

@iwanowww

iwanowww commented May 8, 2026

Copy link
Copy Markdown
Contributor

compiler/vectorapi/TestVectorTest.java (w/ -XX:UseAVX=0)

target agnostic fix is to guard these IR rules with -XX:-IncrementalInlineVector flag, but it will defeat the purpose of this test since IncrementalInlineVector is default on.

I don't see why it defeats the purpose of the test. It's an IR test and limiting possible IR shapes is fine.

compiler/vectorapi/VectorMaskCompareNotTest.java

With the patch, the vector intrinsic fallback inlining generates more code in the compilation unit, this effects inlining of
other methods, e.g. AbstractMask::intoArray.

Do we miss @ForceInline on AbstractMask::intoArray? Any other methods not inlined?

Do you think its beneficial to limit the scope of inlining to only few intrinsics initially.

I think regular inlining heuristics should be applied to vector fallback implementations.

@openjdk openjdk Bot removed the merge-conflict Pull request has merge conflict with target branch label Jun 11, 2026
@jatin-bhateja

Copy link
Copy Markdown
Member Author

Hi @iwanowww , added the handling to prevent accumulation of spurious messages during fallback call generator selection using RAII based mechanism. Also explicitly printing message "late inline succeeded (vector intrinsic fallback)" in case intrinsification fails but fallback generator (inlining) succeedes.

Please let me if the patch looks good land now, your earlier comments have been addressed.

@iwanowww iwanowww 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.

Overall, looks good.

return &_nullStream;
}
if (is_suspended()) {
locate(state, callee);

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.

Why do you perform locate call?

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.

locate() was retained to keep the IPInlineSite topology intact (one node per JVMState frame) while only the message append is suppressed. But that topology is already guaranteed by record ordering — the order in which record() calls happen during compilation ensures every node's parent exists before the node itself is needed — so locate() rebuilding the path during a suspended probe is unnecessary, and dropping it is safe.

Comment thread src/hotspot/share/opto/callGenerator.cpp Outdated
Comment thread src/hotspot/share/opto/callGenerator.cpp Outdated
Comment thread src/hotspot/share/opto/printinlining.hpp Outdated
@jatin-bhateja

Copy link
Copy Markdown
Member Author

Overall, looks good.

Hi @iwanowww , Your comments have been addressed.

@iwanowww iwanowww 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.

Looks good. Submitted for testing.

@iwanowww

Copy link
Copy Markdown
Contributor

Strangely, compiler.vectorapi.VectorMaskCompareNotTest still fails. I noticed that you changed default warmup setting. Why did you do that?

Failed IR Rules (1) of Methods (1)
----------------------------------
1) Method "compiler.vectorapi.VectorMaskCompareNotTest::testCompareUGTMaskNotByteCast" - [Failed IR rules: 1]:
   * @IR rule 3: "@compiler.lib.ir_framework.IR(phase={DEFAULT}, applyIfPlatformAnd={}, applyIfCPUFeatureOr={"avx2", "true", "rvv", "true"}, counts={"_#XOR_V_MASK#_", "= 0", "_#XOR_V#_", "= 0", "_#VECTOR_MASK_CMP#_", "= 1"}, failOn={}, applyIfPlatform={}, applyIfPlatformOr={}, applyIfOr={}, applyIfCPUFeatureAnd={}, applyIf={}, applyIfCPUFeature={}, applyIfAnd={}, applyIfNot={})"
     > Phase "PrintIdeal":
       - counts: Graph contains wrong number of nodes:
         * Constraint 3: "(\\d+(\\s){2}(VectorMaskCmp.*)+(\\s){2}===.*)"
           - Failed comparison: [found] 0 = 1 [given]
           - No nodes matched!

@jatin-bhateja

Copy link
Copy Markdown
Member Author

Strangely, compiler.vectorapi.VectorMaskCompareNotTest still fails. I noticed that you changed default warmup setting. Why did you do that?

Rebased with latest mainline, looks like it mistakenly got introduced with previous merge.

Kindly re-verify.

@iwanowww iwanowww 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.

Looks good.

@jatin-bhateja

Copy link
Copy Markdown
Member Author

Hi @mhaessig , we need one more approval here to transition this to ready state, can you do the needful.

@eme64 eme64 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.

@jatin-bhateja This looks like important work, so thanks for working on it!

I have some questions about the tests below, I'm especially wondering why you had to set -XX:-IncrementalInlineVector in some of the IR tests? Because if the flag is now on by default, would it not be more important to have IR rules with the flag enabled? What are the affected IR rules?

Also: Could we have some new IR tests that demonstrate the benefit of late vector inlining, and make sure there won't be regressions on it?

public static void main(String[] args) {
TestFramework.runWithFlags("--add-modules=jdk.incubator.vector");
TestFramework.runWithFlags("--add-modules=jdk.incubator.vector",
"-XX:-IncrementalInlineVector");

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.

Why did you add these flags here? Would the IR rules fail without?
Suggestion: can you have a run with and a run without the flag, and then show which IR rules are affected, guarding them with the flag?

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.

Please refer to root cause and suggestions from Vladimir.
#30876 (comment)
#30876 (comment)

Comment on lines +256 to +257
.addFlags("--add-modules=jdk.incubator.vector",
"-XX:-IncrementalInlineVector")

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.

Same question about flag here.

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.

Please refer to
#30876 (comment)
#30876 (comment)
There is also a follow up issue JDK-8385134 filed for it

Comment on lines +1750 to +1751
.addFlags("--add-modules=jdk.incubator.vector",
"-XX:-IncrementalInlineVector")

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.

Same question about flag here.

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.

AFAIR I looked at this particular one (not sure about other ones) and the culprit was the code inlined as part of fallback implementation interfered with the IR test assumptions (unexpected nodes were present). So, disabling inlining is a valid fix for the immediate problem.

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.

Hmm. But is that really good design @iwanowww ? Should we not have some comments that explain this?

These tests are here to ensure we have the expected shapes under regular production - what's the benefit of having IR rules that only apply to non-standard execution?

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.

Comments would help, for sure.

I see it as a test issue. IR tests are whitebox in nature and carefully control the mode they execute in to preserve the invariants they test. Ideally, in this particular case, the tests should detect failed intrinsification attempts and treat them as test failures.

what's the benefit of having IR rules that only apply to non-standard execution?

We either have to explicitly enumerate all supported configurations (supporting reliable intrinsification) or disable execution modes which break test assumptions (the approach taken here). I suggest to file a test bug to improve affected tests. For now, preserving original behavior (no late inlining of fallback implementation) looks fine.

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.

I at least need comments. I don't want to have to reverse engineer why we need that flag there.

And I would like to see IR rules for the new default situation now. That would really help me understand the impact on those tests - otherwise I don't fully know what I'm approving here ;)
Enumerating all cases is sometimes helpful.

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.

@jatin-bhateja

Your suggestion works cleanly for TestVectorTest — done. That failure is deterministic and bound to a static condition: under UseAVX=0 the VectorMask.fromLong/fromBitsCoerced intrinsic doesn't apply, the fallback is inlined, and it materializes the mask query with the scalar CmpI/CMoveI the rules forbid. Under UseAVX>0 it intrinsifies cleanly. So I dropped -XX:-IncrementalInlineVector there and guarded the rules per-platform exactly as you proposed

Great to hear that worked!

For VectorMaskCompareNotTest / VectorCompareWithZeroTest [...]
Empirically, running feature-on (no -XX:-IncrementalInlineVector):

  • Default config: 0 failures.
  • Stress config (-XX:CompileThreshold=100 -XX:-TieredCompilation), four byte-for-byte identical runs: 1 → 84 → 0 → 0 failing methods, with the failing method changing run-to-run.

Thanks for the explanation @jatin-bhateja !

Can you have an applyIf that checks for "normal" CompileThreshold/TieredCompilation, so we get the profiling we get under default conditions? Have you tried that yet?

On how to actually handle this test bug

I still don't understand why we classify this as some kind of "special test bug", that is somehow not related to the changes here. If affects inlining, and we see the consequences in the IR. Looking at the IR effects of this patch here seems relevant, isn't it? What we see here, for example, is that the compilation output is very profiling sensitive now, maybe more than before? But maybe that only happens under the lowered CompileThreshold, which makes profiling less stable, so I suppose that's ok? What do you think @iwanowww ?

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.

It could also be good to add comments to the methods that get flaky compilation, especially if the compilation should show to stay flaky under default compilation. Because that would be more than a test-bug.

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.

Hi @eme64 , I have removed -XX:-IncrementalInlineVector from both VectorMaskCompareNotTest and VectorCompareWithZeroTest tests and modified the IR rules as suggested.

I hope that addresses your concern since tests are now enabled under default settings of IncrementalInlineVector.

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.

@jatin-bhateja Excellent. I'm glad this was possible!

Do we now still need your test-bug follow-up?
https://bugs.openjdk.org/browse/JDK-8388060

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.

@jatin-bhateja Excellent. I'm glad this was possible!

Do we now still need your test-bug follow-up? https://bugs.openjdk.org/browse/JDK-8388060

Current test modification pretty much cover what was planned for follow up test bug.

@iwanowww

iwanowww commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Also: Could we have some new IR tests that demonstrate the benefit of late vector inlining, and make sure there won't be regressions on it?

@eme64 what kind of regressions do you have in mind?

@eme64

eme64 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Also: Could we have some new IR tests that demonstrate the benefit of late vector inlining, and make sure there won't be regressions on it?

@eme64 what kind of regressions do you have in mind?

@iwanowww I'd like to have tests that prevent a later change from accidentally regressing our improvements from this PR here.

@iwanowww

iwanowww commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

I'd like to have tests that prevent a later change from accidentally regressing our improvements from this PR here.

Got it. Sounds reasonable.

@jatin-bhateja

Copy link
Copy Markdown
Member Author

Also: Could we have some new IR tests that demonstrate the benefit of late vector inlining, and make sure there won't be regressions on it?

Hi @eme64 , I have added an IR verification test which exercises both the scenarios with and without IncrementalInlineVector.

Comment on lines +169 to +179
if (IncrementalInlineVector && allow_inline) {
// Try to late inline fallback implementation if intrinsification attempt fails.
CallGenerator* fallback_cg;
{
InlinePrinterSuspendScope guard(C->inline_printer());
fallback_cg = call_generator(callee, vtable_index, call_does_dispatch, jvms,
true /*allow_inline*/, prof_factor,
speculative_receiver_type, false /*allow_intrinsics*/);
}
if (fallback_cg != nullptr && fallback_cg->is_parse()) {
return CallGenerator::for_vector_late_inline(callee, cg, fallback_cg);

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.

Question on naming: is it "late" or "incremental" inlining? Does it make sense to have both names?

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.

Done

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.

You now just updated one comment, right?
I am still wondering about IncrementalInlineVector vs for_vector_late_inline.
Is there a reason for this?

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.

Hi @eme64 ,
This is as per existing naming in Hotspot, an existing flag IncrementalInline has its corresponding call generator named LateInlineCallGenerator which is instantiated by CallGenerator::for_late_inline.

Comment on lines +44 to +48
* A 512-bit FloatVector operation cannot be intrinsified when AVX-512 is not used
* (here forced with -XX:UseAVX=2), so the vector intrinsic fails to expand. With
* IncrementalInlineVector enabled (the default) the fallback implementation
* (VectorSupport::binaryOp) is inlined into the caller, absorbing the call
* overhead; with the flag disabled, a static call to the fallback remains.

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.

If we ever do vector-splitting, we could actuall inline 512-bit vectors if we know that we can split it to 256-bit or 128-bit vectors later. That's actually something we would like to do in the future. If we get to that, then this test will need to be rewritten. Is that something you are aware of?

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.

Modified the test.

@Test
@IR(failOn = { IRNode.VMASK_CMP_ZERO_L_NEON })
@IR(failOn = { IRNode.VMASK_CMP_ZERO_L_NEON },
applyIfAnd = { "TieredCompilation", "true", "CompileThreshold", "10000" })

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.

There is a risk that we will at some point tune CompileThreshold, to let's say 11000 or 9000. And then all of these IR rules will never be executed ever again. How high does the CompileThreshold really need to be to get stable compilation?

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.

It seems that CompileThreshold will not impact the test runs, since framework strips it off.
https://github.com/openjdk/jdk/blob/master/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java#L109

I have removed it from IR rules.

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.

Ah, even better!

@jatin-bhateja

Copy link
Copy Markdown
Member Author

Hi @eme64 , your comments have been addressed.

@eme64

eme64 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

@jatin-bhateja this one is still pending for me: #30876 (comment)

I'm also wondering: do we have some benchmarks that benefit from this change, and would justify this extra complexity? There must have been some benchmark that motivated this work, right? It would be good to see something in the PR description.

@jatin-bhateja

Copy link
Copy Markdown
Member Author

I'm also wondering: do we have some benchmarks that benefit from this change, and would justify this extra complexity? There must have been some benchmark that motivated this work, right? It would be good to see something in the PR description.

Hi @eme64, I've included the results of the BlackScholes benchmark runs in the PR description. As noted there, we also have a dependent pull request #24104 whose fallback implementation is itself built on the Vector API — inlining that fallback is what lets us avoid the boxing penalties, which is a key performance motivation for this change.

@jatin-bhateja
jatin-bhateja requested a review from eme64 July 25, 2026 07:42
@jatin-bhateja

Copy link
Copy Markdown
Member Author

Hi @eme64 , your comments have been addressed/answered. Looking forward to your approval

@jatin-bhateja

Copy link
Copy Markdown
Member Author

Hi @XiaohongGong, can you kindly review this pull request.

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