2021-12-22 02:21:41 +08:00
|
|
|
//===- bolt/Passes/RegAnalysis.cpp ----------------------------------------===//
|
2021-03-16 09:04:18 +08:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2021-12-22 02:21:41 +08:00
|
|
|
// This file implements the RegAnalysis class.
|
|
|
|
//
|
2021-03-16 09:04:18 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2021-10-09 02:47:10 +08:00
|
|
|
#include "bolt/Passes/RegAnalysis.h"
|
|
|
|
#include "bolt/Core/BinaryFunction.h"
|
|
|
|
#include "bolt/Passes/CallGraphWalker.h"
|
2022-02-09 21:26:30 +08:00
|
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
2017-06-03 07:57:22 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "ra"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace opts {
|
|
|
|
extern cl::opt<unsigned> Verbosity;
|
|
|
|
extern cl::OptionCategory BoltOptCategory;
|
|
|
|
|
2022-06-06 04:29:49 +08:00
|
|
|
cl::opt<bool> AssumeABI("assume-abi",
|
|
|
|
cl::desc("assume the ABI is never violated"),
|
|
|
|
cl::cat(BoltOptCategory));
|
2017-06-03 07:57:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
namespace bolt {
|
|
|
|
|
|
|
|
RegAnalysis::RegAnalysis(BinaryContext &BC,
|
2018-06-12 04:18:44 +08:00
|
|
|
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);
|
2017-06-03 07:57:22 +08:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2018-06-12 04:18:44 +08:00
|
|
|
if (!BFs)
|
|
|
|
return;
|
|
|
|
|
2017-06-03 07:57:22 +08:00
|
|
|
// This loop is for computing statistics only
|
2018-06-12 04:18:44 +08:00
|
|
|
for (auto &MapEntry : *BFs) {
|
2021-04-08 15:19:26 +08:00
|
|
|
BinaryFunction *Func = &MapEntry.second;
|
2017-06-03 07:57:22 +08:00
|
|
|
auto Iter = RegsKilledMap.find(Func);
|
|
|
|
assert(Iter != RegsKilledMap.end() &&
|
|
|
|
"Failed to compute all clobbers list");
|
|
|
|
if (Iter->second.all()) {
|
2021-04-08 15:19:26 +08:00
|
|
|
uint64_t Count = Func->getExecutionCount();
|
2017-06-03 07:57:22 +08:00
|
|
|
if (Count != BinaryFunction::COUNT_NO_PROFILE)
|
|
|
|
CountFunctionsAllClobber += Count;
|
|
|
|
++NumFunctionsAllClobber;
|
|
|
|
}
|
2017-06-17 06:02:26 +08:00
|
|
|
DEBUG_WITH_TYPE("ra",
|
2017-06-03 07:57:22 +08:00
|
|
|
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 {
|
2018-06-12 04:18:44 +08:00
|
|
|
switch (CS) {
|
|
|
|
case ConservativeStrategy::CLOBBERS_ALL:
|
2017-06-03 07:57:22 +08:00
|
|
|
Result.set();
|
2018-06-12 04:18:44 +08:00
|
|
|
break;
|
|
|
|
case ConservativeStrategy::CLOBBERS_ABI: {
|
2017-06-03 07:57:22 +08:00
|
|
|
BitVector BV(BC.MRI->getNumRegs(), false);
|
2018-03-10 01:45:13 +08:00
|
|
|
BC.MIB->getCalleeSavedRegs(BV);
|
2017-06-03 07:57:22 +08:00
|
|
|
BV.flip();
|
|
|
|
Result |= BV;
|
2018-10-05 01:46:16 +08:00
|
|
|
break;
|
2017-06-03 07:57:22 +08:00
|
|
|
}
|
2018-06-12 04:18:44 +08:00
|
|
|
case ConservativeStrategy::CLOBBERS_NONE:
|
|
|
|
Result.reset();
|
|
|
|
break;
|
|
|
|
}
|
2017-06-03 07:57:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool RegAnalysis::isConservative(BitVector &Vec) const {
|
2018-06-12 04:18:44 +08:00
|
|
|
switch (CS) {
|
|
|
|
case ConservativeStrategy::CLOBBERS_ALL:
|
2017-06-03 07:57:22 +08:00
|
|
|
return Vec.all();
|
2018-06-12 04:18:44 +08:00
|
|
|
case ConservativeStrategy::CLOBBERS_ABI: {
|
2017-06-03 07:57:22 +08:00
|
|
|
BitVector BV(BC.MRI->getNumRegs(), false);
|
2018-03-10 01:45:13 +08:00
|
|
|
BC.MIB->getCalleeSavedRegs(BV);
|
2017-06-03 07:57:22 +08:00
|
|
|
BV |= Vec;
|
|
|
|
return BV.all();
|
|
|
|
}
|
2018-06-12 04:18:44 +08:00
|
|
|
case ConservativeStrategy::CLOBBERS_NONE:
|
|
|
|
return Vec.none();
|
|
|
|
}
|
|
|
|
return false;
|
2017-06-03 07:57:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void RegAnalysis::getInstUsedRegsList(const MCInst &Inst, BitVector &RegSet,
|
|
|
|
bool GetClobbers) const {
|
2018-03-10 01:45:13 +08:00
|
|
|
if (!BC.MIB->isCall(Inst)) {
|
2017-06-03 07:57:22 +08:00
|
|
|
if (GetClobbers)
|
2018-03-10 01:45:13 +08:00
|
|
|
BC.MIB->getClobberedRegs(Inst, RegSet);
|
2017-06-03 07:57:22 +08:00
|
|
|
else
|
2018-03-10 01:45:13 +08:00
|
|
|
BC.MIB->getUsedRegs(Inst, RegSet);
|
2017-06-03 07:57:22 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-12 04:18:44 +08:00
|
|
|
// If no call graph supplied...
|
|
|
|
if (RegsKilledMap.size() == 0) {
|
|
|
|
beConservative(RegSet);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-04-08 15:19:26 +08:00
|
|
|
const MCSymbol *TargetSymbol = BC.MIB->getTargetSymbol(Inst);
|
2017-06-03 07:57:22 +08:00
|
|
|
// If indirect call, we know nothing
|
|
|
|
if (TargetSymbol == nullptr) {
|
|
|
|
beConservative(RegSet);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-04-08 15:19:26 +08:00
|
|
|
const BinaryFunction *Function = BC.getFunctionForSymbol(TargetSymbol);
|
2017-06-03 07:57:22 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-04-08 15:19:26 +08:00
|
|
|
for (const BinaryBasicBlock &BB : *Func) {
|
|
|
|
for (const MCInst &Inst : BB) {
|
2021-12-15 08:52:51 +08:00
|
|
|
getInstUsedRegsList(Inst, UsedRegs, /*GetClobbers*/ false);
|
2017-06-03 07:57:22 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-04-08 15:19:26 +08:00
|
|
|
for (const BinaryBasicBlock &BB : *Func) {
|
|
|
|
for (const MCInst &Inst : BB) {
|
2017-06-03 07:57:22 +08:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2021-12-15 08:52:51 +08:00
|
|
|
} // namespace bolt
|
|
|
|
} // namespace llvm
|