Fix ARM NEON scan helpers truncating 64-bit versions #75

Merged
andrew merged 1 commits from weaselbot/conflict-set:weaselbot/issue-69 into main 2026-08-03 12:26:09 +00:00
Member

Summary

Fixes the aarch64 ARM NEON fast paths that truncated 64-bit versions to 32 bits when USE_64_BIT=1, producing spurious conflicts/commits once the version counter exceeded 2^32 - 1.

Root cause

scan16 (both the indexed Node48 variant and the Node256 variant) and checkMaxBetweenExclusiveImpl(Node16) copied only the low 32 bits of each InternalVersionT into uint32x4_t lanes and compared against a 32-bit readVersion. With USE_64_BIT=1, InternalVersionT stores an int64_t, so this is wrong for any version above 2^32.

Fix

The per-version vs[i] > readVersion computation is extracted into a shared conflictMask16 helper that returns a uint8x16_t (byte i = 0xff on conflict). For 64-bit versions it compares the full int64 values with vcgtq_s64 and narrows the result into the same nibble-packed (4 bits per version) layout the callers already consume; the 32-bit path is unchanged.

Verification

Built on aarch64 with -DUSE_64_BIT=1 (the previously failing configuration). script_test_internal_version_zero now passes, the corpus blackbox case eace36b9... (which previously reported Expected commit, got conflict ... at version 6993204482) now succeeds, and the full non-valgrind ctest suite (8554 tests) passes for both USE_64_BIT=1 and the default 32-bit build. (Valgrind tests are skipped here because the host valgrind does not support this aarch64 CPU.)

Closes #69

## Summary Fixes the aarch64 ARM NEON fast paths that truncated 64-bit versions to 32 bits when `USE_64_BIT=1`, producing spurious conflicts/commits once the version counter exceeded `2^32 - 1`. ## Root cause `scan16` (both the indexed `Node48` variant and the `Node256` variant) and `checkMaxBetweenExclusiveImpl(Node16)` copied only the low 32 bits of each `InternalVersionT` into `uint32x4_t` lanes and compared against a 32-bit `readVersion`. With `USE_64_BIT=1`, `InternalVersionT` stores an `int64_t`, so this is wrong for any version above `2^32`. ## Fix The per-version `vs[i] > readVersion` computation is extracted into a shared `conflictMask16` helper that returns a `uint8x16_t` (byte `i` = `0xff` on conflict). For 64-bit versions it compares the full `int64` values with `vcgtq_s64` and narrows the result into the same nibble-packed (4 bits per version) layout the callers already consume; the 32-bit path is unchanged. ## Verification Built on aarch64 with `-DUSE_64_BIT=1` (the previously failing configuration). `script_test_internal_version_zero` now passes, the corpus blackbox case `eace36b9...` (which previously reported `Expected commit, got conflict ... at version 6993204482`) now succeeds, and the full non-valgrind ctest suite (8554 tests) passes for both `USE_64_BIT=1` and the default 32-bit build. (Valgrind tests are skipped here because the host valgrind does not support this aarch64 CPU.) Closes #69
weaselbot added 1 commit 2026-08-03 03:35:54 +00:00
Fix ARM NEON scan helpers truncating 64-bit versions
CI / release (arm64, , ubuntu-latest-arm64) (pull_request) Successful in 2m13s
CI / pre-commit (pull_request) Successful in 2m2s
CI / test (-DCMAKE_BUILD_TYPE=Debug -DMSAN_TOOLCHAIN_PATH=/opt/msan, debug) (pull_request) Successful in 3m47s
CI / test (-DCMAKE_CXX_FLAGS=-DUSE_64_BIT=1, 64-bit-versions) (pull_request) Successful in 3m15s
CI / test (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc) (pull_request) Successful in 3m12s
CI / test (-DUSE_SIMD_FALLBACK=ON, simd-fallback) (pull_request) Successful in 3m17s
CI / release (amd64, -DMSAN_TOOLCHAIN_PATH=/opt/msan, ubuntu-latest-amd64) (pull_request) Successful in 5m34s
CI / coverage (pull_request) Successful in 3m43s
6b1f597d77
When USE_64_BIT=1, InternalVersionT stores an int64_t, but the aarch64
NEON fast paths in scan16 (both the indexed Node48 variant and the
Node256 variant) and checkMaxBetweenExclusiveImpl(Node16) only copied the
low 32 bits of each version into uint32x4_t lanes and compared against a
truncated 32-bit readVersion. This produced wrong conflict/commit
decisions once any version exceeded 2^32 - 1.

Extract the per-version "greater than readVersion" computation into a
shared conflictMask16 helper. For 64-bit versions it uses vcgtq_s64 on
the full int64 values and narrows the resulting 16-byte mask into the
same nibble-packed layout the callers already consume. The 32-bit path is
preserved unchanged.

Closes #69
andrew merged commit 1179c1f56e into main 2026-08-03 12:26:09 +00:00
andrew deleted branch weaselbot/issue-69 2026-08-03 12:26:10 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: weaselab/conflict-set#75