[llvm] [CVP] Generalize udiv/urem expansion for small quotients (MaxQ == 2) (PR #209321)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 18 08:53:21 PDT 2026


https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/209321

>From f857a0c8088b09b82a6e7262591a742c95337546 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Mon, 13 Jul 2026 18:11:35 -0400
Subject: [PATCH 1/2] Pre-commit tests (NFC)

---
 .../udiv-expansion.ll                         | 90 +++++++++++++++++++
 .../urem-expansion.ll                         | 90 +++++++++++++++++++
 2 files changed, 180 insertions(+)

diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll b/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll
index 8e568c671f94d..75f34a504f95c 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll
@@ -382,3 +382,93 @@ define i8 @known_uge(i8 noundef %x) {
   %div = udiv i8 %x, 3
   ret i8 %div
 }
+
+; MaxQ == 2: boundary tests
+
+define i8 @constant.divisor.v8(i8 %x) {
+; CHECK-LABEL: @constant.divisor.v8(
+; CHECK-NEXT:    [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 8
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_UPPER]])
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[X]], 3
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %cmp.x.upper = icmp ult i8 %x, 8
+  call void @llvm.assume(i1 %cmp.x.upper)
+  %div = udiv i8 %x, 3
+  ret i8 %div
+}
+
+define i8 @constant.divisor.v9(i8 %x) {
+; CHECK-LABEL: @constant.divisor.v9(
+; CHECK-NEXT:    [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 9
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_UPPER]])
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[X]], 3
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %cmp.x.upper = icmp ult i8 %x, 9
+  call void @llvm.assume(i1 %cmp.x.upper)
+  %div = udiv i8 %x, 3
+  ret i8 %div
+}
+
+; MaxQ == 3: should NOT expand
+define i8 @constant.divisor.v10(i8 %x) {
+; CHECK-LABEL: @constant.divisor.v10(
+; CHECK-NEXT:    [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 10
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_UPPER]])
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[X]], 3
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %cmp.x.upper = icmp ult i8 %x, 10
+  call void @llvm.assume(i1 %cmp.x.upper)
+  %div = udiv i8 %x, 3
+  ret i8 %div
+}
+
+; MaxQ == 2: variable divisor, wider range
+define i8 @variable.v8(i8 %x, i8 %y) {
+; CHECK-LABEL: @variable.v8(
+; CHECK-NEXT:    [[CMP_X:%.*]] = icmp ult i8 [[X:%.*]], 8
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X]])
+; CHECK-NEXT:    [[CMP_Y_LOWER:%.*]] = icmp samesign uge i8 [[Y:%.*]], 3
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_Y_LOWER]])
+; CHECK-NEXT:    [[CMP_Y_UPPER:%.*]] = icmp ule i8 [[Y]], 4
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_Y_UPPER]])
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[X]], [[Y]]
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %cmp.x = icmp ult i8 %x, 8
+  call void @llvm.assume(i1 %cmp.x)
+  %cmp.y.lower = icmp uge i8 %y, 3
+  call void @llvm.assume(i1 %cmp.y.lower)
+  %cmp.y.upper = icmp ule i8 %y, 4
+  call void @llvm.assume(i1 %cmp.y.upper)
+  %div = udiv i8 %x, %y
+  ret i8 %div
+}
+
+; MaxQ == 2: INT_MAX divisor (full i32 range, MaxQ == 2)
+define i32 @large.constant.divisor.intmax(i32 %x) {
+; CHECK-LABEL: @large.constant.divisor.intmax(
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 [[X:%.*]], 2147483647
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %div = udiv i32 %x, 2147483647
+  ret i32 %div
+}
+
+define i8 @test_maxq_0(i8 %x, i8 %y) {
+; CHECK-LABEL: @test_maxq_0(
+; CHECK-NEXT:    [[C1:%.*]] = icmp ult i8 [[X:%.*]], 10
+; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
+; CHECK-NEXT:    [[C2:%.*]] = icmp uge i8 [[Y:%.*]], 20
+; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
+; CHECK-NEXT:    ret i8 0
+;
+  %c1 = icmp ult i8 %x, 10
+  call void @llvm.assume(i1 %c1)
+  %c2 = icmp uge i8 %y, 20
+  call void @llvm.assume(i1 %c2)
+  %r = udiv i8 %x, %y
+  ret i8 %r
+}
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll b/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll
index c6e4265f855e0..48b3aa79f5564 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll
@@ -456,3 +456,93 @@ define i8 @known_uge(i8 noundef %x) {
   %rem = urem i8 %x, 3
   ret i8 %rem
 }
+
+; MaxQ == 2: boundary tests
+
+define i8 @constant.divisor.v8(i8 %x) {
+; CHECK-LABEL: @constant.divisor.v8(
+; CHECK-NEXT:    [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 8
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_UPPER]])
+; CHECK-NEXT:    [[REM:%.*]] = urem i8 [[X]], 3
+; CHECK-NEXT:    ret i8 [[REM]]
+;
+  %cmp.x.upper = icmp ult i8 %x, 8
+  call void @llvm.assume(i1 %cmp.x.upper)
+  %rem = urem i8 %x, 3
+  ret i8 %rem
+}
+
+define i8 @constant.divisor.v9(i8 %x) {
+; CHECK-LABEL: @constant.divisor.v9(
+; CHECK-NEXT:    [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 9
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_UPPER]])
+; CHECK-NEXT:    [[REM:%.*]] = urem i8 [[X]], 3
+; CHECK-NEXT:    ret i8 [[REM]]
+;
+  %cmp.x.upper = icmp ult i8 %x, 9
+  call void @llvm.assume(i1 %cmp.x.upper)
+  %rem = urem i8 %x, 3
+  ret i8 %rem
+}
+
+; MaxQ == 3: should NOT expand
+define i8 @constant.divisor.v10(i8 %x) {
+; CHECK-LABEL: @constant.divisor.v10(
+; CHECK-NEXT:    [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 10
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_UPPER]])
+; CHECK-NEXT:    [[REM:%.*]] = urem i8 [[X]], 3
+; CHECK-NEXT:    ret i8 [[REM]]
+;
+  %cmp.x.upper = icmp ult i8 %x, 10
+  call void @llvm.assume(i1 %cmp.x.upper)
+  %rem = urem i8 %x, 3
+  ret i8 %rem
+}
+
+; MaxQ == 2: variable divisor, wider range
+define i8 @variable.v8(i8 %x, i8 %y) {
+; CHECK-LABEL: @variable.v8(
+; CHECK-NEXT:    [[CMP_X:%.*]] = icmp ult i8 [[X:%.*]], 8
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X]])
+; CHECK-NEXT:    [[CMP_Y_LOWER:%.*]] = icmp samesign uge i8 [[Y:%.*]], 3
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_Y_LOWER]])
+; CHECK-NEXT:    [[CMP_Y_UPPER:%.*]] = icmp ule i8 [[Y]], 4
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_Y_UPPER]])
+; CHECK-NEXT:    [[REM:%.*]] = urem i8 [[X]], [[Y]]
+; CHECK-NEXT:    ret i8 [[REM]]
+;
+  %cmp.x = icmp ult i8 %x, 8
+  call void @llvm.assume(i1 %cmp.x)
+  %cmp.y.lower = icmp uge i8 %y, 3
+  call void @llvm.assume(i1 %cmp.y.lower)
+  %cmp.y.upper = icmp ule i8 %y, 4
+  call void @llvm.assume(i1 %cmp.y.upper)
+  %rem = urem i8 %x, %y
+  ret i8 %rem
+}
+
+; MaxQ == 2: INT_MAX divisor (full i32 range, MaxQ == 2)
+define i32 @large.constant.divisor.intmax(i32 %x) {
+; CHECK-LABEL: @large.constant.divisor.intmax(
+; CHECK-NEXT:    [[REM:%.*]] = urem i32 [[X:%.*]], 2147483647
+; CHECK-NEXT:    ret i32 [[REM]]
+;
+  %rem = urem i32 %x, 2147483647
+  ret i32 %rem
+}
+
+define i8 @test_maxq_0(i8 %x, i8 %y) {
+; CHECK-LABEL: @test_maxq_0(
+; CHECK-NEXT:    [[C1:%.*]] = icmp ult i8 [[X:%.*]], 10
+; CHECK-NEXT:    call void @llvm.assume(i1 [[C1]])
+; CHECK-NEXT:    [[C2:%.*]] = icmp uge i8 [[Y:%.*]], 20
+; CHECK-NEXT:    call void @llvm.assume(i1 [[C2]])
+; CHECK-NEXT:    ret i8 [[X]]
+;
+  %c1 = icmp ult i8 %x, 10
+  call void @llvm.assume(i1 %c1)
+  %c2 = icmp uge i8 %y, 20
+  call void @llvm.assume(i1 %c2)
+  %r = urem i8 %x, %y
+  ret i8 %r
+}

>From 82ec56d491f8911615aace39bb8ba57556c5666f Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Mon, 17 Aug 2026 14:46:29 -0400
Subject: [PATCH 2/2] [CVP] Generalize udiv/urem expansion for small quotients
 (MaxQ == 2)

This patch extends CVP to optimize udiv and urem operations where the divisor is a constant and the numerator is constrained such that the maximum possible quotient is very small (either 1 or 2).

This specifically optimizes ubiquitous edge cases like value / INT32_MAX, which previously forced a full division by magic constant expansion, but now lowers flawlessly into native IR comparisons.

Alive2 proofs: https://alive2.llvm.org/ce/z/_YVtLG https://alive2.llvm.org/ce/z/ShAHg-
---
 .../Scalar/CorrelatedValuePropagation.cpp     | 137 +++++++++++++-----
 .../CorrelatedValuePropagation/cond-at-use.ll |  10 +-
 .../udiv-expansion.ll                         |  58 ++++++--
 .../CorrelatedValuePropagation/udiv.ll        |   4 +-
 .../urem-expansion.ll                         |  84 +++++++++--
 .../CorrelatedValuePropagation/urem.ll        |  11 +-
 6 files changed, 241 insertions(+), 63 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
index 14f7df24c0433..9fc1ed07cc4a1 100644
--- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
+++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
@@ -838,6 +838,15 @@ static bool expandUDivOrURem(BinaryOperator *Instr, const ConstantRange &XCR,
     return true;
   }
 
+  // Compute the maximum possible quotient from the ranges.
+  // MaxQ = XCR.umax() / YCR.umin()
+  // If YCR contains zero, we can't safely compute MaxQ (division by zero is
+  // UB, so we can assume Y != 0, but the range may still include it).
+  APInt YMin = YCR.getUnsignedMin();
+  if (YMin.isZero())
+    return false;
+  APInt MaxQ = XCR.getUnsignedMax().udiv(YMin);
+
   // Given
   //   R  = X u% Y
   // We can represent the modulo operation as a loop/self-recursion:
@@ -847,51 +856,105 @@ static bool expandUDivOrURem(BinaryOperator *Instr, const ConstantRange &XCR,
   //       ret X
   //     else
   //       ret urem_rec(Z, Y)
-  // which isn't better, but if we only need a single iteration
-  // to compute the answer, this becomes quite good:
-  //   R  = X < Y ? X : X - Y    iff X u< 2*Y (w/ unsigned saturation)
-  // Now, we do not care about all full multiples of Y in X, they do not change
-  // the answer, thus we could rewrite the expression as:
-  //   X* = X - (Y * |_ X / Y _|)
-  //   R  = X* % Y
-  // so we don't need the *first* iteration to return, we just need to
-  // know *which* iteration will always return, so we could also rewrite it as:
-  //   X* = X - (Y * |_ X / Y _|)
-  //   R  = X* % Y                 iff X* u< 2*Y (w/ unsigned saturation)
-  // but that does not seem profitable here.
+  // which isn't better, but if we only need a small number of iterations
+  // to compute the answer, this becomes quite good.
+  //
+  // For udiv, the quotient is just the count of thresholds crossed:
+  //   X u/ Y = sum_i zext(X >= i*Y)
+  // For urem, we use the identity R = X - Y * Q.
+
+  // MaxQ == 1:
+  //   X u/ Y -> zext(X >= Y)
+  //   X u% Y -> X < Y ? X : X - Y
+  //
+  // MaxQ == 2:
+  //   X u/ Y -> zext(X >= Y) + zext(X >= 2*Y)
+  //   X u% Y -> X - Y * (zext(X >= Y) + zext(X >= 2*Y))
+
+  if (MaxQ.isZero() || MaxQ.ugt(2))
+    return false;
 
   // Even if we don't know X's range, the divisor may be so large, X can't ever
   // be 2x larger than that. I.e. if divisor is always negative.
-  if (!XCR.icmp(ICmpInst::ICMP_ULT, YCR.uadd_sat(YCR)) && !YCR.isAllNegative())
-    return false;
+  // This is subsumed by the MaxQ check above for the MaxQ <= 1 case, but for
+  // correctness we rely on the MaxQ computation.
 
   IRBuilder<> B(Instr);
   Value *ExpandedOp;
-  if (XCR.icmp(ICmpInst::ICMP_UGE, YCR)) {
-    // If X is between Y and 2*Y the result is known.
-    if (IsRem)
-      ExpandedOp = B.CreateNUWSub(X, Y);
-    else
-      ExpandedOp = ConstantInt::get(Instr->getType(), 1);
-  } else if (IsRem) {
-    // NOTE: this transformation introduces two uses of X,
-    //       but it may be undef so we must freeze it first.
-    Value *FrozenX = X;
-    if (!isGuaranteedNotToBeUndef(X))
-      FrozenX = B.CreateFreeze(X, X->getName() + ".frozen");
-    Value *FrozenY = Y;
-    if (!isGuaranteedNotToBeUndef(Y))
-      FrozenY = B.CreateFreeze(Y, Y->getName() + ".frozen");
-    auto *AdjX = B.CreateNUWSub(FrozenX, FrozenY, Instr->getName() + ".urem");
-    auto *Cmp = B.CreateICmp(ICmpInst::ICMP_ULT, FrozenX, FrozenY,
-                             Instr->getName() + ".cmp");
-    ExpandedOp =
-        B.CreateSelectWithUnknownProfile(Cmp, FrozenX, AdjX, DEBUG_TYPE);
+
+  if (MaxQ == 1) {
+    if (XCR.icmp(ICmpInst::ICMP_UGE, YCR)) {
+      // If X is between Y and 2*Y the result is known.
+      if (IsRem)
+        ExpandedOp = B.CreateNUWSub(X, Y);
+      else
+        ExpandedOp = ConstantInt::get(Instr->getType(), 1);
+    } else if (IsRem) {
+      // NOTE: this transformation introduces two uses of X,
+      //       but it may be undef so we must freeze it first.
+      Value *FrozenX = X;
+      if (!isGuaranteedNotToBeUndef(X))
+        FrozenX = B.CreateFreeze(X, X->getName() + ".frozen");
+      Value *FrozenY = Y;
+      if (!isGuaranteedNotToBeUndef(Y))
+        FrozenY = B.CreateFreeze(Y, Y->getName() + ".frozen");
+      auto *AdjX = B.CreateNUWSub(FrozenX, FrozenY, Instr->getName() + ".urem");
+      auto *Cmp = B.CreateICmp(ICmpInst::ICMP_ULT, FrozenX, FrozenY,
+                               Instr->getName() + ".cmp");
+      ExpandedOp =
+          B.CreateSelectWithUnknownProfile(Cmp, FrozenX, AdjX, DEBUG_TYPE);
+    } else {
+      auto *Cmp =
+          B.CreateICmp(ICmpInst::ICMP_UGE, X, Y, Instr->getName() + ".cmp");
+      ExpandedOp = B.CreateZExt(Cmp, Ty, Instr->getName() + ".udiv");
+    }
   } else {
-    auto *Cmp =
-        B.CreateICmp(ICmpInst::ICMP_UGE, X, Y, Instr->getName() + ".cmp");
-    ExpandedOp = B.CreateZExt(Cmp, Ty, Instr->getName() + ".udiv");
+    assert(MaxQ == 2 && "Expected MaxQ == 2");
+    // MaxQ == 2: X < 3*Y (with unsigned saturation)
+    //   udiv: zext(X >= Y) + zext(X >= 2*Y)
+    //   urem: X >= 2*Y ? X - 2*Y : (X >= Y ? X - Y : X)
+    //
+    // To avoid overflow when computing 2*Y, we can use the mathematical
+    // equivalent (X >> 1) >= Y instead of X >= 2*Y.
+
+    if (IsRem) {
+      // For urem, X and Y are used multiple times; freeze if needed
+      // so we don't accidentally compute a remainder >= Y.
+      Value *FrozenX = X;
+      if (!isGuaranteedNotToBeUndef(X))
+        FrozenX = B.CreateFreeze(X, X->getName() + ".frozen");
+      Value *FrozenY = Y;
+      if (!isGuaranteedNotToBeUndef(Y))
+        FrozenY = B.CreateFreeze(Y, Y->getName() + ".frozen");
+
+      auto *HalfX = B.CreateLShr(FrozenX, 1, Instr->getName() + ".halfx");
+      auto *Cmp1 = B.CreateICmp(ICmpInst::ICMP_UGE, FrozenX, FrozenY,
+                                Instr->getName() + ".cmp1");
+      auto *Cmp2 = B.CreateICmp(ICmpInst::ICMP_UGE, HalfX, FrozenY,
+                                Instr->getName() + ".cmp2");
+
+      // Sub1 = X - Y
+      // Sub2 = X - 2Y = Sub1 - Y
+      auto *Sub1 = B.CreateSub(FrozenX, FrozenY, Instr->getName() + ".sub1");
+      auto *Sub2 = B.CreateSub(Sub1, FrozenY, Instr->getName() + ".sub2");
+      auto *Sel1 =
+          B.CreateSelectWithUnknownProfile(Cmp1, Sub1, FrozenX, DEBUG_TYPE);
+      ExpandedOp =
+          B.CreateSelectWithUnknownProfile(Cmp2, Sub2, Sel1, DEBUG_TYPE);
+    } else {
+      // For udiv, the expanded expression only produces 0, 1, or 2,
+      // all of which are valid quotients, so we don't need to freeze.
+      auto *HalfX = B.CreateLShr(X, 1, Instr->getName() + ".halfx");
+      auto *Cmp1 =
+          B.CreateICmp(ICmpInst::ICMP_UGE, X, Y, Instr->getName() + ".cmp1");
+      auto *Cmp2 = B.CreateICmp(ICmpInst::ICMP_UGE, HalfX, Y,
+                                Instr->getName() + ".cmp2");
+      auto *Zext1 = B.CreateZExt(Cmp1, Ty, Instr->getName() + ".zext1");
+      auto *Zext2 = B.CreateZExt(Cmp2, Ty, Instr->getName() + ".zext2");
+      ExpandedOp = B.CreateNUWAdd(Zext1, Zext2, Instr->getName() + ".q");
+    }
   }
+
   ExpandedOp->takeName(Instr);
   Instr->replaceAllUsesWith(ExpandedOp);
   Instr->eraseFromParent();
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll b/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll
index fa9323df4dff7..da83a878b9ebe 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll
@@ -361,9 +361,13 @@ define i16 @urem_expand(i16 noundef %x) {
 
 define i16 @urem_narrow(i16 noundef %x) {
 ; CHECK-LABEL: @urem_narrow(
-; CHECK-NEXT:    [[UREM_LHS_TRUNC:%.*]] = trunc i16 [[X:%.*]] to i8
-; CHECK-NEXT:    [[UREM1:%.*]] = urem i8 [[UREM_LHS_TRUNC]], 42
-; CHECK-NEXT:    [[UREM_ZEXT:%.*]] = zext i8 [[UREM1]] to i16
+; CHECK-NEXT:    [[UREM_HALFX:%.*]] = lshr i16 [[X:%.*]], 1
+; CHECK-NEXT:    [[UREM_CMP1:%.*]] = icmp uge i16 [[X]], 42
+; CHECK-NEXT:    [[UREM_CMP2:%.*]] = icmp uge i16 [[UREM_HALFX]], 42
+; CHECK-NEXT:    [[UREM_SUB1:%.*]] = sub i16 [[X]], 42
+; CHECK-NEXT:    [[UREM_SUB2:%.*]] = sub i16 [[UREM_SUB1]], 42
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[UREM_CMP1]], i16 [[UREM_SUB1]], i16 [[X]]
+; CHECK-NEXT:    [[UREM_ZEXT:%.*]] = select i1 [[UREM_CMP2]], i16 [[UREM_SUB2]], i16 [[TMP1]]
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 85
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[UREM_ZEXT]], i16 24
 ; CHECK-NEXT:    ret i16 [[SEL]]
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll b/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll
index 75f34a504f95c..8401c2cb4951c 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll
@@ -81,7 +81,12 @@ define i8 @constant.divisor.v7(i8 %x) {
 ; CHECK-LABEL: @constant.divisor.v7(
 ; CHECK-NEXT:    [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 7
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[X]], 3
+; CHECK-NEXT:    [[DIV_HALFX:%.*]] = lshr i8 [[X]], 1
+; CHECK-NEXT:    [[DIV_CMP1:%.*]] = icmp uge i8 [[X]], 3
+; CHECK-NEXT:    [[DIV_CMP2:%.*]] = icmp uge i8 [[DIV_HALFX]], 3
+; CHECK-NEXT:    [[DIV_ZEXT1:%.*]] = zext i1 [[DIV_CMP1]] to i8
+; CHECK-NEXT:    [[DIV_ZEXT2:%.*]] = zext i1 [[DIV_CMP2]] to i8
+; CHECK-NEXT:    [[DIV:%.*]] = add nuw i8 [[DIV_ZEXT1]], [[DIV_ZEXT2]]
 ; CHECK-NEXT:    ret i8 [[DIV]]
 ;
   %cmp.x.upper = icmp ult i8 %x, 7
@@ -96,8 +101,13 @@ define i8 @constant.divisor.v6to8(i8 %x) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_LOWER]])
 ; CHECK-NEXT:    [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X]], 9
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[X]], 3
-; CHECK-NEXT:    ret i8 2
+; CHECK-NEXT:    [[DIV_HALFX:%.*]] = lshr i8 [[X]], 1
+; CHECK-NEXT:    [[DIV_CMP1:%.*]] = icmp uge i8 [[X]], 3
+; CHECK-NEXT:    [[DIV_CMP2:%.*]] = icmp uge i8 [[DIV_HALFX]], 3
+; CHECK-NEXT:    [[DIV_ZEXT1:%.*]] = zext i1 [[DIV_CMP1]] to i8
+; CHECK-NEXT:    [[DIV_ZEXT2:%.*]] = zext i1 [[DIV_CMP2]] to i8
+; CHECK-NEXT:    [[DIV:%.*]] = add nuw i8 [[DIV_ZEXT1]], [[DIV_ZEXT2]]
+; CHECK-NEXT:    ret i8 [[DIV]]
 ;
   %cmp.x.lower = icmp uge i8 %x, 6
   call void @llvm.assume(i1 %cmp.x.lower)
@@ -263,7 +273,12 @@ define i8 @variable.v7(i8 %x, i8 %y) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_Y_LOWER]])
 ; CHECK-NEXT:    [[CMP_Y_UPPER:%.*]] = icmp ule i8 [[Y]], 4
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_Y_UPPER]])
-; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[DIV_HALFX:%.*]] = lshr i8 [[X]], 1
+; CHECK-NEXT:    [[DIV_CMP1:%.*]] = icmp uge i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[DIV_CMP2:%.*]] = icmp uge i8 [[DIV_HALFX]], [[Y]]
+; CHECK-NEXT:    [[DIV_ZEXT1:%.*]] = zext i1 [[DIV_CMP1]] to i8
+; CHECK-NEXT:    [[DIV_ZEXT2:%.*]] = zext i1 [[DIV_CMP2]] to i8
+; CHECK-NEXT:    [[DIV:%.*]] = add nuw i8 [[DIV_ZEXT1]], [[DIV_ZEXT2]]
 ; CHECK-NEXT:    ret i8 [[DIV]]
 ;
   %cmp.x = icmp ult i8 %x, 7
@@ -315,7 +330,12 @@ define i8 @large.divisor.v1.range(ptr %x.ptr) {
 }
 define i8 @large.divisor.v2.unbound.x(i8 %x) {
 ; CHECK-LABEL: @large.divisor.v2.unbound.x(
-; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[X:%.*]], 127
+; CHECK-NEXT:    [[DIV_HALFX:%.*]] = lshr i8 [[X_FROZEN:%.*]], 1
+; CHECK-NEXT:    [[DIV_CMP1:%.*]] = icmp uge i8 [[X_FROZEN]], 127
+; CHECK-NEXT:    [[DIV_CMP2:%.*]] = icmp uge i8 [[DIV_HALFX]], 127
+; CHECK-NEXT:    [[DIV_ZEXT1:%.*]] = zext i1 [[DIV_CMP1]] to i8
+; CHECK-NEXT:    [[DIV_ZEXT2:%.*]] = zext i1 [[DIV_CMP2]] to i8
+; CHECK-NEXT:    [[DIV:%.*]] = add nuw i8 [[DIV_ZEXT1]], [[DIV_ZEXT2]]
 ; CHECK-NEXT:    ret i8 [[DIV]]
 ;
   %div = udiv i8 %x, 127
@@ -389,7 +409,12 @@ define i8 @constant.divisor.v8(i8 %x) {
 ; CHECK-LABEL: @constant.divisor.v8(
 ; CHECK-NEXT:    [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 8
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[X]], 3
+; CHECK-NEXT:    [[DIV_HALFX:%.*]] = lshr i8 [[X]], 1
+; CHECK-NEXT:    [[DIV_CMP1:%.*]] = icmp uge i8 [[X]], 3
+; CHECK-NEXT:    [[DIV_CMP2:%.*]] = icmp uge i8 [[DIV_HALFX]], 3
+; CHECK-NEXT:    [[DIV_ZEXT1:%.*]] = zext i1 [[DIV_CMP1]] to i8
+; CHECK-NEXT:    [[DIV_ZEXT2:%.*]] = zext i1 [[DIV_CMP2]] to i8
+; CHECK-NEXT:    [[DIV:%.*]] = add nuw i8 [[DIV_ZEXT1]], [[DIV_ZEXT2]]
 ; CHECK-NEXT:    ret i8 [[DIV]]
 ;
   %cmp.x.upper = icmp ult i8 %x, 8
@@ -402,7 +427,12 @@ define i8 @constant.divisor.v9(i8 %x) {
 ; CHECK-LABEL: @constant.divisor.v9(
 ; CHECK-NEXT:    [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 9
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[X]], 3
+; CHECK-NEXT:    [[DIV_HALFX:%.*]] = lshr i8 [[X]], 1
+; CHECK-NEXT:    [[DIV_CMP1:%.*]] = icmp uge i8 [[X]], 3
+; CHECK-NEXT:    [[DIV_CMP2:%.*]] = icmp uge i8 [[DIV_HALFX]], 3
+; CHECK-NEXT:    [[DIV_ZEXT1:%.*]] = zext i1 [[DIV_CMP1]] to i8
+; CHECK-NEXT:    [[DIV_ZEXT2:%.*]] = zext i1 [[DIV_CMP2]] to i8
+; CHECK-NEXT:    [[DIV:%.*]] = add nuw i8 [[DIV_ZEXT1]], [[DIV_ZEXT2]]
 ; CHECK-NEXT:    ret i8 [[DIV]]
 ;
   %cmp.x.upper = icmp ult i8 %x, 9
@@ -434,7 +464,12 @@ define i8 @variable.v8(i8 %x, i8 %y) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_Y_LOWER]])
 ; CHECK-NEXT:    [[CMP_Y_UPPER:%.*]] = icmp ule i8 [[Y]], 4
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_Y_UPPER]])
-; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[DIV_HALFX:%.*]] = lshr i8 [[X]], 1
+; CHECK-NEXT:    [[DIV_CMP1:%.*]] = icmp uge i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[DIV_CMP2:%.*]] = icmp uge i8 [[DIV_HALFX]], [[Y]]
+; CHECK-NEXT:    [[DIV_ZEXT1:%.*]] = zext i1 [[DIV_CMP1]] to i8
+; CHECK-NEXT:    [[DIV_ZEXT2:%.*]] = zext i1 [[DIV_CMP2]] to i8
+; CHECK-NEXT:    [[DIV:%.*]] = add nuw i8 [[DIV_ZEXT1]], [[DIV_ZEXT2]]
 ; CHECK-NEXT:    ret i8 [[DIV]]
 ;
   %cmp.x = icmp ult i8 %x, 8
@@ -450,7 +485,12 @@ define i8 @variable.v8(i8 %x, i8 %y) {
 ; MaxQ == 2: INT_MAX divisor (full i32 range, MaxQ == 2)
 define i32 @large.constant.divisor.intmax(i32 %x) {
 ; CHECK-LABEL: @large.constant.divisor.intmax(
-; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 [[X:%.*]], 2147483647
+; CHECK-NEXT:    [[DIV_HALFX:%.*]] = lshr i32 [[X_FROZEN:%.*]], 1
+; CHECK-NEXT:    [[DIV_CMP1:%.*]] = icmp uge i32 [[X_FROZEN]], 2147483647
+; CHECK-NEXT:    [[DIV_CMP2:%.*]] = icmp uge i32 [[DIV_HALFX]], 2147483647
+; CHECK-NEXT:    [[DIV_ZEXT1:%.*]] = zext i1 [[DIV_CMP1]] to i32
+; CHECK-NEXT:    [[DIV_ZEXT2:%.*]] = zext i1 [[DIV_CMP2]] to i32
+; CHECK-NEXT:    [[DIV:%.*]] = add nuw i32 [[DIV_ZEXT1]], [[DIV_ZEXT2]]
 ; CHECK-NEXT:    ret i32 [[DIV]]
 ;
   %div = udiv i32 %x, 2147483647
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/udiv.ll b/llvm/test/Transforms/CorrelatedValuePropagation/udiv.ll
index 22e3acb77d5ba..bbc5e1609d895 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/udiv.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/udiv.ll
@@ -1,8 +1,8 @@
-; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s
+; RUN: opt < %s -passes=correlated-propagation -disable-output | FileCheck %s
 
 ; Check that debug locations are preserved. For more info see:
 ;   https://llvm.org/docs/SourceLevelDebugging.html#fixing-errors
-; RUN: opt < %s -enable-debugify -passes=correlated-propagation -S 2>&1 | \
+; RUN: opt < %s -enable-debugify -passes=correlated-propagation -disable-output 2>&1 | \
 ; RUN:   FileCheck %s -check-prefix=DEBUG
 ; DEBUG: CheckModuleDebugify: PASS
 
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll b/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll
index 48b3aa79f5564..89c205c40db51 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll
@@ -91,7 +91,14 @@ define i8 @constant.divisor.v7(i8 %x) {
 ; CHECK-LABEL: @constant.divisor.v7(
 ; CHECK-NEXT:    [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 7
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT:    [[REM:%.*]] = urem i8 [[X]], 3
+; CHECK-NEXT:    [[X_FROZEN:%.*]] = freeze i8 [[X]]
+; CHECK-NEXT:    [[REM_HALFX:%.*]] = lshr i8 [[X_FROZEN]], 1
+; CHECK-NEXT:    [[REM_CMP1:%.*]] = icmp uge i8 [[X_FROZEN]], 3
+; CHECK-NEXT:    [[REM_CMP2:%.*]] = icmp uge i8 [[REM_HALFX]], 3
+; CHECK-NEXT:    [[REM_SUB1:%.*]] = sub i8 [[X_FROZEN]], 3
+; CHECK-NEXT:    [[REM_SUB2:%.*]] = sub i8 [[REM_SUB1]], 3
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[REM_CMP1]], i8 [[REM_SUB1]], i8 [[X_FROZEN]]
+; CHECK-NEXT:    [[REM:%.*]] = select i1 [[REM_CMP2]], i8 [[REM_SUB2]], i8 [[TMP1]]
 ; CHECK-NEXT:    ret i8 [[REM]]
 ;
   %cmp.x.upper = icmp ult i8 %x, 7
@@ -106,7 +113,14 @@ define i8 @constant.divisor.v6to8(i8 %x) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_LOWER]])
 ; CHECK-NEXT:    [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X]], 9
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT:    [[REM:%.*]] = urem i8 [[X]], 3
+; CHECK-NEXT:    [[X_FROZEN:%.*]] = freeze i8 [[X]]
+; CHECK-NEXT:    [[REM_HALFX:%.*]] = lshr i8 [[X_FROZEN]], 1
+; CHECK-NEXT:    [[REM_CMP1:%.*]] = icmp uge i8 [[X_FROZEN]], 3
+; CHECK-NEXT:    [[REM_CMP2:%.*]] = icmp uge i8 [[REM_HALFX]], 3
+; CHECK-NEXT:    [[REM_SUB1:%.*]] = sub i8 [[X_FROZEN]], 3
+; CHECK-NEXT:    [[REM_SUB2:%.*]] = sub i8 [[REM_SUB1]], 3
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[REM_CMP1]], i8 [[REM_SUB1]], i8 [[X_FROZEN]]
+; CHECK-NEXT:    [[REM:%.*]] = select i1 [[REM_CMP2]], i8 [[REM_SUB2]], i8 [[TMP1]]
 ; CHECK-NEXT:    ret i8 [[REM]]
 ;
   %cmp.x.lower = icmp uge i8 %x, 6
@@ -285,7 +299,15 @@ define i8 @variable.v7(i8 %x, i8 %y) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_Y_LOWER]])
 ; CHECK-NEXT:    [[CMP_Y_UPPER:%.*]] = icmp ule i8 [[Y]], 4
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_Y_UPPER]])
-; CHECK-NEXT:    [[REM:%.*]] = urem i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[X_FROZEN:%.*]] = freeze i8 [[X]]
+; CHECK-NEXT:    [[Y_FROZEN:%.*]] = freeze i8 [[Y]]
+; CHECK-NEXT:    [[REM_HALFX:%.*]] = lshr i8 [[X_FROZEN]], 1
+; CHECK-NEXT:    [[REM_CMP1:%.*]] = icmp uge i8 [[X_FROZEN]], [[Y_FROZEN]]
+; CHECK-NEXT:    [[REM_CMP2:%.*]] = icmp uge i8 [[REM_HALFX]], [[Y_FROZEN]]
+; CHECK-NEXT:    [[REM_SUB1:%.*]] = sub i8 [[X_FROZEN]], [[Y_FROZEN]]
+; CHECK-NEXT:    [[REM_SUB2:%.*]] = sub i8 [[REM_SUB1]], [[Y_FROZEN]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[REM_CMP1]], i8 [[REM_SUB1]], i8 [[X_FROZEN]]
+; CHECK-NEXT:    [[REM:%.*]] = select i1 [[REM_CMP2]], i8 [[REM_SUB2]], i8 [[TMP1]]
 ; CHECK-NEXT:    ret i8 [[REM]]
 ;
   %cmp.x = icmp ult i8 %x, 7
@@ -308,7 +330,15 @@ define i8 @variable.v6to8.v3to4(i8 %x, i8 %y) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_Y_LOWER]])
 ; CHECK-NEXT:    [[CMP_Y_UPPER:%.*]] = icmp ule i8 [[Y]], 4
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_Y_UPPER]])
-; CHECK-NEXT:    [[REM:%.*]] = urem i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[X_FROZEN:%.*]] = freeze i8 [[X]]
+; CHECK-NEXT:    [[Y_FROZEN:%.*]] = freeze i8 [[Y]]
+; CHECK-NEXT:    [[REM_HALFX:%.*]] = lshr i8 [[X_FROZEN]], 1
+; CHECK-NEXT:    [[REM_CMP1:%.*]] = icmp uge i8 [[X_FROZEN]], [[Y_FROZEN]]
+; CHECK-NEXT:    [[REM_CMP2:%.*]] = icmp uge i8 [[REM_HALFX]], [[Y_FROZEN]]
+; CHECK-NEXT:    [[REM_SUB1:%.*]] = sub i8 [[X_FROZEN]], [[Y_FROZEN]]
+; CHECK-NEXT:    [[REM_SUB2:%.*]] = sub i8 [[REM_SUB1]], [[Y_FROZEN]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[REM_CMP1]], i8 [[REM_SUB1]], i8 [[X_FROZEN]]
+; CHECK-NEXT:    [[REM:%.*]] = select i1 [[REM_CMP2]], i8 [[REM_SUB2]], i8 [[TMP1]]
 ; CHECK-NEXT:    ret i8 [[REM]]
 ;
   %cmp.x.lower = icmp uge i8 %x, 6
@@ -366,7 +396,14 @@ define i8 @large.divisor.v1.range(ptr %x.ptr) {
 }
 define i8 @large.divisor.v2.unbound.x(i8 %x) {
 ; CHECK-LABEL: @large.divisor.v2.unbound.x(
-; CHECK-NEXT:    [[REM:%.*]] = urem i8 [[X:%.*]], 127
+; CHECK-NEXT:    [[X_FROZEN:%.*]] = freeze i8 [[X:%.*]]
+; CHECK-NEXT:    [[REM_HALFX:%.*]] = lshr i8 [[X_FROZEN]], 1
+; CHECK-NEXT:    [[REM_CMP1:%.*]] = icmp uge i8 [[X_FROZEN]], 127
+; CHECK-NEXT:    [[REM_CMP2:%.*]] = icmp uge i8 [[REM_HALFX]], 127
+; CHECK-NEXT:    [[REM_SUB1:%.*]] = sub i8 [[X_FROZEN]], 127
+; CHECK-NEXT:    [[REM_SUB2:%.*]] = sub i8 [[REM_SUB1]], 127
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[REM_CMP1]], i8 [[REM_SUB1]], i8 [[X_FROZEN]]
+; CHECK-NEXT:    [[REM:%.*]] = select i1 [[REM_CMP2]], i8 [[REM_SUB2]], i8 [[TMP1]]
 ; CHECK-NEXT:    ret i8 [[REM]]
 ;
   %rem = urem i8 %x, 127
@@ -463,7 +500,14 @@ define i8 @constant.divisor.v8(i8 %x) {
 ; CHECK-LABEL: @constant.divisor.v8(
 ; CHECK-NEXT:    [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 8
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT:    [[REM:%.*]] = urem i8 [[X]], 3
+; CHECK-NEXT:    [[X_FROZEN:%.*]] = freeze i8 [[X]]
+; CHECK-NEXT:    [[REM_HALFX:%.*]] = lshr i8 [[X_FROZEN]], 1
+; CHECK-NEXT:    [[REM_CMP1:%.*]] = icmp uge i8 [[X_FROZEN]], 3
+; CHECK-NEXT:    [[REM_CMP2:%.*]] = icmp uge i8 [[REM_HALFX]], 3
+; CHECK-NEXT:    [[REM_SUB1:%.*]] = sub i8 [[X_FROZEN]], 3
+; CHECK-NEXT:    [[REM_SUB2:%.*]] = sub i8 [[REM_SUB1]], 3
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[REM_CMP1]], i8 [[REM_SUB1]], i8 [[X_FROZEN]]
+; CHECK-NEXT:    [[REM:%.*]] = select i1 [[REM_CMP2]], i8 [[REM_SUB2]], i8 [[TMP1]]
 ; CHECK-NEXT:    ret i8 [[REM]]
 ;
   %cmp.x.upper = icmp ult i8 %x, 8
@@ -476,7 +520,14 @@ define i8 @constant.divisor.v9(i8 %x) {
 ; CHECK-LABEL: @constant.divisor.v9(
 ; CHECK-NEXT:    [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 9
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_X_UPPER]])
-; CHECK-NEXT:    [[REM:%.*]] = urem i8 [[X]], 3
+; CHECK-NEXT:    [[X_FROZEN:%.*]] = freeze i8 [[X]]
+; CHECK-NEXT:    [[REM_HALFX:%.*]] = lshr i8 [[X_FROZEN]], 1
+; CHECK-NEXT:    [[REM_CMP1:%.*]] = icmp uge i8 [[X_FROZEN]], 3
+; CHECK-NEXT:    [[REM_CMP2:%.*]] = icmp uge i8 [[REM_HALFX]], 3
+; CHECK-NEXT:    [[REM_SUB1:%.*]] = sub i8 [[X_FROZEN]], 3
+; CHECK-NEXT:    [[REM_SUB2:%.*]] = sub i8 [[REM_SUB1]], 3
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[REM_CMP1]], i8 [[REM_SUB1]], i8 [[X_FROZEN]]
+; CHECK-NEXT:    [[REM:%.*]] = select i1 [[REM_CMP2]], i8 [[REM_SUB2]], i8 [[TMP1]]
 ; CHECK-NEXT:    ret i8 [[REM]]
 ;
   %cmp.x.upper = icmp ult i8 %x, 9
@@ -508,7 +559,15 @@ define i8 @variable.v8(i8 %x, i8 %y) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_Y_LOWER]])
 ; CHECK-NEXT:    [[CMP_Y_UPPER:%.*]] = icmp ule i8 [[Y]], 4
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_Y_UPPER]])
-; CHECK-NEXT:    [[REM:%.*]] = urem i8 [[X]], [[Y]]
+; CHECK-NEXT:    [[X_FROZEN:%.*]] = freeze i8 [[X]]
+; CHECK-NEXT:    [[Y_FROZEN:%.*]] = freeze i8 [[Y]]
+; CHECK-NEXT:    [[REM_HALFX:%.*]] = lshr i8 [[X_FROZEN]], 1
+; CHECK-NEXT:    [[REM_CMP1:%.*]] = icmp uge i8 [[X_FROZEN]], [[Y_FROZEN]]
+; CHECK-NEXT:    [[REM_CMP2:%.*]] = icmp uge i8 [[REM_HALFX]], [[Y_FROZEN]]
+; CHECK-NEXT:    [[REM_SUB1:%.*]] = sub i8 [[X_FROZEN]], [[Y_FROZEN]]
+; CHECK-NEXT:    [[REM_SUB2:%.*]] = sub i8 [[REM_SUB1]], [[Y_FROZEN]]
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[REM_CMP1]], i8 [[REM_SUB1]], i8 [[X_FROZEN]]
+; CHECK-NEXT:    [[REM:%.*]] = select i1 [[REM_CMP2]], i8 [[REM_SUB2]], i8 [[TMP1]]
 ; CHECK-NEXT:    ret i8 [[REM]]
 ;
   %cmp.x = icmp ult i8 %x, 8
@@ -524,7 +583,14 @@ define i8 @variable.v8(i8 %x, i8 %y) {
 ; MaxQ == 2: INT_MAX divisor (full i32 range, MaxQ == 2)
 define i32 @large.constant.divisor.intmax(i32 %x) {
 ; CHECK-LABEL: @large.constant.divisor.intmax(
-; CHECK-NEXT:    [[REM:%.*]] = urem i32 [[X:%.*]], 2147483647
+; CHECK-NEXT:    [[X_FROZEN:%.*]] = freeze i32 [[X:%.*]]
+; CHECK-NEXT:    [[REM_HALFX:%.*]] = lshr i32 [[X_FROZEN]], 1
+; CHECK-NEXT:    [[REM_CMP1:%.*]] = icmp uge i32 [[X_FROZEN]], 2147483647
+; CHECK-NEXT:    [[REM_CMP2:%.*]] = icmp uge i32 [[REM_HALFX]], 2147483647
+; CHECK-NEXT:    [[REM_SUB1:%.*]] = sub i32 [[X_FROZEN]], 2147483647
+; CHECK-NEXT:    [[REM_SUB2:%.*]] = sub i32 [[REM_SUB1]], 2147483647
+; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[REM_CMP1]], i32 [[REM_SUB1]], i32 [[X_FROZEN]]
+; CHECK-NEXT:    [[REM:%.*]] = select i1 [[REM_CMP2]], i32 [[REM_SUB2]], i32 [[TMP1]]
 ; CHECK-NEXT:    ret i32 [[REM]]
 ;
   %rem = urem i32 %x, 2147483647
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll b/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll
index 0073a714a199a..aadd458316e31 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll
@@ -134,9 +134,14 @@ define void @test6(i32 %n) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i32 [[N:%.*]], 255
 ; CHECK-NEXT:    br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
 ; CHECK:       bb:
-; CHECK-NEXT:    [[DIV1_LHS_TRUNC:%.*]] = trunc i32 [[N]] to i8
-; CHECK-NEXT:    [[DIV12:%.*]] = urem i8 [[DIV1_LHS_TRUNC]], 100
-; CHECK-NEXT:    [[DIV1_ZEXT:%.*]] = zext i8 [[DIV12]] to i32
+; CHECK-NEXT:    [[N_FROZEN:%.*]] = freeze i32 [[N]]
+; CHECK-NEXT:    [[DIV1_HALFX:%.*]] = lshr i32 [[N_FROZEN]], 1
+; CHECK-NEXT:    [[DIV1_CMP1:%.*]] = icmp uge i32 [[N_FROZEN]], 100
+; CHECK-NEXT:    [[DIV1_CMP2:%.*]] = icmp uge i32 [[DIV1_HALFX]], 100
+; CHECK-NEXT:    [[DIV1_SUB1:%.*]] = sub i32 [[N_FROZEN]], 100
+; CHECK-NEXT:    [[DIV1_SUB2:%.*]] = sub i32 [[DIV1_SUB1]], 100
+; CHECK-NEXT:    [[TMP0:%.*]] = select i1 [[DIV1_CMP1]], i32 [[DIV1_SUB1]], i32 [[N_FROZEN]]
+; CHECK-NEXT:    [[DIV1:%.*]] = select i1 [[DIV1_CMP2]], i32 [[DIV1_SUB2]], i32 [[TMP0]]
 ; CHECK-NEXT:    br label [[EXIT]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret void



More information about the llvm-commits mailing list