[llvm-branch-commits] [llvm] a13c0f6 - [InstSimplify] Fold x*C1/C2 <= x (PR48744)
Nikita Popov via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Jan 17 07:07:38 PST 2021
Author: Nikita Popov
Date: 2021-01-17T16:02:55+01:00
New Revision: a13c0f62c38131ef2656b06de02d82110abaf272
URL: https://github.com/llvm/llvm-project/commit/a13c0f62c38131ef2656b06de02d82110abaf272
DIFF: https://github.com/llvm/llvm-project/commit/a13c0f62c38131ef2656b06de02d82110abaf272.diff
LOG: [InstSimplify] Fold x*C1/C2 <= x (PR48744)
We can fold x*C1/C2 <= x to true if C1 <= C2. This is valid even
if the multiplication is not nuw: https://alive2.llvm.org/ce/z/vULors
The multiplication or division can be replaced by shifts. We don't
handle the case where both are shifts, as that should get folded
away by InstCombine.
Added:
Modified:
llvm/lib/Analysis/InstructionSimplify.cpp
llvm/test/Transforms/InstSimplify/icmp.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index b672798aaffc..3cab06079a87 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -2901,6 +2901,28 @@ static Value *simplifyICmpWithBinOpOnLHS(
return getTrue(ITy);
}
+ // (x*C1)/C2 <= x for C1 <= C2.
+ // This holds even if the multiplication overflows: Assume that x != 0 and
+ // arithmetic is modulo M. For overflow to occur we must have C1 >= M/x and
+ // thus C2 >= M/x. It follows that (x*C1)/C2 <= (M-1)/C2 <= ((M-1)*x)/M < x.
+ //
+ // Additionally, either the multiplication and division might be represented
+ // as shifts:
+ // (x*C1)>>C2 <= x for C1 < 2**C2.
+ // (x<<C1)/C2 <= x for 2**C1 < C2.
+ const APInt *C1, *C2;
+ if ((match(LBO, m_UDiv(m_Mul(m_Specific(RHS), m_APInt(C1)), m_APInt(C2))) &&
+ C1->ule(*C2)) ||
+ (match(LBO, m_LShr(m_Mul(m_Specific(RHS), m_APInt(C1)), m_APInt(C2))) &&
+ C1->ule(APInt(C2->getBitWidth(), 1) << *C2)) ||
+ (match(LBO, m_UDiv(m_Shl(m_Specific(RHS), m_APInt(C1)), m_APInt(C2))) &&
+ (APInt(C1->getBitWidth(), 1) << *C1).ule(*C2))) {
+ if (Pred == ICmpInst::ICMP_UGT)
+ return getFalse(ITy);
+ if (Pred == ICmpInst::ICMP_ULE)
+ return getTrue(ITy);
+ }
+
return nullptr;
}
diff --git a/llvm/test/Transforms/InstSimplify/icmp.ll b/llvm/test/Transforms/InstSimplify/icmp.ll
index ad39725889c8..1d4e954256a0 100644
--- a/llvm/test/Transforms/InstSimplify/icmp.ll
+++ b/llvm/test/Transforms/InstSimplify/icmp.ll
@@ -39,10 +39,7 @@ define i1 @poison2(i32 %x) {
define i1 @mul_div_cmp_smaller(i8 %x) {
; CHECK-LABEL: @mul_div_cmp_smaller(
-; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 3
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[MUL]], 4
-; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%mul = mul i8 %x, 3
%div = udiv i8 %mul, 4
@@ -52,10 +49,7 @@ define i1 @mul_div_cmp_smaller(i8 %x) {
define i1 @mul_div_cmp_equal(i8 %x) {
; CHECK-LABEL: @mul_div_cmp_equal(
-; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 3
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[MUL]], 3
-; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%mul = mul i8 %x, 3
%div = udiv i8 %mul, 3
@@ -78,10 +72,7 @@ define i1 @mul_div_cmp_greater(i8 %x) {
}
define i1 @mul_div_cmp_ugt(i8 %x) {
; CHECK-LABEL: @mul_div_cmp_ugt(
-; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 3
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[MUL]], 4
-; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[DIV]], [[X]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%mul = mul i8 %x, 3
%div = udiv i8 %mul, 4
@@ -133,10 +124,7 @@ define i1 @mul_div_cmp_wrong_operand(i8 %x, i8 %y) {
define i1 @mul_lshr_cmp_smaller(i8 %x) {
; CHECK-LABEL: @mul_lshr_cmp_smaller(
-; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 3
-; CHECK-NEXT: [[DIV:%.*]] = lshr i8 [[MUL]], 2
-; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%mul = mul i8 %x, 3
%div = lshr i8 %mul, 2
@@ -146,10 +134,7 @@ define i1 @mul_lshr_cmp_smaller(i8 %x) {
define i1 @mul_lshr_cmp_equal(i8 %x) {
; CHECK-LABEL: @mul_lshr_cmp_equal(
-; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 4
-; CHECK-NEXT: [[DIV:%.*]] = lshr i8 [[MUL]], 2
-; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%mul = mul i8 %x, 4
%div = lshr i8 %mul, 2
@@ -172,10 +157,7 @@ define i1 @mul_lshr_cmp_greater(i8 %x) {
define i1 @shl_div_cmp_smaller(i8 %x) {
; CHECK-LABEL: @shl_div_cmp_smaller(
-; CHECK-NEXT: [[MUL:%.*]] = shl i8 [[X:%.*]], 2
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[MUL]], 5
-; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%mul = shl i8 %x, 2
%div = udiv i8 %mul, 5
@@ -185,10 +167,7 @@ define i1 @shl_div_cmp_smaller(i8 %x) {
define i1 @shl_div_cmp_equal(i8 %x) {
; CHECK-LABEL: @shl_div_cmp_equal(
-; CHECK-NEXT: [[MUL:%.*]] = shl i8 [[X:%.*]], 2
-; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[MUL]], 4
-; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[DIV]], [[X]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%mul = shl i8 %x, 2
%div = udiv i8 %mul, 4
More information about the llvm-branch-commits
mailing list