Source code
Revision control
Copy as Markdown
Other Tools
// |jit-test| skip-if: !wasmSimdEnabled()
// replace_lane fed by extract_lane, for every lane size pairing, including the
// ones where the extracted value is sign- or zero-extended into the replaced
// lane, the ones reading from the vector being replaced into, an extracted
// value with several uses, and a replaced-into vector that stays live.
const extracts = [
["i8x16.extract_lane_s", 1, "i32", true],
["i8x16.extract_lane_u", 1, "i32", false],
["i16x8.extract_lane_s", 2, "i32", true],
["i16x8.extract_lane_u", 2, "i32", false],
["i32x4.extract_lane", 4, "i32", true],
["i64x2.extract_lane", 8, "i64", true],
];
const replaces = [
["i8x16.replace_lane", 1, "i32"],
["i16x8.replace_lane", 2, "i32"],
["i32x4.replace_lane", 4, "i32"],
["i64x2.replace_lane", 8, "i64"],
];
const src = iota(16).map(i => (0x80 + i * 17) & 0xff);
const dst = iota(16).map(i => (0x40 + i * 29) & 0xff);
function readLane(bytes, size, lane, signed) {
if (size === 8) {
let v = 0n;
for (let i = 7; i >= 0; i--) {
v = v * 256n + BigInt(bytes[lane * 8 + i]);
}
if (signed && v >= 0x8000000000000000n) {
v -= 0x10000000000000000n;
}
return v;
}
let v = 0;
for (let i = size - 1; i >= 0; i--) {
v = v * 256 + bytes[lane * size + i];
}
if (signed && v >= 2 ** (8 * size - 1)) {
v -= 2 ** (8 * size);
}
return v;
}
function expected(base, dstSize, dstLane, value) {
const out = base.slice();
const low = BigInt.asUintN(8 * dstSize, BigInt(value));
for (let i = 0; i < dstSize; i++) {
out[dstLane * dstSize + i] = Number((low >> BigInt(8 * i)) & 0xffn);
}
return out;
}
for (const [extract, srcSize, srcType, signed] of extracts) {
for (const [replace, dstSize, dstType] of replaces) {
if (srcType !== dstType) {
continue;
}
const dstLanes = 16 / dstSize;
const funcs = [];
const cases = [];
for (let s = 0; s < 16 / srcSize; s++) {
for (let d = 0; d < dstLanes; d++) {
for (const self of [false, true]) {
const from = self ? "$v" : "$w";
funcs.push(`
(func (export "f${cases.length}") (local $v v128) (local $w v128)
(local.set $v (v128.load (i32.const 0)))
(local.set $w (v128.load (i32.const 16)))
(v128.store (i32.const 32)
(${replace} ${d} (local.get $v)
(${extract} ${s} (local.get ${from})))))`);
cases.push([s, d, self]);
}
const d2 = (d + 1) % dstLanes;
funcs.push(`
(func (export "g${s}_${d}") (local $l ${srcType})
(v128.store (i32.const 32)
(${replace} ${d2}
(${replace} ${d} (v128.load (i32.const 0))
(local.tee $l (${extract} ${s} (v128.load (i32.const 16)))))
(local.get $l)))
(${srcType}.store (i32.const 48) (local.get $l)))`);
funcs.push(`
(func (export "h${s}_${d}") (local $v v128)
(local.set $v (v128.load (i32.const 0)))
(v128.store (i32.const 32)
(${replace} ${d} (local.get $v)
(${extract} ${s} (v128.load (i32.const 16)))))
(v128.store (i32.const 48) (local.get $v)))`);
}
}
const ins = wasmEvalText(`(module (memory (export "mem") 1) ${funcs.join("")})`);
const mem = new Uint8Array(ins.exports.mem.buffer);
const view = new DataView(ins.exports.mem.buffer);
cases.forEach(([s, d, self], i) => {
mem.set(dst, 0);
mem.set(src, 16);
ins.exports["f" + i]();
const value = readLane(self ? dst : src, srcSize, s, signed);
assertSame(Array.from(mem.subarray(32, 48)),
expected(dst, dstSize, d, value));
});
for (let s = 0; s < 16 / srcSize; s++) {
for (let d = 0; d < dstLanes; d++) {
const d2 = (d + 1) % dstLanes;
mem.set(dst, 0);
mem.set(src, 16);
ins.exports[`g${s}_${d}`]();
const value = readLane(src, srcSize, s, signed);
assertSame(Array.from(mem.subarray(32, 48)),
expected(expected(dst, dstSize, d, value), dstSize, d2,
value));
if (srcType === "i64") {
assertEq(view.getBigInt64(48, true), value);
} else {
assertEq(view.getInt32(48, true), value | 0);
}
mem.set(dst, 0);
mem.set(src, 16);
ins.exports[`h${s}_${d}`]();
assertSame(Array.from(mem.subarray(32, 48)),
expected(dst, dstSize, d, value));
assertSame(Array.from(mem.subarray(48, 64)), dst);
}
}
}
}