| ... | @@ -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 { |
| 1789 | | 1789 | |
| 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 | } |
| 1795 | | 1795 | |
| 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 first | 1945 | // 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()); |
| 1948 | | 1950 | |
| 1949 | // retrieve length from rhs, and store that alongside lhs as well | 1951 | // 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 | } |
| 1997 | | 2003 | |
| 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 | } |
| 2000 | | 2007 | |
| | 2008 | /// Loads an operand from the linear memory section. |
| | 2009 | /// NOTE: Leaves the value on the stack. |
| 2001 | fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue { | 2010 | fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue { |
| 2002 | // load local's value from memory by its stack position | 2011 | // 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 | ); |
| 2017 | | 2026 | |
| 2018 | // store the result in a local | 2027 | return WValue{ .stack = {} }; |
| 2019 | const result = try self.allocLocal(ty); | | |
| 2020 | try self.addLabel(.local_set, result.local); | | |
| 2021 | return result; | | |
| 2022 | } | 2028 | } |
| 2023 | | 2029 | |
| 2024 | fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 2030 | fn 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 | } |
| 2126 | | 2132 | |
| | 2133 | /// Performs a binary operation for 16-bit floats. |
| | 2134 | /// NOTE: Leaves the result value on the stack |
| 2127 | fn binOpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: Op) InnerError!WValue { | 2135 | fn 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)); |
| 2135 | | 2140 | |
| 2136 | // re-use temporary local | 2141 | 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 | } |
| 2140 | | 2143 | |
| 2141 | fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { | 2144 | fn 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 | } |
| 2149 | | 2152 | |
| 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); |
| 2158 | | 2161 | |
| 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 { |
| 2204 | | 2207 | |
| 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); |
| 2209 | | 2211 | |
| 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 | } |
| 2694 | | 2697 | |
| | 2698 | /// Compares 16-bit floats |
| | 2699 | /// NOTE: The result value remains on top of the stack. |
| 2695 | fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperator) InnerError!WValue { | 2700 | fn 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)); |
| 2714 | | 2716 | |
| 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()); |
| 2786 | | 2790 | |
| 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 | } |
| 2877 | | 2881 | |
| 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 | } |
| 2880 | | 2885 | |
| 2881 | fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 2886 | fn 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 | } |
| 3090 | | 3097 | |
| 3091 | fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!WValue { | 3098 | fn 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 | } |
| 3107 | | 3114 | |
| 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 | } |
| 3110 | | 3118 | |
| 3111 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3119 | fn 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 |
| 3235 | | 3243 | |
| 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 | } |
| 3240 | | 3249 | |
| | 3250 | /// For a given type and operand, checks if it's considered `null`. |
| | 3251 | /// NOTE: Leaves the result on the stack |
| 3241 | fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue { | 3252 | fn 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)); |
| 3256 | | 3267 | |
| 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 | } |
| 3261 | | 3270 | |
| 3262 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3271 | 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,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 | } |
| 3276 | | 3285 | |
| 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 | } |
| 3279 | | 3289 | |
| 3280 | fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3290 | fn 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); |
| 3379 | | 3389 | |
| 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 | } |
| 3382 | | 3393 | |
| 3383 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3394 | 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,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); |
| 3392 | | 3403 | |
| 3393 | // load pointer onto stack | 3404 | // 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); | | |
| 3396 | | 3406 | |
| 3397 | // calculate index into slice | 3407 | // 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 | } |
| 3411 | | 3423 | |
| 3412 | fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3424 | 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,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); |
| 3421 | | 3433 | |
| 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); | | |
| 3424 | | 3435 | |
| 3425 | // calculate index into slice | 3436 | // 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); |
| 3430 | | 3441 | |
| 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 | } |
| 3442 | | 3454 | |
| 3443 | fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3455 | fn 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 { |
| 3511 | | 3523 | |
| 3512 | // load pointer onto the stack | 3524 | // 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 | } |
| 3533 | | 3546 | |
| 3534 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3547 | fn 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 { |
| 3544 | | 3557 | |
| 3545 | // load pointer onto the stack | 3558 | // 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); |
| 3558 | | 3570 | |
| 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 | } |
| 3712 | | 3725 | |
| 3713 | fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3726 | fn 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)); |
| 3931 | | 3944 | |
| 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 validated | 3945 | // 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)); |
| 3938 | | 3948 | |
| 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 early | 3952 | 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); |
| 3944 | | 3954 | |
| 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 | } |
| 3975 | | 3982 | |
| 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); | | |
| 3980 | | 3985 | |
| 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"); |
| 3986 | | 3993 | |
| ... | @@ -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 | } |
| 4045 | | 4055 | |
| 4046 | fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 4056 | 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,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); |
| 4052 | | 4062 | |
| 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 | } |
| 4055 | | 4066 | |
| | 4067 | /// Extends a float from a given `Type` to a larger wanted `Type` |
| | 4068 | /// NOTE: Leaves the result on the stack |
| 4056 | fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue { | 4069 | fn 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); |
| 4059 | | 4072 | |
| 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) f32 | 4078 | // 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 | } |
| 4100 | | 4110 | |
| | 4111 | /// Truncates a float from a given `Type` to its wanted `Type` |
| | 4112 | /// NOTE: The result value remains on the stack |
| 4101 | fn fptrunc(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue { | 4113 | fn 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); |
| 4104 | | 4116 | |
| 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; |
| 4119 | | 4127 | |
| 4120 | // call __truncsfhf2(f32) f16 | 4128 | // 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 { |
| 4199 | | 4207 | |
| 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 | } |
| 4353 | | 4358 | |
| 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); |
| 4358 | | 4363 | |
| 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); |
| 4564 | | 4569 | |
| 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 | } |
| 4578 | | 4583 | |
| 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); | | |
| 4611 | | 4615 | |
| 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); | | |
| 4672 | | 4675 | |
| 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 | } |
| 4815 | | 4819 | |
| 4816 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 4820 | fn 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 | } |
| 4973 | | 4977 | |
| 4974 | if (is_f16) { | 4978 | if (is_f16) { |
| 4975 | // we can re-use temporary local | 4979 | _ = 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 | } |
| 4980 | | 4982 | |
| ... | @@ -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)); |
| 5067 | | 5069 | |
| 5068 | if (is_f16) { | 5070 | if (is_f16) { |
| 5069 | // re-use temporary to save locals | 5071 | _ = 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 | } |
| 5073 | | 5073 | |
| 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. |
| 5288 | fn callIntrinsic( | 5290 | fn 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( |
| 5314 | | 5316 | |
| 5315 | // Lower all arguments to the stack before we call our function | 5317 | // 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 | } |