diff --git a/src/codegen/wasm.zig b/src/codegen/wasm.zig index 912577a358..33ab07faf3 100644 --- a/src/codegen/wasm.zig +++ b/src/codegen/wasm.zig @@ -25,7 +25,7 @@ const WValue = union(enum) { /// Index of the local variable local: u32, /// Instruction holding a constant `Value` - constant: *Inst, + constant: Air.Inst.Index, /// Offset position in the list of bytecode instructions code_offset: usize, /// Used for variables that create multiple locals on the stack when allocated @@ -484,7 +484,7 @@ pub const Result = union(enum) { }; /// Hashmap to store generated `WValue` for each `Inst` -pub const ValueTable = std.AutoHashMapUnmanaged(*Inst, WValue); +pub const ValueTable = std.AutoHashMapUnmanaged(Air.Inst.Index, WValue); /// Code represents the `Code` section of wasm that /// belongs to a function @@ -497,8 +497,8 @@ pub const Context = struct { gpa: *mem.Allocator, /// Table to save `WValue`'s generated by an `Inst` values: ValueTable, - /// Mapping from *Inst.Block to block ids - blocks: std.AutoArrayHashMapUnmanaged(*Inst.Block, u32) = .{}, + /// Mapping from Air.Inst.Index to block ids + blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, u32) = .{}, /// `bytes` contains the wasm bytecode belonging to the 'code' section. code: ArrayList(u8), /// Contains the generated function type bytecode for the current function @@ -538,7 +538,8 @@ pub const Context = struct { } /// Sets `err_msg` on `Context` and returns `error.CodegemFail` which is caught in link/Wasm.zig - fn fail(self: *Context, src: LazySrcLoc, comptime fmt: []const u8, args: anytype) InnerError { + fn fail(self: *Context, comptime fmt: []const u8, args: anytype) InnerError { + const src: LazySrcLoc = .{ .node_offset = 0 }; const src_loc = src.toSrcLocWithDecl(self.decl); self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, fmt, args); return error.CodegenFail; @@ -546,7 +547,7 @@ pub const Context = struct { /// Resolves the `WValue` for the given instruction `inst` /// When the given instruction has a `Value`, it returns a constant instead - fn resolveInst(self: Context, inst: *Inst) WValue { + fn resolveInst(self: Context, inst: Air.Inst) Index { if (!inst.ty.hasCodeGenBits()) return .none; if (inst.value()) |_| { @@ -557,48 +558,45 @@ pub const Context = struct { } /// Using a given `Type`, returns the corresponding wasm Valtype - fn typeToValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!wasm.Valtype { + fn typeToValtype(self: *Context, ty: Type) InnerError!wasm.Valtype { return switch (ty.zigTypeTag()) { .Float => blk: { const bits = ty.floatBits(self.target); if (bits == 16 or bits == 32) break :blk wasm.Valtype.f32; if (bits == 64) break :blk wasm.Valtype.f64; - return self.fail(src, "Float bit size not supported by wasm: '{d}'", .{bits}); + return self.fail("Float bit size not supported by wasm: '{d}'", .{bits}); }, .Int => blk: { const info = ty.intInfo(self.target); if (info.bits <= 32) break :blk wasm.Valtype.i32; if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64; - return self.fail(src, "Integer bit size not supported by wasm: '{d}'", .{info.bits}); + return self.fail("Integer bit size not supported by wasm: '{d}'", .{info.bits}); }, .Enum => switch (ty.tag()) { .enum_simple => wasm.Valtype.i32, - else => self.typeToValtype( - src, - ty.cast(Type.Payload.EnumFull).?.data.tag_ty, - ), + else => self.typeToValtype(ty.cast(Type.Payload.EnumFull).?.data.tag_ty), }, .Bool, .Pointer, .ErrorSet, => wasm.Valtype.i32, .Struct, .ErrorUnion => unreachable, // Multi typed, must be handled individually. - else => self.fail(src, "TODO - Wasm valtype for type '{s}'", .{ty.zigTypeTag()}), + else => self.fail("TODO - Wasm valtype for type '{s}'", .{ty.zigTypeTag()}), }; } /// Using a given `Type`, returns the byte representation of its wasm value type - fn genValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 { - return wasm.valtype(try self.typeToValtype(src, ty)); + fn genValtype(self: *Context, ty: Type) InnerError!u8 { + return wasm.valtype(try self.typeToValtype(ty)); } /// Using a given `Type`, returns the corresponding wasm value type /// Differently from `genValtype` this also allows `void` to create a block /// with no return type - fn genBlockType(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 { + fn genBlockType(self: *Context, ty: Type) InnerError!u8 { return switch (ty.tag()) { .void, .noreturn => wasm.block_empty, - else => self.genValtype(src, ty), + else => self.genValtype(ty), }; } @@ -612,7 +610,7 @@ pub const Context = struct { try writer.writeByte(wasm.opcode(.local_get)); try leb.writeULEB128(writer, idx); }, - .constant => |inst| try self.emitConstant(inst.src, inst.value().?, inst.ty), // creates a new constant onto the stack + .constant => |inst| try self.emitConstant(inst.value().?, inst.ty), // creates a new constant onto the stack } } @@ -682,7 +680,7 @@ pub const Context = struct { ty.fnParamTypes(params); for (params) |param_type| { // Can we maybe get the source index of each param? - const val_type = try self.genValtype(.{ .node_offset = 0 }, param_type); + const val_type = try self.genValtype(param_type); try writer.writeByte(val_type); } } @@ -691,13 +689,10 @@ pub const Context = struct { const return_type = ty.fnReturnType(); switch (return_type.zigTypeTag()) { .Void, .NoReturn => try leb.writeULEB128(writer, @as(u32, 0)), - .Struct => return self.fail(.{ .node_offset = 0 }, "TODO: Implement struct as return type for wasm", .{}), - .Optional => return self.fail(.{ .node_offset = 0 }, "TODO: Implement optionals as return type for wasm", .{}), + .Struct => return self.fail("TODO: Implement struct as return type for wasm", .{}), + .Optional => return self.fail("TODO: Implement optionals as return type for wasm", .{}), .ErrorUnion => { - const val_type = try self.genValtype( - .{ .node_offset = 0 }, - return_type.errorUnionChild(), - ); + const val_type = try self.genValtype(return_type.errorUnionChild()); // write down the amount of return values try leb.writeULEB128(writer, @as(u32, 2)); @@ -707,22 +702,21 @@ pub const Context = struct { else => { try leb.writeULEB128(writer, @as(u32, 1)); // Can we maybe get the source index of the return type? - const val_type = try self.genValtype(.{ .node_offset = 0 }, return_type); + const val_type = try self.genValtype(return_type); try writer.writeByte(val_type); }, } } pub fn genFunc(self: *Context, func: *Module.Fn) InnerError!Result { + _ = func; try self.genFunctype(); - - // Write instructions // TODO: check for and handle death of instructions // Reserve space to write the size after generating the code as well as space for locals count try self.code.resize(10); - try self.genBody(func.body); + try self.genBody(self.air.getMainBody()); // finally, write our local types at the 'offset' position { @@ -753,7 +747,7 @@ pub const Context = struct { return Result.appended; } - /// Generates the wasm bytecode for the function declaration belonging to `Context` + /// Generates the wasm bytecode for the declaration belonging to `Context` pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result { switch (typed_value.ty.zigTypeTag()) { .Fn => { @@ -793,58 +787,59 @@ pub const Context = struct { } } - fn genInst(self: *Context, inst: *Inst) InnerError!WValue { - return switch (inst.tag) { - .add => self.genBinOp(inst.castTag(.add).?, .add), - .alloc => self.genAlloc(inst.castTag(.alloc).?), - .arg => self.genArg(inst.castTag(.arg).?), - .bit_and => self.genBinOp(inst.castTag(.bit_and).?, .@"and"), - .bitcast => self.genBitcast(inst.castTag(.bitcast).?), - .bit_or => self.genBinOp(inst.castTag(.bit_or).?, .@"or"), - .block => self.genBlock(inst.castTag(.block).?), - .bool_and => self.genBinOp(inst.castTag(.bool_and).?, .@"and"), - .bool_or => self.genBinOp(inst.castTag(.bool_or).?, .@"or"), - .breakpoint => self.genBreakpoint(inst.castTag(.breakpoint).?), - .br => self.genBr(inst.castTag(.br).?), - .call => self.genCall(inst.castTag(.call).?), - .cmp_eq => self.genCmp(inst.castTag(.cmp_eq).?, .eq), - .cmp_gte => self.genCmp(inst.castTag(.cmp_gte).?, .gte), - .cmp_gt => self.genCmp(inst.castTag(.cmp_gt).?, .gt), - .cmp_lte => self.genCmp(inst.castTag(.cmp_lte).?, .lte), - .cmp_lt => self.genCmp(inst.castTag(.cmp_lt).?, .lt), - .cmp_neq => self.genCmp(inst.castTag(.cmp_neq).?, .neq), - .condbr => self.genCondBr(inst.castTag(.condbr).?), - .constant => unreachable, - .dbg_stmt => WValue.none, - .div => self.genBinOp(inst.castTag(.div).?, .div), - .is_err => self.genIsErr(inst.castTag(.is_err).?, .i32_ne), - .is_non_err => self.genIsErr(inst.castTag(.is_non_err).?, .i32_eq), - .load => self.genLoad(inst.castTag(.load).?), - .loop => self.genLoop(inst.castTag(.loop).?), - .mul => self.genBinOp(inst.castTag(.mul).?, .mul), - .not => self.genNot(inst.castTag(.not).?), - .ret => self.genRet(inst.castTag(.ret).?), - .retvoid => WValue.none, - .store => self.genStore(inst.castTag(.store).?), - .struct_field_ptr => self.genStructFieldPtr(inst.castTag(.struct_field_ptr).?), - .sub => self.genBinOp(inst.castTag(.sub).?, .sub), - .switchbr => self.genSwitchBr(inst.castTag(.switchbr).?), - .unreach => self.genUnreachable(inst.castTag(.unreach).?), - .unwrap_errunion_payload => self.genUnwrapErrUnionPayload(inst.castTag(.unwrap_errunion_payload).?), - .wrap_errunion_payload => self.genWrapErrUnionPayload(inst.castTag(.wrap_errunion_payload).?), - .xor => self.genBinOp(inst.castTag(.xor).?, .xor), - else => self.fail(.{ .node_offset = 0 }, "TODO: Implement wasm inst: {s}", .{inst.tag}), + fn genInst(self: *Context, inst: Air.Inst.Index) !WValue { + const air_tags = self.air.instructions.items(.tag); + return switch (air_tags[inst]) { + // .add => self.genBinOp(inst.castTag(.add).?, .add), + // .alloc => self.genAlloc(inst.castTag(.alloc).?), + // .arg => self.genArg(inst.castTag(.arg).?), + // .bit_and => self.genBinOp(inst.castTag(.bit_and).?, .@"and"), + // .bitcast => self.genBitcast(inst.castTag(.bitcast).?), + // .bit_or => self.genBinOp(inst.castTag(.bit_or).?, .@"or"), + // .block => self.genBlock(inst.castTag(.block).?), + // .bool_and => self.genBinOp(inst.castTag(.bool_and).?, .@"and"), + // .bool_or => self.genBinOp(inst.castTag(.bool_or).?, .@"or"), + // .breakpoint => self.genBreakpoint(inst.castTag(.breakpoint).?), + // .br => self.genBr(inst.castTag(.br).?), + // .call => self.genCall(inst.castTag(.call).?), + // .cmp_eq => self.genCmp(inst.castTag(.cmp_eq).?, .eq), + // .cmp_gte => self.genCmp(inst.castTag(.cmp_gte).?, .gte), + // .cmp_gt => self.genCmp(inst.castTag(.cmp_gt).?, .gt), + // .cmp_lte => self.genCmp(inst.castTag(.cmp_lte).?, .lte), + // .cmp_lt => self.genCmp(inst.castTag(.cmp_lt).?, .lt), + // .cmp_neq => self.genCmp(inst.castTag(.cmp_neq).?, .neq), + // .condbr => self.genCondBr(inst.castTag(.condbr).?), + // .constant => unreachable, + // .dbg_stmt => WValue.none, + // .div => self.genBinOp(inst.castTag(.div).?, .div), + // .is_err => self.genIsErr(inst.castTag(.is_err).?, .i32_ne), + // .is_non_err => self.genIsErr(inst.castTag(.is_non_err).?, .i32_eq), + // .load => self.genLoad(inst.castTag(.load).?), + // .loop => self.genLoop(inst.castTag(.loop).?), + // .mul => self.genBinOp(inst.castTag(.mul).?, .mul), + // .not => self.genNot(inst.castTag(.not).?), + // .ret => self.genRet(inst.castTag(.ret).?), + // .retvoid => WValue.none, + // .store => self.genStore(inst.castTag(.store).?), + // .struct_field_ptr => self.genStructFieldPtr(inst.castTag(.struct_field_ptr).?), + // .sub => self.genBinOp(inst.castTag(.sub).?, .sub), + // .switchbr => self.genSwitchBr(inst.castTag(.switchbr).?), + // .unreach => self.genUnreachable(inst.castTag(.unreach).?), + // .unwrap_errunion_payload => self.genUnwrapErrUnionPayload(inst.castTag(.unwrap_errunion_payload).?), + // .wrap_errunion_payload => self.genWrapErrUnionPayload(inst.castTag(.wrap_errunion_payload).?), + // .xor => self.genBinOp(inst.castTag(.xor).?, .xor), + else => |tag| self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), }; } - fn genBody(self: *Context, body: ir.Body) InnerError!void { - for (body.instructions) |inst| { + fn genBody(self: *Context, body: []const Air.Inst.Index) InnerError!void { + for (body) |inst| { const result = try self.genInst(inst); try self.values.putNoClobber(self.gpa, inst, result); } } - fn genRet(self: *Context, inst: *Inst.UnOp) InnerError!WValue { + fn genRet(self: *Context, inst: Air.Inst.Index) InnerError!WValue { // TODO: Implement tail calls const operand = self.resolveInst(inst.operand); try self.emitWValue(operand); @@ -852,7 +847,7 @@ pub const Context = struct { return .none; } - fn genCall(self: *Context, inst: *Inst.Call) InnerError!WValue { + fn genCall(self: *Context, inst: Air.Inst.Index) InnerError!WValue { const func_val = inst.func.value().?; const target: *Decl = blk: { @@ -861,7 +856,7 @@ pub const Context = struct { } else if (func_val.castTag(.extern_fn)) |ext_fn| { break :blk ext_fn.data; } - return self.fail(inst.base.src, "Expected a function, but instead found type '{s}'", .{func_val.tag()}); + return self.fail("Expected a function, but instead found type '{s}'", .{func_val.tag()}); }; for (inst.args) |arg| { @@ -881,12 +876,12 @@ pub const Context = struct { return .none; } - fn genAlloc(self: *Context, inst: *Inst.NoOp) InnerError!WValue { + fn genAlloc(self: *Context, inst: Air.Inst.Index) InnerError!WValue { const elem_type = inst.base.ty.elemType(); return self.allocLocal(elem_type); } - fn genStore(self: *Context, inst: *Inst.BinOp) InnerError!WValue { + fn genStore(self: *Context, inst: Air.Inst.Index) InnerError!WValue { const writer = self.code.writer(); const lhs = self.resolveInst(inst.lhs); @@ -924,18 +919,18 @@ pub const Context = struct { return .none; } - fn genLoad(self: *Context, inst: *Inst.UnOp) InnerError!WValue { + fn genLoad(self: *Context, inst: Air.Inst.Index) InnerError!WValue { return self.resolveInst(inst.operand); } - fn genArg(self: *Context, inst: *Inst.Arg) InnerError!WValue { + fn genArg(self: *Context, inst: Air.Inst.Index) InnerError!WValue { _ = inst; // arguments share the index with locals defer self.local_index += 1; return WValue{ .local = self.local_index }; } - fn genBinOp(self: *Context, inst: *Inst.BinOp, op: Op) InnerError!WValue { + fn genBinOp(self: *Context, inst: Air.Inst.Index, op: Op) InnerError!WValue { const lhs = self.resolveInst(inst.lhs); const rhs = self.resolveInst(inst.rhs); @@ -952,21 +947,21 @@ pub const Context = struct { const opcode: wasm.Opcode = buildOpcode(.{ .op = op, - .valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty), + .valtype1 = try self.typeToValtype(inst.base.ty), .signedness = if (inst.base.ty.isSignedInt()) .signed else .unsigned, }); try self.code.append(wasm.opcode(opcode)); return WValue{ .code_offset = offset }; } - fn emitConstant(self: *Context, src: LazySrcLoc, value: Value, ty: Type) InnerError!void { + fn emitConstant(self: *Context, value: Value, ty: Type) InnerError!void { const writer = self.code.writer(); switch (ty.zigTypeTag()) { .Int => { // write opcode const opcode: wasm.Opcode = buildOpcode(.{ .op = .@"const", - .valtype1 = try self.typeToValtype(src, ty), + .valtype1 = try self.typeToValtype(ty), }); try writer.writeByte(wasm.opcode(opcode)); // write constant @@ -985,14 +980,14 @@ pub const Context = struct { // write opcode const opcode: wasm.Opcode = buildOpcode(.{ .op = .@"const", - .valtype1 = try self.typeToValtype(src, ty), + .valtype1 = try self.typeToValtype(ty), }); try writer.writeByte(wasm.opcode(opcode)); // write constant switch (ty.floatBits(self.target)) { 0...32 => try writer.writeIntLittle(u32, @bitCast(u32, value.toFloat(f32))), 64 => try writer.writeIntLittle(u64, @bitCast(u64, value.toFloat(f64))), - else => |bits| return self.fail(src, "Wasm TODO: emitConstant for float with {d} bits", .{bits}), + else => |bits| return self.fail("Wasm TODO: emitConstant for float with {d} bits", .{bits}), } }, .Pointer => { @@ -1009,7 +1004,7 @@ pub const Context = struct { try writer.writeByte(wasm.opcode(.i32_load)); try leb.writeULEB128(writer, @as(u32, 0)); try leb.writeULEB128(writer, @as(u32, 0)); - } else return self.fail(src, "Wasm TODO: emitConstant for other const pointer tag {s}", .{value.tag()}); + } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{value.tag()}); }, .Void => {}, .Enum => { @@ -1023,7 +1018,7 @@ pub const Context = struct { const enum_full = ty.cast(Type.Payload.EnumFull).?.data; if (enum_full.values.count() != 0) { const tag_val = enum_full.values.keys()[field_index.data]; - try self.emitConstant(src, tag_val, enum_full.tag_ty); + try self.emitConstant(tag_val, enum_full.tag_ty); } else { try writer.writeByte(wasm.opcode(.i32_const)); try leb.writeULEB128(writer, field_index.data); @@ -1034,7 +1029,7 @@ pub const Context = struct { } else { var int_tag_buffer: Type.Payload.Bits = undefined; const int_tag_ty = ty.intTagType(&int_tag_buffer); - try self.emitConstant(src, value, int_tag_ty); + try self.emitConstant(value, int_tag_ty); } }, .ErrorSet => { @@ -1048,12 +1043,12 @@ pub const Context = struct { const payload_type = ty.errorUnionChild(); if (value.getError()) |_| { // write the error value - try self.emitConstant(src, data, error_type); + try self.emitConstant(data, error_type); // no payload, so write a '0' const const opcode: wasm.Opcode = buildOpcode(.{ .op = .@"const", - .valtype1 = try self.typeToValtype(src, payload_type), + .valtype1 = try self.typeToValtype(payload_type), }); try writer.writeByte(wasm.opcode(opcode)); try leb.writeULEB128(writer, @as(u32, 0)); @@ -1062,15 +1057,15 @@ pub const Context = struct { try writer.writeByte(wasm.opcode(.i32_const)); try leb.writeULEB128(writer, @as(u32, 0)); // after the error code, we emit the payload - try self.emitConstant(src, data, payload_type); + try self.emitConstant(data, payload_type); } }, - else => |zig_type| return self.fail(src, "Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}), + else => |zig_type| return self.fail("Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}), } } - fn genBlock(self: *Context, block: *Inst.Block) InnerError!WValue { - const block_ty = try self.genBlockType(block.base.src, block.base.ty); + fn genBlock(self: *Context, block: Air.Inst.Index) InnerError!WValue { + const block_ty = try self.genBlockType(block.base.ty); try self.startBlock(.block, block_ty, null); // Here we set the current block idx, so breaks know the depth to jump @@ -1100,8 +1095,8 @@ pub const Context = struct { self.block_depth -= 1; } - fn genLoop(self: *Context, loop: *Inst.Loop) InnerError!WValue { - const loop_ty = try self.genBlockType(loop.base.src, loop.base.ty); + fn genLoop(self: *Context, loop: Air.Inst.Index) InnerError!WValue { + const loop_ty = try self.genBlockType(loop.base.ty); try self.startBlock(.loop, loop_ty, null); try self.genBody(loop.body); @@ -1115,7 +1110,7 @@ pub const Context = struct { return .none; } - fn genCondBr(self: *Context, condbr: *Inst.CondBr) InnerError!WValue { + fn genCondBr(self: *Context, condbr: Air.Inst.Index) InnerError!WValue { const condition = self.resolveInst(condbr.condition); const writer = self.code.writer(); @@ -1131,7 +1126,7 @@ pub const Context = struct { break :blk offset; }, }; - const block_ty = try self.genBlockType(condbr.base.src, condbr.base.ty); + const block_ty = try self.genBlockType(condbr.base.ty); try self.startBlock(.block, block_ty, offset); // we inserted the block in front of the condition @@ -1149,7 +1144,7 @@ pub const Context = struct { return .none; } - fn genCmp(self: *Context, inst: *Inst.BinOp, op: std.math.CompareOperator) InnerError!WValue { + fn genCmp(self: *Context, inst: Air.Inst.Index, op: std.math.CompareOperator) InnerError!WValue { // save offset, so potential conditions can insert blocks in front of // the comparison that we can later jump back to const offset = self.code.items.len; @@ -1168,7 +1163,7 @@ pub const Context = struct { break :blk inst.lhs.ty.intInfo(self.target).signedness; }; const opcode: wasm.Opcode = buildOpcode(.{ - .valtype1 = try self.typeToValtype(inst.base.src, inst.lhs.ty), + .valtype1 = try self.typeToValtype(inst.lhs.ty), .op = switch (op) { .lt => .lt, .lte => .le, @@ -1183,7 +1178,7 @@ pub const Context = struct { return WValue{ .code_offset = offset }; } - fn genBr(self: *Context, br: *Inst.Br) InnerError!WValue { + fn genBr(self: *Context, br: Air.Inst.Index) InnerError!WValue { // if operand has codegen bits we should break with a value if (br.operand.ty.hasCodeGenBits()) { const operand = self.resolveInst(br.operand); @@ -1200,7 +1195,7 @@ pub const Context = struct { return .none; } - fn genNot(self: *Context, not: *Inst.UnOp) InnerError!WValue { + fn genNot(self: *Context, not: Air.Inst.Index) InnerError!WValue { const offset = self.code.items.len; const operand = self.resolveInst(not.operand); @@ -1217,7 +1212,7 @@ pub const Context = struct { return WValue{ .code_offset = offset }; } - fn genBreakpoint(self: *Context, breakpoint: *Inst.NoOp) InnerError!WValue { + fn genBreakpoint(self: *Context, breakpoint: Air.Inst.Index) InnerError!WValue { _ = self; _ = breakpoint; // unsupported by wasm itself. Can be implemented once we support DWARF @@ -1225,27 +1220,27 @@ pub const Context = struct { return .none; } - fn genUnreachable(self: *Context, unreach: *Inst.NoOp) InnerError!WValue { + fn genUnreachable(self: *Context, unreach: Air.Inst.Index) InnerError!WValue { _ = unreach; try self.code.append(wasm.opcode(.@"unreachable")); return .none; } - fn genBitcast(self: *Context, bitcast: *Inst.UnOp) InnerError!WValue { + fn genBitcast(self: *Context, bitcast: Air.Inst.Index) InnerError!WValue { return self.resolveInst(bitcast.operand); } - fn genStructFieldPtr(self: *Context, inst: *Inst.StructFieldPtr) InnerError!WValue { + fn genStructFieldPtr(self: *Context, inst: Air.Inst.Index) InnerError!WValue { const struct_ptr = self.resolveInst(inst.struct_ptr); return WValue{ .local = struct_ptr.multi_value.index + @intCast(u32, inst.field_index) }; } - fn genSwitchBr(self: *Context, inst: *Inst.SwitchBr) InnerError!WValue { + fn genSwitchBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue { const target = self.resolveInst(inst.target); const target_ty = inst.target.ty; const valtype = try self.typeToValtype(.{ .node_offset = 0 }, target_ty); - const blocktype = try self.genBlockType(inst.base.src, inst.base.ty); + const blocktype = try self.genBlockType(inst.base.ty); const signedness: std.builtin.Signedness = blk: { // by default we tell the operand type is unsigned (i.e. bools and enum values) @@ -1282,7 +1277,7 @@ pub const Context = struct { return .none; } - fn genIsErr(self: *Context, inst: *Inst.UnOp, opcode: wasm.Opcode) InnerError!WValue { + fn genIsErr(self: *Context, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!WValue { const operand = self.resolveInst(inst.operand); const offset = self.code.items.len; const writer = self.code.writer(); @@ -1298,7 +1293,7 @@ pub const Context = struct { return WValue{ .code_offset = offset }; } - fn genUnwrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue { + fn genUnwrapErrUnionPayload(self: *Context, inst: Air.Inst.Index) InnerError!WValue { const operand = self.resolveInst(inst.operand); // The index of multi_value contains the error code. To get the initial index of the payload we get // the following index. Next, convert it to a `WValue.local` @@ -1307,7 +1302,7 @@ pub const Context = struct { return WValue{ .local = operand.multi_value.index + 1 }; } - fn genWrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue { + fn genWrapErrUnionPayload(self: *Context, inst: Air.Inst.Index) InnerError!WValue { return self.resolveInst(inst.operand); } }; diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index be6ad78701..1387615d15 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -228,7 +228,7 @@ pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, live }, else => |e| return e, }; - return self.finishUpdateDecl(decl, result); + return self.finishUpdateDecl(decl, result, &context); } // Generate code for the Decl, storing it in memory to be later written to @@ -270,18 +270,21 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { }, else => |e| return e, }; - return self.finishUpdateDecl(decl, result); + + return self.finishUpdateDecl(decl, result, &context); } -fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: codegen.Result) !void { - const code: []const u8 = switch (result) { - .appended => @as([]const u8, context.code.items), - .externally_managed => |payload| payload, - }; +fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: codegen.Result, context: *codegen.Context) !void { + const fn_data: *FnData = &decl.fn_link.wasm; fn_data.code = context.code.toUnmanaged(); fn_data.functype = context.func_type_data.toUnmanaged(); + const code: []const u8 = switch (result) { + .appended => @as([]const u8, fn_data.code.items), + .externally_managed => |payload| payload, + }; + const block = &decl.link.wasm; if (decl.ty.zigTypeTag() == .Fn) { // as locals are patched afterwards, the offsets of funcidx's are off,