On Fri, 31 Jul 2026 02:33:12 GMT, Dean Long <[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...
>
> src/hotspot/cpu/aarch64/aarch64_vector.ad line 1876:
> 
>> 1874: instruct vnot_and(vReg dst, vReg src1, vReg src2) %{
>> 1875:   match(Set dst (XorV (AndV src1 src2) src2));
>> 1876:   match(Set dst (XorV (AndV src2 src1) src2));
> 
> Do we already turn ~A & B into BIC somewhere?  I was expecting a match rule 
> here for it.

Yeah we have some similar rules, see 
https://github.com/openjdk/jdk/blob/cc278dbb8a1ca0754d5842708b9029441055d361/src/hotspot/cpu/aarch64/aarch64_vector.ad#L1907,
 which are different with these patterns.

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

PR Review Comment: https://git.openjdk.org/jdk/pull/32095#discussion_r3687685547

Reply via email to