From 74a5f4d848a48e3dde8bb43cfa5b36e89aa86dfe Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Sat, 4 Dec 2021 19:38:56 +0100 Subject: wasm: Initial behavior tests succeeding Note: This also fixes a memory leak for inferred error sets, and for usingnamespace --- src/Module.zig | 12 ++++++++---- src/arch/wasm/CodeGen.zig | 45 +++++++++++++++++++++++++++++++-------------- src/arch/wasm/Emit.zig | 18 +++++++++++++++++- src/arch/wasm/Mir.zig | 10 ++++++++-- 4 files changed, 64 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/Module.zig b/src/Module.zig index 7ef9a02e09..7fa91486d3 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1226,19 +1226,20 @@ pub const Fn = struct { }; pub fn deinit(func: *Fn, gpa: Allocator) void { - if (func.getInferredErrorSet()) |map| { - map.deinit(gpa); + if (func.getInferredErrorSet()) |error_set_data| { + error_set_data.map.deinit(gpa); + error_set_data.functions.deinit(gpa); } } - pub fn getInferredErrorSet(func: *Fn) ?*std.StringHashMapUnmanaged(void) { + pub fn getInferredErrorSet(func: *Fn) ?*Type.Payload.ErrorSetInferred.Data { const ret_ty = func.owner_decl.ty.fnReturnType(); if (ret_ty.tag() == .generic_poison) { return null; } if (ret_ty.zigTypeTag() == .ErrorUnion) { if (ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| { - return &payload.data.map; + return &payload.data; } } return null; @@ -1301,6 +1302,7 @@ pub const Namespace = struct { key.destroy(mod); } anon_decls.deinit(gpa); + ns.usingnamespace_set.deinit(gpa); } pub fn deleteAllDecls( @@ -1332,6 +1334,8 @@ pub const Namespace = struct { child_decl.destroy(mod); } anon_decls.deinit(gpa); + + ns.usingnamespace_set.deinit(gpa); } // This renders e.g. "std.fs.Dir.OpenOptions" diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 1f7dd85f47..92b1bf4498 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1235,15 +1235,15 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { // local, containing the offset to the stack position const local = try self.allocLocal(Type.initTag(.i32)); // always pointer therefore i32 try self.moveStack(@intCast(u32, abi_size), local.local); - return local; } fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { const un_op = self.air.instructions.items(.data)[inst].un_op; const operand = self.resolveInst(un_op); - const result = try self.load(operand, self.air.typeOf(un_op), 0); - try self.addLabel(.local_get, result.local); + + const result = try self.load(operand, self.air.typeOf(un_op).childType(), 0); + try self.emitWValue(result); try self.restoreStackPointer(); try self.addTag(.@"return"); return .none; @@ -1301,8 +1301,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { // so load its value onto the stack std.debug.assert(ty.zigTypeTag() == .Pointer); const operand = self.resolveInst(pl_op.operand); - try self.emitWValue(operand); - const result = try self.load(operand, fn_ty, operand.local_with_offset.offset); + const offset = switch (operand) { + .local_with_offset => |with_offset| with_offset.offset, + else => @as(u32, 0), + }; + const result = try self.load(operand, fn_ty, offset); try self.addLabel(.local_get, result.local); var fn_type = try self.genFunctype(fn_ty); @@ -1335,7 +1338,6 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) InnerError!WValue { // local, containing the offset to the stack position const local = try self.allocLocal(Type.initTag(.i32)); // always pointer therefore i32 try self.moveStack(@intCast(u32, abi_size), local.local); - return local; } @@ -1470,6 +1472,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { const operand = self.resolveInst(ty_op.operand); const ty = self.air.getRefType(ty_op.ty); + if (!ty.hasCodeGenBits()) return WValue{ .none = {} }; + return switch (ty.zigTypeTag()) { .Struct, .ErrorUnion, .Optional, .Pointer => operand, // pass as pointer else => switch (operand) { @@ -1632,7 +1636,14 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void { } else if (val.castTag(.decl_ref)) |payload| { const decl = payload.data; decl.alive = true; - try self.addLabel(.memory_address, decl.link.wasm.sym_index); + // Function pointers use a table index, rather than a memory address + if (decl.ty.zigTypeTag() == .Fn) { + const target_sym_index = decl.link.wasm.sym_index; + try self.bin_file.addTableFunction(target_sym_index); + try self.addLabel(.function_index, target_sym_index); + } else { + try self.addLabel(.memory_address, decl.link.wasm.sym_index); + } } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{val.tag()}); }, .Void => {}, @@ -1873,7 +1884,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner }); try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); - const cmp_tmp = try self.allocLocal(lhs_ty); + const cmp_tmp = try self.allocLocal(Type.initTag(.i32)); // bool is always i32 try self.addLabel(.local_set, cmp_tmp.local); return cmp_tmp; } @@ -2200,20 +2211,26 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue { const operand = self.resolveInst(ty_op.operand); const ref_ty = self.air.typeOf(ty_op.operand); const ref_info = ref_ty.intInfo(self.target); - const op_bits = ref_info.bits; - const wanted_bits = ty.intInfo(self.target).bits; + const wanted_info = ty.intInfo(self.target); + + const op_bits = toWasmIntBits(ref_info.bits) orelse + return self.fail("TODO: Wasm intcast integer types of bitsize: {d}", .{ref_info.bits}); + const wanted_bits = toWasmIntBits(wanted_info.bits) orelse + return self.fail("TODO: Wasm intcast integer types of bitsize: {d}", .{wanted_info.bits}); - if (op_bits > 32 and wanted_bits <= 32) { + // hot path + if (op_bits == wanted_bits) return operand; + + if (op_bits > 32 and wanted_bits == 32) { try self.emitWValue(operand); try self.addTag(.i32_wrap_i64); - } else if (op_bits <= 32 and wanted_bits > 32) { + } else if (op_bits == 32 and wanted_bits > 32) { try self.emitWValue(operand); try self.addTag(switch (ref_info.signedness) { .signed => .i64_extend_i32_s, .unsigned => .i64_extend_i32_u, }); - } else return operand; - + } const result = try self.allocLocal(ty); try self.addLabel(.local_set, result.local); return result; diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig index 63080075d6..346ba1b6a0 100644 --- a/src/arch/wasm/Emit.zig +++ b/src/arch/wasm/Emit.zig @@ -50,6 +50,7 @@ pub fn emitMir(emit: *Emit) InnerError!void { .call_indirect => try emit.emitCallIndirect(inst), .global_get => try emit.emitGlobal(tag, inst), .global_set => try emit.emitGlobal(tag, inst), + .function_index => try emit.emitFunctionIndex(inst), .memory_address => try emit.emitMemAddress(inst), // immediates @@ -240,7 +241,7 @@ fn emitImm64(emit: *Emit, inst: Mir.Inst.Index) !void { const extra_index = emit.mir.instructions.items(.data)[inst].payload; const value = emit.mir.extraData(Mir.Imm64, extra_index); try emit.code.append(std.wasm.opcode(.i64_const)); - try leb128.writeULEB128(emit.code.writer(), value.data.toU64()); + try leb128.writeILEB128(emit.code.writer(), @bitCast(i64, value.data.toU64())); } fn emitFloat32(emit: *Emit, inst: Mir.Inst.Index) !void { @@ -289,6 +290,21 @@ fn emitCallIndirect(emit: *Emit, inst: Mir.Inst.Index) !void { try leb128.writeULEB128(emit.code.writer(), label); } +fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void { + const symbol_index = emit.mir.instructions.items(.data)[inst].label; + try emit.code.append(std.wasm.opcode(.i32_const)); + const index_offset = emit.offset(); + var buf: [5]u8 = undefined; + leb128.writeUnsignedFixed(5, &buf, symbol_index); + try emit.code.appendSlice(&buf); + + try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{ + .offset = index_offset, + .index = symbol_index, + .relocation_type = .R_WASM_TABLE_INDEX_SLEB, + }); +} + fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void { const symbol_index = emit.mir.instructions.items(.data)[inst].label; try emit.code.append(std.wasm.opcode(.i32_const)); diff --git a/src/arch/wasm/Mir.zig b/src/arch/wasm/Mir.zig index a47fed5b9f..c2d6e919b0 100644 --- a/src/arch/wasm/Mir.zig +++ b/src/arch/wasm/Mir.zig @@ -373,11 +373,17 @@ pub const Inst = struct { i64_extend16_s = 0xC3, /// Uses `tag` i64_extend32_s = 0xC4, + /// Contains a symbol to a function pointer + /// uses `label` + /// + /// Note: This uses `0xFE` as value as it is unused and not reserved + /// by the wasm specification, making it safe to use. + function_index = 0xFE, /// Contains a symbol to a memory address /// Uses `label` /// - /// Note: This uses `0xFF` as value as it is unused and not-reserved - /// by the wasm specification, making it safe to use + /// Note: This uses `0xFF` as value as it is unused and not reserved + /// by the wasm specification, making it safe to use. memory_address = 0xFF, /// From a given wasm opcode, returns a MIR tag. -- cgit v1.2.3