-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[ValueTracking] Handle assume(trunc x to i1) in ComputeKnownBits #118406
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
Conversation
@llvm/pr-subscribers-llvm-analysis Author: Andreas Jonson (andjo403) ChangesHandle assume( trunc x to i1) in ComputeKnownBits and KnownNonZero to avoid regressions when converting more icmp to trunc as the #84628 remove the canonicalization part of #118104 Full diff: https://github.com/llvm/llvm-project/pull/118406.diff 5 Files Affected:
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index c48068afc04816..7b7eea027c82b9 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -612,11 +612,16 @@ static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) {
// Warning: This loop can end up being somewhat performance sensitive.
// We're running this loop for once for each value queried resulting in a
// runtime of ~O(#assumes * #values).
+ Value *Arg = I->getArgOperand(0);
+ if (match(Arg, m_TruncOrSelf(m_Specific(V))) &&
+ isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
+ return true;
+ }
Value *RHS;
CmpInst::Predicate Pred;
auto m_V = m_CombineOr(m_Specific(V), m_PtrToInt(m_Specific(V)));
- if (!match(I->getArgOperand(0), m_c_ICmp(Pred, m_V, m_Value(RHS))))
+ if (!match(Arg, m_c_ICmp(Pred, m_V, m_Value(RHS))))
continue;
if (cmpExcludesZero(Pred, RHS) && isValidAssumeForContext(I, Q.CxtI, Q.DT))
@@ -809,8 +814,6 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
if (!Q.AC)
return;
- unsigned BitWidth = Known.getBitWidth();
-
// Note that the patterns below need to be kept in sync with the code
// in AssumptionCache::updateAffectedValues.
@@ -844,17 +847,14 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
Value *Arg = I->getArgOperand(0);
- if (Arg == V && isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
- assert(BitWidth == 1 && "assume operand is not i1?");
- (void)BitWidth;
- Known.setAllOnes();
+ if (match(Arg, m_TruncOrSelf(m_Specific(V))) &&
+ isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
+ Known.One.setBit(0);
return;
}
- if (match(Arg, m_Not(m_Specific(V))) &&
+ if (match(Arg, m_Not(m_TruncOrSelf(m_Specific(V)))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
- assert(BitWidth == 1 && "assume operand is not i1?");
- (void)BitWidth;
- Known.setAllZero();
+ Known.Zero.setBit(0);
return;
}
diff --git a/llvm/test/Transforms/Attributor/lvi-after-jumpthreading.ll b/llvm/test/Transforms/Attributor/lvi-after-jumpthreading.ll
index 2aa95216a66569..fd9d2e4de61ba8 100644
--- a/llvm/test/Transforms/Attributor/lvi-after-jumpthreading.ll
+++ b/llvm/test/Transforms/Attributor/lvi-after-jumpthreading.ll
@@ -130,8 +130,6 @@ exit2:
ret i32 30
}
-; FIXME: We should be able to merge cont into do.
-; FIXME: COND should be replaced with false. This will be fixed by improving LVI.
define i32 @test4(i32 %i, i1 %f, i32 %n) {
; CHECK-LABEL: define {{[^@]+}}@test4
; CHECK-SAME: (i32 [[I:%.*]], i1 [[F:%.*]], i32 [[N:%.*]]) {
@@ -148,8 +146,7 @@ define i32 @test4(i32 %i, i1 %f, i32 %n) {
; CHECK-NEXT: call void @dummy(i1 [[F]]) #[[ATTR2]]
; CHECK-NEXT: [[CONSUME:%.*]] = call i32 @exit()
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[F]])
-; CHECK-NEXT: [[COND:%.*]] = icmp eq i1 [[F]], false
-; CHECK-NEXT: br i1 [[COND]], label [[EXIT]], label [[CONT:%.*]]
+; CHECK-NEXT: br label [[CONT:%.*]]
; CHECK: exit2:
; CHECK-NEXT: ret i32 30
;
diff --git a/llvm/test/Transforms/InstSimplify/assume-non-zero.ll b/llvm/test/Transforms/InstSimplify/assume-non-zero.ll
index 9176b8101da659..331c9504f2da6f 100644
--- a/llvm/test/Transforms/InstSimplify/assume-non-zero.ll
+++ b/llvm/test/Transforms/InstSimplify/assume-non-zero.ll
@@ -231,3 +231,16 @@ define i1 @nonnull17_unknown(i8 %x) {
%q = icmp ne i8 %x, 0
ret i1 %q
}
+
+define i1 @nonnull_trunc_true(i8 %x) {
+; CHECK-LABEL: @nonnull_trunc_true(
+; CHECK-NEXT: [[A:%.*]] = trunc i8 [[X:%.*]] to i1
+; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
+; CHECK-NEXT: ret i1 true
+;
+ %a = trunc i8 %x to i1
+ call void @llvm.assume(i1 %a)
+ %q = icmp ne i8 %x, 0
+ ret i1 %q
+}
+
diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll
index 21653d800dce2d..a2a8fe42e7583b 100644
--- a/llvm/test/Transforms/InstSimplify/compare.ll
+++ b/llvm/test/Transforms/InstSimplify/compare.ll
@@ -3424,6 +3424,20 @@ define i1 @icmp_ult_vscale_false(i8 %x, i8 %y) {
ret i1 %cmp
}
+define i1 @icmp_eq_false_by_trunc(i8 %x) {
+; CHECK-LABEL: @icmp_eq_false_by_trunc(
+; CHECK-NEXT: [[TRUNC:%.*]] = trunc i8 [[X:%.*]] to i1
+; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[TRUNC]], true
+; CHECK-NEXT: call void @llvm.assume(i1 [[NOT]])
+; CHECK-NEXT: ret i1 false
+;
+ %trunc = trunc i8 %x to i1
+ %not = xor i1 %trunc, true
+ call void @llvm.assume(i1 %not)
+ %cmp = icmp eq i8 %x, 1
+ ret i1 %cmp
+}
+
declare i64 @llvm.vscale.i64()
; TODO: Add coverage for global aliases, link once, etc..
diff --git a/llvm/test/Transforms/InstSimplify/shr-nop.ll b/llvm/test/Transforms/InstSimplify/shr-nop.ll
index 29fe222faaae3e..b18a1c6d30e745 100644
--- a/llvm/test/Transforms/InstSimplify/shr-nop.ll
+++ b/llvm/test/Transforms/InstSimplify/shr-nop.ll
@@ -381,6 +381,18 @@ define i32 @exact_lshr_lowbit(i32 %shiftval) {
ret i32 %shr
}
+define i8 @exact_lshr_lowbit_set_assume_trunc(i8 %x) {
+; CHECK-LABEL: @exact_lshr_lowbit_set_assume_trunc(
+; CHECK-NEXT: [[COND:%.*]] = trunc i8 [[X:%.*]] to i1
+; CHECK-NEXT: call void @llvm.assume(i1 [[COND]])
+; CHECK-NEXT: ret i8 [[X]]
+;
+ %cond = trunc i8 %x to i1
+ call void @llvm.assume(i1 %cond)
+ %shr = lshr exact i8 %x, 1
+ ret i8 %shr
+}
+
define i32 @exact_ashr_lowbit(i32 %shiftval) {
; CHECK-LABEL: @exact_ashr_lowbit(
; CHECK-NEXT: ret i32 7
|
@llvm/pr-subscribers-llvm-transforms Author: Andreas Jonson (andjo403) ChangesHandle assume( trunc x to i1) in ComputeKnownBits and KnownNonZero to avoid regressions when converting more icmp to trunc as the #84628 remove the canonicalization part of #118104 Full diff: https://github.com/llvm/llvm-project/pull/118406.diff 5 Files Affected:
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index c48068afc04816..7b7eea027c82b9 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -612,11 +612,16 @@ static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) {
// Warning: This loop can end up being somewhat performance sensitive.
// We're running this loop for once for each value queried resulting in a
// runtime of ~O(#assumes * #values).
+ Value *Arg = I->getArgOperand(0);
+ if (match(Arg, m_TruncOrSelf(m_Specific(V))) &&
+ isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
+ return true;
+ }
Value *RHS;
CmpInst::Predicate Pred;
auto m_V = m_CombineOr(m_Specific(V), m_PtrToInt(m_Specific(V)));
- if (!match(I->getArgOperand(0), m_c_ICmp(Pred, m_V, m_Value(RHS))))
+ if (!match(Arg, m_c_ICmp(Pred, m_V, m_Value(RHS))))
continue;
if (cmpExcludesZero(Pred, RHS) && isValidAssumeForContext(I, Q.CxtI, Q.DT))
@@ -809,8 +814,6 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
if (!Q.AC)
return;
- unsigned BitWidth = Known.getBitWidth();
-
// Note that the patterns below need to be kept in sync with the code
// in AssumptionCache::updateAffectedValues.
@@ -844,17 +847,14 @@ void llvm::computeKnownBitsFromContext(const Value *V, KnownBits &Known,
Value *Arg = I->getArgOperand(0);
- if (Arg == V && isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
- assert(BitWidth == 1 && "assume operand is not i1?");
- (void)BitWidth;
- Known.setAllOnes();
+ if (match(Arg, m_TruncOrSelf(m_Specific(V))) &&
+ isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
+ Known.One.setBit(0);
return;
}
- if (match(Arg, m_Not(m_Specific(V))) &&
+ if (match(Arg, m_Not(m_TruncOrSelf(m_Specific(V)))) &&
isValidAssumeForContext(I, Q.CxtI, Q.DT)) {
- assert(BitWidth == 1 && "assume operand is not i1?");
- (void)BitWidth;
- Known.setAllZero();
+ Known.Zero.setBit(0);
return;
}
diff --git a/llvm/test/Transforms/Attributor/lvi-after-jumpthreading.ll b/llvm/test/Transforms/Attributor/lvi-after-jumpthreading.ll
index 2aa95216a66569..fd9d2e4de61ba8 100644
--- a/llvm/test/Transforms/Attributor/lvi-after-jumpthreading.ll
+++ b/llvm/test/Transforms/Attributor/lvi-after-jumpthreading.ll
@@ -130,8 +130,6 @@ exit2:
ret i32 30
}
-; FIXME: We should be able to merge cont into do.
-; FIXME: COND should be replaced with false. This will be fixed by improving LVI.
define i32 @test4(i32 %i, i1 %f, i32 %n) {
; CHECK-LABEL: define {{[^@]+}}@test4
; CHECK-SAME: (i32 [[I:%.*]], i1 [[F:%.*]], i32 [[N:%.*]]) {
@@ -148,8 +146,7 @@ define i32 @test4(i32 %i, i1 %f, i32 %n) {
; CHECK-NEXT: call void @dummy(i1 [[F]]) #[[ATTR2]]
; CHECK-NEXT: [[CONSUME:%.*]] = call i32 @exit()
; CHECK-NEXT: call void @llvm.assume(i1 noundef [[F]])
-; CHECK-NEXT: [[COND:%.*]] = icmp eq i1 [[F]], false
-; CHECK-NEXT: br i1 [[COND]], label [[EXIT]], label [[CONT:%.*]]
+; CHECK-NEXT: br label [[CONT:%.*]]
; CHECK: exit2:
; CHECK-NEXT: ret i32 30
;
diff --git a/llvm/test/Transforms/InstSimplify/assume-non-zero.ll b/llvm/test/Transforms/InstSimplify/assume-non-zero.ll
index 9176b8101da659..331c9504f2da6f 100644
--- a/llvm/test/Transforms/InstSimplify/assume-non-zero.ll
+++ b/llvm/test/Transforms/InstSimplify/assume-non-zero.ll
@@ -231,3 +231,16 @@ define i1 @nonnull17_unknown(i8 %x) {
%q = icmp ne i8 %x, 0
ret i1 %q
}
+
+define i1 @nonnull_trunc_true(i8 %x) {
+; CHECK-LABEL: @nonnull_trunc_true(
+; CHECK-NEXT: [[A:%.*]] = trunc i8 [[X:%.*]] to i1
+; CHECK-NEXT: call void @llvm.assume(i1 [[A]])
+; CHECK-NEXT: ret i1 true
+;
+ %a = trunc i8 %x to i1
+ call void @llvm.assume(i1 %a)
+ %q = icmp ne i8 %x, 0
+ ret i1 %q
+}
+
diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll
index 21653d800dce2d..a2a8fe42e7583b 100644
--- a/llvm/test/Transforms/InstSimplify/compare.ll
+++ b/llvm/test/Transforms/InstSimplify/compare.ll
@@ -3424,6 +3424,20 @@ define i1 @icmp_ult_vscale_false(i8 %x, i8 %y) {
ret i1 %cmp
}
+define i1 @icmp_eq_false_by_trunc(i8 %x) {
+; CHECK-LABEL: @icmp_eq_false_by_trunc(
+; CHECK-NEXT: [[TRUNC:%.*]] = trunc i8 [[X:%.*]] to i1
+; CHECK-NEXT: [[NOT:%.*]] = xor i1 [[TRUNC]], true
+; CHECK-NEXT: call void @llvm.assume(i1 [[NOT]])
+; CHECK-NEXT: ret i1 false
+;
+ %trunc = trunc i8 %x to i1
+ %not = xor i1 %trunc, true
+ call void @llvm.assume(i1 %not)
+ %cmp = icmp eq i8 %x, 1
+ ret i1 %cmp
+}
+
declare i64 @llvm.vscale.i64()
; TODO: Add coverage for global aliases, link once, etc..
diff --git a/llvm/test/Transforms/InstSimplify/shr-nop.ll b/llvm/test/Transforms/InstSimplify/shr-nop.ll
index 29fe222faaae3e..b18a1c6d30e745 100644
--- a/llvm/test/Transforms/InstSimplify/shr-nop.ll
+++ b/llvm/test/Transforms/InstSimplify/shr-nop.ll
@@ -381,6 +381,18 @@ define i32 @exact_lshr_lowbit(i32 %shiftval) {
ret i32 %shr
}
+define i8 @exact_lshr_lowbit_set_assume_trunc(i8 %x) {
+; CHECK-LABEL: @exact_lshr_lowbit_set_assume_trunc(
+; CHECK-NEXT: [[COND:%.*]] = trunc i8 [[X:%.*]] to i1
+; CHECK-NEXT: call void @llvm.assume(i1 [[COND]])
+; CHECK-NEXT: ret i8 [[X]]
+;
+ %cond = trunc i8 %x to i1
+ call void @llvm.assume(i1 %cond)
+ %shr = lshr exact i8 %x, 1
+ ret i8 %shr
+}
+
define i32 @exact_ashr_lowbit(i32 %shiftval) {
; CHECK-LABEL: @exact_ashr_lowbit(
; CHECK-NEXT: ret i32 7
|
llvm/lib/Analysis/ValueTracking.cpp
Outdated
@@ -612,11 +612,16 @@ static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) { | |||
// Warning: This loop can end up being somewhat performance sensitive. | |||
// We're running this loop for once for each value queried resulting in a | |||
// runtime of ~O(#assumes * #values). | |||
Value *Arg = I->getArgOperand(0); | |||
if (match(Arg, m_TruncOrSelf(m_Specific(V))) && | |||
isValidAssumeForContext(I, Q.CxtI, Q.DT)) { |
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.
Looks like we hit another "ephemeral value" issue :(
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.
I do not know what issue you are thinking about is it something that is shown in the llvm-opt-benchmark?
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.
Yeah. The test diff shows it only removes some (unused?) assumptions.
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.
I do not know if there is that many assumptions like this right now but was looking at folding some icmp eq X, C to trunc X to i1 when X is known to be 0 or 1 and got lots of regressions due to this.
even if there maybe is problems with ephemeral values resulting in not all assumes is used, |
The problem is not that the assume isn't used, it's that the assume is used to simplify itself, removing the assume. |
a32a721
to
59efb40
Compare
Have removed the problematic fold, so this shall not have the "ephemeral value" issue anymore |
Have rebased and fixed the comments so this is ready for a new review. |
llvm/lib/Analysis/ValueTracking.cpp
Outdated
@@ -643,11 +643,16 @@ static bool isKnownNonZeroFromAssume(const Value *V, const SimplifyQuery &Q) { | |||
// Warning: This loop can end up being somewhat performance sensitive. | |||
// We're running this loop for once for each value queried resulting in a | |||
// runtime of ~O(#assumes * #values). | |||
Value *Arg = I->getArgOperand(0); |
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.
Which test covers this change? InstSimplify can fold the zero check in nonnull_trunc_true
even without the change to isKnownNonZeroFromAssume
.
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.
I'm not sure I understand if I remove this code the tests nonnull_trunc_true
and test4
fails
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.
However, InstCombine can simplify both of them after I removed the change to isKnownNonZeroFromAssume
.
(the original tests check InstSimplify/LVI instead).
Can you please spill isKnownNonZeroFromAssume
changes into a separate PR? Sorry for the inconvenience.
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.
sure I can split this PR to the two commits.
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.
@dtcxzyw this PR is only the ComputeKnownBits commit now |
Handle assume( trunc x to i1) in ComputeKnownBits to avoid regressions when converting more icmp to trunc as the #84628 remove the canonicalization
trunc x to i1 -> icmp ne (and x, 1), 0
proof: https://alive2.llvm.org/ce/z/zAspzb