[llvm] [InstCombine] Extend canonicalization of addition to positive numbers (PR #179343)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 3 06:23:41 PST 2026


================
@@ -1147,51 +1147,84 @@ static Value *canonicalizeSaturatedAddSigned(ICmpInst *Cmp, Value *TVal,
   Value *Cmp0 = Cmp->getOperand(0);
   Value *Cmp1 = Cmp->getOperand(1);
   ICmpInst::Predicate Pred = Cmp->getPredicate();
-  Value *X;
-  const APInt *C;
 
-  // Canonicalize INT_MAX to true value of the select.
-  if (match(FVal, m_MaxSignedValue())) {
+  // Canonicalize TVal to be the saturation constant.
+  if (match(FVal, m_MaxSignedValue()) || match(FVal, m_SignMask())) {
     std::swap(TVal, FVal);
     Pred = CmpInst::getInversePredicate(Pred);
   }
 
-  if (!match(TVal, m_MaxSignedValue()))
+  const APInt *SatC;
+  if (!match(TVal, m_APInt(SatC)) ||
+      !(SatC->isMaxSignedValue() || SatC->isSignMask()))
     return nullptr;
 
+  bool IsMax = SatC->isMaxSignedValue();
+
   // sge maximum signed value is canonicalized to eq maximum 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) {
+  // requires special handling. sle minimum signed value is similarly
+  // canonicalized to eq minimum signed value.
+  if (Pred == ICmpInst::ICMP_EQ && Cmp1 == TVal) {
+    // (a == INT_MAX) ? INT_MAX : a + 1 -> sadd.sat(a, 1)
+    if (IsMax && match(FVal, m_Add(m_Specific(Cmp0), m_One()))) {
       return Builder.CreateBinaryIntrinsic(
           Intrinsic::sadd_sat, Cmp0, ConstantInt::get(Cmp0->getType(), 1));
     }
+
+    // (a == INT_MIN) ? INT_MIN : a + -1 -> sadd.sat(a, -1)
+    if (!IsMax && match(FVal, m_Add(m_Specific(Cmp0), m_AllOnes()))) {
+      return Builder.CreateBinaryIntrinsic(
+          Intrinsic::sadd_sat, Cmp0,
+          ConstantInt::get(Cmp0->getType(), -1, /*IsSigned=*/true));
+    }
     return nullptr;
   }
 
+  const APInt *C;
+
   // (X > Y) ? INT_MAX : (X + C) --> sadd.sat(X, C)
   // (X >= Y) ? INT_MAX : (X + C) --> sadd.sat(X, C)
-  // where Y is INT_MAX - C or INT_MAX - C - 1, and C > 0
-  if ((Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SGE) &&
+  // where C > 0
+  if (IsMax && (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SGE) &&
       isa<Constant>(Cmp1) &&
       match(FVal, m_Add(m_Specific(Cmp0), m_StrictlyPositive(C)))) {
-    APInt IntMax =
-        APInt::getSignedMaxValue(Cmp1->getType()->getScalarSizeInBits());
-
-    // For SGE, try to flip to SGT to normalize the comparison constant.
+    // Normalize SGE to SGT for threshold comparison.
     if (Pred == ICmpInst::ICMP_SGE) {
       if (auto Flipped = getFlippedStrictnessPredicateAndConstant(
               Pred, cast<Constant>(Cmp1))) {
         Pred = Flipped->first;
         Cmp1 = Flipped->second;
       }
     }
-
-    // Check the pattern: X > INT_MAX - C or X > INT_MAX - C - 1
+    // Check: X > INT_MAX - C or X > INT_MAX - C - 1
+    APInt Threshold = *SatC - *C;
     if (Pred == ICmpInst::ICMP_SGT &&
-        (match(Cmp1, m_SpecificIntAllowPoison(IntMax - *C)) ||
-         match(Cmp1, m_SpecificIntAllowPoison(IntMax - *C - 1))))
+        (match(Cmp1, m_SpecificIntAllowPoison(Threshold)) ||
+         match(Cmp1, m_SpecificIntAllowPoison(Threshold - 1))))
+      return Builder.CreateBinaryIntrinsic(
+          Intrinsic::sadd_sat, Cmp0, ConstantInt::get(Cmp0->getType(), *C));
+  }
+
+  // (X < Y) ? INT_MIN : (X + C) --> sadd.sat(X, C)
+  // (X <= Y) ? INT_MIN : (X + C) --> sadd.sat(X, C)
+  // where C < 0
----------------
dtcxzyw wrote:

Missing definition for Y.

https://github.com/llvm/llvm-project/pull/179343


More information about the llvm-commits mailing list