zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit c4b295bb6e9fcb1d02122cb70c95019c81ae543e (tree)
parent 21aa55d34e432b677f71cbb377aa89c8cdbd1483
Author: Luuk de Gram <luuk@degram.dev>
Date:   Sat, 15 Apr 2023 16:17:25 +0200

wasm: implement `cmp_lt_errors_len` instruction

Creates a global undefined symbol when this instruction is called.
The linker will then resolve it as a lazy symbol, ensuring it is
only generated when the symbol was created. In `flush` it will then
generate the function as only then, all errors are known and we can
generate the function body. This logic allows us to re-use the same
functionality of linker-synthetic-functions.

Diffstat:
Msrc/arch/wasm/CodeGen.zig | 8++++++--
Msrc/link/Wasm.zig | 45+++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig @@ -3338,9 +3338,13 @@ fn airCmpVector(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { fn airCmpLtErrorsLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const un_op = func.air.instructions.items(.data)[inst].un_op; const operand = try func.resolveInst(un_op); + const sym_index = try func.bin_file.getGlobalSymbol("__zig_lt_errors_len", null); - _ = operand; - return func.fail("TODO implement airCmpLtErrorsLen for wasm", .{}); + try func.emitWValue(operand); + try func.addLabel(.call, sym_index); + const result = try func.allocLocal(Type.bool); + try func.addLabel(.local_set, result.local.value); + return func.finishAir(inst, result, &.{un_op}); } fn airBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig @@ -1209,6 +1209,10 @@ fn resolveLazySymbols(wasm: *Wasm) !void { try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); } } + if (wasm.undefs.fetchSwapRemove("__zig_lt_errors_len")) |kv| { + const loc = try wasm.createSyntheticSymbol("__zig_lt_errors_len", .function); + try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); + } } // Tries to find a global symbol by its name. Returns null when not found, @@ -2185,6 +2189,46 @@ fn setupInitFunctions(wasm: *Wasm) !void { std.sort.sort(InitFuncLoc, wasm.init_funcs.items, {}, InitFuncLoc.lessThan); } +/// Generates the function which verifies if an integer value is less than the +/// amount of error values. This will only be generated if the symbol exists. +fn setupLtErrorsLenFunction(wasm: *Wasm) !void { + if (wasm.findGlobalSymbol("__zig_lt_errors_len") == null) return; + const errors_len = wasm.base.options.module.?.global_error_set.count(); + + var body_list = std.ArrayList(u8).init(wasm.base.allocator); + defer body_list.deinit(); + const writer = body_list.writer(); + + { + // generates bytecode for the following function: + // fn (index: u16) bool { + // return index < errors_len; + // } + + // no locals + try leb.writeULEB128(writer, @as(u32, 0)); + + // get argument + try writer.writeByte(std.wasm.opcode(.local_get)); + try leb.writeULEB128(writer, @as(u32, 0)); + + // get error length + try writer.writeByte(std.wasm.opcode(.i32_const)); + try leb.writeULEB128(writer, @intCast(u32, errors_len)); + + try writer.writeByte(std.wasm.opcode(.i32_lt_u)); + + // stack values are implicit return values so keep the value + // on the stack and end the function. + + // end function + try writer.writeByte(std.wasm.opcode(.end)); + } + + const func_type: std.wasm.Type = .{ .params = &.{std.wasm.Valtype.i32}, .returns = &.{std.wasm.Valtype.i32} }; + try wasm.createSyntheticFunction("__zig_lt_errors_len", func_type, &body_list); +} + /// Creates a function body for the `__wasm_call_ctors` symbol. /// Loops over all constructors found in `init_funcs` and calls them /// respectively based on their priority which was sorted by `setupInitFunctions`. @@ -3379,6 +3423,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod try wasm.setupInitMemoryFunction(); try wasm.setupTLSRelocationsFunction(); try wasm.initializeTLSFunction(); + try wasm.setupLtErrorsLenFunction(); try wasm.setupExports(); try wasm.writeToFile(enabled_features, emit_features_count, arena); }