authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-12-20 19:18:09+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-12-21 17:02:53+01:00
log0d66112643286a754101eb71382f860ae1874012
tree80fd56e6adff4e99cbc3638fc8f03a967b0be61e
parenta52dcdd3c5ebd3a1d5a0189ded830dadd253193c

wasm: refactor extended instructions

The extended instructions starting with opcode `0xFC` are refactored to make the work the same as the SIMD instructions. This means a `Mir` instruction no longer contains a field 'secondary'. Instead, we use the `payload` field to store the index into the extra list which contains the extended opcode value. In case of instructions such as 'memory.fill' which also have an immediate value, such values will also be stored in the extra list right after the instruction itself. This makes each `Mir` instruction smaller.

4 files changed, 43 insertions(+), 10 deletions(-)

lib/std/wasm.zig+3-1
......@@ -215,7 +215,9 @@ test "Wasm - opcodes" {
215215}
216216
217217/// Opcodes that require a prefix `0xFC`
218pub const PrefixedOpcode = enum(u8) {
218/// Each opcode represents a varuint32, meaning
219/// they are encoded as leb128 in binary.
220pub const PrefixedOpcode = enum(u32) {
219221 i32_trunc_sat_f32_s = 0x00,
220222 i32_trunc_sat_f32_u = 0x01,
221223 i32_trunc_sat_f64_s = 0x02,
src/arch/wasm/CodeGen.zig+3-1
......@@ -905,7 +905,9 @@ fn addTag(func: *CodeGen, tag: Mir.Inst.Tag) error{OutOfMemory}!void {
905905}
906906
907907fn addExtended(func: *CodeGen, opcode: wasm.PrefixedOpcode) error{OutOfMemory}!void {
908 try func.addInst(.{ .tag = .extended, .secondary = @enumToInt(opcode), .data = .{ .tag = {} } });
908 const extra_index = @intCast(u32, func.mir_extra.items.len);
909 try func.mir_extra.append(func.gpa, @enumToInt(opcode));
910 try func.addInst(.{ .tag = .extended, .data = .{ .payload = extra_index } });
909911}
910912
911913fn addLabel(func: *CodeGen, tag: Mir.Inst.Tag, label: u32) error{OutOfMemory}!void {
src/arch/wasm/Emit.zig+33-2
......@@ -423,9 +423,40 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {
423423}
424424
425425fn emitExtended(emit: *Emit, inst: Mir.Inst.Index) !void {
426 const opcode = emit.mir.instructions.items(.secondary)[inst];
426 const extra_index = emit.mir.instructions.items(.data)[inst].payload;
427 const opcode = emit.mir.extra[extra_index];
428 const writer = emit.code.writer();
429 try emit.code.append(0xFC);
430 try leb128.writeULEB128(writer, opcode);
427431 switch (@intToEnum(std.wasm.PrefixedOpcode, opcode)) {
428 .memory_fill => try emit.emitMemFill(),
432 // bulk-memory opcodes
433 .data_drop => {
434 const segment = emit.mir.extra[extra_index + 1];
435 try leb128.writeULEB128(writer, segment);
436 },
437 .memory_init => {
438 const segment = emit.mir.extra[extra_index + 1];
439 try leb128.writeULEB128(writer, segment);
440 try leb128.writeULEB128(writer, @as(u32, 0)); // memory index
441 },
442 .memory_fill => {
443 try leb128.writeULEB128(writer, @as(u32, 0)); // memory index
444 },
445 .memory_copy => {
446 try leb128.writeULEB128(writer, @as(u32, 0)); // dst memory index
447 try leb128.writeULEB128(writer, @as(u32, 0)); // src memory index
448 },
449
450 // nontrapping-float-to-int-conversion opcodes
451 .i32_trunc_sat_f32_s,
452 .i32_trunc_sat_f32_u,
453 .i32_trunc_sat_f64_s,
454 .i32_trunc_sat_f64_u,
455 .i64_trunc_sat_f32_s,
456 .i64_trunc_sat_f32_u,
457 .i64_trunc_sat_f64_s,
458 .i64_trunc_sat_f64_u,
459 => {}, // opcode already written
429460 else => |tag| return emit.fail("TODO: Implement extension instruction: {s}\n", .{@tagName(tag)}),
430461 }
431462}
src/arch/wasm/Mir.zig+4-6
......@@ -19,9 +19,6 @@ extra: []const u32,
1919pub const Inst = struct {
2020 /// The opcode that represents this instruction
2121 tag: Tag,
22 /// This opcode will be set when `tag` represents an extended
23 /// instruction with prefix 0xFC, or a simd instruction with prefix 0xFD.
24 secondary: u8 = 0,
2522 /// Data is determined by the set `tag`.
2623 /// For example, `data` will be an i32 for when `tag` is 'i32_const'.
2724 data: Data,
......@@ -513,10 +510,11 @@ pub const Inst = struct {
513510 i64_extend16_s = 0xC3,
514511 /// Uses `tag`
515512 i64_extend32_s = 0xC4,
516 /// The instruction consists of an extension opcode
517 /// set in `secondary`
513 /// The instruction consists of an extension opcode.
514 /// The prefixed opcode can be found at payload's index.
518515 ///
519 /// The `data` field depends on the extension instruction
516 /// The `data` field depends on the extension instruction and
517 /// may contain additional data.
520518 extended = 0xFC,
521519 /// The instruction consists of a simd opcode.
522520 /// The actual simd-opcode is found at payload's index.