NEON-vectorized exclusiveUnion2by2 - #569
Open
gitRasheed wants to merge 3 commits into
Open
gitRasheed wants to merge 3 commits into
gitRasheed wants to merge 3 commits into
Conversation
union2by2 already has a generic definition and an arm64 one. Give difference, exclusiveUnion2by2, intersection2by2 and intersection2by2Cardinality the same split so vector versions can land one at a time without touching the shared files. The arm64 versions pass through to the scalar code for now.
This was referenced Sep 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
NEON kernel for
exclusiveUnion2by2, the array-container xor, on arm64. Both arrays need at least 32 elements. Smaller inputs keep the scalar merge.Unlike the union kernel, this one carries no partial block between steps. Each step takes a 16-element window from both sides and counts how many elements of each lie at or below the smaller window maximum. It sorts all 32 through a bitonic network and keeps a value only when it differs from both neighbours and lies at or below that maximum. Every step consumes a closed value interval, so a duplicate pair can never straddle two steps and there is no seam state. Windows entirely below the other side are copied straight through, and identical windows cancel without sorting.
Xor had no vector path on any architecture here. The output buffer is always fresh and sized for both inputs, so the kernel needs neither an in-place spill nor a store clamp.
I made a page that steps through this kernel on worked examples and annotates the assembly line by line, to make the design choices easier to follow: https://claude.ai/code/artifact/5f77af0d-89c2-4965-9d15-95fde361c47f#xor (the other tabs cover the other three kernels).
Changes
setutil_arm64.go: the lane-compaction table, its own commit, shared with NEON-vectorized intersection2by2 #543, NEON-vectorized union2by2 #567 and NEON-vectorized difference #568.setutil.go/setutil_generic.go:difference,exclusiveUnion2by2and the two intersection entry points get the generic/arm64 split thatunion2by2already has. This commit is shared with NEON-vectorized intersection2by2 #543 and NEON-vectorized difference #568 so the three merge in any order, and it drops out of the others once one of them lands; the two passthrough files for the other operations are part of it.setutil_xor_neon_arm64.s: the kernel.setutil_xor_arm64.go: dispatch and the wrapper that hands the unread tails to the scalar merge.Testing
go testpasses on Graviton 4 with this branch, and passed on Graviton 5 and 2 and on amd64 with the same kernel on 5 September.go fmtclean. Smat fuzzer, 300 seconds on Graviton 5: 594,777 executions, no failures.Performance
Against master on Graviton 5 (c9g.xlarge, Neoverse V3), medians of five interleaved runs:
Graviton 2 (c6g.large, Neoverse N1):
BenchmarkXor1.41x, the others unchanged. Bulk-merge xor benchmarks within 3 percent either way on both machines.Kernel against scalar merge at 32 and 2048 elements per side, 128 rotated fixed-seed inputs per cell, worse input order, V3: low-overlap random 1.9x and 7.7x, identical 3.0x and 11.7x, every-eighth-value periodic difference 1.3x and 1.7x. N1: 3.1x and 5.6x, 3.8x and 11.3x, 1.4x and 1.9x.
The threshold of 32 per side is the smallest size at which the kernel beat the scalar merge on every tested shape in both input orders on both cores.