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

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 27 07:56:18 PST 2023


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

>From 8bd4109dd9af8c1db67172d94fa01e9965e2c679 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 | 97 ++++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll
index 9b2e141bdb0506..4e673828967a1b 100644
--- a/llvm/test/Transforms/InstCombine/icmp.ll
+++ b/llvm/test/Transforms/InstCombine/icmp.ll
@@ -5013,3 +5013,100 @@ define i1 @or_positive_sgt_zero_multi_use(i8 %a) {
   %cmp = icmp sgt i8 %b, 0
   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 d9e5bdc00c4adeac177a9a725a2ea9616a5e5711 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 0222c93faf24e9..43d1562a3177d4 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2636,6 +2636,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 4e673828967a1b..48a33b65177714 100644
--- a/llvm/test/Transforms/InstCombine/icmp.ll
+++ b/llvm/test/Transforms/InstCombine/icmp.ll
@@ -5016,8 +5016,7 @@ define i1 @or_positive_sgt_zero_multi_use(i8 %a) {
 
 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
@@ -5027,8 +5026,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 ae5de11211758adef4fab75587c606b7ff385e8e 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 43d1562a3177d4..e7c40114397cba 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2645,7 +2645,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 48a33b65177714..9370589355055b 100644
--- a/llvm/test/Transforms/InstCombine/icmp.ll
+++ b/llvm/test/Transforms/InstCombine/icmp.ll
@@ -5108,3 +5108,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