blob: 53b6cc34e921b4600e905bbc49759ce4c435a7cd [file] [edit]
//@ requireOptions("--useWasmSIMD=1")
//@ skip if !$isSIMDPlatform
import { instantiate } from "../wabt-wrapper.js"
import * as assert from "../assert.js"
// Test vector shift-by-immediate for all lane types, sign modes, and edge cases.
// Constant shifts use NEON SHL/SSHR/USHR immediate instructions on ARM64.
// Dynamic shifts use the mask+splat+SSHL/USHL path.
// Both paths must produce identical results.
// Module 1: i8x16 shifts
async function testI8x16() {
let wat = `(module
(memory (export "mem") 1)
(func (export "shl_3") (param i32 i32)
(v128.store (local.get 1) (i8x16.shl (v128.load (local.get 0)) (i32.const 3))))
(func (export "shl_dyn") (param i32 i32 i32)
(v128.store (local.get 1) (i8x16.shl (v128.load (local.get 0)) (local.get 2))))
(func (export "shr_u_4") (param i32 i32)
(v128.store (local.get 1) (i8x16.shr_u (v128.load (local.get 0)) (i32.const 4))))
(func (export "shr_u_dyn") (param i32 i32 i32)
(v128.store (local.get 1) (i8x16.shr_u (v128.load (local.get 0)) (local.get 2))))
(func (export "shr_s_2") (param i32 i32)
(v128.store (local.get 1) (i8x16.shr_s (v128.load (local.get 0)) (i32.const 2))))
(func (export "shr_s_dyn") (param i32 i32 i32)
(v128.store (local.get 1) (i8x16.shr_s (v128.load (local.get 0)) (local.get 2))))
(func (export "shl_0") (param i32 i32)
(v128.store (local.get 1) (i8x16.shl (v128.load (local.get 0)) (i32.const 0))))
(func (export "shl_7") (param i32 i32)
(v128.store (local.get 1) (i8x16.shl (v128.load (local.get 0)) (i32.const 7))))
(func (export "shl_8") (param i32 i32)
(v128.store (local.get 1) (i8x16.shl (v128.load (local.get 0)) (i32.const 8))))
(func (export "shl_11") (param i32 i32)
(v128.store (local.get 1) (i8x16.shl (v128.load (local.get 0)) (i32.const 11))))
)`
const instance = await instantiate(wat, {}, { simd: true })
const u8 = new Uint8Array(instance.exports.mem.buffer)
const e = instance.exports
const pattern = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01]
for (let i = 0; i < 16; i++) u8[i] = pattern[i]
for (let iter = 0; iter < wasmTestLoopCount; ++iter) {
// shl const=3 vs dyn=3
e.shl_3(0, 16)
e.shl_dyn(0, 32, 3)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], u8[32 + i])
// shr_u const=4 vs dyn=4
e.shr_u_4(0, 16)
e.shr_u_dyn(0, 32, 4)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], u8[32 + i])
// shr_s const=2 vs dyn=2
e.shr_s_2(0, 16)
e.shr_s_dyn(0, 32, 2)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], u8[32 + i])
// shift 0: identity
e.shl_0(0, 16)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], pattern[i])
// shift 8: wraps to 0 (identity)
e.shl_8(0, 16)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], pattern[i])
// shift 11 == shift 3
e.shl_11(0, 16)
e.shl_3(0, 32)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], u8[32 + i])
}
}
// Module 2: i16x8 shifts
async function testI16x8() {
let wat = `(module
(memory (export "mem") 1)
(func (export "shl_5") (param i32 i32)
(v128.store (local.get 1) (i16x8.shl (v128.load (local.get 0)) (i32.const 5))))
(func (export "shl_dyn") (param i32 i32 i32)
(v128.store (local.get 1) (i16x8.shl (v128.load (local.get 0)) (local.get 2))))
(func (export "shr_u_8") (param i32 i32)
(v128.store (local.get 1) (i16x8.shr_u (v128.load (local.get 0)) (i32.const 8))))
(func (export "shr_u_dyn") (param i32 i32 i32)
(v128.store (local.get 1) (i16x8.shr_u (v128.load (local.get 0)) (local.get 2))))
(func (export "shr_s_10") (param i32 i32)
(v128.store (local.get 1) (i16x8.shr_s (v128.load (local.get 0)) (i32.const 10))))
(func (export "shr_s_dyn") (param i32 i32 i32)
(v128.store (local.get 1) (i16x8.shr_s (v128.load (local.get 0)) (local.get 2))))
(func (export "shr_u_0") (param i32 i32)
(v128.store (local.get 1) (i16x8.shr_u (v128.load (local.get 0)) (i32.const 0))))
(func (export "shr_u_16") (param i32 i32)
(v128.store (local.get 1) (i16x8.shr_u (v128.load (local.get 0)) (i32.const 16))))
(func (export "shr_u_19") (param i32 i32)
(v128.store (local.get 1) (i16x8.shr_u (v128.load (local.get 0)) (i32.const 19))))
)`
const instance = await instantiate(wat, {}, { simd: true })
const u8 = new Uint8Array(instance.exports.mem.buffer)
const e = instance.exports
const pattern = [0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x11, 0x22, 0x33, 0x44]
for (let i = 0; i < 16; i++) u8[i] = pattern[i]
for (let iter = 0; iter < wasmTestLoopCount; ++iter) {
e.shl_5(0, 16)
e.shl_dyn(0, 32, 5)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], u8[32 + i])
e.shr_u_8(0, 16)
e.shr_u_dyn(0, 32, 8)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], u8[32 + i])
e.shr_s_10(0, 16)
e.shr_s_dyn(0, 32, 10)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], u8[32 + i])
// shift 0: identity
e.shr_u_0(0, 16)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], pattern[i])
// shift 16: wraps to 0
e.shr_u_16(0, 16)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], pattern[i])
// shift 19 == shift 3
e.shr_u_19(0, 16)
e.shr_u_dyn(0, 32, 3)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], u8[32 + i])
}
}
// Module 3: i32x4 shifts
async function testI32x4() {
let wat = `(module
(memory (export "mem") 1)
(func (export "shl_16") (param i32 i32)
(v128.store (local.get 1) (i32x4.shl (v128.load (local.get 0)) (i32.const 16))))
(func (export "shl_dyn") (param i32 i32 i32)
(v128.store (local.get 1) (i32x4.shl (v128.load (local.get 0)) (local.get 2))))
(func (export "shr_u_12") (param i32 i32)
(v128.store (local.get 1) (i32x4.shr_u (v128.load (local.get 0)) (i32.const 12))))
(func (export "shr_u_dyn") (param i32 i32 i32)
(v128.store (local.get 1) (i32x4.shr_u (v128.load (local.get 0)) (local.get 2))))
(func (export "shr_s_20") (param i32 i32)
(v128.store (local.get 1) (i32x4.shr_s (v128.load (local.get 0)) (i32.const 20))))
(func (export "shr_s_dyn") (param i32 i32 i32)
(v128.store (local.get 1) (i32x4.shr_s (v128.load (local.get 0)) (local.get 2))))
(func (export "shl_0") (param i32 i32)
(v128.store (local.get 1) (i32x4.shl (v128.load (local.get 0)) (i32.const 0))))
(func (export "shl_32") (param i32 i32)
(v128.store (local.get 1) (i32x4.shl (v128.load (local.get 0)) (i32.const 32))))
)`
const instance = await instantiate(wat, {}, { simd: true })
const u8 = new Uint8Array(instance.exports.mem.buffer)
const mem = new DataView(instance.exports.mem.buffer)
const e = instance.exports
const pattern = [0xDE, 0xAD, 0xBE, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x11, 0x22, 0x33, 0x44]
for (let i = 0; i < 16; i++) u8[i] = pattern[i]
for (let iter = 0; iter < wasmTestLoopCount; ++iter) {
e.shl_16(0, 16)
e.shl_dyn(0, 32, 16)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], u8[32 + i])
e.shr_u_12(0, 16)
e.shr_u_dyn(0, 32, 12)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], u8[32 + i])
e.shr_s_20(0, 16)
e.shr_s_dyn(0, 32, 20)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], u8[32 + i])
// shift 0: identity
e.shl_0(0, 16)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], pattern[i])
// shift 32: wraps to 0
e.shl_32(0, 16)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], pattern[i])
}
}
// Module 4: i64x2 shifts
async function testI64x2() {
let wat = `(module
(memory (export "mem") 1)
(func (export "shl_32") (param i32 i32)
(v128.store (local.get 1) (i64x2.shl (v128.load (local.get 0)) (i32.const 32))))
(func (export "shl_dyn") (param i32 i32 i32)
(v128.store (local.get 1) (i64x2.shl (v128.load (local.get 0)) (local.get 2))))
(func (export "shr_u_48") (param i32 i32)
(v128.store (local.get 1) (i64x2.shr_u (v128.load (local.get 0)) (i32.const 48))))
(func (export "shr_u_dyn") (param i32 i32 i32)
(v128.store (local.get 1) (i64x2.shr_u (v128.load (local.get 0)) (local.get 2))))
(func (export "shr_s_16") (param i32 i32)
(v128.store (local.get 1) (i64x2.shr_s (v128.load (local.get 0)) (i32.const 16))))
(func (export "shr_s_dyn") (param i32 i32 i32)
(v128.store (local.get 1) (i64x2.shr_s (v128.load (local.get 0)) (local.get 2))))
(func (export "shr_s_0") (param i32 i32)
(v128.store (local.get 1) (i64x2.shr_s (v128.load (local.get 0)) (i32.const 0))))
(func (export "shr_s_63") (param i32 i32)
(v128.store (local.get 1) (i64x2.shr_s (v128.load (local.get 0)) (i32.const 63))))
(func (export "shr_s_64") (param i32 i32)
(v128.store (local.get 1) (i64x2.shr_s (v128.load (local.get 0)) (i32.const 64))))
)`
const instance = await instantiate(wat, {}, { simd: true })
const u8 = new Uint8Array(instance.exports.mem.buffer)
const mem = new DataView(instance.exports.mem.buffer)
const e = instance.exports
mem.setBigUint64(0, 0x8000000000000001n, true)
mem.setBigUint64(8, 0xFFFFFFFFFFFFFFFFn, true)
for (let iter = 0; iter < wasmTestLoopCount; ++iter) {
e.shl_32(0, 16)
e.shl_dyn(0, 32, 32)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], u8[32 + i])
e.shr_u_48(0, 16)
e.shr_u_dyn(0, 32, 48)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], u8[32 + i])
e.shr_s_16(0, 16)
e.shr_s_dyn(0, 32, 16)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], u8[32 + i])
// shift 0: identity
e.shr_s_0(0, 16)
assert.eq(mem.getBigUint64(16, true), 0x8000000000000001n)
assert.eq(mem.getBigUint64(24, true), 0xFFFFFFFFFFFFFFFFn)
// shift 64: wraps to 0
e.shr_s_64(0, 16)
assert.eq(mem.getBigUint64(16, true), 0x8000000000000001n)
assert.eq(mem.getBigUint64(24, true), 0xFFFFFFFFFFFFFFFFn)
// shift 63: max signed right shift
e.shr_s_63(0, 16)
e.shr_s_dyn(0, 32, 63)
for (let i = 0; i < 16; i++) assert.eq(u8[16 + i], u8[32 + i])
}
}
async function test() {
await testI8x16()
await testI16x8()
await testI32x4()
await testI64x2()
}
await assert.asyncTest(test())