On Fri, 7 Aug 2026 03:16:56 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 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 three additional commits since > the last revision: > > - Canonicalize "(A & B) ^ B" to "~A & B" in midend > - Merge branch 'master' into JDK-8388918-not-and-opt > - 8388918: AArch64: Optimize vector and vector mask (A & B) ^ B to BIC > instruction > > 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: > ``` > 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 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.2 3400.5 1.7 1.71 > MaskLogicOperationsBenchmark.shortMaskNotAnd 256 ops/ms 30460.9 > 35.2 52855.5 30.4 1.74 > MaskLogicOperationsBenchmark.shortMaskNotAnd 512 ops/ms 15430.4 > 37.9 26508.9 33.5 1.72 > MaskLogicOperationsBenchmark.shortMaskNotAnd 1024 ops/ms 8064.8 > 14.7 13846.5 4.9 1.72 > ``` > > On an AWS Graviton3 (Neoverse-V1) machine with 256-bit SVE1: > ``` > Benchmark size Unit... Since these transformations are similar between different kinds of `XorNode` (scalar, vector, mask). I suggest refactoring it to a separate function that gets called from those places. ------------- PR Comment: https://git.openjdk.org/jdk/pull/32095#issuecomment-5212940253
