Repository navigation
Conversation
This was referenced Oct 17, 2026
4 lanes: AND with the lane weights + ADDV instead of USHR + USHL + ADDV. 8 lanes (2 x native, also used by the 512 and 1024 bit composites): UZP2 narrows both halves into one register of 16 bit lanes, then one AND + ADDV instead of a reduction per half (GCC 13: 9 instructions to 4). Both read one bit per lane rather than the sign bit, so like AnyMask they rely on each mask lane being all ones or all zeros. The NEON level keeps the existing versions. Covered by the m32/m32i bit mask to int tests.
Round + vcvtq_s32_f32 is FRINTN + FCVTZS with GCC 13 and clang 15/18; vcvtnq_s32_f32 rounds to nearest even in one instruction with the same results (ties to even, saturation, NaN -> 0). Clang 23 already fuses the pair into FCVTNS, but through the intrinsic it no longer fuses a preceding Floor into FCVTMS (or Round into FCVTNS). That only costs an instruction when the rounded float isn't used too: in FastNoise2 master clang 23 swaps all 120 FCVTMS for FCVTNS with no extra FRINTM. The NEON level keeps Round + vcvtq.
Auburn
force-pushed
the
perf/aarch64-conversions
branch
from
October 17, 2026 16:53
2e06e5a to
0275c69
Compare
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.
Change
Two commits, both AArch64 only (
ToolSet/ARM/128/m32x4.handToolSet/ARM/NEON.h). The NEON level is unchanged.BitMaskweights each lane by its bit and adds across. 4 lanes:andwith the weights +addv, instead ofushr+ushl+addv. 8 lanes (2 × native, which the 512 and 1024 bit composites also go through):uzp2narrows both halves into one register of 16 bit lanes, then oneand+addvinstead of a reduction per half.Convertf32 → i32 with FCVTNS, for every compiler.vcvtq_s32_f32( Round( a ) )is FRINTN + FCVTZS with GCC 13 and clang 15 and 18.vcvtnq_s32_f32is a single FCVTNS that rounds to nearest even with the same results (ties to even, saturation, NaN → 0).Like
AnyMask(vmaxvq), the newBitMaskexpects each lane to be all ones or all zeros, which is what comparisons and mask operations produce. It reads one bit per lane, not the sign bit.Changes since the first version of this PR:
AnyMaskoverload is gone. Since Composite AnyMask: test the OR of both halves #15 the generic compositeAnyMaskis the sameAnyMask( a.v0 | a.v1 ), and the generated code is identical without it.BitMask. That branch compiled to the same code as the generic composite.Convertno longer keeps clang onRound+vcvtq. Only recent clang fuses that pair into FCVTNS (23 does, 15 and 18 don't), so the exception left older clang on two instructions.Why
Per call on AARCH64,
-O3 -ffast-math, after a compare. Not counting loads, the compares or the weights load:BitMask, GCC 13ushr,ushl,addv,fmovand,addv,fmovBitMask, clang 18movi,and,ushl,addv,fmovand,addv,fmovBitMask, clang 23and,addv,fmovBitMask, GCC 13ushr/ushl/addv/fmov,orr)uzp2,and,addv,umov)BitMask, clang 18movi, 2 ×and/ushl/addv/fmov,orr)uzp2,and,addv,fmov)BitMask, clang 23and/addv/fmov,orr)uzp2,and,addv,fmov)Convert, GCC 13 and clang 18frintn,fcvtzsfcvtnsConvert, clang 23fcvtnsfcvtnsConvert( Floor ), GCC 13frintm,frintn,fcvtzsfrintm,fcvtnsConvert( Floor ), clang 18frintm,fcvtzsfrintm,fcvtnsConvert( Floor ), clang 23fcvtmsfrintm,fcvtnsConvert( Round ), clang 23fcvtnsfrintn,fcvtnsThe last two rows are the cost: clang 23 doesn't fuse a rounding into the intrinsic, so
Convert( Floor( x ) )orConvert( Round( x ) )takes one more instruction when the rounded float isn't also used. A float → int floor function (vcvtmq_s32_f32) would fix that for every compiler.FastNoise2 master (c47a7b9),
FastSIMD_FastNoiseAARCH64 object, instruction count:The NEON objects are identical for all three compilers. Nothing in FastNoise2 master calls
BitMaskon ARM.Testing
qemu-aarch64, with GCC 13, clang 18 and clang 23. Full suite at 65,536 inputs for seeds 24301, 1 and 2: 628 passed, 88 known failures, 0 failed, output identical to master in all nine runs. The mask and convert tests also ran at the full count (4,194,304) and pass on all three compilers.m32andm32i bit mask to inton AARCH64: at 128 bit for the 4 lane version, at 256, 512 and 1024 bit for the 8 lane version.arm64_neon.hdefines every intrinsic used.AnyMaskchange (now in Composite AnyMask: test the OR of both halves #15) together withBitMask.Not in this PR
Convert( Floor( x ) )is FRINTM + FCVTNS where FCVTMS would do. That needs a float → int floor function (vcvtmq_s32_f32). FastNoise2's performance branch currently does this on its own side.