From 0d66112643286a754101eb71382f860ae1874012 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Tue, 20 Dec 2022 19:18:09 +0100 Subject: [PATCH] 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. --- lib/std/wasm.zig | 4 +++- src/arch/wasm/CodeGen.zig | 4 +++- src/arch/wasm/Emit.zig | 35 +++++++++++++++++++++++++++++++++-- src/arch/wasm/Mir.zig | 10 ++++------ 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/lib/std/wasm.zig b/lib/std/wasm.zig index 0e61b3fb3007b42b9d3e2a948b78cd7ea9c02941..2d519ace8b20860666be14bedbed9adb4678e531 100644 --- a/lib/std/wasm.zig +++ b/lib/std/wasm.zig @@ -215,7 +215,9 @@ test "Wasm - opcodes" { } /// Opcodes that require a prefix `0xFC` -pub const PrefixedOpcode = enum(u8) { +/// Each opcode represents a varuint32, meaning +/// they are encoded as leb128 in binary. +pub const PrefixedOpcode = enum(u32) { i32_trunc_sat_f32_s = 0x00, i32_trunc_sat_f32_u = 0x01, i32_trunc_sat_f64_s = 0x02, diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index ed7f0303deea60ddbc09454b98f43d61dd56a208..21d792697899d2fdf6f579aa46f362ffabe2184f 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -905,7 +905,9 @@ fn addTag(func: *CodeGen, tag: Mir.Inst.Tag) error{OutOfMemory}!void { } fn addExtended(func: *CodeGen, opcode: wasm.PrefixedOpcode) error{OutOfMemory}!void { - try func.addInst(.{ .tag = .extended, .secondary = @enumToInt(opcode), .data = .{ .tag = {} } }); + const extra_index = @intCast(u32, func.mir_extra.items.len); + try func.mir_extra.append(func.gpa, @enumToInt(opcode)); + try func.addInst(.{ .tag = .extended, .data = .{ .payload = extra_index } }); } fn addLabel(func: *CodeGen, tag: Mir.Inst.Tag, label: u32) error{OutOfMemory}!void { diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig index 45e02e0986668f5dadf3e04462c77e33f06ff63a..71d21d2797e7341c0d2cfe98f8d0513c717dc7c9 100644 --- a/src/arch/wasm/Emit.zig +++ b/src/arch/wasm/Emit.zig @@ -423,9 +423,40 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void { } fn emitExtended(emit: *Emit, inst: Mir.Inst.Index) !void { - const opcode = emit.mir.instructions.items(.secondary)[inst]; + const extra_index = emit.mir.instructions.items(.data)[inst].payload; + const opcode = emit.mir.extra[extra_index]; + const writer = emit.code.writer(); + try emit.code.append(0xFC); + try leb128.writeULEB128(writer, opcode); switch (@intToEnum(std.wasm.PrefixedOpcode, opcode)) { - .memory_fill => try emit.emitMemFill(), + // bulk-memory opcodes + .data_drop => { + const segment = emit.mir.extra[extra_index + 1]; + try leb128.writeULEB128(writer, segment); + }, + .memory_init => { + const segment = emit.mir.extra[extra_index + 1]; + try leb128.writeULEB128(writer, segment); + try leb128.writeULEB128(writer, @as(u32, 0)); // memory index + }, + .memory_fill => { + try leb128.writeULEB128(writer, @as(u32, 0)); // memory index + }, + .memory_copy => { + try leb128.writeULEB128(writer, @as(u32, 0)); // dst memory index + try leb128.writeULEB128(writer, @as(u32, 0)); // src memory index + }, + + // nontrapping-float-to-int-conversion opcodes + .i32_trunc_sat_f32_s, + .i32_trunc_sat_f32_u, + .i32_trunc_sat_f64_s, + .i32_trunc_sat_f64_u, + .i64_trunc_sat_f32_s, + .i64_trunc_sat_f32_u, + .i64_trunc_sat_f64_s, + .i64_trunc_sat_f64_u, + => {}, // opcode already written else => |tag| return emit.fail("TODO: Implement extension instruction: {s}\n", .{@tagName(tag)}), } } diff --git a/src/arch/wasm/Mir.zig b/src/arch/wasm/Mir.zig index 66969a9c218acc258d25b5baa8247ad41f12e284..2d59c09e186b5b3fb78999c85b442cc1e5dfb624 100644 --- a/src/arch/wasm/Mir.zig +++ b/src/arch/wasm/Mir.zig @@ -19,9 +19,6 @@ extra: []const u32, pub const Inst = struct { /// The opcode that represents this instruction tag: Tag, - /// This opcode will be set when `tag` represents an extended - /// instruction with prefix 0xFC, or a simd instruction with prefix 0xFD. - secondary: u8 = 0, /// Data is determined by the set `tag`. /// For example, `data` will be an i32 for when `tag` is 'i32_const'. data: Data, @@ -513,10 +510,11 @@ pub const Inst = struct { i64_extend16_s = 0xC3, /// Uses `tag` i64_extend32_s = 0xC4, - /// The instruction consists of an extension opcode - /// set in `secondary` + /// The instruction consists of an extension opcode. + /// The prefixed opcode can be found at payload's index. /// - /// The `data` field depends on the extension instruction + /// The `data` field depends on the extension instruction and + /// may contain additional data. extended = 0xFC, /// The instruction consists of a simd opcode. /// The actual simd-opcode is found at payload's index. -- 2.54.0