[llvm] [SCEV] Updates for getUDivExactExpr() to improve handling of MulExpr numerators/denominators (PR #195704)

Ryan Buchner via llvm-commits llvm-commits at lists.llvm.org
Mon May 4 22:56:10 PDT 2026


================
@@ -3745,6 +3745,39 @@ const SCEV *ScalarEvolution::getUDivExactExpr(SCEVUse LHS, SCEVUse RHS) {
   // just deal with u/exact (multiply, constant). See SCEVDivision towards the
   // end of this file for inspiration.
 
+  if (LHS == RHS)
+    return getConstant(LHS->getType(), 1);
+
+  if (const SCEVMulExpr *RHSMul = dyn_cast<SCEVMulExpr>(RHS);
+      RHSMul && RHSMul->hasNoUnsignedWrap() &&
+      isa<SCEVMulExpr, SCEVConstant, SCEVUnknown>(LHS)) {
+    const SCEV *CurrSCEV = LHS;
+    SmallVector<SCEVUse, 2> Operands;
+    bool OnlyNonZero = true;
+    for (SCEVUse Op : RHSMul->operands()) {
+      if (!OnlyNonZero) {
+        Operands.push_back(Op);
+        continue;
+      }
+      const SCEV *NewSCEV = getUDivExactExpr(CurrSCEV, Op);
+      if (isa<SCEVUDivExpr>(NewSCEV)) {
+        Operands.push_back(Op);
+        continue;
+      }
+      if (!isa<SCEVConstant>(Op)) // Constant is guaranteed non-zero is MulExpr
+        OnlyNonZero = false;
----------------
bababuck wrote:

I was also unable to find any documentation either. I guess the only way that we could know that `X * Y * Z` was `NUW` and not know if `X * Y` is `NUW` is i we knew that `Z` is zero, in which case we would have already replacez `Z` with zero. I will remove this logic.

The reason for `!OnlyNonZero` initially was that in the case of `X * Y u/ X * Y * Z` (where both multiplications are `NUW`, after the first iteration, the remaining values would be `Y u/ Y * Z` (where the multiplication is not `NUW`), and we could no longer simplify.

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


More information about the llvm-commits mailing list