-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[InstCombine] Drop range attributes in foldIsPowerOf2
#111946
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-transforms Author: Yingwei Zheng (dtcxzyw) ChangesFixes #111934. Full diff: https://github.com/llvm/llvm-project/pull/111946.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 688601a8ffa543..964616a4eb35e2 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -955,9 +955,11 @@ static Value *foldIsPowerOf2OrZero(ICmpInst *Cmp0, ICmpInst *Cmp1, bool IsAnd,
}
/// Reduce a pair of compares that check if a value has exactly 1 bit set.
-/// Also used for logical and/or, must be poison safe.
+/// Also used for logical and/or, must be poison safe if range attributes are
+/// dropped.
static Value *foldIsPowerOf2(ICmpInst *Cmp0, ICmpInst *Cmp1, bool JoinedByAnd,
- InstCombiner::BuilderTy &Builder) {
+ InstCombiner::BuilderTy &Builder,
+ InstCombinerImpl &IC) {
// Handle 'and' / 'or' commutation: make the equality check the first operand.
if (JoinedByAnd && Cmp1->getPredicate() == ICmpInst::ICMP_NE)
std::swap(Cmp0, Cmp1);
@@ -971,7 +973,10 @@ static Value *foldIsPowerOf2(ICmpInst *Cmp0, ICmpInst *Cmp1, bool JoinedByAnd,
match(Cmp1, m_SpecificICmp(ICmpInst::ICMP_ULT,
m_Intrinsic<Intrinsic::ctpop>(m_Specific(X)),
m_SpecificInt(2)))) {
- Value *CtPop = Cmp1->getOperand(0);
+ auto *CtPop = cast<Instruction>(Cmp1->getOperand(0));
+ // Drop range attributes and re-infer them in the next iteration.
+ CtPop->dropPoisonGeneratingAnnotations();
+ IC.addToWorklist(CtPop);
return Builder.CreateICmpEQ(CtPop, ConstantInt::get(CtPop->getType(), 1));
}
// (X == 0) || (ctpop(X) u> 1) --> ctpop(X) != 1
@@ -980,7 +985,10 @@ static Value *foldIsPowerOf2(ICmpInst *Cmp0, ICmpInst *Cmp1, bool JoinedByAnd,
match(Cmp1, m_SpecificICmp(ICmpInst::ICMP_UGT,
m_Intrinsic<Intrinsic::ctpop>(m_Specific(X)),
m_SpecificInt(1)))) {
- Value *CtPop = Cmp1->getOperand(0);
+ auto *CtPop = cast<Instruction>(Cmp1->getOperand(0));
+ // Drop range attributes and re-infer them in the next iteration.
+ CtPop->dropPoisonGeneratingAnnotations();
+ IC.addToWorklist(CtPop);
return Builder.CreateICmpNE(CtPop, ConstantInt::get(CtPop->getType(), 1));
}
return nullptr;
@@ -3375,7 +3383,7 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
if (Value *V = foldSignedTruncationCheck(LHS, RHS, I, Builder))
return V;
- if (Value *V = foldIsPowerOf2(LHS, RHS, IsAnd, Builder))
+ if (Value *V = foldIsPowerOf2(LHS, RHS, IsAnd, Builder, *this))
return V;
if (Value *V = foldPowerOf2AndShiftedMask(LHS, RHS, IsAnd, Builder))
diff --git a/llvm/test/Transforms/InstCombine/ispow2.ll b/llvm/test/Transforms/InstCombine/ispow2.ll
index c21ad95f83a1c4..832c066370b0f8 100644
--- a/llvm/test/Transforms/InstCombine/ispow2.ll
+++ b/llvm/test/Transforms/InstCombine/ispow2.ll
@@ -1522,3 +1522,35 @@ define <2 x i1> @not_pow2_or_z_known_bits_fail_wrong_cmp(<2 x i32> %xin) {
%r = icmp ugt <2 x i32> %cnt, <i32 2, i32 2>
ret <2 x i1> %r
}
+
+; Make sure that range attributes on return values are dropped after merging these two icmps
+
+define i1 @has_single_bit(i32 %x) {
+; CHECK-LABEL: @has_single_bit(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[POPCNT:%.*]] = call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X:%.*]])
+; CHECK-NEXT: [[SEL:%.*]] = icmp eq i32 [[POPCNT]], 1
+; CHECK-NEXT: ret i1 [[SEL]]
+;
+entry:
+ %cmp1 = icmp ne i32 %x, 0
+ %popcnt = call range(i32 1, 33) i32 @llvm.ctpop.i32(i32 %x)
+ %cmp2 = icmp ult i32 %popcnt, 2
+ %sel = select i1 %cmp1, i1 %cmp2, i1 false
+ ret i1 %sel
+}
+
+define i1 @has_single_bit_inv(i32 %x) {
+; CHECK-LABEL: @has_single_bit_inv(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[POPCNT:%.*]] = call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X:%.*]])
+; CHECK-NEXT: [[SEL:%.*]] = icmp ne i32 [[POPCNT]], 1
+; CHECK-NEXT: ret i1 [[SEL]]
+;
+entry:
+ %cmp1 = icmp eq i32 %x, 0
+ %popcnt = call range(i32 1, 33) i32 @llvm.ctpop.i32(i32 %x)
+ %cmp2 = icmp ugt i32 %popcnt, 1
+ %sel = select i1 %cmp1, i1 true, i1 %cmp2
+ ret i1 %sel
+}
|
auto *CtPop = cast<Instruction>(Cmp1->getOperand(0)); | ||
// Drop range attributes and re-infer them in the next iteration. | ||
CtPop->dropPoisonGeneratingAnnotations(); | ||
IC.addToWorklist(CtPop); |
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.
Add ctpop to worklist to pass the fix-point verification.
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
/cherry-pick 6a65e98 |
Failed to cherry-pick: 6a65e98 https://github.com/llvm/llvm-project/actions/runs/11290628445 Please manually backport the fix and push it to your github fork. Once this is done, please create a pull request |
…/u> 2/1` (#111284)` (#111998) Relands #111284. Test failure with stage2 build has been fixed by #111946. Some targets have better codegen for `ctpop(X) u< 2` than `ctpop(X) == 1`. After #100899, we set the range of ctpop's return value to indicate the argument/result is non-zero. This patch converts `ctpop(X) ==/!= 1` into `ctpop(X) u</u> 2/1` in CGP to fix #95255.
…/u> 2/1` (llvm#111284)` (llvm#111998) Relands llvm#111284. Test failure with stage2 build has been fixed by llvm#111946. Some targets have better codegen for `ctpop(X) u< 2` than `ctpop(X) == 1`. After llvm#100899, we set the range of ctpop's return value to indicate the argument/result is non-zero. This patch converts `ctpop(X) ==/!= 1` into `ctpop(X) u</u> 2/1` in CGP to fix llvm#95255.
Fixes #111934.