Skip to content

arm/neon: add LSX implementations - #1447

Merged
mr-c merged 1 commit into
simd-everywhere:masterfrom
jinboson:loongarch_neon_2_lsx
Sep 16, 2026
Merged

mr-c merged 1 commit into
simd-everywhere:masterfrom
jinboson:loongarch_neon_2_lsx

Conversation

@jinboson

@jinboson jinboson commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Based on this libjpeg-turbo/libjpeg-turbo#838, we made a performance test:

Current libjpeg-turbo commit: 174da652ef60ef7191357620eaf1d8fe776de723
Current SIMDe commit: 6a72a0434262d0f7f50e1e264284973bcbbd373e
Loongson-3A5000HV, Loongnix GNU/Linux 20 (DaoXiangHu), gcc (Loongnix 8.3.0-6.lnd.vec.44) 8.3.0 :

Algorithm Scalar/C Native SIMDe
RGB-to-YCbCr Color Conversion (Mpixels/sec) 209 0 387
RGB-to-Grayscale Color Conversion (Mpixels/sec) 456 0 579
H2V1 (4:2:2) Downsampling (Msamples/sec) 857 0 3924
H2V2 (4:2:0) Downsampling (Msamples/sec) 1222 0 5084
Integer Sample Conversion (Msamples/sec) 825 0 1185
Accurate Integer Forward DCT (Mcoefficients/sec) 316 0 479
Integer Quantization (Mcoefficients/sec) 277 0 651
Huffman Encoding (Mcoefficients/sec) 558 0 522
Accurate Integer Inverse DCT (Mcoefficients/sec) 392 0 461
H2V1 (4:2:2) Fancy (Smooth) Upsampling (Msamples/sec) 1601 0 4751
H2V2 (4:2:0) Fancy (Smooth) Upsampling (Msamples/sec) 1197 0 3907
H2V1 (4:2:2) Merged Upsampling/Color Conversion (Mpixels/sec) 375 0 629
H2V2 (4:2:0) Merged Upsampling/Color Conversion (Mpixels/sec) 432 0 784
YCbCr-to-RGB Color Conversion (Mpixels/sec) 204 0 458

Comment thread simde/arm/neon/get_lane.h
Comment thread simde/arm/neon/ld1_lane.h Outdated
@jinboson

Copy link
Copy Markdown
Contributor Author

Sorry for the delay — I'm away on vacation. I'll get back to this once I return. Thanks for your understanding!

@jinboson
jinboson force-pushed the loongarch_neon_2_lsx branch from 2d92bf5 to b6db5f9 Compare September 14, 2026 08:35
@mr-c
mr-c force-pushed the loongarch_neon_2_lsx branch from b6db5f9 to eb56eb3 Compare September 14, 2026 08:45
@mr-c
mr-c enabled auto-merge (rebase) September 14, 2026 08:51
@mr-c
mr-c disabled auto-merge September 14, 2026 15:21

@mr-c mr-c left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jinboson
jinboson force-pushed the loongarch_neon_2_lsx branch from eb56eb3 to ef9a06b Compare September 15, 2026 06:15
@jinboson

jinboson commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

Reproduced with GCC 12.3:

[loongson@linux simde]$ SIMDEPATH=$HOME/jin/simde
[loongson@linux simde]$ gcc -I$SIMDEPATH/test/arm/neon -I$SINCE -std=c99 -Ofast -mlsx -DSIMDE_TEST_BARE -o /tmp/aba $SIMDEPATH/test/arm/neon/aba.c && /tmp/aba
1..12
ok 1 aba/vaba_s8
ok 2 aba/vaba_s16
ok 3 aba/vaba_u8
ok 4 aba/vaba_u16
ok 5 aba/vaba_u32
/home/loongson/jin/simde/test/arm/neon/aba.c:227: assertion failed: r[0] == simde_vld1_s32(test_vec[i].r)[0] (-1971202570 == -1971202570)
not ok 6 aba/vaba_s32
ok 7 aba/vabaq_s8
ok 8 aba/vabaq_s16
ok 9 aba/vabaq_u8
ok 10 aba/vabaq_u16
ok 11 aba/vabaq_s32
ok 12 aba/vabaq_u32

The failing subtest is aba/vaba_s32 on the LoongArch native build. The cause is
signed-integer-overflow UB in the SIMDE_VECTOR_SUBSCRIPT_OPS fallback of simde_vadd_s32:

r_.values = a_.values + b_.values;      /* signed lanes */

simde_vaba_s32(a,b,c) = simde_vadd_s32(simde_vabd_s32(b,c), a), and simde_vabd_s32 widens the
subtraction to 64 bits before truncating, so the add that follows can overflow: with one of the
aba vectors it computes 222721906 + 2101042820 = 2323764726 (> INT32_MAX). UBSan flags exactly
that statement (add.h:252; also add.h:186 for simde_vadd_s8) - we used UBSan to localize it, but
the CI itself does not run sanitizers: the failure there is a wrong result, not a sanitizer report.

Because signed overflow is UB, at -O3-level optimization GCC may assume it never happens and
removes the code that depends on it: in the generated test_simde_vaba_s32 only 6 of the 16 lane
comparisons survive and the single ret returns 1, i.e. the success path is gone - which is why the
assertion prints two equal values and still fails. This is not Ofast- or GCC-version-specific:
-O2 passes, -O3/-Ofast fail, "-O2 -ffast-math" passes, "-O3 -fno-fast-math" fails, and
"-O3 -fno-strict-overflow" / "-Ofast -fwrapv" pass. The -fastmath CI job is simply the only
LoongArch job built at -O3 (the others use meson's default -O0).

Fix: keep the operation out of C signed arithmetic. Adding the LSX path for simde_vadd_s32
does that, because the intrinsic is opaque to the optimizer:

#elif defined(SIMDE_LOONGARCH_LSX_NATIVE)
  simde_x_lsx_store64(&r_.values, __lsx_vadd_w(simde_x_lsx_load64(&a_.values), simde_x_lsx_load64(&b_.values)));

Verified: the aba suite passes at -O2/-O3/-Ofast and UBSan reports zero runtime errors (it
reported 3 before). The same latent UB exists in the other 64-bit signed adds, so the patch
covers vadd_s8/s32/s64 as well (plus the unsigned ones for consistency).

The above analysis is based on DeepSeek Harness + DeepSeek-V4-Flash.

@jinboson
jinboson requested a review from mr-c September 15, 2026 07:42
This change only implements the NEON instructions used by the
libjpeg-turbo project in the simde/arm directory. The remaining
instructions in each file will be submitted in subsequent patches.
@mr-c
mr-c force-pushed the loongarch_neon_2_lsx branch from ef9a06b to 26a80d6 Compare September 15, 2026 07:46
@jinboson

Copy link
Copy Markdown
Contributor Author

Is this ready to merge, or is something still needed? :)

@mr-c
mr-c merged commit 72abe1e into simd-everywhere:master Sep 16, 2026
146 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants