From: Craig Topper Date: Mon, 8 May 2017 17:22:34 +0000 (+0000) Subject: [ValueTracking] Use KnownOnes to provide a better bound on known zeros for ctlz/cttz... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d99549318e64675c75c2ecad2abc73b54fb730ec;p=llvm [ValueTracking] Use KnownOnes to provide a better bound on known zeros for ctlz/cttz intrinics This patch uses KnownOnes of the input of ctlz/cttz to bound the value that can be returned from these intrinsics. This makes these intrinsics more similar to the handling for ctpop which already uses known bits to produce a similar bound. Differential Revision: https://reviews.llvm.org/D32521 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@302444 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index 7a0cb28ea46..39a92066a48 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -1392,12 +1392,25 @@ static void computeKnownBitsFromOperator(const Operator *I, KnownBits &Known, Known.Zero |= Known2.Zero.byteSwap(); Known.One |= Known2.One.byteSwap(); break; - case Intrinsic::ctlz: + case Intrinsic::ctlz: { + computeKnownBits(I->getOperand(0), Known2, Depth + 1, Q); + // If we have a known 1, its position is our upper bound. + unsigned PossibleLZ = Known2.One.countLeadingZeros(); + // If this call is undefined for 0, the result will be less than 2^n. + if (II->getArgOperand(1) == ConstantInt::getTrue(II->getContext())) + PossibleLZ = std::min(PossibleLZ, BitWidth - 1); + unsigned LowBits = Log2_32(PossibleLZ)+1; + Known.Zero.setBitsFrom(LowBits); + break; + } case Intrinsic::cttz: { - unsigned LowBits = Log2_32(BitWidth)+1; + computeKnownBits(I->getOperand(0), Known2, Depth + 1, Q); + // If we have a known 1, its position is our upper bound. + unsigned PossibleTZ = Known2.One.countTrailingZeros(); // If this call is undefined for 0, the result will be less than 2^n. if (II->getArgOperand(1) == ConstantInt::getTrue(II->getContext())) - LowBits -= 1; + PossibleTZ = std::min(PossibleTZ, BitWidth - 1); + unsigned LowBits = Log2_32(PossibleTZ)+1; Known.Zero.setBitsFrom(LowBits); break; } diff --git a/test/Transforms/InstCombine/intrinsics.ll b/test/Transforms/InstCombine/intrinsics.ll index 66ab7f48aef..5654b265da5 100644 --- a/test/Transforms/InstCombine/intrinsics.ll +++ b/test/Transforms/InstCombine/intrinsics.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -instcombine -S < %s | FileCheck %s %overflow.result = type {i8, i1} @@ -283,14 +284,24 @@ define i32 @cttz(i32 %a) { define i1 @cttz_knownbits(i32 %arg) { ; CHECK-LABEL: @cttz_knownbits( +; CHECK-NEXT: ret i1 false +; + %or = or i32 %arg, 4 + %cnt = call i32 @llvm.cttz.i32(i32 %or, i1 true) nounwind readnone + %res = icmp eq i32 %cnt, 4 + ret i1 %res +} + +define i1 @cttz_knownbits2(i32 %arg) { +; CHECK-LABEL: @cttz_knownbits2( ; CHECK-NEXT: [[OR:%.*]] = or i32 [[ARG:%.*]], 4 ; CHECK-NEXT: [[CNT:%.*]] = call i32 @llvm.cttz.i32(i32 [[OR]], i1 true) -; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[CNT]], 4 +; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[CNT]], 2 ; CHECK-NEXT: ret i1 [[RES]] ; %or = or i32 %arg, 4 %cnt = call i32 @llvm.cttz.i32(i32 %or, i1 true) nounwind readnone - %res = icmp eq i32 %cnt, 4 + %res = icmp eq i32 %cnt, 2 ret i1 %res } @@ -306,14 +317,24 @@ define i8 @ctlz(i8 %a) { define i1 @ctlz_knownbits(i8 %arg) { ; CHECK-LABEL: @ctlz_knownbits( +; CHECK-NEXT: ret i1 false +; + %or = or i8 %arg, 32 + %cnt = call i8 @llvm.ctlz.i8(i8 %or, i1 true) nounwind readnone + %res = icmp eq i8 %cnt, 4 + ret i1 %res +} + +define i1 @ctlz_knownbits2(i8 %arg) { +; CHECK-LABEL: @ctlz_knownbits2( ; CHECK-NEXT: [[OR:%.*]] = or i8 [[ARG:%.*]], 32 ; CHECK-NEXT: [[CNT:%.*]] = call i8 @llvm.ctlz.i8(i8 [[OR]], i1 true) -; CHECK-NEXT: [[RES:%.*]] = icmp eq i8 [[CNT]], 4 +; CHECK-NEXT: [[RES:%.*]] = icmp eq i8 [[CNT]], 2 ; CHECK-NEXT: ret i1 [[RES]] ; %or = or i8 %arg, 32 %cnt = call i8 @llvm.ctlz.i8(i8 %or, i1 true) nounwind readnone - %res = icmp eq i8 %cnt, 4 + %res = icmp eq i8 %cnt, 2 ret i1 %res }