On Thu, 30 Jul 2026 02:02:54 GMT, Eric Fang <[email protected]> wrote:
> VectorMask.lastTrue() returns the index of the last (highest-numbered) lane > that is set in the mask, or -1 if no lane is set. > > Currently on AArch64 with SVE enabled, this API is implemented on a predicate > register via the sequence `rev + brkb + cntp + movw + subw`. There is no > native SVE predicate instruction for "last active lane index". This > implementation doesn't perform very well because it heavily relies on the M > pipeline, and the dependency chain between instructions is too long. > > There is a SVE `lastb` instruction [1] that can extract the last active > element from a vector register, and we can use this instruction to implement > this API. As follow: > > // vtmp = 0, 1, 2, ... > sve_index(vtmp, size, 0, 1); > // dst = last true or the highest-numbered element if src is all false > sve_lastb(dst, size, src, vtmp); > // Zero flag = 1 iff no active lane > sve_ptest(ptrue, src); > // active: keep; else -1 > csinvw(dst, dst, zr, Assembler::NE); > > This implementation is more evenly distributed across the different pipelines > and exhibits better parallelism. Thus has better performance. > > On a Nvidia Grace (Neoverse-V2) machine with 128-bit SVE2: > > Benchmark inputs Unit Before Error After > Error Uplift > testLastTrueByte 1 ops/ms 1047092.6 33773.0 1132866.9 > 29053.6 1.08 > testLastTrueByte 2 ops/ms 1032945.0 18573.7 1152164.6 > 21749.0 1.12 > testLastTrueByte 3 ops/ms 1032476.9 25744.7 1136212.3 > 33285.8 1.10 > testLastTrueDouble 1 ops/ms 987207.0 6460.4 1126175.6 > 5973.0 1.14 > testLastTrueDouble 2 ops/ms 987724.9 5854.1 1126033.5 > 3558.7 1.14 > testLastTrueDouble 3 ops/ms 985976.2 3525.5 1128522.9 > 2284.2 1.14 > testLastTrueFloat 1 ops/ms 978225.9 12308.3 1129334.8 > 7655.7 1.15 > testLastTrueFloat 2 ops/ms 980388.5 15776.9 1119524.3 > 25849.4 1.14 > testLastTrueFloat 3 ops/ms 988192.5 3414.6 1129177.4 > 7393.8 1.14 > testLastTrueInt 1 ops/ms 979679.8 9878.7 > 1125093.3 7802.7 1.15 > testLastTrueInt 2 ops/ms 987964.7 3320.0 > 1116457.0 12490.9 1.13 > testLastTrueInt 3 ops/ms 982718.4 6455.4 > 1131456.3 8357.6 1.15 > testLastTrueLong 1 ops/ms 1009693.7 3160.9 1113229.0 > 18412.3 1.10 > testLastTrueLong 2 ops/ms 1003385.8 6314.5 1126162.2 > 6872.6 1.12 > testLastTrueLong 3 ops/ms 998882.0 10596.3 1126631.1 > 2575.0 1.13 > testLastTrueShort 1 ops/ms 981657.4 16531.1 1110119.0 > 22422.8 1.13 > testLastTrueShort 2 ops/ms 989732.1 5418.9 1120666.7 > 14837.0 1.13 > testLastTrueShort 3 ops/ms 993479.7 20890.1 1113419.3 > 9783.8 1.12 > > > On an AWS Graviton3 (Neoverse-V1) machine with 256-bit SVE1: > > Benchmark bits inputs Unit Before Error After... Marked as reviewed by ruben (Author). ------------- PR Review: https://git.openjdk.org/jdk/pull/32094#pullrequestreview-5031030533
