[llvm] [InstCombine] Canonicalize signed saturated additions (PR #153053)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Sun Nov 9 02:22:03 PST 2025
================
@@ -1115,6 +1113,107 @@ static Value *canonicalizeSaturatedAdd(ICmpInst *Cmp, Value *TVal, Value *FVal,
return nullptr;
}
+static Value *canonicalizeSaturatedAddSigned(ICmpInst *Cmp, Value *TVal,
+ Value *FVal,
+ InstCombiner::BuilderTy &Builder) {
+ // Match saturated add with constant.
+ Value *Cmp0 = Cmp->getOperand(0);
+ Value *Cmp1 = Cmp->getOperand(1);
+ ICmpInst::Predicate Pred = Cmp->getPredicate();
+ Value *X, *Y;
+ const APInt *C;
+
+ // Canonicalize INT_MAX to true value of the select.
+ if (match(FVal, m_MaxSignedValue())) {
+ std::swap(TVal, FVal);
+ Pred = CmpInst::getInversePredicate(Pred);
+ }
+ if (!match(TVal, m_MaxSignedValue()))
+ return nullptr;
+
+ // sge maximum signed value is canonicalized to eq minimum signed value and
+ // requires special handling (a == INT_MAX) ? INT_MAX : a + 1 -> sadd.sat(a,
+ // 1)
+ if (Pred == ICmpInst::ICMP_EQ) {
+ if (match(FVal, m_Add(m_Specific(Cmp0), m_One())) && Cmp1 == TVal) {
+ return Builder.CreateBinaryIntrinsic(
+ Intrinsic::sadd_sat, Cmp0, ConstantInt::get(Cmp0->getType(), 1));
+ }
+ return nullptr;
+ }
+
+ if ((Pred == ICmpInst::ICMP_SGE || Pred == ICmpInst::ICMP_SGT) &&
+ match(FVal, m_Add(m_Specific(Cmp0), m_APIntAllowPoison(C))) &&
+ match(Cmp1, m_SpecificIntAllowPoison(
+ APInt::getSignedMaxValue(
+ Cmp1->getType()->getScalarSizeInBits()) -
+ *C)) &&
+ !C->isNegative()) {
+ // (X > INT_MAX - C) ? INT_MAX : (X + C) --> sadd.sat(X, C)
+ // (X >= INT_MAX - C) ? INT_MAX : (X + C) --> sadd.sat(X, C)
+ return Builder.CreateBinaryIntrinsic(Intrinsic::sadd_sat, Cmp0,
+ ConstantInt::get(Cmp0->getType(), *C));
+ }
+
+ if (Pred == ICmpInst::ICMP_SGT &&
+ match(FVal, m_Add(m_Specific(Cmp0), m_APIntAllowPoison(C))) &&
+ match(Cmp1, m_SpecificIntAllowPoison(
+ APInt::getSignedMaxValue(
+ Cmp1->getType()->getScalarSizeInBits()) -
+ *C - 1)) &&
+ !C->isNegative()) {
+ // (X > INT_MAX - C - 1) ? INT_MAX : (X + C) --> sadd.sat(X, C)
+ return Builder.CreateBinaryIntrinsic(Intrinsic::sadd_sat, Cmp0,
+ ConstantInt::get(Cmp0->getType(), *C));
+ }
+
+ // This does not work with 0, or negative numbers as
+ // (X >= INT_MIN + 0 + 1) ? INT_MAX : (X + 0) is not a saturated add.
+ if (Pred == ICmpInst::ICMP_SGE &&
+ match(FVal, m_Add(m_Specific(Cmp0), m_APIntAllowPoison(C))) &&
+ match(Cmp1, m_SpecificIntAllowPoison(
+ APInt::getSignedMinValue(
+ Cmp1->getType()->getScalarSizeInBits()) -
+ *C + 1)) &&
+ C->isStrictlyPositive()) {
+ // (X >= INT_MAX - C + 1) ? INT_MAX : (X + C) --> sadd.sat(X, C)
+ return Builder.CreateBinaryIntrinsic(Intrinsic::sadd_sat, Cmp0,
+ ConstantInt::get(Cmp0->getType(), *C));
+ }
+
+ // Canonicalize predicate to less-than or less-or-equal-than.
+ if (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SGE) {
+ std::swap(Cmp0, Cmp1);
+ Pred = CmpInst::getSwappedPredicate(Pred);
+ }
+
+ if (Pred != ICmpInst::ICMP_SLT && Pred != ICmpInst::ICMP_SLE)
+ return nullptr;
+
+ if (match(Cmp0, m_NSWSub(m_MaxSignedValue(), m_Value(X))) &&
+ match(FVal, m_c_Add(m_Specific(X), m_Value(Y))) && Y == Cmp1) {
----------------
dtcxzyw wrote:
```suggestion
match(FVal, m_c_Add(m_Specific(X), m_Specific(Cmp1)))) {
```
https://github.com/llvm/llvm-project/pull/153053
More information about the llvm-commits
mailing list