[llvm] 6357ccf - [InstCombine] reassociate min/max intrinsics with constant operands

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 15 05:31:29 PST 2022


Author: Sanjay Patel
Date: 2022-02-15T08:31:23-05:00
New Revision: 6357ccf57fd5d5c60ffddd611a3f5510b52c2b9c

URL: https://github.com/llvm/llvm-project/commit/6357ccf57fd5d5c60ffddd611a3f5510b52c2b9c
DIFF: https://github.com/llvm/llvm-project/commit/6357ccf57fd5d5c60ffddd611a3f5510b52c2b9c.diff

LOG: [InstCombine] reassociate min/max intrinsics with constant operands

Integer min/max operations are associative:
  max (max X, C0), C1 --> max X, (max C0, C1) --> max X, NewC

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

This would avoid a regression when we canonicalize to min/max intrinsics
(see D98152 ).

Differential Revision: https://reviews.llvm.org/D119754

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
    llvm/test/Transforms/InstCombine/minmax-intrinsics.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index e77017afe048..d2a104be802a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -879,6 +879,29 @@ static Instruction *foldClampRangeOfTwo(IntrinsicInst *II,
   return SelectInst::Create(Cmp, ConstantInt::get(II->getType(), *C0), I1);
 }
 
+/// If this min/max has a constant operand and an operand that is a matching
+/// min/max with a constant operand, constant-fold the 2 constant operands.
+static Instruction *reassociateMinMaxWithConstants(IntrinsicInst *II) {
+  Intrinsic::ID MinMaxID = II->getIntrinsicID();
+  auto *LHS = dyn_cast<IntrinsicInst>(II->getArgOperand(0));
+  if (!LHS || LHS->getIntrinsicID() != MinMaxID)
+    return nullptr;
+
+  Constant *C0, *C1;
+  if (!match(LHS->getArgOperand(1), m_ImmConstant(C0)) ||
+      !match(II->getArgOperand(1), m_ImmConstant(C1)))
+    return nullptr;
+
+  // max (max X, C0), C1 --> max X, (max C0, C1) --> max X, NewC
+  ICmpInst::Predicate Pred = MinMaxIntrinsic::getPredicate(MinMaxID);
+  Constant *CondC = ConstantExpr::getICmp(Pred, C0, C1);
+  Constant *NewC = ConstantExpr::getSelect(CondC, C0, C1);
+
+  Module *Mod = II->getModule();
+  Function *MinMax = Intrinsic::getDeclaration(Mod, MinMaxID, II->getType());
+  return CallInst::Create(MinMax, {LHS->getArgOperand(0), NewC});
+}
+
 /// Reduce a sequence of min/max intrinsics with a common operand.
 static Instruction *factorizeMinMaxTree(IntrinsicInst *II) {
   // Match 3 of the same min/max ops. Example: umin(umin(), umin()).
@@ -1224,6 +1247,9 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
         if (Instruction *R = FoldOpIntoSelect(*II, Sel))
           return R;
 
+    if (Instruction *NewMinMax = reassociateMinMaxWithConstants(II))
+      return NewMinMax;
+
     if (Instruction *NewMinMax = factorizeMinMaxTree(II))
        return NewMinMax;
 

diff  --git a/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll b/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
index e147a05abb25..f3b9757b6a5a 100644
--- a/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
+++ b/llvm/test/Transforms/InstCombine/minmax-intrinsics.ll
@@ -2144,8 +2144,7 @@ define i8 @smax_offset_simplify(i8 %x) {
 
 define <3 x i8> @smax_smax_reassoc_constants(<3 x i8> %x) {
 ; CHECK-LABEL: @smax_smax_reassoc_constants(
-; CHECK-NEXT:    [[M1:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> <i8 42, i8 43, i8 44>)
-; CHECK-NEXT:    [[M2:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[M1]], <3 x i8> <i8 43, i8 -43, i8 0>)
+; CHECK-NEXT:    [[M2:%.*]] = call <3 x i8> @llvm.smax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> <i8 43, i8 43, i8 44>)
 ; CHECK-NEXT:    ret <3 x i8> [[M2]]
 ;
   %m1 = call <3 x i8> @llvm.smax.v3i8(<3 x i8> %x, <3 x i8> <i8 42, i8 43, i8 44>)
@@ -2155,8 +2154,7 @@ define <3 x i8> @smax_smax_reassoc_constants(<3 x i8> %x) {
 
 define i8 @smin_smin_reassoc_constants(i8 %x) {
 ; CHECK-LABEL: @smin_smin_reassoc_constants(
-; CHECK-NEXT:    [[M1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 97)
-; CHECK-NEXT:    [[M2:%.*]] = call i8 @llvm.smin.i8(i8 [[M1]], i8 -3)
+; CHECK-NEXT:    [[M2:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 -3)
 ; CHECK-NEXT:    ret i8 [[M2]]
 ;
   %m1 = call i8 @llvm.smin.i8(i8 %x, i8 97)
@@ -2166,8 +2164,7 @@ define i8 @smin_smin_reassoc_constants(i8 %x) {
 
 define <3 x i8> @umax_umax_reassoc_constants(<3 x i8> %x) {
 ; CHECK-LABEL: @umax_umax_reassoc_constants(
-; CHECK-NEXT:    [[M1:%.*]] = call <3 x i8> @llvm.umax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> <i8 42, i8 43, i8 44>)
-; CHECK-NEXT:    [[M2:%.*]] = call <3 x i8> @llvm.umax.v3i8(<3 x i8> [[M1]], <3 x i8> <i8 43, i8 -113, i8 poison>)
+; CHECK-NEXT:    [[M2:%.*]] = call <3 x i8> @llvm.umax.v3i8(<3 x i8> [[X:%.*]], <3 x i8> <i8 43, i8 -113, i8 poison>)
 ; CHECK-NEXT:    ret <3 x i8> [[M2]]
 ;
   %m1 = call <3 x i8> @llvm.umax.v3i8(<3 x i8> %x, <3 x i8> <i8 42, i8 43, i8 44>)
@@ -2175,11 +2172,13 @@ define <3 x i8> @umax_umax_reassoc_constants(<3 x i8> %x) {
   ret <3 x i8> %m2
 }
 
+; extra use is ok
+
 define i8 @umin_umin_reassoc_constants(i8 %x) {
 ; CHECK-LABEL: @umin_umin_reassoc_constants(
 ; CHECK-NEXT:    [[M1:%.*]] = call i8 @llvm.umin.i8(i8 [[X:%.*]], i8 -116)
 ; CHECK-NEXT:    call void @use(i8 [[M1]])
-; CHECK-NEXT:    [[M2:%.*]] = call i8 @llvm.umin.i8(i8 [[M1]], i8 42)
+; CHECK-NEXT:    [[M2:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 42)
 ; CHECK-NEXT:    ret i8 [[M2]]
 ;
   %m1 = call i8 @llvm.umin.i8(i8 140, i8 %x)
@@ -2188,6 +2187,8 @@ define i8 @umin_umin_reassoc_constants(i8 %x) {
   ret i8 %m2
 }
 
+; negative test - must have matching intrinsics
+
 define i8 @smin_smax_reassoc_constants(i8 %x) {
 ; CHECK-LABEL: @smin_smax_reassoc_constants(
 ; CHECK-NEXT:    [[M1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 97)


        


More information about the llvm-commits mailing list