On Fri, 18 Sep 2026 18:16:25 GMT, Vladimir Ivanov <[email protected]> wrote:

>> Eric Fang has updated the pull request with a new target base due to a merge 
>> or a rebase. The incremental webrev excludes the unrelated changes brought 
>> in by the merge/rebase. The pull request contains four additional commits 
>> since the last revision:
>> 
>>  - Merge branch 'master' into JDK-8384571-vector-blend-opt-pr1
>>  - Add JMH and JTReg tests for each optimization pattern and each type
>>  - Merge branch 'master' into JDK-8384571-vector-blend-opt-pr1
>>  - 8384571: C2: Add some basic IGVN optimization for VectorBlendNode
>>    
>>    This PR introduces the basic Ideal/Identity transformations for
>>    `VectorBlendNode`.
>>    
>>    The semantic of `VectorBlend(X, Y, M)` is: `M ? Y : X`.
>>    
>>    **Identity**:
>>    ```
>>      (VectorBlend X Y (Replicate -1)) => Y
>>      (VectorBlend X Y (MaskAll   -1)) => Y
>>      (VectorBlend X Y (Replicate  0)) => X
>>      (VectorBlend X Y (MaskAll    0)) => X
>>    ```
>>    
>>    **Ideal**:
>>    ```
>>      (VectorBlend (VectorBlend X A M) B M) => (VectorBlend X B M)
>>      (VectorBlend A (VectorBlend B X M) M) => (VectorBlend A X M)
>>      (VectorBlend A B (XorV/XorVMask M -1)) => (VectorBlend B A M)
>>    ```
>>    
>>    Also corrects the VectorBlendNode header comment: across all backends
>>    (X86 SSE/AVX, AArch64 NEON/SVE, RISC-V V) the active mask lane selects
>>    `vec2` (in(2)), and the inactive lane selects `vec1` (in(1)).
>>    
>>    JTReg and JMH tests are also added for each optimization pattern. All
>>    tests (tier1, tier2, and tier3) passed on AArch64 and X86 platforms.
>>    
>>    JMH benchmark test results:
>>    
>>    On a Nvidia Grace (Neoverse-V2) machine with 128-bit SVE2:
>>    ```
>>    Benchmark         Unit    Before  Error   After           Error   Uplift
>>    blendNegatedMaskInt       ops/ms  7990.6  2.8     10215.2         11.0    
>> 1.3
>>    identityAllOnesInt        ops/ms  3574.8  2.6     7967.1          0.3     
>> 2.2
>>    identityAllZerosLong      ops/ms  3575.6  1.0     7966.0          3.6     
>> 2.2
>>    nestedBlendInnerLong      ops/ms  3533.8  2.8     478573.0        3178.5  
>> 135.4
>>    nestedBlendOuterInt       ops/ms  3537.6  3.4     472242.2        3034.2  
>> 133.5
>>    ```
>>    
>>    On an AWS Graviton3 (Neoverse-V1) machine with 256-bit SVE1:
>>    ```
>>    Benchmark         Unit    Before  Error   After           Error   Uplift
>>    blendNegatedMaskInt       ops/ms  5171.9  5.2     8129.0          17.3    
>> 1.6
>>    identityAllOnesInt        ops/ms  2722.0  0.1     5891.3          0.1     
>> 2.2
>>    identityAllZerosLong      ops/ms  2722.4  0.1     5891.1          0.3     
>> 2.2
>>    nestedBlendInnerLong      ops/ms  2697.6  0.0     312148.7        2366.4  
>> 115.7
>>    nestedBlendOuterInt       ops/ms  2702.7  0.1     308686.0        2709.8  
>> 114.2
>>    ```
>>    
>>    On...
>
> src/hotspot/share/opto/vectornode.cpp line 2919:
> 
>> 2917: 
>> 2918:   // (VectorBlend A B (XorV/XorVMask M -1)) => (VectorBlend B A M)
>> 2919:   Node* uncasted_mask = uncast_mask(mask);
> 
> A simpler alternative is to detect negated mask shape and swap arguments 
> along with double negating the mask:
> 
> VectorBlend A B (NotV M) ==> VectorBlend B A (NotV (NotV M)) ==> VectorBlend 
> B A M

Hi @iwanowww thanks for your review! Your suggestion makes sense to me. 
However, after some trials, I do not see a clear simplification compared with 
the current approach. I have two questions—could you help clarify them?

1. The optimization `NotV(NotV M) => M` has not been implemented yet. Should we 
open a separate PR to add that optimization first, or should we just include it 
in this PR?

2. If we convert `VectorBlend A B (NotV M) => VectorBlend B A (NotV (NotV M))`, 
then this optimization will depend on `NotV(NotV M) => M`. That means the two 
optimizations would not be well decoupled, which does not seem ideal from a 
design perspective. Is your concern that the two optimizations may share some 
code? If so, perhaps extracting a helper function would be sufficient. What do 
you think?

> src/hotspot/share/opto/vectornode.cpp line 2949:
> 
>> 2947:   // (VectorBlend X Y (Replicate -1)) => Y
>> 2948:   // (VectorBlend X Y (MaskAll   -1)) => Y
>> 2949:   if (VectorNode::is_all_ones_vector(uncast_mask(in(3)))) {
> 
> I suggest to either enhance `VectorNode::is_all_ones_vector` to cover vector 
> masks or introduce a helper method. Explicit vector mask uncasting 
> (`uncast_mask()`) is error-prone and harder to read.

Make sense, I'll add a new helper to do this, avoid changing the semantics of 
`VectorNode::is_all_ones_vector`.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/31333#discussion_r4072277539
PR Review Comment: https://git.openjdk.org/jdk/pull/31333#discussion_r4072293030

Reply via email to