[llvm] [InstCombine] Generalize `icmp (shl nuw C2, Y), C -> icmp Y, C3` (PR #104696)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 17 08:55:27 PDT 2024
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/104696
>From a12a05b10634dc69090361c0dcd5148ec61bda53 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 18 Aug 2024 17:20:36 +0800
Subject: [PATCH 1/5] [InstCombine] Add pre-commit tests. NFC.
---
.../Transforms/InstCombine/icmp-shl-nuw.ll | 72 +++++++++++++++++++
1 file changed, 72 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll b/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll
index 57c3abc7b9841f..8cfd3228999ac5 100644
--- a/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll
@@ -90,3 +90,75 @@ define <2 x i1> @icmp_ugt_16x2(<2 x i32>) {
%d = icmp ugt <2 x i32> %c, <i32 1048575, i32 1048575>
ret <2 x i1> %d
}
+
+define i1 @fold_icmp_shl_nuw_c1(i32 %x) {
+; CHECK-LABEL: @fold_icmp_shl_nuw_c1(
+; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[X:%.*]], 12
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[LSHR]], 15
+; CHECK-NEXT: [[SHL:%.*]] = shl nuw nsw i32 2, [[AND]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[SHL]], 4
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %lshr = lshr i32 %x, 12
+ %and = and i32 %lshr, 15
+ %shl = shl nuw i32 2, %and
+ %cmp = icmp ult i32 %shl, 4
+ ret i1 %cmp
+}
+
+define i1 @fold_icmp_shl_nuw_c2(i32 %x) {
+; CHECK-LABEL: @fold_icmp_shl_nuw_c2(
+; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 16, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[SHL]], 64
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %shl = shl nuw i32 16, %x
+ %cmp = icmp ult i32 %shl, 64
+ ret i1 %cmp
+}
+
+define i1 @fold_icmp_shl_nuw_c2_non_pow2(i32 %x) {
+; CHECK-LABEL: @fold_icmp_shl_nuw_c2_non_pow2(
+; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 48, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[SHL]], 192
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %shl = shl nuw i32 48, %x
+ %cmp = icmp ult i32 %shl, 192
+ ret i1 %cmp
+}
+
+define i1 @fold_icmp_shl_nuw_c2_div_non_pow2(i32 %x) {
+; CHECK-LABEL: @fold_icmp_shl_nuw_c2_div_non_pow2(
+; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 2, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[SHL]], 60
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %shl = shl nuw i32 2, %x
+ %cmp = icmp ult i32 %shl, 60
+ ret i1 %cmp
+}
+
+; Negative tests
+
+define i1 @fold_icmp_shl_nuw_c2_indivisible(i32 %x) {
+; CHECK-LABEL: @fold_icmp_shl_nuw_c2_indivisible(
+; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 16, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[SHL]], 63
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %shl = shl nuw i32 16, %x
+ %cmp = icmp ult i32 %shl, 63
+ ret i1 %cmp
+}
+
+define i1 @fold_icmp_shl_c2_without_nuw(i32 %x) {
+; CHECK-LABEL: @fold_icmp_shl_c2_without_nuw(
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 16, [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[SHL]], 64
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %shl = shl i32 16, %x
+ %cmp = icmp ult i32 %shl, 64
+ ret i1 %cmp
+}
>From 52bf8d6ab313bd495b368cd75b8fd50ac846efbb Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 18 Aug 2024 17:22:01 +0800
Subject: [PATCH 2/5] [InstCombine] Generalize `icmp (shl nuw C2, Y), C -> icmp
Y, C3`
---
.../InstCombine/InstCombineCompares.cpp | 22 ++++++++++++-------
.../Transforms/InstCombine/icmp-shl-nuw.ll | 15 +++++--------
2 files changed, 19 insertions(+), 18 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 8e8d472a5df1d3..bf9f5f5593b362 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2227,18 +2227,24 @@ Instruction *InstCombinerImpl::foldICmpMulConstant(ICmpInst &Cmp,
return NewC ? new ICmpInst(Pred, X, NewC) : nullptr;
}
-/// Fold icmp (shl 1, Y), C.
-static Instruction *foldICmpShlOne(ICmpInst &Cmp, Instruction *Shl,
- const APInt &C) {
+/// Fold icmp (shl nuw C2, Y), C.
+static Instruction *foldICmpShlLHSC(ICmpInst &Cmp, Instruction *Shl,
+ const APInt &C) {
Value *Y;
- if (!match(Shl, m_Shl(m_One(), m_Value(Y))))
+ const APInt *C2;
+ if (!match(Shl, m_NUWShl(m_APInt(C2), m_Value(Y))))
return nullptr;
Type *ShiftType = Shl->getType();
unsigned TypeBits = C.getBitWidth();
- bool CIsPowerOf2 = C.isPowerOf2();
ICmpInst::Predicate Pred = Cmp.getPredicate();
if (Cmp.isUnsigned()) {
+ APInt Div, Rem;
+ APInt::udivrem(C, *C2, Div, Rem);
+ if (!Rem.isZero())
+ return nullptr;
+ bool CIsPowerOf2 = Div.isPowerOf2();
+
// (1 << Y) pred C -> Y pred Log2(C)
if (!CIsPowerOf2) {
// (1 << Y) < 30 -> Y <= 4
@@ -2251,9 +2257,9 @@ static Instruction *foldICmpShlOne(ICmpInst &Cmp, Instruction *Shl,
Pred = ICmpInst::ICMP_UGT;
}
- unsigned CLog2 = C.logBase2();
+ unsigned CLog2 = Div.logBase2();
return new ICmpInst(Pred, Y, ConstantInt::get(ShiftType, CLog2));
- } else if (Cmp.isSigned()) {
+ } else if (Cmp.isSigned() && C2->isOne()) {
Constant *BitWidthMinusOne = ConstantInt::get(ShiftType, TypeBits - 1);
// (1 << Y) > 0 -> Y != 31
// (1 << Y) > C -> Y != 31 if C is negative.
@@ -2307,7 +2313,7 @@ Instruction *InstCombinerImpl::foldICmpShlConstant(ICmpInst &Cmp,
const APInt *ShiftAmt;
if (!match(Shl->getOperand(1), m_APInt(ShiftAmt)))
- return foldICmpShlOne(Cmp, Shl, C);
+ return foldICmpShlLHSC(Cmp, Shl, C);
// Check that the shift amount is in range. If not, don't perform undefined
// shifts. When the shift is visited, it will be simplified.
diff --git a/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll b/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll
index 8cfd3228999ac5..46671f83610fd1 100644
--- a/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll
@@ -93,10 +93,8 @@ define <2 x i1> @icmp_ugt_16x2(<2 x i32>) {
define i1 @fold_icmp_shl_nuw_c1(i32 %x) {
; CHECK-LABEL: @fold_icmp_shl_nuw_c1(
-; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[X:%.*]], 12
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[LSHR]], 15
-; CHECK-NEXT: [[SHL:%.*]] = shl nuw nsw i32 2, [[AND]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[SHL]], 4
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 61440
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%lshr = lshr i32 %x, 12
@@ -108,8 +106,7 @@ define i1 @fold_icmp_shl_nuw_c1(i32 %x) {
define i1 @fold_icmp_shl_nuw_c2(i32 %x) {
; CHECK-LABEL: @fold_icmp_shl_nuw_c2(
-; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 16, [[X:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[SHL]], 64
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 2
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nuw i32 16, %x
@@ -119,8 +116,7 @@ define i1 @fold_icmp_shl_nuw_c2(i32 %x) {
define i1 @fold_icmp_shl_nuw_c2_non_pow2(i32 %x) {
; CHECK-LABEL: @fold_icmp_shl_nuw_c2_non_pow2(
-; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 48, [[X:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[SHL]], 192
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 2
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nuw i32 48, %x
@@ -130,8 +126,7 @@ define i1 @fold_icmp_shl_nuw_c2_non_pow2(i32 %x) {
define i1 @fold_icmp_shl_nuw_c2_div_non_pow2(i32 %x) {
; CHECK-LABEL: @fold_icmp_shl_nuw_c2_div_non_pow2(
-; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 2, [[X:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[SHL]], 60
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 5
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nuw i32 2, %x
>From f2c57001018a9f0408b563c3c7e2951ff1bc285b Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 10 Sep 2024 15:04:46 +0800
Subject: [PATCH 3/5] [InstCombine] Generalize to handle non-rem-zero cases
---
.../InstCombine/InstCombineCompares.cpp | 6 ++---
.../Transforms/InstCombine/icmp-shl-nuw.ll | 23 +++++++++++++++++--
2 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index bf9f5f5593b362..11e7c64baf10fa 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2239,11 +2239,11 @@ static Instruction *foldICmpShlLHSC(ICmpInst &Cmp, Instruction *Shl,
unsigned TypeBits = C.getBitWidth();
ICmpInst::Predicate Pred = Cmp.getPredicate();
if (Cmp.isUnsigned()) {
+ assert(!C2->isZero() && C2->ult(C) &&
+ "Should be simplified by InstSimplify");
APInt Div, Rem;
APInt::udivrem(C, *C2, Div, Rem);
- if (!Rem.isZero())
- return nullptr;
- bool CIsPowerOf2 = Div.isPowerOf2();
+ bool CIsPowerOf2 = Rem.isZero() && Div.isPowerOf2();
// (1 << Y) pred C -> Y pred Log2(C)
if (!CIsPowerOf2) {
diff --git a/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll b/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll
index 46671f83610fd1..c6b03ed8c80fef 100644
--- a/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll
@@ -138,8 +138,7 @@ define i1 @fold_icmp_shl_nuw_c2_div_non_pow2(i32 %x) {
define i1 @fold_icmp_shl_nuw_c2_indivisible(i32 %x) {
; CHECK-LABEL: @fold_icmp_shl_nuw_c2_indivisible(
-; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 16, [[X:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[SHL]], 63
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], 2
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl = shl nuw i32 16, %x
@@ -157,3 +156,23 @@ define i1 @fold_icmp_shl_c2_without_nuw(i32 %x) {
%cmp = icmp ult i32 %shl, 64
ret i1 %cmp
}
+
+; Make sure this trivial case is folded by InstSimplify.
+define i1 @fold_icmp_shl_nuw_c2_precondition1(i32 %x) {
+; CHECK-LABEL: @fold_icmp_shl_nuw_c2_precondition1(
+; CHECK-NEXT: ret i1 true
+;
+ %shl = shl nuw i32 0, %x
+ %cmp = icmp ult i32 %shl, 63
+ ret i1 %cmp
+}
+
+; Make sure this trivial case is folded by InstSimplify.
+define i1 @fold_icmp_shl_nuw_c2_precondition2(i32 %x) {
+; CHECK-LABEL: @fold_icmp_shl_nuw_c2_precondition2(
+; CHECK-NEXT: ret i1 false
+;
+ %shl = shl nuw i32 127, %x
+ %cmp = icmp ult i32 %shl, 63
+ ret i1 %cmp
+}
>From 0150745b81603c26a8ef59e109ccf22d1f67f5cd Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 10 Sep 2024 16:06:43 +0800
Subject: [PATCH 4/5] [InnstCombine] Fix assertion failure on trivial cases
---
.../lib/Transforms/InstCombine/InstCombineCompares.cpp | 2 +-
llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll | 10 ++++++++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 11e7c64baf10fa..ec585187f65ba9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2239,7 +2239,7 @@ static Instruction *foldICmpShlLHSC(ICmpInst &Cmp, Instruction *Shl,
unsigned TypeBits = C.getBitWidth();
ICmpInst::Predicate Pred = Cmp.getPredicate();
if (Cmp.isUnsigned()) {
- assert(!C2->isZero() && C2->ult(C) &&
+ assert(!C2->isZero() && C2->ule(C) &&
"Should be simplified by InstSimplify");
APInt Div, Rem;
APInt::udivrem(C, *C2, Div, Rem);
diff --git a/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll b/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll
index c6b03ed8c80fef..d445bb63cc213e 100644
--- a/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll
@@ -176,3 +176,13 @@ define i1 @fold_icmp_shl_nuw_c2_precondition2(i32 %x) {
%cmp = icmp ult i32 %shl, 63
ret i1 %cmp
}
+
+; Make sure we don't crash on this case.
+define i1 @fold_icmp_shl_nuw_c2_precondition3(i32 %x) {
+; CHECK-LABEL: @fold_icmp_shl_nuw_c2_precondition3(
+; CHECK-NEXT: ret i1 false
+;
+ %shl = shl nuw i32 1, %x
+ %cmp = icmp ult i32 %shl, 1
+ ret i1 %cmp
+}
>From 81dd910307270b836139a14305970da21d6f8b6e Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 17 Sep 2024 23:54:56 +0800
Subject: [PATCH 5/5] [InstCombine] Add more tests. NFC.
---
llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll b/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll
index d445bb63cc213e..9341f820bc6403 100644
--- a/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-shl-nuw.ll
@@ -134,6 +134,16 @@ define i1 @fold_icmp_shl_nuw_c2_div_non_pow2(i32 %x) {
ret i1 %cmp
}
+define i1 @fold_icmp_shl_nuw_c3(i32 %x) {
+; CHECK-LABEL: @fold_icmp_shl_nuw_c3(
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X:%.*]], 1
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %shl = shl nuw i32 48, %x
+ %cmp = icmp uge i32 %shl, 144
+ ret i1 %cmp
+}
+
; Negative tests
define i1 @fold_icmp_shl_nuw_c2_indivisible(i32 %x) {
More information about the llvm-commits
mailing list