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) {...@@ -32,8 +32,13 @@ const WValue = union(enum) {
32 none: void,32 none: void,
33 /// The value lives on top of the stack33 /// The value lives on top of the stack
34 stack: void,34 stack: void,
35 /// Index of the local variable35 /// Index of the local
36 local: u32,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 },
37 /// An immediate 32bit value42 /// An immediate 32bit value
38 imm32: u32,43 imm32: u32,
39 /// An immediate 64bit value44 /// An immediate 64bit value
...@@ -60,7 +65,12 @@ const WValue = union(enum) {...@@ -60,7 +65,12 @@ const WValue = union(enum) {
60 function_index: u32,65 function_index: u32,
61 /// Offset from the bottom of the virtual stack, with the offset66 /// Offset from the bottom of the virtual stack, with the offset
62 /// pointing to where the value lives.67 /// 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
65 /// Returns the offset from the bottom of the stack. This is useful when75 /// Returns the offset from the bottom of the stack. This is useful when
66 /// we use the load or store instruction to ensure we retrieve the value76 /// we use the load or store instruction to ensure we retrieve the value
...@@ -70,7 +80,7 @@ const WValue = union(enum) {...@@ -70,7 +80,7 @@ const WValue = union(enum) {
70 /// loads and stores without requiring checks everywhere.80 /// loads and stores without requiring checks everywhere.
71 fn offset(self: WValue) u32 {81 fn offset(self: WValue) u32 {
72 switch (self) {82 switch (self) {
73 .stack_offset => |stack_offset| return stack_offset,83 .stack_offset => |stack_offset| return stack_offset.value,
74 else => return 0,84 else => return 0,
75 }85 }
76 }86 }
...@@ -81,9 +91,9 @@ const WValue = union(enum) {...@@ -81,9 +91,9 @@ const WValue = union(enum) {
81 fn toLocal(value: WValue, gen: *Self, ty: Type) InnerError!WValue {91 fn toLocal(value: WValue, gen: *Self, ty: Type) InnerError!WValue {
82 switch (value) {92 switch (value) {
83 .stack => {93 .stack => {
84 const local = try gen.allocLocal(ty);94 const new_local = try gen.allocLocal(ty);
85 try gen.addLabel(.local_set, local.local);95 try gen.addLabel(.local_set, new_local.local.value);
86 return local;96 return new_local;
87 },97 },
88 .local, .stack_offset => return value,98 .local, .stack_offset => return value,
89 else => unreachable,99 else => unreachable,
...@@ -95,7 +105,7 @@ const WValue = union(enum) {...@@ -95,7 +105,7 @@ const WValue = union(enum) {
95 /// The valtype of the local is deducted by using the index of the given `WValue`.105 /// The valtype of the local is deducted by using the index of the given `WValue`.
96 fn free(value: *WValue, gen: *Self) void {106 fn free(value: *WValue, gen: *Self) void {
97 if (value.* != .local) return;107 if (value.* != .local) return;
98 const local_value = value.local;108 const local_value = value.local.value;
99 const reserved = gen.args.len + @boolToInt(gen.return_value != .none) + 2; // 2 for stack locals109 const reserved = gen.args.len + @boolToInt(gen.return_value != .none) + 2; // 2 for stack locals
100 if (local_value < reserved) return; // reserved locals may never be re-used.110 if (local_value < reserved) return; // reserved locals may never be re-used.
101111
...@@ -107,7 +117,7 @@ const WValue = union(enum) {...@@ -107,7 +117,7 @@ const WValue = union(enum) {
107 .f32 => gen.free_locals_f32.append(gen.gpa, local_value) catch return,117 .f32 => gen.free_locals_f32.append(gen.gpa, local_value) catch return,
108 .f64 => gen.free_locals_f64.append(gen.gpa, local_value) catch return,118 .f64 => gen.free_locals_f64.append(gen.gpa, local_value) catch return,
109 }119 }
110 value.* = WValue{ .none = {} };120 value.* = undefined;
111 }121 }
112};122};
113123
...@@ -761,7 +771,9 @@ const BigTomb = struct {...@@ -761,7 +771,9 @@ const BigTomb = struct {
761 bt.gen.values.putAssumeCapacityNoClobber(Air.indexToRef(bt.inst), result);771 bt.gen.values.putAssumeCapacityNoClobber(Air.indexToRef(bt.inst), result);
762 }772 }
763773
764 bt.gen.air_bookkeeping += 1;774 if (builtin.mode == .Debug) {
775 bt.gen.air_bookkeeping += 1;
776 }
765 }777 }
766};778};
767779
...@@ -883,7 +895,7 @@ fn genBlockType(ty: Type, target: std.Target) u8 {...@@ -883,7 +895,7 @@ fn genBlockType(ty: Type, target: std.Target) u8 {
883fn emitWValue(self: *Self, value: WValue) InnerError!void {895fn emitWValue(self: *Self, value: WValue) InnerError!void {
884 switch (value) {896 switch (value) {
885 .none, .stack => {}, // no-op897 .none, .stack => {}, // no-op
886 .local => |idx| try self.addLabel(.local_get, idx),898 .local => |idx| try self.addLabel(.local_get, idx.value),
887 .imm32 => |val| try self.addImm32(@bitCast(i32, val)),899 .imm32 => |val| try self.addImm32(@bitCast(i32, val)),
888 .imm64 => |val| try self.addImm64(val),900 .imm64 => |val| try self.addImm64(val),
889 .float32 => |val| try self.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }),901 .float32 => |val| try self.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }),
...@@ -907,16 +919,16 @@ fn allocLocal(self: *Self, ty: Type) InnerError!WValue {...@@ -907,16 +919,16 @@ fn allocLocal(self: *Self, ty: Type) InnerError!WValue {
907 const valtype = typeToValtype(ty, self.target);919 const valtype = typeToValtype(ty, self.target);
908 switch (valtype) {920 switch (valtype) {
909 .i32 => if (self.free_locals_i32.popOrNull()) |index| {921 .i32 => if (self.free_locals_i32.popOrNull()) |index| {
910 return WValue{ .local = index };922 return WValue{ .local = .{ .value = index, .references = 1 } };
911 },923 },
912 .i64 => if (self.free_locals_i64.popOrNull()) |index| {924 .i64 => if (self.free_locals_i64.popOrNull()) |index| {
913 return WValue{ .local = index };925 return WValue{ .local = .{ .value = index, .references = 1 } };
914 },926 },
915 .f32 => if (self.free_locals_f32.popOrNull()) |index| {927 .f32 => if (self.free_locals_f32.popOrNull()) |index| {
916 return WValue{ .local = index };928 return WValue{ .local = .{ .value = index, .references = 1 } };
917 },929 },
918 .f64 => if (self.free_locals_f64.popOrNull()) |index| {930 .f64 => if (self.free_locals_f64.popOrNull()) |index| {
919 return WValue{ .local = index };931 return WValue{ .local = .{ .value = index, .references = 1 } };
920 },932 },
921 }933 }
922 // no local was free to be re-used, so allocate a new local instead934 // 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 {...@@ -929,7 +941,7 @@ fn ensureAllocLocal(self: *Self, ty: Type) InnerError!WValue {
929 try self.locals.append(self.gpa, genValtype(ty, self.target));941 try self.locals.append(self.gpa, genValtype(ty, self.target));
930 const initial_index = self.local_index;942 const initial_index = self.local_index;
931 self.local_index += 1;943 self.local_index += 1;
932 return WValue{ .local = initial_index };944 return WValue{ .local = .{ .value = initial_index, .references = 1 } };
933}945}
934946
935/// Generates a `wasm.Type` from a given function type.947/// Generates a `wasm.Type` from a given function type.
...@@ -1059,7 +1071,7 @@ fn genFunc(self: *Self) InnerError!void {...@@ -1059,7 +1071,7 @@ fn genFunc(self: *Self) InnerError!void {
1059 // load stack pointer1071 // load stack pointer
1060 try prologue.append(.{ .tag = .global_get, .data = .{ .label = 0 } });1072 try prologue.append(.{ .tag = .global_get, .data = .{ .label = 0 } });
1061 // store stack pointer so we can restore it when we return from the function1073 // 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 } });
1063 // get the total stack size1075 // get the total stack size
1064 const aligned_stack = std.mem.alignForwardGeneric(u32, self.stack_size, self.stack_alignment);1076 const aligned_stack = std.mem.alignForwardGeneric(u32, self.stack_size, self.stack_alignment);
1065 try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @intCast(i32, aligned_stack) } });1077 try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @intCast(i32, aligned_stack) } });
...@@ -1070,7 +1082,7 @@ fn genFunc(self: *Self) InnerError!void {...@@ -1070,7 +1082,7 @@ fn genFunc(self: *Self) InnerError!void {
1070 // Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment1082 // Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment
1071 try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } });1083 try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } });
1072 // store the current stack pointer as the bottom, which will be used to calculate all stack pointer offsets1084 // 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 } });
1074 // Store the current stack pointer value into the global stack pointer so other function calls will1086 // Store the current stack pointer value into the global stack pointer so other function calls will
1075 // start from this value instead and not overwrite the current stack.1087 // start from this value instead and not overwrite the current stack.
1076 try prologue.append(.{ .tag = .global_set, .data = .{ .label = 0 } });1088 try prologue.append(.{ .tag = .global_set, .data = .{ .label = 0 } });
...@@ -1141,7 +1153,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu...@@ -1141,7 +1153,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
1141 if (firstParamSRet(fn_info.cc, fn_info.return_type, self.target)) {1153 if (firstParamSRet(fn_info.cc, fn_info.return_type, self.target)) {
1142 // the sret arg will be passed as first argument, therefore we1154 // the sret arg will be passed as first argument, therefore we
1143 // set the `return_value` before allocating locals for regular args.1155 // 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 } };
1145 self.local_index += 1;1157 self.local_index += 1;
1146 }1158 }
11471159
...@@ -1152,7 +1164,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu...@@ -1152,7 +1164,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
1152 continue;1164 continue;
1153 }1165 }
11541166
1155 try args.append(.{ .local = self.local_index });1167 try args.append(.{ .local = .{ .value = self.local_index, .references = 1 } });
1156 self.local_index += 1;1168 self.local_index += 1;
1157 }1169 }
1158 },1170 },
...@@ -1161,7 +1173,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu...@@ -1161,7 +1173,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
1161 const ty_classes = abi.classifyType(ty, self.target);1173 const ty_classes = abi.classifyType(ty, self.target);
1162 for (ty_classes) |class| {1174 for (ty_classes) |class| {
1163 if (class == .none) continue;1175 if (class == .none) continue;
1164 try args.append(.{ .local = self.local_index });1176 try args.append(.{ .local = .{ .value = self.local_index, .references = 1 } });
1165 self.local_index += 1;1177 self.local_index += 1;
1166 }1178 }
1167 }1179 }
...@@ -1254,14 +1266,14 @@ fn lowerToStack(self: *Self, value: WValue) !void {...@@ -1254,14 +1266,14 @@ fn lowerToStack(self: *Self, value: WValue) !void {
1254 switch (value) {1266 switch (value) {
1255 .stack_offset => |offset| {1267 .stack_offset => |offset| {
1256 try self.emitWValue(value);1268 try self.emitWValue(value);
1257 if (offset > 0) {1269 if (offset.value > 0) {
1258 switch (self.arch()) {1270 switch (self.arch()) {
1259 .wasm32 => {1271 .wasm32 => {
1260 try self.addImm32(@bitCast(i32, offset));1272 try self.addImm32(@bitCast(i32, offset.value));
1261 try self.addTag(.i32_add);1273 try self.addTag(.i32_add);
1262 },1274 },
1263 .wasm64 => {1275 .wasm64 => {
1264 try self.addImm64(offset);1276 try self.addImm64(offset.value);
1265 try self.addTag(.i64_add);1277 try self.addTag(.i64_add);
1266 },1278 },
1267 else => unreachable,1279 else => unreachable,
...@@ -1323,7 +1335,7 @@ fn allocStack(self: *Self, ty: Type) !WValue {...@@ -1323,7 +1335,7 @@ fn allocStack(self: *Self, ty: Type) !WValue {
1323 const offset = std.mem.alignForwardGeneric(u32, self.stack_size, abi_align);1335 const offset = std.mem.alignForwardGeneric(u32, self.stack_size, abi_align);
1324 defer self.stack_size = offset + abi_size;1336 defer self.stack_size = offset + abi_size;
13251337
1326 return WValue{ .stack_offset = offset };1338 return WValue{ .stack_offset = .{ .value = offset, .references = 1 } };
1327}1339}
13281340
1329/// From a given AIR instruction generates a pointer to the stack where1341/// 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 {...@@ -1356,7 +1368,7 @@ fn allocStackPtr(self: *Self, inst: Air.Inst.Index) !WValue {
1356 const offset = std.mem.alignForwardGeneric(u32, self.stack_size, abi_alignment);1368 const offset = std.mem.alignForwardGeneric(u32, self.stack_size, abi_alignment);
1357 defer self.stack_size = offset + abi_size;1369 defer self.stack_size = offset + abi_size;
13581370
1359 return WValue{ .stack_offset = offset };1371 return WValue{ .stack_offset = .{ .value = offset, .references = 1 } };
1360}1372}
13611373
1362/// From given zig bitsize, returns the wasm bitsize1374/// From given zig bitsize, returns the wasm bitsize
...@@ -1475,7 +1487,7 @@ fn memcpy(self: *Self, dst: WValue, src: WValue, len: WValue) !void {...@@ -1475,7 +1487,7 @@ fn memcpy(self: *Self, dst: WValue, src: WValue, len: WValue) !void {
1475 },1487 },
1476 else => unreachable,1488 else => unreachable,
1477 }1489 }
1478 try self.addLabel(.local_set, offset.local);1490 try self.addLabel(.local_set, offset.local.value);
1479 try self.addLabel(.br, 0); // jump to start of loop1491 try self.addLabel(.br, 0); // jump to start of loop
1480 }1492 }
1481 try self.endBlock(); // close off loop block1493 try self.endBlock(); // close off loop block
...@@ -1568,7 +1580,7 @@ fn buildPointerOffset(self: *Self, ptr_value: WValue, offset: u64, action: enum...@@ -1568,7 +1580,7 @@ fn buildPointerOffset(self: *Self, ptr_value: WValue, offset: u64, action: enum
1568 else => unreachable,1580 else => unreachable,
1569 }1581 }
1570 }1582 }
1571 try self.addLabel(.local_set, result_ptr.local);1583 try self.addLabel(.local_set, result_ptr.local.value);
1572 return result_ptr;1584 return result_ptr;
1573}1585}
15741586
...@@ -1984,14 +1996,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -1984,14 +1996,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
1984 // TODO: Make this less fragile and optimize1996 // TODO: Make this less fragile and optimize
1985 } else if (fn_ty.fnInfo().cc == .C and ret_ty.zigTypeTag() == .Struct or ret_ty.zigTypeTag() == .Union) {1997 } else if (fn_ty.fnInfo().cc == .C and ret_ty.zigTypeTag() == .Struct or ret_ty.zigTypeTag() == .Union) {
1986 const result_local = try self.allocLocal(ret_ty);1998 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);
1988 const scalar_type = abi.scalarType(ret_ty, self.target);2000 const scalar_type = abi.scalarType(ret_ty, self.target);
1989 const result = try self.allocStack(scalar_type);2001 const result = try self.allocStack(scalar_type);
1990 try self.store(result, result_local, scalar_type, 0);2002 try self.store(result, result_local, scalar_type, 0);
1991 break :result_value result;2003 break :result_value result;
1992 } else {2004 } else {
1993 const result_local = try self.allocLocal(ret_ty);2005 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);
1995 break :result_value result_local;2007 break :result_value result_local;
1996 }2008 }
1997 };2009 };
...@@ -2175,7 +2187,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -2175,7 +2187,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!void {
2175 .dwarf => |dwarf| {2187 .dwarf => |dwarf| {
2176 // TODO: Get the original arg index rather than wasm arg index2188 // TODO: Get the original arg index rather than wasm arg index
2177 const name = self.mod_fn.getParamName(self.bin_file.base.options.module.?, arg_index);2189 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);
2179 const dbg_info = &dwarf.dbg_info;2191 const dbg_info = &dwarf.dbg_info;
2180 try dbg_info.ensureUnusedCapacity(3 + leb_size + 5 + name.len + 1);2192 try dbg_info.ensureUnusedCapacity(3 + leb_size + 5 + name.len + 1);
2181 // wasm locations are encoded as follow:2193 // wasm locations are encoded as follow:
...@@ -2189,7 +2201,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -2189,7 +2201,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!void {
2189 std.dwarf.OP.WASM_location,2201 std.dwarf.OP.WASM_location,
2190 std.dwarf.OP.WASM_local,2202 std.dwarf.OP.WASM_local,
2191 });2203 });
2192 leb.writeULEB128(dbg_info.writer(), arg.local) catch unreachable;2204 leb.writeULEB128(dbg_info.writer(), arg.local.value) catch unreachable;
2193 try self.addDbgInfoTypeReloc(arg_ty);2205 try self.addDbgInfoTypeReloc(arg_ty);
2194 dbg_info.appendSliceAssumeCapacity(name);2206 dbg_info.appendSliceAssumeCapacity(name);
2195 dbg_info.appendAssumeCapacity(0);2207 dbg_info.appendAssumeCapacity(0);
...@@ -2869,7 +2881,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -2869,7 +2881,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!void {
2869 try self.lowerToStack(operand);2881 try self.lowerToStack(operand);
28702882
2871 if (block.value != .none) {2883 if (block.value != .none) {
2872 try self.addLabel(.local_set, block.value.local);2884 try self.addLabel(.local_set, block.value.local.value);
2873 }2885 }
2874 }2886 }
28752887
...@@ -2893,7 +2905,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -2893,7 +2905,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!void {
2893 try self.emitWValue(operand);2905 try self.emitWValue(operand);
2894 try self.addTag(.i32_eqz);2906 try self.addTag(.i32_eqz);
2895 const not_tmp = try self.allocLocal(operand_ty);2907 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);
2897 break :result not_tmp;2909 break :result not_tmp;
2898 } else {2910 } else {
2899 const operand_bits = operand_ty.intInfo(self.target).bits;2911 const operand_bits = operand_ty.intInfo(self.target).bits;
...@@ -2985,7 +2997,7 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerEr...@@ -2985,7 +2997,7 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerEr
2985fn structFieldPtr(self: *Self, struct_ptr: WValue, offset: u32) InnerError!WValue {2997fn structFieldPtr(self: *Self, struct_ptr: WValue, offset: u32) InnerError!WValue {
2986 switch (struct_ptr) {2998 switch (struct_ptr) {
2987 .stack_offset => |stack_offset| {2999 .stack_offset => |stack_offset| {
2988 return WValue{ .stack_offset = stack_offset + offset };3000 return WValue{ .stack_offset = .{ .value = stack_offset.value + offset, .references = 1 } };
2989 },3001 },
2990 else => return self.buildPointerOffset(struct_ptr, offset, .new),3002 else => return self.buildPointerOffset(struct_ptr, offset, .new),
2991 }3003 }
...@@ -3011,7 +3023,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -3011,7 +3023,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!void {
3011 if (isByRef(field_ty, self.target)) {3023 if (isByRef(field_ty, self.target)) {
3012 switch (operand) {3024 switch (operand) {
3013 .stack_offset => |stack_offset| {3025 .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 } };
3015 },3027 },
3016 else => break :result try self.buildPointerOffset(operand, offset, .new),3028 else => break :result try self.buildPointerOffset(operand, offset, .new),
3017 }3029 }
...@@ -3214,7 +3226,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!v...@@ -3214,7 +3226,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!v
3214 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));3226 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
32153227
3216 const is_err_tmp = try self.allocLocal(Type.i32);3228 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);
3218 break :result is_err_tmp;3230 break :result is_err_tmp;
3219 };3231 };
3220 self.finishAir(inst, result, &.{un_op});3232 self.finishAir(inst, result, &.{un_op});
...@@ -3578,7 +3590,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -3578,7 +3590,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!void {
3578 try self.addTag(.i32_add);3590 try self.addTag(.i32_add);
35793591
3580 const result_ptr = try self.allocLocal(elem_ty);3592 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
3583 const result = if (!isByRef(elem_ty, self.target)) result: {3595 const result = if (!isByRef(elem_ty, self.target)) result: {
3584 const elem_val = try self.load(result_ptr, elem_ty, 0);3596 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 {...@@ -3608,7 +3620,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!void {
3608 try self.addTag(.i32_add);3620 try self.addTag(.i32_add);
36093621
3610 const result = try self.allocLocal(Type.i32);3622 const result = try self.allocLocal(Type.i32);
3611 try self.addLabel(.local_set, result.local);3623 try self.addLabel(.local_set, result.local.value);
3612 self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });3624 self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
3613}3625}
36143626
...@@ -3715,7 +3727,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -3715,7 +3727,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!void {
37153727
3716 const elem_result = val: {3728 const elem_result = val: {
3717 var result = try self.allocLocal(elem_ty);3729 var result = try self.allocLocal(elem_ty);
3718 try self.addLabel(.local_set, result.local);3730 try self.addLabel(.local_set, result.local.value);
3719 if (isByRef(elem_ty, self.target)) {3731 if (isByRef(elem_ty, self.target)) {
3720 break :val result;3732 break :val result;
3721 }3733 }
...@@ -3753,7 +3765,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -3753,7 +3765,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!void {
3753 try self.addTag(.i32_add);3765 try self.addTag(.i32_add);
37543766
3755 const result = try self.allocLocal(Type.i32);3767 const result = try self.allocLocal(Type.i32);
3756 try self.addLabel(.local_set, result.local);3768 try self.addLabel(.local_set, result.local.value);
3757 self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });3769 self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
3758}3770}
37593771
...@@ -3781,7 +3793,7 @@ fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!void {...@@ -3781,7 +3793,7 @@ fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!void {
3781 try self.addTag(Mir.Inst.Tag.fromOpcode(bin_opcode));3793 try self.addTag(Mir.Inst.Tag.fromOpcode(bin_opcode));
37823794
3783 const result = try self.allocLocal(Type.usize);3795 const result = try self.allocLocal(Type.usize);
3784 try self.addLabel(.local_set, result.local);3796 try self.addLabel(.local_set, result.local.value);
3785 self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });3797 self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
3786}3798}
37873799
...@@ -3874,7 +3886,7 @@ fn memset(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void...@@ -3874,7 +3886,7 @@ fn memset(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void
3874 .wasm64 => try self.addTag(.i64_add),3886 .wasm64 => try self.addTag(.i64_add),
3875 else => unreachable,3887 else => unreachable,
3876 }3888 }
3877 try self.addLabel(.local_set, offset.local);3889 try self.addLabel(.local_set, offset.local.value);
3878 try self.addLabel(.br, 0); // jump to start of loop3890 try self.addLabel(.br, 0); // jump to start of loop
3879 try self.endBlock();3891 try self.endBlock();
3880 try self.endBlock();3892 try self.endBlock();
...@@ -3900,7 +3912,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -3900,7 +3912,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!void {
39003912
3901 const elem_result = val: {3913 const elem_result = val: {
3902 var result = try self.allocLocal(Type.usize);3914 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
3905 if (isByRef(elem_ty, self.target)) {3917 if (isByRef(elem_ty, self.target)) {
3906 break :val result;3918 break :val result;
...@@ -3961,7 +3973,7 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -3961,7 +3973,7 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!void {
3961 try self.addTag(Mir.Inst.Tag.fromOpcode(op));3973 try self.addTag(Mir.Inst.Tag.fromOpcode(op));
39623974
3963 const result = try self.allocLocal(dest_ty);3975 const result = try self.allocLocal(dest_ty);
3964 try self.addLabel(.local_set, result.local);3976 try self.addLabel(.local_set, result.local.value);
3965 self.finishAir(inst, result, &.{ty_op.operand});3977 self.finishAir(inst, result, &.{ty_op.operand});
3966}3978}
39673979
...@@ -4107,7 +4119,7 @@ fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -4107,7 +4119,7 @@ fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) InnerError!void {
41074119
4108 const result = try self.allocLocal(self.air.typeOfIndex(inst));4120 const result = try self.allocLocal(self.air.typeOfIndex(inst));
4109 try self.addLabel(.memory_size, pl_op.payload);4121 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);
4111 self.finishAir(inst, result, &.{pl_op.operand});4123 self.finishAir(inst, result, &.{pl_op.operand});
4112}4124}
41134125
...@@ -4119,7 +4131,7 @@ fn airWasmMemoryGrow(self: *Self, inst: Air.Inst.Index) !void {...@@ -4119,7 +4131,7 @@ fn airWasmMemoryGrow(self: *Self, inst: Air.Inst.Index) !void {
4119 const result = try self.allocLocal(self.air.typeOfIndex(inst));4131 const result = try self.allocLocal(self.air.typeOfIndex(inst));
4120 try self.emitWValue(operand);4132 try self.emitWValue(operand);
4121 try self.addLabel(.memory_grow, pl_op.payload);4133 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);
4123 self.finishAir(inst, result, &.{pl_op.operand});4135 self.finishAir(inst, result, &.{pl_op.operand});
4124}4136}
41254137
...@@ -4148,7 +4160,7 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std...@@ -4148,7 +4160,7 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std
4148 try self.addLabel(.br_if, 0);4160 try self.addLabel(.br_if, 0);
41494161
4150 try self.addImm32(1);4162 try self.addImm32(1);
4151 try self.addLabel(.local_set, result.local);4163 try self.addLabel(.local_set, result.local.value);
4152 try self.endBlock();4164 try self.endBlock();
41534165
4154 try self.emitWValue(result);4166 try self.emitWValue(result);
...@@ -4363,10 +4375,10 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -4363,10 +4375,10 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) InnerError!void {
43634375
4364 const result = if (field_offset != 0) result: {4376 const result = if (field_offset != 0) result: {
4365 const base = try self.buildPointerOffset(field_ptr, 0, .new);4377 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);
4367 try self.addImm32(@bitCast(i32, @intCast(u32, field_offset)));4379 try self.addImm32(@bitCast(i32, @intCast(u32, field_offset)));
4368 try self.addTag(.i32_sub);4380 try self.addTag(.i32_sub);
4369 try self.addLabel(.local_set, base.local);4381 try self.addLabel(.local_set, base.local.value);
4370 break :result base;4382 break :result base;
4371 } else field_ptr;4383 } else field_ptr;
43724384
...@@ -4425,7 +4437,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -4425,7 +4437,7 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) InnerError!void {
4425 }4437 }
44264438
4427 const result = try self.allocLocal(result_ty);4439 const result = try self.allocLocal(result_ty);
4428 try self.addLabel(.local_set, result.local);4440 try self.addLabel(.local_set, result.local.value);
4429 self.finishAir(inst, result, &.{ty_op.operand});4441 self.finishAir(inst, result, &.{ty_op.operand});
4430}4442}
44314443
...@@ -4467,7 +4479,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -4467,7 +4479,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) InnerError!void {
4467 }4479 }
44684480
4469 const result_ptr = try self.allocLocal(Type.usize);4481 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);
4471 self.finishAir(inst, result_ptr, &.{un_op});4483 self.finishAir(inst, result_ptr, &.{un_op});
4472}4484}
44734485
...@@ -4714,7 +4726,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -4714,7 +4726,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!void {
4714 const shr = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr);4726 const shr = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr);
4715 const wrap = try self.intcast(shr, new_ty, lhs_ty);4727 const wrap = try self.intcast(shr, new_ty, lhs_ty);
4716 _ = try self.cmp(wrap, zero, lhs_ty, .neq);4728 _ = 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);
4718 break :blk try self.intcast(bin_op, new_ty, lhs_ty);4730 break :blk try self.intcast(bin_op, new_ty, lhs_ty);
4719 } else {4731 } else {
4720 const down_cast = try (try self.intcast(bin_op, new_ty, lhs_ty)).toLocal(self, lhs_ty);4732 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 {...@@ -4724,7 +4736,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!void {
4724 const shr_res = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr);4736 const shr_res = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr);
4725 const down_shr_res = try self.intcast(shr_res, new_ty, lhs_ty);4737 const down_shr_res = try self.intcast(shr_res, new_ty, lhs_ty);
4726 _ = try self.cmp(down_shr_res, shr, lhs_ty, .neq);4738 _ = 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);
4728 break :blk down_cast;4740 break :blk down_cast;
4729 }4741 }
4730 } else if (int_info.signedness == .signed) blk: {4742 } else if (int_info.signedness == .signed) blk: {
...@@ -4733,7 +4745,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -4733,7 +4745,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!void {
4733 const bin_op = try (try self.binOp(lhs_abs, rhs_abs, lhs_ty, .mul)).toLocal(self, lhs_ty);4745 const bin_op = try (try self.binOp(lhs_abs, rhs_abs, lhs_ty, .mul)).toLocal(self, lhs_ty);
4734 const mul_abs = try self.signAbsValue(bin_op, lhs_ty);4746 const mul_abs = try self.signAbsValue(bin_op, lhs_ty);
4735 _ = try self.cmp(mul_abs, bin_op, lhs_ty, .neq);4747 _ = 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);
4737 break :blk try self.wrapOperand(bin_op, lhs_ty);4749 break :blk try self.wrapOperand(bin_op, lhs_ty);
4738 } else blk: {4750 } else blk: {
4739 var bin_op = try (try self.binOp(lhs, rhs, lhs_ty, .mul)).toLocal(self, lhs_ty);4751 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 {...@@ -4744,7 +4756,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!void {
4744 WValue{ .imm64 = int_info.bits };4756 WValue{ .imm64 = int_info.bits };
4745 const shr = try self.binOp(bin_op, shift_imm, lhs_ty, .shr);4757 const shr = try self.binOp(bin_op, shift_imm, lhs_ty, .shr);
4746 _ = try self.cmp(shr, zero, lhs_ty, .neq);4758 _ = 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);
4748 break :blk try self.wrapOperand(bin_op, lhs_ty);4760 break :blk try self.wrapOperand(bin_op, lhs_ty);
4749 };4761 };
4750 var bin_op_local = try bin_op.toLocal(self, lhs_ty);4762 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...@@ -4785,7 +4797,7 @@ fn airMaxMin(self: *Self, inst: Air.Inst.Index, op: enum { max, min }) InnerErro
4785 // store result in local4797 // store result in local
4786 const result_ty = if (isByRef(ty, self.target)) Type.u32 else ty;4798 const result_ty = if (isByRef(ty, self.target)) Type.u32 else ty;
4787 const result = try self.allocLocal(result_ty);4799 const result = try self.allocLocal(result_ty);
4788 try self.addLabel(.local_set, result.local);4800 try self.addLabel(.local_set, result.local.value);
4789 self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });4801 self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
4790}4802}
47914803
...@@ -4872,7 +4884,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -4872,7 +4884,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!void {
4872 }4884 }
48734885
4874 const result = try self.allocLocal(result_ty);4886 const result = try self.allocLocal(result_ty);
4875 try self.addLabel(.local_set, result.local);4887 try self.addLabel(.local_set, result.local.value);
4876 self.finishAir(inst, result, &.{ty_op.operand});4888 self.finishAir(inst, result, &.{ty_op.operand});
4877}4889}
48784890
...@@ -4937,7 +4949,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -4937,7 +4949,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!void {
4937 }4949 }
49384950
4939 const result = try self.allocLocal(result_ty);4951 const result = try self.allocLocal(result_ty);
4940 try self.addLabel(.local_set, result.local);4952 try self.addLabel(.local_set, result.local.value);
4941 self.finishAir(inst, result, &.{ty_op.operand});4953 self.finishAir(inst, result, &.{ty_op.operand});
4942}4954}
49434955
...@@ -4958,7 +4970,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index, is_ptr: bool) !void {...@@ -4958,7 +4970,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index, is_ptr: bool) !void {
4958 try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));4970 try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
4959 switch (operand) {4971 switch (operand) {
4960 .local => |local| {4972 .local => |local| {
4961 const leb_size = link.File.Wasm.getULEB128Size(local);4973 const leb_size = link.File.Wasm.getULEB128Size(local.value);
4962 try dbg_info.ensureUnusedCapacity(2 + leb_size);4974 try dbg_info.ensureUnusedCapacity(2 + leb_size);
4963 // wasm locals are encoded as follow:4975 // wasm locals are encoded as follow:
4964 // DW_OP_WASM_location wasm-op4976 // DW_OP_WASM_location wasm-op
...@@ -4970,7 +4982,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index, is_ptr: bool) !void {...@@ -4970,7 +4982,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index, is_ptr: bool) !void {
4970 std.dwarf.OP.WASM_location,4982 std.dwarf.OP.WASM_location,
4971 std.dwarf.OP.WASM_local,4983 std.dwarf.OP.WASM_local,
4972 });4984 });
4973 leb.writeULEB128(dbg_info.writer(), local) catch unreachable;4985 leb.writeULEB128(dbg_info.writer(), local.value) catch unreachable;
4974 },4986 },
4975 else => {}, // TODO4987 else => {}, // TODO
4976 }4988 }
...@@ -5179,7 +5191,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -5179,7 +5191,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!void {
5179 const div_result = try self.allocLocal(ty);5191 const div_result = try self.allocLocal(ty);
5180 // leave on stack5192 // leave on stack
5181 _ = try self.binOp(lhs_res, rhs_res, ty, .div);5193 _ = 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);
5183 _ = try self.cmp(lhs_res, zero, ty, .lt);5195 _ = try self.cmp(lhs_res, zero, ty, .lt);
5184 _ = try self.cmp(rhs_res, zero, ty, .lt);5196 _ = try self.cmp(rhs_res, zero, ty, .lt);
5185 switch (wasm_bits) {5197 switch (wasm_bits) {
...@@ -5232,7 +5244,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -5232,7 +5244,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!void {
5232 }5244 }
52335245
5234 const result = try self.allocLocal(ty);5246 const result = try self.allocLocal(ty);
5235 try self.addLabel(.local_set, result.local);5247 try self.addLabel(.local_set, result.local.value);
5236 self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });5248 self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
5237}5249}
52385250
...@@ -5257,7 +5269,7 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue...@@ -5257,7 +5269,7 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue
5257 try self.addTag(.i32_div_s);5269 try self.addTag(.i32_div_s);
52585270
5259 const result = try self.allocLocal(ty);5271 const result = try self.allocLocal(ty);
5260 try self.addLabel(.local_set, result.local);5272 try self.addLabel(.local_set, result.local.value);
5261 return result;5273 return result;
5262}5274}
52635275
...@@ -5323,7 +5335,7 @@ fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!void...@@ -5323,7 +5335,7 @@ fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!void
5323 }5335 }
53245336
5325 const result = try self.allocLocal(ty);5337 const result = try self.allocLocal(ty);
5326 try self.addLabel(.local_set, result.local);5338 try self.addLabel(.local_set, result.local.value);
5327 self.finishAir(inst, result, &.{un_op});5339 self.finishAir(inst, result, &.{un_op});
5328}5340}
53295341
...@@ -5374,7 +5386,7 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!void {...@@ -5374,7 +5386,7 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!void {
53745386
5375 try self.addTag(.select);5387 try self.addTag(.select);
5376 const result = try self.allocLocal(ty);5388 const result = try self.allocLocal(ty);
5377 try self.addLabel(.local_set, result.local);5389 try self.addLabel(.local_set, result.local.value);
5378 return self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });5390 return self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
5379}5391}
53805392
...@@ -5412,13 +5424,13 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op...@@ -5412,13 +5424,13 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op
5412 try self.emitWValue(max_wvalue);5424 try self.emitWValue(max_wvalue);
5413 _ = try self.cmp(bin_result, max_wvalue, ty, .lt);5425 _ = try self.cmp(bin_result, max_wvalue, ty, .lt);
5414 try self.addTag(.select);5426 try self.addTag(.select);
5415 try self.addLabel(.local_set, bin_result.local); // re-use local5427 try self.addLabel(.local_set, bin_result.local.value); // re-use local
54165428
5417 try self.emitWValue(bin_result);5429 try self.emitWValue(bin_result);
5418 try self.emitWValue(min_wvalue);5430 try self.emitWValue(min_wvalue);
5419 _ = try self.cmp(bin_result, min_wvalue, ty, .gt);5431 _ = try self.cmp(bin_result, min_wvalue, ty, .gt);
5420 try self.addTag(.select);5432 try self.addTag(.select);
5421 try self.addLabel(.local_set, bin_result.local); // re-use local5433 try self.addLabel(.local_set, bin_result.local.value); // re-use local
5422 return (try self.wrapOperand(bin_result, ty)).toLocal(self, ty);5434 return (try self.wrapOperand(bin_result, ty)).toLocal(self, ty);
5423 } else {5435 } else {
5424 const zero = switch (wasm_bits) {5436 const zero = switch (wasm_bits) {
...@@ -5436,7 +5448,7 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op...@@ -5436,7 +5448,7 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op
5436 const cmp_bin_result = try self.cmp(bin_result, lhs, ty, .lt);5448 const cmp_bin_result = try self.cmp(bin_result, lhs, ty, .lt);
5437 _ = try self.binOp(cmp_zero_result, cmp_bin_result, Type.u32, .xor); // comparisons always return i32, so provide u32 as type to xor.5449 _ = try self.binOp(cmp_zero_result, cmp_bin_result, Type.u32, .xor); // comparisons always return i32, so provide u32 as type to xor.
5438 try self.addTag(.select);5450 try self.addTag(.select);
5439 try self.addLabel(.local_set, bin_result.local); // re-use local5451 try self.addLabel(.local_set, bin_result.local.value); // re-use local
5440 return bin_result;5452 return bin_result;
5441 }5453 }
5442}5454}
...@@ -5489,7 +5501,7 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -5489,7 +5501,7 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!void {
5489 try self.emitWValue(shl);5501 try self.emitWValue(shl);
5490 _ = try self.cmp(lhs, shr, ty, .neq);5502 _ = try self.cmp(lhs, shr, ty, .neq);
5491 try self.addTag(.select);5503 try self.addTag(.select);
5492 try self.addLabel(.local_set, result.local);5504 try self.addLabel(.local_set, result.local.value);
5493 break :outer_blk;5505 break :outer_blk;
5494 } else {5506 } else {
5495 const shift_size = wasm_bits - int_info.bits;5507 const shift_size = wasm_bits - int_info.bits;
...@@ -5534,12 +5546,12 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!void {...@@ -5534,12 +5546,12 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!void {
5534 try self.emitWValue(shl);5546 try self.emitWValue(shl);
5535 _ = try self.cmp(shl_res, shr, ty, .neq);5547 _ = try self.cmp(shl_res, shr, ty, .neq);
5536 try self.addTag(.select);5548 try self.addTag(.select);
5537 try self.addLabel(.local_set, result.local);5549 try self.addLabel(.local_set, result.local.value);
5538 var shift_result = try self.binOp(result, shift_value, ty, .shr);5550 var shift_result = try self.binOp(result, shift_value, ty, .shr);
5539 if (is_signed) {5551 if (is_signed) {
5540 shift_result = try self.wrapOperand(shift_result, ty);5552 shift_result = try self.wrapOperand(shift_result, ty);
5541 }5553 }
5542 try self.addLabel(.local_set, result.local);5554 try self.addLabel(.local_set, result.local.value);
5543 }5555 }
55445556
5545 return self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });5557 return self.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });