[llvm] [ConstantRange] Improve ConstantRange::binaryXor (PR #80146)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Sat Feb 3 22:13:52 PST 2024
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/80146
>From 991c976e4dadf2bc84edda85e1317dd18960e796 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 31 Jan 2024 22:12:38 +0800
Subject: [PATCH 1/3] [ConstantRange] Add pre-commit tests. NFC.
---
llvm/test/Transforms/SCCP/pr79696.ll | 56 ++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
create mode 100644 llvm/test/Transforms/SCCP/pr79696.ll
diff --git a/llvm/test/Transforms/SCCP/pr79696.ll b/llvm/test/Transforms/SCCP/pr79696.ll
new file mode 100644
index 0000000000000..58529b8900c34
--- /dev/null
+++ b/llvm/test/Transforms/SCCP/pr79696.ll
@@ -0,0 +1,56 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt < %s -passes=ipsccp -S | FileCheck %s
+
+; Tests from PR79696
+
+define i1 @constant_range_xor(i64 %a) {
+; CHECK-LABEL: define i1 @constant_range_xor(
+; CHECK-SAME: i64 [[A:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[A]], 8192
+; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK: then:
+; CHECK-NEXT: [[CTLZ:%.*]] = call i64 @llvm.ctlz.i64(i64 [[A]], i1 true)
+; CHECK-NEXT: [[CONV:%.*]] = xor i64 [[CTLZ]], 63
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i64 [[CONV]], 13
+; CHECK-NEXT: ret i1 [[CMP1]]
+; CHECK: else:
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %cmp = icmp ugt i64 %a, 8192
+ br i1 %cmp, label %then, label %else
+then:
+ %ctlz = call i64 @llvm.ctlz.i64(i64 %a, i1 true) ;[0, 50]
+ %conv = xor i64 %ctlz, 63 ;[13, 63]
+ %cmp1 = icmp ult i64 %conv, 13
+ ret i1 %cmp1
+else:
+ ret i1 false
+}
+
+define i1 @constant_range_xor_negative(i64 %a) {
+; CHECK-LABEL: define i1 @constant_range_xor_negative(
+; CHECK-SAME: i64 [[A:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[A]], 8192
+; CHECK-NEXT: br i1 [[CMP]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK: then:
+; CHECK-NEXT: [[CTLZ:%.*]] = call i64 @llvm.ctlz.i64(i64 [[A]], i1 true)
+; CHECK-NEXT: [[CONV:%.*]] = xor i64 [[CTLZ]], 62
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i64 [[CONV]], 13
+; CHECK-NEXT: ret i1 [[CMP1]]
+; CHECK: else:
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %cmp = icmp ugt i64 %a, 8192
+ br i1 %cmp, label %then, label %else
+then:
+ %ctlz = call i64 @llvm.ctlz.i64(i64 %a, i1 true) ;[0, 50]
+ %conv = xor i64 %ctlz, 62 ;[12, 63]
+ %cmp1 = icmp ult i64 %conv, 13
+ ret i1 %cmp1
+else:
+ ret i1 false
+}
>From 3909948a8ef954224d6404c76837b05cfb61da10 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 31 Jan 2024 22:15:46 +0800
Subject: [PATCH 2/3] [ConstantRange] Improve ConstantRange::binaryXor
---
llvm/lib/IR/ConstantRange.cpp | 23 ++++++++++++++++++++++-
llvm/test/Transforms/SCCP/pr79696.ll | 3 +--
2 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index cbb64b299e648..f951bd9b8354d 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -1467,7 +1467,28 @@ ConstantRange ConstantRange::binaryXor(const ConstantRange &Other) const {
if (isSingleElement() && getSingleElement()->isAllOnes())
return Other.binaryNot();
- return fromKnownBits(toKnownBits() ^ Other.toKnownBits(), /*IsSigned*/false);
+ KnownBits LHSKnown = toKnownBits();
+ KnownBits RHSKnown = Other.toKnownBits();
+ KnownBits Known = LHSKnown ^ RHSKnown;
+ ConstantRange CR = fromKnownBits(Known, /*IsSigned*/ false);
+ // Typically the following code doesn't improve the result if BW = 1.
+ if (getBitWidth() == 1)
+ return CR;
+
+ // If LHS is known to be the subset of RHS, treat LHS ^ RHS as RHS -nuw/nsw
+ // LHS. If RHS is known to be the subset of LHS, treat LHS ^ RHS as LHS
+ // -nuw/nsw RHS.
+ if (LHSKnown.getMaxValue().isSubsetOf(RHSKnown.getMinValue()))
+ CR = CR.intersectWith(
+ Other.subWithNoWrap(*this, OverflowingBinaryOperator::NoUnsignedWrap |
+ OverflowingBinaryOperator::NoSignedWrap),
+ PreferredRangeType::Unsigned);
+ else if (RHSKnown.getMaxValue().isSubsetOf(LHSKnown.getMinValue()))
+ CR = CR.intersectWith(
+ subWithNoWrap(Other, OverflowingBinaryOperator::NoUnsignedWrap |
+ OverflowingBinaryOperator::NoSignedWrap),
+ PreferredRangeType::Unsigned);
+ return CR;
}
ConstantRange
diff --git a/llvm/test/Transforms/SCCP/pr79696.ll b/llvm/test/Transforms/SCCP/pr79696.ll
index 58529b8900c34..a860112d5ef36 100644
--- a/llvm/test/Transforms/SCCP/pr79696.ll
+++ b/llvm/test/Transforms/SCCP/pr79696.ll
@@ -12,8 +12,7 @@ define i1 @constant_range_xor(i64 %a) {
; CHECK: then:
; CHECK-NEXT: [[CTLZ:%.*]] = call i64 @llvm.ctlz.i64(i64 [[A]], i1 true)
; CHECK-NEXT: [[CONV:%.*]] = xor i64 [[CTLZ]], 63
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i64 [[CONV]], 13
-; CHECK-NEXT: ret i1 [[CMP1]]
+; CHECK-NEXT: ret i1 false
; CHECK: else:
; CHECK-NEXT: ret i1 false
;
>From 02a8a2e4bf2fb2cbcce7512bc24e0542c590b500 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 4 Feb 2024 14:12:32 +0800
Subject: [PATCH 3/3] fixup! [ConstantRange] Improve ConstantRange::binaryXor
Address review comments.
---
llvm/lib/IR/ConstantRange.cpp | 14 ++++----------
llvm/unittests/IR/ConstantRangeTest.cpp | 6 ++++++
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index f951bd9b8354d..3394a1ec8dc47 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -1478,16 +1478,10 @@ ConstantRange ConstantRange::binaryXor(const ConstantRange &Other) const {
// If LHS is known to be the subset of RHS, treat LHS ^ RHS as RHS -nuw/nsw
// LHS. If RHS is known to be the subset of LHS, treat LHS ^ RHS as LHS
// -nuw/nsw RHS.
- if (LHSKnown.getMaxValue().isSubsetOf(RHSKnown.getMinValue()))
- CR = CR.intersectWith(
- Other.subWithNoWrap(*this, OverflowingBinaryOperator::NoUnsignedWrap |
- OverflowingBinaryOperator::NoSignedWrap),
- PreferredRangeType::Unsigned);
- else if (RHSKnown.getMaxValue().isSubsetOf(LHSKnown.getMinValue()))
- CR = CR.intersectWith(
- subWithNoWrap(Other, OverflowingBinaryOperator::NoUnsignedWrap |
- OverflowingBinaryOperator::NoSignedWrap),
- PreferredRangeType::Unsigned);
+ if ((~LHSKnown.Zero).isSubsetOf(RHSKnown.One))
+ CR = CR.intersectWith(Other.sub(*this), PreferredRangeType::Unsigned);
+ else if ((~RHSKnown.Zero).isSubsetOf(LHSKnown.One))
+ CR = CR.intersectWith(this->sub(Other), PreferredRangeType::Unsigned);
return CR;
}
diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp
index e505af5d3275e..34a162a5514e9 100644
--- a/llvm/unittests/IR/ConstantRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeTest.cpp
@@ -2565,6 +2565,12 @@ TEST_F(ConstantRangeTest, binaryXor) {
EXPECT_EQ(R16_35.binaryXor(R0_99), ConstantRange(APInt(8, 0), APInt(8, 128)));
EXPECT_EQ(R0_99.binaryXor(R16_35), ConstantRange(APInt(8, 0), APInt(8, 128)));
+ // Treat xor A, B as sub nsw nuw A, B
+ ConstantRange R0_51(APInt(8, 0), APInt(8, 51));
+ ConstantRange R63(APInt(8, 63));
+ EXPECT_EQ(R0_51.binaryXor(R63), ConstantRange(APInt(8, 13), APInt(8, 64)));
+ EXPECT_EQ(R63.binaryXor(R0_51), ConstantRange(APInt(8, 13), APInt(8, 64)));
+
TestBinaryOpExhaustive(
[](const ConstantRange &CR1, const ConstantRange &CR2) {
return CR1.binaryXor(CR2);
More information about the llvm-commits
mailing list