| ... | ... | @@ -3,7 +3,7 @@ const Emit = @This(); |
| 3 | 3 | const std = @import("std"); |
| 4 | 4 | const assert = std.debug.assert; |
| 5 | 5 | const Allocator = std.mem.Allocator; |
| 6 | | const leb = std.leb; |
| 6 | const ArrayList = std.ArrayList; |
| 7 | 7 | |
| 8 | 8 | const Wasm = link.File.Wasm; |
| 9 | 9 | const Mir = @import("Mir.zig"); |
| ... | ... | @@ -15,7 +15,7 @@ const codegen = @import("../../codegen.zig"); |
| 15 | 15 | mir: Mir, |
| 16 | 16 | wasm: *Wasm, |
| 17 | 17 | /// The binary representation that will be emitted by this module. |
| 18 | | code: *std.ArrayListUnmanaged(u8), |
| 18 | code: *ArrayList(u8), |
| 19 | 19 | |
| 20 | 20 | pub const Error = error{ |
| 21 | 21 | OutOfMemory, |
| ... | ... | @@ -85,7 +85,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 85 | 85 | if (is_obj) { |
| 86 | 86 | @panic("TODO"); |
| 87 | 87 | } else { |
| 88 | | leb.writeUleb128(code.fixedWriter(), 1 + @intFromEnum(indirect_func_idx)) catch unreachable; |
| 88 | writeUleb128(code, 1 + @intFromEnum(indirect_func_idx)); |
| 89 | 89 | } |
| 90 | 90 | inst += 1; |
| 91 | 91 | continue :loop tags[inst]; |
| ... | ... | @@ -99,7 +99,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 99 | 99 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 100 | 100 | // MIR is lowered during flush, so there is indeed only one thread at this time. |
| 101 | 101 | const errors_len = 1 + comp.zcu.?.intern_pool.global_error_set.getNamesFromMainThread().len; |
| 102 | | leb.writeIleb128(code.fixedWriter(), errors_len) catch unreachable; |
| 102 | writeSleb128(code, errors_len); |
| 103 | 103 | |
| 104 | 104 | inst += 1; |
| 105 | 105 | continue :loop tags[inst]; |
| ... | ... | @@ -122,7 +122,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 122 | 122 | continue :loop tags[inst]; |
| 123 | 123 | } else { |
| 124 | 124 | const addr: u32 = wasm.errorNameTableAddr(); |
| 125 | | leb.writeIleb128(code.fixedWriter(), addr) catch unreachable; |
| 125 | writeSleb128(code, addr); |
| 126 | 126 | |
| 127 | 127 | inst += 1; |
| 128 | 128 | continue :loop tags[inst]; |
| ... | ... | @@ -131,7 +131,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 131 | 131 | .br_if, .br, .memory_grow, .memory_size => { |
| 132 | 132 | try code.ensureUnusedCapacity(gpa, 11); |
| 133 | 133 | code.appendAssumeCapacity(@intFromEnum(tags[inst])); |
| 134 | | leb.writeUleb128(code.fixedWriter(), datas[inst].label) catch unreachable; |
| 134 | writeUleb128(code, datas[inst].label); |
| 135 | 135 | |
| 136 | 136 | inst += 1; |
| 137 | 137 | continue :loop tags[inst]; |
| ... | ... | @@ -140,7 +140,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 140 | 140 | .local_get, .local_set, .local_tee => { |
| 141 | 141 | try code.ensureUnusedCapacity(gpa, 11); |
| 142 | 142 | code.appendAssumeCapacity(@intFromEnum(tags[inst])); |
| 143 | | leb.writeUleb128(code.fixedWriter(), datas[inst].local) catch unreachable; |
| 143 | writeUleb128(code, datas[inst].local); |
| 144 | 144 | |
| 145 | 145 | inst += 1; |
| 146 | 146 | continue :loop tags[inst]; |
| ... | ... | @@ -153,8 +153,8 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 153 | 153 | try code.ensureUnusedCapacity(gpa, 11 + 10 * labels.len); |
| 154 | 154 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.br_table)); |
| 155 | 155 | // -1 because default label is not part of length/depth. |
| 156 | | leb.writeUleb128(code.fixedWriter(), extra.data.length - 1) catch unreachable; |
| 157 | | for (labels) |label| leb.writeUleb128(code.fixedWriter(), label) catch unreachable; |
| 156 | writeUleb128(code, extra.data.length - 1); |
| 157 | for (labels) |label| writeUleb128(code, label); |
| 158 | 158 | |
| 159 | 159 | inst += 1; |
| 160 | 160 | continue :loop tags[inst]; |
| ... | ... | @@ -199,9 +199,9 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 199 | 199 | code.appendNTimesAssumeCapacity(0, 5); |
| 200 | 200 | } else { |
| 201 | 201 | const index: Wasm.Flush.FuncTypeIndex = .fromTypeIndex(func_ty_index, &wasm.flush_buffer); |
| 202 | | leb.writeUleb128(code.fixedWriter(), @intFromEnum(index)) catch unreachable; |
| 202 | writeUleb128(code, @intFromEnum(index)); |
| 203 | 203 | } |
| 204 | | leb.writeUleb128(code.fixedWriter(), @as(u32, 0)) catch unreachable; // table index |
| 204 | writeUleb128(code, @as(u32, 0)); // table index |
| 205 | 205 | |
| 206 | 206 | inst += 1; |
| 207 | 207 | continue :loop tags[inst]; |
| ... | ... | @@ -263,7 +263,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 263 | 263 | code.appendNTimesAssumeCapacity(0, 5); |
| 264 | 264 | } else { |
| 265 | 265 | const sp_global: Wasm.GlobalIndex = .stack_pointer; |
| 266 | | std.leb.writeUleb128(code.fixedWriter(), @intFromEnum(sp_global)) catch unreachable; |
| 266 | writeUleb128(code, @intFromEnum(sp_global)); |
| 267 | 267 | } |
| 268 | 268 | |
| 269 | 269 | inst += 1; |
| ... | ... | @@ -291,7 +291,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 291 | 291 | .i32_const => { |
| 292 | 292 | try code.ensureUnusedCapacity(gpa, 6); |
| 293 | 293 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 294 | | leb.writeIleb128(code.fixedWriter(), datas[inst].imm32) catch unreachable; |
| 294 | writeSleb128(code, datas[inst].imm32); |
| 295 | 295 | |
| 296 | 296 | inst += 1; |
| 297 | 297 | continue :loop tags[inst]; |
| ... | ... | @@ -300,7 +300,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 300 | 300 | try code.ensureUnusedCapacity(gpa, 11); |
| 301 | 301 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const)); |
| 302 | 302 | const int64: i64 = @bitCast(mir.extraData(Mir.Imm64, datas[inst].payload).data.toInt()); |
| 303 | | leb.writeIleb128(code.fixedWriter(), int64) catch unreachable; |
| 303 | writeSleb128(code, int64); |
| 304 | 304 | |
| 305 | 305 | inst += 1; |
| 306 | 306 | continue :loop tags[inst]; |
| ... | ... | @@ -476,33 +476,33 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 476 | 476 | const extra_index = datas[inst].payload; |
| 477 | 477 | const opcode = mir.extra[extra_index]; |
| 478 | 478 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.misc_prefix)); |
| 479 | | leb.writeUleb128(code.fixedWriter(), opcode) catch unreachable; |
| 479 | writeUleb128(code, opcode); |
| 480 | 480 | switch (@as(std.wasm.MiscOpcode, @enumFromInt(opcode))) { |
| 481 | 481 | // bulk-memory opcodes |
| 482 | 482 | .data_drop => { |
| 483 | 483 | const segment = mir.extra[extra_index + 1]; |
| 484 | | leb.writeUleb128(code.fixedWriter(), segment) catch unreachable; |
| 484 | writeUleb128(code, segment); |
| 485 | 485 | |
| 486 | 486 | inst += 1; |
| 487 | 487 | continue :loop tags[inst]; |
| 488 | 488 | }, |
| 489 | 489 | .memory_init => { |
| 490 | 490 | const segment = mir.extra[extra_index + 1]; |
| 491 | | leb.writeUleb128(code.fixedWriter(), segment) catch unreachable; |
| 492 | | leb.writeUleb128(code.fixedWriter(), @as(u32, 0)) catch unreachable; // memory index |
| 491 | writeUleb128(code, segment); |
| 492 | writeUleb128(code, @as(u32, 0)); // memory index |
| 493 | 493 | |
| 494 | 494 | inst += 1; |
| 495 | 495 | continue :loop tags[inst]; |
| 496 | 496 | }, |
| 497 | 497 | .memory_fill => { |
| 498 | | leb.writeUleb128(code.fixedWriter(), @as(u32, 0)) catch unreachable; // memory index |
| 498 | writeUleb128(code, @as(u32, 0)); // memory index |
| 499 | 499 | |
| 500 | 500 | inst += 1; |
| 501 | 501 | continue :loop tags[inst]; |
| 502 | 502 | }, |
| 503 | 503 | .memory_copy => { |
| 504 | | leb.writeUleb128(code.fixedWriter(), @as(u32, 0)) catch unreachable; // dst memory index |
| 505 | | leb.writeUleb128(code.fixedWriter(), @as(u32, 0)) catch unreachable; // src memory index |
| 504 | writeUleb128(code, @as(u32, 0)); // dst memory index |
| 505 | writeUleb128(code, @as(u32, 0)); // src memory index |
| 506 | 506 | |
| 507 | 507 | inst += 1; |
| 508 | 508 | continue :loop tags[inst]; |
| ... | ... | @@ -538,7 +538,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 538 | 538 | const extra_index = datas[inst].payload; |
| 539 | 539 | const opcode = mir.extra[extra_index]; |
| 540 | 540 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.simd_prefix)); |
| 541 | | leb.writeUleb128(code.fixedWriter(), opcode) catch unreachable; |
| 541 | writeUleb128(code, opcode); |
| 542 | 542 | switch (@as(std.wasm.SimdOpcode, @enumFromInt(opcode))) { |
| 543 | 543 | .v128_store, |
| 544 | 544 | .v128_load, |
| ... | ... | @@ -824,7 +824,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 824 | 824 | const extra_index = datas[inst].payload; |
| 825 | 825 | const opcode = mir.extra[extra_index]; |
| 826 | 826 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix)); |
| 827 | | leb.writeUleb128(code.fixedWriter(), opcode) catch unreachable; |
| 827 | writeUleb128(code, opcode); |
| 828 | 828 | switch (@as(std.wasm.AtomicsOpcode, @enumFromInt(opcode))) { |
| 829 | 829 | .i32_atomic_load, |
| 830 | 830 | .i64_atomic_load, |
| ... | ... | @@ -900,7 +900,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 900 | 900 | // Hard-codes memory index 0 since multi-memory proposal is |
| 901 | 901 | // not yet accepted nor implemented. |
| 902 | 902 | const memory_index: u32 = 0; |
| 903 | | leb.writeUleb128(code.fixedWriter(), memory_index) catch unreachable; |
| 903 | writeUleb128(code, memory_index); |
| 904 | 904 | inst += 1; |
| 905 | 905 | continue :loop tags[inst]; |
| 906 | 906 | }, |
| ... | ... | @@ -915,15 +915,15 @@ pub fn lowerToCode(emit: *Emit) Error!void { |
| 915 | 915 | } |
| 916 | 916 | |
| 917 | 917 | /// Asserts 20 unused capacity. |
| 918 | | fn encodeMemArg(code: *std.ArrayListUnmanaged(u8), mem_arg: Mir.MemArg) void { |
| 918 | fn encodeMemArg(code: *ArrayList(u8), mem_arg: Mir.MemArg) void { |
| 919 | 919 | assert(code.unusedCapacitySlice().len >= 20); |
| 920 | 920 | // Wasm encodes alignment as power of 2, rather than natural alignment. |
| 921 | 921 | const encoded_alignment = @ctz(mem_arg.alignment); |
| 922 | | leb.writeUleb128(code.fixedWriter(), encoded_alignment) catch unreachable; |
| 923 | | leb.writeUleb128(code.fixedWriter(), mem_arg.offset) catch unreachable; |
| 922 | writeUleb128(code, encoded_alignment); |
| 923 | writeUleb128(code, mem_arg.offset); |
| 924 | 924 | } |
| 925 | 925 | |
| 926 | | fn uavRefObj(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), value: InternPool.Index, offset: i32, is_wasm32: bool) !void { |
| 926 | fn uavRefObj(wasm: *Wasm, code: *ArrayList(u8), value: InternPool.Index, offset: i32, is_wasm32: bool) !void { |
| 927 | 927 | const comp = wasm.base.comp; |
| 928 | 928 | const gpa = comp.gpa; |
| 929 | 929 | const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; |
| ... | ... | @@ -940,7 +940,7 @@ fn uavRefObj(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), value: InternPool.I |
| 940 | 940 | code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10); |
| 941 | 941 | } |
| 942 | 942 | |
| 943 | | fn uavRefExe(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), value: InternPool.Index, offset: i32, is_wasm32: bool) !void { |
| 943 | fn uavRefExe(wasm: *Wasm, code: *ArrayList(u8), value: InternPool.Index, offset: i32, is_wasm32: bool) !void { |
| 944 | 944 | const comp = wasm.base.comp; |
| 945 | 945 | const gpa = comp.gpa; |
| 946 | 946 | const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; |
| ... | ... | @@ -949,10 +949,10 @@ fn uavRefExe(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), value: InternPool.I |
| 949 | 949 | code.appendAssumeCapacity(@intFromEnum(opcode)); |
| 950 | 950 | |
| 951 | 951 | const addr = wasm.uavAddr(value); |
| 952 | | leb.writeUleb128(code.fixedWriter(), @as(u32, @intCast(@as(i64, addr) + offset))) catch unreachable; |
| 952 | writeUleb128(code, @as(u32, @intCast(@as(i64, addr) + offset))); |
| 953 | 953 | } |
| 954 | 954 | |
| 955 | | fn navRefOff(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff, is_wasm32: bool) !void { |
| 955 | fn navRefOff(wasm: *Wasm, code: *ArrayList(u8), data: Mir.NavRefOff, is_wasm32: bool) !void { |
| 956 | 956 | const comp = wasm.base.comp; |
| 957 | 957 | const zcu = comp.zcu.?; |
| 958 | 958 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -975,10 +975,22 @@ fn navRefOff(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff |
| 975 | 975 | code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10); |
| 976 | 976 | } else { |
| 977 | 977 | const addr = wasm.navAddr(data.nav_index); |
| 978 | | leb.writeUleb128(code.fixedWriter(), @as(u32, @intCast(@as(i64, addr) + data.offset))) catch unreachable; |
| 978 | writeUleb128(code, @as(u32, @intCast(@as(i64, addr) + data.offset))); |
| 979 | 979 | } |
| 980 | 980 | } |
| 981 | 981 | |
| 982 | | fn appendOutputFunctionIndex(code: *std.ArrayListUnmanaged(u8), i: Wasm.OutputFunctionIndex) void { |
| 983 | | leb.writeUleb128(code.fixedWriter(), @intFromEnum(i)) catch unreachable; |
| 982 | fn appendOutputFunctionIndex(code: *ArrayList(u8), i: Wasm.OutputFunctionIndex) void { |
| 983 | writeUleb128(code, @intFromEnum(i)); |
| 984 | } |
| 985 | |
| 986 | fn writeUleb128(code: *ArrayList(u8), arg: anytype) void { |
| 987 | var w: std.Io.Writer = .fixed(code.unusedCapacitySlice()); |
| 988 | w.writeUleb128(arg) catch unreachable; |
| 989 | code.items.len += w.end; |
| 990 | } |
| 991 | |
| 992 | fn writeSleb128(code: *ArrayList(u8), arg: anytype) void { |
| 993 | var w: std.Io.Writer = .fixed(code.unusedCapacitySlice()); |
| 994 | w.writeSleb128(arg) catch unreachable; |
| 995 | code.items.len += w.end; |
| 984 | 996 | } |