mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 05:32:28 +08:00
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)
208 lines
5.6 KiB
C++
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));
|
|
}
|
|
|
|
}
|
|
}
|