diff options
| author | Luuk de Gram <luuk@degram.dev> | 2021-07-16 22:43:06 +0200 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-07-20 12:19:16 -0700 |
| commit | 2438f61f1c37aefa16852130370df44b3fabf785 (patch) | |
| tree | 831f7d890c87cf50119f5f639a2818e9a7b1c8ba /src/codegen | |
| parent | 424f260f850cb22637888bbfdf5bfaf9c08a4dae (diff) | |
| download | zig-2438f61f1c37aefa16852130370df44b3fabf785.tar.gz zig-2438f61f1c37aefa16852130370df44b3fabf785.zip | |
Refactor entire wasm-backend to use new AIR memory layout
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/wasm.zig | 275 |
1 files changed, 160 insertions, 115 deletions
diff --git a/src/codegen/wasm.zig b/src/codegen/wasm.zig index 33ab07faf3..5cf3fb15fd 100644 --- a/src/codegen/wasm.zig +++ b/src/codegen/wasm.zig @@ -483,8 +483,8 @@ pub const Result = union(enum) { externally_managed: []const u8, }; -/// Hashmap to store generated `WValue` for each `Inst` -pub const ValueTable = std.AutoHashMapUnmanaged(Air.Inst.Index, WValue); +/// Hashmap to store generated `WValue` for each `Air.Inst.Ref` +pub const ValueTable = std.AutoHashMapUnmanaged(Air.Inst.Ref, WValue); /// Code represents the `Code` section of wasm that /// belongs to a function @@ -495,7 +495,7 @@ pub const Context = struct { air: Air, liveness: Liveness, gpa: *mem.Allocator, - /// Table to save `WValue`'s generated by an `Inst` + /// Table to save `WValue`'s generated by an `Air.Inst` values: ValueTable, /// Mapping from Air.Inst.Index to block ids blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, u32) = .{}, @@ -547,14 +547,15 @@ 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: Air.Inst) Index { - if (!inst.ty.hasCodeGenBits()) return .none; + fn resolveInst(self: Context, ref: Air.Inst.Ref) WValue { + const ref_type = self.air.getRefType(ref); + if (ref_type.hasCodeGenBits()) return .none; - if (inst.value()) |_| { - return WValue{ .constant = inst }; + if (self.air.instructions.items(.tag)[@enumToInt(ref)] == .constant) { + return WValue{ .constant = @enumToInt(ref) }; } - return self.values.get(inst).?; // Instruction does not dominate all uses! + return self.values.get(ref).?; // Instruction does not dominate all uses! } /// Using a given `Type`, returns the corresponding wasm Valtype @@ -610,7 +611,12 @@ pub const Context = struct { try writer.writeByte(wasm.opcode(.local_get)); try leb.writeULEB128(writer, idx); }, - .constant => |inst| try self.emitConstant(inst.value().?, inst.ty), // creates a new constant onto the stack + .constant => |index| { + const ty_pl = self.air.instructions.items(.data)[index].ty_pl; + const value = self.air.values[ty_pl.payload]; + // create a new constant onto the stack + try self.emitConstant(value, self.air.getRefType(ty_pl.ty)); + }, } } @@ -626,10 +632,7 @@ pub const Context = struct { const fields_len = @intCast(u32, struct_data.fields.count()); try self.locals.ensureCapacity(self.gpa, self.locals.items.len + fields_len); for (struct_data.fields.values()) |*value| { - const val_type = try self.genValtype( - .{ .node_offset = struct_data.node_offset }, - value.ty, - ); + const val_type = try self.genValtype(value.ty); self.locals.appendAssumeCapacity(val_type); self.local_index += 1; } @@ -640,7 +643,7 @@ pub const Context = struct { }, .ErrorUnion => { const payload_type = ty.errorUnionChild(); - const val_type = try self.genValtype(.{ .node_offset = 0 }, payload_type); + const val_type = try self.genValtype(payload_type); // we emit the error value as the first local, and the payload as the following. // The first local is also used to find the index of the error and payload. @@ -657,7 +660,7 @@ pub const Context = struct { } }; }, else => { - const valtype = try self.genValtype(.{ .node_offset = 0 }, ty); + const valtype = try self.genValtype(ty); try self.locals.append(self.gpa, valtype); self.local_index += 1; return WValue{ .local = initial_index }; @@ -708,8 +711,7 @@ pub const Context = struct { } } - pub fn genFunc(self: *Context, func: *Module.Fn) InnerError!Result { - _ = func; + pub fn genFunc(self: *Context) InnerError!Result { try self.genFunctype(); // TODO: check for and handle death of instructions @@ -790,44 +792,43 @@ pub const Context = struct { 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), + .add => self.genBinOp(inst, .add), + .alloc => self.genAlloc(inst), + .arg => self.genArg(inst), + .bit_and => self.genBinOp(inst, .@"and"), + .bitcast => self.genBitcast(inst), + .bit_or => self.genBinOp(inst, .@"or"), + .block => self.genBlock(inst), + .bool_and => self.genBinOp(inst, .@"and"), + .bool_or => self.genBinOp(inst, .@"or"), + .breakpoint => self.genBreakpoint(inst), + .br => self.genBr(inst), + .call => self.genCall(inst), + .cmp_eq => self.genCmp(inst, .eq), + .cmp_gte => self.genCmp(inst, .gte), + .cmp_gt => self.genCmp(inst, .gt), + .cmp_lte => self.genCmp(inst, .lte), + .cmp_lt => self.genCmp(inst, .lt), + .cmp_neq => self.genCmp(inst, .neq), + .cond_br => self.genCondBr(inst), + .constant => unreachable, + .dbg_stmt => WValue.none, + .div => self.genBinOp(inst, .div), + .is_err => self.genIsErr(inst, .i32_ne), + .is_non_err => self.genIsErr(inst, .i32_eq), + .load => self.genLoad(inst), + .loop => self.genLoop(inst), + .mul => self.genBinOp(inst, .mul), + .not => self.genNot(inst), + .ret => self.genRet(inst), + .store => self.genStore(inst), + .struct_field_ptr => self.genStructFieldPtr(inst), + .sub => self.genBinOp(inst, .sub), + .switch_br => self.genSwitchBr(inst), + .unreach => self.genUnreachable(inst), + .unwrap_errunion_payload => self.genUnwrapErrUnionPayload(inst), + .wrap_errunion_payload => self.genWrapErrUnionPayload(inst), + .xor => self.genBinOp(inst, .xor), else => |tag| self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), }; } @@ -835,22 +836,27 @@ pub const Context = struct { 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); + try self.values.putNoClobber(self.gpa, @intToEnum(Air.Inst.Ref, inst), result); } } fn genRet(self: *Context, inst: Air.Inst.Index) InnerError!WValue { - // TODO: Implement tail calls - const operand = self.resolveInst(inst.operand); + const un_op = self.air.instructions.items(.data)[inst].un_op; + const operand = self.resolveInst(un_op); try self.emitWValue(operand); try self.code.append(wasm.opcode(.@"return")); return .none; } fn genCall(self: *Context, inst: Air.Inst.Index) InnerError!WValue { - const func_val = inst.func.value().?; + const pl_op = self.air.instructions.items(.data)[inst].pl_op; + const extra = self.air.extraData(Air.Call, pl_op.payload); + const args = self.air.extra[extra.end..][0..extra.data.args_len]; const target: *Decl = blk: { + const ty_pl = self.air.instructions.items(.data)[@enumToInt(pl_op.operand)].ty_pl; + const func_val = self.air.values[ty_pl.payload]; + if (func_val.castTag(.function)) |func| { break :blk func.data.owner_decl; } else if (func_val.castTag(.extern_fn)) |ext_fn| { @@ -859,8 +865,8 @@ pub const Context = struct { return self.fail("Expected a function, but instead found type '{s}'", .{func_val.tag()}); }; - for (inst.args) |arg| { - const arg_val = self.resolveInst(arg); + for (args) |arg| { + const arg_val = self.resolveInst(@intToEnum(Air.Inst.Ref, arg)); try self.emitWValue(arg_val); } @@ -877,15 +883,16 @@ pub const Context = struct { } fn genAlloc(self: *Context, inst: Air.Inst.Index) InnerError!WValue { - const elem_type = inst.base.ty.elemType(); + const elem_type = self.air.getType(inst).elemType(); return self.allocLocal(elem_type); } fn genStore(self: *Context, inst: Air.Inst.Index) InnerError!WValue { + const bin_op = self.air.instructions.items(.data)[inst].bin_op; const writer = self.code.writer(); - const lhs = self.resolveInst(inst.lhs); - const rhs = self.resolveInst(inst.rhs); + const lhs = self.resolveInst(bin_op.lhs); + const rhs = self.resolveInst(bin_op.rhs); switch (lhs) { .multi_value => |multi_value| switch (rhs) { @@ -893,7 +900,7 @@ pub const Context = struct { // we simply assign the local_index to the rhs one. // This allows us to update struct fields without having to individually // set each local as each field's index will be calculated off the struct's base index - .multi_value => self.values.put(self.gpa, inst.lhs, rhs) catch unreachable, // Instruction does not dominate all uses! + .multi_value => self.values.put(self.gpa, bin_op.lhs, rhs) catch unreachable, // Instruction does not dominate all uses! .constant, .none => { // emit all values onto the stack if constant try self.emitWValue(rhs); @@ -920,7 +927,8 @@ pub const Context = struct { } fn genLoad(self: *Context, inst: Air.Inst.Index) InnerError!WValue { - return self.resolveInst(inst.operand); + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + return self.resolveInst(ty_op.operand); } fn genArg(self: *Context, inst: Air.Inst.Index) InnerError!WValue { @@ -931,8 +939,9 @@ pub const Context = struct { } fn genBinOp(self: *Context, inst: Air.Inst.Index, op: Op) InnerError!WValue { - const lhs = self.resolveInst(inst.lhs); - const rhs = self.resolveInst(inst.rhs); + const bin_op = self.air.instructions.items(.data)[inst].bin_op; + const lhs = self.resolveInst(bin_op.lhs); + const rhs = self.resolveInst(bin_op.rhs); // it's possible for both lhs and/or rhs to return an offset as well, // in which case we return the first offset occurance we find. @@ -945,10 +954,11 @@ pub const Context = struct { try self.emitWValue(lhs); try self.emitWValue(rhs); + const bin_ty = self.air.getRefType(bin_op.lhs); const opcode: wasm.Opcode = buildOpcode(.{ .op = op, - .valtype1 = try self.typeToValtype(inst.base.ty), - .signedness = if (inst.base.ty.isSignedInt()) .signed else .unsigned, + .valtype1 = try self.typeToValtype(bin_ty), + .signedness = if (bin_ty.isSignedInt()) .signed else .unsigned, }); try self.code.append(wasm.opcode(opcode)); return WValue{ .code_offset = offset }; @@ -1064,14 +1074,17 @@ pub const Context = struct { } } - fn genBlock(self: *Context, block: Air.Inst.Index) InnerError!WValue { - const block_ty = try self.genBlockType(block.base.ty); + fn genBlock(self: *Context, inst: Air.Inst.Index) InnerError!WValue { + const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; + const block_ty = try self.genBlockType(self.air.getRefType(ty_pl.ty)); + const extra = self.air.extraData(Air.Block, ty_pl.payload); + const body = self.air.extra[extra.end..][0..extra.data.body_len]; try self.startBlock(.block, block_ty, null); // Here we set the current block idx, so breaks know the depth to jump // to when breaking out. - try self.blocks.putNoClobber(self.gpa, block, self.block_depth); - try self.genBody(block.body); + try self.blocks.putNoClobber(self.gpa, inst, self.block_depth); + try self.genBody(body); try self.endBlock(); return .none; @@ -1095,11 +1108,15 @@ pub const Context = struct { self.block_depth -= 1; } - fn genLoop(self: *Context, loop: Air.Inst.Index) InnerError!WValue { - const loop_ty = try self.genBlockType(loop.base.ty); + fn genLoop(self: *Context, inst: Air.Inst.Index) InnerError!WValue { + const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; + const loop = self.air.extraData(Air.Block, ty_pl.payload); + const body = self.air.extra[loop.end..][0..loop.data.body_len]; - try self.startBlock(.loop, loop_ty, null); - try self.genBody(loop.body); + // result type of loop is always 'noreturn', meaning we can always + // emit the wasm type 'block_empty'. + try self.startBlock(.loop, wasm.block_empty, null); + try self.genBody(body); // breaking to the index of a loop block will continue the loop instead try self.code.append(wasm.opcode(.br)); @@ -1110,8 +1127,12 @@ pub const Context = struct { return .none; } - fn genCondBr(self: *Context, condbr: Air.Inst.Index) InnerError!WValue { - const condition = self.resolveInst(condbr.condition); + fn genCondBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue { + const pl_op = self.air.instructions.items(.data)[inst].pl_op; + const condition = self.resolveInst(pl_op.operand); + const extra = self.air.extraData(Air.CondBr, pl_op.payload); + const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len]; + const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; const writer = self.code.writer(); // TODO: Handle death instructions for then and else body @@ -1126,8 +1147,9 @@ pub const Context = struct { break :blk offset; }, }; - const block_ty = try self.genBlockType(condbr.base.ty); - try self.startBlock(.block, block_ty, offset); + + // result type is always noreturn, so use `block_empty` as type. + try self.startBlock(.block, wasm.block_empty, offset); // we inserted the block in front of the condition // so now check if condition matches. If not, break outside this block @@ -1135,11 +1157,11 @@ pub const Context = struct { try writer.writeByte(wasm.opcode(.br_if)); try leb.writeULEB128(writer, @as(u32, 0)); - try self.genBody(condbr.else_body); + try self.genBody(else_body); try self.endBlock(); // Outer block that matches the condition - try self.genBody(condbr.then_body); + try self.genBody(then_body); return .none; } @@ -1149,21 +1171,23 @@ pub const Context = struct { // the comparison that we can later jump back to const offset = self.code.items.len; - const lhs = self.resolveInst(inst.lhs); - const rhs = self.resolveInst(inst.rhs); + const data: Air.Inst.Data = self.air.instructions.items(.data)[inst]; + const lhs = self.resolveInst(data.bin_op.lhs); + const rhs = self.resolveInst(data.bin_op.rhs); + const lhs_ty = self.air.getRefType(data.bin_op.lhs); try self.emitWValue(lhs); try self.emitWValue(rhs); const signedness: std.builtin.Signedness = blk: { // by default we tell the operand type is unsigned (i.e. bools and enum values) - if (inst.lhs.ty.zigTypeTag() != .Int) break :blk .unsigned; + if (lhs_ty.zigTypeTag() != .Int) break :blk .unsigned; // incase of an actual integer, we emit the correct signedness - break :blk inst.lhs.ty.intInfo(self.target).signedness; + break :blk lhs_ty.intInfo(self.target).signedness; }; const opcode: wasm.Opcode = buildOpcode(.{ - .valtype1 = try self.typeToValtype(inst.lhs.ty), + .valtype1 = try self.typeToValtype(lhs_ty), .op = switch (op) { .lt => .lt, .lte => .le, @@ -1178,16 +1202,17 @@ pub const Context = struct { return WValue{ .code_offset = offset }; } - fn genBr(self: *Context, br: Air.Inst.Index) InnerError!WValue { + fn genBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue { + const br = self.air.instructions.items(.data)[inst].br; + // if operand has codegen bits we should break with a value - if (br.operand.ty.hasCodeGenBits()) { - const operand = self.resolveInst(br.operand); - try self.emitWValue(operand); + if (self.air.getRefType(br.operand).hasCodeGenBits()) { + try self.emitWValue(self.resolveInst(br.operand)); } // We map every block to its block index. // We then determine how far we have to jump to it by substracting it from current block depth - const idx: u32 = self.block_depth - self.blocks.get(br.block).?; + const idx: u32 = self.block_depth - self.blocks.get(br.block_inst).?; const writer = self.code.writer(); try writer.writeByte(wasm.opcode(.br)); try leb.writeULEB128(writer, idx); @@ -1195,10 +1220,11 @@ pub const Context = struct { return .none; } - fn genNot(self: *Context, not: Air.Inst.Index) InnerError!WValue { + fn genNot(self: *Context, inst: Air.Inst.Index) InnerError!WValue { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; const offset = self.code.items.len; - const operand = self.resolveInst(not.operand); + const operand = self.resolveInst(ty_op.operand); try self.emitWValue(operand); // wasm does not have booleans nor the `not` instruction, therefore compare with 0 @@ -1212,35 +1238,44 @@ pub const Context = struct { return WValue{ .code_offset = offset }; } - fn genBreakpoint(self: *Context, breakpoint: Air.Inst.Index) InnerError!WValue { + fn genBreakpoint(self: *Context, inst: Air.Inst.Index) InnerError!WValue { _ = self; - _ = breakpoint; + _ = inst; // unsupported by wasm itself. Can be implemented once we support DWARF // for wasm return .none; } - fn genUnreachable(self: *Context, unreach: Air.Inst.Index) InnerError!WValue { - _ = unreach; + fn genUnreachable(self: *Context, inst: Air.Inst.Index) InnerError!WValue { + _ = inst; try self.code.append(wasm.opcode(.@"unreachable")); return .none; } - fn genBitcast(self: *Context, bitcast: Air.Inst.Index) InnerError!WValue { - return self.resolveInst(bitcast.operand); + fn genBitcast(self: *Context, inst: Air.Inst.Index) InnerError!WValue { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + return self.resolveInst(ty_op.operand); } fn genStructFieldPtr(self: *Context, inst: Air.Inst.Index) InnerError!WValue { - const struct_ptr = self.resolveInst(inst.struct_ptr); + const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; + const extra = self.air.extraData(Air.StructField, ty_pl.payload); + const struct_ptr = self.resolveInst(extra.data.struct_ptr); - return WValue{ .local = struct_ptr.multi_value.index + @intCast(u32, inst.field_index) }; + return WValue{ .local = struct_ptr.multi_value.index + @intCast(u32, extra.data.field_index) }; } 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.ty); + const pl_op = self.air.instructions.items(.data)[inst].pl_op; + const extra = self.air.extraData(Air.SwitchBr, pl_op.payload); + const cases = self.air.extra[extra.end..][0..extra.data.cases_len]; + const else_body = self.air.extra[extra.end + cases.len ..][0..extra.data.else_body_len]; + + const target = self.resolveInst(pl_op.operand); + const target_ty = self.air.getRefType(pl_op.operand); + const valtype = try self.typeToValtype(target_ty); + // result type is always 'noreturn' + const blocktype = wasm.block_empty; const signedness: std.builtin.Signedness = blk: { // by default we tell the operand type is unsigned (i.e. bools and enum values) @@ -1249,11 +1284,18 @@ pub const Context = struct { // incase of an actual integer, we emit the correct signedness break :blk target_ty.intInfo(self.target).signedness; }; - for (inst.cases) |case| { + for (cases) |case_idx| { + const case = self.air.extraData(Air.SwitchBr.Case, case_idx); + const case_body = self.air.extra[case.end..][0..case.data.body_len]; + // create a block for each case, when the condition does not match we break out of it try self.startBlock(.block, blocktype, null); try self.emitWValue(target); - try self.emitConstant(.{ .node_offset = 0 }, case.item, target_ty); + + // cases must represent a constant of which its type is in the `typed_value_map` + // Therefore we can simply retrieve it. + const ty_val = Air.Inst.Ref.typed_value_map[@enumToInt(case.data.item)]; + try self.emitConstant(ty_val.val, target_ty); const opcode = buildOpcode(.{ .valtype1 = valtype, .op = .ne, // not equal because we jump out the block if it does not match the condition @@ -1264,7 +1306,7 @@ pub const Context = struct { try leb.writeULEB128(self.code.writer(), @as(u32, 0)); // emit our block code - try self.genBody(case.body); + try self.genBody(case_body); // end the block we created earlier try self.endBlock(); @@ -1272,13 +1314,14 @@ pub const Context = struct { // finally, emit the else case if it exists. Here we will not have to // check for a condition, so also no need to emit a block. - try self.genBody(inst.else_body); + try self.genBody(else_body); return .none; } fn genIsErr(self: *Context, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!WValue { - const operand = self.resolveInst(inst.operand); + const un_op = self.air.instructions.items(.data)[inst].un_op; + const operand = self.resolveInst(un_op); const offset = self.code.items.len; const writer = self.code.writer(); @@ -1294,7 +1337,8 @@ pub const Context = struct { } fn genUnwrapErrUnionPayload(self: *Context, inst: Air.Inst.Index) InnerError!WValue { - const operand = self.resolveInst(inst.operand); + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const operand = self.resolveInst(ty_op.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` // @@ -1303,6 +1347,7 @@ pub const Context = struct { } fn genWrapErrUnionPayload(self: *Context, inst: Air.Inst.Index) InnerError!WValue { - return self.resolveInst(inst.operand); + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + return self.resolveInst(ty_op.operand); } }; |
