[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