| ... | @@ -4885,8 +4885,8 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -4885,8 +4885,8 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 4885 | | 4885 | |
| 4886 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 4886 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 4887 | const ty = self.air.typeOfIndex(inst); | 4887 | const ty = self.air.typeOfIndex(inst); |
| 4888 | const lhs_operand = try self.resolveInst(bin_op.lhs); | 4888 | const lhs = try self.resolveInst(bin_op.lhs); |
| 4889 | const rhs_operand = try self.resolveInst(bin_op.rhs); | 4889 | const rhs = try self.resolveInst(bin_op.rhs); |
| 4890 | | 4890 | |
| 4891 | const int_info = ty.intInfo(self.target); | 4891 | const int_info = ty.intInfo(self.target); |
| 4892 | const is_signed = int_info.signedness == .signed; | 4892 | const is_signed = int_info.signedness == .signed; |
| ... | @@ -4895,22 +4895,12 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -4895,22 +4895,12 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 4895 | return self.fail("TODO: saturating arithmetic for integers with bitsize '{d}'", .{int_info.bits}); | 4895 | return self.fail("TODO: saturating arithmetic for integers with bitsize '{d}'", .{int_info.bits}); |
| 4896 | } | 4896 | } |
| 4897 | | 4897 | |
| 4898 | const wasm_bits = toWasmBits(int_info.bits).?; | 4898 | if (is_signed) { |
| 4899 | | 4899 | return signedSat(self, lhs, rhs, ty, op); |
| 4900 | const lhs = if (is_signed) blk: { | 4900 | } |
| 4901 | break :blk try self.signAbsValue(lhs_operand, ty); | | |
| 4902 | } else lhs_operand; | | |
| 4903 | const rhs = if (is_signed) blk: { | | |
| 4904 | break :blk try self.signAbsValue(rhs_operand, ty); | | |
| 4905 | } else rhs_operand; | | |
| 4906 | | | |
| 4907 | const opcode = buildOpcode(.{ .op = op, .valtype1 = typeToValtype(ty, self.target) }); | | |
| 4908 | try self.emitWValue(lhs); | | |
| 4909 | try self.emitWValue(rhs); | | |
| 4910 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | | |
| 4911 | const bin_result = try self.allocLocal(ty); | | |
| 4912 | try self.addLabel(.local_set, bin_result.local); | | |
| 4913 | | 4901 | |
| | 4902 | const wasm_bits = toWasmBits(int_info.bits).?; |
| | 4903 | const bin_result = try self.binOp(lhs, rhs, ty, op); |
| 4914 | if (wasm_bits != int_info.bits and op == .add) { | 4904 | if (wasm_bits != int_info.bits and op == .add) { |
| 4915 | const val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits)) - 1); | 4905 | const val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits)) - 1); |
| 4916 | const imm_val = switch (wasm_bits) { | 4906 | const imm_val = switch (wasm_bits) { |
| ... | @@ -4919,7 +4909,7 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -4919,7 +4909,7 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 4919 | else => unreachable, | 4909 | else => unreachable, |
| 4920 | }; | 4910 | }; |
| 4921 | | 4911 | |
| 4922 | const cmp_result = try self.cmp(bin_result, imm_val, ty, if (op == .add) .lt else .gt); | 4912 | const cmp_result = try self.cmp(bin_result, imm_val, ty, .lt); |
| 4923 | try self.emitWValue(bin_result); | 4913 | try self.emitWValue(bin_result); |
| 4924 | try self.emitWValue(imm_val); | 4914 | try self.emitWValue(imm_val); |
| 4925 | try self.emitWValue(cmp_result); | 4915 | try self.emitWValue(cmp_result); |
| ... | @@ -4939,3 +4929,62 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { | ... | @@ -4939,3 +4929,62 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue { |
| 4939 | try self.addLabel(.local_set, result.local); | 4929 | try self.addLabel(.local_set, result.local); |
| 4940 | return result; | 4930 | return result; |
| 4941 | } | 4931 | } |
| | 4932 | |
| | 4933 | fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op: Op) InnerError!WValue { |
| | 4934 | const int_info = ty.intInfo(self.target); |
| | 4935 | const wasm_bits = toWasmBits(int_info.bits).?; |
| | 4936 | const is_wasm_bits = wasm_bits == int_info.bits; |
| | 4937 | |
| | 4938 | const lhs = if (!is_wasm_bits) try self.signAbsValue(lhs_operand, ty) else lhs_operand; |
| | 4939 | const rhs = if (!is_wasm_bits) try self.signAbsValue(rhs_operand, ty) else rhs_operand; |
| | 4940 | |
| | 4941 | const max_val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits - 1)) - 1); |
| | 4942 | const min_val = @intCast(i64, ~@intCast(u63, max_val)); |
| | 4943 | const max_wvalue = switch (wasm_bits) { |
| | 4944 | 32 => WValue{ .imm32 = @intCast(u32, max_val) }, |
| | 4945 | 64 => WValue{ .imm64 = max_val }, |
| | 4946 | else => unreachable, |
| | 4947 | }; |
| | 4948 | const min_wvalue = switch (wasm_bits) { |
| | 4949 | 32 => WValue{ .imm32 = @bitCast(u32, @truncate(i32, min_val)) }, |
| | 4950 | 64 => WValue{ .imm64 = @bitCast(u64, min_val) }, |
| | 4951 | else => unreachable, |
| | 4952 | }; |
| | 4953 | |
| | 4954 | const bin_result = try self.binOp(lhs, rhs, ty, op); |
| | 4955 | if (!is_wasm_bits) { |
| | 4956 | const cmp_result_lt = try self.cmp(bin_result, max_wvalue, ty, .lt); |
| | 4957 | try self.emitWValue(bin_result); |
| | 4958 | try self.emitWValue(max_wvalue); |
| | 4959 | try self.emitWValue(cmp_result_lt); |
| | 4960 | try self.addTag(.select); |
| | 4961 | try self.addLabel(.local_set, bin_result.local); // re-use local |
| | 4962 | |
| | 4963 | const cmp_result_gt = try self.cmp(bin_result, min_wvalue, ty, .gt); |
| | 4964 | try self.emitWValue(bin_result); |
| | 4965 | try self.emitWValue(min_wvalue); |
| | 4966 | try self.emitWValue(cmp_result_gt); |
| | 4967 | try self.addTag(.select); |
| | 4968 | try self.addLabel(.local_set, bin_result.local); // re-use local |
| | 4969 | return self.wrapOperand(bin_result, ty); |
| | 4970 | } else { |
| | 4971 | const zero = switch (wasm_bits) { |
| | 4972 | 32 => WValue{ .imm32 = 0 }, |
| | 4973 | 64 => WValue{ .imm64 = 0 }, |
| | 4974 | else => unreachable, |
| | 4975 | }; |
| | 4976 | const cmp_bin_result = try self.cmp(bin_result, lhs, ty, .lt); |
| | 4977 | const cmp_zero_result = try self.cmp(rhs, zero, ty, if (op == .add) .lt else .gt); |
| | 4978 | const xor = try self.binOp(cmp_zero_result, cmp_bin_result, ty, .xor); |
| | 4979 | const cmp_bin_zero_result = try self.cmp(bin_result, zero, ty, .lt); |
| | 4980 | try self.emitWValue(max_wvalue); |
| | 4981 | try self.emitWValue(min_wvalue); |
| | 4982 | try self.emitWValue(cmp_bin_zero_result); |
| | 4983 | try self.addTag(.select); |
| | 4984 | try self.emitWValue(bin_result); |
| | 4985 | try self.emitWValue(xor); |
| | 4986 | try self.addTag(.select); |
| | 4987 | try self.addLabel(.local_set, bin_result.local); // re-use local |
| | 4988 | return bin_result; |
| | 4989 | } |
| | 4990 | } |