From 083b7f6b28fe6e2d09b12be2080e58dc725624f3 Mon Sep 17 00:00:00 2001 From: CarolineConcatto Date: Tue, 20 Oct 2026 13:57:09 +0000 Subject: [PATCH] Add ACLE intrinsics for non-temporal and unprivileged pair loads/stores Add ACLE intrinsics for: LDTNP[1]/STTNP[2] unprivileged non-temporal pairs. These instructions require FEAT_LSUI. The 128-bit instruction forms are proposed using Neon vector types because there are no scalar arithmetic instructions with a 128-bit scalar data type. A scalar 128-bit floating-point type is not consistently available across AArch64 targets. For example, long double is 64-bit on Darwin and Windows AArch64 targets. References: [1]https://support.arm.com/documentation/ddi0602/2026-09/SIMD-FP-Instructions/STTP--SIMD-FP---Store-unprivileged-pair-of-SIMD-FP-registers-?lang=en [2]https://support.arm.com/documentation/ddi0602/2026-09/SIMD-FP-Instructions/STTNP--SIMD-FP---Store-unprivileged-pair-of-SIMD-FP-registers--with-non-temporal-hint-?lang=en --- neon_intrinsics/advsimd.md | 40 +++++++++++++++++++ neon_intrinsics/advsimd.template.md | 1 + tools/intrinsic_db/advsimd.csv | 27 +++++++++++++ tools/intrinsic_db/advsimd_classification.csv | 26 ++++++++++++ 4 files changed, 94 insertions(+) diff --git a/neon_intrinsics/advsimd.md b/neon_intrinsics/advsimd.md index b44f4769..62db9e5b 100644 --- a/neon_intrinsics/advsimd.md +++ b/neon_intrinsics/advsimd.md @@ -118,6 +118,7 @@ See [Changelog for year 2026](#changelog-for-year-2026). ### Changelog for year 2026 +* Added proposed support for FEAT_LSUI LDTNP/STTNP intrinsics. * Added support for FEAT_F16F32DOT * Added support for FEAT_F16F32MM and FEAT_F16MM * Renamed vmmlaq_f16_f16 to vmmlaq_f16 @@ -3829,6 +3830,27 @@ The intrinsics in this section are guarded by the macro ``__ARM_NEON``. ### Load + +#### Unprivileged pair with non-temporal hint + + +| Intrinsic | Argument preparation | AArch64 Instruction | Result | Supported architectures | +|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------|---------------------------------------------------------------------------------------------------------------------|---------------------------| +| int8x16x2_t vldtnq_s8_x2(
     int8_t const *ptr)
| `ptr -> Xn` | `LDTNP Qt1,Qt2,[Xn]` | `Qt1/Qt2 -> result.val[0]/result.val[1]` | `A64` | +| int16x8x2_t vldtnq_s16_x2(
     int16_t const *ptr)
| `ptr -> Xn` | `LDTNP Qt1,Qt2,[Xn]` | `Qt1/Qt2 -> result.val[0]/result.val[1]` | `A64` | +| int32x4x2_t vldtnq_s32_x2(
     int32_t const *ptr)
| `ptr -> Xn` | `LDTNP Qt1,Qt2,[Xn]` | `Qt1/Qt2 -> result.val[0]/result.val[1]` | `A64` | +| int64x2x2_t vldtnq_s64_x2(
     int64_t const *ptr)
| `ptr -> Xn` | `LDTNP Qt1,Qt2,[Xn]` | `Qt1/Qt2 -> result.val[0]/result.val[1]` | `A64` | +| uint8x16x2_t vldtnq_u8_x2(
     uint8_t const *ptr)
| `ptr -> Xn` | `LDTNP Qt1,Qt2,[Xn]` | `Qt1/Qt2 -> result.val[0]/result.val[1]` | `A64` | +| uint16x8x2_t vldtnq_u16_x2(
     uint16_t const *ptr)
| `ptr -> Xn` | `LDTNP Qt1,Qt2,[Xn]` | `Qt1/Qt2 -> result.val[0]/result.val[1]` | `A64` | +| uint32x4x2_t vldtnq_u32_x2(
     uint32_t const *ptr)
| `ptr -> Xn` | `LDTNP Qt1,Qt2,[Xn]` | `Qt1/Qt2 -> result.val[0]/result.val[1]` | `A64` | +| uint64x2x2_t vldtnq_u64_x2(
     uint64_t const *ptr)
| `ptr -> Xn` | `LDTNP Qt1,Qt2,[Xn]` | `Qt1/Qt2 -> result.val[0]/result.val[1]` | `A64` | +| float16x8x2_t vldtnq_f16_x2(
     float16_t const *ptr)
| `ptr -> Xn` | `LDTNP Qt1,Qt2,[Xn]` | `Qt1/Qt2 -> result.val[0]/result.val[1]` | `A64` | +| bfloat16x8x2_t vldtnq_bf16_x2(
     bfloat16_t const *ptr)
| `ptr -> Xn` | `LDTNP Qt1,Qt2,[Xn]` | `Qt1/Qt2 -> result.val[0]/result.val[1]` | `A64` | +| float32x4x2_t vldtnq_f32_x2(
     float32_t const *ptr)
| `ptr -> Xn` | `LDTNP Qt1,Qt2,[Xn]` | `Qt1/Qt2 -> result.val[0]/result.val[1]` | `A64` | +| float64x2x2_t vldtnq_f64_x2(
     float64_t const *ptr)
| `ptr -> Xn` | `LDTNP Qt1,Qt2,[Xn]` | `Qt1/Qt2 -> result.val[0]/result.val[1]` | `A64` | +| mfloat8x16x2_t vldtnq_mf8_x2(
     mfloat8_t const *ptr)
| `ptr -> Xn` | `LDTNP Qt1,Qt2,[Xn]` | `Qt1/Qt2 -> result.val[0]/result.val[1]` | `A64` | + + #### Stride | Intrinsic | Argument preparation | AArch64 Instruction | Result | Supported architectures | @@ -4308,6 +4330,24 @@ The intrinsics in this section are guarded by the macro ``__ARM_NEON``. ### Store +#### Unprivileged pair with non-temporal hint + +| Intrinsic | Argument preparation | AArch64 Instruction | Result | Supported architectures | +|-----------|----------------------|---------------------|--------|-------------------------| +| void vsttnq_s8_x2(
     int8_t *ptr,
     int8x16x2_t val)
| `val.val[0]/val.val[1] -> Qt1/Qt2`
`ptr -> Xn` | `STTNP Qt1,Qt2,[Xn]` | | `A64` | +| void vsttnq_s16_x2(
     int16_t *ptr,
     int16x8x2_t val)
| `val.val[0]/val.val[1] -> Qt1/Qt2`
`ptr -> Xn` | `STTNP Qt1,Qt2,[Xn]` | | `A64` | +| void vsttnq_s32_x2(
     int32_t *ptr,
     int32x4x2_t val)
| `val.val[0]/val.val[1] -> Qt1/Qt2`
`ptr -> Xn` | `STTNP Qt1,Qt2,[Xn]` | | `A64` | +| void vsttnq_s64_x2(
     int64_t *ptr,
     int64x2x2_t val)
| `val.val[0]/val.val[1] -> Qt1/Qt2`
`ptr -> Xn` | `STTNP Qt1,Qt2,[Xn]` | | `A64` | +| void vsttnq_u8_x2(
     uint8_t *ptr,
     uint8x16x2_t val)
| `val.val[0]/val.val[1] -> Qt1/Qt2`
`ptr -> Xn` | `STTNP Qt1,Qt2,[Xn]` | | `A64` | +| void vsttnq_u16_x2(
     uint16_t *ptr,
     uint16x8x2_t val)
| `val.val[0]/val.val[1] -> Qt1/Qt2`
`ptr -> Xn` | `STTNP Qt1,Qt2,[Xn]` | | `A64` | +| void vsttnq_u32_x2(
     uint32_t *ptr,
     uint32x4x2_t val)
| `val.val[0]/val.val[1] -> Qt1/Qt2`
`ptr -> Xn` | `STTNP Qt1,Qt2,[Xn]` | | `A64` | +| void vsttnq_u64_x2(
     uint64_t *ptr,
     uint64x2x2_t val)
| `val.val[0]/val.val[1] -> Qt1/Qt2`
`ptr -> Xn` | `STTNP Qt1,Qt2,[Xn]` | | `A64` | +| void vsttnq_f16_x2(
     float16_t *ptr,
     float16x8x2_t val)
| `val.val[0]/val.val[1] -> Qt1/Qt2`
`ptr -> Xn` | `STTNP Qt1,Qt2,[Xn]` | | `A64` | +| void vsttnq_bf16_x2(
     bfloat16_t *ptr,
     bfloat16x8x2_t val)
| `val.val[0]/val.val[1] -> Qt1/Qt2`
`ptr -> Xn` | `STTNP Qt1,Qt2,[Xn]` | | `A64` | +| void vsttnq_f32_x2(
     float32_t *ptr,
     float32x4x2_t val)
| `val.val[0]/val.val[1] -> Qt1/Qt2`
`ptr -> Xn` | `STTNP Qt1,Qt2,[Xn]` | | `A64` | +| void vsttnq_f64_x2(
     float64_t *ptr,
     float64x2x2_t val)
| `val.val[0]/val.val[1] -> Qt1/Qt2`
`ptr -> Xn` | `STTNP Qt1,Qt2,[Xn]` | | `A64` | +| void vsttnq_mf8_x2(
     mfloat8_t *ptr,
     mfloat8x16x2_t val)
| `val.val[0]/val.val[1] -> Qt1/Qt2`
`ptr -> Xn` | `STTNP Qt1,Qt2,[Xn]` | | `A64` | + #### Stride | Intrinsic | Argument preparation | AArch64 Instruction | Result | Supported architectures | diff --git a/neon_intrinsics/advsimd.template.md b/neon_intrinsics/advsimd.template.md index 45fee375..76627147 100644 --- a/neon_intrinsics/advsimd.template.md +++ b/neon_intrinsics/advsimd.template.md @@ -118,6 +118,7 @@ See [Changelog for year 2026](#changelog-for-year-2026). ### Changelog for year 2026 +* Added proposed support for FEAT_LSUI LDTNP/STTNP intrinsics. * Added support for FEAT_F16F32DOT * Added support for FEAT_F16F32MM and FEAT_F16MM * Renamed vmmlaq_f16_f16 to vmmlaq_f16 diff --git a/tools/intrinsic_db/advsimd.csv b/tools/intrinsic_db/advsimd.csv index d5bac768..4abc93c8 100644 --- a/tools/intrinsic_db/advsimd.csv +++ b/tools/intrinsic_db/advsimd.csv @@ -4863,3 +4863,30 @@ float32x4_t vmmlaq_f32_f16(float32x4_t r, float16x8_t a, float16x8_t b) r -> Vd.
Non-widening half-precision matrix multiply instruction. Requires the +f16mm architecture extension. float16x8_t vmmlaq_f16(float16x8_t r, float16x8_t a, float16x8_t b) r -> Vd.8H;a -> Vn.8H;b -> Vm.8H FMMLA Vd.8H, Vn.8H, Vm.8H Vd.8H -> result A64 +
Unprivileged pair with non-temporal hint +int8x16x2_t vldtnq_s8_x2(int8_t const *ptr) ptr -> Xn LDTNP Qt1,Qt2,[Xn] Qt2 -> result.val[1];Qt1 -> result.val[0] A64 +int16x8x2_t vldtnq_s16_x2(int16_t const *ptr) ptr -> Xn LDTNP Qt1,Qt2,[Xn] Qt2 -> result.val[1];Qt1 -> result.val[0] A64 +int32x4x2_t vldtnq_s32_x2(int32_t const *ptr) ptr -> Xn LDTNP Qt1,Qt2,[Xn] Qt2 -> result.val[1];Qt1 -> result.val[0] A64 +int64x2x2_t vldtnq_s64_x2(int64_t const *ptr) ptr -> Xn LDTNP Qt1,Qt2,[Xn] Qt2 -> result.val[1];Qt1 -> result.val[0] A64 +uint8x16x2_t vldtnq_u8_x2(uint8_t const *ptr) ptr -> Xn LDTNP Qt1,Qt2,[Xn] Qt2 -> result.val[1];Qt1 -> result.val[0] A64 +uint16x8x2_t vldtnq_u16_x2(uint16_t const *ptr) ptr -> Xn LDTNP Qt1,Qt2,[Xn] Qt2 -> result.val[1];Qt1 -> result.val[0] A64 +uint32x4x2_t vldtnq_u32_x2(uint32_t const *ptr) ptr -> Xn LDTNP Qt1,Qt2,[Xn] Qt2 -> result.val[1];Qt1 -> result.val[0] A64 +uint64x2x2_t vldtnq_u64_x2(uint64_t const *ptr) ptr -> Xn LDTNP Qt1,Qt2,[Xn] Qt2 -> result.val[1];Qt1 -> result.val[0] A64 +float16x8x2_t vldtnq_f16_x2(float16_t const *ptr) ptr -> Xn LDTNP Qt1,Qt2,[Xn] Qt2 -> result.val[1];Qt1 -> result.val[0] A64 +bfloat16x8x2_t vldtnq_bf16_x2(bfloat16_t const *ptr) ptr -> Xn LDTNP Qt1,Qt2,[Xn] Qt2 -> result.val[1];Qt1 -> result.val[0] A64 +float32x4x2_t vldtnq_f32_x2(float32_t const *ptr) ptr -> Xn LDTNP Qt1,Qt2,[Xn] Qt2 -> result.val[1];Qt1 -> result.val[0] A64 +float64x2x2_t vldtnq_f64_x2(float64_t const *ptr) ptr -> Xn LDTNP Qt1,Qt2,[Xn] Qt2 -> result.val[1];Qt1 -> result.val[0] A64 +mfloat8x16x2_t vldtnq_mf8_x2(mfloat8_t const *ptr) ptr -> Xn LDTNP Qt1,Qt2,[Xn] Qt2 -> result.val[1];Qt1 -> result.val[0] A64 +void vsttnq_s8_x2(int8_t *ptr, int8x16x2_t val) val.val[1] -> Qt2;val.val[0] -> Qt1;ptr -> Xn STTNP Qt1,Qt2,[Xn] A64 +void vsttnq_s16_x2(int16_t *ptr, int16x8x2_t val) val.val[1] -> Qt2;val.val[0] -> Qt1;ptr -> Xn STTNP Qt1,Qt2,[Xn] A64 +void vsttnq_s32_x2(int32_t *ptr, int32x4x2_t val) val.val[1] -> Qt2;val.val[0] -> Qt1;ptr -> Xn STTNP Qt1,Qt2,[Xn] A64 +void vsttnq_s64_x2(int64_t *ptr, int64x2x2_t val) val.val[1] -> Qt2;val.val[0] -> Qt1;ptr -> Xn STTNP Qt1,Qt2,[Xn] A64 +void vsttnq_u8_x2(uint8_t *ptr, uint8x16x2_t val) val.val[1] -> Qt2;val.val[0] -> Qt1;ptr -> Xn STTNP Qt1,Qt2,[Xn] A64 +void vsttnq_u16_x2(uint16_t *ptr, uint16x8x2_t val) val.val[1] -> Qt2;val.val[0] -> Qt1;ptr -> Xn STTNP Qt1,Qt2,[Xn] A64 +void vsttnq_u32_x2(uint32_t *ptr, uint32x4x2_t val) val.val[1] -> Qt2;val.val[0] -> Qt1;ptr -> Xn STTNP Qt1,Qt2,[Xn] A64 +void vsttnq_u64_x2(uint64_t *ptr, uint64x2x2_t val) val.val[1] -> Qt2;val.val[0] -> Qt1;ptr -> Xn STTNP Qt1,Qt2,[Xn] A64 +void vsttnq_f16_x2(float16_t *ptr, float16x8x2_t val) val.val[1] -> Qt2;val.val[0] -> Qt1;ptr -> Xn STTNP Qt1,Qt2,[Xn] A64 +void vsttnq_bf16_x2(bfloat16_t *ptr, bfloat16x8x2_t val) val.val[1] -> Qt2;val.val[0] -> Qt1;ptr -> Xn STTNP Qt1,Qt2,[Xn] A64 +void vsttnq_f32_x2(float32_t *ptr, float32x4x2_t val) val.val[1] -> Qt2;val.val[0] -> Qt1;ptr -> Xn STTNP Qt1,Qt2,[Xn] A64 +void vsttnq_f64_x2(float64_t *ptr, float64x2x2_t val) val.val[1] -> Qt2;val.val[0] -> Qt1;ptr -> Xn STTNP Qt1,Qt2,[Xn] A64 +void vsttnq_mf8_x2(mfloat8_t *ptr, mfloat8x16x2_t val) val.val[1] -> Qt2;val.val[0] -> Qt1;ptr -> Xn STTNP Qt1,Qt2,[Xn] A64 diff --git a/tools/intrinsic_db/advsimd_classification.csv b/tools/intrinsic_db/advsimd_classification.csv index 312f9b05..6b301d3d 100644 --- a/tools/intrinsic_db/advsimd_classification.csv +++ b/tools/intrinsic_db/advsimd_classification.csv @@ -4745,3 +4745,29 @@ vdot_laneq_f32_f16 Vector arithmetic|Dot product vdotq_lane_f32_f16 Vector arithmetic|Dot product vmmlaq_f32_f16 Vector arithmetic|Matrix multiply vmmlaq_f16 Vector arithmetic|Matrix multiply +vldtnq_s8_x2 Load|Stride +vldtnq_s16_x2 Load|Stride +vldtnq_s32_x2 Load|Stride +vldtnq_s64_x2 Load|Stride +vldtnq_u8_x2 Load|Stride +vldtnq_u16_x2 Load|Stride +vldtnq_u32_x2 Load|Stride +vldtnq_u64_x2 Load|Stride +vldtnq_f16_x2 Load|Stride +vldtnq_bf16_x2 Load|Stride +vldtnq_f32_x2 Load|Stride +vldtnq_f64_x2 Load|Stride +vldtnq_mf8_x2 Load|Stride +vsttnq_s8_x2 Store|Stride +vsttnq_s16_x2 Store|Stride +vsttnq_s32_x2 Store|Stride +vsttnq_s64_x2 Store|Stride +vsttnq_u8_x2 Store|Stride +vsttnq_u16_x2 Store|Stride +vsttnq_u32_x2 Store|Stride +vsttnq_u64_x2 Store|Stride +vsttnq_f16_x2 Store|Stride +vsttnq_bf16_x2 Store|Stride +vsttnq_f32_x2 Store|Stride +vsttnq_f64_x2 Store|Stride +vsttnq_mf8_x2 Store|Stride