#include "llvm/Analysis/DemandedBits.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define DEBUG_TYPE "demanded-bits"
char DemandedBits::ID = 0;
INITIALIZE_PASS_BEGIN(DemandedBits, "demanded-bits", "Demanded bits analysis",
false, false)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_END(DemandedBits, "demanded-bits", "Demanded bits analysis",
false, false)
DemandedBits::DemandedBits() : FunctionPass(ID), F(nullptr), Analyzed(false) {
initializeDemandedBitsPass(*PassRegistry::getPassRegistry());
}
void DemandedBits::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
AU.addRequired<AssumptionCacheTracker>();
AU.addRequired<DominatorTreeWrapperPass>();
AU.setPreservesAll();
}
static bool isAlwaysLive(Instruction *I) {
return isa<TerminatorInst>(I) || isa<DbgInfoIntrinsic>(I) ||
I->isEHPad() || I->mayHaveSideEffects();
}
void DemandedBits::determineLiveOperandBits(
const Instruction *UserI, const Instruction *I, unsigned OperandNo,
const APInt &AOut, APInt &AB, APInt &KnownZero, APInt &KnownOne,
APInt &KnownZero2, APInt &KnownOne2) {
unsigned BitWidth = AB.getBitWidth();
auto ComputeKnownBits =
[&](unsigned BitWidth, const Value *V1, const Value *V2) {
const DataLayout &DL = I->getModule()->getDataLayout();
KnownZero = APInt(BitWidth, 0);
KnownOne = APInt(BitWidth, 0);
computeKnownBits(const_cast<Value *>(V1), KnownZero, KnownOne, DL, 0,
AC, UserI, DT);
if (V2) {
KnownZero2 = APInt(BitWidth, 0);
KnownOne2 = APInt(BitWidth, 0);
computeKnownBits(const_cast<Value *>(V2), KnownZero2, KnownOne2, DL,
0, AC, UserI, DT);
}
};
switch (UserI->getOpcode()) {
default: break;
case Instruction::Call:
case Instruction::Invoke:
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(UserI))
switch (II->getIntrinsicID()) {
default: break;
case Intrinsic::bswap:
AB = AOut.byteSwap();
break;
case Intrinsic::ctlz:
if (OperandNo == 0) {
ComputeKnownBits(BitWidth, I, nullptr);
AB = APInt::getHighBitsSet(BitWidth,
std::min(BitWidth, KnownOne.countLeadingZeros()+1));
}
break;
case Intrinsic::cttz:
if (OperandNo == 0) {
ComputeKnownBits(BitWidth, I, nullptr);
AB = APInt::getLowBitsSet(BitWidth,
std::min(BitWidth, KnownOne.countTrailingZeros()+1));
}
break;
}
break;
case Instruction::Add:
case Instruction::Sub:
case Instruction::Mul:
AB = APInt::getLowBitsSet(BitWidth, AOut.getActiveBits());
break;
case Instruction::Shl:
if (OperandNo == 0)
if (ConstantInt *CI =
dyn_cast<ConstantInt>(UserI->getOperand(1))) {
uint64_t ShiftAmt = CI->getLimitedValue(BitWidth-1);
AB = AOut.lshr(ShiftAmt);
const ShlOperator *S = cast<ShlOperator>(UserI);
if (S->hasNoSignedWrap())
AB |= APInt::getHighBitsSet(BitWidth, ShiftAmt+1);
else if (S->hasNoUnsignedWrap())
AB |= APInt::getHighBitsSet(BitWidth, ShiftAmt);
}
break;
case Instruction::LShr:
if (OperandNo == 0)
if (ConstantInt *CI =
dyn_cast<ConstantInt>(UserI->getOperand(1))) {
uint64_t ShiftAmt = CI->getLimitedValue(BitWidth-1);
AB = AOut.shl(ShiftAmt);
if (cast<LShrOperator>(UserI)->isExact())
AB |= APInt::getLowBitsSet(BitWidth, ShiftAmt);
}
break;
case Instruction::AShr:
if (OperandNo == 0)
if (ConstantInt *CI =
dyn_cast<ConstantInt>(UserI->getOperand(1))) {
uint64_t ShiftAmt = CI->getLimitedValue(BitWidth-1);
AB = AOut.shl(ShiftAmt);
if ((AOut & APInt::getHighBitsSet(BitWidth, ShiftAmt))
.getBoolValue())
AB.setBit(BitWidth-1);
if (cast<AShrOperator>(UserI)->isExact())
AB |= APInt::getLowBitsSet(BitWidth, ShiftAmt);
}
break;
case Instruction::And:
AB = AOut;
if (OperandNo == 0) {
ComputeKnownBits(BitWidth, I, UserI->getOperand(1));
AB &= ~KnownZero2;
} else {
if (!isa<Instruction>(UserI->getOperand(0)))
ComputeKnownBits(BitWidth, UserI->getOperand(0), I);
AB &= ~(KnownZero & ~KnownZero2);
}
break;
case Instruction::Or:
AB = AOut;
if (OperandNo == 0) {
ComputeKnownBits(BitWidth, I, UserI->getOperand(1));
AB &= ~KnownOne2;
} else {
if (!isa<Instruction>(UserI->getOperand(0)))
ComputeKnownBits(BitWidth, UserI->getOperand(0), I);
AB &= ~(KnownOne & ~KnownOne2);
}
break;
case Instruction::Xor:
case Instruction::PHI:
AB = AOut;
break;
case Instruction::Trunc:
AB = AOut.zext(BitWidth);
break;
case Instruction::ZExt:
AB = AOut.trunc(BitWidth);
break;
case Instruction::SExt:
AB = AOut.trunc(BitWidth);
if ((AOut & APInt::getHighBitsSet(AOut.getBitWidth(),
AOut.getBitWidth() - BitWidth))
.getBoolValue())
AB.setBit(BitWidth-1);
break;
case Instruction::Select:
if (OperandNo != 0)
AB = AOut;
break;
}
}
bool DemandedBits::runOnFunction(Function& Fn) {
F = &Fn;
Analyzed = false;
return false;
}
void DemandedBits::performAnalysis() {
if (Analyzed)
return;
Analyzed = true;
AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(*F);
DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
Visited.clear();
AliveBits.clear();
SmallVector<Instruction*, 128> Worklist;
for (Instruction &I : instructions(*F)) {
if (!isAlwaysLive(&I))
continue;
DEBUG(dbgs() << "DemandedBits: Root: " << I << "\n");
if (IntegerType *IT = dyn_cast<IntegerType>(I.getType())) {
if (!AliveBits.count(&I)) {
AliveBits[&I] = APInt(IT->getBitWidth(), 0);
Worklist.push_back(&I);
}
continue;
}
for (Use &OI : I.operands()) {
if (Instruction *J = dyn_cast<Instruction>(OI)) {
if (IntegerType *IT = dyn_cast<IntegerType>(J->getType()))
AliveBits[J] = APInt::getAllOnesValue(IT->getBitWidth());
Worklist.push_back(J);
}
}
}
while (!Worklist.empty()) {
Instruction *UserI = Worklist.pop_back_val();
DEBUG(dbgs() << "DemandedBits: Visiting: " << *UserI);
APInt AOut;
if (UserI->getType()->isIntegerTy()) {
AOut = AliveBits[UserI];
DEBUG(dbgs() << " Alive Out: " << AOut);
}
DEBUG(dbgs() << "\n");
if (!UserI->getType()->isIntegerTy())
Visited.insert(UserI);
APInt KnownZero, KnownOne, KnownZero2, KnownOne2;
for (Use &OI : UserI->operands()) {
if (Instruction *I = dyn_cast<Instruction>(OI)) {
if (IntegerType *IT = dyn_cast<IntegerType>(I->getType())) {
unsigned BitWidth = IT->getBitWidth();
APInt AB = APInt::getAllOnesValue(BitWidth);
if (UserI->getType()->isIntegerTy() && !AOut &&
!isAlwaysLive(UserI)) {
AB = APInt(BitWidth, 0);
} else {
determineLiveOperandBits(UserI, I, OI.getOperandNo(), AOut, AB,
KnownZero, KnownOne,
KnownZero2, KnownOne2);
}
APInt ABPrev(BitWidth, 0);
auto ABI = AliveBits.find(I);
if (ABI != AliveBits.end())
ABPrev = ABI->second;
APInt ABNew = AB | ABPrev;
if (ABNew != ABPrev || ABI == AliveBits.end()) {
AliveBits[I] = std::move(ABNew);
Worklist.push_back(I);
}
} else if (!Visited.count(I)) {
Worklist.push_back(I);
}
}
}
}
}
APInt DemandedBits::getDemandedBits(Instruction *I) {
performAnalysis();
const DataLayout &DL = I->getParent()->getModule()->getDataLayout();
if (AliveBits.count(I))
return AliveBits[I];
return APInt::getAllOnesValue(DL.getTypeSizeInBits(I->getType()));
}
bool DemandedBits::isInstructionDead(Instruction *I) {
performAnalysis();
return !Visited.count(I) && AliveBits.find(I) == AliveBits.end() &&
!isAlwaysLive(I);
}
void DemandedBits::print(raw_ostream &OS, const Module *M) const {
const_cast<DemandedBits*>(this)->performAnalysis();
for (auto &KV : AliveBits) {
OS << "DemandedBits: 0x" << utohexstr(KV.second.getLimitedValue()) << " for "
<< *KV.first << "\n";
}
}
FunctionPass *llvm::createDemandedBitsPass() {
return new DemandedBits();
}