Skip to content

Commit

Permalink
[InstCombine] Drop range attributes in foldIsPowerOf2 (llvm#111946)
Browse files Browse the repository at this point in the history
  • Loading branch information
dtcxzyw authored and DanielCChen committed Oct 16, 2024
1 parent bd8a11f commit a18ba76
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 5 deletions.
18 changes: 13 additions & 5 deletions llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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))
Expand Down
32 changes: 32 additions & 0 deletions llvm/test/Transforms/InstCombine/ispow2.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

0 comments on commit a18ba76

Please sign in to comment.