[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 Dec 27 21:53:31 PST 2025
https://github.com/ARandomDev99 updated https://github.com/llvm/llvm-project/pull/167109
>From fc350e7df1b0076556e81cee9e33d8ddb9201123 Mon Sep 17 00:00:00 2001
From: Aneesh K <notspaceboy at pm.me>
Date: Sat, 27 Dec 2025 23:01:59 +0530
Subject: [PATCH] [InstCombine] Fold binary operators into single minmax
intrinsic
---
.../InstCombine/InstCombineAddSub.cpp | 20 +++
.../InstCombine/InstCombineInternal.h | 4 +
.../InstCombine/InstructionCombining.cpp | 165 +++++++++++-------
.../Transforms/InstCombine/add-min-max.ll | 30 ++++
4 files changed, 155 insertions(+), 64 deletions(-)
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..fe477e651cf24 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -122,13 +122,13 @@ STATISTIC(NumThreeIterations, "Number of functions with three iterations");
STATISTIC(NumFourOrMoreIterations,
"Number of functions with four or more iterations");
-STATISTIC(NumCombined , "Number of insts combined");
+STATISTIC(NumCombined, "Number of insts combined");
STATISTIC(NumConstProp, "Number of constant folds");
-STATISTIC(NumDeadInst , "Number of dead inst eliminated");
-STATISTIC(NumSunkInst , "Number of instructions sunk");
-STATISTIC(NumExpand, "Number of expansions");
-STATISTIC(NumFactor , "Number of factorizations");
-STATISTIC(NumReassoc , "Number of reassociations");
+STATISTIC(NumDeadInst, "Number of dead inst eliminated");
+STATISTIC(NumSunkInst, "Number of instructions sunk");
+STATISTIC(NumExpand, "Number of expansions");
+STATISTIC(NumFactor, "Number of factorizations");
+STATISTIC(NumReassoc, "Number of reassociations");
DEBUG_COUNTER(VisitCounter, "instcombine-visit",
"Controls which instructions are visited");
@@ -140,9 +140,9 @@ static cl::opt<unsigned> MaxSinkNumUsers(
"instcombine-max-sink-users", cl::init(32),
cl::desc("Maximum number of undroppable users for instruction sinking"));
-static cl::opt<unsigned>
-MaxArraySize("instcombine-maxarray-size", cl::init(1024),
- cl::desc("Maximum array size considered when doing a combine"));
+static cl::opt<unsigned> MaxArraySize(
+ "instcombine-maxarray-size", cl::init(1024),
+ cl::desc("Maximum array size considered when doing a combine"));
namespace llvm {
extern cl::opt<bool> ProfcheckDisableMetadataFixes;
@@ -504,8 +504,8 @@ bool InstCombinerImpl::SimplifyAssociativeOrCommutative(BinaryOperator &I) {
// Order operands such that they are listed from right (least complex) to
// left (most complex). This puts constants before unary operators before
// binary operators.
- if (I.isCommutative() && getComplexity(I.getOperand(0)) <
- getComplexity(I.getOperand(1)))
+ if (I.isCommutative() &&
+ getComplexity(I.getOperand(0)) < getComplexity(I.getOperand(1)))
Changed = !I.swapOperands();
if (I.isCommutative()) {
@@ -625,23 +625,21 @@ bool InstCombinerImpl::SimplifyAssociativeOrCommutative(BinaryOperator &I) {
// if C1 and C2 are constants.
Value *A, *B;
Constant *C1, *C2, *CRes;
- if (Op0 && Op1 &&
- Op0->getOpcode() == Opcode && Op1->getOpcode() == Opcode &&
+ if (Op0 && Op1 && Op0->getOpcode() == Opcode &&
+ Op1->getOpcode() == Opcode &&
match(Op0, m_OneUse(m_BinOp(m_Value(A), m_Constant(C1)))) &&
match(Op1, m_OneUse(m_BinOp(m_Value(B), m_Constant(C2)))) &&
(CRes = ConstantFoldBinaryOpOperands(Opcode, C1, C2, DL))) {
- bool IsNUW = hasNoUnsignedWrap(I) &&
- hasNoUnsignedWrap(*Op0) &&
- hasNoUnsignedWrap(*Op1);
- BinaryOperator *NewBO = (IsNUW && Opcode == Instruction::Add) ?
- BinaryOperator::CreateNUW(Opcode, A, B) :
- BinaryOperator::Create(Opcode, A, B);
-
- if (isa<FPMathOperator>(NewBO)) {
- FastMathFlags Flags = I.getFastMathFlags() &
- Op0->getFastMathFlags() &
- Op1->getFastMathFlags();
- NewBO->setFastMathFlags(Flags);
+ bool IsNUW = hasNoUnsignedWrap(I) && hasNoUnsignedWrap(*Op0) &&
+ hasNoUnsignedWrap(*Op1);
+ BinaryOperator *NewBO = (IsNUW && Opcode == Instruction::Add)
+ ? BinaryOperator::CreateNUW(Opcode, A, B)
+ : BinaryOperator::Create(Opcode, A, B);
+
+ if (isa<FPMathOperator>(NewBO)) {
+ FastMathFlags Flags = I.getFastMathFlags() & Op0->getFastMathFlags() &
+ Op1->getFastMathFlags();
+ NewBO->setFastMathFlags(Flags);
}
InsertNewInstWith(NewBO, I.getIterator());
NewBO->takeName(Op1);
@@ -1833,6 +1831,44 @@ 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;
+ }
+ // Neither operand is a min/max intrinsic
+ if (!MinMax)
+ return nullptr;
+
+ Value *X = MinMax->getLHS();
+ Value *Y = MinMax->getRHS();
+
+ // Attempt to fold OtherOp +/- X and OtherOp +/- Y
+ Value *NewX =
+ simplifyBinOp(I.getOpcode(), OtherOp, X, SQ.getWithInstruction(&I));
+ Value *NewY =
+ simplifyBinOp(I.getOpcode(), OtherOp, Y, SQ.getWithInstruction(&I));
+ if (!NewX && !NewY)
+ return nullptr;
+
+ if (!NewX) {
+ NewX = InsertNewInstBefore(
+ BinaryOperator::Create(I.getOpcode(), X, OtherOp), I.getIterator());
+ }
+ if (!NewY) {
+ NewY = InsertNewInstBefore(
+ BinaryOperator::Create(I.getOpcode(), Y, OtherOp), I.getIterator());
+ }
+
+ Function *F = Intrinsic::getOrInsertDeclaration(
+ I.getModule(), MinMax->getIntrinsicID(), {I.getType()});
+ return CallInst::Create(F, {NewX, NewY});
+}
+
static Value *simplifyInstructionWithPHI(Instruction &I, PHINode *PN,
Value *InValue, BasicBlock *InBB,
const DataLayout &DL,
@@ -2278,8 +2314,7 @@ static bool shouldMergeGEPs(GEPOperator &GEP, GEPOperator &Src) {
// If this GEP has only 0 indices, it is the same pointer as
// Src. If Src is not a trivial GEP too, don't combine
// the indices.
- if (GEP.hasAllZeroIndices() && !Src.hasAllZeroIndices() &&
- !Src.hasOneUse())
+ if (GEP.hasAllZeroIndices() && !Src.hasAllZeroIndices() && !Src.hasOneUse())
return false;
return true;
}
@@ -3083,7 +3118,7 @@ static Instruction *foldGEPOfPhi(GetElementPtrInst &GEP, PHINode *PN,
int DI = -1;
- for (auto I = PN->op_begin()+1, E = PN->op_end(); I !=E; ++I) {
+ for (auto I = PN->op_begin() + 1, E = PN->op_end(); I != E; ++I) {
auto *Op2 = dyn_cast<GetElementPtrInst>(*I);
if (!Op2 || Op1->getNumOperands() != Op2->getNumOperands() ||
Op1->getSourceElementType() != Op2->getSourceElementType())
@@ -3131,8 +3166,7 @@ static Instruction *foldGEPOfPhi(GetElementPtrInst &GEP, PHINode *PN,
if (J == 1) {
CurTy = Op1->getSourceElementType();
} else {
- CurTy =
- GetElementPtrInst::getTypeAtIndex(CurTy, Op1->getOperand(J));
+ CurTy = GetElementPtrInst::getTypeAtIndex(CurTy, Op1->getOperand(J));
}
}
}
@@ -3171,7 +3205,8 @@ static Instruction *foldGEPOfPhi(GetElementPtrInst &GEP, PHINode *PN,
NewGEP->setOperand(DI, NewPN);
}
- NewGEP->insertBefore(*GEP.getParent(), GEP.getParent()->getFirstInsertionPt());
+ NewGEP->insertBefore(*GEP.getParent(),
+ GEP.getParent()->getFirstInsertionPt());
return NewGEP;
}
@@ -3192,8 +3227,8 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
auto VWidth = GEPFVTy->getNumElements();
APInt PoisonElts(VWidth, 0);
APInt AllOnesEltMask(APInt::getAllOnes(VWidth));
- if (Value *V = SimplifyDemandedVectorElts(&GEP, AllOnesEltMask,
- PoisonElts)) {
+ if (Value *V =
+ SimplifyDemandedVectorElts(&GEP, AllOnesEltMask, PoisonElts)) {
if (V != &GEP)
return replaceInstUsesWith(GEP, V);
return &GEP;
@@ -3562,7 +3597,7 @@ static bool isRemovableWrite(CallBase &CB, Value *UsedV,
static std::optional<ModRefInfo>
isAllocSiteRemovable(Instruction *AI, SmallVectorImpl<WeakTrackingVH> &Users,
const TargetLibraryInfo &TLI, bool KnowInit) {
- SmallVector<Instruction*, 4> Worklist;
+ SmallVector<Instruction *, 4> Worklist;
const std::optional<StringRef> Family = getAllocationFamily(AI, &TLI);
Worklist.push_back(AI);
ModRefInfo Access = KnowInit ? ModRefInfo::NoModRef : ModRefInfo::Mod;
@@ -4308,9 +4343,11 @@ Instruction *InstCombinerImpl::visitSwitchInst(SwitchInst &SI) {
uint64_t ShiftAmt;
if (match(Cond, m_Shl(m_Value(Op0), m_ConstantInt(ShiftAmt))) &&
ShiftAmt < Op0->getType()->getScalarSizeInBits() &&
- all_of(SI.cases(), [&](const auto &Case) {
- return Case.getCaseValue()->getValue().countr_zero() >= ShiftAmt;
- })) {
+ all_of(
+ SI.cases(),
+ [&](const auto &Case) {
+ return Case.getCaseValue()->getValue().countr_zero() >= ShiftAmt;
+ })) {
// Change 'switch (X << 2) case 4:' into 'switch (X) case 1:'.
OverflowingBinaryOperator *Shl = cast<OverflowingBinaryOperator>(Cond);
if (Shl->hasNoUnsignedWrap() || Shl->hasNoSignedWrap() ||
@@ -4374,7 +4411,8 @@ Instruction *InstCombinerImpl::visitSwitchInst(SwitchInst &SI) {
std::min(LeadingKnownOnes, C.getCaseValue()->getValue().countl_one());
}
- unsigned NewWidth = Known.getBitWidth() - std::max(LeadingKnownZeros, LeadingKnownOnes);
+ unsigned NewWidth =
+ Known.getBitWidth() - std::max(LeadingKnownZeros, LeadingKnownOnes);
// Shrink the condition operand if the new type is smaller than the old type.
// But do not shrink to a non-standard type, because backend can't generate
@@ -4557,10 +4595,9 @@ Instruction *InstCombinerImpl::visitExtractValueInst(ExtractValueInst &EV) {
if (InsertValueInst *IV = dyn_cast<InsertValueInst>(Agg)) {
// We're extracting from an insertvalue instruction, compare the indices
const unsigned *exti, *exte, *insi, *inse;
- for (exti = EV.idx_begin(), insi = IV->idx_begin(),
- exte = EV.idx_end(), inse = IV->idx_end();
- exti != exte && insi != inse;
- ++exti, ++insi) {
+ for (exti = EV.idx_begin(), insi = IV->idx_begin(), exte = EV.idx_end(),
+ inse = IV->idx_end();
+ exti != exte && insi != inse; ++exti, ++insi) {
if (*insi != *exti)
// The insert and extract both reference distinctly different elements.
// This means the extract is not influenced by the insert, and we can
@@ -4622,7 +4659,7 @@ Instruction *InstCombinerImpl::visitExtractValueInst(ExtractValueInst &EV) {
// don't want to do the transformation as it loses padding knowledge.
if (L->isSimple() && L->hasOneUse()) {
// extractvalue has integer indices, getelementptr has Value*s. Convert.
- SmallVector<Value*, 4> Indices;
+ SmallVector<Value *, 4> Indices;
// Prefix an i32 0 since we need the first element.
Indices.push_back(Builder.getInt32(0));
for (unsigned Idx : EV.indices())
@@ -4695,10 +4732,8 @@ static bool isCatchAll(EHPersonality Personality, Constant *TypeInfo) {
}
static bool shorter_filter(const Value *LHS, const Value *RHS) {
- return
- cast<ArrayType>(LHS->getType())->getNumElements()
- <
- cast<ArrayType>(RHS->getType())->getNumElements();
+ return cast<ArrayType>(LHS->getType())->getNumElements() <
+ cast<ArrayType>(RHS->getType())->getNumElements();
}
Instruction *InstCombinerImpl::visitLandingPadInst(LandingPadInst &LI) {
@@ -4712,7 +4747,7 @@ Instruction *InstCombinerImpl::visitLandingPadInst(LandingPadInst &LI) {
// (these are often created by inlining).
bool MakeNewInstruction = false; // If true, recreate using the following:
SmallVector<Constant *, 16> NewClauses; // - Clauses for the new instruction;
- bool CleanupFlag = LI.isCleanup(); // - The new instruction is a cleanup.
+ bool CleanupFlag = LI.isCleanup(); // - The new instruction is a cleanup.
SmallPtrSet<Value *, 16> AlreadyCaught; // Typeinfos known caught already.
for (unsigned i = 0, e = LI.getNumClauses(); i != e; ++i) {
@@ -4764,13 +4799,13 @@ Instruction *InstCombinerImpl::visitLandingPadInst(LandingPadInst &LI) {
break;
}
- bool MakeNewFilter = false; // If true, make a new filter.
+ bool MakeNewFilter = false; // If true, make a new filter.
SmallVector<Constant *, 16> NewFilterElts; // New elements.
if (isa<ConstantAggregateZero>(FilterClause)) {
// Not an empty filter - it contains at least one null typeinfo.
assert(NumTypeInfos > 0 && "Should have handled empty filter already!");
Constant *TypeInfo =
- Constant::getNullValue(FilterType->getElementType());
+ Constant::getNullValue(FilterType->getElementType());
// If this typeinfo is a catch-all then the filter can never match.
if (isCatchAll(Personality, TypeInfo)) {
// Throw the filter away.
@@ -4835,8 +4870,8 @@ Instruction *InstCombinerImpl::visitLandingPadInst(LandingPadInst &LI) {
MakeNewFilter = true;
}
if (MakeNewFilter) {
- FilterType = ArrayType::get(FilterType->getElementType(),
- NewFilterElts.size());
+ FilterType =
+ ArrayType::get(FilterType->getElementType(), NewFilterElts.size());
FilterClause = ConstantArray::get(FilterType, NewFilterElts);
MakeNewInstruction = true;
}
@@ -4860,7 +4895,7 @@ Instruction *InstCombinerImpl::visitLandingPadInst(LandingPadInst &LI) {
// advantageous because shorter filters are more likely to match, speeding up
// unwinding, but mostly because it increases the effectiveness of the other
// filter optimizations below.
- for (unsigned i = 0, e = NewClauses.size(); i + 1 < e; ) {
+ for (unsigned i = 0, e = NewClauses.size(); i + 1 < e;) {
unsigned j;
// Find the maximal 'j' s.t. the range [i, j) consists entirely of filters.
for (j = i; j != e; ++j)
@@ -4871,7 +4906,7 @@ Instruction *InstCombinerImpl::visitLandingPadInst(LandingPadInst &LI) {
// if sorting them is actually going to do anything so that we only make a
// new landingpad instruction if it does.
for (unsigned k = i; k + 1 < j; ++k)
- if (shorter_filter(NewClauses[k+1], NewClauses[k])) {
+ if (shorter_filter(NewClauses[k + 1], NewClauses[k])) {
// Not sorted, so sort the filters now. Doing an unstable sort would be
// correct too but reordering filters pointlessly might confuse users.
std::stable_sort(NewClauses.begin() + i, NewClauses.begin() + j,
@@ -4986,8 +5021,8 @@ Instruction *InstCombinerImpl::visitLandingPadInst(LandingPadInst &LI) {
// If we changed any of the clauses, replace the old landingpad instruction
// with a new one.
if (MakeNewInstruction) {
- LandingPadInst *NLI = LandingPadInst::Create(LI.getType(),
- NewClauses.size());
+ LandingPadInst *NLI =
+ LandingPadInst::Create(LI.getType(), NewClauses.size());
for (Constant *C : NewClauses)
NLI->addClause(C);
// A landing pad with no clauses must have the cleanup flag set. It is
@@ -5138,8 +5173,8 @@ Instruction *InstCombinerImpl::foldFreezeIntoRecurrence(FreezeInst &FI,
if (StartNeedsFreeze) {
Builder.SetInsertPoint(StartBB->getTerminator());
- Value *FrozenStartV = Builder.CreateFreeze(StartV,
- StartV->getName() + ".fr");
+ Value *FrozenStartV =
+ Builder.CreateFreeze(StartV, StartV->getName() + ".fr");
replaceUse(*StartU, FrozenStartV);
}
return replaceInstUsesWith(FI, PN);
@@ -5598,7 +5633,8 @@ bool InstCombinerImpl::run() {
}
Instruction *I = Worklist.removeOne();
- if (I == nullptr) continue; // skip null values.
+ if (I == nullptr)
+ continue; // skip null values.
// Check to see if we can DCE the instruction.
if (isInstructionTriviallyDead(I, &TLI)) {
@@ -6072,8 +6108,9 @@ PreservedAnalyses InstCombinePass::run(Function &F,
auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
ProfileSummaryInfo *PSI =
MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent());
- auto *BFI = (PSI && PSI->hasProfileSummary()) ?
- &AM.getResult<BlockFrequencyAnalysis>(F) : nullptr;
+ auto *BFI = (PSI && PSI->hasProfileSummary())
+ ? &AM.getResult<BlockFrequencyAnalysis>(F)
+ : nullptr;
auto *BPI = AM.getCachedResult<BranchProbabilityAnalysis>(F);
if (!combineInstructionsOverFunction(F, Worklist, AA, AC, TLI, TTI, DT, ORE,
@@ -6123,9 +6160,9 @@ bool InstructionCombiningPass::runOnFunction(Function &F) {
ProfileSummaryInfo *PSI =
&getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
BlockFrequencyInfo *BFI =
- (PSI && PSI->hasProfileSummary()) ?
- &getAnalysis<LazyBlockFrequencyInfoPass>().getBFI() :
- nullptr;
+ (PSI && PSI->hasProfileSummary())
+ ? &getAnalysis<LazyBlockFrequencyInfoPass>().getBFI()
+ : nullptr;
BranchProbabilityInfo *BPI = nullptr;
if (auto *WrapperPass =
getAnalysisIfAvailable<BranchProbabilityInfoWrapperPass>())
diff --git a/llvm/test/Transforms/InstCombine/add-min-max.ll b/llvm/test/Transforms/InstCombine/add-min-max.ll
index 2117a55e2a490..b2bdb9331593b 100644
--- a/llvm/test/Transforms/InstCombine/add-min-max.ll
+++ b/llvm/test/Transforms/InstCombine/add-min-max.ll
@@ -83,3 +83,33 @@ 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 [[X:%.*]], i32 0)
+; 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
+}
+
+define i32 @sadd_min_neg_2(i32 %x, i32 %a) {
+; CHECK-LABEL: @sadd_min_neg_2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[A:%.*]], 128
+; CHECK-NEXT: [[RES:%.*]] = call i32 @llvm.smin.i32(i32 [[X:%.*]], i32 [[TMP0]])
+; CHECK-NEXT: ret i32 [[RES]]
+;
+entry:
+ %other = add i32 0, 128
+ %x_minus_a = sub nsw i32 %x, %a
+ %smin = call i32 @llvm.smin.i32(i32 %other, i32 %x_minus_a)
+ %res = add nsw i32 %smin, %a
+ ret i32 %res
+}
More information about the llvm-commits
mailing list