[llvm] 7e720b0 - ValueTracking: Fix canCreateUndefOrPoison for saturating shifts
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Fri Dec 30 08:28:33 PST 2022
Author: Matt Arsenault
Date: 2022-12-30T11:28:28-05:00
New Revision: 7e720b010a19c9941c9d0765cc9467c6d5de4173
URL: https://github.com/llvm/llvm-project/commit/7e720b010a19c9941c9d0765cc9467c6d5de4173
DIFF: https://github.com/llvm/llvm-project/commit/7e720b010a19c9941c9d0765cc9467c6d5de4173.diff
LOG: ValueTracking: Fix canCreateUndefOrPoison for saturating shifts
These need to consider the shift amount.
Added:
Modified:
llvm/lib/Analysis/ValueTracking.cpp
llvm/test/Transforms/InstCombine/freeze-integer-intrinsics.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index a975f1c55d7af..8fe98b5ba427a 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5197,6 +5197,31 @@ bool llvm::isOverflowIntrinsicNoWrap(const WithOverflowInst *WO,
return llvm::any_of(GuardingBranches, AllUsesGuardedByBranch);
}
+/// Shifts return poison if shiftwidth is larger than the bitwidth.
+static bool shiftAmountKnownInRange(const Value *ShiftAmount) {
+ auto *C = dyn_cast<Constant>(ShiftAmount);
+ if (!C)
+ return false;
+
+ // Shifts return poison if shiftwidth is larger than the bitwidth.
+ SmallVector<const Constant *, 4> ShiftAmounts;
+ if (auto *FVTy = dyn_cast<FixedVectorType>(C->getType())) {
+ unsigned NumElts = FVTy->getNumElements();
+ for (unsigned i = 0; i < NumElts; ++i)
+ ShiftAmounts.push_back(C->getAggregateElement(i));
+ } else if (isa<ScalableVectorType>(C->getType()))
+ return false; // Can't tell, just return false to be safe
+ else
+ ShiftAmounts.push_back(C);
+
+ bool Safe = llvm::all_of(ShiftAmounts, [](const Constant *C) {
+ auto *CI = dyn_cast_or_null<ConstantInt>(C);
+ return CI && CI->getValue().ult(C->getType()->getIntegerBitWidth());
+ });
+
+ return Safe;
+}
+
static bool canCreateUndefOrPoison(const Operator *Op, bool PoisonOnly,
bool ConsiderFlags) {
@@ -5209,27 +5234,8 @@ static bool canCreateUndefOrPoison(const Operator *Op, bool PoisonOnly,
switch (Opcode) {
case Instruction::Shl:
case Instruction::AShr:
- case Instruction::LShr: {
- // Shifts return poison if shiftwidth is larger than the bitwidth.
- if (auto *C = dyn_cast<Constant>(Op->getOperand(1))) {
- SmallVector<Constant *, 4> ShiftAmounts;
- if (auto *FVTy = dyn_cast<FixedVectorType>(C->getType())) {
- unsigned NumElts = FVTy->getNumElements();
- for (unsigned i = 0; i < NumElts; ++i)
- ShiftAmounts.push_back(C->getAggregateElement(i));
- } else if (isa<ScalableVectorType>(C->getType()))
- return true; // Can't tell, just return true to be safe
- else
- ShiftAmounts.push_back(C);
-
- bool Safe = llvm::all_of(ShiftAmounts, [](Constant *C) {
- auto *CI = dyn_cast_or_null<ConstantInt>(C);
- return CI && CI->getValue().ult(C->getType()->getIntegerBitWidth());
- });
- return !Safe;
- }
- return true;
- }
+ case Instruction::LShr:
+ return !shiftAmountKnownInRange(Op->getOperand(1));
case Instruction::FPToSI:
case Instruction::FPToUI:
// fptosi/ui yields poison if the resulting value does not fit in the
@@ -5267,8 +5273,10 @@ static bool canCreateUndefOrPoison(const Operator *Op, bool PoisonOnly,
case Intrinsic::uadd_sat:
case Intrinsic::ssub_sat:
case Intrinsic::usub_sat:
+ return false;
case Intrinsic::sshl_sat:
case Intrinsic::ushl_sat:
+ return !shiftAmountKnownInRange(II->getArgOperand(1));
case Intrinsic::fma:
case Intrinsic::fmuladd:
case Intrinsic::sqrt:
diff --git a/llvm/test/Transforms/InstCombine/freeze-integer-intrinsics.ll b/llvm/test/Transforms/InstCombine/freeze-integer-intrinsics.ll
index 122f4f260eb01..fa62cbcd24dc1 100644
--- a/llvm/test/Transforms/InstCombine/freeze-integer-intrinsics.ll
+++ b/llvm/test/Transforms/InstCombine/freeze-integer-intrinsics.ll
@@ -286,9 +286,9 @@ define i32 @usub_sat_i32(i32 %arg0, i32 noundef %arg1) {
define i32 @sshl_sat_i32(i32 %arg0, i32 noundef %arg1) {
; CHECK-LABEL: @sshl_sat_i32(
-; CHECK-NEXT: [[ARG0_FR:%.*]] = freeze i32 [[ARG0:%.*]]
-; CHECK-NEXT: [[CALL:%.*]] = call i32 @llvm.sshl.sat.i32(i32 [[ARG0_FR]], i32 [[ARG1:%.*]])
-; CHECK-NEXT: ret i32 [[CALL]]
+; CHECK-NEXT: [[CALL:%.*]] = call i32 @llvm.sshl.sat.i32(i32 [[ARG0:%.*]], i32 [[ARG1:%.*]])
+; CHECK-NEXT: [[FREEZE:%.*]] = freeze i32 [[CALL]]
+; CHECK-NEXT: ret i32 [[FREEZE]]
;
%call = call i32 @llvm.sshl.sat.i32(i32 %arg0, i32 %arg1)
%freeze = freeze i32 %call
@@ -297,15 +297,125 @@ define i32 @sshl_sat_i32(i32 %arg0, i32 noundef %arg1) {
define i32 @ushl_sat_i32(i32 %arg0, i32 noundef %arg1) {
; CHECK-LABEL: @ushl_sat_i32(
+; CHECK-NEXT: [[CALL:%.*]] = call i32 @llvm.ushl.sat.i32(i32 [[ARG0:%.*]], i32 [[ARG1:%.*]])
+; CHECK-NEXT: [[FREEZE:%.*]] = freeze i32 [[CALL]]
+; CHECK-NEXT: ret i32 [[FREEZE]]
+;
+ %call = call i32 @llvm.ushl.sat.i32(i32 %arg0, i32 %arg1)
+ %freeze = freeze i32 %call
+ ret i32 %freeze
+}
+
+define i32 @sshl_sat_i32_safe_constant(i32 %arg0) {
+; CHECK-LABEL: @sshl_sat_i32_safe_constant(
; CHECK-NEXT: [[ARG0_FR:%.*]] = freeze i32 [[ARG0:%.*]]
-; CHECK-NEXT: [[CALL:%.*]] = call i32 @llvm.ushl.sat.i32(i32 [[ARG0_FR]], i32 [[ARG1:%.*]])
+; CHECK-NEXT: [[CALL:%.*]] = call i32 @llvm.sshl.sat.i32(i32 [[ARG0_FR]], i32 8)
; CHECK-NEXT: ret i32 [[CALL]]
;
- %call = call i32 @llvm.ushl.sat.i32(i32 %arg0, i32 %arg1)
+ %call = call i32 @llvm.sshl.sat.i32(i32 %arg0, i32 8)
+ %freeze = freeze i32 %call
+ ret i32 %freeze
+}
+
+define i32 @ushl_sat_i32_safe_constant(i32 %arg0) {
+; CHECK-LABEL: @ushl_sat_i32_safe_constant(
+; CHECK-NEXT: [[ARG0_FR:%.*]] = freeze i32 [[ARG0:%.*]]
+; CHECK-NEXT: [[CALL:%.*]] = call i32 @llvm.ushl.sat.i32(i32 [[ARG0_FR]], i32 8)
+; CHECK-NEXT: ret i32 [[CALL]]
+;
+ %call = call i32 @llvm.ushl.sat.i32(i32 %arg0, i32 8)
+ %freeze = freeze i32 %call
+ ret i32 %freeze
+}
+
+define i32 @sshl_sat_i32_unsafe_constant(i32 %arg0) {
+; CHECK-LABEL: @sshl_sat_i32_unsafe_constant(
+; CHECK-NEXT: [[CALL:%.*]] = call i32 @llvm.sshl.sat.i32(i32 [[ARG0:%.*]], i32 32)
+; CHECK-NEXT: [[FREEZE:%.*]] = freeze i32 [[CALL]]
+; CHECK-NEXT: ret i32 [[FREEZE]]
+;
+ %call = call i32 @llvm.sshl.sat.i32(i32 %arg0, i32 32)
%freeze = freeze i32 %call
ret i32 %freeze
}
+define i32 @ushl_sat_i32_unsafe_constant(i32 %arg0) {
+; CHECK-LABEL: @ushl_sat_i32_unsafe_constant(
+; CHECK-NEXT: [[CALL:%.*]] = call i32 @llvm.ushl.sat.i32(i32 [[ARG0:%.*]], i32 32)
+; CHECK-NEXT: [[FREEZE:%.*]] = freeze i32 [[CALL]]
+; CHECK-NEXT: ret i32 [[FREEZE]]
+;
+ %call = call i32 @llvm.ushl.sat.i32(i32 %arg0, i32 32)
+ %freeze = freeze i32 %call
+ ret i32 %freeze
+}
+
+define <2 x i32> @sshl_sat_v2i32_safe_constant(<2 x i32> %arg0) {
+; CHECK-LABEL: @sshl_sat_v2i32_safe_constant(
+; CHECK-NEXT: [[ARG0_FR:%.*]] = freeze <2 x i32> [[ARG0:%.*]]
+; CHECK-NEXT: [[CALL:%.*]] = call <2 x i32> @llvm.sshl.sat.v2i32(<2 x i32> [[ARG0_FR]], <2 x i32> <i32 8, i32 9>)
+; CHECK-NEXT: ret <2 x i32> [[CALL]]
+;
+ %call = call <2 x i32> @llvm.sshl.sat.v2i32(<2 x i32> %arg0, <2 x i32> <i32 8, i32 9>)
+ %freeze = freeze <2 x i32> %call
+ ret <2 x i32> %freeze
+}
+
+define <2 x i32> @ushl_sat_v2i32_safe_constant_vector(<2 x i32> %arg0) {
+; CHECK-LABEL: @ushl_sat_v2i32_safe_constant_vector(
+; CHECK-NEXT: [[ARG0_FR:%.*]] = freeze <2 x i32> [[ARG0:%.*]]
+; CHECK-NEXT: [[CALL:%.*]] = call <2 x i32> @llvm.ushl.sat.v2i32(<2 x i32> [[ARG0_FR]], <2 x i32> <i32 8, i32 9>)
+; CHECK-NEXT: ret <2 x i32> [[CALL]]
+;
+ %call = call <2 x i32> @llvm.ushl.sat.v2i32(<2 x i32> %arg0, <2 x i32> <i32 8, i32 9>)
+ %freeze = freeze <2 x i32> %call
+ ret <2 x i32> %freeze
+}
+
+define <2 x i32> @ushl_sat_v2i32_unsafe_constant_vector(<2 x i32> %arg0) {
+; CHECK-LABEL: @ushl_sat_v2i32_unsafe_constant_vector(
+; CHECK-NEXT: [[CALL:%.*]] = call <2 x i32> @llvm.ushl.sat.v2i32(<2 x i32> [[ARG0:%.*]], <2 x i32> <i32 undef, i32 9>)
+; CHECK-NEXT: [[FREEZE:%.*]] = freeze <2 x i32> [[CALL]]
+; CHECK-NEXT: ret <2 x i32> [[FREEZE]]
+;
+ %call = call <2 x i32> @llvm.ushl.sat.v2i32(<2 x i32> %arg0, <2 x i32> <i32 undef, i32 9>)
+ %freeze = freeze <2 x i32> %call
+ ret <2 x i32> %freeze
+}
+
+define <2 x i32> @sshl_sat_v2i32_unsafe_constant_vector(<2 x i32> %arg0) {
+; CHECK-LABEL: @sshl_sat_v2i32_unsafe_constant_vector(
+; CHECK-NEXT: [[CALL:%.*]] = call <2 x i32> @llvm.sshl.sat.v2i32(<2 x i32> [[ARG0:%.*]], <2 x i32> <i32 undef, i32 9>)
+; CHECK-NEXT: [[FREEZE:%.*]] = freeze <2 x i32> [[CALL]]
+; CHECK-NEXT: ret <2 x i32> [[FREEZE]]
+;
+ %call = call <2 x i32> @llvm.sshl.sat.v2i32(<2 x i32> %arg0, <2 x i32> <i32 undef, i32 9>)
+ %freeze = freeze <2 x i32> %call
+ ret <2 x i32> %freeze
+}
+
+define <vscale x 2 x i32> @ushl_sat_v2i32_scalable_zeroinitializer(<vscale x 2 x i32> %arg0) {
+; CHECK-LABEL: @ushl_sat_v2i32_scalable_zeroinitializer(
+; CHECK-NEXT: [[CALL:%.*]] = call <vscale x 2 x i32> @llvm.ushl.sat.nxv2i32(<vscale x 2 x i32> [[ARG0:%.*]], <vscale x 2 x i32> zeroinitializer)
+; CHECK-NEXT: [[FREEZE:%.*]] = freeze <vscale x 2 x i32> [[CALL]]
+; CHECK-NEXT: ret <vscale x 2 x i32> [[FREEZE]]
+;
+ %call = call <vscale x 2 x i32> @llvm.ushl.sat.nxv2i32(<vscale x 2 x i32> %arg0, <vscale x 2 x i32> zeroinitializer)
+ %freeze = freeze <vscale x 2 x i32> %call
+ ret <vscale x 2 x i32> %freeze
+}
+
+define <vscale x 2 x i32> @sshl_sat_v2i32_scalable_zeroinitializer(<vscale x 2 x i32> %arg0) {
+; CHECK-LABEL: @sshl_sat_v2i32_scalable_zeroinitializer(
+; CHECK-NEXT: [[CALL:%.*]] = call <vscale x 2 x i32> @llvm.sshl.sat.nxv2i32(<vscale x 2 x i32> [[ARG0:%.*]], <vscale x 2 x i32> zeroinitializer)
+; CHECK-NEXT: [[FREEZE:%.*]] = freeze <vscale x 2 x i32> [[CALL]]
+; CHECK-NEXT: ret <vscale x 2 x i32> [[FREEZE]]
+;
+ %call = call <vscale x 2 x i32> @llvm.sshl.sat.nxv2i32(<vscale x 2 x i32> %arg0, <vscale x 2 x i32> zeroinitializer)
+ %freeze = freeze <vscale x 2 x i32> %call
+ ret <vscale x 2 x i32> %freeze
+}
+
declare i32 @llvm.ctlz.i32(i32, i1 immarg)
declare i32 @llvm.cttz.i32(i32, i1 immarg)
declare i32 @llvm.abs.i32(i32, i1 immarg)
@@ -326,3 +436,7 @@ declare i32 @llvm.ssub.sat.i32(i32, i32)
declare i32 @llvm.usub.sat.i32(i32, i32)
declare i32 @llvm.sshl.sat.i32(i32, i32)
declare i32 @llvm.ushl.sat.i32(i32, i32)
+declare <2 x i32> @llvm.sshl.sat.v2i32(<2 x i32>, <2 x i32>)
+declare <2 x i32> @llvm.ushl.sat.v2i32(<2 x i32>, <2 x i32>)
+declare <vscale x 2 x i32> @llvm.sshl.sat.nxv2i32(<vscale x 2 x i32>, <vscale x 2 x i32>)
+declare <vscale x 2 x i32> @llvm.ushl.sat.nxv2i32(<vscale x 2 x i32>, <vscale x 2 x i32>)
More information about the llvm-commits
mailing list