[llvm] 86b4d86 - [InstCombine] canonicalize cmp+select as umin/umax

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 8 14:26:07 PST 2023


Author: Sanjay Patel
Date: 2023-02-08T17:25:58-05:00
New Revision: 86b4d8645fc1b86693fef564cef68f24599c930f

URL: https://github.com/llvm/llvm-project/commit/86b4d8645fc1b86693fef564cef68f24599c930f
DIFF: https://github.com/llvm/llvm-project/commit/86b4d8645fc1b86693fef564cef68f24599c930f.diff

LOG: [InstCombine] canonicalize cmp+select as umin/umax

(V == 0) ? 1 : V --> umax(V, 1)
(V == UMAX) ? UMAX-1 : V --> umin(V, UMAX-1)

https://alive2.llvm.org/ce/z/pfDBAf

This is one pair of the variants discussed in issue #60374.

Enhancements for the other end of the constant range and
signed variants are potential follow-ups, but that may
require more work because we canonicalize at least one
min/max like that to icmp+zext.

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
    llvm/test/Transforms/InstCombine/div-shift.ll
    llvm/test/Transforms/InstCombine/select.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index e7d8208f94fd4..894b11c9d918c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1593,13 +1593,26 @@ static Instruction *foldSelectZeroOrOnes(ICmpInst *Cmp, Value *TVal,
   return nullptr;
 }
 
-static Value *foldSelectInstWithICmpConst(SelectInst &SI, ICmpInst *ICI) {
+static Value *foldSelectInstWithICmpConst(SelectInst &SI, ICmpInst *ICI,
+                                          InstCombiner::BuilderTy &Builder) {
   const APInt *CmpC;
   Value *V;
   CmpInst::Predicate Pred;
   if (!match(ICI, m_ICmp(Pred, m_Value(V), m_APInt(CmpC))))
     return nullptr;
 
+  // Match clamp away from min/max value as a max/min operation.
+  Value *TVal = SI.getTrueValue();
+  Value *FVal = SI.getFalseValue();
+  if (Pred == ICmpInst::ICMP_EQ && V == FVal) {
+    // (V == 0) ? 1 : V --> umax(V, 1)
+    if (CmpC->isMinValue() && match(TVal, m_SpecificInt(*CmpC + 1)))
+      return Builder.CreateBinaryIntrinsic(Intrinsic::umax, V, TVal);
+    // (V == UMAX) ? UMAX-1 : V --> umin(V, UMAX-1)
+    if (CmpC->isMaxValue() && match(TVal, m_SpecificInt(*CmpC - 1)))
+      return Builder.CreateBinaryIntrinsic(Intrinsic::umin, V, TVal);
+  }
+
   BinaryOperator *BO;
   const APInt *C;
   CmpInst::Predicate CPred;
@@ -1632,7 +1645,7 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
   if (Instruction *NewSPF = canonicalizeSPF(SI, *ICI, *this))
     return NewSPF;
 
-  if (Value *V = foldSelectInstWithICmpConst(SI, ICI))
+  if (Value *V = foldSelectInstWithICmpConst(SI, ICI, Builder))
     return replaceInstUsesWith(SI, V);
 
   if (Value *V = canonicalizeClampLike(SI, *ICI, Builder))

diff  --git a/llvm/test/Transforms/InstCombine/div-shift.ll b/llvm/test/Transforms/InstCombine/div-shift.ll
index b87ace5a630ef..efdaa0ce9d059 100644
--- a/llvm/test/Transforms/InstCombine/div-shift.ll
+++ b/llvm/test/Transforms/InstCombine/div-shift.ll
@@ -90,8 +90,7 @@ define i32 @t5(i1 %x, i1 %y, i32 %V) {
 
 define i32 @t6(i32 %x, i32 %z) {
 ; CHECK-LABEL: @t6(
-; CHECK-NEXT:    [[X_IS_ZERO:%.*]] = icmp eq i32 [[X:%.*]], 0
-; CHECK-NEXT:    [[DIVISOR:%.*]] = select i1 [[X_IS_ZERO]], i32 1, i32 [[X]]
+; CHECK-NEXT:    [[DIVISOR:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 1)
 ; CHECK-NEXT:    [[Y:%.*]] = udiv i32 [[Z:%.*]], [[DIVISOR]]
 ; CHECK-NEXT:    ret i32 [[Y]]
 ;

diff  --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index 96303bae2f753..87a26cf6c1b5c 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -3399,8 +3399,7 @@ define <vscale x 2 x i1> @scalable_non_zero(<vscale x 2 x i32> %x) {
 
 define i32 @clamp_zero(i32 %x) {
 ; CHECK-LABEL: @clamp_zero(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 1, i32 [[X]]
+; CHECK-NEXT:    [[SEL:%.*]] = call i32 @llvm.umax.i32(i32 [[X:%.*]], i32 1)
 ; CHECK-NEXT:    ret i32 [[SEL]]
 ;
   %cmp = icmp eq i32 %x, 0
@@ -3412,7 +3411,7 @@ define i32 @clamp_zero_use(i32 %x) {
 ; CHECK-LABEL: @clamp_zero_use(
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
 ; CHECK-NEXT:    call void @use1(i1 [[CMP]])
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 1, i32 [[X]]
+; CHECK-NEXT:    [[SEL:%.*]] = call i32 @llvm.umax.i32(i32 [[X]], i32 1)
 ; CHECK-NEXT:    ret i32 [[SEL]]
 ;
   %cmp = icmp eq i32 %x, 0
@@ -3421,6 +3420,8 @@ define i32 @clamp_zero_use(i32 %x) {
   ret i32 %sel
 }
 
+; negative test - wrong cmp constant
+
 define i32 @not_clamp_zero1(i32 %x) {
 ; CHECK-LABEL: @not_clamp_zero1(
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 2
@@ -3432,6 +3433,8 @@ define i32 @not_clamp_zero1(i32 %x) {
   ret i32 %sel
 }
 
+; negative test - wrong select constant
+
 define i32 @not_clamp_zero2(i32 %x) {
 ; CHECK-LABEL: @not_clamp_zero2(
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
@@ -3445,8 +3448,7 @@ define i32 @not_clamp_zero2(i32 %x) {
 
 define <2 x i8> @clamp_umaxval(<2 x i8> %x) {
 ; CHECK-LABEL: @clamp_umaxval(
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
-; CHECK-NEXT:    [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> <i8 -2, i8 -2>, <2 x i8> [[X]]
+; CHECK-NEXT:    [[SEL:%.*]] = call <2 x i8> @llvm.umin.v2i8(<2 x i8> [[X:%.*]], <2 x i8> <i8 -2, i8 -2>)
 ; CHECK-NEXT:    ret <2 x i8> [[SEL]]
 ;
   %cmp = icmp eq <2 x i8> %x, <i8 255, i8 255>
@@ -3454,6 +3456,8 @@ define <2 x i8> @clamp_umaxval(<2 x i8> %x) {
   ret <2 x i8> %sel
 }
 
+; negative test - wrong cmp constant
+
 define i8 @not_clamp_umax1(i8 %x) {
 ; CHECK-LABEL: @not_clamp_umax1(
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X:%.*]], -3
@@ -3465,6 +3469,8 @@ define i8 @not_clamp_umax1(i8 %x) {
   ret i8 %sel
 }
 
+; negative test - wrong select constant
+
 define i8 @not_clamp_umax2(i8 %x) {
 ; CHECK-LABEL: @not_clamp_umax2(
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X:%.*]], -1


        


More information about the llvm-commits mailing list