[llvm] [InstCombine] Fold umul.overflow(x, c1) | (x*c1 > c2) to x > c2/c1 (PR #147327)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 8 00:52:31 PDT 2025
================
@@ -3659,6 +3659,37 @@ static std::optional<DecomposedBitMaskMul> matchBitmaskMul(Value *V) {
return std::nullopt;
}
+/// Fold Res, Overflow = (umul.with.overflow x c1); (or Overflow (ugt Res c2))
+/// --> (ugt x (c2/c1)). This code checks whether a multiplication of two
+/// unsigned numbers (one is a constant) is mathematically greater than a
+/// second constant.
+static Value *foldOrUnsignedUMulOverflowICmp(BinaryOperator &I,
+ InstCombiner::BuilderTy &Builder,
+ const DataLayout &DL) {
+ const WithOverflowInst *WO;
+ const Value *WOV;
+ Constant *C1, *C2;
+ if (match(&I, m_c_Or(m_OneUse(m_ExtractValue<1>(
+ m_CombineAnd(m_WithOverflowInst(WO), m_Value(WOV)))),
+ m_OneUse(m_SpecificCmp(
+ ICmpInst::ICMP_UGT,
+ m_OneUse(m_ExtractValue<0>(m_Deferred(WOV))),
+ m_ImmConstant(C2))))) &&
+ WO->getIntrinsicID() == Intrinsic::umul_with_overflow &&
+ match(WO->getRHS(), m_ImmConstant(C1)) && WO->hasNUses(2)) {
+ Type *Ty = C1->getType();
+ // If C1 is 0 (which may occur in non-splat vectors), we use -1 as the new
+ // constant instead.
+ Constant *NewC = ConstantFoldSelectInstruction(
+ ConstantFoldCompareInstOperands(ICmpInst::ICMP_EQ, C1,
+ ConstantInt::getNullValue(Ty), DL),
+ ConstantInt::getAllOnesValue(Ty),
+ ConstantFoldBinaryOpOperands(Instruction::UDiv, C2, C1, DL));
----------------
nikic wrote:
What you're doing here is on pretty thin ice because division UB is not lane-wise, so if the constant folding implementation were a bit smarter, it would return a poison element for the whole value rather than one lane. I'm also not sure what will happen for an undef lane (depends on the direction the eq is folded).
TBH I don't think this is worthwhile and we should just match m_APInt() to handle the splat case.
https://github.com/llvm/llvm-project/pull/147327
More information about the llvm-commits
mailing list