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.
This commit is contained in:
@@ -6817,15 +6817,37 @@ pub const FuncGen = struct {
|
||||
const rhs_ty = self.air.typeOf(bin_op.rhs);
|
||||
const lhs_scalar_ty = lhs_ty.scalarType();
|
||||
const rhs_scalar_ty = rhs_ty.scalarType();
|
||||
|
||||
const tg = self.dg.module.getTarget();
|
||||
const lhs_bits = lhs_scalar_ty.bitSize(tg);
|
||||
|
||||
const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
|
||||
self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "")
|
||||
const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_bits)
|
||||
self.builder.buildZExt(rhs, lhs.typeOf(), "")
|
||||
else
|
||||
rhs;
|
||||
if (lhs_scalar_ty.isSignedInt()) return self.builder.buildSShlSat(lhs, casted_rhs, "");
|
||||
return self.builder.buildUShlSat(lhs, casted_rhs, "");
|
||||
|
||||
const result = if (lhs_scalar_ty.isSignedInt())
|
||||
self.builder.buildSShlSat(lhs, casted_rhs, "")
|
||||
else
|
||||
self.builder.buildUShlSat(lhs, casted_rhs, "");
|
||||
|
||||
// LLVM langref says "If b is (statically or dynamically) equal to or
|
||||
// larger than the integer bit width of the arguments, the result is a
|
||||
// poison value."
|
||||
// However Zig semantics says that saturating shift left can never produce
|
||||
// undefined; instead it saturates.
|
||||
const lhs_scalar_llvm_ty = try self.dg.lowerType(lhs_scalar_ty);
|
||||
const bits = lhs_scalar_llvm_ty.constInt(lhs_bits, .False);
|
||||
const lhs_max = lhs_scalar_llvm_ty.constAllOnes();
|
||||
if (rhs_ty.zigTypeTag() == .Vector) {
|
||||
const vec_len = rhs_ty.vectorLen();
|
||||
const bits_vec = self.builder.buildVectorSplat(vec_len, bits, "");
|
||||
const lhs_max_vec = self.builder.buildVectorSplat(vec_len, lhs_max, "");
|
||||
const in_range = self.builder.buildICmp(.ULT, rhs, bits_vec, "");
|
||||
return self.builder.buildSelect(in_range, result, lhs_max_vec, "");
|
||||
} else {
|
||||
const in_range = self.builder.buildICmp(.ULT, rhs, bits, "");
|
||||
return self.builder.buildSelect(in_range, result, lhs_max, "");
|
||||
}
|
||||
}
|
||||
|
||||
fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*const llvm.Value {
|
||||
|
||||
Reference in New Issue
Block a user