[llvm] [InstCombine] Fold `X > C2 ? X + C1 : C2 + C1` to `max(X, C2) + C1` (PR #116888)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 22 06:37:21 PST 2024


================
@@ -1898,6 +1898,69 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
   return nullptr;
 }
 
+// Turn select (Cmp X C1) (BOp X C2) C3
+//   -> BOp (min/max X C1) C2
+// iff C3 == BOp C1 C2
+// This allows for better canonicalization.
+static Value *canonicalizeConstToBOp(ICmpInst *Cmp, Value *TrueVal,
+                                     Value *FalseVal,
+                                     InstCombiner::BuilderTy &Builder) {
+  BinaryOperator *BOp;
+  Constant *C1, *C2, *C3;
+  Value *X;
+  ICmpInst::Predicate Predicate;
+
+  if (!match(Cmp, m_ICmp(Predicate, m_Value(X), m_Constant(C1))))
+    return nullptr;
+
+  if (!((match(TrueVal, m_BinOp(BOp)) && match(FalseVal, m_Constant(C3))) ||
+        (match(FalseVal, m_BinOp(BOp)) && match(TrueVal, m_Constant(C3)))))
+    return nullptr;
+
+  if (!match(BOp, m_OneUse(m_c_BinOp(m_Specific(X), m_Constant(C2)))))
+    return nullptr;
+
+  // `select (Cmp X C1) (sub C2 X) (sub C1 C2)` cannot be transformed
+  // into something like `sub (select (Cmp X C1) X C1) C2`
+  if (!BOp->isCommutative() && BOp->getOperand(0) != X)
+    return nullptr;
+
+  if (!(ICmpInst::isRelational(Predicate) &&
+        C3 == ConstantFoldBinaryOpOperands(BOp->getOpcode(), C1, C2,
+                                           BOp->getDataLayout())))
+    return nullptr;
+
+  Value *NewTrueVal = isa<Constant>(TrueVal) ? C1 : X;
+  Value *NewFalseVal = isa<Constant>(FalseVal) ? C1 : X;
+  Value *LHS, *RHS;
+  SelectPatternFlavor SPF =
+      matchDecomposedSelectPattern(Cmp, NewTrueVal, NewFalseVal, LHS, RHS)
+          .Flavor;
+
+  Intrinsic::ID IntrinsicID;
+  switch (SPF) {
+  case SelectPatternFlavor::SPF_UMIN:
+    IntrinsicID = Intrinsic::umin;
+    break;
+  case SelectPatternFlavor::SPF_UMAX:
+    IntrinsicID = Intrinsic::umax;
+    break;
+  case SelectPatternFlavor::SPF_SMIN:
+    IntrinsicID = Intrinsic::smin;
+    break;
+  case SelectPatternFlavor::SPF_SMAX:
+    IntrinsicID = Intrinsic::smax;
+    break;
+  default:
+    llvm_unreachable("Unexpected SPF");
+  }
+  Value *Intrinsic = Builder.CreateBinaryIntrinsic(IntrinsicID, LHS, RHS);
+  BinaryOperator *NewBO = cast<BinaryOperator>(
+      Builder.CreateBinOp(BOp->getOpcode(), Intrinsic, C2));
+  NewBO->copyIRFlags(BOp);
----------------
nikic wrote:

I don't think this is generally correct, because we don't know that the nowrap flags hold for C1 op C2. Consider something like this: https://alive2.llvm.org/ce/z/-d3zme

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


More information about the llvm-commits mailing list