| ... | @@ -2179,40 +2179,22 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -2179,40 +2179,22 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 2179 | return self.fail("TODO: Implement wrapping arithmetic for vectors", .{}); | 2179 | return self.fail("TODO: Implement wrapping arithmetic for vectors", .{}); |
| 2180 | } | 2180 | } |
| 2181 | | 2181 | |
| 2182 | return self.wrapBinOp(lhs, rhs, ty, op); | 2182 | return (try self.wrapBinOp(lhs, rhs, ty, op)).toLocal(self, ty); |
| 2183 | } | 2183 | } |
| 2184 | | 2184 | |
| | 2185 | /// Performs a wrapping binary operation. |
| | 2186 | /// Asserts rhs is not a stack value when lhs also isn't. |
| | 2187 | /// NOTE: Leaves the result on the stack when its Type is <= 64 bits |
| 2185 | fn wrapBinOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { | 2188 | fn wrapBinOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { |
| 2186 | const bit_size = ty.intInfo(self.target).bits; | 2189 | const bin_local = try self.binOp(lhs, rhs, ty, op); |
| 2187 | var wasm_bits = toWasmBits(bit_size) orelse { | | |
| 2188 | return self.fail("TODO: Implement wrapping arithmetic for integers with bitsize: {d}\n", .{bit_size}); | | |
| 2189 | }; | | |
| 2190 | | | |
| 2191 | if (wasm_bits == 128) { | | |
| 2192 | const bin_op = try self.binOpBigInt(lhs, rhs, ty, op); | | |
| 2193 | return self.wrapOperand(bin_op, ty); | | |
| 2194 | } | | |
| 2195 | | | |
| 2196 | const opcode: wasm.Opcode = buildOpcode(.{ | | |
| 2197 | .op = op, | | |
| 2198 | .valtype1 = typeToValtype(ty, self.target), | | |
| 2199 | .signedness = if (ty.isSignedInt()) .signed else .unsigned, | | |
| 2200 | }); | | |
| 2201 | | | |
| 2202 | try self.emitWValue(lhs); | | |
| 2203 | try self.emitWValue(rhs); | | |
| 2204 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | | |
| 2205 | const bin_local = try self.allocLocal(ty); | | |
| 2206 | try self.addLabel(.local_set, bin_local.local); | | |
| 2207 | | | |
| 2208 | return self.wrapOperand(bin_local, ty); | 2190 | return self.wrapOperand(bin_local, ty); |
| 2209 | } | 2191 | } |
| 2210 | | 2192 | |
| 2211 | /// Wraps an operand based on a given type's bitsize. | 2193 | /// Wraps an operand based on a given type's bitsize. |
| 2212 | /// Asserts `Type` is <= 128 bits. | 2194 | /// Asserts `Type` is <= 128 bits. |
| | 2195 | /// NOTE: When the Type is <= 64 bits, leaves the value on top of the stack. |
| 2213 | fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue { | 2196 | fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue { |
| 2214 | assert(ty.abiSize(self.target) <= 16); | 2197 | assert(ty.abiSize(self.target) <= 16); |
| 2215 | const result_local = try self.allocLocal(ty); | | |
| 2216 | const bitsize = ty.intInfo(self.target).bits; | 2198 | const bitsize = ty.intInfo(self.target).bits; |
| 2217 | const wasm_bits = toWasmBits(bitsize) orelse { | 2199 | const wasm_bits = toWasmBits(bitsize) orelse { |
| 2218 | return self.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize}); | 2200 | return self.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize}); |
| ... | @@ -2246,8 +2228,7 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue { | ... | @@ -2246,8 +2228,7 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue { |
| 2246 | try self.addTag(.i64_and); | 2228 | try self.addTag(.i64_and); |
| 2247 | } else unreachable; | 2229 | } else unreachable; |
| 2248 | | 2230 | |
| 2249 | try self.addLabel(.local_set, result_local.local); | 2231 | return WValue{ .stack = {} }; |
| 2250 | return result_local; | | |
| 2251 | } | 2232 | } |
| 2252 | | 2233 | |
| 2253 | fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WValue { | 2234 | fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WValue { |
| ... | @@ -3471,11 +3452,11 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3471,11 +3452,11 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3471 | return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{int_info.bits}); | 3452 | return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{int_info.bits}); |
| 3472 | } | 3453 | } |
| 3473 | | 3454 | |
| 3474 | const result = try self.intcast(operand, op_ty, wanted_ty); | 3455 | var result = try self.intcast(operand, op_ty, wanted_ty); |
| 3475 | const wanted_bits = wanted_ty.intInfo(self.target).bits; | 3456 | const wanted_bits = wanted_ty.intInfo(self.target).bits; |
| 3476 | const wasm_bits = toWasmBits(wanted_bits).?; | 3457 | const wasm_bits = toWasmBits(wanted_bits).?; |
| 3477 | if (wasm_bits != wanted_bits) { | 3458 | if (wasm_bits != wanted_bits) { |
| 3478 | return self.wrapOperand(result, wanted_ty); | 3459 | result = try self.wrapOperand(result, wanted_ty); |
| 3479 | } | 3460 | } |
| 3480 | return result.toLocal(self, wanted_ty); | 3461 | return result.toLocal(self, wanted_ty); |
| 3481 | } | 3462 | } |
| ... | @@ -3749,11 +3730,8 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3749,11 +3730,8 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3749 | .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned, | 3730 | .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned, |
| 3750 | }); | 3731 | }); |
| 3751 | try self.addTag(Mir.Inst.Tag.fromOpcode(op)); | 3732 | try self.addTag(Mir.Inst.Tag.fromOpcode(op)); |
| 3752 | | 3733 | const wrapped = try self.wrapOperand(.{ .stack = {} }, dest_ty); |
| 3753 | const result = try self.allocLocal(dest_ty); | 3734 | return wrapped.toLocal(self, dest_ty); |
| 3754 | try self.addLabel(.local_set, result.local); | | |
| 3755 | | | |
| 3756 | return self.wrapOperand(result, dest_ty); | | |
| 3757 | } | 3735 | } |
| 3758 | | 3736 | |
| 3759 | fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 3737 | fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | @@ -4339,7 +4317,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W | ... | @@ -4339,7 +4317,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W |
| 4339 | | 4317 | |
| 4340 | const bin_op = try (try self.binOp(lhs, rhs, lhs_ty, op)).toLocal(self, lhs_ty); | 4318 | const bin_op = try (try self.binOp(lhs, rhs, lhs_ty, op)).toLocal(self, lhs_ty); |
| 4341 | const result = if (wasm_bits != int_info.bits) blk: { | 4319 | const result = if (wasm_bits != int_info.bits) blk: { |
| 4342 | break :blk try self.wrapOperand(bin_op, lhs_ty); | 4320 | break :blk try (try self.wrapOperand(bin_op, lhs_ty)).toLocal(self, lhs_ty); |
| 4343 | } else bin_op; | 4321 | } else bin_op; |
| 4344 | | 4322 | |
| 4345 | const cmp_op: std.math.CompareOperator = if (op == .sub) .gt else .lt; | 4323 | const cmp_op: std.math.CompareOperator = if (op == .sub) .gt else .lt; |
| ... | @@ -4438,13 +4416,15 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4438,13 +4416,15 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4438 | | 4416 | |
| 4439 | const shl = try (try self.binOp(lhs, rhs, lhs_ty, .shl)).toLocal(self, lhs_ty); | 4417 | const shl = try (try self.binOp(lhs, rhs, lhs_ty, .shl)).toLocal(self, lhs_ty); |
| 4440 | const result = if (wasm_bits != int_info.bits) blk: { | 4418 | const result = if (wasm_bits != int_info.bits) blk: { |
| 4441 | break :blk try self.wrapOperand(shl, lhs_ty); | 4419 | break :blk try (try self.wrapOperand(shl, lhs_ty)).toLocal(self, lhs_ty); |
| 4442 | } else shl; | 4420 | } else shl; |
| 4443 | | 4421 | |
| 4444 | const overflow_bit = if (wasm_bits != int_info.bits and is_signed) blk: { | 4422 | const overflow_bit = if (wasm_bits != int_info.bits and is_signed) blk: { |
| 4445 | const abs = try self.signAbsValue(shl, lhs_ty); | 4423 | const abs = try self.signAbsValue(shl, lhs_ty); |
| | 4424 | // emit lhs to stack to we can keep 'wrapped' on the stack also |
| | 4425 | try self.emitWValue(lhs); |
| 4446 | const wrapped = try self.wrapBinOp(abs, rhs, lhs_ty, .shr); | 4426 | const wrapped = try self.wrapBinOp(abs, rhs, lhs_ty, .shr); |
| 4447 | break :blk try self.cmp(lhs, wrapped, lhs_ty, .neq); | 4427 | break :blk try self.cmp(.{ .stack = {} }, wrapped, lhs_ty, .neq); |
| 4448 | } else blk: { | 4428 | } else blk: { |
| 4449 | const shr = try (try self.binOp(result, rhs, lhs_ty, .shr)).toLocal(self, lhs_ty); | 4429 | const shr = try (try self.binOp(result, rhs, lhs_ty, .shr)).toLocal(self, lhs_ty); |
| 4450 | break :blk try self.cmp(lhs, shr, lhs_ty, .neq); | 4430 | break :blk try self.cmp(lhs, shr, lhs_ty, .neq); |
| ... | @@ -4499,7 +4479,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4499,7 +4479,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4499 | const wrap = try self.intcast(shr, new_ty, lhs_ty); | 4479 | const wrap = try self.intcast(shr, new_ty, lhs_ty); |
| 4500 | _ = try self.cmp(wrap, zero, lhs_ty, .neq); | 4480 | _ = try self.cmp(wrap, zero, lhs_ty, .neq); |
| 4501 | try self.addLabel(.local_set, overflow_bit.local); | 4481 | try self.addLabel(.local_set, overflow_bit.local); |
| 4502 | break :blk try (try self.intcast(bin_op, new_ty, lhs_ty)).toLocal(self, lhs_ty); | 4482 | break :blk try self.intcast(bin_op, new_ty, lhs_ty); |
| 4503 | } else { | 4483 | } else { |
| 4504 | const down_cast = try (try self.intcast(bin_op, new_ty, lhs_ty)).toLocal(self, lhs_ty); | 4484 | const down_cast = try (try self.intcast(bin_op, new_ty, lhs_ty)).toLocal(self, lhs_ty); |
| 4505 | const shr = try (try self.binOp(down_cast, .{ .imm32 = int_info.bits - 1 }, lhs_ty, .shr)).toLocal(self, lhs_ty); | 4485 | const shr = try (try self.binOp(down_cast, .{ .imm32 = int_info.bits - 1 }, lhs_ty, .shr)).toLocal(self, lhs_ty); |
| ... | @@ -4529,9 +4509,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4529,9 +4509,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4529 | try self.addLabel(.local_set, overflow_bit.local); | 4509 | try self.addLabel(.local_set, overflow_bit.local); |
| 4530 | break :blk try self.wrapOperand(bin_op, lhs_ty); | 4510 | break :blk try self.wrapOperand(bin_op, lhs_ty); |
| 4531 | }; | 4511 | }; |
| | 4512 | const bin_op_local = try bin_op.toLocal(self, lhs_ty); |
| 4532 | | 4513 | |
| 4533 | const result_ptr = try self.allocStack(self.air.typeOfIndex(inst)); | 4514 | const result_ptr = try self.allocStack(self.air.typeOfIndex(inst)); |
| 4534 | try self.store(result_ptr, bin_op, lhs_ty, 0); | 4515 | try self.store(result_ptr, bin_op_local, lhs_ty, 0); |
| 4535 | const offset = @intCast(u32, lhs_ty.abiSize(self.target)); | 4516 | const offset = @intCast(u32, lhs_ty.abiSize(self.target)); |
| 4536 | try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset); | 4517 | try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset); |
| 4537 | | 4518 | |
| ... | @@ -4854,29 +4835,29 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4854,29 +4835,29 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4854 | switch (int_info.bits) { | 4835 | switch (int_info.bits) { |
| 4855 | 16 => { | 4836 | 16 => { |
| 4856 | const shl_res = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shl); | 4837 | const shl_res = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shl); |
| 4857 | const lhs = try (try self.binOp(shl_res, .{ .imm32 = 0xFF00 }, ty, .@"and")).toLocal(self, ty); | 4838 | const lhs = try self.binOp(shl_res, .{ .imm32 = 0xFF00 }, ty, .@"and"); |
| 4858 | const shr_res = try (try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr)).toLocal(self, ty); | 4839 | const shr_res = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr); |
| 4859 | const res = if (int_info.signedness == .signed) blk: { | 4840 | const res = if (int_info.signedness == .signed) blk: { |
| 4860 | break :blk try self.wrapOperand(shr_res, Type.u8); | 4841 | break :blk try self.wrapOperand(shr_res, Type.u8); |
| 4861 | } else shr_res; | 4842 | } else shr_res; |
| 4862 | return (try self.binOp(lhs, res, ty, .@"or")).toLocal(self, ty); | 4843 | return (try self.binOp(lhs, res, ty, .@"or")).toLocal(self, ty); |
| 4863 | }, | 4844 | }, |
| 4864 | 24 => { | 4845 | 24 => { |
| 4865 | const msb = try self.wrapOperand(operand, Type.u16); | 4846 | const msb = try (try self.wrapOperand(operand, Type.u16)).toLocal(self, Type.u16); |
| 4866 | const lsb = try self.wrapBinOp(operand, .{ .imm32 = 16 }, Type.u8, .shr); | | |
| 4867 | | 4847 | |
| 4868 | const shl_res = try self.binOp(msb, .{ .imm32 = 8 }, Type.u16, .shl); | 4848 | const shl_res = try self.binOp(msb, .{ .imm32 = 8 }, Type.u16, .shl); |
| 4869 | const lhs = try (try self.binOp(shl_res, .{ .imm32 = 0xFF0000 }, Type.u16, .@"and")).toLocal(self, Type.u16); | 4849 | const lhs = try self.binOp(shl_res, .{ .imm32 = 0xFF0000 }, Type.u16, .@"and"); |
| 4870 | const shr_res = try (try self.binOp(msb, .{ .imm32 = 8 }, ty, .shr)).toLocal(self, ty); | 4850 | const shr_res = try self.binOp(msb, .{ .imm32 = 8 }, ty, .shr); |
| 4871 | | 4851 | |
| 4872 | const res = if (int_info.signedness == .signed) blk: { | 4852 | const res = if (int_info.signedness == .signed) blk: { |
| 4873 | break :blk try self.wrapOperand(shr_res, Type.u8); | 4853 | break :blk try self.wrapOperand(shr_res, Type.u8); |
| 4874 | } else shr_res; | 4854 | } else shr_res; |
| 4875 | const lhs_tmp = try self.binOp(lhs, res, ty, .@"or"); | 4855 | const lhs_tmp = try self.binOp(lhs, res, ty, .@"or"); |
| 4876 | const lhs_result = try (try self.binOp(lhs_tmp, .{ .imm32 = 8 }, ty, .shr)).toLocal(self, ty); | 4856 | const lhs_result = try self.binOp(lhs_tmp, .{ .imm32 = 8 }, ty, .shr); |
| 4877 | const rhs_wrap = try self.wrapOperand(msb, Type.u8); | 4857 | const rhs_wrap = try self.wrapOperand(msb, Type.u8); |
| 4878 | const rhs_result = try (try self.binOp(rhs_wrap, .{ .imm32 = 16 }, ty, .shl)).toLocal(self, ty); | 4858 | const rhs_result = try self.binOp(rhs_wrap, .{ .imm32 = 16 }, ty, .shl); |
| 4879 | | 4859 | |
| | 4860 | const lsb = try self.wrapBinOp(operand, .{ .imm32 = 16 }, Type.u8, .shr); |
| 4880 | const tmp = try self.binOp(lhs_result, rhs_result, ty, .@"or"); | 4861 | const tmp = try self.binOp(lhs_result, rhs_result, ty, .@"or"); |
| 4881 | return (try self.binOp(tmp, lsb, ty, .@"or")).toLocal(self, ty); | 4862 | return (try self.binOp(tmp, lsb, ty, .@"or")).toLocal(self, ty); |
| 4882 | }, | 4863 | }, |
| ... | @@ -4887,11 +4868,11 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -4887,11 +4868,11 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 4887 | const rhs = try (try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and")).toLocal(self, ty); | 4868 | const rhs = try (try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and")).toLocal(self, ty); |
| 4888 | const tmp_or = try (try self.binOp(lhs, rhs, ty, .@"or")).toLocal(self, ty); | 4869 | const tmp_or = try (try self.binOp(lhs, rhs, ty, .@"or")).toLocal(self, ty); |
| 4889 | | 4870 | |
| 4890 | const shr = try (try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr)).toLocal(self, ty); | 4871 | const shl = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl); |
| | 4872 | const shr = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr); |
| 4891 | const res = if (int_info.signedness == .signed) blk: { | 4873 | const res = if (int_info.signedness == .signed) blk: { |
| 4892 | break :blk try self.wrapOperand(shr, Type.u16); | 4874 | break :blk try self.wrapOperand(shr, Type.u16); |
| 4893 | } else shr; | 4875 | } else shr; |
| 4894 | const shl = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl); | | |
| 4895 | return (try self.binOp(shl, res, ty, .@"or")).toLocal(self, ty); | 4876 | return (try self.binOp(shl, res, ty, .@"or")).toLocal(self, ty); |
| 4896 | }, | 4877 | }, |
| 4897 | else => return self.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}), | 4878 | else => return self.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}), |
| ... | @@ -5178,7 +5159,7 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op | ... | @@ -5178,7 +5159,7 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op |
| 5178 | _ = try self.cmp(bin_result, min_wvalue, ty, .gt); | 5159 | _ = try self.cmp(bin_result, min_wvalue, ty, .gt); |
| 5179 | try self.addTag(.select); | 5160 | try self.addTag(.select); |
| 5180 | try self.addLabel(.local_set, bin_result.local); // re-use local | 5161 | try self.addLabel(.local_set, bin_result.local); // re-use local |
| 5181 | return self.wrapOperand(bin_result, ty); | 5162 | return (try self.wrapOperand(bin_result, ty)).toLocal(self, ty); |
| 5182 | } else { | 5163 | } else { |
| 5183 | const zero = switch (wasm_bits) { | 5164 | const zero = switch (wasm_bits) { |
| 5184 | 32 => WValue{ .imm32 = 0 }, | 5165 | 32 => WValue{ .imm32 = 0 }, |
| ... | @@ -5289,11 +5270,11 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -5289,11 +5270,11 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 5289 | _ = try self.cmp(shl_res, shr, ty, .neq); | 5270 | _ = try self.cmp(shl_res, shr, ty, .neq); |
| 5290 | try self.addTag(.select); | 5271 | try self.addTag(.select); |
| 5291 | try self.addLabel(.local_set, result.local); | 5272 | try self.addLabel(.local_set, result.local); |
| 5292 | const shift_result = try (try self.binOp(result, shift_value, ty, .shr)).toLocal(self, ty); | 5273 | var shift_result = try self.binOp(result, shift_value, ty, .shr); |
| 5293 | if (is_signed) { | 5274 | if (is_signed) { |
| 5294 | return self.wrapOperand(shift_result, ty); | 5275 | shift_result = try self.wrapOperand(shift_result, ty); |
| 5295 | } | 5276 | } |
| 5296 | return shift_result; | 5277 | return try shift_result.toLocal(self, ty); |
| 5297 | } | 5278 | } |
| 5298 | } | 5279 | } |
| 5299 | | 5280 | |