[llvm] [InstCombine] Div ceil optimizations (PR #190175)
Takashi Idobe via llvm-commits
llvm-commits at lists.llvm.org
Sun Apr 5 17:01:35 PDT 2026
================
@@ -1523,6 +1523,68 @@ static Instruction *foldBoxMultiply(BinaryOperator &I) {
return nullptr;
}
+// Return true if X + (Y-1) is provably non-wrapping in X's type
+static bool checkDivCeilNUW(Value *X, Value *Y, BinaryOperator &I,
+ AssumptionCache &AC, DominatorTree &DT) {
+ ConstantRange CRX = computeConstantRange(X, /*ForSigned=*/false,
+ /*UseInstrInfo=*/true, &AC, &I, &DT);
+ ConstantRange CRY = computeConstantRange(Y, /*ForSigned=*/false,
+ /*UseInstrInfo=*/true, &AC, &I, &DT);
+ APInt MaxX = CRX.getUnsignedMax();
+ APInt MaxY = CRY.getUnsignedMax();
+ unsigned BitWidth = MaxX.getBitWidth();
+ // MaxX + (MaxY - 1) <= UINT_MAX <==> MaxX <= UINT_MAX - (MaxY - 1)
+ return !MaxX.ugt(APInt::getMaxValue(BitWidth) - (MaxY - 1));
+}
+
+// Fold the same-type form of the div_ceil idiom:
+// add(udiv(X, Y), zext(icmp ne(urem(X, Y), 0)))
+// -> udiv(add nuw(X, Y - 1), Y)
+// where udiv and urem are the same type as the add.
+Instruction *InstCombinerImpl::foldSameTypeDivCeil(BinaryOperator &I) {
+ Value *X, *X2, *Y, *Y2;
+ CmpPredicate Pred;
+
+ auto UDivPat = m_OneUse(m_UDiv(m_Value(X), m_Value(Y)));
+ auto URemPat = m_OneUse(m_URem(m_Value(X2), m_Value(Y2)));
+ auto ICmpPat = m_OneUse(m_ICmp(Pred, URemPat, m_Zero()));
+ auto ZExtCmpPat = m_OneUse(m_ZExt(ICmpPat));
+
+ if (!match(&I, m_c_Add(UDivPat, ZExtCmpPat)) || Pred != ICmpInst::ICMP_NE ||
+ X != X2 || Y != Y2 || !checkDivCeilNUW(X, Y, I, AC, DT))
+ return nullptr;
+
+ Value *YMinusOne = Builder.CreateSub(Y, ConstantInt::get(Y->getType(), 1));
+ Value *NUWAdd = Builder.CreateAdd(X, YMinusOne, "", /*HasNUW=*/true);
+ return BinaryOperator::CreateUDiv(NUWAdd, Y);
+}
+
+// Fold the zext form of the div_ceil idiom:
+// add(zext(udiv(X, Y)), zext(icmp ne(urem(X, Y), 0)))
----------------
Takashiidobe wrote:
I went ahead and tried the add(zext(X), zext(Y)) -> zext(add nuw(A, B)) and tried to delete the zext form of this fold. Even adding udiv range tracking to computeConstantRange, this still doesn't work, because the udiv for this fold has 2 users, the add + not erased zext, so m_OneUse is not true for this match. Is there a way to say at most one non-dead use?
https://github.com/llvm/llvm-project/pull/190175
More information about the llvm-commits
mailing list