authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-03 13:07:23-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-03 13:07:23-07:00
log15f111a085dcd2da7b91da8e29b89def24cb3c6a
treeb06957a599f66d333a4b91e1e489bacaee5f3a15
parentb1873f20744dfa9b5402b936ccc0858d7ef01529

LLVM: update lowering of saturating shift-left

LLVM 14 makes it so that a RHS of saturating shift left produces a poison value if the value is greater than the number of bits of the LHS. Zig now emits code that will check if this is the case and select a saturated LHS value in such case, matching Zig semantics.

2 files changed, 52 insertions(+), 13 deletions(-)

src/codegen/llvm.zig+27-5
......@@ -6817,15 +6817,37 @@ pub const FuncGen = struct {
68176817 const rhs_ty = self.air.typeOf(bin_op.rhs);
68186818 const lhs_scalar_ty = lhs_ty.scalarType();
68196819 const rhs_scalar_ty = rhs_ty.scalarType();
6820
68216820 const tg = self.dg.module.getTarget();
6821 const lhs_bits = lhs_scalar_ty.bitSize(tg);
68226822
6823 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
6824 self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "")
6823 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_bits)
6824 self.builder.buildZExt(rhs, lhs.typeOf(), "")
68256825 else
68266826 rhs;
6827 if (lhs_scalar_ty.isSignedInt()) return self.builder.buildSShlSat(lhs, casted_rhs, "");
6828 return self.builder.buildUShlSat(lhs, casted_rhs, "");
6827
6828 const result = if (lhs_scalar_ty.isSignedInt())
6829 self.builder.buildSShlSat(lhs, casted_rhs, "")
6830 else
6831 self.builder.buildUShlSat(lhs, casted_rhs, "");
6832
6833 // LLVM langref says "If b is (statically or dynamically) equal to or
6834 // larger than the integer bit width of the arguments, the result is a
6835 // poison value."
6836 // However Zig semantics says that saturating shift left can never produce
6837 // undefined; instead it saturates.
6838 const lhs_scalar_llvm_ty = try self.dg.lowerType(lhs_scalar_ty);
6839 const bits = lhs_scalar_llvm_ty.constInt(lhs_bits, .False);
6840 const lhs_max = lhs_scalar_llvm_ty.constAllOnes();
6841 if (rhs_ty.zigTypeTag() == .Vector) {
6842 const vec_len = rhs_ty.vectorLen();
6843 const bits_vec = self.builder.buildVectorSplat(vec_len, bits, "");
6844 const lhs_max_vec = self.builder.buildVectorSplat(vec_len, lhs_max, "");
6845 const in_range = self.builder.buildICmp(.ULT, rhs, bits_vec, "");
6846 return self.builder.buildSelect(in_range, result, lhs_max_vec, "");
6847 } else {
6848 const in_range = self.builder.buildICmp(.ULT, rhs, bits, "");
6849 return self.builder.buildSelect(in_range, result, lhs_max, "");
6850 }
68296851 }
68306852
68316853 fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*const llvm.Value {
src/stage1/codegen.cpp+25-8
......@@ -3868,16 +3868,33 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
38683868 } else {
38693869 zig_unreachable();
38703870 }
3871 case IrBinOpShlSat:
3872 if (scalar_type->id == ZigTypeIdInt) {
3873 if (scalar_type->data.integral.is_signed) {
3874 return ZigLLVMBuildSShlSat(g->builder, op1_value, op2_value, "");
3875 } else {
3876 return ZigLLVMBuildUShlSat(g->builder, op1_value, op2_value, "");
3877 }
3878 } else {
3871 case IrBinOpShlSat: {
3872 if (scalar_type->id != ZigTypeIdInt) {
38793873 zig_unreachable();
38803874 }
3875 LLVMValueRef result = scalar_type->data.integral.is_signed ?
3876 ZigLLVMBuildSShlSat(g->builder, op1_value, op2_value, "") :
3877 ZigLLVMBuildUShlSat(g->builder, op1_value, op2_value, "");
3878 // LLVM langref says "If b is (statically or dynamically) equal to or
3879 // larger than the integer bit width of the arguments, the result is a
3880 // poison value."
3881 // However Zig semantics says that saturating shift left can never produce
3882 // undefined; instead it saturates.
3883 LLVMTypeRef lhs_scalar_llvm_ty = get_llvm_type(g, scalar_type);
3884 LLVMValueRef bits = LLVMConstInt(lhs_scalar_llvm_ty,
3885 scalar_type->data.integral.bit_count, false);
3886 LLVMValueRef lhs_max = LLVMConstAllOnes(lhs_scalar_llvm_ty);
3887 if (operand_type->id == ZigTypeIdVector) {
3888 uint64_t vec_len = operand_type->data.vector.len;
3889 LLVMValueRef bits_vec = LLVMBuildVectorSplat(g->builder, vec_len, bits, "");
3890 LLVMValueRef lhs_max_vec = LLVMBuildVectorSplat(g->builder, vec_len, lhs_max, "");
3891 LLVMValueRef in_range = LLVMBuildICmp(g->builder, LLVMIntULT, op2_value, bits_vec, "");
3892 return LLVMBuildSelect(g->builder, in_range, result, lhs_max_vec, "");
3893 } else {
3894 LLVMValueRef in_range = LLVMBuildICmp(g->builder, LLVMIntULT, op2_value, bits, "");
3895 return LLVMBuildSelect(g->builder, in_range, result, lhs_max, "");
3896 }
3897 }
38813898 }
38823899 zig_unreachable();
38833900}