[llvm] [InstCombine] Fold smin(-a, x - a) + a to smin(x, 0) (PR #167109)
Aneesh Kadiyala via llvm-commits
llvm-commits at lists.llvm.org
Sat Nov 8 09:31:52 PST 2025
https://github.com/ARandomDev99 updated https://github.com/llvm/llvm-project/pull/167109
>From 20147c22840a9296dd3db586dda6a2f54eaab251 Mon Sep 17 00:00:00 2001
From: Aneesh K <notspaceboy at pm.me>
Date: Sat, 8 Nov 2025 12:27:52 +0530
Subject: [PATCH] [InstCombine] Fold binary operators into single minmax
intrinsic
---
.../InstCombine/InstCombineAddSub.cpp | 20 +++++++++++++++++++
.../InstCombine/InstCombineInternal.h | 4 ++++
.../InstCombine/InstructionCombining.cpp | 19 ++++++++++++++++++
.../Transforms/InstCombine/add-min-max.ll | 15 ++++++++++++++
4 files changed, 58 insertions(+)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 9bee523c7b7e5..a811fd6fba9c2 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -1535,6 +1535,9 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
if (Instruction *Phi = foldBinopWithPhiOperands(I))
return Phi;
+ if (Instruction *R = foldBinOpIntoMinMax(I))
+ return R;
+
// (A*B)+(A*C) -> A*(B+C) etc
if (Value *V = foldUsingDistributiveLaws(I))
return replaceInstUsesWith(I, V);
@@ -2037,6 +2040,20 @@ Instruction *InstCombinerImpl::visitFAdd(BinaryOperator &I) {
return BinaryOperator::CreateFSubFMF(Z, XY, &I);
}
+ // smin(-a, x - a) + a --> smin(x, 0) [2 commuted variants]
+ // smin(x - a, -a) + a --> smin(x, 0) [2 commuted variants]
+ if (match(&I,
+ m_c_FAdd(m_SMin(m_FNeg(m_Value(A)), m_FSub(m_Value(X), m_Value(A))),
+ m_Value(A))) ||
+ match(&I,
+ m_c_FAdd(m_SMin(m_FSub(m_Value(X), m_Value(A)), m_FNeg(m_Value(A))),
+ m_Value(A)))) {
+ Constant *Zero = Constant::getNullValue(I.getType());
+ return replaceInstUsesWith(
+ I,
+ Builder.CreateIntrinsic(Intrinsic::smin, {I.getType()}, {X, Zero}, &I));
+ }
+
// Check for (fadd double (sitofp x), y), see if we can merge this into an
// integer add followed by a promotion.
if (Instruction *R = foldFBinOpOfIntCasts(I))
@@ -2310,6 +2327,9 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
return Res;
}
+ if (Instruction *R = foldBinOpIntoMinMax(I))
+ return R;
+
// Try this before Negator to preserve NSW flag.
if (Instruction *R = factorizeMathWithShlOps(I, Builder))
return R;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 9bdd8cb71f7f3..8d3064a4eb56a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -670,6 +670,10 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
/// This is a convenience wrapper function for the above two functions.
Instruction *foldBinOpIntoSelectOrPhi(BinaryOperator &I);
+ /// Given a binary operator with min/max intrinsic as one operand,
+ /// try to fold it into a single min/max intrinsic call.
+ Instruction *foldBinOpIntoMinMax(BinaryOperator &I);
+
Instruction *foldAddWithConstant(BinaryOperator &Add);
Instruction *foldSquareSumInt(BinaryOperator &I);
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index b158e0f626850..3a99295f645b2 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -1833,6 +1833,25 @@ Instruction *InstCombinerImpl::FoldOpIntoSelect(Instruction &Op, SelectInst *SI,
return SelectInst::Create(SI->getCondition(), NewTV, NewFV, "", nullptr, SI);
}
+Instruction *InstCombinerImpl::foldBinOpIntoMinMax(BinaryOperator &I) {
+ Value *LHS = I.getOperand(0);
+ Value *RHS = I.getOperand(1);
+ MinMaxIntrinsic *MinMax = dyn_cast<MinMaxIntrinsic>(LHS);
+ Value* otherOp = RHS;
+ if (!MinMax) {
+ MinMax = dyn_cast<MinMaxIntrinsic>(RHS);
+ otherOp = LHS;
+ }
+ if (!MinMax) return nullptr;
+ Value* X = MinMax->getLHS();
+ Value* Y = MinMax->getRHS();
+ Value* NewX = BinaryOperator::Create(I.getOpcode(), X, otherOp);
+ Value* NewY = BinaryOperator::Create(I.getOpcode(), Y, otherOp);
+ Intrinsic::ID InvID = getInverseMinMaxIntrinsic(MinMax->getIntrinsicID());
+ Function *F = Intrinsic::getOrInsertDeclaration(I.getModule(), InvID, I.getType());
+ return CallInst::Create(F, {NewX, NewY});
+}
+
static Value *simplifyInstructionWithPHI(Instruction &I, PHINode *PN,
Value *InValue, BasicBlock *InBB,
const DataLayout &DL,
diff --git a/llvm/test/Transforms/InstCombine/add-min-max.ll b/llvm/test/Transforms/InstCombine/add-min-max.ll
index 2117a55e2a490..cbf960d32cb90 100644
--- a/llvm/test/Transforms/InstCombine/add-min-max.ll
+++ b/llvm/test/Transforms/InstCombine/add-min-max.ll
@@ -83,3 +83,18 @@ entry:
%res = add nuw nsw i32 %min, %max
ret i32 %res
}
+
+
+define i32 @sadd_min_neg(i32 %x, i32 %a) {
+; CHECK-LABEL: @sadd_min_neg(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[RES:%.*]] = call i32 @llvm.smin.i32(i32 [[A:%.*]], i64 5)
+; CHECK-NEXT: ret i32 [[RES]]
+;
+entry:
+ %neg_a = sub nsw i32 0, %a
+ %x_minus_a = sub nsw i32 %x, %a
+ %smin = call i32 @llvm.smin.i32(i32 %neg_a, i32 %x_minus_a)
+ %res = add nsw i32 %smin, %a
+ ret i32 %res
+}
\ No newline at end of file
More information about the llvm-commits
mailing list