[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:55:57 PDT 2026
https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/209321
>From 5a7f0d43036fb32e4ab4c2182dc425e1f556dd16 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 0da448610fee481ece15173fd631fba13b1b818f 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 | 101 +++++++++++--
.../urem-expansion.ll | 84 +++++++++--
.../CorrelatedValuePropagation/urem.ll | 11 +-
6 files changed, 324 insertions(+), 77 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..ef7df8e711465 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/udiv.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/udiv.ll
@@ -1,26 +1,41 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt < %s -passes=correlated-propagation -S | 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
-; CHECK-LABEL: @test_nop
+; https://llvm.org/docs/SourceLevelDebugging.html#fixing-errors
define void @test_nop(i32 %n) {
-; CHECK: udiv i32 %n, 100
+; CHECK-LABEL: define void @test_nop(
+; CHECK-SAME: i32 [[N:%.*]]) {
+; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[N]], 100
+; CHECK-NEXT: ret void
+;
%div = udiv i32 %n, 100
ret void
}
-; CHECK-LABEL: @test1(
define void @test1(i32 %n) {
+; CHECK-LABEL: define void @test1(
+; CHECK-SAME: i32 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[N]], 65535
+; CHECK-NEXT: br i1 [[CMP]], label %[[BB:.*]], label %[[EXIT:.*]]
+; CHECK: [[BB]]:
+; CHECK-NEXT: [[DIV_LHS_TRUNC:%.*]] = trunc i32 [[N]] to i16
+; CHECK-NEXT: [[DIV1:%.*]] = udiv i16 [[DIV_LHS_TRUNC]], 100
+; CHECK-NEXT: [[DIV_ZEXT:%.*]] = zext i16 [[DIV1]] to i32
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
entry:
%cmp = icmp ule i32 %n, 65535
br i1 %cmp, label %bb, label %exit
bb:
-; CHECK: udiv i16
%div = udiv i32 %n, 100
br label %exit
@@ -28,14 +43,23 @@ exit:
ret void
}
-; CHECK-LABEL: @test2(
define void @test2(i32 %n) {
+; CHECK-LABEL: define void @test2(
+; CHECK-SAME: i32 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[N]], 65536
+; CHECK-NEXT: br i1 [[CMP]], label %[[BB:.*]], label %[[EXIT:.*]]
+; CHECK: [[BB]]:
+; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[N]], 100
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
entry:
%cmp = icmp ule i32 %n, 65536
br i1 %cmp, label %bb, label %exit
bb:
-; CHECK: udiv i32 %n, 100
%div = udiv i32 %n, 100
br label %exit
@@ -43,8 +67,23 @@ exit:
ret void
}
-; CHECK-LABEL: @test3(
define void @test3(i32 %m, i32 %n) {
+; CHECK-LABEL: define void @test3(
+; CHECK-SAME: i32 [[M:%.*]], i32 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[M]], 65535
+; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[N]], 65535
+; CHECK-NEXT: [[CMP:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[BB:.*]], label %[[EXIT:.*]]
+; CHECK: [[BB]]:
+; CHECK-NEXT: [[DIV_LHS_TRUNC:%.*]] = trunc i32 [[M]] to i16
+; CHECK-NEXT: [[DIV_RHS_TRUNC:%.*]] = trunc i32 [[N]] to i16
+; CHECK-NEXT: [[DIV1:%.*]] = udiv i16 [[DIV_LHS_TRUNC]], [[DIV_RHS_TRUNC]]
+; CHECK-NEXT: [[DIV_ZEXT:%.*]] = zext i16 [[DIV1]] to i32
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
entry:
%cmp1 = icmp ult i32 %m, 65535
%cmp2 = icmp ult i32 %n, 65535
@@ -52,7 +91,6 @@ entry:
br i1 %cmp, label %bb, label %exit
bb:
-; CHECK: udiv i16
%div = udiv i32 %m, %n
br label %exit
@@ -60,8 +98,20 @@ exit:
ret void
}
-; CHECK-LABEL: @test4(
define void @test4(i32 %m, i32 %n) {
+; CHECK-LABEL: define void @test4(
+; CHECK-SAME: i32 [[M:%.*]], i32 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[M]], 65535
+; CHECK-NEXT: [[CMP2:%.*]] = icmp ule i32 [[N]], 65536
+; CHECK-NEXT: [[CMP:%.*]] = and i1 [[CMP1]], [[CMP2]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[BB:.*]], label %[[EXIT:.*]]
+; CHECK: [[BB]]:
+; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[M]], [[N]]
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
entry:
%cmp1 = icmp ult i32 %m, 65535
%cmp2 = icmp ule i32 %n, 65536
@@ -69,7 +119,6 @@ entry:
br i1 %cmp, label %bb, label %exit
bb:
-; CHECK: udiv i32 %m, %n
%div = udiv i32 %m, %n
br label %exit
@@ -77,22 +126,42 @@ exit:
ret void
}
-; CHECK-LABEL: @test5
define void @test5(i32 %n) {
+; CHECK-LABEL: define void @test5(
+; CHECK-SAME: i32 [[N:%.*]]) {
+; CHECK-NEXT: [[TRUNC:%.*]] = and i32 [[N]], 65535
+; CHECK-NEXT: [[DIV_LHS_TRUNC:%.*]] = trunc i32 [[TRUNC]] to i16
+; CHECK-NEXT: [[DIV1:%.*]] = udiv i16 [[DIV_LHS_TRUNC]], 42
+; CHECK-NEXT: [[DIV_ZEXT:%.*]] = zext i16 [[DIV1]] to i32
+; CHECK-NEXT: ret void
+;
%trunc = and i32 %n, 65535
- ; CHECK: udiv i16
%div = udiv i32 %trunc, 42
ret void
}
-; CHECK-LABEL: @test6
define void @test6(i32 %n) {
+; CHECK-LABEL: define void @test6(
+; CHECK-SAME: i32 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[N]], 255
+; CHECK-NEXT: br i1 [[CMP]], label %[[BB:.*]], label %[[EXIT:.*]]
+; CHECK: [[BB]]:
+; CHECK-NEXT: [[DIV1_HALFX:%.*]] = lshr i32 [[N]], 1
+; CHECK-NEXT: [[DIV1_CMP1:%.*]] = icmp uge i32 [[N]], 100
+; CHECK-NEXT: [[DIV1_CMP2:%.*]] = icmp uge i32 [[DIV1_HALFX]], 100
+; CHECK-NEXT: [[DIV1_ZEXT1:%.*]] = zext i1 [[DIV1_CMP1]] to i32
+; CHECK-NEXT: [[DIV1_ZEXT2:%.*]] = zext i1 [[DIV1_CMP2]] to i32
+; CHECK-NEXT: [[DIV1:%.*]] = add nuw i32 [[DIV1_ZEXT1]], [[DIV1_ZEXT2]]
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
entry:
%cmp = icmp ule i32 %n, 255
br i1 %cmp, label %bb, label %exit
bb:
-; CHECK: udiv i8
%div = sdiv i32 %n, 100
br label %exit
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