[llvm] [InstCombine] Fold the bound check idiom into sign bit test (PR #76439)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Sun Jan 7 04:09:28 PST 2024


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/76439

>From 578c2960c04282352d2169a28fc2e98b4be75064 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 27 Dec 2023 21:36:28 +0800
Subject: [PATCH 1/3] [InstCombine] Add pre-commit tests. NFC.

---
 llvm/test/Transforms/InstCombine/icmp.ll | 98 +++++++++++++++++++++++-
 1 file changed, 97 insertions(+), 1 deletion(-)

diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll
index 1f554c7b60256c..2ea3fe8cb2ef1f 100644
--- a/llvm/test/Transforms/InstCombine/icmp.ll
+++ b/llvm/test/Transforms/InstCombine/icmp.ll
@@ -5006,7 +5006,6 @@ define i1 @or_positive_sgt_zero_multi_use(i8 %a) {
   ret i1 %cmp
 }
 
-
 define i1 @disjoint_or_sgt_1(i8 %a, i8 %b) {
 ; CHECK-LABEL: @disjoint_or_sgt_1(
 ; CHECK-NEXT:    [[B1:%.*]] = add nsw i8 [[B:%.*]], 2
@@ -5138,3 +5137,100 @@ entry:
   %cmp = icmp eq i8 %add2, %add1
   ret i1 %cmp
 }
+
+define i1 @icmp_ugt_sdiv_by_constant(i64 %x) {
+; CHECK-LABEL: @icmp_ugt_sdiv_by_constant(
+; CHECK-NEXT:    [[SDIV:%.*]] = sdiv exact i64 [[X:%.*]], 24
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i64 [[SDIV]], 384307168202282325
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sdiv = sdiv exact i64 %x, 24
+  %cmp = icmp ugt i64 %sdiv, 384307168202282325
+  ret i1 %cmp
+}
+
+define i1 @icmp_ult_sdiv_by_constant(i64 %x) {
+; CHECK-LABEL: @icmp_ult_sdiv_by_constant(
+; CHECK-NEXT:    [[SDIV:%.*]] = sdiv exact i64 [[X:%.*]], 24
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[SDIV]], 384307168202282326
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sdiv = sdiv exact i64 %x, 24
+  %cmp = icmp ult i64 %sdiv, 384307168202282326
+  ret i1 %cmp
+}
+
+; TODO: This should be simplified to icmp slt i64 %x, 0
+define i1 @icmp_ugt_ashr_by_constant(i64 %x) {
+; CHECK-LABEL: @icmp_ugt_ashr_by_constant(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i64 [[X:%.*]], 9223372036854775804
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sdiv = ashr exact i64 %x, 2
+  %cmp = icmp ugt i64 %sdiv, 2305843009213693951
+  ret i1 %cmp
+}
+
+define i1 @icmp_ult_ashr_by_constant(i64 %x) {
+; CHECK-LABEL: @icmp_ult_ashr_by_constant(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i64 [[X:%.*]], -1
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sdiv = ashr exact i64 %x, 2
+  %cmp = icmp ult i64 %sdiv, 2305843009213693952
+  ret i1 %cmp
+}
+
+; Negative tests
+define i1 @icmp_ugt_sdiv_by_constant_without_exact(i64 %x) {
+; CHECK-LABEL: @icmp_ugt_sdiv_by_constant_without_exact(
+; CHECK-NEXT:    [[SDIV:%.*]] = sdiv i64 [[X:%.*]], 24
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i64 [[SDIV]], 384307168202282325
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sdiv = sdiv i64 %x, 24
+  %cmp = icmp ugt i64 %sdiv, 384307168202282325
+  ret i1 %cmp
+}
+
+define i1 @icmp_ugt_udiv_by_constant(i64 %x) {
+; CHECK-LABEL: @icmp_ugt_udiv_by_constant(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i64 [[X:%.*]], 9223372036854775800
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sdiv = udiv exact i64 %x, 24
+  %cmp = icmp ugt i64 %sdiv, 384307168202282325
+  ret i1 %cmp
+}
+
+define i1 @icmp_ne_sdiv_by_constant(i64 %x) {
+; CHECK-LABEL: @icmp_ne_sdiv_by_constant(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 [[X:%.*]], 9223372036854775800
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sdiv = sdiv exact i64 %x, 24
+  %cmp = icmp ne i64 %sdiv, 384307168202282325
+  ret i1 %cmp
+}
+
+define i1 @icmp_ugt_sdiv_by_constant_wrong_rhs(i64 %x) {
+; CHECK-LABEL: @icmp_ugt_sdiv_by_constant_wrong_rhs(
+; CHECK-NEXT:    [[SDIV:%.*]] = sdiv exact i64 [[X:%.*]], 24
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i64 [[SDIV]], 384307168202282324
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sdiv = sdiv exact i64 %x, 24
+  %cmp = icmp ugt i64 %sdiv, 384307168202282324
+  ret i1 %cmp
+}
+
+define i1 @icmp_ugt_sdiv_by_negative_constant(i64 %x) {
+; CHECK-LABEL: @icmp_ugt_sdiv_by_negative_constant(
+; CHECK-NEXT:    [[SDIV:%.*]] = sdiv i64 [[X:%.*]], -24
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i64 [[SDIV]], -384307168202282326
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sdiv = sdiv i64 %x, -24
+  %cmp = icmp ugt i64 %sdiv, -384307168202282326
+  ret i1 %cmp
+}

>From 3a386e38283006139356dd6dcdf0d4e89f27efe9 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 27 Dec 2023 21:36:58 +0800
Subject: [PATCH 2/3] [InstCombine] Fold the bound check idiom into sign bit
 test

---
 .../InstCombine/InstCombineCompares.cpp       | 20 +++++++++++++++++++
 llvm/test/Transforms/InstCombine/icmp.ll      |  6 ++----
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index a2ff8f3eef8199..07ccec2a7681b8 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2641,6 +2641,26 @@ Instruction *InstCombinerImpl::foldICmpDivConstant(ICmpInst &Cmp,
   if (!match(Y, m_APInt(C2)))
     return nullptr;
 
+  // Fold the bound check idiom:
+  //  T *end, *start;
+  //  (size_t)(end - start) > (size_t)(PTRDIFF_MAX / sizeof(T))
+  // into:
+  //  (ptrdiff_t)(end - start) < 0
+  // i.e.:
+  //   icmp ugt (sdiv exact X, C2), (sdiv signed_max, C2) --> icmp slt X, 0
+  //   icmp ult (sdiv exact X, C2), (sdiv signed_max, C2) + 1 --> icmp sgt X, -1
+  // where C2 is positive.
+  if (DivIsSigned && Div->isExact() &&
+      (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULT) &&
+      C2->isStrictlyPositive() &&
+      APInt::getSignedMaxValue(C2->getBitWidth()).sdiv(*C2) +
+              APInt(C2->getBitWidth(), Pred == ICmpInst::ICMP_UGT ? 0 : 1) ==
+          C)
+    return new ICmpInst(
+        Pred == ICmpInst::ICMP_UGT ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_SGT, X,
+        Pred == ICmpInst::ICMP_UGT ? Constant::getNullValue(X->getType())
+                                   : Constant::getAllOnesValue(X->getType()));
+
   // FIXME: If the operand types don't match the type of the divide
   // then don't attempt this transform. The code below doesn't have the
   // logic to deal with a signed divide and an unsigned compare (and
diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll
index 2ea3fe8cb2ef1f..d51ec90622dcf3 100644
--- a/llvm/test/Transforms/InstCombine/icmp.ll
+++ b/llvm/test/Transforms/InstCombine/icmp.ll
@@ -5140,8 +5140,7 @@ entry:
 
 define i1 @icmp_ugt_sdiv_by_constant(i64 %x) {
 ; CHECK-LABEL: @icmp_ugt_sdiv_by_constant(
-; CHECK-NEXT:    [[SDIV:%.*]] = sdiv exact i64 [[X:%.*]], 24
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i64 [[SDIV]], 384307168202282325
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %sdiv = sdiv exact i64 %x, 24
@@ -5151,8 +5150,7 @@ define i1 @icmp_ugt_sdiv_by_constant(i64 %x) {
 
 define i1 @icmp_ult_sdiv_by_constant(i64 %x) {
 ; CHECK-LABEL: @icmp_ult_sdiv_by_constant(
-; CHECK-NEXT:    [[SDIV:%.*]] = sdiv exact i64 [[X:%.*]], 24
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[SDIV]], 384307168202282326
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i64 [[X:%.*]], -1
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %sdiv = sdiv exact i64 %x, 24

>From e55b9def3a36f233377cc02cbc9e702c66144ca9 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 27 Dec 2023 23:54:42 +0800
Subject: [PATCH 3/3] [InstCombine] Add one-use constraint for the
 simplification

---
 .../Transforms/InstCombine/InstCombineCompares.cpp  |  2 +-
 llvm/test/Transforms/InstCombine/icmp.ll            | 13 +++++++++++++
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 07ccec2a7681b8..8076dec2732d48 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2650,7 +2650,7 @@ Instruction *InstCombinerImpl::foldICmpDivConstant(ICmpInst &Cmp,
   //   icmp ugt (sdiv exact X, C2), (sdiv signed_max, C2) --> icmp slt X, 0
   //   icmp ult (sdiv exact X, C2), (sdiv signed_max, C2) + 1 --> icmp sgt X, -1
   // where C2 is positive.
-  if (DivIsSigned && Div->isExact() &&
+  if (DivIsSigned && Div->hasOneUse() && Div->isExact() &&
       (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULT) &&
       C2->isStrictlyPositive() &&
       APInt::getSignedMaxValue(C2->getBitWidth()).sdiv(*C2) +
diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll
index d51ec90622dcf3..c2d06754278ceb 100644
--- a/llvm/test/Transforms/InstCombine/icmp.ll
+++ b/llvm/test/Transforms/InstCombine/icmp.ll
@@ -5232,3 +5232,16 @@ define i1 @icmp_ugt_sdiv_by_negative_constant(i64 %x) {
   %cmp = icmp ugt i64 %sdiv, -384307168202282326
   ret i1 %cmp
 }
+
+define i1 @icmp_ugt_sdiv_by_constant_multiuse(i64 %x) {
+; CHECK-LABEL: @icmp_ugt_sdiv_by_constant_multiuse(
+; CHECK-NEXT:    [[SDIV:%.*]] = sdiv exact i64 [[X:%.*]], 24
+; CHECK-NEXT:    call void @use_i64(i64 [[SDIV]])
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i64 [[SDIV]], 384307168202282325
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %sdiv = sdiv exact i64 %x, 24
+  call void @use_i64(i64 %sdiv)
+  %cmp = icmp ugt i64 %sdiv, 384307168202282325
+  ret i1 %cmp
+}



More information about the llvm-commits mailing list