Skip to content

Commit

Permalink
Add support to print out v128 values
Browse files Browse the repository at this point in the history
  • Loading branch information
jay-tux committed Oct 4, 2024
1 parent a7cea4e commit ce287be
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 16 deletions.
6 changes: 6 additions & 0 deletions src/Debug/debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,12 @@ void Debugger::printValue(StackValue *v, uint32_t idx, bool end = false) const {
snprintf(buff, 255, R"("type":"F64","value":"%)" PRIx64 "\"",
v->value.uint64);
break;
case V128:
// we'll just use hex-strings
// 64-bit = 8 bytes = 16 nibbles = 16 hex-characters
snprintf(buff, 255, R"("type":"V128","value":"%016lx%016lx")",
v->value.simd.i64x2[0], v->value.simd.i64x2[1]);
break;
default:
snprintf(buff, 255, R"("type":"%02x","value":"%)" PRIx64 "\"",
v->value_type, v->value.uint64);
Expand Down
15 changes: 8 additions & 7 deletions src/Interpreter/instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1336,25 +1336,25 @@ bool i_instr_simd_extract(Module* m, uint8_t opcode){
};

switch(opcode) { // TODO: we ignore the _s and _u for now...
case 0x15: // i8x16.extract_lane_s
case 0x15: // i8x16.extract_lane_s
case 0x16: // i8x16.extract_lane_u
return lane_handler(15, raw_top.value.simd.i8x16, raw_top.value.uint32, I32);

case 0x18: // i16x8.extract_lane_s
case 0x18: // i16x8.extract_lane_s
case 0x19: // i16x8.extract_lane_u
return lane_handler(8, raw_top.value.simd.i16x8, raw_top.value.uint32, I32);
return lane_handler(7, raw_top.value.simd.i16x8, raw_top.value.uint32, I32);

case 0x1b: // i32x4.extract_lane
return lane_handler(4, raw_top.value.simd.i32x4, raw_top.value.uint32, I32);
return lane_handler(3, raw_top.value.simd.i32x4, raw_top.value.uint32, I32);

case 0x1d: // i64x2.extract_lane
return lane_handler(2, raw_top.value.simd.i64x2, raw_top.value.uint64, I64);
return lane_handler(1, raw_top.value.simd.i64x2, raw_top.value.uint64, I64);

case 0x1f: // f32x4.extract_lane
return lane_handler(4, raw_top.value.simd.f32x4, raw_top.value.uint32, F32);
return lane_handler(3, raw_top.value.simd.f32x4, raw_top.value.uint32, F32);

case 0x21: // f64x2.extract_lane
return lane_handler(2, raw_top.value.simd.f64x2, raw_top.value.uint64, F64);
return lane_handler(1, raw_top.value.simd.f64x2, raw_top.value.uint64, F64);
}

return false;
Expand Down Expand Up @@ -1418,6 +1418,7 @@ bool i_instr_simd_const(Module* m){
m->sp++;
auto &v = m->stack[m->sp].value.simd;
std::memcpy(&v, data, 16);
m->stack[m->sp].value_type = V128;
return true;
}

Expand Down
5 changes: 5 additions & 0 deletions src/Utils/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ StackValue *readWasmArgs(Type function, uint8_t *data) {
data += sizeof(double);
break;
}
case V128: {
memcpy(&args[i].value.simd, data, 16 * sizeof(decltype(args[i].value.simd)));
data += sizeof(decltype(args[i].value.simd));
break;
}
default: {
FATAL("no argument of type %" SCNu8 "\n", args[i].value_type);
}
Expand Down
Binary file modified tests/latch/latch-0.3.0.tgz
Binary file not shown.
11 changes: 4 additions & 7 deletions tests/latch/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion tests/latch/src/spec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ spec.tests(tests);
framework.run([spec]);

// Helper function

function createTest(module: string, asserts: string[]): TestScenario {
const steps: Step[] = [];

Expand Down
73 changes: 73 additions & 0 deletions tests/latch/src/util/spec.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,75 @@ interface Cursor {
value: number;
}

// 8b -> 16 elems; pad 2
// 16b -> 8 elems, pad 4
// 32b -> 4 elems, pad 8
// 64b -> 2 elems, pad 16
// -> 128 / b elems; pad b / 4

function parseV128(type: string, args: string[]): string | undefined {
const int_lambda = (bit_width: number, mask: bigint): string|undefined => {
const elems = 128 / bit_width;
const pad_len = bit_width / 4;

if(args.length !== elems) return undefined;
return args
.map(str => str.replace(/_/gi, '')) // WASM allows _ in numbers, TS doesn't like those
.map(str => {
let start_idx = 0;
let sign = 1;
if(str.startsWith('-')) { sign = -1; start_idx = 1; }
else if(str.startsWith('+')) { start_idx = 1; }
return BigInt(sign) * BigInt(str.slice(start_idx))
}) // parse to (big)-int
.map(num => num & mask) // ensure correct bit width
.map(num => num.toString(16).padStart(pad_len, '0')) // convert to hex
.reduce((acc, val) => acc + val, ''); // concat
};

const float_lambda = (bit_width: number, mask: bigint, flt2bigint: (flt: number, ab: ArrayBuffer) => bigint): string|undefined => {
const elems = 128 / bit_width;
const pad_len = bit_width / 4;

if(args.length !== elems) return undefined;
return args
.map(str => str.replace(/_/gi, '')) // WASM allows _ in numbers, TS doesn't like those
.map(str => parseFloat(str)) // parse to float ~ might not accept all floats
.map(flt => {
const buf = new ArrayBuffer(bit_width / 8);
return flt2bigint(flt, buf) & mask;
})
.map(num => num.toString(16).padStart(pad_len, '0')) // convert to hex
.reduce((acc, str) => acc + str, ''); // concat
};

const flt32_lambda = (flt: number, ab: ArrayBuffer) => {
const fltBuffer = new Float32Array(ab);
fltBuffer[0] = flt;
const intBuffer = new Int32Array(ab);
return BigInt(intBuffer[0]);
};

const flt64_lambda = (flt: number, ab: ArrayBuffer) => {
const fltBuffer = new Float64Array(ab);
fltBuffer[0] = flt;
const intBuffer = new BigInt64Array(ab);
return intBuffer[0];
};

switch(type) {
case 'i8x16': return int_lambda(8, 0x00000000000000ffn);
case 'i16x8': return int_lambda(16, 0x000000000000ffffn);
case 'i32x4': return int_lambda(32, 0x00000000ffffffffn);
case 'i64x2': return int_lambda(64, 0xffffffffffffffffn);

case 'f32x4': return float_lambda(32, 0x00000000ffffffffn, flt32_lambda);
case 'f64x2': return float_lambda(64, 0xffffffffffffffffn, flt64_lambda);

default: return undefined;
}
}

export function parseResult(input: string): WASM.Value | undefined {
let cursor = 0;
let delta: number = consume(input, cursor, /\(/d);
Expand All @@ -22,6 +91,9 @@ export function parseResult(input: string): WASM.Value | undefined {
delta = consume(input, cursor, /^[^)]*/d);
if (type === WASM.Type.f32 || type === WASM.Type.f64) {
value = parseHexFloat(input.slice(cursor, cursor + delta));
} else if(type === WASM.Type.v128) {
const slice = input.slice(cursor, cursor + delta).split(' ').filter(x => x.trim() !== ''); // [dim, arg1, ...]
value = parseV128(slice[0], slice.slice(1));
} else {
value = parseInteger(input.slice(cursor, cursor + delta));
}
Expand All @@ -46,6 +118,7 @@ export function parseArguments(input: string, index: Cursor): WASM.Value[] {

delta = consume(input, cursor, /^[^.)]*/d);
const type: WASM.Type = WASM.typing.get(input.slice(cursor + delta - 3, cursor + delta)) ?? WASM.Type.i64;
// console.log(`arg #${args.length}.type: ${input.slice(cursor + delta - 3, cursor + delta)}`);

cursor += delta + consume(input, cursor + delta, /^[^)]*const /d);
delta = consume(input, cursor, /^[^)]*/d);
Expand Down
2 changes: 1 addition & 1 deletion tutorials/wat/main/simd.wat
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
(memory 1)

(func $run (type $void->void)
(v128.store (i32.const 0) (v128.const i16x8 1 2 3 4 5 6 7 8))
(v128.store (i32.const 0) (v128.const i16x8 -1 2 -3 4 -5 6 -7 8))

(v128.load (i32.const 0))
i16x8.extract_lane_s 0
Expand Down

0 comments on commit ce287be

Please sign in to comment.