authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-10-12 21:18:56+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-10-16 15:54:16+02:00
logb17c8c542420e14e24ec397b248dfc101a08421e
tree3821eba40a5555939f2c1131a7f888bb634c1a13
parentb9b20b14ea5886aa862927daa7164073aab56132
signaturelock-open Commit is signed but in an unrecognized format.

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.

1 files changed, 84 insertions(+), 72 deletions(-)

src/arch/wasm/CodeGen.zig+84-72
......@@ -32,8 +32,13 @@ const WValue = union(enum) {
3232 none: void,
3333 /// The value lives on top of the stack
3434 stack: void,
35 /// Index of the local variable
36 local: u32,
35 /// Index of the local
36 local: struct {
37 /// Contains the index to the local
38 value: u32,
39 /// The amount of instructions referencing this `WValue`
40 references: u32,
41 },
3742 /// An immediate 32bit value
3843 imm32: u32,
3944 /// An immediate 64bit value
......@@ -60,7 +65,12 @@ const WValue = union(enum) {
6065 function_index: u32,
6166 /// Offset from the bottom of the virtual stack, with the offset
6267 /// pointing to where the value lives.
63 stack_offset: u32,
68 stack_offset: struct {
69 /// Contains the actual value of the offset
70 value: u32,
71 /// The amount of instructions referencing this `WValue`
72 references: u32,
73 },
6474
6575 /// Returns the offset from the bottom of the stack. This is useful when
6676 /// we use the load or store instruction to ensure we retrieve the value
......@@ -70,7 +80,7 @@ const WValue = union(enum) {
7080 /// loads and stores without requiring checks everywhere.
7181 fn offset(self: WValue) u32 {
7282 switch (self) {
73 .stack_offset => |stack_offset| return stack_offset,
83 .stack_offset => |stack_offset| return stack_offset.value,
7484 else => return 0,
7585 }
7686 }
......@@ -81,9 +91,9 @@ const WValue = union(enum) {
8191 fn toLocal(value: WValue, gen: *Self, ty: Type) InnerError!WValue {
8292 switch (value) {
8393 .stack => {
84 const local = try gen.allocLocal(ty);
85 try gen.addLabel(.local_set, local.local);
86 return local;
94 const new_local = try gen.allocLocal(ty);
95 try gen.addLabel(.local_set, new_local.local.value);
96 return new_local;
8797 },
8898 .local, .stack_offset => return value,
8999 else => unreachable,
......@@ -95,7 +105,7 @@ const WValue = union(enum) {
95105 /// The valtype of the local is deducted by using the index of the given `WValue`.
96106 fn free(value: *WValue, gen: *Self) void {
97107 if (value.* != .local) return;
98 const local_value = value.local;
108 const local_value = value.local.value;
99109 const reserved = gen.args.len + @boolToInt(gen.return_value != .none) + 2; // 2 for stack locals
100110 if (local_value < reserved) return; // reserved locals may never be re-used.
101111
......@@ -107,7 +117,7 @@ const WValue = union(enum) {
107117 .f32 => gen.free_locals_f32.append(gen.gpa, local_value) catch return,
108118 .f64 => gen.free_locals_f64.append(gen.gpa, local_value) catch return,
109119 }
110 value.* = WValue{ .none = {} };
120 value.* = undefined;
111121 }
112122};
113123
......@@ -761,7 +771,9 @@ const BigTomb = struct {
761771 bt.gen.values.putAssumeCapacityNoClobber(Air.indexToRef(bt.inst), result);
762772 }
763773
764 bt.gen.air_bookkeeping += 1;
774 if (builtin.mode == .Debug) {
775 bt.gen.air_bookkeeping += 1;
776 }
765777 }
766778};
767779
......@@ -883,7 +895,7 @@ fn genBlockType(ty: Type, target: std.Target) u8 {
883895fn emitWValue(self: *Self, value: WValue) InnerError!void {
884896 switch (value) {
885897 .none, .stack => {}, // no-op
886 .local => |idx| try self.addLabel(.local_get, idx),
898 .local => |idx| try self.addLabel(.local_get, idx.value),
887899 .imm32 => |val| try self.addImm32(@bitCast(i32, val)),
888900 .imm64 => |val| try self.addImm64(val),
889901 .float32 => |val| try self.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }),
......@@ -907,16 +919,16 @@ fn allocLocal(self: *Self, ty: Type) InnerError!WValue {
907919 const valtype = typeToValtype(ty, self.target);
908920 switch (valtype) {
909921 .i32 => if (self.free_locals_i32.popOrNull()) |index| {
910 return WValue{ .local = index };
922 return WValue{ .local = .{ .value = index, .references = 1 } };
911923 },
912924 .i64 => if (self.free_locals_i64.popOrNull()) |index| {
913 return WValue{ .local = index };
925 return WValue{ .local = .{ .value = index, .references = 1 } };
914926 },
915927 .f32 => if (self.free_locals_f32.popOrNull()) |index| {
916 return WValue{ .local = index };
928 return WValue{ .local = .{ .value = index, .references = 1 } };
917929 },
918930 .f64 => if (self.free_locals_f64.popOrNull()) |index| {
919 return WValue{ .local = index };
931 return WValue{ .local = .{ .value = index, .references = 1 } };
920932 },
921933 }
922934 // 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 {
929941 try self.locals.append(self.gpa, genValtype(ty, self.target));
930942 const initial_index = self.local_index;
931943 self.local_index += 1;
932 return WValue{ .local = initial_index };
944 return WValue{ .local = .{ .value = initial_index, .references = 1 } };
933945}
934946
935947/// Generates a `wasm.Type` from a given function type.
......@@ -1059,7 +1071,7 @@ fn genFunc(self: *Self) InnerError!void {
10591071 // load stack pointer
10601072 try prologue.append(.{ .tag = .global_get, .data = .{ .label = 0 } });
10611073 // store stack pointer so we can restore it when we return from the function
1062 try prologue.append(.{ .tag = .local_tee, .data = .{ .label = self.initial_stack_value.local } });
1074 try prologue.append(.{ .tag = .local_tee, .data = .{ .label = self.initial_stack_value.local.value } });
10631075 // get the total stack size
10641076 const aligned_stack = std.mem.alignForwardGeneric(u32, self.stack_size, self.stack_alignment);
10651077 try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @intCast(i32, aligned_stack) } });
......@@ -1070,7 +1082,7 @@ fn genFunc(self: *Self) InnerError!void {
10701082 // Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment
10711083 try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } });
10721084 // store the current stack pointer as the bottom, which will be used to calculate all stack pointer offsets
1073 try prologue.append(.{ .tag = .local_tee, .data = .{ .label = self.bottom_stack_value.local } });
1085 try prologue.append(.{ .tag = .local_tee, .data = .{ .label = self.bottom_stack_value.local.value } });
10741086 // Store the current stack pointer value into the global stack pointer so other function calls will
10751087 // start from this value instead and not overwrite the current stack.
10761088 try prologue.append(.{ .tag = .global_set, .data = .{ .label = 0 } });
......@@ -1141,7 +1153,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
11411153 if (firstParamSRet(fn_info.cc, fn_info.return_type, self.target)) {
11421154 // the sret arg will be passed as first argument, therefore we
11431155 // set the `return_value` before allocating locals for regular args.
1144 result.return_value = .{ .local = self.local_index };
1156 result.return_value = .{ .local = .{ .value = self.local_index, .references = 1 } };
11451157 self.local_index += 1;
11461158 }
11471159
......@@ -1152,7 +1164,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
11521164 continue;
11531165 }
11541166
1155 try args.append(.{ .local = self.local_index });
1167 try args.append(.{ .local = .{ .value = self.local_index, .references = 1 } });
11561168 self.local_index += 1;
11571169 }
11581170 },
......@@ -1161,7 +1173,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
11611173 const ty_classes = abi.classifyType(ty, self.target);
11621174 for (ty_classes) |class| {
11631175 if (class == .none) continue;
1164 try args.append(.{ .local = self.local_index });
1176 try args.append(.{ .local = .{ .value = self.local_index, .references = 1 } });
11651177 self.local_index += 1;
11661178 }
11671179 }
......@@ -1254,14 +1266,14 @@ fn lowerToStack(self: *Self, value: WValue) !void {
12541266 switch (value) {
12551267 .stack_offset => |offset| {
12561268 try self.emitWValue(value);
1257 if (offset > 0) {
1269 if (offset.value > 0) {
12581270 switch (self.arch()) {
12591271 .wasm32 => {
1260 try self.addImm32(@bitCast(i32, offset));
1272 try self.addImm32(@bitCast(i32, offset.value));
12611273 try self.addTag(.i32_add);
12621274 },
12631275 .wasm64 => {
1264 try self.addImm64(offset);
1276 try self.addImm64(offset.value);
12651277 try self.addTag(.i64_add);
12661278 },
12671279 else => unreachable,
......@@ -1323,7 +1335,7 @@ fn allocStack(self: *Self, ty: Type) !WValue {
13231335 const offset = std.mem.alignForwardGeneric(u32, self.stack_size, abi_align);
13241336 defer self.stack_size = offset + abi_size;
13251337
1326 return WValue{ .stack_offset = offset };
1338 return WValue{ .stack_offset = .{ .value = offset, .references = 1 } };
13271339}
13281340
13291341/// 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 {
13561368 const offset = std.mem.alignForwardGeneric(u32, self.stack_size, abi_alignment);
13571369 defer self.stack_size = offset + abi_size;
13581370
1359 return WValue{ .stack_offset = offset };
1371 return WValue{ .stack_offset = .{ .value = offset, .references = 1 } };
13601372}
13611373
13621374/// From given zig bitsize, returns the wasm bitsize
......@@ -1475,7 +1487,7 @@ fn memcpy(self: *Self, dst: WValue, src: WValue, len: WValue) !void {
14751487 },
14761488 else => unreachable,
14771489 }
1478 try self.addLabel(.local_set, offset.local);
1490 try self.addLabel(.local_set, offset.local.value);
14791491 try self.addLabel(.br, 0); // jump to start of loop
14801492 }
14811493 try self.endBlock(); // close off loop block
......@@ -1568,7 +1580,7 @@ fn buildPointerOffset(self: *Self, ptr_value: WValue, offset: u64, action: enum
15681580 else => unreachable,
15691581 }
15701582 }
1571 try self.addLabel(.local_set, result_ptr.local);
1583 try self.addLabel(.local_set, result_ptr.local.value);
15721584 return result_ptr;
15731585}
15741586
......@@ -1984,14 +1996,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
19841996 // TODO: Make this less fragile and optimize
19851997 } else if (fn_ty.fnInfo().cc == .C and ret_ty.zigTypeTag() == .Struct or ret_ty.zigTypeTag() == .Union) {
19861998 const result_local = try self.allocLocal(ret_ty);
1987 try self.addLabel(.local_set, result_local.local);
1999 try self.addLabel(.local_set, result_local.local.value);
19882000 const scalar_type = abi.scalarType(ret_ty, self.target);
19892001 const result = try self.allocStack(scalar_type);
19902002 try self.store(result, result_local, scalar_type, 0);
19912003 break :result_value result;
19922004 } else {
19932005 const result_local = try self.allocLocal(ret_ty);
1994 try self.addLabel(.local_set, result_local.local);
2006 try self.addLabel(.local_set, result_local.local.value);
19952007 break :result_value result_local;
19962008 }
19972009 };
......@@ -2175,7 +2187,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!void {
21752187 .dwarf => |dwarf| {
21762188 // TODO: Get the original arg index rather than wasm arg index
21772189 const name = self.mod_fn.getParamName(self.bin_file.base.options.module.?, arg_index);
2178 const leb_size = link.File.Wasm.getULEB128Size(arg.local);
2190 const leb_size = link.File.Wasm.getULEB128Size(arg.local.value);
21792191 const dbg_info = &dwarf.dbg_info;
21802192 try dbg_info.ensureUnusedCapacity(3 + leb_size + 5 + name.len + 1);
21812193 // wasm locations are encoded as follow:
......@@ -2189,7 +2201,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!void {
21892201 std.dwarf.OP.WASM_location,
21902202 std.dwarf.OP.WASM_local,
21912203 });
2192 leb.writeULEB128(dbg_info.writer(), arg.local) catch unreachable;
2204 leb.writeULEB128(dbg_info.writer(), arg.local.value) catch unreachable;
21932205 try self.addDbgInfoTypeReloc(arg_ty);
21942206 dbg_info.appendSliceAssumeCapacity(name);
21952207 dbg_info.appendAssumeCapacity(0);
......@@ -2869,7 +2881,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!void {
28692881 try self.lowerToStack(operand);
28702882
28712883 if (block.value != .none) {
2872 try self.addLabel(.local_set, block.value.local);
2884 try self.addLabel(.local_set, block.value.local.value);
28732885 }
28742886 }
28752887
......@@ -2893,7 +2905,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!void {
28932905 try self.emitWValue(operand);
28942906 try self.addTag(.i32_eqz);
28952907 const not_tmp = try self.allocLocal(operand_ty);
2896 try self.addLabel(.local_set, not_tmp.local);
2908 try self.addLabel(.local_set, not_tmp.local.value);
28972909 break :result not_tmp;
28982910 } else {
28992911 const operand_bits = operand_ty.intInfo(self.target).bits;
......@@ -2985,7 +2997,7 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerEr
29852997fn structFieldPtr(self: *Self, struct_ptr: WValue, offset: u32) InnerError!WValue {
29862998 switch (struct_ptr) {
29872999 .stack_offset => |stack_offset| {
2988 return WValue{ .stack_offset = stack_offset + offset };
3000 return WValue{ .stack_offset = .{ .value = stack_offset.value + offset, .references = 1 } };
29893001 },
29903002 else => return self.buildPointerOffset(struct_ptr, offset, .new),
29913003 }
......@@ -3011,7 +3023,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!void {
30113023 if (isByRef(field_ty, self.target)) {
30123024 switch (operand) {
30133025 .stack_offset => |stack_offset| {
3014 break :result WValue{ .stack_offset = stack_offset + offset };
3026 break :result WValue{ .stack_offset = .{ .value = stack_offset.value + offset, .references = 1 } };
30153027 },
30163028 else => break :result try self.buildPointerOffset(operand, offset, .new),
30173029 }
......@@ -3214,7 +3226,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!v
32143226 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
32153227
32163228 const is_err_tmp = try self.allocLocal(Type.i32);
3217 try self.addLabel(.local_set, is_err_tmp.local);
3229 try self.addLabel(.local_set, is_err_tmp.local.value);
32183230 break :result is_err_tmp;
32193231 };
32203232 self.finishAir(inst, result, &.{un_op});
......@@ -3578,7 +3590,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!void {
35783590 try self.addTag(.i32_add);
35793591
35803592 const result_ptr = try self.allocLocal(elem_ty);
3581 try self.addLabel(.local_set, result_ptr.local);
3593 try self.addLabel(.local_set, result_ptr.local.value);
35823594
35833595 const result = if (!isByRef(elem_ty, self.target)) result: {
35843596 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 {
36083620 try self.addTag(.i32_add);
36093621
36103622 const result = try self.allocLocal(Type.i32);
3611 try self.addLabel(.local_set, result.local);
3623 try self.addLabel(.local_set, result.local.value);
36123624 self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
36133625}
36143626
......@@ -3715,7 +3727,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!void {
37153727
37163728 const elem_result = val: {
37173729 var result = try self.allocLocal(elem_ty);
3718 try self.addLabel(.local_set, result.local);
3730 try self.addLabel(.local_set, result.local.value);
37193731 if (isByRef(elem_ty, self.target)) {
37203732 break :val result;
37213733 }
......@@ -3753,7 +3765,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!void {
37533765 try self.addTag(.i32_add);
37543766
37553767 const result = try self.allocLocal(Type.i32);
3756 try self.addLabel(.local_set, result.local);
3768 try self.addLabel(.local_set, result.local.value);
37573769 self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
37583770}
37593771
......@@ -3781,7 +3793,7 @@ fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!void {
37813793 try self.addTag(Mir.Inst.Tag.fromOpcode(bin_opcode));
37823794
37833795 const result = try self.allocLocal(Type.usize);
3784 try self.addLabel(.local_set, result.local);
3796 try self.addLabel(.local_set, result.local.value);
37853797 self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
37863798}
37873799
......@@ -3874,7 +3886,7 @@ fn memset(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void
38743886 .wasm64 => try self.addTag(.i64_add),
38753887 else => unreachable,
38763888 }
3877 try self.addLabel(.local_set, offset.local);
3889 try self.addLabel(.local_set, offset.local.value);
38783890 try self.addLabel(.br, 0); // jump to start of loop
38793891 try self.endBlock();
38803892 try self.endBlock();
......@@ -3900,7 +3912,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!void {
39003912
39013913 const elem_result = val: {
39023914 var result = try self.allocLocal(Type.usize);
3903 try self.addLabel(.local_set, result.local);
3915 try self.addLabel(.local_set, result.local.value);
39043916
39053917 if (isByRef(elem_ty, self.target)) {
39063918 break :val result;
......@@ -3961,7 +3973,7 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!void {
39613973 try self.addTag(Mir.Inst.Tag.fromOpcode(op));
39623974
39633975 const result = try self.allocLocal(dest_ty);
3964 try self.addLabel(.local_set, result.local);
3976 try self.addLabel(.local_set, result.local.value);
39653977 self.finishAir(inst, result, &.{ty_op.operand});
39663978}
39673979
......@@ -4107,7 +4119,7 @@ fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) InnerError!void {
41074119
41084120 const result = try self.allocLocal(self.air.typeOfIndex(inst));
41094121 try self.addLabel(.memory_size, pl_op.payload);
4110 try self.addLabel(.local_set, result.local);
4122 try self.addLabel(.local_set, result.local.value);
41114123 self.finishAir(inst, result, &.{pl_op.operand});
41124124}
41134125
......@@ -4119,7 +4131,7 @@ fn airWasmMemoryGrow(self: *Self, inst: Air.Inst.Index) !void {
41194131 const result = try self.allocLocal(self.air.typeOfIndex(inst));
41204132 try self.emitWValue(operand);
41214133 try self.addLabel(.memory_grow, pl_op.payload);
4122 try self.addLabel(.local_set, result.local);
4134 try self.addLabel(.local_set, result.local.value);
41234135 self.finishAir(inst, result, &.{pl_op.operand});
41244136}
41254137
......@@ -4148,7 +4160,7 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std
41484160 try self.addLabel(.br_if, 0);
41494161
41504162 try self.addImm32(1);
4151 try self.addLabel(.local_set, result.local);
4163 try self.addLabel(.local_set, result.local.value);
41524164 try self.endBlock();
41534165
41544166 try self.emitWValue(result);
......@@ -4363,10 +4375,10 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) InnerError!void {
43634375
43644376 const result = if (field_offset != 0) result: {
43654377 const base = try self.buildPointerOffset(field_ptr, 0, .new);
4366 try self.addLabel(.local_get, base.local);
4378 try self.addLabel(.local_get, base.local.value);
43674379 try self.addImm32(@bitCast(i32, @intCast(u32, field_offset)));
43684380 try self.addTag(.i32_sub);
4369 try self.addLabel(.local_set, base.local);
4381 try self.addLabel(.local_set, base.local.value);
43704382 break :result base;
43714383 } else field_ptr;
43724384
......@@ -4425,7 +4437,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) InnerError!void {
44254437 }
44264438
44274439 const result = try self.allocLocal(result_ty);
4428 try self.addLabel(.local_set, result.local);
4440 try self.addLabel(.local_set, result.local.value);
44294441 self.finishAir(inst, result, &.{ty_op.operand});
44304442}
44314443
......@@ -4467,7 +4479,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) InnerError!void {
44674479 }
44684480
44694481 const result_ptr = try self.allocLocal(Type.usize);
4470 try self.addLabel(.local_set, result_ptr.local);
4482 try self.addLabel(.local_set, result_ptr.local.value);
44714483 self.finishAir(inst, result_ptr, &.{un_op});
44724484}
44734485
......@@ -4714,7 +4726,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!void {
47144726 const shr = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr);
47154727 const wrap = try self.intcast(shr, new_ty, lhs_ty);
47164728 _ = try self.cmp(wrap, zero, lhs_ty, .neq);
4717 try self.addLabel(.local_set, overflow_bit.local);
4729 try self.addLabel(.local_set, overflow_bit.local.value);
47184730 break :blk try self.intcast(bin_op, new_ty, lhs_ty);
47194731 } else {
47204732 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 {
47244736 const shr_res = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr);
47254737 const down_shr_res = try self.intcast(shr_res, new_ty, lhs_ty);
47264738 _ = try self.cmp(down_shr_res, shr, lhs_ty, .neq);
4727 try self.addLabel(.local_set, overflow_bit.local);
4739 try self.addLabel(.local_set, overflow_bit.local.value);
47284740 break :blk down_cast;
47294741 }
47304742 } else if (int_info.signedness == .signed) blk: {
......@@ -4733,7 +4745,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!void {
47334745 const bin_op = try (try self.binOp(lhs_abs, rhs_abs, lhs_ty, .mul)).toLocal(self, lhs_ty);
47344746 const mul_abs = try self.signAbsValue(bin_op, lhs_ty);
47354747 _ = try self.cmp(mul_abs, bin_op, lhs_ty, .neq);
4736 try self.addLabel(.local_set, overflow_bit.local);
4748 try self.addLabel(.local_set, overflow_bit.local.value);
47374749 break :blk try self.wrapOperand(bin_op, lhs_ty);
47384750 } else blk: {
47394751 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 {
47444756 WValue{ .imm64 = int_info.bits };
47454757 const shr = try self.binOp(bin_op, shift_imm, lhs_ty, .shr);
47464758 _ = try self.cmp(shr, zero, lhs_ty, .neq);
4747 try self.addLabel(.local_set, overflow_bit.local);
4759 try self.addLabel(.local_set, overflow_bit.local.value);
47484760 break :blk try self.wrapOperand(bin_op, lhs_ty);
47494761 };
47504762 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
47854797 // store result in local
47864798 const result_ty = if (isByRef(ty, self.target)) Type.u32 else ty;
47874799 const result = try self.allocLocal(result_ty);
4788 try self.addLabel(.local_set, result.local);
4800 try self.addLabel(.local_set, result.local.value);
47894801 self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
47904802}
47914803
......@@ -4872,7 +4884,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!void {
48724884 }
48734885
48744886 const result = try self.allocLocal(result_ty);
4875 try self.addLabel(.local_set, result.local);
4887 try self.addLabel(.local_set, result.local.value);
48764888 self.finishAir(inst, result, &.{ty_op.operand});
48774889}
48784890
......@@ -4937,7 +4949,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!void {
49374949 }
49384950
49394951 const result = try self.allocLocal(result_ty);
4940 try self.addLabel(.local_set, result.local);
4952 try self.addLabel(.local_set, result.local.value);
49414953 self.finishAir(inst, result, &.{ty_op.operand});
49424954}
49434955
......@@ -4958,7 +4970,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index, is_ptr: bool) !void {
49584970 try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
49594971 switch (operand) {
49604972 .local => |local| {
4961 const leb_size = link.File.Wasm.getULEB128Size(local);
4973 const leb_size = link.File.Wasm.getULEB128Size(local.value);
49624974 try dbg_info.ensureUnusedCapacity(2 + leb_size);
49634975 // wasm locals are encoded as follow:
49644976 // DW_OP_WASM_location wasm-op
......@@ -4970,7 +4982,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index, is_ptr: bool) !void {
49704982 std.dwarf.OP.WASM_location,
49714983 std.dwarf.OP.WASM_local,
49724984 });
4973 leb.writeULEB128(dbg_info.writer(), local) catch unreachable;
4985 leb.writeULEB128(dbg_info.writer(), local.value) catch unreachable;
49744986 },
49754987 else => {}, // TODO
49764988 }
......@@ -5179,7 +5191,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!void {
51795191 const div_result = try self.allocLocal(ty);
51805192 // leave on stack
51815193 _ = try self.binOp(lhs_res, rhs_res, ty, .div);
5182 try self.addLabel(.local_tee, div_result.local);
5194 try self.addLabel(.local_tee, div_result.local.value);
51835195 _ = try self.cmp(lhs_res, zero, ty, .lt);
51845196 _ = try self.cmp(rhs_res, zero, ty, .lt);
51855197 switch (wasm_bits) {
......@@ -5232,7 +5244,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!void {
52325244 }
52335245
52345246 const result = try self.allocLocal(ty);
5235 try self.addLabel(.local_set, result.local);
5247 try self.addLabel(.local_set, result.local.value);
52365248 self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
52375249}
52385250
......@@ -5257,7 +5269,7 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue
52575269 try self.addTag(.i32_div_s);
52585270
52595271 const result = try self.allocLocal(ty);
5260 try self.addLabel(.local_set, result.local);
5272 try self.addLabel(.local_set, result.local.value);
52615273 return result;
52625274}
52635275
......@@ -5323,7 +5335,7 @@ fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!void
53235335 }
53245336
53255337 const result = try self.allocLocal(ty);
5326 try self.addLabel(.local_set, result.local);
5338 try self.addLabel(.local_set, result.local.value);
53275339 self.finishAir(inst, result, &.{un_op});
53285340}
53295341
......@@ -5374,7 +5386,7 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!void {
53745386
53755387 try self.addTag(.select);
53765388 const result = try self.allocLocal(ty);
5377 try self.addLabel(.local_set, result.local);
5389 try self.addLabel(.local_set, result.local.value);
53785390 return self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
53795391}
53805392
......@@ -5412,13 +5424,13 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op
54125424 try self.emitWValue(max_wvalue);
54135425 _ = try self.cmp(bin_result, max_wvalue, ty, .lt);
54145426 try self.addTag(.select);
5415 try self.addLabel(.local_set, bin_result.local); // re-use local
5427 try self.addLabel(.local_set, bin_result.local.value); // re-use local
54165428
54175429 try self.emitWValue(bin_result);
54185430 try self.emitWValue(min_wvalue);
54195431 _ = try self.cmp(bin_result, min_wvalue, ty, .gt);
54205432 try self.addTag(.select);
5421 try self.addLabel(.local_set, bin_result.local); // re-use local
5433 try self.addLabel(.local_set, bin_result.local.value); // re-use local
54225434 return (try self.wrapOperand(bin_result, ty)).toLocal(self, ty);
54235435 } else {
54245436 const zero = switch (wasm_bits) {
......@@ -5436,7 +5448,7 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op
54365448 const cmp_bin_result = try self.cmp(bin_result, lhs, ty, .lt);
54375449 _ = try self.binOp(cmp_zero_result, cmp_bin_result, Type.u32, .xor); // comparisons always return i32, so provide u32 as type to xor.
54385450 try self.addTag(.select);
5439 try self.addLabel(.local_set, bin_result.local); // re-use local
5451 try self.addLabel(.local_set, bin_result.local.value); // re-use local
54405452 return bin_result;
54415453 }
54425454}
......@@ -5489,7 +5501,7 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!void {
54895501 try self.emitWValue(shl);
54905502 _ = try self.cmp(lhs, shr, ty, .neq);
54915503 try self.addTag(.select);
5492 try self.addLabel(.local_set, result.local);
5504 try self.addLabel(.local_set, result.local.value);
54935505 break :outer_blk;
54945506 } else {
54955507 const shift_size = wasm_bits - int_info.bits;
......@@ -5534,12 +5546,12 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!void {
55345546 try self.emitWValue(shl);
55355547 _ = try self.cmp(shl_res, shr, ty, .neq);
55365548 try self.addTag(.select);
5537 try self.addLabel(.local_set, result.local);
5549 try self.addLabel(.local_set, result.local.value);
55385550 var shift_result = try self.binOp(result, shift_value, ty, .shr);
55395551 if (is_signed) {
55405552 shift_result = try self.wrapOperand(shift_result, ty);
55415553 }
5542 try self.addLabel(.local_set, result.local);
5554 try self.addLabel(.local_set, result.local.value);
55435555 }
55445556
55455557 return self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });