[llvm] [ValueTracking] Improve constant range computation for `shl` and `and`. (PR #68446)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 6 13:31:11 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis
<details>
<summary>Changes</summary>
- [ValueTracking] Add more tests for constant ranges; NFC
- [ValueTracking] Add better support for ConstantRange(Shl)
- [ValueTracking] Add better support for ConstantRange(And)
---
Full diff: https://github.com/llvm/llvm-project/pull/68446.diff
2 Files Affected:
- (modified) llvm/lib/Analysis/ValueTracking.cpp (+18)
- (added) llvm/test/Analysis/ValueTracking/constant-ranges.ll (+132)
``````````diff
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 3af5a6d9a167de4..7ca1e7de9ae96e0 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:
@@ -8581,7 +8586,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))) {
+ 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
new file mode 100644
index 000000000000000..47680e32b89b41f
--- /dev/null
+++ b/llvm/test/Analysis/ValueTracking/constant-ranges.ll
@@ -0,0 +1,132 @@
+; 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: ret i1 false
+;
+ %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: ret i1 false
+;
+ %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: ret i1 false
+;
+ %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, i8 %yy) {
+; CHECK-LABEL: @and_ugt(
+; CHECK-NEXT: ret i1 false
+;
+ %x = or i8 %xx, %yy
+ %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, i8 %yy) {
+; CHECK-LABEL: @and_ugt2(
+; CHECK-NEXT: ret i1 false
+;
+ %x = or i8 %xx, %yy
+ %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, i8 %yy) {
+; CHECK-LABEL: @and_ugt_fail(
+; CHECK-NEXT: [[X:%.*]] = or i8 [[XX:%.*]], [[YY:%.*]]
+; 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 = or i8 %xx, %yy
+ %negx = sub i8 0, %x
+ %x_p2 = and i8 %x, %negx
+ %r = icmp ugt i8 %x_p2, 127
+ ret i1 %r
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/68446
More information about the llvm-commits
mailing list