diff options
| author | Luuk de Gram <luuk@degram.dev> | 2022-10-12 21:18:56 +0200 |
|---|---|---|
| committer | Luuk de Gram <luuk@degram.dev> | 2022-10-16 15:54:16 +0200 |
| commit | b17c8c542420e14e24ec397b248dfc101a08421e (patch) | |
| tree | 3821eba40a5555939f2c1131a7f888bb634c1a13 /src | |
| parent | b9b20b14ea5886aa862927daa7164073aab56132 (diff) | |
| download | zig-b17c8c542420e14e24ec397b248dfc101a08421e.tar.gz zig-b17c8c542420e14e24ec397b248dfc101a08421e.zip | |
wasm: reference count locals
By reference counting the locals, we can ensure that when we free
a local, no local will be reused while it still has references pointing
to it. This prevents misscompilations. The compiler will also panic if
we free a local more than we reference it, introducing extra safety to
ensure they match up.
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 156 |
1 files changed, 84 insertions, 72 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index e82a652d06..b2dedd6d56 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -32,8 +32,13 @@ const WValue = union(enum) { none: void, /// The value lives on top of the stack stack: void, - /// Index of the local variable - local: u32, + /// Index of the local + local: struct { + /// Contains the index to the local + value: u32, + /// The amount of instructions referencing this `WValue` + references: u32, + }, /// An immediate 32bit value imm32: u32, /// An immediate 64bit value @@ -60,7 +65,12 @@ const WValue = union(enum) { function_index: u32, /// Offset from the bottom of the virtual stack, with the offset /// pointing to where the value lives. - stack_offset: u32, + stack_offset: struct { + /// Contains the actual value of the offset + value: u32, + /// The amount of instructions referencing this `WValue` + references: u32, + }, /// Returns the offset from the bottom of the stack. This is useful when /// we use the load or store instruction to ensure we retrieve the value @@ -70,7 +80,7 @@ const WValue = union(enum) { /// loads and stores without requiring checks everywhere. fn offset(self: WValue) u32 { switch (self) { - .stack_offset => |stack_offset| return stack_offset, + .stack_offset => |stack_offset| return stack_offset.value, else => return 0, } } @@ -81,9 +91,9 @@ const WValue = union(enum) { fn toLocal(value: WValue, gen: *Self, ty: Type) InnerError!WValue { switch (value) { .stack => { - const local = try gen.allocLocal(ty); - try gen.addLabel(.local_set, local.local); - return local; + const new_local = try gen.allocLocal(ty); + try gen.addLabel(.local_set, new_local.local.value); + return new_local; }, .local, .stack_offset => return value, else => unreachable, @@ -95,7 +105,7 @@ const WValue = union(enum) { /// The valtype of the local is deducted by using the index of the given `WValue`. fn free(value: *WValue, gen: *Self) void { if (value.* != .local) return; - const local_value = value.local; + const local_value = value.local.value; const reserved = gen.args.len + @boolToInt(gen.return_value != .none) + 2; // 2 for stack locals if (local_value < reserved) return; // reserved locals may never be re-used. @@ -107,7 +117,7 @@ const WValue = union(enum) { .f32 => gen.free_locals_f32.append(gen.gpa, local_value) catch return, .f64 => gen.free_locals_f64.append(gen.gpa, local_value) catch return, } - value.* = WValue{ .none = {} }; + value.* = undefined; } }; @@ -761,7 +771,9 @@ const BigTomb = struct { bt.gen.values.putAssumeCapacityNoClobber(Air.indexToRef(bt.inst), result); } - bt.gen.air_bookkeeping += 1; + if (builtin.mode == .Debug) { + bt.gen.air_bookkeeping += 1; + } } }; @@ -883,7 +895,7 @@ fn genBlockType(ty: Type, target: std.Target) u8 { fn emitWValue(self: *Self, value: WValue) InnerError!void { switch (value) { .none, .stack => {}, // no-op - .local => |idx| try self.addLabel(.local_get, idx), + .local => |idx| try self.addLabel(.local_get, idx.value), .imm32 => |val| try self.addImm32(@bitCast(i32, val)), .imm64 => |val| try self.addImm64(val), .float32 => |val| try self.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }), @@ -907,16 +919,16 @@ fn allocLocal(self: *Self, ty: Type) InnerError!WValue { const valtype = typeToValtype(ty, self.target); switch (valtype) { .i32 => if (self.free_locals_i32.popOrNull()) |index| { - return WValue{ .local = index }; + return WValue{ .local = .{ .value = index, .references = 1 } }; }, .i64 => if (self.free_locals_i64.popOrNull()) |index| { - return WValue{ .local = index }; + return WValue{ .local = .{ .value = index, .references = 1 } }; }, .f32 => if (self.free_locals_f32.popOrNull()) |index| { - return WValue{ .local = index }; + return WValue{ .local = .{ .value = index, .references = 1 } }; }, .f64 => if (self.free_locals_f64.popOrNull()) |index| { - return WValue{ .local = index }; + return WValue{ .local = .{ .value = index, .references = 1 } }; }, } // no local was free to be re-used, so allocate a new local instead @@ -929,7 +941,7 @@ fn ensureAllocLocal(self: *Self, ty: Type) InnerError!WValue { try self.locals.append(self.gpa, genValtype(ty, self.target)); const initial_index = self.local_index; self.local_index += 1; - return WValue{ .local = initial_index }; + return WValue{ .local = .{ .value = initial_index, .references = 1 } }; } /// Generates a `wasm.Type` from a given function type. @@ -1059,7 +1071,7 @@ fn genFunc(self: *Self) InnerError!void { // load stack pointer try prologue.append(.{ .tag = .global_get, .data = .{ .label = 0 } }); // store stack pointer so we can restore it when we return from the function - try prologue.append(.{ .tag = .local_tee, .data = .{ .label = self.initial_stack_value.local } }); + try prologue.append(.{ .tag = .local_tee, .data = .{ .label = self.initial_stack_value.local.value } }); // get the total stack size const aligned_stack = std.mem.alignForwardGeneric(u32, self.stack_size, self.stack_alignment); try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @intCast(i32, aligned_stack) } }); @@ -1070,7 +1082,7 @@ fn genFunc(self: *Self) InnerError!void { // Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } }); // store the current stack pointer as the bottom, which will be used to calculate all stack pointer offsets - try prologue.append(.{ .tag = .local_tee, .data = .{ .label = self.bottom_stack_value.local } }); + try prologue.append(.{ .tag = .local_tee, .data = .{ .label = self.bottom_stack_value.local.value } }); // Store the current stack pointer value into the global stack pointer so other function calls will // start from this value instead and not overwrite the current stack. try prologue.append(.{ .tag = .global_set, .data = .{ .label = 0 } }); @@ -1141,7 +1153,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu if (firstParamSRet(fn_info.cc, fn_info.return_type, self.target)) { // the sret arg will be passed as first argument, therefore we // set the `return_value` before allocating locals for regular args. - result.return_value = .{ .local = self.local_index }; + result.return_value = .{ .local = .{ .value = self.local_index, .references = 1 } }; self.local_index += 1; } @@ -1152,7 +1164,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu continue; } - try args.append(.{ .local = self.local_index }); + try args.append(.{ .local = .{ .value = self.local_index, .references = 1 } }); self.local_index += 1; } }, @@ -1161,7 +1173,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu const ty_classes = abi.classifyType(ty, self.target); for (ty_classes) |class| { if (class == .none) continue; - try args.append(.{ .local = self.local_index }); + try args.append(.{ .local = .{ .value = self.local_index, .references = 1 } }); self.local_index += 1; } } @@ -1254,14 +1266,14 @@ fn lowerToStack(self: *Self, value: WValue) !void { switch (value) { .stack_offset => |offset| { try self.emitWValue(value); - if (offset > 0) { + if (offset.value > 0) { switch (self.arch()) { .wasm32 => { - try self.addImm32(@bitCast(i32, offset)); + try self.addImm32(@bitCast(i32, offset.value)); try self.addTag(.i32_add); }, .wasm64 => { - try self.addImm64(offset); + try self.addImm64(offset.value); try self.addTag(.i64_add); }, else => unreachable, @@ -1323,7 +1335,7 @@ fn allocStack(self: *Self, ty: Type) !WValue { const offset = std.mem.alignForwardGeneric(u32, self.stack_size, abi_align); defer self.stack_size = offset + abi_size; - return WValue{ .stack_offset = offset }; + return WValue{ .stack_offset = .{ .value = offset, .references = 1 } }; } /// From a given AIR instruction generates a pointer to the stack where @@ -1356,7 +1368,7 @@ fn allocStackPtr(self: *Self, inst: Air.Inst.Index) !WValue { const offset = std.mem.alignForwardGeneric(u32, self.stack_size, abi_alignment); defer self.stack_size = offset + abi_size; - return WValue{ .stack_offset = offset }; + return WValue{ .stack_offset = .{ .value = offset, .references = 1 } }; } /// From given zig bitsize, returns the wasm bitsize @@ -1475,7 +1487,7 @@ fn memcpy(self: *Self, dst: WValue, src: WValue, len: WValue) !void { }, else => unreachable, } - try self.addLabel(.local_set, offset.local); + try self.addLabel(.local_set, offset.local.value); try self.addLabel(.br, 0); // jump to start of loop } try self.endBlock(); // close off loop block @@ -1568,7 +1580,7 @@ fn buildPointerOffset(self: *Self, ptr_value: WValue, offset: u64, action: enum else => unreachable, } } - try self.addLabel(.local_set, result_ptr.local); + try self.addLabel(.local_set, result_ptr.local.value); return result_ptr; } @@ -1984,14 +1996,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. // TODO: Make this less fragile and optimize } else if (fn_ty.fnInfo().cc == .C and ret_ty.zigTypeTag() == .Struct or ret_ty.zigTypeTag() == .Union) { const result_local = try self.allocLocal(ret_ty); - try self.addLabel(.local_set, result_local.local); + try self.addLabel(.local_set, result_local.local.value); const scalar_type = abi.scalarType(ret_ty, self.target); const result = try self.allocStack(scalar_type); try self.store(result, result_local, scalar_type, 0); break :result_value result; } else { const result_local = try self.allocLocal(ret_ty); - try self.addLabel(.local_set, result_local.local); + try self.addLabel(.local_set, result_local.local.value); break :result_value result_local; } }; @@ -2175,7 +2187,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!void { .dwarf => |dwarf| { // TODO: Get the original arg index rather than wasm arg index const name = self.mod_fn.getParamName(self.bin_file.base.options.module.?, arg_index); - const leb_size = link.File.Wasm.getULEB128Size(arg.local); + const leb_size = link.File.Wasm.getULEB128Size(arg.local.value); const dbg_info = &dwarf.dbg_info; try dbg_info.ensureUnusedCapacity(3 + leb_size + 5 + name.len + 1); // wasm locations are encoded as follow: @@ -2189,7 +2201,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!void { std.dwarf.OP.WASM_location, std.dwarf.OP.WASM_local, }); - leb.writeULEB128(dbg_info.writer(), arg.local) catch unreachable; + leb.writeULEB128(dbg_info.writer(), arg.local.value) catch unreachable; try self.addDbgInfoTypeReloc(arg_ty); dbg_info.appendSliceAssumeCapacity(name); dbg_info.appendAssumeCapacity(0); @@ -2869,7 +2881,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!void { try self.lowerToStack(operand); if (block.value != .none) { - try self.addLabel(.local_set, block.value.local); + try self.addLabel(.local_set, block.value.local.value); } } @@ -2893,7 +2905,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!void { try self.emitWValue(operand); try self.addTag(.i32_eqz); const not_tmp = try self.allocLocal(operand_ty); - try self.addLabel(.local_set, not_tmp.local); + try self.addLabel(.local_set, not_tmp.local.value); break :result not_tmp; } else { const operand_bits = operand_ty.intInfo(self.target).bits; @@ -2985,7 +2997,7 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerEr fn structFieldPtr(self: *Self, struct_ptr: WValue, offset: u32) InnerError!WValue { switch (struct_ptr) { .stack_offset => |stack_offset| { - return WValue{ .stack_offset = stack_offset + offset }; + return WValue{ .stack_offset = .{ .value = stack_offset.value + offset, .references = 1 } }; }, else => return self.buildPointerOffset(struct_ptr, offset, .new), } @@ -3011,7 +3023,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!void { if (isByRef(field_ty, self.target)) { switch (operand) { .stack_offset => |stack_offset| { - break :result WValue{ .stack_offset = stack_offset + offset }; + break :result WValue{ .stack_offset = .{ .value = stack_offset.value + offset, .references = 1 } }; }, else => break :result try self.buildPointerOffset(operand, offset, .new), } @@ -3214,7 +3226,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!v try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); const is_err_tmp = try self.allocLocal(Type.i32); - try self.addLabel(.local_set, is_err_tmp.local); + try self.addLabel(.local_set, is_err_tmp.local.value); break :result is_err_tmp; }; self.finishAir(inst, result, &.{un_op}); @@ -3578,7 +3590,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!void { try self.addTag(.i32_add); const result_ptr = try self.allocLocal(elem_ty); - try self.addLabel(.local_set, result_ptr.local); + try self.addLabel(.local_set, result_ptr.local.value); const result = if (!isByRef(elem_ty, self.target)) result: { const elem_val = try self.load(result_ptr, elem_ty, 0); @@ -3608,7 +3620,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!void { try self.addTag(.i32_add); const result = try self.allocLocal(Type.i32); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); } @@ -3715,7 +3727,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!void { const elem_result = val: { var result = try self.allocLocal(elem_ty); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); if (isByRef(elem_ty, self.target)) { break :val result; } @@ -3753,7 +3765,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!void { try self.addTag(.i32_add); const result = try self.allocLocal(Type.i32); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); } @@ -3781,7 +3793,7 @@ fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!void { try self.addTag(Mir.Inst.Tag.fromOpcode(bin_opcode)); const result = try self.allocLocal(Type.usize); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); } @@ -3874,7 +3886,7 @@ fn memset(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void .wasm64 => try self.addTag(.i64_add), else => unreachable, } - try self.addLabel(.local_set, offset.local); + try self.addLabel(.local_set, offset.local.value); try self.addLabel(.br, 0); // jump to start of loop try self.endBlock(); try self.endBlock(); @@ -3900,7 +3912,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!void { const elem_result = val: { var result = try self.allocLocal(Type.usize); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); if (isByRef(elem_ty, self.target)) { break :val result; @@ -3961,7 +3973,7 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!void { try self.addTag(Mir.Inst.Tag.fromOpcode(op)); const result = try self.allocLocal(dest_ty); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); self.finishAir(inst, result, &.{ty_op.operand}); } @@ -4107,7 +4119,7 @@ fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) InnerError!void { const result = try self.allocLocal(self.air.typeOfIndex(inst)); try self.addLabel(.memory_size, pl_op.payload); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); self.finishAir(inst, result, &.{pl_op.operand}); } @@ -4119,7 +4131,7 @@ fn airWasmMemoryGrow(self: *Self, inst: Air.Inst.Index) !void { const result = try self.allocLocal(self.air.typeOfIndex(inst)); try self.emitWValue(operand); try self.addLabel(.memory_grow, pl_op.payload); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); self.finishAir(inst, result, &.{pl_op.operand}); } @@ -4148,7 +4160,7 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std try self.addLabel(.br_if, 0); try self.addImm32(1); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); try self.endBlock(); try self.emitWValue(result); @@ -4363,10 +4375,10 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) InnerError!void { const result = if (field_offset != 0) result: { const base = try self.buildPointerOffset(field_ptr, 0, .new); - try self.addLabel(.local_get, base.local); + try self.addLabel(.local_get, base.local.value); try self.addImm32(@bitCast(i32, @intCast(u32, field_offset))); try self.addTag(.i32_sub); - try self.addLabel(.local_set, base.local); + try self.addLabel(.local_set, base.local.value); break :result base; } else field_ptr; @@ -4425,7 +4437,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) InnerError!void { } const result = try self.allocLocal(result_ty); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); self.finishAir(inst, result, &.{ty_op.operand}); } @@ -4467,7 +4479,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) InnerError!void { } const result_ptr = try self.allocLocal(Type.usize); - try self.addLabel(.local_set, result_ptr.local); + try self.addLabel(.local_set, result_ptr.local.value); self.finishAir(inst, result_ptr, &.{un_op}); } @@ -4714,7 +4726,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!void { const shr = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr); const wrap = try self.intcast(shr, new_ty, lhs_ty); _ = try self.cmp(wrap, zero, lhs_ty, .neq); - try self.addLabel(.local_set, overflow_bit.local); + try self.addLabel(.local_set, overflow_bit.local.value); break :blk try self.intcast(bin_op, new_ty, lhs_ty); } else { const down_cast = try (try self.intcast(bin_op, new_ty, lhs_ty)).toLocal(self, lhs_ty); @@ -4724,7 +4736,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!void { const shr_res = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr); const down_shr_res = try self.intcast(shr_res, new_ty, lhs_ty); _ = try self.cmp(down_shr_res, shr, lhs_ty, .neq); - try self.addLabel(.local_set, overflow_bit.local); + try self.addLabel(.local_set, overflow_bit.local.value); break :blk down_cast; } } else if (int_info.signedness == .signed) blk: { @@ -4733,7 +4745,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!void { const bin_op = try (try self.binOp(lhs_abs, rhs_abs, lhs_ty, .mul)).toLocal(self, lhs_ty); const mul_abs = try self.signAbsValue(bin_op, lhs_ty); _ = try self.cmp(mul_abs, bin_op, lhs_ty, .neq); - try self.addLabel(.local_set, overflow_bit.local); + try self.addLabel(.local_set, overflow_bit.local.value); break :blk try self.wrapOperand(bin_op, lhs_ty); } else blk: { var bin_op = try (try self.binOp(lhs, rhs, lhs_ty, .mul)).toLocal(self, lhs_ty); @@ -4744,7 +4756,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!void { WValue{ .imm64 = int_info.bits }; const shr = try self.binOp(bin_op, shift_imm, lhs_ty, .shr); _ = try self.cmp(shr, zero, lhs_ty, .neq); - try self.addLabel(.local_set, overflow_bit.local); + try self.addLabel(.local_set, overflow_bit.local.value); break :blk try self.wrapOperand(bin_op, lhs_ty); }; var bin_op_local = try bin_op.toLocal(self, lhs_ty); @@ -4785,7 +4797,7 @@ fn airMaxMin(self: *Self, inst: Air.Inst.Index, op: enum { max, min }) InnerErro // store result in local const result_ty = if (isByRef(ty, self.target)) Type.u32 else ty; const result = try self.allocLocal(result_ty); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); } @@ -4872,7 +4884,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!void { } const result = try self.allocLocal(result_ty); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); self.finishAir(inst, result, &.{ty_op.operand}); } @@ -4937,7 +4949,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!void { } const result = try self.allocLocal(result_ty); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); self.finishAir(inst, result, &.{ty_op.operand}); } @@ -4958,7 +4970,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index, is_ptr: bool) !void { try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable)); switch (operand) { .local => |local| { - const leb_size = link.File.Wasm.getULEB128Size(local); + const leb_size = link.File.Wasm.getULEB128Size(local.value); try dbg_info.ensureUnusedCapacity(2 + leb_size); // wasm locals are encoded as follow: // DW_OP_WASM_location wasm-op @@ -4970,7 +4982,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index, is_ptr: bool) !void { std.dwarf.OP.WASM_location, std.dwarf.OP.WASM_local, }); - leb.writeULEB128(dbg_info.writer(), local) catch unreachable; + leb.writeULEB128(dbg_info.writer(), local.value) catch unreachable; }, else => {}, // TODO } @@ -5179,7 +5191,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!void { const div_result = try self.allocLocal(ty); // leave on stack _ = try self.binOp(lhs_res, rhs_res, ty, .div); - try self.addLabel(.local_tee, div_result.local); + try self.addLabel(.local_tee, div_result.local.value); _ = try self.cmp(lhs_res, zero, ty, .lt); _ = try self.cmp(rhs_res, zero, ty, .lt); switch (wasm_bits) { @@ -5232,7 +5244,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!void { } const result = try self.allocLocal(ty); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); } @@ -5257,7 +5269,7 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue try self.addTag(.i32_div_s); const result = try self.allocLocal(ty); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); return result; } @@ -5323,7 +5335,7 @@ fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!void } const result = try self.allocLocal(ty); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); self.finishAir(inst, result, &.{un_op}); } @@ -5374,7 +5386,7 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!void { try self.addTag(.select); const result = try self.allocLocal(ty); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); return self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); } @@ -5412,13 +5424,13 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op try self.emitWValue(max_wvalue); _ = try self.cmp(bin_result, max_wvalue, ty, .lt); try self.addTag(.select); - try self.addLabel(.local_set, bin_result.local); // re-use local + try self.addLabel(.local_set, bin_result.local.value); // re-use local try self.emitWValue(bin_result); try self.emitWValue(min_wvalue); _ = try self.cmp(bin_result, min_wvalue, ty, .gt); try self.addTag(.select); - try self.addLabel(.local_set, bin_result.local); // re-use local + try self.addLabel(.local_set, bin_result.local.value); // re-use local return (try self.wrapOperand(bin_result, ty)).toLocal(self, ty); } else { const zero = switch (wasm_bits) { @@ -5436,7 +5448,7 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op const cmp_bin_result = try self.cmp(bin_result, lhs, ty, .lt); _ = try self.binOp(cmp_zero_result, cmp_bin_result, Type.u32, .xor); // comparisons always return i32, so provide u32 as type to xor. try self.addTag(.select); - try self.addLabel(.local_set, bin_result.local); // re-use local + try self.addLabel(.local_set, bin_result.local.value); // re-use local return bin_result; } } @@ -5489,7 +5501,7 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!void { try self.emitWValue(shl); _ = try self.cmp(lhs, shr, ty, .neq); try self.addTag(.select); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); break :outer_blk; } else { const shift_size = wasm_bits - int_info.bits; @@ -5534,12 +5546,12 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!void { try self.emitWValue(shl); _ = try self.cmp(shl_res, shr, ty, .neq); try self.addTag(.select); - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); var shift_result = try self.binOp(result, shift_value, ty, .shr); if (is_signed) { shift_result = try self.wrapOperand(shift_result, ty); } - try self.addLabel(.local_set, result.local); + try self.addLabel(.local_set, result.local.value); } return self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
