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
