[llvm] [ValueTracking] Improve constant range computation for `shl` and `and`. (PR #68446)

via llvm-commits llvm-commits at lists.llvm.org
Sat Oct 7 00:08:36 PDT 2023


https://github.com/goldsteinn updated https://github.com/llvm/llvm-project/pull/68446

>From b1fadfc8c18a87888f5380b079c75673d75d71e2 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 6 Oct 2023 15:17:58 -0500
Subject: [PATCH 1/3] [ValueTracking] Add more tests for constant ranges; NFC

---
 .../Analysis/ValueTracking/constant-ranges.ll | 146 ++++++++++++++++++
 1 file changed, 146 insertions(+)
 create mode 100644 llvm/test/Analysis/ValueTracking/constant-ranges.ll

diff --git a/llvm/test/Analysis/ValueTracking/constant-ranges.ll b/llvm/test/Analysis/ValueTracking/constant-ranges.ll
new file mode 100644
index 000000000000000..e425c1547bc3a60
--- /dev/null
+++ b/llvm/test/Analysis/ValueTracking/constant-ranges.ll
@@ -0,0 +1,146 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=instsimplify < %s -S | FileCheck %s
+
+define i1 @shl_C_X_ugt(i8 %x) {
+; CHECK-LABEL: @shl_C_X_ugt(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i8 7, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[SHL]], -32
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %shl = shl i8 7, %x
+  %r = icmp ugt i8 %shl, 224
+  ret i1 %r
+}
+
+define i1 @shl_C_X_ugt2(i8 %x) {
+; CHECK-LABEL: @shl_C_X_ugt2(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i8 5, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[SHL]], -64
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %shl = shl i8 5, %x
+  %r = icmp ugt i8 %shl, 192
+  ret i1 %r
+}
+
+define i1 @shl_C_X_ugt_fail(i8 %x) {
+; CHECK-LABEL: @shl_C_X_ugt_fail(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i8 1, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[SHL]], 127
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %shl = shl i8 1, %x
+  %r = icmp ugt i8 %shl, 127
+  ret i1 %r
+}
+
+define i1 @shl_C_X_ugt_fail2(i8 %x) {
+; CHECK-LABEL: @shl_C_X_ugt_fail2(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i8 3, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[SHL]], -66
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %shl = shl i8 3, %x
+  %r = icmp ugt i8 %shl, 190
+  ret i1 %r
+}
+
+define i1 @shl_C_X_ugt_fail3(i8 %x) {
+; CHECK-LABEL: @shl_C_X_ugt_fail3(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i8 -1, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[SHL]], -2
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %shl = shl i8 -1, %x
+  %r = icmp ugt i8 %shl, 254
+  ret i1 %r
+}
+
+define i1 @shl_C_X_ugt_todo(i8 %x) {
+; CHECK-LABEL: @shl_C_X_ugt_todo(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i8 -127, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[SHL]], -116
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %shl = shl i8 129, %x
+  %r = icmp ugt i8 %shl, 140
+  ret i1 %r
+}
+
+define i1 @shl_X_C_ugt(i8 %x) {
+; CHECK-LABEL: @shl_X_C_ugt(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i8 [[X:%.*]], 6
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[SHL]], -64
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %shl = shl i8 %x, 6
+  %r = icmp ugt i8 %shl, 192
+  ret i1 %r
+}
+
+define i1 @shl_X_C_ugt_fail(i8 %x) {
+; CHECK-LABEL: @shl_X_C_ugt_fail(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i8 [[X:%.*]], 6
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[SHL]], -65
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %shl = shl i8 %x, 6
+  %r = icmp ugt i8 %shl, 191
+  ret i1 %r
+}
+
+define i1 @shl_X_C_ugt_fail2(i8 %x) {
+; CHECK-LABEL: @shl_X_C_ugt_fail2(
+; CHECK-NEXT:    [[SHL:%.*]] = shl i8 [[X:%.*]], 5
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[SHL]], -64
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %shl = shl i8 %x, 5
+  %r = icmp ugt i8 %shl, 192
+  ret i1 %r
+}
+
+define i1 @and_ugt(i8 %xx) {
+; CHECK-LABEL: @and_ugt(
+; CHECK-NEXT:    [[X:%.*]] = mul i8 [[XX:%.*]], [[XX]]
+; CHECK-NEXT:    [[NEGX:%.*]] = sub i8 0, [[X]]
+; CHECK-NEXT:    [[X_P2:%.*]] = and i8 [[NEGX]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[X_P2]], -128
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %x = mul i8 %xx, %xx  ; thwart complexity-based canonicalization
+  %negx = sub i8 0, %x
+  %x_p2 = and i8 %negx, %x
+  %r = icmp ugt i8 %x_p2, 128
+  ret i1 %r
+}
+
+define i1 @and_ugt2(i8 %xx) {
+; CHECK-LABEL: @and_ugt2(
+; CHECK-NEXT:    [[X:%.*]] = mul i8 [[XX:%.*]], [[XX]]
+; CHECK-NEXT:    [[NEGX:%.*]] = sub i8 0, [[X]]
+; CHECK-NEXT:    [[X_P2:%.*]] = and i8 [[X]], [[NEGX]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[X_P2]], -128
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %x = mul i8 %xx, %xx  ; thwart complexity-based canonicalization
+  %negx = sub i8 0, %x
+  %x_p2 = and i8 %x, %negx
+  %r = icmp ugt i8 %x_p2, 128
+  ret i1 %r
+}
+
+define i1 @and_ugt_fail(i8 %xx) {
+; CHECK-LABEL: @and_ugt_fail(
+; CHECK-NEXT:    [[X:%.*]] = mul i8 [[XX:%.*]], [[XX]]
+; CHECK-NEXT:    [[NEGX:%.*]] = sub i8 0, [[X]]
+; CHECK-NEXT:    [[X_P2:%.*]] = and i8 [[X]], [[NEGX]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[X_P2]], 127
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %x = mul i8 %xx, %xx  ; thwart complexity-based canonicalization
+  %negx = sub i8 0, %x
+  %x_p2 = and i8 %x, %negx
+  %r = icmp ugt i8 %x_p2, 127
+  ret i1 %r
+}

>From 53ee37904263b6a048e5a4dd6f87d7fc19ec4280 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 6 Oct 2023 15:18:21 -0500
Subject: [PATCH 2/3] [ValueTracking] Add better support for ConstantRange(Shl)

1) If LHS is constant:
    - The low bits of the LHS is set, the lower bound is non-zero
    - The upper bound can be capped at popcount(LHS) high bits
2) If RHS is constant:
    - The upper bound can be capped at (Width - RHS) high bits
---
 llvm/lib/Analysis/ValueTracking.cpp                 | 13 +++++++++++++
 llvm/test/Analysis/ValueTracking/constant-ranges.ll | 12 +++---------
 2 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 3af5a6d9a167de4..82eed6b6127a6b6 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -8581,7 +8581,20 @@ static void setLimitsForBinOp(const BinaryOperator &BO, APInt &Lower,
           Lower = *C;
           Upper = C->shl(ShiftAmount) + 1;
         }
+      } else {
+        // If lowbit is set, value can never be zero.
+        if ((*C)[0])
+          Lower = APInt::getOneBitSet(Width, 0);
+        // If we are shifting a constant the largest it can be is if the longest
+        // sequence of consecutive ones is shifted to the highbits (breaking
+        // ties for which sequence is higher). At the moment we take a liberal
+        // upper bound on this by just popcounting the constant.
+        // TODO: There may be a bitwise trick for it longest/highest
+        // consecutative sequence of ones (naive method is O(Width) loop).
+        Upper = APInt::getHighBitsSet(Width, C->popcount()) + 1;
       }
+    } else if (match(BO.getOperand(1), m_APInt(C)) && C->ule(Width)) {
+      Upper = APInt::getBitsSetFrom(Width, C->getZExtValue()) + 1;
     }
     break;
 
diff --git a/llvm/test/Analysis/ValueTracking/constant-ranges.ll b/llvm/test/Analysis/ValueTracking/constant-ranges.ll
index e425c1547bc3a60..14331c251ff5239 100644
--- a/llvm/test/Analysis/ValueTracking/constant-ranges.ll
+++ b/llvm/test/Analysis/ValueTracking/constant-ranges.ll
@@ -3,9 +3,7 @@
 
 define i1 @shl_C_X_ugt(i8 %x) {
 ; CHECK-LABEL: @shl_C_X_ugt(
-; CHECK-NEXT:    [[SHL:%.*]] = shl i8 7, [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[SHL]], -32
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 false
 ;
   %shl = shl i8 7, %x
   %r = icmp ugt i8 %shl, 224
@@ -14,9 +12,7 @@ define i1 @shl_C_X_ugt(i8 %x) {
 
 define i1 @shl_C_X_ugt2(i8 %x) {
 ; CHECK-LABEL: @shl_C_X_ugt2(
-; CHECK-NEXT:    [[SHL:%.*]] = shl i8 5, [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[SHL]], -64
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 false
 ;
   %shl = shl i8 5, %x
   %r = icmp ugt i8 %shl, 192
@@ -69,9 +65,7 @@ define i1 @shl_C_X_ugt_todo(i8 %x) {
 
 define i1 @shl_X_C_ugt(i8 %x) {
 ; CHECK-LABEL: @shl_X_C_ugt(
-; CHECK-NEXT:    [[SHL:%.*]] = shl i8 [[X:%.*]], 6
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[SHL]], -64
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 false
 ;
   %shl = shl i8 %x, 6
   %r = icmp ugt i8 %shl, 192

>From b622e1626ab6f6238d61c6064f22f8ce4e5255a9 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 6 Oct 2023 15:18:29 -0500
Subject: [PATCH 3/3] [ValueTracking] Add better support for ConstantRange(And)

The fairly common power of two pattern `X & -X` can be capped at the
highest power of 2 (signbit set).
---
 llvm/lib/Analysis/ValueTracking.cpp                 |  5 +++++
 llvm/test/Analysis/ValueTracking/constant-ranges.ll | 12 ++----------
 2 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 82eed6b6127a6b6..07ec3700bc36731 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -8520,6 +8520,11 @@ static void setLimitsForBinOp(const BinaryOperator &BO, APInt &Lower,
     if (match(BO.getOperand(1), m_APInt(C)))
       // 'and x, C' produces [0, C].
       Upper = *C + 1;
+    // X & -X is a power of two or zero. So we can cap the value at max power of
+    // two.
+    if (match(BO.getOperand(0), m_Neg(m_Specific(BO.getOperand(1)))) ||
+        match(BO.getOperand(1), m_Neg(m_Specific(BO.getOperand(0)))))
+      Upper = APInt::getSignedMinValue(Width) + 1;
     break;
 
   case Instruction::Or:
diff --git a/llvm/test/Analysis/ValueTracking/constant-ranges.ll b/llvm/test/Analysis/ValueTracking/constant-ranges.ll
index 14331c251ff5239..26e01efedd3dfc7 100644
--- a/llvm/test/Analysis/ValueTracking/constant-ranges.ll
+++ b/llvm/test/Analysis/ValueTracking/constant-ranges.ll
@@ -96,11 +96,7 @@ define i1 @shl_X_C_ugt_fail2(i8 %x) {
 
 define i1 @and_ugt(i8 %xx) {
 ; CHECK-LABEL: @and_ugt(
-; CHECK-NEXT:    [[X:%.*]] = mul i8 [[XX:%.*]], [[XX]]
-; CHECK-NEXT:    [[NEGX:%.*]] = sub i8 0, [[X]]
-; CHECK-NEXT:    [[X_P2:%.*]] = and i8 [[NEGX]], [[X]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[X_P2]], -128
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 false
 ;
   %x = mul i8 %xx, %xx  ; thwart complexity-based canonicalization
   %negx = sub i8 0, %x
@@ -111,11 +107,7 @@ define i1 @and_ugt(i8 %xx) {
 
 define i1 @and_ugt2(i8 %xx) {
 ; CHECK-LABEL: @and_ugt2(
-; CHECK-NEXT:    [[X:%.*]] = mul i8 [[XX:%.*]], [[XX]]
-; CHECK-NEXT:    [[NEGX:%.*]] = sub i8 0, [[X]]
-; CHECK-NEXT:    [[X_P2:%.*]] = and i8 [[X]], [[NEGX]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[X_P2]], -128
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 false
 ;
   %x = mul i8 %xx, %xx  ; thwart complexity-based canonicalization
   %negx = sub i8 0, %x



More information about the llvm-commits mailing list