On Thu, 30 Jul 2026 02:19:09 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.2 | 
> 3400.5 | 1.7 | 1.71
> MaskLogicOperationsBenchmark.shortMaskNotAnd | 256 | ...

@dean-long @theRealAph Your points seem to point in the same direction, which I 
think is reasonable. One thing to note here is that changing `(A & B) ^ B` to 
`~A & B` might result in an extra `Replicate` operation on backends without 
`AND_NOT` match rule support. However, I expect it to have almost no impact on 
performance because such instructions have no dependencies and are usually 
moved outside the loop. Let me revise it, thank you~

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

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

Reply via email to