-
Notifications
You must be signed in to change notification settings - Fork 11.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ConstantRange] Improve ConstantRange::binaryXor #80146
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Yingwei Zheng (dtcxzyw) Changes
Alive2: https://alive2.llvm.org/ce/z/bmTMV9 Full diff: https://github.com/llvm/llvm-project/pull/80146.diff 2 Files Affected:
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
new file mode 100644
index 0000000000000..a860112d5ef36
--- /dev/null
+++ b/llvm/test/Transforms/SCCP/pr79696.ll
@@ -0,0 +1,55 @@
+; 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: ret i1 false
+; 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
+}
|
@llvm/pr-subscribers-llvm-ir Author: Yingwei Zheng (dtcxzyw) Changes
Alive2: https://alive2.llvm.org/ce/z/bmTMV9 Full diff: https://github.com/llvm/llvm-project/pull/80146.diff 2 Files Affected:
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
new file mode 100644
index 0000000000000..a860112d5ef36
--- /dev/null
+++ b/llvm/test/Transforms/SCCP/pr79696.ll
@@ -0,0 +1,55 @@
+; 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: ret i1 false
+; 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
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For ConstantRange changes, please always add unit tests in ConstantRangeTest.
835946b
to
02a8a2e
Compare
Ping. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
ConstantRange::binaryXor
gives poor results as it currently depends onKnownBits::operator^
.Since
sub A, B
is canonicalized intoxor A, B
ifB
is the subset ofA
, this patch reverts the transform inConstantRange::binaryXor
, which will give better results.Alive2: https://alive2.llvm.org/ce/z/bmTMV9
Fixes #79696.