From c443a7a57fab7118a9793b7f77b7ab817235a896 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 7 Dec 2024 14:42:30 -0800 Subject: [PATCH] wasm: move error_name lowering to Emit phase --- src/arch/wasm/CodeGen.zig | 10 ++-------- src/arch/wasm/Emit.zig | 37 +++++++++++++++++++++++++++++-------- src/arch/wasm/Mir.zig | 6 ++++++ 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 976b817b13..4fd5ee5c1e 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -5900,12 +5900,7 @@ fn airBitReverse(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { fn airErrorName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const operand = try cg.resolveInst(un_op); - // First retrieve the symbol index to the error name table - // that will be used to emit a relocation for the pointer - // to the error name table. - // // Each entry to this table is a slice (ptr+len). // The operand in this instruction represents the index within this table. // This means to get the final name, we emit the base pointer and then perform @@ -5914,12 +5909,11 @@ fn airErrorName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { // As the names are global and the slice elements are constant, we do not have // to make a copy of the ptr+value but can point towards them directly. const pt = cg.pt; - const error_table_symbol = try cg.wasm.getErrorTableSymbol(pt); const name_ty = Type.slice_const_u8_sentinel_0; const abi_size = name_ty.abiSize(pt.zcu); - const error_name_value: WValue = .{ .memory = error_table_symbol }; // emitting this will create a relocation - try cg.emitWValue(error_name_value); + // Lowers to a i32.const or i64.const with the error table memory address. + try cg.addTag(.error_name_table_ref); try cg.emitWValue(operand); switch (cg.ptr_size) { .wasm32 => { diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig index 55138a5dbe..20d45247a9 100644 --- a/src/arch/wasm/Emit.zig +++ b/src/arch/wasm/Emit.zig @@ -27,6 +27,8 @@ pub fn lowerToCode(emit: *Emit) Error!void { const comp = wasm.base.comp; const gpa = comp.gpa; const is_obj = comp.config.output_mode == .Obj; + const target = &comp.root_mod.resolved_target.result; + const is_wasm32 = target.cpu.arch == .wasm32; const tags = mir.instructions.items(.tag); const datas = mir.instructions.items(.data); @@ -56,12 +58,12 @@ pub fn lowerToCode(emit: *Emit) Error!void { continue :loop tags[inst]; }, .nav_ref => { - try navRefOff(wasm, code, .{ .ip_index = datas[inst].ip_index, .offset = 0 }); + try navRefOff(wasm, code, .{ .ip_index = datas[inst].ip_index, .offset = 0 }, is_wasm32); inst += 1; continue :loop tags[inst]; }, .nav_ref_off => { - try navRefOff(wasm, code, mir.extraData(Mir.NavRefOff, datas[inst].payload).data); + try navRefOff(wasm, code, mir.extraData(Mir.NavRefOff, datas[inst].payload).data, is_wasm32); inst += 1; continue :loop tags[inst]; }, @@ -80,6 +82,29 @@ pub fn lowerToCode(emit: *Emit) Error!void { inst += 1; continue :loop tags[inst]; }, + .error_name_table_ref => { + try code.ensureUnusedCapacity(gpa, 11); + const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; + code.appendAssumeCapacity(@intFromEnum(opcode)); + if (is_obj) { + try wasm.out_relocs.append(gpa, .{ + .offset = @intCast(code.items.len), + .index = try wasm.errorNameTableSymbolIndex(), + .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64, + .addend = 0, + }); + code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10); + + inst += 1; + continue :loop tags[inst]; + } else { + const addr = try wasm.errorNameTableAddr(); + leb.writeIleb128(code.fixedWriter(), addr) catch unreachable; + + inst += 1; + continue :loop tags[inst]; + } + }, .br_if, .br, .memory_grow, .memory_size => { try code.ensureUnusedCapacity(gpa, 11); code.appendAssumeCapacity(@intFromEnum(tags[inst])); @@ -607,11 +632,9 @@ fn encodeMemArg(code: *std.ArrayListUnmanaged(u8), mem_arg: Mir.MemArg) void { leb.writeUleb128(code.fixedWriter(), mem_arg.offset) catch unreachable; } -fn uavRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.UavRefOff) !void { +fn uavRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.UavRefOff, is_wasm32: bool) !void { const comp = wasm.base.comp; const gpa = comp.gpa; - const target = comp.root_mod.resolved_target.result; - const is_wasm32 = target.cpu.arch == .wasm32; const is_obj = comp.config.output_mode == .Obj; const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; @@ -636,13 +659,12 @@ fn uavRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable; } -fn navRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff) !void { +fn navRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff, is_wasm32: bool) !void { const comp = wasm.base.comp; const zcu = comp.zcu.?; const ip = &zcu.intern_pool; const gpa = comp.gpa; const is_obj = comp.config.output_mode == .Obj; - const target = &comp.root_mod.resolved_target.result; const nav_ty = ip.getNav(data.nav_index).typeOf(ip); try code.ensureUnusedCapacity(gpa, 11); @@ -663,7 +685,6 @@ fn navRefOff(wasm: *link.File.Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir leb.writeUleb128(code.fixedWriter(), addr + data.offset) catch unreachable; } } else { - const is_wasm32 = target.cpu.arch == .wasm32; const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; code.appendAssumeCapacity(@intFromEnum(opcode)); if (is_obj) { diff --git a/src/arch/wasm/Mir.zig b/src/arch/wasm/Mir.zig index fa74c0ee7e..54b427228e 100644 --- a/src/arch/wasm/Mir.zig +++ b/src/arch/wasm/Mir.zig @@ -88,6 +88,12 @@ pub const Inst = struct { /// names. /// Uses `tag`. errors_len, + /// Lowers to an i32_const (wasm32) or i64_const (wasm64) containing + /// the base address of the table of error code names, with each + /// element being a null-terminated slice. + /// + /// Uses `tag`. + error_name_table_ref, /// Represents the end of a function body or an initialization expression /// /// Uses `tag` (no additional data).