authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-07-27 19:14:42+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-08-11 11:08:00+02:00
loga5e4fd7ef66bbd16ddad1a12d378eefcb740da1d
treeda07a631ac4ca59f6f7912e8867a7e3c8240ff55
parent3cd0cd12a08435fca5f5b2b6788ff519abfc6184
signaturelock-open Commit is signed but in an unrecognized format.

wasm: keep `load` values on the stack

We internally use a lot of `load`'s that used to put the result in a newly created local. For instance, when is considered byRef or when we need a specific field/element/bytes from a larger type. However, sometimes we want to directly use this value and then forget about it, which means storing it in a local first is wasted instructions as well as wasted locals that shouldn't be generated in the first place. With this change it's explicit and requires the usage of `toLocal`.

1 files changed, 116 insertions(+), 113 deletions(-)

src/arch/wasm/CodeGen.zig+116-113
...@@ -1789,8 +1789,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1789,8 +1789,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
17891789
1790 const fn_info = self.decl.ty.fnInfo();1790 const fn_info = self.decl.ty.fnInfo();
1791 if (!firstParamSRet(fn_info.cc, fn_info.return_type, self.target)) {1791 if (!firstParamSRet(fn_info.cc, fn_info.return_type, self.target)) {
1792 const result = try self.load(operand, ret_ty, 0);1792 // leave on the stack
1793 try self.emitWValue(result);1793 _ = try self.load(operand, ret_ty, 0);
1794 }1794 }
17951795
1796 try self.restoreStackPointer();1796 try self.restoreStackPointer();
...@@ -1943,20 +1943,26 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1943,20 +1943,26 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1943 .Pointer => {1943 .Pointer => {
1944 if (ty.isSlice()) {1944 if (ty.isSlice()) {
1945 // store pointer first1945 // store pointer first
1946 // lower it to the stack so we do not have to store rhs into a local first
1947 try self.emitWValue(lhs);
1946 const ptr_local = try self.load(rhs, Type.usize, 0);1948 const ptr_local = try self.load(rhs, Type.usize, 0);
1947 try self.store(lhs, ptr_local, Type.usize, 0);1949 try self.store(.{ .stack = {} }, ptr_local, Type.usize, 0 + lhs.offset());
19481950
1949 // retrieve length from rhs, and store that alongside lhs as well1951 // retrieve length from rhs, and store that alongside lhs as well
1952 try self.emitWValue(lhs);
1950 const len_local = try self.load(rhs, Type.usize, self.ptrSize());1953 const len_local = try self.load(rhs, Type.usize, self.ptrSize());
1951 try self.store(lhs, len_local, Type.usize, self.ptrSize());1954 try self.store(.{ .stack = {} }, len_local, Type.usize, self.ptrSize() + lhs.offset());
1952 return;1955 return;
1953 }1956 }
1954 },1957 },
1955 .Int => if (ty.intInfo(self.target).bits > 64) {1958 .Int => if (ty.intInfo(self.target).bits > 64) {
1959 try self.emitWValue(lhs);
1956 const lsb = try self.load(rhs, Type.u64, 0);1960 const lsb = try self.load(rhs, Type.u64, 0);
1961 try self.store(.{ .stack = {} }, lsb, Type.u64, 0 + lhs.offset());
1962
1963 try self.emitWValue(lhs);
1957 const msb = try self.load(rhs, Type.u64, 8);1964 const msb = try self.load(rhs, Type.u64, 8);
1958 try self.store(lhs, lsb, Type.u64, 0);1965 try self.store(.{ .stack = {} }, msb, Type.u64, 8 + lhs.offset());
1959 try self.store(lhs, msb, Type.u64, 8);
1960 return;1966 return;
1961 },1967 },
1962 else => {},1968 else => {},
...@@ -1995,9 +2001,12 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1995,9 +2001,12 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1995 return new_local;2001 return new_local;
1996 }2002 }
19972003
1998 return self.load(operand, ty, 0);2004 const stack_loaded = try self.load(operand, ty, 0);
2005 return stack_loaded.toLocal(self, ty);
1999}2006}
20002007
2008/// Loads an operand from the linear memory section.
2009/// NOTE: Leaves the value on the stack.
2001fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {2010fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
2002 // load local's value from memory by its stack position2011 // load local's value from memory by its stack position
2003 try self.emitWValue(operand);2012 try self.emitWValue(operand);
...@@ -2015,10 +2024,7 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {...@@ -2015,10 +2024,7 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
2015 .{ .offset = offset + operand.offset(), .alignment = ty.abiAlignment(self.target) },2024 .{ .offset = offset + operand.offset(), .alignment = ty.abiAlignment(self.target) },
2016 );2025 );
20172026
2018 // store the result in a local2027 return WValue{ .stack = {} };
2019 const result = try self.allocLocal(ty);
2020 try self.addLabel(.local_set, result.local);
2021 return result;
2022}2028}
20232029
2024fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2030fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -2124,18 +2130,15 @@ fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WVa...@@ -2124,18 +2130,15 @@ fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WVa
2124 return WValue{ .stack = {} };2130 return WValue{ .stack = {} };
2125}2131}
21262132
2133/// Performs a binary operation for 16-bit floats.
2134/// NOTE: Leaves the result value on the stack
2127fn binOpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: Op) InnerError!WValue {2135fn binOpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: Op) InnerError!WValue {
2128 const ext_lhs = try self.fpext(lhs, Type.f16, Type.f32);
2129 const ext_rhs = try self.fpext(rhs, Type.f16, Type.f32);
2130
2131 const opcode: wasm.Opcode = buildOpcode(.{ .op = op, .valtype1 = .f32, .signedness = .unsigned });2136 const opcode: wasm.Opcode = buildOpcode(.{ .op = op, .valtype1 = .f32, .signedness = .unsigned });
2132 try self.emitWValue(ext_lhs);2137 _ = try self.fpext(lhs, Type.f16, Type.f32);
2133 try self.emitWValue(ext_rhs);2138 _ = try self.fpext(rhs, Type.f16, Type.f32);
2134 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));2139 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
21352140
2136 // re-use temporary local2141 return self.fptrunc(.{ .stack = {} }, Type.f32, Type.f16);
2137 try self.addLabel(.local_set, ext_lhs.local);
2138 return self.fptrunc(ext_lhs, Type.f32, Type.f16);
2139}2142}
21402143
2141fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {2144fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
...@@ -2148,12 +2151,12 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr...@@ -2148,12 +2151,12 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr
2148 }2151 }
21492152
2150 const result = try self.allocStack(ty);2153 const result = try self.allocStack(ty);
2151 const lhs_high_bit = try self.load(lhs, Type.u64, 0);2154 const lhs_high_bit = try (try self.load(lhs, Type.u64, 0)).toLocal(self, Type.u64);
2155 const rhs_high_bit = try (try self.load(rhs, Type.u64, 0)).toLocal(self, Type.u64);
2156 const high_op_res = try (try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op)).toLocal(self, Type.u64);
2157
2152 const lhs_low_bit = try self.load(lhs, Type.u64, 8);2158 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
2153 const rhs_high_bit = try self.load(rhs, Type.u64, 0);
2154 const rhs_low_bit = try self.load(rhs, Type.u64, 8);2159 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
2155
2156 const high_op_res = try (try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op)).toLocal(self, Type.u64);
2157 const low_op_res = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op);2160 const low_op_res = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op);
21582161
2159 const lt = if (op == .add) blk: {2162 const lt = if (op == .add) blk: {
...@@ -2204,14 +2207,14 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {...@@ -2204,14 +2207,14 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
22042207
2205 if (wasm_bits == 128) {2208 if (wasm_bits == 128) {
2206 assert(operand != .stack);2209 assert(operand != .stack);
2207 const msb = try self.load(operand, Type.u64, 0);
2208 const lsb = try self.load(operand, Type.u64, 8);2210 const lsb = try self.load(operand, Type.u64, 8);
22092211
2210 const result_ptr = try self.allocStack(ty);2212 const result_ptr = try self.allocStack(ty);
2211 try self.store(result_ptr, lsb, Type.u64, 8);2213 try self.emitWValue(result_ptr);
2214 try self.store(.{ .stack = {} }, lsb, Type.u64, 8 + result_ptr.offset());
2212 const result = (@as(u64, 1) << @intCast(u6, 64 - (wasm_bits - bitsize))) - 1;2215 const result = (@as(u64, 1) << @intCast(u6, 64 - (wasm_bits - bitsize))) - 1;
2213 try self.emitWValue(result_ptr);2216 try self.emitWValue(result_ptr);
2214 try self.emitWValue(msb);2217 _ = try self.load(operand, Type.u64, 0);
2215 try self.addImm64(result);2218 try self.addImm64(result);
2216 try self.addTag(.i64_and);2219 try self.addTag(.i64_and);
2217 try self.addMemArg(.i64_store, .{ .offset = result_ptr.offset(), .alignment = 8 });2220 try self.addMemArg(.i64_store, .{ .offset = result_ptr.offset(), .alignment = 8 });
...@@ -2692,10 +2695,9 @@ fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOper...@@ -2692,10 +2695,9 @@ fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOper
2692 return WValue{ .stack = {} };2695 return WValue{ .stack = {} };
2693}2696}
26942697
2698/// Compares 16-bit floats
2699/// NOTE: The result value remains on top of the stack.
2695fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperator) InnerError!WValue {2700fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperator) InnerError!WValue {
2696 const ext_lhs = try self.fpext(lhs, Type.f16, Type.f32);
2697 const ext_rhs = try self.fpext(rhs, Type.f16, Type.f32);
2698
2699 const opcode: wasm.Opcode = buildOpcode(.{2701 const opcode: wasm.Opcode = buildOpcode(.{
2700 .op = switch (op) {2702 .op = switch (op) {
2701 .lt => .lt,2703 .lt => .lt,
...@@ -2708,8 +2710,8 @@ fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperato...@@ -2708,8 +2710,8 @@ fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperato
2708 .valtype1 = .f32,2710 .valtype1 = .f32,
2709 .signedness = .unsigned,2711 .signedness = .unsigned,
2710 });2712 });
2711 try self.emitWValue(ext_lhs);2713 _ = try self.fpext(lhs, Type.f16, Type.f32);
2712 try self.emitWValue(ext_rhs);2714 _ = try self.fpext(rhs, Type.f16, Type.f32);
2713 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));2715 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
27142716
2715 return WValue{ .stack = {} };2717 return WValue{ .stack = {} };
...@@ -2781,13 +2783,15 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2781,13 +2783,15 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2781 },2783 },
2782 128 => {2784 128 => {
2783 const result_ptr = try self.allocStack(operand_ty);2785 const result_ptr = try self.allocStack(operand_ty);
2786 try self.emitWValue(result_ptr);
2784 const msb = try self.load(operand, Type.u64, 0);2787 const msb = try self.load(operand, Type.u64, 0);
2785 const lsb = try self.load(operand, Type.u64, 8);2788 const msb_xor = try self.binOp(msb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);
2789 try self.store(.{ .stack = {} }, msb_xor, Type.u64, 0 + result_ptr.offset());
27862790
2787 const msb_xor = try (try self.binOp(msb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor)).toLocal(self, operand_ty);2791 try self.emitWValue(result_ptr);
2788 const lsb_xor = try (try self.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor)).toLocal(self, operand_ty);2792 const lsb = try self.load(operand, Type.u64, 8);
2789 try self.store(result_ptr, msb_xor, Type.u64, 0);2793 const lsb_xor = try self.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);
2790 try self.store(result_ptr, lsb_xor, Type.u64, 8);2794 try self.store(result_ptr, lsb_xor, Type.u64, 8 + result_ptr.offset());
2791 return result_ptr;2795 return result_ptr;
2792 },2796 },
2793 else => unreachable,2797 else => unreachable,
...@@ -2875,7 +2879,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2875,7 +2879,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2875 }2879 }
2876 }2880 }
28772881
2878 return self.load(operand, field_ty, offset);2882 const field = try self.load(operand, field_ty, offset);
2883 return field.toLocal(self, field_ty);
2879}2884}
28802885
2881fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2886fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3085,7 +3090,9 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool)...@@ -3085,7 +3090,9 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool)
3085 if (op_is_ptr or isByRef(payload_ty, self.target)) {3090 if (op_is_ptr or isByRef(payload_ty, self.target)) {
3086 return self.buildPointerOffset(operand, pl_offset, .new);3091 return self.buildPointerOffset(operand, pl_offset, .new);
3087 }3092 }
3088 return self.load(operand, payload_ty, pl_offset);3093
3094 const payload = try self.load(operand, payload_ty, pl_offset);
3095 return payload.toLocal(self, payload_ty);
3089}3096}
30903097
3091fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!WValue {3098fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!WValue {
...@@ -3105,7 +3112,8 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) In...@@ -3105,7 +3112,8 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) In
3105 return operand;3112 return operand;
3106 }3113 }
31073114
3108 return self.load(operand, Type.anyerror, @intCast(u32, errUnionErrorOffset(payload_ty, self.target)));3115 const error_val = try self.load(operand, Type.anyerror, @intCast(u32, errUnionErrorOffset(payload_ty, self.target)));
3116 return error_val.toLocal(self, Type.anyerror);
3109}3117}
31103118
3111fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3119fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3235,9 +3243,12 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: en...@@ -3235,9 +3243,12 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: en
32353243
3236 const op_ty = self.air.typeOf(un_op);3244 const op_ty = self.air.typeOf(un_op);
3237 const optional_ty = if (op_kind == .ptr) op_ty.childType() else op_ty;3245 const optional_ty = if (op_kind == .ptr) op_ty.childType() else op_ty;
3238 return self.isNull(operand, optional_ty, opcode);3246 const is_null = try self.isNull(operand, optional_ty, opcode);
3247 return is_null.toLocal(self, optional_ty);
3239}3248}
32403249
3250/// For a given type and operand, checks if it's considered `null`.
3251/// NOTE: Leaves the result on the stack
3241fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue {3252fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue {
3242 try self.emitWValue(operand);3253 try self.emitWValue(operand);
3243 if (!optional_ty.optionalReprIsPayload()) {3254 if (!optional_ty.optionalReprIsPayload()) {
...@@ -3254,9 +3265,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode)...@@ -3254,9 +3265,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode)
3254 try self.addImm32(0);3265 try self.addImm32(0);
3255 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));3266 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
32563267
3257 const is_null_tmp = try self.allocLocal(Type.initTag(.i32));3268 return WValue{ .stack = {} };
3258 try self.addLabel(.local_set, is_null_tmp.local);
3259 return is_null_tmp;
3260}3269}
32613270
3262fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3271fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3274,7 +3283,8 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3274,7 +3283,8 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3274 return self.buildPointerOffset(operand, offset, .new);3283 return self.buildPointerOffset(operand, offset, .new);
3275 }3284 }
32763285
3277 return self.load(operand, payload_ty, @intCast(u32, offset));3286 const payload = try self.load(operand, payload_ty, @intCast(u32, offset));
3287 return payload.toLocal(self, payload_ty);
3278}3288}
32793289
3280fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3290fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3377,7 +3387,8 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3377,7 +3387,8 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3377 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3387 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3378 const operand = try self.resolveInst(ty_op.operand);3388 const operand = try self.resolveInst(ty_op.operand);
33793389
3380 return self.load(operand, Type.usize, self.ptrSize());3390 const len = try self.load(operand, Type.usize, self.ptrSize());
3391 return len.toLocal(self, Type.usize);
3381}3392}
33823393
3383fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3394fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3391,8 +3402,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3391,8 +3402,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3391 const elem_size = elem_ty.abiSize(self.target);3402 const elem_size = elem_ty.abiSize(self.target);
33923403
3393 // load pointer onto stack3404 // load pointer onto stack
3394 const slice_ptr = try self.load(slice, Type.usize, 0);3405 _ = try self.load(slice, Type.usize, 0);
3395 try self.addLabel(.local_get, slice_ptr.local);
33963406
3397 // calculate index into slice3407 // calculate index into slice
3398 try self.emitWValue(index);3408 try self.emitWValue(index);
...@@ -3406,7 +3416,9 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3406,7 +3416,9 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3406 if (isByRef(elem_ty, self.target)) {3416 if (isByRef(elem_ty, self.target)) {
3407 return result;3417 return result;
3408 }3418 }
3409 return self.load(result, elem_ty, 0);3419
3420 const elem_val = try self.load(result, elem_ty, 0);
3421 return elem_val.toLocal(self, elem_ty);
3410}3422}
34113423
3412fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3424fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3419,8 +3431,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3419,8 +3431,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3419 const slice = try self.resolveInst(bin_op.lhs);3431 const slice = try self.resolveInst(bin_op.lhs);
3420 const index = try self.resolveInst(bin_op.rhs);3432 const index = try self.resolveInst(bin_op.rhs);
34213433
3422 const slice_ptr = try self.load(slice, Type.usize, 0);3434 _ = try self.load(slice, Type.usize, 0);
3423 try self.addLabel(.local_get, slice_ptr.local);
34243435
3425 // calculate index into slice3436 // calculate index into slice
3426 try self.emitWValue(index);3437 try self.emitWValue(index);
...@@ -3428,7 +3439,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3428,7 +3439,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3428 try self.addTag(.i32_mul);3439 try self.addTag(.i32_mul);
3429 try self.addTag(.i32_add);3440 try self.addTag(.i32_add);
34303441
3431 const result = try self.allocLocal(Type.initTag(.i32));3442 const result = try self.allocLocal(Type.i32);
3432 try self.addLabel(.local_set, result.local);3443 try self.addLabel(.local_set, result.local);
3433 return result;3444 return result;
3434}3445}
...@@ -3437,7 +3448,8 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3437,7 +3448,8 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3437 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };3448 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3438 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3449 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3439 const operand = try self.resolveInst(ty_op.operand);3450 const operand = try self.resolveInst(ty_op.operand);
3440 return self.load(operand, Type.usize, 0);3451 const ptr = try self.load(operand, Type.usize, 0);
3452 return ptr.toLocal(self, Type.usize);
3441}3453}
34423454
3443fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3455fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3511,8 +3523,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3511,8 +3523,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
35113523
3512 // load pointer onto the stack3524 // load pointer onto the stack
3513 if (ptr_ty.isSlice()) {3525 if (ptr_ty.isSlice()) {
3514 const ptr_local = try self.load(ptr, Type.usize, 0);3526 _ = try self.load(ptr, Type.usize, 0);
3515 try self.addLabel(.local_get, ptr_local.local);
3516 } else {3527 } else {
3517 try self.lowerToStack(ptr);3528 try self.lowerToStack(ptr);
3518 }3529 }
...@@ -3528,7 +3539,9 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3528,7 +3539,9 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3528 if (isByRef(elem_ty, self.target)) {3539 if (isByRef(elem_ty, self.target)) {
3529 return result;3540 return result;
3530 }3541 }
3531 return self.load(result, elem_ty, 0);3542
3543 const elem_val = try self.load(result, elem_ty, 0);
3544 return elem_val.toLocal(self, elem_ty);
3532}3545}
35333546
3534fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3547fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3544,8 +3557,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3544,8 +3557,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
35443557
3545 // load pointer onto the stack3558 // load pointer onto the stack
3546 if (ptr_ty.isSlice()) {3559 if (ptr_ty.isSlice()) {
3547 const ptr_local = try self.load(ptr, Type.usize, 0);3560 _ = try self.load(ptr, Type.usize, 0);
3548 try self.addLabel(.local_get, ptr_local.local);
3549 } else {3561 } else {
3550 try self.lowerToStack(ptr);3562 try self.lowerToStack(ptr);
3551 }3563 }
...@@ -3556,7 +3568,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3556,7 +3568,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3556 try self.addTag(.i32_mul);3568 try self.addTag(.i32_mul);
3557 try self.addTag(.i32_add);3569 try self.addTag(.i32_add);
35583570
3559 const result = try self.allocLocal(Type.initTag(.i32));3571 const result = try self.allocLocal(Type.i32);
3560 try self.addLabel(.local_set, result.local);3572 try self.addLabel(.local_set, result.local);
3561 return result;3573 return result;
3562}3574}
...@@ -3707,7 +3719,8 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3707,7 +3719,8 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3707 if (isByRef(elem_ty, self.target)) {3719 if (isByRef(elem_ty, self.target)) {
3708 return result;3720 return result;
3709 }3721 }
3710 return self.load(result, elem_ty, 0);3722 const elem_val = try self.load(result, elem_ty, 0);
3723 return elem_val.toLocal(self, elem_ty);
3711}3724}
37123725
3713fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3726fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3929,24 +3942,18 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std...@@ -3929,24 +3942,18 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std
3929 const payload_ty = operand_ty.optionalChild(&buf);3942 const payload_ty = operand_ty.optionalChild(&buf);
3930 const offset = @intCast(u32, operand_ty.abiSize(self.target) - payload_ty.abiSize(self.target));3943 const offset = @intCast(u32, operand_ty.abiSize(self.target) - payload_ty.abiSize(self.target));
39313944
3932 const lhs_is_null = try self.isNull(lhs, operand_ty, .i32_eq);
3933 const rhs_is_null = try self.isNull(rhs, operand_ty, .i32_eq);
3934
3935 // We store the final result in here that will be validated3945 // We store the final result in here that will be validated
3936 // if the optional is truly equal.3946 // if the optional is truly equal.
3937 const result = try self.allocLocal(Type.initTag(.i32));3947 const result = try self.allocLocal(Type.initTag(.i32));
39383948
3939 try self.startBlock(.block, wasm.block_empty);3949 try self.startBlock(.block, wasm.block_empty);
3940 try self.emitWValue(lhs_is_null);3950 _ = try self.isNull(lhs, operand_ty, .i32_eq);
3941 try self.emitWValue(rhs_is_null);3951 _ = try self.isNull(rhs, operand_ty, .i32_eq);
3942 try self.addTag(.i32_ne); // inverse so we can exit early3952 try self.addTag(.i32_ne); // inverse so we can exit early
3943 try self.addLabel(.br_if, 0);3953 try self.addLabel(.br_if, 0);
39443954
3945 const lhs_pl = try self.load(lhs, payload_ty, offset);3955 _ = try self.load(lhs, payload_ty, offset);
3946 const rhs_pl = try self.load(rhs, payload_ty, offset);3956 _ = try self.load(rhs, payload_ty, offset);
3947
3948 try self.emitWValue(lhs_pl);
3949 try self.emitWValue(rhs_pl);
3950 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, self.target) });3957 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, self.target) });
3951 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));3958 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
3952 try self.addLabel(.br_if, 0);3959 try self.addLabel(.br_if, 0);
...@@ -3973,14 +3980,14 @@ fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.ma...@@ -3973,14 +3980,14 @@ fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.ma
3973 return self.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(self.target).bits});3980 return self.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(self.target).bits});
3974 }3981 }
39753982
3976 const lhs_high_bit = try self.load(lhs, Type.u64, 0);3983 const lhs_high_bit = try (try self.load(lhs, Type.u64, 0)).toLocal(self, Type.u64);
3977 const lhs_low_bit = try self.load(lhs, Type.u64, 8);3984 const rhs_high_bit = try (try self.load(rhs, Type.u64, 0)).toLocal(self, Type.u64);
3978 const rhs_high_bit = try self.load(rhs, Type.u64, 0);
3979 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
39803985
3981 switch (op) {3986 switch (op) {
3982 .eq, .neq => {3987 .eq, .neq => {
3983 const xor_high = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, .xor);3988 const xor_high = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, .xor);
3989 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
3990 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
3984 const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);3991 const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);
3985 const or_result = try self.binOp(xor_high, xor_low, Type.u64, .@"or");3992 const or_result = try self.binOp(xor_high, xor_low, Type.u64, .@"or");
39863993
...@@ -3993,6 +4000,8 @@ fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.ma...@@ -3993,6 +4000,8 @@ fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.ma
3993 else => {4000 else => {
3994 const ty = if (operand_ty.isSignedInt()) Type.i64 else Type.u64;4001 const ty = if (operand_ty.isSignedInt()) Type.i64 else Type.u64;
3995 // leave those value on top of the stack for '.select'4002 // leave those value on top of the stack for '.select'
4003 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
4004 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
3996 _ = try self.cmp(lhs_low_bit, rhs_low_bit, ty, op);4005 _ = try self.cmp(lhs_low_bit, rhs_low_bit, ty, op);
3997 _ = try self.cmp(lhs_high_bit, rhs_high_bit, ty, op);4006 _ = try self.cmp(lhs_high_bit, rhs_high_bit, ty, op);
3998 _ = try self.cmp(lhs_high_bit, rhs_high_bit, ty, .eq);4007 _ = try self.cmp(lhs_high_bit, rhs_high_bit, ty, .eq);
...@@ -4040,7 +4049,8 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4040,7 +4049,8 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4040 const offset = if (layout.tag_align < layout.payload_align) blk: {4049 const offset = if (layout.tag_align < layout.payload_align) blk: {
4041 break :blk @intCast(u32, layout.payload_size);4050 break :blk @intCast(u32, layout.payload_size);
4042 } else @as(u32, 0);4051 } else @as(u32, 0);
4043 return self.load(operand, tag_ty, offset);4052 const tag = try self.load(operand, tag_ty, offset);
4053 return tag.toLocal(self, tag_ty);
4044}4054}
40454055
4046fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue {4056fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -4050,19 +4060,20 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4050,19 +4060,20 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4050 const dest_ty = self.air.typeOfIndex(inst);4060 const dest_ty = self.air.typeOfIndex(inst);
4051 const operand = try self.resolveInst(ty_op.operand);4061 const operand = try self.resolveInst(ty_op.operand);
40524062
4053 return self.fpext(operand, self.air.typeOf(ty_op.operand), dest_ty);4063 const extended = try self.fpext(operand, self.air.typeOf(ty_op.operand), dest_ty);
4064 return extended.toLocal(self, dest_ty);
4054}4065}
40554066
4067/// Extends a float from a given `Type` to a larger wanted `Type`
4068/// NOTE: Leaves the result on the stack
4056fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {4069fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
4057 const given_bits = given.floatBits(self.target);4070 const given_bits = given.floatBits(self.target);
4058 const wanted_bits = wanted.floatBits(self.target);4071 const wanted_bits = wanted.floatBits(self.target);
40594072
4060 if (wanted_bits == 64 and given_bits == 32) {4073 if (wanted_bits == 64 and given_bits == 32) {
4061 const result = try self.allocLocal(wanted);
4062 try self.emitWValue(operand);4074 try self.emitWValue(operand);
4063 try self.addTag(.f64_promote_f32);4075 try self.addTag(.f64_promote_f32);
4064 try self.addLabel(.local_set, result.local);4076 return WValue{ .stack = {} };
4065 return result;
4066 } else if (given_bits == 16) {4077 } else if (given_bits == 16) {
4067 // call __extendhfsf2(f16) f324078 // call __extendhfsf2(f16) f32
4068 const f32_result = try self.callIntrinsic(4079 const f32_result = try self.callIntrinsic(
...@@ -4076,11 +4087,9 @@ fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WVa...@@ -4076,11 +4087,9 @@ fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WVa
4076 return f32_result;4087 return f32_result;
4077 }4088 }
4078 if (wanted_bits == 64) {4089 if (wanted_bits == 64) {
4079 const result = try self.allocLocal(wanted);
4080 try self.emitWValue(f32_result);4090 try self.emitWValue(f32_result);
4081 try self.addTag(.f64_promote_f32);4091 try self.addTag(.f64_promote_f32);
4082 try self.addLabel(.local_set, result.local);4092 return WValue{ .stack = {} };
4083 return result;
4084 }4093 }
4085 return self.fail("TODO: Implement 'fpext' for floats with bitsize: {d}", .{wanted_bits});4094 return self.fail("TODO: Implement 'fpext' for floats with bitsize: {d}", .{wanted_bits});
4086 } else {4095 } else {
...@@ -4095,26 +4104,25 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4095,26 +4104,25 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4095 const ty_op = self.air.instructions.items(.data)[inst].ty_op;4104 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
4096 const dest_ty = self.air.typeOfIndex(inst);4105 const dest_ty = self.air.typeOfIndex(inst);
4097 const operand = try self.resolveInst(ty_op.operand);4106 const operand = try self.resolveInst(ty_op.operand);
4098 return self.fptrunc(operand, self.air.typeOf(ty_op.operand), dest_ty);4107 const trunc = try self.fptrunc(operand, self.air.typeOf(ty_op.operand), dest_ty);
4108 return trunc.toLocal(self, dest_ty);
4099}4109}
41004110
4111/// Truncates a float from a given `Type` to its wanted `Type`
4112/// NOTE: The result value remains on the stack
4101fn fptrunc(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {4113fn fptrunc(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
4102 const given_bits = given.floatBits(self.target);4114 const given_bits = given.floatBits(self.target);
4103 const wanted_bits = wanted.floatBits(self.target);4115 const wanted_bits = wanted.floatBits(self.target);
41044116
4105 if (wanted_bits == 32 and given_bits == 64) {4117 if (wanted_bits == 32 and given_bits == 64) {
4106 const result = try self.allocLocal(wanted);
4107 try self.emitWValue(operand);4118 try self.emitWValue(operand);
4108 try self.addTag(.f32_demote_f64);4119 try self.addTag(.f32_demote_f64);
4109 try self.addLabel(.local_set, result.local);4120 return WValue{ .stack = {} };
4110 return result;
4111 } else if (wanted_bits == 16) {4121 } else if (wanted_bits == 16) {
4112 const op: WValue = if (given_bits == 64) blk: {4122 const op: WValue = if (given_bits == 64) blk: {
4113 const tmp = try self.allocLocal(Type.f32);
4114 try self.emitWValue(operand);4123 try self.emitWValue(operand);
4115 try self.addTag(.f32_demote_f64);4124 try self.addTag(.f32_demote_f64);
4116 try self.addLabel(.local_set, tmp.local);4125 break :blk WValue{ .stack = {} };
4117 break :blk tmp;
4118 } else operand;4126 } else operand;
41194127
4120 // call __truncsfhf2(f32) f164128 // call __truncsfhf2(f32) f16
...@@ -4199,12 +4207,9 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4199,12 +4207,9 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
41994207
4200 switch (wasm_bits) {4208 switch (wasm_bits) {
4201 128 => {4209 128 => {
4202 const msb = try self.load(operand, Type.u64, 0);4210 _ = try self.load(operand, Type.u64, 0);
4203 const lsb = try self.load(operand, Type.u64, 8);
4204
4205 try self.emitWValue(msb);
4206 try self.addTag(.i64_popcnt);4211 try self.addTag(.i64_popcnt);
4207 try self.emitWValue(lsb);4212 _ = try self.load(operand, Type.u64, 8);
4208 try self.addTag(.i64_popcnt);4213 try self.addTag(.i64_popcnt);
4209 try self.addTag(.i64_add);4214 try self.addTag(.i64_add);
4210 try self.addTag(.i32_wrap_i64);4215 try self.addTag(.i32_wrap_i64);
...@@ -4351,10 +4356,10 @@ fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type,...@@ -4351,10 +4356,10 @@ fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type,
4351 return self.fail("TODO: Implement @{{add/sub}}WithOverflow for integer bitsize '{d}'", .{int_info.bits});4356 return self.fail("TODO: Implement @{{add/sub}}WithOverflow for integer bitsize '{d}'", .{int_info.bits});
4352 }4357 }
43534358
4354 const lhs_high_bit = try self.load(lhs, Type.u64, 0);4359 const lhs_high_bit = try (try self.load(lhs, Type.u64, 0)).toLocal(self, Type.u64);
4355 const lhs_low_bit = try self.load(lhs, Type.u64, 8);4360 const lhs_low_bit = try (try self.load(lhs, Type.u64, 8)).toLocal(self, Type.u64);
4356 const rhs_high_bit = try self.load(rhs, Type.u64, 0);4361 const rhs_high_bit = try (try self.load(rhs, Type.u64, 0)).toLocal(self, Type.u64);
4357 const rhs_low_bit = try self.load(rhs, Type.u64, 8);4362 const rhs_low_bit = try (try self.load(rhs, Type.u64, 8)).toLocal(self, Type.u64);
43584363
4359 const low_op_res = try (try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op)).toLocal(self, Type.u64);4364 const low_op_res = try (try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op)).toLocal(self, Type.u64);
4360 const high_op_res = try (try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op)).toLocal(self, Type.u64);4365 const high_op_res = try (try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op)).toLocal(self, Type.u64);
...@@ -4563,9 +4568,9 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4563,9 +4568,9 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4563 const rhs = try self.resolveInst(bin_op.rhs);4568 const rhs = try self.resolveInst(bin_op.rhs);
45644569
4565 if (ty.floatBits(self.target) == 16) {4570 if (ty.floatBits(self.target) == 16) {
4566 const addend_ext = try self.fpext(addend, ty, Type.f32);
4567 const lhs_ext = try self.fpext(lhs, ty, Type.f32);
4568 const rhs_ext = try self.fpext(rhs, ty, Type.f32);4571 const rhs_ext = try self.fpext(rhs, ty, Type.f32);
4572 const lhs_ext = try self.fpext(lhs, ty, Type.f32);
4573 const addend_ext = try self.fpext(addend, ty, Type.f32);
4569 // call to compiler-rt `fn fmaf(f32, f32, f32) f32`4574 // call to compiler-rt `fn fmaf(f32, f32, f32) f32`
4570 const result = try self.callIntrinsic(4575 const result = try self.callIntrinsic(
4571 "fmaf",4576 "fmaf",
...@@ -4573,7 +4578,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4573,7 +4578,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4573 Type.f32,4578 Type.f32,
4574 &.{ rhs_ext, lhs_ext, addend_ext },4579 &.{ rhs_ext, lhs_ext, addend_ext },
4575 );4580 );
4576 return try self.fptrunc(result, Type.f32, ty);4581 return try (try self.fptrunc(result, Type.f32, ty)).toLocal(self, ty);
4577 }4582 }
45784583
4579 const mul_result = try self.binOp(lhs, rhs, ty, .mul);4584 const mul_result = try self.binOp(lhs, rhs, ty, .mul);
...@@ -4606,12 +4611,11 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4606,12 +4611,11 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4606 try self.addTag(.i32_wrap_i64);4611 try self.addTag(.i32_wrap_i64);
4607 },4612 },
4608 128 => {4613 128 => {
4609 const msb = try self.load(operand, Type.u64, 0);4614 const lsb = try (try self.load(operand, Type.u64, 8)).toLocal(self, Type.u64);
4610 const lsb = try self.load(operand, Type.u64, 8);
46114615
4612 try self.emitWValue(lsb);4616 try self.emitWValue(lsb);
4613 try self.addTag(.i64_clz);4617 try self.addTag(.i64_clz);
4614 try self.emitWValue(msb);4618 _ = try self.load(operand, Type.u64, 0);
4615 try self.addTag(.i64_clz);4619 try self.addTag(.i64_clz);
4616 try self.emitWValue(.{ .imm64 = 64 });4620 try self.emitWValue(.{ .imm64 = 64 });
4617 try self.addTag(.i64_add);4621 try self.addTag(.i64_add);
...@@ -4667,12 +4671,11 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4667,12 +4671,11 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4667 try self.addTag(.i32_wrap_i64);4671 try self.addTag(.i32_wrap_i64);
4668 },4672 },
4669 128 => {4673 128 => {
4670 const msb = try self.load(operand, Type.u64, 0);4674 const msb = try (try self.load(operand, Type.u64, 0)).toLocal(self, Type.u64);
4671 const lsb = try self.load(operand, Type.u64, 8);
46724675
4673 try self.emitWValue(msb);4676 try self.emitWValue(msb);
4674 try self.addTag(.i64_ctz);4677 try self.addTag(.i64_ctz);
4675 try self.emitWValue(lsb);4678 _ = try self.load(operand, Type.u64, 8);
4676 if (wasm_bits != int_info.bits) {4679 if (wasm_bits != int_info.bits) {
4677 try self.addImm64(@as(u64, 1) << @intCast(u6, int_info.bits - 64));4680 try self.addImm64(@as(u64, 1) << @intCast(u6, int_info.bits - 64));
4678 try self.addTag(.i64_or);4681 try self.addTag(.i64_or);
...@@ -4810,7 +4813,8 @@ fn lowerTry(...@@ -4810,7 +4813,8 @@ fn lowerTry(
4810 if (isByRef(pl_ty, self.target)) {4813 if (isByRef(pl_ty, self.target)) {
4811 return buildPointerOffset(self, err_union, pl_offset, .new);4814 return buildPointerOffset(self, err_union, pl_offset, .new);
4812 }4815 }
4813 return self.load(err_union, pl_ty, pl_offset);4816 const payload = try self.load(err_union, pl_ty, pl_offset);
4817 return payload.toLocal(self, pl_ty);
4814}4818}
48154819
4816fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {4820fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -4972,9 +4976,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4972,9 +4976,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4972 }4976 }
49734977
4974 if (is_f16) {4978 if (is_f16) {
4975 // we can re-use temporary local4979 _ = try self.fptrunc(.{ .stack = {} }, Type.f32, Type.f16);
4976 try self.addLabel(.local_set, lhs_operand.local);
4977 return self.fptrunc(lhs_operand, Type.f32, Type.f16);
4978 }4980 }
4979 }4981 }
49804982
...@@ -5066,9 +5068,7 @@ fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValu...@@ -5066,9 +5068,7 @@ fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValu
5066 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));5068 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
50675069
5068 if (is_f16) {5070 if (is_f16) {
5069 // re-use temporary to save locals5071 _ = try self.fptrunc(.{ .stack = {} }, Type.f32, Type.f16);
5070 try self.addLabel(.local_set, op_to_lower.local);
5071 return self.fptrunc(op_to_lower, Type.f32, Type.f16);
5072 }5072 }
50735073
5074 const result = try self.allocLocal(ty);5074 const result = try self.allocLocal(ty);
...@@ -5285,6 +5285,8 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -5285,6 +5285,8 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
5285/// Calls a compiler-rt intrinsic by creating an undefined symbol,5285/// Calls a compiler-rt intrinsic by creating an undefined symbol,
5286/// then lowering the arguments and calling the symbol as a function call.5286/// then lowering the arguments and calling the symbol as a function call.
5287/// This function call assumes the C-ABI.5287/// This function call assumes the C-ABI.
5288/// Asserts arguments are not stack values when the return value is
5289/// passed as the first parameter.
5288fn callIntrinsic(5290fn callIntrinsic(
5289 self: *Self,5291 self: *Self,
5290 name: []const u8,5292 name: []const u8,
...@@ -5314,6 +5316,7 @@ fn callIntrinsic(...@@ -5314,6 +5316,7 @@ fn callIntrinsic(
53145316
5315 // Lower all arguments to the stack before we call our function5317 // Lower all arguments to the stack before we call our function
5316 for (args) |arg, arg_i| {5318 for (args) |arg, arg_i| {
5319 assert(!(want_sret_param and arg == .stack));
5317 assert(param_types[arg_i].hasRuntimeBitsIgnoreComptime());5320 assert(param_types[arg_i].hasRuntimeBitsIgnoreComptime());
5318 try self.lowerArg(.C, param_types[arg_i], arg);5321 try self.lowerArg(.C, param_types[arg_i], arg);
5319 }5322 }