diff --git a/llvm/include/llvm/Analysis/DemandedBits.h b/llvm/include/llvm/Analysis/DemandedBits.h --- a/llvm/include/llvm/Analysis/DemandedBits.h +++ b/llvm/include/llvm/Analysis/DemandedBits.h @@ -53,6 +53,9 @@ /// accepted, but will always produce a mask with all bits set. APInt getDemandedBits(Instruction *I); + /// Return the bits demanded from use U. + APInt getDemandedBits(Use *U); + /// Return true if, during analysis, I could not be reached. bool isInstructionDead(Instruction *I); diff --git a/llvm/lib/Analysis/DemandedBits.cpp b/llvm/lib/Analysis/DemandedBits.cpp --- a/llvm/lib/Analysis/DemandedBits.cpp +++ b/llvm/lib/Analysis/DemandedBits.cpp @@ -452,6 +452,33 @@ DL.getTypeSizeInBits(I->getType()->getScalarType())); } +APInt DemandedBits::getDemandedBits(Use *U) { + Type *T = (*U)->getType(); + Instruction *UserI = cast(U->getUser()); + const DataLayout &DL = UserI->getModule()->getDataLayout(); + unsigned BitWidth = DL.getTypeSizeInBits(T->getScalarType()); + + // We only track integer uses, everything else produces a mask with all bits + // set + if (!T->isIntOrIntVectorTy()) + return APInt::getAllOnesValue(BitWidth); + + if (isUseDead(U)) + return APInt(BitWidth, 0); + + performAnalysis(); + + APInt AOut = getDemandedBits(UserI); + APInt AB = APInt::getAllOnesValue(BitWidth); + KnownBits Known, Known2; + bool KnownBitsComputed = false; + + determineLiveOperandBits(UserI, *U, U->getOperandNo(), AOut, AB, Known, + Known2, KnownBitsComputed); + + return AB; +} + bool DemandedBits::isInstructionDead(Instruction *I) { performAnalysis(); @@ -485,10 +512,24 @@ } void DemandedBits::print(raw_ostream &OS) { + auto PrintDB = [&](const Instruction *I, const APInt &A, Value *V = nullptr) { + OS << "DemandedBits: 0x" << Twine::utohexstr(A.getLimitedValue()) + << " for "; + if (V) { + V->printAsOperand(OS, false); + OS << " in "; + } + OS << *I << '\n'; + }; + performAnalysis(); for (auto &KV : AliveBits) { - OS << "DemandedBits: 0x" << Twine::utohexstr(KV.second.getLimitedValue()) - << " for " << *KV.first << '\n'; + Instruction *I = KV.first; + PrintDB(I, KV.second); + + for (Use &OI : I->operands()) { + PrintDB(I, getDemandedBits(&OI), OI); + } } } diff --git a/llvm/test/Analysis/DemandedBits/basic.ll b/llvm/test/Analysis/DemandedBits/basic.ll --- a/llvm/test/Analysis/DemandedBits/basic.ll +++ b/llvm/test/Analysis/DemandedBits/basic.ll @@ -4,9 +4,24 @@ ; CHECK-DAG: DemandedBits: 0xff for %1 = add nsw i32 %a, 5 ; CHECK-DAG: DemandedBits: 0xff for %3 = trunc i32 %2 to i8 ; CHECK-DAG: DemandedBits: 0xff for %2 = mul nsw i32 %1, %b +; CHECK-DAG: DemandedBits: 0x1 for %4 = trunc i32 %2 to i1 +; CHECK-DAG: DemandedBits: 0xff for %5 = zext i1 %4 to i8 +; CHECK-DAG: DemandedBits: 0xff for %6 = add nsw i8 %3, %5 +; CHECK-DAG: DemandedBits: 0xff for %a in %1 = add nsw i32 %a, 5 +; CHECK-DAG: DemandedBits: 0xff for 5 in %1 = add nsw i32 %a, 5 +; CHECK-DAG: DemandedBits: 0xff for %1 in %2 = mul nsw i32 %1, %b +; CHECK-DAG: DemandedBits: 0xff for %b in %2 = mul nsw i32 %1, %b +; CHECK-DAG: DemandedBits: 0xff for %2 in %3 = trunc i32 %2 to i8 +; CHECK-DAG: DemandedBits: 0x1 for %2 in %4 = trunc i32 %2 to i1 +; CHECK-DAG: DemandedBits: 0x1 for %4 in %5 = zext i1 %4 to i8 +; CHECK-DAG: DemandedBits: 0xff for %3 in %6 = add nsw i8 %3, %5 +; CHECK-DAG: DemandedBits: 0xff for %5 in %6 = add nsw i8 %3, %5 define i8 @test_mul(i32 %a, i32 %b) { %1 = add nsw i32 %a, 5 %2 = mul nsw i32 %1, %b %3 = trunc i32 %2 to i8 - ret i8 %3 + %4 = trunc i32 %2 to i1 + %5 = zext i1 %4 to i8 + %6 = add nsw i8 %3, %5 + ret i8 %6 }