[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