| author | |
| committer | |
| log | 0d66112643286a754101eb71382f860ae1874012 |
| tree | 80fd56e6adff4e99cbc3638fc8f03a967b0be61e |
| parent | a52dcdd3c5ebd3a1d5a0189ded830dadd253193c |
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" { |
| 215 | 215 | } |
| 216 | 216 | |
| 217 | 217 | /// Opcodes that require a prefix `0xFC` |
| 218 | pub const PrefixedOpcode = enum(u8) { | |
| 218 | /// Each opcode represents a varuint32, meaning | |
| 219 | /// they are encoded as leb128 in binary. | |
| 220 | pub const PrefixedOpcode = enum(u32) { | |
| 219 | 221 | i32_trunc_sat_f32_s = 0x00, |
| 220 | 222 | i32_trunc_sat_f32_u = 0x01, |
| 221 | 223 | 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 { |
| 905 | 905 | } |
| 906 | 906 | |
| 907 | 907 | fn 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 } }); | |
| 909 | 911 | } |
| 910 | 912 | |
| 911 | 913 | fn 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 { |
| 423 | 423 | } |
| 424 | 424 | |
| 425 | 425 | fn 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); | |
| 427 | 431 | 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 | |
| 429 | 460 | else => |tag| return emit.fail("TODO: Implement extension instruction: {s}\n", .{@tagName(tag)}), |
| 430 | 461 | } |
| 431 | 462 | } |
src/arch/wasm/Mir.zig+4-6| ... | ... | @@ -19,9 +19,6 @@ extra: []const u32, |
| 19 | 19 | pub const Inst = struct { |
| 20 | 20 | /// The opcode that represents this instruction |
| 21 | 21 | 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, | |
| 25 | 22 | /// Data is determined by the set `tag`. |
| 26 | 23 | /// For example, `data` will be an i32 for when `tag` is 'i32_const'. |
| 27 | 24 | data: Data, |
| ... | ... | @@ -513,10 +510,11 @@ pub const Inst = struct { |
| 513 | 510 | i64_extend16_s = 0xC3, |
| 514 | 511 | /// Uses `tag` |
| 515 | 512 | 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. | |
| 518 | 515 | /// |
| 519 | /// The `data` field depends on the extension instruction | |
| 516 | /// The `data` field depends on the extension instruction and | |
| 517 | /// may contain additional data. | |
| 520 | 518 | extended = 0xFC, |
| 521 | 519 | /// The instruction consists of a simd opcode. |
| 522 | 520 | /// The actual simd-opcode is found at payload's index. |