// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
fn load_u16_le(bytes : FixedArray[Byte], offset : Int) -> UInt16 {
bytes.unsafe_get(offset).to_uint16() |
(bytes.unsafe_get(offset + 1).to_uint16() << 8)
}
///|
fn load_u16x4_le(str : String, offset : Int) -> UInt64 {
for i in 0..<4; word = UInt64(0) {
continue word | (str.unsafe_get(offset + i).to_uint64() << (16 * i))
} nobreak {
word
}
}
///|
fn load_u32_le(bytes : FixedArray[Byte], offset : Int) -> UInt {
bytes.unsafe_get(offset).to_uint() |
(bytes.unsafe_get(offset + 1).to_uint() << 8) |
(bytes.unsafe_get(offset + 2).to_uint() << 16) |
(bytes.unsafe_get(offset + 3).to_uint() << 24)
}
///|
fn load_u64_le(bytes : FixedArray[Byte], offset : Int) -> UInt64 {
bytes.unsafe_get(offset).to_uint64() |
(bytes.unsafe_get(offset + 1).to_uint64() << 8) |
(bytes.unsafe_get(offset + 2).to_uint64() << 16) |
(bytes.unsafe_get(offset + 3).to_uint64() << 24) |
(bytes.unsafe_get(offset + 4).to_uint64() << 32) |
(bytes.unsafe_get(offset + 5).to_uint64() << 40) |
(bytes.unsafe_get(offset + 6).to_uint64() << 48) |
(bytes.unsafe_get(offset + 7).to_uint64() << 56)
}
///|
fn store_u16_le(bytes : FixedArray[Byte], offset : Int, value : UInt16) -> Unit {
bytes.unsafe_set(offset, value.to_byte())
bytes.unsafe_set(offset + 1, (value >> 8).to_byte())
}
///|
fn store_u32_le(bytes : FixedArray[Byte], offset : Int, value : UInt) -> Unit {
bytes.unsafe_set(offset, value.to_byte())
bytes.unsafe_set(offset + 1, (value >> 8).to_byte())
bytes.unsafe_set(offset + 2, (value >> 16).to_byte())
bytes.unsafe_set(offset + 3, (value >> 24).to_byte())
}
///|
fn store_u64_le(bytes : FixedArray[Byte], offset : Int, value : UInt64) -> Unit {
bytes.unsafe_set(offset, value.to_byte())
bytes.unsafe_set(offset + 1, (value >> 8).to_byte())
bytes.unsafe_set(offset + 2, (value >> 16).to_byte())
bytes.unsafe_set(offset + 3, (value >> 24).to_byte())
bytes.unsafe_set(offset + 4, (value >> 32).to_byte())
bytes.unsafe_set(offset + 5, (value >> 40).to_byte())
bytes.unsafe_set(offset + 6, (value >> 48).to_byte())
bytes.unsafe_set(offset + 7, (value >> 56).to_byte())
}
///|
/// Selects bytes of `value` indexed by `indices`; indices >= 16 yield zero.
#intrinsic("%v128.i8x16_swizzle")
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn i8x16_swizzle(value : V128, indices : V128) -> V128 {
pack_u8x16_by(i => {
let index = u8_lane(indices, i).to_int()
if index < 16 {
u8_lane(value, index)
} else {
0
}
})
}
///|
/// Relaxed byte swizzle; behavior for out-of-range indices is implementation-defined.
#intrinsic("%v128.i8x16_relaxed_swizzle")
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn i8x16_relaxed_swizzle(value : V128, indices : V128) -> V128 {
i8x16_swizzle(value, indices)
}
///|
fn shuffle_lane(value : V128, other : V128, index : Int) -> Byte {
if index < 16 {
u8_lane(value, index)
} else {
u8_lane(other, index - 16)
}
}
///|
/// Selects 16 bytes from the concatenation of the two vectors by constant lane indices.
#intrinsic("%v128.i8x16_shuffle")
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn i8x16_shuffle(
value : V128,
other : V128,
i0 : Int,
i1 : Int,
i2 : Int,
i3 : Int,
i4 : Int,
i5 : Int,
i6 : Int,
i7 : Int,
i8 : Int,
i9 : Int,
i10 : Int,
i11 : Int,
i12 : Int,
i13 : Int,
i14 : Int,
i15 : Int,
) -> V128 {
pack_u8x16_by(fn(i) {
match i {
0 => shuffle_lane(value, other, i0)
1 => shuffle_lane(value, other, i1)
2 => shuffle_lane(value, other, i2)
3 => shuffle_lane(value, other, i3)
4 => shuffle_lane(value, other, i4)
5 => shuffle_lane(value, other, i5)
6 => shuffle_lane(value, other, i6)
7 => shuffle_lane(value, other, i7)
8 => shuffle_lane(value, other, i8)
9 => shuffle_lane(value, other, i9)
10 => shuffle_lane(value, other, i10)
11 => shuffle_lane(value, other, i11)
12 => shuffle_lane(value, other, i12)
13 => shuffle_lane(value, other, i13)
14 => shuffle_lane(value, other, i14)
_ => shuffle_lane(value, other, i15)
}
})
}
///|
/// Loads a 128-bit vector from `bytes` at `offset` (little-endian).
#intrinsic("%v128.v128_load")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load(bytes : FixedArray[Byte], offset : Int) -> V128 {
make(load_u64_le(bytes, offset), load_u64_le(bytes, offset + 8))
}
///|
/// Loads eight consecutive UTF-16 code units of `str` starting at code unit
/// `offset` into the eight 16-bit lanes of the vector. The caller must ensure
/// `offset + 8 <= str.length()`.
#intrinsic("%v128.v128_load_i16x8")
#borrow(str)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load_i16x8(str : String, offset : Int) -> V128 {
make(load_u16x4_le(str, offset), load_u16x4_le(str, offset + 4))
}
///|
/// Loads packed elements from `bytes` and sign-extends them into the vector.
#intrinsic("%v128.v128_load8x8_s")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load8x8_s(bytes : FixedArray[Byte], offset : Int) -> V128 {
let value = load_u64_le(bytes, offset)
make(sign_extend_u8x4_to_u16x4(value), sign_extend_u8x4_to_u16x4(value >> 32))
}
///|
/// Loads packed elements from `bytes` and zero-extends them into the vector.
#intrinsic("%v128.v128_load8x8_u")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load8x8_u(bytes : FixedArray[Byte], offset : Int) -> V128 {
let value = load_u64_le(bytes, offset)
make(widen_u8x4_to_u16x4(value), widen_u8x4_to_u16x4(value >> 32))
}
///|
/// Loads packed elements from `bytes` and sign-extends them into the vector.
#intrinsic("%v128.v128_load16x4_s")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load16x4_s(bytes : FixedArray[Byte], offset : Int) -> V128 {
let value = load_u64_le(bytes, offset)
make(
sign_extend_u16x2_to_u32x2(value),
sign_extend_u16x2_to_u32x2(value >> 32),
)
}
///|
/// Loads packed elements from `bytes` and zero-extends them into the vector.
#intrinsic("%v128.v128_load16x4_u")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load16x4_u(bytes : FixedArray[Byte], offset : Int) -> V128 {
let value = load_u64_le(bytes, offset)
make(widen_u16x2_to_u32x2(value), widen_u16x2_to_u32x2(value >> 32))
}
///|
/// Loads packed elements from `bytes` and sign-extends them into the vector.
#intrinsic("%v128.v128_load32x2_s")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load32x2_s(bytes : FixedArray[Byte], offset : Int) -> V128 {
let value = load_u64_le(bytes, offset)
make(sign_extend_u32_to_u64(value), sign_extend_u32_to_u64(value >> 32))
}
///|
/// Loads packed elements from `bytes` and zero-extends them into the vector.
#intrinsic("%v128.v128_load32x2_u")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load32x2_u(bytes : FixedArray[Byte], offset : Int) -> V128 {
let value = load_u64_le(bytes, offset)
make(value & 0xffffffffUL, value >> 32)
}
///|
/// Loads one element from `bytes` and splats it across the vector.
#intrinsic("%v128.v128_load8_splat")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load8_splat(bytes : FixedArray[Byte], offset : Int) -> V128 {
i8x16_splat(bytes.unsafe_get(offset))
}
///|
/// Loads one element from `bytes` and splats it across the vector.
#intrinsic("%v128.v128_load16_splat")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load16_splat(bytes : FixedArray[Byte], offset : Int) -> V128 {
i16x8_splat(load_u16_le(bytes, offset))
}
///|
/// Loads one element from `bytes` and splats it across the vector.
#intrinsic("%v128.v128_load32_splat")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load32_splat(bytes : FixedArray[Byte], offset : Int) -> V128 {
i32x4_splat(load_u32_le(bytes, offset))
}
///|
/// Loads one element from `bytes` and splats it across the vector.
#intrinsic("%v128.v128_load64_splat")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load64_splat(bytes : FixedArray[Byte], offset : Int) -> V128 {
i64x2_splat(load_u64_le(bytes, offset))
}
///|
/// Loads one element from `bytes` into the low lane, zeroing the rest.
#intrinsic("%v128.v128_load32_zero")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load32_zero(bytes : FixedArray[Byte], offset : Int) -> V128 {
i32x4_const(load_u32_le(bytes, offset), 0, 0, 0)
}
///|
/// Loads one element from `bytes` into the low lane, zeroing the rest.
#intrinsic("%v128.v128_load64_zero")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load64_zero(bytes : FixedArray[Byte], offset : Int) -> V128 {
make(load_u64_le(bytes, offset), 0UL)
}
///|
/// Loads one element from `bytes` into lane `lane`, keeping the other lanes.
#intrinsic("%v128.v128_load8_lane")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load8_lane(
bytes : FixedArray[Byte],
offset : Int,
value : V128,
lane : Int,
) -> V128 {
i8x16_replace_lane(value, bytes.unsafe_get(offset).to_uint(), lane)
}
///|
/// Loads one element from `bytes` into lane `lane`, keeping the other lanes.
#intrinsic("%v128.v128_load16_lane")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load16_lane(
bytes : FixedArray[Byte],
offset : Int,
value : V128,
lane : Int,
) -> V128 {
i16x8_replace_lane(value, load_u16_le(bytes, offset).to_uint(), lane)
}
///|
/// Loads one element from `bytes` into lane `lane`, keeping the other lanes.
#intrinsic("%v128.v128_load32_lane")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load32_lane(
bytes : FixedArray[Byte],
offset : Int,
value : V128,
lane : Int,
) -> V128 {
i32x4_replace_lane(value, load_u32_le(bytes, offset), lane)
}
///|
/// Loads one element from `bytes` into lane `lane`, keeping the other lanes.
#intrinsic("%v128.v128_load64_lane")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_load64_lane(
bytes : FixedArray[Byte],
offset : Int,
value : V128,
lane : Int,
) -> V128 {
i64x2_replace_lane(value, load_u64_le(bytes, offset), lane)
}
///|
/// Stores a 128-bit vector to `bytes` at `offset` (little-endian).
#intrinsic("%v128.v128_store")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_store(bytes : FixedArray[Byte], offset : Int, value : V128) -> Unit {
store_u64_le(bytes, offset, lo(value))
store_u64_le(bytes, offset + 8, hi(value))
}
///|
/// Stores lane `lane` to `bytes` at `offset` (little-endian).
#intrinsic("%v128.v128_store8_lane")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_store8_lane(
bytes : FixedArray[Byte],
offset : Int,
value : V128,
lane : Int,
) -> Unit {
bytes.unsafe_set(offset, u8_lane(value, lane))
}
///|
/// Stores lane `lane` to `bytes` at `offset` (little-endian).
#intrinsic("%v128.v128_store16_lane")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_store16_lane(
bytes : FixedArray[Byte],
offset : Int,
value : V128,
lane : Int,
) -> Unit {
store_u16_le(bytes, offset, u16_lane(value, lane))
}
///|
/// Stores lane `lane` to `bytes` at `offset` (little-endian).
#intrinsic("%v128.v128_store32_lane")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_store32_lane(
bytes : FixedArray[Byte],
offset : Int,
value : V128,
lane : Int,
) -> Unit {
store_u32_le(bytes, offset, u32_lane(value, lane))
}
///|
/// Stores lane `lane` to `bytes` at `offset` (little-endian).
#intrinsic("%v128.v128_store64_lane")
#borrow(bytes)
#internal(experimental, "subject to breaking change without notice")
#doc(hidden)
pub fn v128_store64_lane(
bytes : FixedArray[Byte],
offset : Int,
value : V128,
lane : Int,
) -> Unit {
store_u64_le(bytes, offset, u64_lane(value, lane))
}