On Tue, 20 Oct 2026 08:02:05 GMT, Eric Fang <[email protected]> wrote:

>> The expression `(A & B) ^ B` is algebraically equivalent to `~A & B`, which 
>> maps directly to the AArch64 `BIC` (bit clear) instruction.
>> 
>> Now the expression is lowered as two operations `AndV` and `XorV`, this 
>> patch adds C2 match rules to fold this pattern into a single `BIC` for both 
>> integral vectors and vector masks on AArch64 (NEON and SVE). JMH 
>> micro-benchmarks demonstrate a significant performance improvement.
>> 
>> On a Nvidia Grace (Neoverse-V2) machine with 128-bit SVE2:
>> <html xmlns:v="urn:schemas-microsoft-com:vml"
>> xmlns:o="urn:schemas-microsoft-com:office:office"
>> xmlns:x="urn:schemas-microsoft-com:office:excel"
>> xmlns="http://www.w3.org/TR/REC-html40";>
>> 
>> <head>
>> 
>> <meta name=ProgId content=Excel.Sheet>
>> <meta name=Generator content="Microsoft Excel 15">
>> <link id=Main-File rel=Main-File
>> href="file:////Users/erfang/Library/Group%20Containers/UBF8T346G9.Office/TemporaryItems/msohtmlclip/clip.htm">
>> <link rel=File-List
>> href="file:////Users/erfang/Library/Group%20Containers/UBF8T346G9.Office/TemporaryItems/msohtmlclip/clip_filelist.xml">
>> 
>> </head>
>> 
>> <body link="#467886" vlink="#96607D">
>> 
>> 
>> Benchmark | size | Unit | Before | Error | After | Error | Uplift
>> -- | -- | -- | -- | -- | -- | -- | --
>> LogicOperationsBenchmark.byteNotAnd | 1024 | ops/ms | 20769.0 | 49.6 | 
>> 52065.1 | 684.0 | 2.51
>> LogicOperationsBenchmark.intNotAnd | 1024 | ops/ms | 3576.6 | 0.4 | 7980.8 | 
>> 4.0 | 2.23
>> LogicOperationsBenchmark.longNotAnd | 1024 | ops/ms | 1699.1 | 0.6 | 3575.1 
>> | 0.6 | 2.10
>> LogicOperationsBenchmark.shortNotAnd | 1024 | ops/ms | 7986.0 | 3.4 | 
>> 20523.8 | 13.6 | 2.57
>> MaskLogicOperationsBenchmark.byteMaskNotAnd | 256 | ops/ms | 82165.6 | 70.1 
>> | 108802.4 | 169.4 | 1.32
>> MaskLogicOperationsBenchmark.byteMaskNotAnd | 512 | ops/ms | 42859.7 | 27.1 
>> | 59531.1 | 65.5 | 1.39
>> MaskLogicOperationsBenchmark.byteMaskNotAnd | 1024 | ops/ms | 21703.1 | 9.3 
>> | 31475.2 | 5.5 | 1.45
>> MaskLogicOperationsBenchmark.intMaskNotAnd | 256 | ops/ms | 15467.4 | 50.9 | 
>> 27138.2 | 76.1 | 1.75
>> MaskLogicOperationsBenchmark.intMaskNotAnd | 512 | ops/ms | 7951.4 | 14.9 | 
>> 13962.2 | 4.9 | 1.76
>> MaskLogicOperationsBenchmark.intMaskNotAnd | 1024 | ops/ms | 3988.2 | 4.1 | 
>> 6876.1 | 2.1 | 1.72
>> MaskLogicOperationsBenchmark.longMaskNotAnd | 256 | ops/ms | 7933.8 | 6.4 | 
>> 13933.2 | 6.6 | 1.76
>> MaskLogicOperationsBenchmark.longMaskNotAnd | 512 | ops/ms | 3977.9 | 4.0 | 
>> 6865.8 | 4.2 | 1.73
>> MaskLogicOperationsBenchmark.longMaskNotAnd | 1024 | ops/ms | 1992.7 | 1...
>
> Eric Fang has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   Remove the unrelated files that were accidentally included

Hi,

I’d like to provide some additional context for this patch to help with the 
**review**.

## What this patch does

This patch optimizes IR patterns such as `(A & B) ^ B` into a single AArch64 
`BIC` instruction for better performance.

## Background

Before August, the implementation used an AArch64 backend match rule, as I 
initially considered this a purely AArch64-specific backend optimization.

@theRealAph  then suggested that implementing it in the C2 middle end might be 
better, since this would allow us to reuse the existing BIC optimization rules 
in the backend. @merykitty  also pointed out that this optimization applies to 
both scalar and vector operations, and suggested using a shared optimization 
framework to avoid duplicating the optimization for different types.

These are reasonable suggestions. In the long term, we may add more type 
independent optimizations. I have therefore revised the implementation 
accordingly.

## Current implementation

1. Introduced a generic optimization framework shared across scalar, vector, 
and vector mask types:
   - `src/hotspot/share/opto/genericOpts.hpp`
   - `src/hotspot/share/opto/genericOpts.cpp`

2. The framework supports optimizations that take a root node, match an IR 
pattern, and return either `nullptr` or a `Node*`. The caller defines the 
semantics of the return value. It can be used by IGVN optimizations such as 
`Ideal`, `Identity`, and `Hash`.

3. The implementation uses templates, with node classes as template arguments 
for compile-time instantiation. Call sites do not need to specify template 
arguments, keeping the calls decoupled from the implementation.

4. Currently, the framework only implements the vector `not_and → and_not` 
transformation. Support for the same optimization on scalar types can be added 
easily later.

5. Other changes:
   - Added `VectorNode::make_con` to simplify constant creation and used it 
where applicable.
   - Added JTReg and JMH tests. The JTReg tests, including tiers 1–3, passed on 
both AArch64 and x86. The JMH results show good performance improvements, with 
no noticeable regressions on either platform.

Please take another look at this PR when you have time. Thank you!

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

PR Comment: https://git.openjdk.org/jdk/pull/32095#issuecomment-6436460583

Reply via email to