Files
llvm/bolt/Passes/RegAnalysis.cpp
Maksim Panchenko 48ae32a33b [BOLT] Introduce MCPlus layer
Summary:
Refactor architecture-specific code out of llvm into llvm-bolt.

Introduce MCPlusBuilder, a class that is taking over MCInstrAnalysis
responsibilities, i.e. creating, analyzing, and modifying instructions.
To access the builder use BC->MIB, i.e. substitute MIA with MIB.
MIB is an acronym for MCInstBuilder, that's what MCPlusBuilder used
to be. The name stuck, and I find it better than MPB.

Instructions are still MCInst, and a bunch of BOLT-specific code still
lives in LLVM, but the staff under Target/* is significantly reduced.

(cherry picked from FBD7300101)
2018-03-09 09:45:13 -08:00

208 lines
5.6 KiB
C++

#include "RegAnalysis.h"
#include "CallGraphWalker.h"
#include "llvm/Support/CommandLine.h"
#define DEBUG_TYPE "ra"
using namespace llvm;
namespace opts {
extern cl::opt<unsigned> Verbosity;
extern cl::OptionCategory BoltOptCategory;
cl::opt<bool> AssumeABI(
"assume-abi",
cl::desc("assume the ABI is never violated"),
cl::ZeroOrMore,
cl::init(false),
cl::cat(BoltOptCategory));
}
namespace llvm {
namespace bolt {
RegAnalysis::RegAnalysis(BinaryContext &BC,
std::map<uint64_t, BinaryFunction> &BFs,
BinaryFunctionCallGraph &CG)
: BC(BC) {
CallGraphWalker CGWalker(CG);
CGWalker.registerVisitor([&](BinaryFunction *Func) -> bool {
BitVector RegsKilled = getFunctionClobberList(Func);
bool Updated = RegsKilledMap.find(Func) == RegsKilledMap.end() ||
RegsKilledMap[Func] != RegsKilled;
if (Updated)
RegsKilledMap[Func] = std::move(RegsKilled);
return Updated;
});
CGWalker.registerVisitor([&](BinaryFunction *Func) -> bool {
BitVector RegsGen = getFunctionUsedRegsList(Func);
bool Updated = RegsGenMap.find(Func) == RegsGenMap.end() ||
RegsGenMap[Func] != RegsGen;
if (Updated)
RegsGenMap[Func] = std::move(RegsGen);
return Updated;
});
CGWalker.walk();
if (opts::Verbosity == 0) {
#ifndef NDEBUG
if (!DebugFlag || !isCurrentDebugType(DEBUG_TYPE))
return;
#else
return;
#endif
}
// This loop is for computing statistics only
for (auto &MapEntry : BFs) {
auto *Func = &MapEntry.second;
auto Iter = RegsKilledMap.find(Func);
assert(Iter != RegsKilledMap.end() &&
"Failed to compute all clobbers list");
if (Iter->second.all()) {
auto Count = Func->getExecutionCount();
if (Count != BinaryFunction::COUNT_NO_PROFILE)
CountFunctionsAllClobber += Count;
++NumFunctionsAllClobber;
}
DEBUG_WITH_TYPE("ra",
dbgs() << "Killed regs set for func: " << Func->getPrintName() << "\n";
const BitVector &RegsKilled = Iter->second;
int RegIdx = RegsKilled.find_first();
while (RegIdx != -1) {
dbgs() << "\tREG" << RegIdx;
RegIdx = RegsKilled.find_next(RegIdx);
};
dbgs() << "\nUsed regs set for func: " << Func->getPrintName() << "\n";
const BitVector &RegsUsed = RegsGenMap.find(Func)->second;
RegIdx = RegsUsed.find_first();
while (RegIdx != -1) {
dbgs() << "\tREG" << RegIdx;
RegIdx = RegsUsed.find_next(RegIdx);
};
dbgs() << "\n";
);
}
}
void RegAnalysis::beConservative(BitVector &Result) const {
if (!opts::AssumeABI) {
Result.set();
} else {
BitVector BV(BC.MRI->getNumRegs(), false);
BC.MIB->getCalleeSavedRegs(BV);
BV.flip();
Result |= BV;
}
}
bool RegAnalysis::isConservative(BitVector &Vec) const {
if (!opts::AssumeABI) {
return Vec.all();
} else {
BitVector BV(BC.MRI->getNumRegs(), false);
BC.MIB->getCalleeSavedRegs(BV);
BV |= Vec;
return BV.all();
}
}
void RegAnalysis::getInstUsedRegsList(const MCInst &Inst, BitVector &RegSet,
bool GetClobbers) const {
if (!BC.MIB->isCall(Inst)) {
if (GetClobbers)
BC.MIB->getClobberedRegs(Inst, RegSet);
else
BC.MIB->getUsedRegs(Inst, RegSet);
return;
}
const auto *TargetSymbol = BC.MIB->getTargetSymbol(Inst);
// If indirect call, we know nothing
if (TargetSymbol == nullptr) {
beConservative(RegSet);
return;
}
const auto *Function = BC.getFunctionForSymbol(TargetSymbol);
if (Function == nullptr) {
// Call to a function without a BinaryFunction object.
// This should be a call to a PLT entry, and since it is a trampoline to
// a DSO, we can't really know the code in advance.
beConservative(RegSet);
return;
}
if (GetClobbers) {
auto BV = RegsKilledMap.find(Function);
if (BV != RegsKilledMap.end()) {
RegSet |= BV->second;
return;
}
// Ignore calls to function whose clobber list wasn't yet calculated. This
// instruction will be evaluated again once we have info for the callee.
return;
}
auto BV = RegsGenMap.find(Function);
if (BV != RegsGenMap.end()) {
RegSet |= BV->second;
return;
}
}
void RegAnalysis::getInstClobberList(const MCInst &Inst,
BitVector &KillSet) const {
return getInstUsedRegsList(Inst, KillSet, /*GetClobbers*/ true);
}
BitVector RegAnalysis::getFunctionUsedRegsList(const BinaryFunction *Func) {
BitVector UsedRegs = BitVector(BC.MRI->getNumRegs(), false);
if (!Func->isSimple() || !Func->hasCFG()) {
beConservative(UsedRegs);
return UsedRegs;
}
for (const auto &BB : *Func) {
for (const auto &Inst : BB) {
getInstUsedRegsList(Inst, UsedRegs, /*GetClobbers*/false);
if (UsedRegs.all())
return UsedRegs;
}
}
return UsedRegs;
}
BitVector RegAnalysis::getFunctionClobberList(const BinaryFunction *Func) {
BitVector RegsKilled = BitVector(BC.MRI->getNumRegs(), false);
if (!Func->isSimple() || !Func->hasCFG()) {
beConservative(RegsKilled);
return RegsKilled;
}
for (const auto &BB : *Func) {
for (const auto &Inst : BB) {
getInstClobberList(Inst, RegsKilled);
if (RegsKilled.all())
return RegsKilled;
}
}
return RegsKilled;
}
void RegAnalysis::printStats() {
outs() << "BOLT-INFO REG ANALYSIS: Number of functions conservatively "
"treated as clobbering all registers: "
<< NumFunctionsAllClobber
<< format(" (%.1lf%% dyn cov)\n",
(100.0 * CountFunctionsAllClobber / CountDenominator));
}
}
}