From 5385710fa575e509abb78be7b897d471c2056c21 Mon Sep 17 00:00:00 2001 From: Alexander Zhura Date: Mon, 10 Aug 2026 20:03:54 +0300 Subject: [PATCH 01/10] Impl simd arm neon extended table lookup --- core/simd/arm/neon.odin | 582 +++++++++++++++++++++++++++++++++++++++ core/simd/arm/pmull.odin | 334 ++++++++++++++++++++++ 2 files changed, 916 insertions(+) diff --git a/core/simd/arm/neon.odin b/core/simd/arm/neon.odin index e89caff64..33713d128 100644 --- a/core/simd/arm/neon.odin +++ b/core/simd/arm/neon.odin @@ -822,6 +822,172 @@ vtbl4_u8 :: #force_inline proc "c" (t: uint8x8x4_t, idx: uint8x8_t) -> uint8x8_t } } +// Extended Table Lookup. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtbx1_s8) +@(require_results, enable_target_feature = "neon") +vtbx1_s8 :: #force_inline proc "c" (v: int8x8_t, t: int8x8_t, idx: int8x8_t) -> int8x8_t { + when ODIN_ARCH == .arm64 { + return simd.select( + simd.lanes_lt(idx, int8x8_t(8)), + vqtbx1_s8(v, vcombine_s8(t, int8x8_t{}), transmute(uint8x8_t)idx), + v, + ) + } else { + return _vtbx1(v, t, idx) + } +} + +// Extended Table Lookup. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtbx1_u8) +@(require_results, enable_target_feature = "neon") +vtbx1_u8 :: #force_inline proc "c" (v: uint8x8_t, t: uint8x8_t, idx: uint8x8_t) -> uint8x8_t { + when ODIN_ARCH == .arm64 { + return simd.select( + simd.lanes_lt(idx, uint8x8_t(8)), + vqtbx1_u8(v, vcombine_u8(t, uint8x8_t{}), idx), + v, + ) + } else { + return transmute(uint8x8_t)_vtbx1( + transmute(int8x8_t)v, + transmute(int8x8_t)t, + transmute(int8x8_t)idx, + ) + } +} + +// Extended Table Lookup. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtbx2_s8) +@(require_results, enable_target_feature = "neon") +vtbx2_s8 :: #force_inline proc "c" (v: int8x8_t, t: int8x8x2_t, idx: int8x8_t) -> int8x8_t { + when ODIN_ARCH == .arm64 { + return simd.select( + simd.lanes_lt(idx, int8x8_t(16)), + vqtbx1_s8(v, vcombine_s8(t.x, t.y), transmute(uint8x8_t)idx), + v, + ) + } else { + return _vtbx2(v, t.x, t.y, idx) + } +} + +// Extended Table Lookup. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtbx2_u8) +@(require_results, enable_target_feature = "neon") +vtbx2_u8 :: #force_inline proc "c" (v: uint8x8_t, t: uint8x8x2_t, idx: uint8x8_t) -> uint8x8_t { + when ODIN_ARCH == .arm64 { + return simd.select( + simd.lanes_lt(idx, uint8x8_t(16)), + vqtbx1_u8(v, vcombine_u8(t.x, t.y), idx), + v, + ) + } else { + return transmute(uint8x8_t)_vtbx2( + transmute(int8x8_t)v, + transmute(int8x8_t)t.x, + transmute(int8x8_t)t.y, + transmute(int8x8_t)idx, + ) + } +} + +// Extended Table Lookup. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtbx3_s8) +@(require_results, enable_target_feature = "neon") +vtbx3_s8 :: #force_inline proc "c" (v: int8x8_t, t: int8x8x3_t, idx: int8x8_t) -> int8x8_t { + when ODIN_ARCH == .arm64 { + x := int8x16x2_t { + vcombine_s8(t.x, t.y), + vcombine_s8(t.z, int8x8_t{}), + } + return simd.select( + simd.lanes_lt(idx, int8x8_t(24)), + vqtbx2_s8(v, x, transmute(uint8x8_t)idx), + v, + ) + } else { + return _vtbx3(v, t.x, t.y, t.z, idx) + } +} + +// Extended Table Lookup. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtbx3_u8) +@(require_results, enable_target_feature = "neon") +vtbx3_u8 :: #force_inline proc "c" (v: uint8x8_t, t: uint8x8x3_t, idx: uint8x8_t) -> uint8x8_t { + when ODIN_ARCH == .arm64 { + x := uint8x16x2_t { + vcombine_u8(t.x, t.y), + vcombine_u8(t.z, uint8x8_t{}), + } + return simd.select( + simd.lanes_lt(idx, uint8x8_t(24)), + vqtbx2_u8(v, x, idx), + v, + ) + } else { + return transmute(uint8x8_t)_vtbx3( + transmute(int8x8_t)v, + transmute(int8x8_t)t.x, + transmute(int8x8_t)t.y, + transmute(int8x8_t)t.z, + transmute(int8x8_t)idx, + ) + } +} + +// Extended Table Lookup. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtbx4_s8) +@(require_results, enable_target_feature = "neon") +vtbx4_s8 :: #force_inline proc "c" (v: int8x8_t, t: int8x8x4_t, idx: int8x8_t) -> int8x8_t { + when ODIN_ARCH == .arm64 { + x := int8x16x2_t { + vcombine_s8(t.x, t.y), + vcombine_s8(t.z, t.w), + } + return simd.select( + simd.lanes_lt(idx, int8x8_t(32)), + vqtbx2_s8(v, x, transmute(uint8x8_t)idx), + v, + ) + } else { + return _vtbx4(v, t.x, t.y, t.z, t.w, idx) + } +} + +// Extended Table Lookup. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtbx4_u8) +@(require_results, enable_target_feature = "neon") +vtbx4_u8 :: #force_inline proc "c" (v: uint8x8_t, t: uint8x8x4_t, idx: uint8x8_t) -> uint8x8_t { + when ODIN_ARCH == .arm64 { + x := uint8x16x2_t { + vcombine_u8(t.x, t.y), + vcombine_u8(t.z, t.w), + } + return simd.select( + simd.lanes_lt(idx, uint8x8_t(32)), + vqtbx2_u8(v, x, idx), + v, + ) + } else { + return transmute(uint8x8_t)_vtbx4( + transmute(int8x8_t)v, + transmute(int8x8_t)t.x, + transmute(int8x8_t)t.y, + transmute(int8x8_t)t.z, + transmute(int8x8_t)t.w, + transmute(int8x8_t)idx, + ) + } +} + when ODIN_ARCH == .arm64 { // Table Lookup. // @@ -1170,6 +1336,398 @@ when ODIN_ARCH == .arm64 { return simd.shuffle(c, c, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) } } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx1_s8) + @(require_results, enable_target_feature = "neon") + vqtbx1_s8 :: #force_inline proc "c" (v: int8x8_t, t: int8x16_t, idx: uint8x8_t) -> int8x8_t { + when ODIN_ENDIAN == .Little { + return _vqtbx1(v, t, idx) + } else { + v := simd.shuffle(v, v, 7, 6, 5, 4, 3, 2, 1, 0) + t := simd.shuffle(t, t, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + idx := simd.shuffle(idx, idx, 7, 6, 5, 4, 3, 2, 1, 0) + c := _vqtbx1(v, t, idx) + return simd.shuffle(c, c, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx1_u8) + @(require_results, enable_target_feature = "neon") + vqtbx1_u8 :: #force_inline proc "c" (v: uint8x8_t, t: uint8x16_t, idx: uint8x8_t) -> uint8x8_t { + when ODIN_ENDIAN == .Little { + return transmute(uint8x8_t)_vqtbx1( + transmute(int8x8_t)v, + transmute(int8x16_t)t, + idx, + ) + } else { + v := simd.shuffle(v, v, 7, 6, 5, 4, 3, 2, 1, 0) + t := simd.shuffle(t, t, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + idx := simd.shuffle(idx, idx, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(uint8x8_t)_vqtbx1( + transmute(int8x8_t)v, + transmute(int8x16_t)t, + idx, + ) + return simd.shuffle(c, c, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx1q_s8) + @(require_results, enable_target_feature = "neon") + vqtbx1q_s8 :: #force_inline proc "c" (v: int8x16_t, t: int8x16_t, idx: uint8x16_t) -> int8x16_t { + when ODIN_ENDIAN == .Little { + return _vqtbx1q(v, t, idx) + } else { + v := simd.shuffle(v, v, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + t := simd.shuffle(t, t, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + idx := simd.shuffle(idx, idx, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + c := _vqtbx1q(v, t, idx) + return simd.shuffle(c, c, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx1q_u8) + @(require_results, enable_target_feature = "neon") + vqtbx1q_u8 :: #force_inline proc "c" (v: uint8x16_t, t: uint8x16_t, idx: uint8x16_t) -> uint8x16_t { + when ODIN_ENDIAN == .Little { + return transmute(uint8x16_t)_vqtbx1q( + transmute(int8x16_t)v, + transmute(int8x16_t)t, + idx, + ) + } else { + v := simd.shuffle(v, v, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + t := simd.shuffle(t, t, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + idx := simd.shuffle(idx, idx, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(uint8x16_t)_vqtbx1q( + transmute(int8x16_t)v, + transmute(int8x16_t)t, + idx, + ) + return simd.shuffle(c, c, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx2_s8) + @(require_results, enable_target_feature = "neon") + vqtbx2_s8 :: #force_inline proc "c" (v: int8x8_t, t: int8x16x2_t, idx: uint8x8_t) -> int8x8_t { + when ODIN_ENDIAN == .Little { + return _vqtbx2(v, t.x, t.y, idx) + } else { + v := simd.shuffle(v, v, 7, 6, 5, 4, 3, 2, 1, 0) + t := int8x16x2_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 7, 6, 5, 4, 3, 2, 1, 0) + c := _vqtbx2(v, t.x, t.y, idx) + return simd.shuffle(c, c, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx2_u8) + @(require_results, enable_target_feature = "neon") + vqtbx2_u8 :: #force_inline proc "c" (v: uint8x8_t, t: uint8x16x2_t, idx: uint8x8_t) -> uint8x8_t { + when ODIN_ENDIAN == .Little { + return transmute(uint8x8_t)_vqtbx2( + transmute(int8x8_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + idx, + ) + } else { + v := simd.shuffle(v, v, 7, 6, 5, 4, 3, 2, 1, 0) + t := uint8x16x2_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(uint8x8_t)_vqtbx2( + transmute(int8x8_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + idx, + ) + return simd.shuffle(c, c, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx2q_s8) + @(require_results, enable_target_feature = "neon") + vqtbx2q_s8 :: #force_inline proc "c" (v: int8x16_t, t: int8x16x2_t, idx: uint8x16_t) -> int8x16_t { + when ODIN_ENDIAN == .Little { + return _vqtbx2q(v, t.x, t.y, idx) + } else { + v := simd.shuffle(v, v, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + t := int8x16x2_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + c := _vqtbx2q(v, t.x, t.y, idx) + return simd.shuffle(c, c, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx2q_u8) + @(require_results, enable_target_feature = "neon") + vqtbx2q_u8 :: #force_inline proc "c" (v: uint8x16_t, t: uint8x16x2_t, idx: uint8x16_t) -> uint8x16_t { + when ODIN_ENDIAN == .Little { + return transmute(uint8x16_t)_vqtbx2q( + transmute(int8x16_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + idx, + ) + } else { + v := simd.shuffle(v, v, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + t := uint8x16x2_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(uint8x16_t)_vqtbx2q( + transmute(int8x16_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + idx, + ) + return simd.shuffle(c, c, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx3_s8) + @(require_results, enable_target_feature = "neon") + vqtbx3_s8 :: #force_inline proc "c" (v: int8x8_t, t: int8x16x3_t, idx: uint8x8_t) -> int8x8_t { + when ODIN_ENDIAN == .Little { + return _vqtbx3(v, t.x, t.y, t.z, idx) + } else { + v := simd.shuffle(v, v, 7, 6, 5, 4, 3, 2, 1, 0) + t := int8x16x3_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.z, t.z, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 7, 6, 5, 4, 3, 2, 1, 0) + c := _vqtbx3(v, t.x, t.y, t.z, idx) + return simd.shuffle(c, c, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx3_u8) + @(require_results, enable_target_feature = "neon") + vqtbx3_u8 :: #force_inline proc "c" (v: uint8x8_t, t: uint8x16x3_t, idx: uint8x8_t) -> uint8x8_t { + when ODIN_ENDIAN == .Little { + return transmute(uint8x8_t)_vqtbx3( + transmute(int8x8_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + idx, + ) + } else { + v := simd.shuffle(v, v, 7, 6, 5, 4, 3, 2, 1, 0) + t := uint8x16x3_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.z, t.z, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(uint8x8_t)_vqtbx3( + transmute(int8x8_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + idx, + ) + return simd.shuffle(c, c, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx3q_s8) + @(require_results, enable_target_feature = "neon") + vqtbx3q_s8 :: #force_inline proc "c" (v: int8x16_t, t: int8x16x3_t, idx: uint8x16_t) -> int8x16_t { + when ODIN_ENDIAN == .Little { + return _vqtbx3q(v, t.x, t.y, t.z, idx) + } else { + v := simd.shuffle(v, v, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + t := int8x16x3_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.z, t.z, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + c := _vqtbx3q(v, t.x, t.y, t.z, idx) + return simd.shuffle(c, c, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx3q_u8) + @(require_results, enable_target_feature = "neon") + vqtbx3q_u8 :: #force_inline proc "c" (v: uint8x16_t, t: uint8x16x3_t, idx: uint8x16_t) -> uint8x16_t { + when ODIN_ENDIAN == .Little { + return transmute(uint8x16_t)_vqtbx3q( + transmute(int8x16_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + idx, + ) + } else { + v := simd.shuffle(v, v, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + t := uint8x16x3_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.z, t.z, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(uint8x16_t)_vqtbx3q( + transmute(int8x16_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + idx, + ) + return simd.shuffle(c, c, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx4_s8) + @(require_results, enable_target_feature = "neon") + vqtbx4_s8 :: #force_inline proc "c" (v: int8x8_t, t: int8x16x4_t, idx: uint8x8_t) -> int8x8_t { + when ODIN_ENDIAN == .Little { + return _vqtbx4(v, t.x, t.y, t.z, t.w, idx) + } else { + v := simd.shuffle(v, v, 7, 6, 5, 4, 3, 2, 1, 0) + t := int8x16x4_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.z, t.z, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.w, t.w, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 7, 6, 5, 4, 3, 2, 1, 0) + c := _vqtbx4(v, t.x, t.y, t.z, t.w, idx) + return simd.shuffle(c, c, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx4_u8) + @(require_results, enable_target_feature = "neon") + vqtbx4_u8 :: #force_inline proc "c" (v: uint8x8_t, t: uint8x16x4_t, idx: uint8x8_t) -> uint8x8_t { + when ODIN_ENDIAN == .Little { + return transmute(uint8x8_t)_vqtbx4( + transmute(int8x8_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + transmute(int8x16_t)t.w, + idx, + ) + } else { + v := simd.shuffle(v, v, 7, 6, 5, 4, 3, 2, 1, 0) + t := uint8x16x4_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.z, t.z, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.w, t.w, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(uint8x8_t)_vqtbx4( + transmute(int8x8_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + transmute(int8x16_t)t.w, + idx, + ) + return simd.shuffle(c, c, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx4q_s8) + @(require_results, enable_target_feature = "neon") + vqtbx4q_s8 :: #force_inline proc "c" (v: int8x16_t, t: int8x16x4_t, idx: uint8x16_t) -> int8x16_t { + when ODIN_ENDIAN == .Little { + return _vqtbx4q(v, t.x, t.y, t.z, t.w, idx) + } else { + v := simd.shuffle(v, v, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + t := int8x16x4_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.z, t.z, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.w, t.w, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + c := _vqtbx4q(v, t.x, t.y, t.z, t.w, idx) + return simd.shuffle(c, c, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx4q_u8) + @(require_results, enable_target_feature = "neon") + vqtbx4q_u8 :: #force_inline proc "c" (v: uint8x16_t, t: uint8x16x4_t, idx: uint8x16_t) -> uint8x16_t { + when ODIN_ENDIAN == .Little { + return transmute(uint8x16_t)_vqtbx4q( + transmute(int8x16_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + transmute(int8x16_t)t.w, + idx, + ) + } else { + v := simd.shuffle(v, v, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + t := uint8x16x4_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.z, t.z, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.w, t.w, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(uint8x16_t)_vqtbx4q( + transmute(int8x16_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + transmute(int8x16_t)t.w, + idx, + ) + return simd.shuffle(c, c, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + } + } } @(private, default_calling_convention = "none") @@ -1199,6 +1757,14 @@ when ODIN_ARCH == .arm32 { _vtbl3 :: proc(t0, t1, t2: int8x8_t, idx: int8x8_t) -> int8x8_t --- @(link_name = "llvm.arm.neon.vtbl4") _vtbl4 :: proc(t0, t1, t2, t3: int8x8_t, idx: int8x8_t) -> int8x8_t --- + @(link_name = "llvm.arm.neon.vtbx1") + _vtbx1 :: proc(v: int8x8_t, t: int8x8_t, idx: int8x8_t) -> int8x8_t --- + @(link_name = "llvm.arm.neon.vtbx2") + _vtbx2 :: proc(v: int8x8_t, t0, t1: int8x8_t, idx: int8x8_t) -> int8x8_t --- + @(link_name = "llvm.arm.neon.vtbx3") + _vtbx3 :: proc(v: int8x8_t, t0, t1, t2: int8x8_t, idx: int8x8_t) -> int8x8_t --- + @(link_name = "llvm.arm.neon.vtbx4") + _vtbx4 :: proc(v: int8x8_t, t0, t1, t2, t3: int8x8_t, idx: int8x8_t) -> int8x8_t --- } } @@ -1221,5 +1787,21 @@ when ODIN_ARCH == .arm64 { _vqtbl4 :: proc(t0, t1, t2, t3: int8x16_t, idx: uint8x8_t) -> int8x8_t --- @(link_name = "llvm.aarch64.neon.tbl4.v16i8") _vqtbl4q :: proc(t0, t1, t2, t3: int8x16_t, idx: uint8x16_t) -> int8x16_t --- + @(link_name = "llvm.aarch64.neon.tbx1.v8i8") + _vqtbx1 :: proc(v: int8x8_t, t: int8x16_t, idx: uint8x8_t) -> int8x8_t --- + @(link_name = "llvm.aarch64.neon.tbx1.v16i8") + _vqtbx1q :: proc(v: int8x16_t, t: int8x16_t, idx: uint8x16_t) -> int8x16_t --- + @(link_name = "llvm.aarch64.neon.tbx2.v8i8") + _vqtbx2 :: proc(v: int8x8_t, t0, t1: int8x16_t, idx: uint8x8_t) -> int8x8_t --- + @(link_name = "llvm.aarch64.neon.tbx2.v16i8") + _vqtbx2q :: proc(v: int8x16_t, t0, t1: int8x16_t, idx: uint8x16_t) -> int8x16_t --- + @(link_name = "llvm.aarch64.neon.tbx3.v8i8") + _vqtbx3 :: proc(v: int8x8_t, t0, t1, t2: int8x16_t, idx: uint8x8_t) -> int8x8_t --- + @(link_name = "llvm.aarch64.neon.tbx3.v16i8") + _vqtbx3q :: proc(v: int8x16_t, t0, t1, t2: int8x16_t, idx: uint8x16_t) -> int8x16_t --- + @(link_name = "llvm.aarch64.neon.tbx4.v8i8") + _vqtbx4 :: proc(v: int8x8_t, t0, t1, t2, t3: int8x16_t, idx: uint8x8_t) -> int8x8_t --- + @(link_name = "llvm.aarch64.neon.tbx4.v16i8") + _vqtbx4q :: proc(v: int8x16_t, t0, t1, t2, t3: int8x16_t, idx: uint8x16_t) -> int8x16_t --- } } diff --git a/core/simd/arm/pmull.odin b/core/simd/arm/pmull.odin index 56053503f..b2baa85db 100644 --- a/core/simd/arm/pmull.odin +++ b/core/simd/arm/pmull.odin @@ -502,6 +502,100 @@ vtbl4_p8 :: #force_inline proc "c" (t: poly8x8x4_t, idx: poly8x8_t) -> poly8x8_t } } +// Extended Table Lookup. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtbx1_p8) +@(require_results, enable_target_feature = "neon") +vtbx1_p8 :: #force_inline proc "c" (v: poly8x8_t, t: poly8x8_t, idx: uint8x8_t) -> poly8x8_t { + when ODIN_ARCH == .arm64 { + return simd.select( + simd.lanes_lt(idx, uint8x8_t(8)), + vqtbx1_p8(v, vcombine_p8(t, poly8x8_t{}), idx), + v, + ) + } else { + return transmute(poly8x8_t)_vtbx1( + transmute(int8x8_t)v, + transmute(int8x8_t)t, + transmute(int8x8_t)idx, + ) + } +} + +// Extended Table Lookup. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtbx2_p8) +@(require_results, enable_target_feature = "neon") +vtbx2_p8 :: #force_inline proc "c" (v: poly8x8_t, t: poly8x8x2_t, idx: uint8x8_t) -> poly8x8_t { + when ODIN_ARCH == .arm64 { + return simd.select( + simd.lanes_lt(idx, uint8x8_t(16)), + vqtbx1_p8(v, vcombine_p8(t.x, t.y), idx), + v, + ) + } else { + return transmute(poly8x8_t)_vtbx2( + transmute(int8x8_t)v, + transmute(int8x8_t)t.x, + transmute(int8x8_t)t.y, + transmute(int8x8_t)idx, + ) + } +} + +// Extended Table Lookup. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtbx3_p8) +@(require_results, enable_target_feature = "neon") +vtbx3_p8 :: #force_inline proc "c" (v: poly8x8_t, t: poly8x8x3_t, idx: uint8x8_t) -> poly8x8_t { + when ODIN_ARCH == .arm64 { + x := poly8x16x2_t { + vcombine_p8(t.x, t.y), + vcombine_p8(t.z, poly8x8_t{}), + } + return simd.select( + simd.lanes_lt(idx, uint8x8_t(24)), + vqtbx2_p8(v, x, idx), + v, + ) + } else { + return transmute(poly8x8_t)_vtbx3( + transmute(int8x8_t)v, + transmute(int8x8_t)t.x, + transmute(int8x8_t)t.y, + transmute(int8x8_t)t.z, + transmute(int8x8_t)idx, + ) + } +} + +// Extended Table Lookup. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vtbx4_p8) +@(require_results, enable_target_feature = "neon") +vtbx4_p8 :: #force_inline proc "c" (v: poly8x8_t, t: poly8x8x4_t, idx: uint8x8_t) -> poly8x8_t { + when ODIN_ARCH == .arm64 { + x := poly8x16x2_t { + vcombine_p8(t.x, t.y), + vcombine_p8(t.z, t.w), + } + return simd.select( + simd.lanes_lt(idx, uint8x8_t(32)), + vqtbx2_p8(v, x, idx), + v, + ) + } else { + return transmute(poly8x8_t)_vtbx4( + transmute(int8x8_t)v, + transmute(int8x8_t)t.x, + transmute(int8x8_t)t.y, + transmute(int8x8_t)t.z, + transmute(int8x8_t)t.w, + transmute(int8x8_t)idx, + ) + } +} + when ODIN_ARCH == .arm64 { // Polynomial multiply long // @@ -732,6 +826,246 @@ when ODIN_ARCH == .arm64 { return simd.shuffle(c, c, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) } } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx1_p8) + @(require_results, enable_target_feature = "neon") + vqtbx1_p8 :: #force_inline proc "c" (v: poly8x8_t, t: poly8x16_t, idx: uint8x8_t) -> poly8x8_t { + when ODIN_ENDIAN == .Little { + return transmute(poly8x8_t)_vqtbx1( + transmute(int8x8_t)v, + transmute(int8x16_t)t, + idx, + ) + } else { + v := simd.shuffle(v, v, 7, 6, 5, 4, 3, 2, 1, 0) + t := simd.shuffle(t, t, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + idx := simd.shuffle(idx, idx, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(poly8x8_t)_vqtbx1( + transmute(int8x8_t)v, + transmute(int8x16_t)t, + idx, + ) + return simd.shuffle(c, c, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx1q_p8) + @(require_results, enable_target_feature = "neon") + vqtbx1q_p8 :: #force_inline proc "c" (v: poly8x16_t, t: poly8x16_t, idx: uint8x16_t) -> poly8x16_t { + when ODIN_ENDIAN == .Little { + return transmute(poly8x16_t)_vqtbx1q( + transmute(int8x16_t)v, + transmute(int8x16_t)t, + idx, + ) + } else { + v := simd.shuffle(v, v, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + t := simd.shuffle(t, t, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + idx := simd.shuffle(idx, idx, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(poly8x16_t)_vqtbx1q( + transmute(int8x16_t)v, + transmute(int8x16_t)t, + idx, + ) + return simd.shuffle(c, c, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx2_p8) + @(require_results, enable_target_feature = "neon") + vqtbx2_p8 :: #force_inline proc "c" (v: poly8x8_t, t: poly8x16x2_t, idx: uint8x8_t) -> poly8x8_t { + when ODIN_ENDIAN == .Little { + return transmute(poly8x8_t)_vqtbx2( + transmute(int8x8_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + idx, + ) + } else { + v := simd.shuffle(v, v, 7, 6, 5, 4, 3, 2, 1, 0) + t := poly8x16x2_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(poly8x8_t)_vqtbx2( + transmute(int8x8_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + idx, + ) + return simd.shuffle(c, c, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx2q_p8) + @(require_results, enable_target_feature = "neon") + vqtbx2q_p8 :: #force_inline proc "c" (v: poly8x16_t, t: poly8x16x2_t, idx: uint8x16_t) -> poly8x16_t { + when ODIN_ENDIAN == .Little { + return transmute(poly8x16_t)_vqtbx2q( + transmute(int8x16_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + idx, + ) + } else { + v := simd.shuffle(v, v, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + t := poly8x16x2_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(poly8x16_t)_vqtbx2q( + transmute(int8x16_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + idx, + ) + return simd.shuffle(c, c, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx3_p8) + @(require_results, enable_target_feature = "neon") + vqtbx3_p8 :: #force_inline proc "c" (v: poly8x8_t, t: poly8x16x3_t, idx: uint8x8_t) -> poly8x8_t { + when ODIN_ENDIAN == .Little { + return transmute(poly8x8_t)_vqtbx3( + transmute(int8x8_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + idx, + ) + } else { + v := simd.shuffle(v, v, 7, 6, 5, 4, 3, 2, 1, 0) + t := poly8x16x3_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.z, t.z, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(poly8x8_t)_vqtbx3( + transmute(int8x8_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + idx, + ) + return simd.shuffle(c, c, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx3q_p8) + @(require_results, enable_target_feature = "neon") + vqtbx3q_p8 :: #force_inline proc "c" (v: poly8x16_t, t: poly8x16x3_t, idx: uint8x16_t) -> poly8x16_t { + when ODIN_ENDIAN == .Little { + return transmute(poly8x16_t)_vqtbx3q( + transmute(int8x16_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + idx, + ) + } else { + v := simd.shuffle(v, v, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + t := poly8x16x3_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.z, t.z, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(poly8x16_t)_vqtbx3q( + transmute(int8x16_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + idx, + ) + return simd.shuffle(c, c, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx4_p8) + @(require_results, enable_target_feature = "neon") + vqtbx4_p8 :: #force_inline proc "c" (v: poly8x8_t, t: poly8x16x4_t, idx: uint8x8_t) -> poly8x8_t { + when ODIN_ENDIAN == .Little { + return transmute(poly8x8_t)_vqtbx4( + transmute(int8x8_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + transmute(int8x16_t)t.w, + idx, + ) + } else { + v := simd.shuffle(v, v, 7, 6, 5, 4, 3, 2, 1, 0) + t := poly8x16x4_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.z, t.z, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.w, t.w, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(poly8x8_t)_vqtbx4( + transmute(int8x8_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + transmute(int8x16_t)t.w, + idx, + ) + return simd.shuffle(c, c, 7, 6, 5, 4, 3, 2, 1, 0) + } + } + + // Extended Table Lookup. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqtbx4q_p8) + @(require_results, enable_target_feature = "neon") + vqtbx4q_p8 :: #force_inline proc "c" (v: poly8x16_t, t: poly8x16x4_t, idx: uint8x16_t) -> poly8x16_t { + when ODIN_ENDIAN == .Little { + return transmute(poly8x16_t)_vqtbx4q( + transmute(int8x16_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + transmute(int8x16_t)t.w, + idx, + ) + } else { + v := simd.shuffle(v, v, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + t := poly8x16x4_t { + simd.shuffle(t.x, t.x, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.y, t.y, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.z, t.z, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + simd.shuffle(t.w, t.w, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), + } + idx := simd.shuffle(idx, idx, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + c := transmute(poly8x16_t)_vqtbx4q( + transmute(int8x16_t)v, + transmute(int8x16_t)t.x, + transmute(int8x16_t)t.y, + transmute(int8x16_t)t.z, + transmute(int8x16_t)t.w, + idx, + ) + return simd.shuffle(c, c, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) + } + } } @(private, default_calling_convention = "none") From 939802e713db92090916f0a6b7e7c0d3fc7d714b Mon Sep 17 00:00:00 2001 From: kalsprite Date: Wed, 12 Aug 2026 19:23:41 -0700 Subject: [PATCH 02/10] fix bitfield intrinsic --- src/types.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/types.cpp b/src/types.cpp index 13d335348..e9ac4260c 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1446,11 +1446,13 @@ gb_internal bool is_type_ordered(Type *t) { return false; } gb_internal bool is_type_ordered_numeric(Type *t) { - t = core_type(t); + t = base_type(t); if (t == nullptr) { return false; } switch (t->kind) { case Type_Basic: return (t->Basic.flags & BasicFlag_OrderedNumeric) != 0; + case Type_Enum: + return is_type_ordered_numeric(t->Enum.base_type); } return false; } From 02adbc11e33673c6ca531d14db79b482d608d3c0 Mon Sep 17 00:00:00 2001 From: FourteenBrush <74827262+FourteenBrush@users.noreply.github.com> Date: Thu, 13 Aug 2026 12:51:42 +0200 Subject: [PATCH 03/10] Fix oob for zero arg `#load_directory` --- src/check_builtin.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 4a59a59b7..84406c423 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2244,7 +2244,10 @@ gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c String name = bd->name.string; GB_ASSERT(name == "load_directory"); - if (ce->args.count != 1) { + if (ce->args.count == 0) { + error(ce->close, "'#%.*s' expects 1 argument, got 0", LIT(name)); + return LoadDirective_Error; + } else if (ce->args.count != 1) { error(ce->args[0], "'#%.*s' expects 1 argument, got %td", LIT(name), ce->args.count); return LoadDirective_Error; } From ac7110e098a38c003c0c3d780069a5ff76f3cc73 Mon Sep 17 00:00:00 2001 From: diego Date: Fri, 14 Aug 2026 13:21:03 +0200 Subject: [PATCH 04/10] Remove unused variable in fixed-point write procedure --- core/math/fixed/fixed.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/math/fixed/fixed.odin b/core/math/fixed/fixed.odin index 6b9ef364b..65d7af772 100644 --- a/core/math/fixed/fixed.odin +++ b/core/math/fixed/fixed.odin @@ -148,7 +148,7 @@ write :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string { } } - n := copy(dst, buf[:i]) + copy(dst, buf[:i]) return string(dst[:i]) } From 64a5887f831833be334833c146351f15c27275fa Mon Sep 17 00:00:00 2001 From: Alexander Zhura Date: Fri, 14 Aug 2026 22:01:59 +0300 Subject: [PATCH 05/10] Impl simd arm neon logical --- core/simd/arm/neon.odin | 962 ++++++++++++++++++++++++++++++++++++++- core/simd/arm/pmull.odin | 34 ++ 2 files changed, 980 insertions(+), 16 deletions(-) diff --git a/core/simd/arm/neon.odin b/core/simd/arm/neon.odin index 33713d128..17f0f2fa9 100644 --- a/core/simd/arm/neon.odin +++ b/core/simd/arm/neon.odin @@ -211,14 +211,6 @@ vcnt_u8 :: #force_inline proc "c" (a: uint8x8_t) -> uint8x8_t { return transmute(uint8x8_t)vcnt_s8(transmute(int8x8_t)a) } -// Population count per byte. -// -// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcnt_p8) -@(require_results, enable_target_feature = "neon") -vcnt_p8 :: #force_inline proc "c" (a: poly8x8_t) -> poly8x8_t { - return transmute(poly8x8_t)vcnt_s8(transmute(int8x8_t)a) -} - // Population count per byte. // // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcntq_s8) @@ -235,14 +227,6 @@ vcntq_u8 :: #force_inline proc "c" (a: uint8x16_t) -> uint8x16_t { return transmute(uint8x16_t)vcntq_s8(transmute(int8x16_t)a) } -// Population count per byte. -// -// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcntq_p8) -@(require_results, enable_target_feature = "neon") -vcntq_p8 :: #force_inline proc "c" (a: poly8x16_t) -> poly8x16_t { - return transmute(poly8x16_t)vcntq_s8(transmute(int8x16_t)a) -} - // Vector bitwise bit clear. // // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbic_s8) @@ -988,6 +972,864 @@ vtbx4_u8 :: #force_inline proc "c" (v: uint8x8_t, t: uint8x8x4_t, idx: uint8x8_t } } +// Duplicate vector element to vector or scalar +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_n_s8) +@(require_results, enable_target_feature = "neon") +vdup_n_s8 :: #force_inline proc "c" (value: int8_t) -> int8x8_t { + return int8x8_t(value) +} + +// Duplicate vector element to vector or scalar +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_n_s16) +@(require_results, enable_target_feature = "neon") +vdup_n_s16 :: #force_inline proc "c" (value: int16_t) -> int16x4_t { + return int16x4_t(value) +} + +// Duplicate vector element to vector or scalar +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_n_s32) +@(require_results, enable_target_feature = "neon") +vdup_n_s32 :: #force_inline proc "c" (value: int32_t) -> int32x2_t { + return int32x2_t(value) +} + +// Duplicate vector element to vector or scalar +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vdup_n_s64) +@(require_results, enable_target_feature = "neon") +vdup_n_s64 :: #force_inline proc "c" (value: int64_t) -> int64x1_t { + return int64x1_t(value) +} + +// Move vector element to general-purpose register +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vget_lane_s8) +@(require_results, enable_target_feature = "neon") +vget_lane_s8 :: #force_inline proc "c" (v: int8x8_t, $LANE: int32_t) -> int8_t where 0 <= LANE, LANE < 8 { + when ODIN_ENDIAN == .Little { + return simd.extract(v, LANE) + } else { + v := simd.shuffle(v, v, 7, 6, 5, 4, 3, 2, 1, 0) + return simd.extract(v, LANE) + } +} + +// Move vector element to general-purpose register +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vget_lane_u8) +@(require_results, enable_target_feature = "neon") +vget_lane_u8 :: #force_inline proc "c" (v: uint8x8_t, $LANE: int32_t) -> uint8_t where 0 <= LANE, LANE < 8 { + when ODIN_ENDIAN == .Little { + return simd.extract(v, LANE) + } else { + v := simd.shuffle(v, v, 7, 6, 5, 4, 3, 2, 1, 0) + return simd.extract(v, LANE) + } +} + +// Move vector element to general-purpose register +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vget_lane_s16) +@(require_results, enable_target_feature = "neon") +vget_lane_s16 :: #force_inline proc "c" (v: int16x4_t, $LANE: int32_t) -> int16_t where 0 <= LANE, LANE < 4 { + when ODIN_ENDIAN == .Little { + return simd.extract(v, LANE) + } else { + v := simd.shuffle(v, v, 3, 2, 1, 0) + return simd.extract(v, LANE) + } +} + +// Move vector element to general-purpose register +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vget_lane_u16) +@(require_results, enable_target_feature = "neon") +vget_lane_u16 :: #force_inline proc "c" (v: uint16x4_t, $LANE: int32_t) -> uint16_t where 0 <= LANE, LANE < 4 { + when ODIN_ENDIAN == .Little { + return simd.extract(v, LANE) + } else { + v := simd.shuffle(v, v, 3, 2, 1, 0) + return simd.extract(v, LANE) + } +} + +// Move vector element to general-purpose register +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vget_lane_s32) +@(require_results, enable_target_feature = "neon") +vget_lane_s32 :: #force_inline proc "c" (v: int32x2_t, $LANE: int32_t) -> int32_t where 0 <= LANE, LANE < 2 { + when ODIN_ENDIAN == .Little { + return simd.extract(v, LANE) + } else { + v := simd.shuffle(v, v, 1, 0) + return simd.extract(v, LANE) + } +} + +// Move vector element to general-purpose register +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vget_lane_u32) +@(require_results, enable_target_feature = "neon") +vget_lane_u32 :: #force_inline proc "c" (v: uint32x2_t, $LANE: int32_t) -> uint32_t where 0 <= LANE, LANE < 2 { + when ODIN_ENDIAN == .Little { + return simd.extract(v, LANE) + } else { + v := simd.shuffle(v, v, 1, 0) + return simd.extract(v, LANE) + } +} + +// Move vector element to general-purpose register +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vget_lane_s64) +@(require_results, enable_target_feature = "neon") +vget_lane_s64 :: #force_inline proc "c" (v: int64x1_t, $LANE: int32_t) -> int64_t where LANE == 0 { + return simd.extract(v, LANE) +} + +// Move vector element to general-purpose register +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vget_lane_u64) +@(require_results, enable_target_feature = "neon") +vget_lane_u64 :: #force_inline proc "c" (v: uint64x1_t, $LANE: int32_t) -> uint64_t where LANE == 0 { + return simd.extract(v, LANE) +} + +// Negate. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vneg_s8) +@(require_results, enable_target_feature = "neon") +vneg_s8 :: #force_inline proc "c" (a: int8x8_t) -> int8x8_t { + return simd.neg(a) +} + +// Negate. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vnegq_s8) +@(require_results, enable_target_feature = "neon") +vnegq_s8 :: #force_inline proc "c" (a: int8x16_t) -> int8x16_t { + return simd.neg(a) +} + +// Negate. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vneg_s16) +@(require_results, enable_target_feature = "neon") +vneg_s16 :: #force_inline proc "c" (a: int16x4_t) -> int16x4_t { + return simd.neg(a) +} + +// Negate. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vnegq_s16) +@(require_results, enable_target_feature = "neon") +vnegq_s16 :: #force_inline proc "c" (a: int16x8_t) -> int16x8_t { + return simd.neg(a) +} + +// Negate. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vneg_s32) +@(require_results, enable_target_feature = "neon") +vneg_s32 :: #force_inline proc "c" (a: int32x2_t) -> int32x2_t { + return simd.neg(a) +} + +// Negate. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vnegq_s32) +@(require_results, enable_target_feature = "neon") +vnegq_s32 :: #force_inline proc "c" (a: int32x4_t) -> int32x4_t { + return simd.neg(a) +} + +// Signed saturating Negate. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqneg_s8) +@(require_results, enable_target_feature = "neon") +vqneg_s8 :: #force_inline proc "c" (a: int8x8_t) -> int8x8_t { + return _vqneg_s8(a) +} + +// Signed saturating Negate. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqneg_s16) +@(require_results, enable_target_feature = "neon") +vqneg_s16 :: #force_inline proc "c" (a: int16x4_t) -> int16x4_t { + return _vqneg_s16(a) +} + +// Signed saturating Negate. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqneg_s32) +@(require_results, enable_target_feature = "neon") +vqneg_s32 :: #force_inline proc "c" (a: int32x2_t) -> int32x2_t { + return _vqneg_s32(a) +} + +// Signed saturating Negate. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegq_s8) +@(require_results, enable_target_feature = "neon") +vqnegq_s8 :: #force_inline proc "c" (a: int8x16_t) -> int8x16_t { + return _vqnegq_s8(a) +} + +// Signed saturating Negate. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegq_s16) +@(require_results, enable_target_feature = "neon") +vqnegq_s16 :: #force_inline proc "c" (a: int16x8_t) -> int16x8_t { + return _vqnegq_s16(a) +} + +// Signed saturating Negate. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegq_s32) +@(require_results, enable_target_feature = "neon") +vqnegq_s32 :: #force_inline proc "c" (a: int32x4_t) -> int32x4_t { + return _vqnegq_s32(a) +} + +// Bitwise Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmvn_s8) +@(require_results, enable_target_feature = "neon") +vmvn_s8 :: #force_inline proc "c" (a: int8x8_t) -> int8x8_t { + b := int8x8_t(-1) + return simd.bit_xor(a, b) +} + +// Bitwise Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmvn_u8) +@(require_results, enable_target_feature = "neon") +vmvn_u8 :: #force_inline proc "c" (a: uint8x8_t) -> uint8x8_t { + b := uint8x8_t(max(uint8_t)) + return simd.bit_xor(a, b) +} + +// Bitwise Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmvn_s16) +@(require_results, enable_target_feature = "neon") +vmvn_s16 :: #force_inline proc "c" (a: int16x4_t) -> int16x4_t { + b := int16x4_t(-1) + return simd.bit_xor(a, b) +} + +// Bitwise Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmvn_u16) +@(require_results, enable_target_feature = "neon") +vmvn_u16 :: #force_inline proc "c" (a: uint16x4_t) -> uint16x4_t { + b := uint16x4_t(max(uint16_t)) + return simd.bit_xor(a, b) +} + +// Bitwise Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmvn_s32) +@(require_results, enable_target_feature = "neon") +vmvn_s32 :: #force_inline proc "c" (a: int32x2_t) -> int32x2_t { + b := int32x2_t(-1) + return simd.bit_xor(a, b) +} + +// Bitwise Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmvn_u32) +@(require_results, enable_target_feature = "neon") +vmvn_u32 :: #force_inline proc "c" (a: uint32x2_t) -> uint32x2_t { + b := uint32x2_t(max(uint32_t)) + return simd.bit_xor(a, b) +} + +// Bitwise Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmvnq_s8) +@(require_results, enable_target_feature = "neon") +vmvnq_s8 :: #force_inline proc "c" (a: int8x16_t) -> int8x16_t { + b := int8x16_t(-1) + return simd.bit_xor(a, b) +} + +// Bitwise Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmvnq_u8) +@(require_results, enable_target_feature = "neon") +vmvnq_u8 :: #force_inline proc "c" (a: uint8x16_t) -> uint8x16_t { + b := uint8x16_t(max(uint8_t)) + return simd.bit_xor(a, b) +} + +// Bitwise Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmvnq_s16) +@(require_results, enable_target_feature = "neon") +vmvnq_s16 :: #force_inline proc "c" (a: int16x8_t) -> int16x8_t { + b := int16x8_t(-1) + return simd.bit_xor(a, b) +} + +// Bitwise Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmvnq_u16) +@(require_results, enable_target_feature = "neon") +vmvnq_u16 :: #force_inline proc "c" (a: uint16x8_t) -> uint16x8_t { + b := uint16x8_t(max(uint16_t)) + return simd.bit_xor(a, b) +} + +// Bitwise Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmvnq_s32) +@(require_results, enable_target_feature = "neon") +vmvnq_s32 :: #force_inline proc "c" (a: int32x4_t) -> int32x4_t { + b := int32x4_t(-1) + return simd.bit_xor(a, b) +} + +// Bitwise Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmvnq_u32) +@(require_results, enable_target_feature = "neon") +vmvnq_u32 :: #force_inline proc "c" (a: uint32x4_t) -> uint32x4_t { + b := uint32x4_t(max(uint32_t)) + return simd.bit_xor(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_s8) +@(require_results, enable_target_feature = "neon") +vand_s8 :: #force_inline proc "c" (a, b: int8x8_t) -> int8x8_t { + return simd.bit_and(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_u8) +@(require_results, enable_target_feature = "neon") +vand_u8 :: #force_inline proc "c" (a, b: uint8x8_t) -> uint8x8_t { + return simd.bit_and(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_s16) +@(require_results, enable_target_feature = "neon") +vand_s16 :: #force_inline proc "c" (a, b: int16x4_t) -> int16x4_t { + return simd.bit_and(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_u16) +@(require_results, enable_target_feature = "neon") +vand_u16 :: #force_inline proc "c" (a, b: uint16x4_t) -> uint16x4_t { + return simd.bit_and(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_s32) +@(require_results, enable_target_feature = "neon") +vand_s32 :: #force_inline proc "c" (a, b: int32x2_t) -> int32x2_t { + return simd.bit_and(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_u32) +@(require_results, enable_target_feature = "neon") +vand_u32 :: #force_inline proc "c" (a, b: uint32x2_t) -> uint32x2_t { + return simd.bit_and(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_s64) +@(require_results, enable_target_feature = "neon") +vand_s64 :: #force_inline proc "c" (a, b: int64x1_t) -> int64x1_t { + return simd.bit_and(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vand_u64) +@(require_results, enable_target_feature = "neon") +vand_u64 :: #force_inline proc "c" (a, b: uint64x1_t) -> uint64x1_t { + return simd.bit_and(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_s8) +@(require_results, enable_target_feature = "neon") +vandq_s8 :: #force_inline proc "c" (a, b: int8x16_t) -> int8x16_t { + return simd.bit_and(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_u8) +@(require_results, enable_target_feature = "neon") +vandq_u8 :: #force_inline proc "c" (a, b: uint8x16_t) -> uint8x16_t { + return simd.bit_and(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_s16) +@(require_results, enable_target_feature = "neon") +vandq_s16 :: #force_inline proc "c" (a, b: int16x8_t) -> int16x8_t { + return simd.bit_and(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_u16) +@(require_results, enable_target_feature = "neon") +vandq_u16 :: #force_inline proc "c" (a, b: uint16x8_t) -> uint16x8_t { + return simd.bit_and(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_s32) +@(require_results, enable_target_feature = "neon") +vandq_s32 :: #force_inline proc "c" (a, b: int32x4_t) -> int32x4_t { + return simd.bit_and(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_u32) +@(require_results, enable_target_feature = "neon") +vandq_u32 :: #force_inline proc "c" (a, b: uint32x4_t) -> uint32x4_t { + return simd.bit_and(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_s64) +@(require_results, enable_target_feature = "neon") +vandq_s64 :: #force_inline proc "c" (a, b: int64x2_t) -> int64x2_t { + return simd.bit_and(a, b) +} + +// Bitwise And. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vandq_u64) +@(require_results, enable_target_feature = "neon") +vandq_u64 :: #force_inline proc "c" (a, b: uint64x2_t) -> uint64x2_t { + return simd.bit_and(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_s8) +@(require_results, enable_target_feature = "neon") +vorr_s8 :: #force_inline proc "c" (a, b: int8x8_t) -> int8x8_t { + return simd.bit_or(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_u8) +@(require_results, enable_target_feature = "neon") +vorr_u8 :: #force_inline proc "c" (a, b: uint8x8_t) -> uint8x8_t { + return simd.bit_or(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_s16) +@(require_results, enable_target_feature = "neon") +vorr_s16 :: #force_inline proc "c" (a, b: int16x4_t) -> int16x4_t { + return simd.bit_or(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_u16) +@(require_results, enable_target_feature = "neon") +vorr_u16 :: #force_inline proc "c" (a, b: uint16x4_t) -> uint16x4_t { + return simd.bit_or(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_s32) +@(require_results, enable_target_feature = "neon") +vorr_s32 :: #force_inline proc "c" (a, b: int32x2_t) -> int32x2_t { + return simd.bit_or(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_u32) +@(require_results, enable_target_feature = "neon") +vorr_u32 :: #force_inline proc "c" (a, b: uint32x2_t) -> uint32x2_t { + return simd.bit_or(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_s64) +@(require_results, enable_target_feature = "neon") +vorr_s64 :: #force_inline proc "c" (a, b: int64x1_t) -> int64x1_t { + return simd.bit_or(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorr_u64) +@(require_results, enable_target_feature = "neon") +vorr_u64 :: #force_inline proc "c" (a, b: uint64x1_t) -> uint64x1_t { + return simd.bit_or(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_s8) +@(require_results, enable_target_feature = "neon") +vorrq_s8 :: #force_inline proc "c" (a, b: int8x16_t) -> int8x16_t { + return simd.bit_or(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_u8) +@(require_results, enable_target_feature = "neon") +vorrq_u8 :: #force_inline proc "c" (a, b: uint8x16_t) -> uint8x16_t { + return simd.bit_or(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_s16) +@(require_results, enable_target_feature = "neon") +vorrq_s16 :: #force_inline proc "c" (a, b: int16x8_t) -> int16x8_t { + return simd.bit_or(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_u16) +@(require_results, enable_target_feature = "neon") +vorrq_u16 :: #force_inline proc "c" (a, b: uint16x8_t) -> uint16x8_t { + return simd.bit_or(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_s32) +@(require_results, enable_target_feature = "neon") +vorrq_s32 :: #force_inline proc "c" (a, b: int32x4_t) -> int32x4_t { + return simd.bit_or(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_u32) +@(require_results, enable_target_feature = "neon") +vorrq_u32 :: #force_inline proc "c" (a, b: uint32x4_t) -> uint32x4_t { + return simd.bit_or(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_s64) +@(require_results, enable_target_feature = "neon") +vorrq_s64 :: #force_inline proc "c" (a, b: int64x2_t) -> int64x2_t { + return simd.bit_or(a, b) +} + +// Bitwise Inclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorrq_u64) +@(require_results, enable_target_feature = "neon") +vorrq_u64 :: #force_inline proc "c" (a, b: uint64x2_t) -> uint64x2_t { + return simd.bit_or(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_s8) +@(require_results, enable_target_feature = "neon") +veor_s8 :: #force_inline proc "c" (a, b: int8x8_t) -> int8x8_t { + return simd.bit_xor(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_u8) +@(require_results, enable_target_feature = "neon") +veor_u8 :: #force_inline proc "c" (a, b: uint8x8_t) -> uint8x8_t { + return simd.bit_xor(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_s16) +@(require_results, enable_target_feature = "neon") +veor_s16 :: #force_inline proc "c" (a, b: int16x4_t) -> int16x4_t { + return simd.bit_xor(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_u16) +@(require_results, enable_target_feature = "neon") +veor_u16 :: #force_inline proc "c" (a, b: uint16x4_t) -> uint16x4_t { + return simd.bit_xor(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_s32) +@(require_results, enable_target_feature = "neon") +veor_s32 :: #force_inline proc "c" (a, b: int32x2_t) -> int32x2_t { + return simd.bit_xor(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_u32) +@(require_results, enable_target_feature = "neon") +veor_u32 :: #force_inline proc "c" (a, b: uint32x2_t) -> uint32x2_t { + return simd.bit_xor(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_s64) +@(require_results, enable_target_feature = "neon") +veor_s64 :: #force_inline proc "c" (a, b: int64x1_t) -> int64x1_t { + return simd.bit_xor(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veor_u64) +@(require_results, enable_target_feature = "neon") +veor_u64 :: #force_inline proc "c" (a, b: uint64x1_t) -> uint64x1_t { + return simd.bit_xor(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_s8) +@(require_results, enable_target_feature = "neon") +veorq_s8 :: #force_inline proc "c" (a, b: int8x16_t) -> int8x16_t { + return simd.bit_xor(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_u8) +@(require_results, enable_target_feature = "neon") +veorq_u8 :: #force_inline proc "c" (a, b: uint8x16_t) -> uint8x16_t { + return simd.bit_xor(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_s16) +@(require_results, enable_target_feature = "neon") +veorq_s16 :: #force_inline proc "c" (a, b: int16x8_t) -> int16x8_t { + return simd.bit_xor(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_u16) +@(require_results, enable_target_feature = "neon") +veorq_u16 :: #force_inline proc "c" (a, b: uint16x8_t) -> uint16x8_t { + return simd.bit_xor(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_s32) +@(require_results, enable_target_feature = "neon") +veorq_s32 :: #force_inline proc "c" (a, b: int32x4_t) -> int32x4_t { + return simd.bit_xor(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_u32) +@(require_results, enable_target_feature = "neon") +veorq_u32 :: #force_inline proc "c" (a, b: uint32x4_t) -> uint32x4_t { + return simd.bit_xor(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_s64) +@(require_results, enable_target_feature = "neon") +veorq_s64 :: #force_inline proc "c" (a, b: int64x2_t) -> int64x2_t { + return simd.bit_xor(a, b) +} + +// Bitwise Exclusive Or. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/veorq_u64) +@(require_results, enable_target_feature = "neon") +veorq_u64 :: #force_inline proc "c" (a, b: uint64x2_t) -> uint64x2_t { + return simd.bit_xor(a, b) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorn_s8) +@(require_results, enable_target_feature = "neon") +vorn_s8 :: #force_inline proc "c" (a, b: int8x8_t) -> int8x8_t { + c := int8x8_t(-1) + return simd.bit_or(simd.bit_xor(b, c), a) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorn_u8) +@(require_results, enable_target_feature = "neon") +vorn_u8 :: #force_inline proc "c" (a, b: uint8x8_t) -> uint8x8_t { + c := uint8x8_t(max(uint8_t)) + return simd.bit_or(simd.bit_xor(b, c), a) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorn_s16) +@(require_results, enable_target_feature = "neon") +vorn_s16 :: #force_inline proc "c" (a, b: int16x4_t) -> int16x4_t { + c := int16x4_t(-1) + return simd.bit_or(simd.bit_xor(b, c), a) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorn_u16) +@(require_results, enable_target_feature = "neon") +vorn_u16 :: #force_inline proc "c" (a, b: uint16x4_t) -> uint16x4_t { + c := uint16x4_t(max(uint16_t)) + return simd.bit_or(simd.bit_xor(b, c), a) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorn_s32) +@(require_results, enable_target_feature = "neon") +vorn_s32 :: #force_inline proc "c" (a, b: int32x2_t) -> int32x2_t { + c := int32x2_t(-1) + return simd.bit_or(simd.bit_xor(b, c), a) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorn_u32) +@(require_results, enable_target_feature = "neon") +vorn_u32 :: #force_inline proc "c" (a, b: uint32x2_t) -> uint32x2_t { + c := uint32x2_t(max(uint32_t)) + return simd.bit_or(simd.bit_xor(b, c), a) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorn_s64) +@(require_results, enable_target_feature = "neon") +vorn_s64 :: #force_inline proc "c" (a, b: int64x1_t) -> int64x1_t { + c := int64x1_t(-1) + return simd.bit_or(simd.bit_xor(b, c), a) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vorn_u64) +@(require_results, enable_target_feature = "neon") +vorn_u64 :: #force_inline proc "c" (a, b: uint64x1_t) -> uint64x1_t { + c := uint64x1_t(max(uint64_t)) + return simd.bit_or(simd.bit_xor(b, c), a) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vornq_s8) +@(require_results, enable_target_feature = "neon") +vornq_s8 :: #force_inline proc "c" (a, b: int8x16_t) -> int8x16_t { + c := int8x16_t(-1) + return simd.bit_or(simd.bit_xor(b, c), a) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vornq_u8) +@(require_results, enable_target_feature = "neon") +vornq_u8 :: #force_inline proc "c" (a, b: uint8x16_t) -> uint8x16_t { + c := uint8x16_t(max(uint8_t)) + return simd.bit_or(simd.bit_xor(b, c), a) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vornq_s16) +@(require_results, enable_target_feature = "neon") +vornq_s16 :: #force_inline proc "c" (a, b: int16x8_t) -> int16x8_t { + c := int16x8_t(-1) + return simd.bit_or(simd.bit_xor(b, c), a) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vornq_u16) +@(require_results, enable_target_feature = "neon") +vornq_u16 :: #force_inline proc "c" (a, b: uint16x8_t) -> uint16x8_t { + c := uint16x8_t(max(uint16_t)) + return simd.bit_or(simd.bit_xor(b, c), a) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vornq_s32) +@(require_results, enable_target_feature = "neon") +vornq_s32 :: #force_inline proc "c" (a, b: int32x4_t) -> int32x4_t { + c := int32x4_t(-1) + return simd.bit_or(simd.bit_xor(b, c), a) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vornq_u32) +@(require_results, enable_target_feature = "neon") +vornq_u32 :: #force_inline proc "c" (a, b: uint32x4_t) -> uint32x4_t { + c := uint32x4_t(max(uint32_t)) + return simd.bit_or(simd.bit_xor(b, c), a) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vornq_s64) +@(require_results, enable_target_feature = "neon") +vornq_s64 :: #force_inline proc "c" (a, b: int64x2_t) -> int64x2_t { + c := int64x2_t(-1) + return simd.bit_or(simd.bit_xor(b, c), a) +} + +// Bitwise Inclusive Or Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vornq_u64) +@(require_results, enable_target_feature = "neon") +vornq_u64 :: #force_inline proc "c" (a, b: uint64x2_t) -> uint64x2_t { + c := uint64x2_t(max(uint64_t)) + return simd.bit_or(simd.bit_xor(b, c), a) +} + when ODIN_ARCH == .arm64 { // Table Lookup. // @@ -1728,6 +2570,78 @@ when ODIN_ARCH == .arm64 { return simd.shuffle(c, c, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) } } + + // Negate. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vneg_s64) + @(require_results, enable_target_feature = "neon") + vneg_s64 :: #force_inline proc "c" (a: int64x1_t) -> int64x1_t { + return simd.neg(a) + } + + // Negate. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vnegd_s64) + @(require_results, enable_target_feature = "neon") + vnegd_s64 :: #force_inline proc "c" (a: int64_t) -> int64_t { + return -a + } + + // Negate. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vnegq_s64) + @(require_results, enable_target_feature = "neon") + vnegq_s64 :: #force_inline proc "c" (a: int64x2_t) -> int64x2_t { + return simd.neg(a) + } + + // Signed saturating Negate. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqneg_s64) + @(require_results, enable_target_feature = "neon") + vqneg_s64 :: #force_inline proc "c" (a: int64x1_t) -> int64x1_t { + return _vqneg_s64(a) + } + + // Signed saturating Negate. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegq_s64) + @(require_results, enable_target_feature = "neon") + vqnegq_s64 :: #force_inline proc "c" (a: int64x2_t) -> int64x2_t { + return _vqnegq_s64(a) + } + + // Signed saturating Negate. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegb_s8) + @(require_results, enable_target_feature = "neon") + vqnegb_s8 :: #force_inline proc "c" (a: int8_t) -> int8_t { + return vget_lane_s8(vqneg_s8(vdup_n_s8(a)), 0) + } + + // Signed saturating Negate. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegh_s16) + @(require_results, enable_target_feature = "neon") + vqnegh_s16 :: #force_inline proc "c" (a: int16_t) -> int16_t { + return vget_lane_s16(vqneg_s16(vdup_n_s16(a)), 0) + } + + // Signed saturating Negate. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegs_s32) + @(require_results, enable_target_feature = "neon") + vqnegs_s32 :: #force_inline proc "c" (a: int32_t) -> int32_t { + return vget_lane_s32(vqneg_s32(vdup_n_s32(a)), 0) + } + + // Signed saturating Negate. + // + // [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vqnegd_s64) + @(require_results, enable_target_feature = "neon") + vqnegd_s64 :: #force_inline proc "c" (a: int64_t) -> int64_t { + return vget_lane_s64(vqneg_s64(vdup_n_s64(a)), 0) + } } @(private, default_calling_convention = "none") @@ -1744,6 +2658,18 @@ foreign _ { _vclsq_s16 :: proc(a: int16x8_t) -> int16x8_t --- @(link_name = "llvm.aarch64.neon.cls.v4i32" when ODIN_ARCH == .arm64 else "llvm.arm.neon.vcls.v4i32") _vclsq_s32 :: proc(a: int32x4_t) -> int32x4_t --- + @(link_name = "llvm.aarch64.neon.sqneg.v8i8" when ODIN_ARCH == .arm64 else "llvm.arm.neon.vqneg.v8i8") + _vqneg_s8 :: proc(a: int8x8_t) -> int8x8_t --- + @(link_name = "llvm.aarch64.neon.sqneg.v4i16" when ODIN_ARCH == .arm64 else "llvm.arm.neon.vqneg.v4i16") + _vqneg_s16 :: proc(a: int16x4_t) -> int16x4_t --- + @(link_name = "llvm.aarch64.neon.sqneg.v2i32" when ODIN_ARCH == .arm64 else "llvm.arm.neon.vqneg.v2i32") + _vqneg_s32 :: proc(a: int32x2_t) -> int32x2_t --- + @(link_name = "llvm.aarch64.neon.sqneg.v16i8" when ODIN_ARCH == .arm64 else "llvm.arm.neon.vqneg.v16i8") + _vqnegq_s8 :: proc(a: int8x16_t) -> int8x16_t --- + @(link_name = "llvm.aarch64.neon.sqneg.v8i16" when ODIN_ARCH == .arm64 else "llvm.arm.neon.vqneg.v8i16") + _vqnegq_s16 :: proc(a: int16x8_t) -> int16x8_t --- + @(link_name = "llvm.aarch64.neon.sqneg.v4i32" when ODIN_ARCH == .arm64 else "llvm.arm.neon.vqneg.v4i32") + _vqnegq_s32 :: proc(a: int32x4_t) -> int32x4_t --- } when ODIN_ARCH == .arm32 { @@ -1771,6 +2697,10 @@ when ODIN_ARCH == .arm32 { when ODIN_ARCH == .arm64 { @(private, default_calling_convention = "none") foreign _ { + @(link_name = "llvm.aarch64.neon.sqneg.v1i64") + _vqneg_s64 :: proc(a: int64x1_t) -> int64x1_t --- + @(link_name = "llvm.aarch64.neon.sqneg.v2i64") + _vqnegq_s64 :: proc(a: int64x2_t) -> int64x2_t --- @(link_name = "llvm.aarch64.neon.tbl1.v8i8") _vqtbl1 :: proc(t: int8x16_t, idx: uint8x8_t) -> int8x8_t --- @(link_name = "llvm.aarch64.neon.tbl1.v16i8") diff --git a/core/simd/arm/pmull.odin b/core/simd/arm/pmull.odin index b2baa85db..cb2940b2d 100644 --- a/core/simd/arm/pmull.odin +++ b/core/simd/arm/pmull.odin @@ -596,6 +596,40 @@ vtbx4_p8 :: #force_inline proc "c" (v: poly8x8_t, t: poly8x8x4_t, idx: uint8x8_t } } +// Population count per byte. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcnt_p8) +@(require_results, enable_target_feature = "neon") +vcnt_p8 :: #force_inline proc "c" (a: poly8x8_t) -> poly8x8_t { + return transmute(poly8x8_t)vcnt_s8(transmute(int8x8_t)a) +} + +// Population count per byte. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcntq_p8) +@(require_results, enable_target_feature = "neon") +vcntq_p8 :: #force_inline proc "c" (a: poly8x16_t) -> poly8x16_t { + return transmute(poly8x16_t)vcntq_s8(transmute(int8x16_t)a) +} + +// Bitwise Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmvn_p8) +@(require_results, enable_target_feature = "neon") +vmvn_p8 :: #force_inline proc "c" (a: poly8x8_t) -> poly8x8_t { + b := poly8x8_t(max(poly8_t)) + return simd.bit_xor(a, b) +} + +// Bitwise Not. +// +// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vmvnq_p8) +@(require_results, enable_target_feature = "neon") +vmvnq_p8 :: #force_inline proc "c" (a: poly8x16_t) -> poly8x16_t { + b := poly8x16_t(max(poly8_t)) + return simd.bit_xor(a, b) +} + when ODIN_ARCH == .arm64 { // Polynomial multiply long // From 5787cbc68b362a1724317a4910e1c03cf19b009f Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 15 Aug 2026 21:34:58 +0200 Subject: [PATCH 06/10] Fix backend support for #unroll on [dynamic]T --- src/llvm_backend_stmt.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 8b4b021fb..9fbb2d15d 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1740,7 +1740,13 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * slice = lb_emit_load(p, slice); } else { count_ptr = lb_add_local_generated(p, t_int, false).addr; - lb_emit_store(p, count_ptr, lb_slice_len(p, slice)); + if (t->kind == Type_Slice) { + lb_emit_store(p, count_ptr, lb_slice_len(p, slice)); + } else if (t->kind == Type_DynamicArray) { + lb_emit_store(p, count_ptr, lb_dynamic_array_len(p, slice)); + } else { + GB_ASSERT_MSG(false, "Need to add support for this type."); + } } data_ptr = lb_emit_struct_ev(p, slice, 0); break; From 1dbafbab632eb2888c1cd2d60e0cefb9bbbd7bae Mon Sep 17 00:00:00 2001 From: Harold Brenes Date: Sat, 15 Aug 2026 17:13:52 -0400 Subject: [PATCH 07/10] Explicitly specify all required LLVM components on linux build. This fixes missing symbols errors when building with LLVM with separate components. --- build_odin.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_odin.sh b/build_odin.sh index 9eab985e9..ebf2804c6 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -125,7 +125,7 @@ NetBSD) ;; Linux) CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" - LDFLAGS="$LDFLAGS -lstdc++ -ldl $($LLVM_CONFIG --libs core native --system-libs --libfiles)" + LDFLAGS="$LDFLAGS -lstdc++ -ldl $($LLVM_CONFIG --libs core native passes arm aarch64 x86 webassembly riscv --system-libs --libfiles)" # Copy libLLVM*.so into current directory for linking # NOTE: This is needed by the Linux release pipeline! # cp $(readlink -f $($LLVM_CONFIG --libfiles)) ./ From b17c10162de1d71260d938701a2eb8ff5790609d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Tesa=C5=99?= Date: Sun, 16 Aug 2026 00:30:42 +0200 Subject: [PATCH 08/10] Fix bit_set upper endpoint representability check --- src/check_type.cpp | 2 +- tests/issues/run.sh | 7 +++++++ tests/issues/test_issue_7304.odin | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tests/issues/test_issue_7304.odin diff --git a/src/check_type.cpp b/src/check_type.cpp index 14da12340..c5f78fd57 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1368,7 +1368,7 @@ gb_internal void check_bit_set_type(CheckerContext *c, Type *type, Type *named_t gb_free(a, s.text); return; } - if (!check_representable_as_constant(c, iv, t, nullptr)) { + if (!check_representable_as_constant(c, jv, t, nullptr)) { gbAllocator a = heap_allocator(); String s = big_int_to_string(a, &j); gbString ts = type_to_string(t); diff --git a/tests/issues/run.sh b/tests/issues/run.sh index c4dae65f9..393bd1eda 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -107,6 +107,13 @@ else exit 1 fi +if [[ $($ODIN check ../test_issue_7304.odin -no-entry-point $COMMON_CHECK 2>&1 >/dev/null | grep -c "9223372036854775808 is not representable by int") -eq 1 ]]; then + echo "SUCCESSFUL 1/1" +else + echo "SUCCESSFUL 0/1" + exit 1 +fi + clang -c ../test_issue_7010.c -o test_issue_7010_c.o $ODIN test ../test_issue_7010.odin $COMMON diff --git a/tests/issues/test_issue_7304.odin b/tests/issues/test_issue_7304.odin new file mode 100644 index 000000000..c96a0bae2 --- /dev/null +++ b/tests/issues/test_issue_7304.odin @@ -0,0 +1,4 @@ +// Tests issue #7304 https://github.com/odin-lang/Odin/issues/7304 +package test_issues + +Bad_Bit_Set :: bit_set[-1 ..< 9223372036854775808] From a7029ef7b6b94d7a28dbe14e4aec67ad3b547790 Mon Sep 17 00:00:00 2001 From: kalsprite Date: Sat, 15 Aug 2026 23:25:13 -0700 Subject: [PATCH 09/10] bitset subset --- src/check_expr.cpp | 18 +++--- tests/internal/test_constant_folding.odin | 78 +++++++++++++++++++++++ 2 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 tests/internal/test_constant_folding.odin diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ec276884a..344842978 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3343,27 +3343,29 @@ gb_internal void check_comparison(CheckerContext *c, Ast *node, Operand *x, Oper case Token_Lt: case Token_LtEq: { + // subset: (lhs & rhs) == lhs. a proper subset also requires lhs != rhs ExactValue lhs = x->value; ExactValue rhs = y->value; - ExactValue res = exact_binary_operator_value(Token_And, lhs, rhs); - res = exact_value_bool(compare_exact_values(op, res, lhs)); + ExactValue both = exact_binary_operator_value(Token_And, lhs, rhs); + bool res = compare_exact_values(Token_CmpEq, both, lhs); if (op == Token_Lt) { - res = exact_binary_operator_value(Token_And, res, exact_value_bool(compare_exact_values(op, lhs, rhs))); + res = res && compare_exact_values(Token_NotEq, lhs, rhs); } - x->value = res; + x->value = exact_value_bool(res); break; } case Token_Gt: case Token_GtEq: { + // superset: (lhs & rhs) == rhs ExactValue lhs = x->value; ExactValue rhs = y->value; - ExactValue res = exact_binary_operator_value(Token_And, lhs, rhs); - res = exact_value_bool(compare_exact_values(op, res, rhs)); + ExactValue both = exact_binary_operator_value(Token_And, lhs, rhs); + bool res = compare_exact_values(Token_CmpEq, both, rhs); if (op == Token_Gt) { - res = exact_binary_operator_value(Token_And, res, exact_value_bool(compare_exact_values(op, lhs, rhs))); + res = res && compare_exact_values(Token_NotEq, lhs, rhs); } - x->value = res; + x->value = exact_value_bool(res); break; } } diff --git a/tests/internal/test_constant_folding.odin b/tests/internal/test_constant_folding.odin new file mode 100644 index 000000000..385ba6835 --- /dev/null +++ b/tests/internal/test_constant_folding.odin @@ -0,0 +1,78 @@ +package test_internal + +import "core:testing" + +// `<=` and `<` on a `bit_set` are subset and proper subset, `>=` and `>` superset. The folder +// asked `(lhs & rhs) <= lhs` where the definition is `(lhs & rhs) == lhs`, which is true for +// any operands, so `<=` folded true unconditionally; `<` compounded it by requiring `lhs < rhs` +// where it needs `lhs != rhs`. Under `when` this decides which declarations exist. + +@(test) +bit_set_subset_folding_matches_runtime :: proc(t: ^testing.T) { + B :: bit_set[0..<4] + + { // disjoint: neither a subset nor a superset + a, b := B{0, 3}, B{0, 1} + testing.expect_value(t, B{0, 3} <= B{0, 1}, a <= b) + testing.expect_value(t, B{0, 3} <= B{0, 1}, false) + testing.expect_value(t, B{0, 3} >= B{0, 1}, a >= b) + testing.expect_value(t, B{0, 3} >= B{0, 1}, false) + } + { // proper subset + a, b := B{0}, B{0, 1} + testing.expect_value(t, B{0} <= B{0, 1}, a <= b) + testing.expect_value(t, B{0} <= B{0, 1}, true) + testing.expect_value(t, B{0} < B{0, 1}, a < b) + testing.expect_value(t, B{0} < B{0, 1}, true) + } + { // equal: a subset but not a proper one + a, b := B{0, 1}, B{0, 1} + testing.expect_value(t, B{0, 1} <= B{0, 1}, a <= b) + testing.expect_value(t, B{0, 1} <= B{0, 1}, true) + testing.expect_value(t, B{0, 1} < B{0, 1}, a < b) + testing.expect_value(t, B{0, 1} < B{0, 1}, false) + } + { // superset + a, b := B{0, 1}, B{0} + testing.expect_value(t, B{0, 1} <= B{0}, a <= b) + testing.expect_value(t, B{0, 1} <= B{0}, false) + testing.expect_value(t, B{0, 1} > B{0}, a > b) + testing.expect_value(t, B{0, 1} > B{0}, true) + } + { // the empty set is a subset of everything, and a proper one unless both are empty + a, b := B{}, B{0} + testing.expect_value(t, B{} < B{0}, a < b) + testing.expect_value(t, B{} < B{0}, true) + } + { + a, b := B{}, B{} + testing.expect_value(t, B{} <= B{}, a <= b) + testing.expect_value(t, B{} <= B{}, true) + testing.expect_value(t, B{} < B{}, a < b) + testing.expect_value(t, B{} < B{}, false) + } + + // equality was never affected, so a fix here must not disturb it + { + a, b := B{0, 1}, B{1, 0} + testing.expect_value(t, B{0, 1} == B{1, 0}, a == b) + testing.expect_value(t, B{0, 1} == B{1, 0}, true) + testing.expect_value(t, B{0, 1} != B{0}, a != B{0}) + } +} + +// a mis-folded subset test selects the wrong `when` arm, which changes which declarations exist +@(test) +bit_set_subset_folding_selects_the_right_when_arm :: proc(t: ^testing.T) { + B :: bit_set[0..<4] + + when (B{0} < B{0, 1}) { W1 :: 1 } else { W1 :: 0 } + when (B{0, 3} <= B{0, 1}) { W2 :: 0 } else { W2 :: 1 } + when (B{0, 1} <= B{0, 1}) { W3 :: 1 } else { W3 :: 0 } + when (B{0, 1} > B{0}) { W4 :: 1 } else { W4 :: 0 } + + testing.expect_value(t, W1, 1) + testing.expect_value(t, W2, 1) + testing.expect_value(t, W3, 1) + testing.expect_value(t, W4, 1) +} From 4e0a71c24c8a087ba71150b1cdb4a3c4e5a4e5d1 Mon Sep 17 00:00:00 2001 From: mo Date: Sun, 16 Aug 2026 19:48:19 +1200 Subject: [PATCH 10/10] Add non-allocating hex.decode_into_buffer Also minor fixes to documentation of hex.decode(). Adds tests of the new procedure with buffers the correct size, larger, and too small. --- core/encoding/hex/hex.odin | 38 ++++++++++++++- tests/core/encoding/hex/test_core_hex.odin | 56 +++++++++++++++++++++- 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/core/encoding/hex/hex.odin b/core/encoding/hex/hex.odin index c4726d9e9..f7a39a081 100644 --- a/core/encoding/hex/hex.odin +++ b/core/encoding/hex/hex.odin @@ -95,12 +95,12 @@ Decodes a hex sequence into a byte slice *Allocates Using Provided Allocator* Inputs: -- dst: The hex sequence decoded into bytes - src: The `[]byte` to be hex-decoded - allocator: (default: context.allocator) - loc: The caller location for debugging purposes (default: #caller_location) Returns: +- dst: The hex sequence decoded into bytes - ok: A bool, `true` if decoding succeeded, `false` otherwise */ decode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> (dst: []byte, ok: bool) { @@ -123,6 +123,40 @@ decode :: proc(src: []byte, allocator := context.allocator, loc := #caller_locat return dst, true } +/* +Decodes a hex sequence into a byte slice + +Inputs: +- src: The `[]byte` to be hex-decoded +- buf: A buffer large enough to hold the decoded sequence + +Returns: +- dst: The hex sequence decoded into bytes +- ok: A bool, `true` if decoding succeeded, `false` otherwise +*/ +decode_into_buffer :: proc(src: []byte, buf: []byte) -> (dst: []byte, ok: bool) #optional_ok { + if len(src) % 2 == 1 { + return + } + dst_len := len(src) / 2 + if len(buf) < dst_len { + return + } + + #no_bounds_check for i, j := 0, 1; j < len(src); j += 2 { + p := src[j-1] + q := src[j] + + a := hex_digit(p) or_return + b := hex_digit(q) or_return + + buf[i] = (a << 4) | b + i += 1 + } + + return buf[:dst_len], true +} + /* Decodes the first byte in a hex sequence to a byte @@ -173,4 +207,4 @@ hex_digit :: proc(char: byte) -> (u8, bool) { case 'A' ..= 'F': return char - 'A' + 10, true case: return 0, false } -} \ No newline at end of file +} diff --git a/tests/core/encoding/hex/test_core_hex.odin b/tests/core/encoding/hex/test_core_hex.odin index 6a00c9705..fdb3a2734 100644 --- a/tests/core/encoding/hex/test_core_hex.odin +++ b/tests/core/encoding/hex/test_core_hex.odin @@ -47,6 +47,60 @@ hex_decode :: proc(t: ^testing.T) { } } +@(test) +hex_decode_into_buffer :: proc(t: ^testing.T) { + for test in CASES { + buffer := make([]u8, len(test[1]) / 2) + defer delete(buffer) + decoded, ok := hex.decode_into_buffer(transmute([]byte)test[1], buffer) + testing.expect(t, ok, "decode_into_buffer: not ok") + testing.expectf( + t, + ok, + "decode: %q not ok", + test[1], + ) + testing.expectf( + t, + string(decoded) == test[0], + "decode: %q -> %q (should be: %q)", + test[1], + string(decoded), + test[0], + ) + } + + // destination buffer is larger + for test in CASES { + buffer := make([]u8, len(test[1]) / 2 + 1) + defer delete(buffer) + decoded, ok := hex.decode_into_buffer(transmute([]byte)test[1], buffer) + testing.expect(t, ok, "decode_into_buffer: not ok") + testing.expectf( + t, + ok, + "decode: %q not ok", + test[1], + ) + testing.expectf( + t, + string(decoded) == test[0], + "decode: %q -> %q (should be: %q)", + test[1], + string(decoded), + test[0], + ) + } + + // destination buffer is too small + for test in CASES { + buffer := make([]u8, len(test[1]) / 2 - 1) + defer delete(buffer) + _, ok := hex.decode_into_buffer(transmute([]byte)test[1], buffer) + testing.expect(t, !ok, "decode_into_buffer: should not be ok") + } +} + @(test) hex_decode_sequence :: proc(t: ^testing.T) { b, ok := hex.decode_sequence("0x23") @@ -83,4 +137,4 @@ hex_decode_sequence :: proc(t: ^testing.T) { _, ok = hex.decode_sequence("123") testing.expect(t, !ok, "decode_sequence: 123 should be too long") -} \ No newline at end of file +}