Skip to content

Commit

Permalink
[InstCombine] Relax cttz/ctlz with select on zero
Browse files Browse the repository at this point in the history
The cttz/ctlz intrinsics have a parameter specifying whether the
result is undefined for zero. cttz(x, false) can be relaxed to
cttz(x, true) if x is known non-zero, and in fact such an optimization
is already performed. However, this currently doesn't work if x is
non-zero as a result of a select rather than an explicit branch.
This patch adds handling for this case, thus allowing
x != 0 ? cttz(x, false) : y to simplify to x != 0 ? cttz(x, true) : y.

Differential Revision: https://reviews.llvm.org/D55786

llvm-svn: 350463
  • Loading branch information
nikic committed Jan 5, 2019
1 parent 7bd4900 commit 6503851
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 12 deletions.
23 changes: 15 additions & 8 deletions llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
Expand Up @@ -709,24 +709,31 @@ static Value *foldSelectCttzCtlz(ICmpInst *ICI, Value *TrueVal, Value *FalseVal,
match(Count, m_Trunc(m_Value(V))))
Count = V;

// Check that 'Count' is a call to intrinsic cttz/ctlz. Also check that the
// input to the cttz/ctlz is used as LHS for the compare instruction.
if (!match(Count, m_Intrinsic<Intrinsic::cttz>(m_Specific(CmpLHS))) &&
!match(Count, m_Intrinsic<Intrinsic::ctlz>(m_Specific(CmpLHS))))
return nullptr;

IntrinsicInst *II = cast<IntrinsicInst>(Count);

// Check if the value propagated on zero is a constant number equal to the
// sizeof in bits of 'Count'.
unsigned SizeOfInBits = Count->getType()->getScalarSizeInBits();
if (!match(ValueOnZero, m_SpecificInt(SizeOfInBits)))
return nullptr;

// Check that 'Count' is a call to intrinsic cttz/ctlz. Also check that the
// input to the cttz/ctlz is used as LHS for the compare instruction.
if (match(Count, m_Intrinsic<Intrinsic::cttz>(m_Specific(CmpLHS))) ||
match(Count, m_Intrinsic<Intrinsic::ctlz>(m_Specific(CmpLHS)))) {
IntrinsicInst *II = cast<IntrinsicInst>(Count);
if (match(ValueOnZero, m_SpecificInt(SizeOfInBits))) {
// Explicitly clear the 'undef_on_zero' flag.
IntrinsicInst *NewI = cast<IntrinsicInst>(II->clone());
NewI->setArgOperand(1, ConstantInt::getFalse(NewI->getContext()));
Builder.Insert(NewI);
return Builder.CreateZExtOrTrunc(NewI, ValueOnZero->getType());
}

// If the ValueOnZero is not the bitwidth, we can at least make use of the
// fact that the cttz/ctlz result will not be used if the input is zero, so
// it's okay to relax it to undef for that case.
if (II->hasOneUse() && !match(II->getArgOperand(1), m_One()))
II->setArgOperand(1, ConstantInt::getTrue(II->getContext()));

return nullptr;
}

Expand Down
8 changes: 4 additions & 4 deletions llvm/test/Transforms/InstCombine/select-cmp-cttz-ctlz.ll
Expand Up @@ -345,7 +345,7 @@ define i128 @test8(i128 %x) {

define i32 @test_ctlz_not_bw(i32 %x) {
; CHECK-LABEL: @test_ctlz_not_bw(
; CHECK-NEXT: [[CT:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 false), !range !1
; CHECK-NEXT: [[CT:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 true), !range !1
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X]], 0
; CHECK-NEXT: [[RES:%.*]] = select i1 [[CMP]], i32 123, i32 [[CT]]
; CHECK-NEXT: ret i32 [[RES]]
Expand Down Expand Up @@ -373,7 +373,7 @@ define i32 @test_ctlz_not_bw_multiuse(i32 %x) {

define i32 @test_cttz_not_bw(i32 %x) {
; CHECK-LABEL: @test_cttz_not_bw(
; CHECK-NEXT: [[CT:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 false), !range !1
; CHECK-NEXT: [[CT:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 true), !range !1
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X]], 0
; CHECK-NEXT: [[RES:%.*]] = select i1 [[CMP]], i32 123, i32 [[CT]]
; CHECK-NEXT: ret i32 [[RES]]
Expand Down Expand Up @@ -412,7 +412,7 @@ define <2 x i32> @test_ctlz_bw_vec(<2 x i32> %x) {

define <2 x i32> @test_ctlz_not_bw_vec(<2 x i32> %x) {
; CHECK-LABEL: @test_ctlz_not_bw_vec(
; CHECK-NEXT: [[CT:%.*]] = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> [[X:%.*]], i1 false)
; CHECK-NEXT: [[CT:%.*]] = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> [[X:%.*]], i1 true)
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[X]], zeroinitializer
; CHECK-NEXT: [[RES:%.*]] = select <2 x i1> [[CMP]], <2 x i32> zeroinitializer, <2 x i32> [[CT]]
; CHECK-NEXT: ret <2 x i32> [[RES]]
Expand All @@ -436,7 +436,7 @@ define <2 x i32> @test_cttz_bw_vec(<2 x i32> %x) {

define <2 x i32> @test_cttz_not_bw_vec(<2 x i32> %x) {
; CHECK-LABEL: @test_cttz_not_bw_vec(
; CHECK-NEXT: [[CT:%.*]] = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> [[X:%.*]], i1 false)
; CHECK-NEXT: [[CT:%.*]] = tail call <2 x i32> @llvm.cttz.v2i32(<2 x i32> [[X:%.*]], i1 true)
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[X]], zeroinitializer
; CHECK-NEXT: [[RES:%.*]] = select <2 x i1> [[CMP]], <2 x i32> zeroinitializer, <2 x i32> [[CT]]
; CHECK-NEXT: ret <2 x i32> [[RES]]
Expand Down

0 comments on commit 6503851

Please sign in to comment.