blob: eab16cb0903289b9207daa0caddfb283a6722c71 [file] [log] [blame]
//===- bolt/Passes/RegAnalysis.cpp ----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the RegAnalysis class.
//
//===----------------------------------------------------------------------===//
#include "bolt/Passes/RegAnalysis.h"
#include "bolt/Core/BinaryFunction.h"
#include "bolt/Passes/CallGraphWalker.h"
#include "llvm/MC/MCRegisterInfo.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::cat(BoltOptCategory));
}
namespace llvm {
namespace bolt {
RegAnalysis::RegAnalysis(BinaryContext &BC,
std::map<uint64_t, BinaryFunction> *BFs,
BinaryFunctionCallGraph *CG)
: BC(BC), CS(opts::AssumeABI ? ConservativeStrategy::CLOBBERS_ABI
: ConservativeStrategy::CLOBBERS_ALL) {
if (!CG)
return;
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
}
if (!BFs)
return;
// This loop is for computing statistics only
for (auto &MapEntry : *BFs) {
BinaryFunction *Func = &MapEntry.second;
auto Iter = RegsKilledMap.find(Func);
assert(Iter != RegsKilledMap.end() &&
"Failed to compute all clobbers list");
if (Iter->second.all()) {
uint64_t 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 {
switch (CS) {
case ConservativeStrategy::CLOBBERS_ALL:
Result.set();
break;
case ConservativeStrategy::CLOBBERS_ABI: {
BitVector BV(BC.MRI->getNumRegs(), false);
BC.MIB->getCalleeSavedRegs(BV);
BV.flip();
Result |= BV;
break;
}
case ConservativeStrategy::CLOBBERS_NONE:
Result.reset();
break;
}
}
bool RegAnalysis::isConservative(BitVector &Vec) const {
switch (CS) {
case ConservativeStrategy::CLOBBERS_ALL:
return Vec.all();
case ConservativeStrategy::CLOBBERS_ABI: {
BitVector BV(BC.MRI->getNumRegs(), false);
BC.MIB->getCalleeSavedRegs(BV);
BV |= Vec;
return BV.all();
}
case ConservativeStrategy::CLOBBERS_NONE:
return Vec.none();
}
return false;
}
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;
}
// If no call graph supplied...
if (RegsKilledMap.size() == 0) {
beConservative(RegSet);
return;
}
const MCSymbol *TargetSymbol = BC.MIB->getTargetSymbol(Inst);
// If indirect call, we know nothing
if (TargetSymbol == nullptr) {
beConservative(RegSet);
return;
}
const BinaryFunction *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 BinaryBasicBlock &BB : *Func) {
for (const MCInst &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 BinaryBasicBlock &BB : *Func) {
for (const MCInst &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));
}
} // namespace bolt
} // namespace llvm