Files
revng-revng/lib/EarlyFunctionAnalysis/FunctionSummaryOracle.cpp
T
2022-11-30 15:06:54 +01:00

201 lines
7.0 KiB
C++

/// \file FunctionSummaryOracle.cpp
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include "revng/ABI/FunctionType.h"
#include "revng/EarlyFunctionAnalysis/FunctionSummaryOracle.h"
using namespace llvm;
static Logger<> Log("efa-import-model");
namespace efa {
static FunctionSummary
importPrototype(Module &M,
const llvm::SmallVector<GlobalVariable *, 16> &ABICSVs,
const AttributesSet &Attributes,
const model::TypePath &Prototype) {
using namespace llvm;
using namespace model;
using Register = model::Register::Values;
using State = abi::RegisterState::Values;
FunctionSummary Summary(Attributes,
{ ABICSVs.begin(), ABICSVs.end() },
ABIAnalyses::ABIAnalysesResults(),
{},
0);
for (GlobalVariable *CSV : ABICSVs) {
Summary.ABIResults.ArgumentsRegisters[CSV] = State::No;
Summary.ABIResults.FinalReturnValuesRegisters[CSV] = State::No;
}
auto Layout = abi::FunctionType::Layout::make(Prototype);
for (Register ArgumentRegister : Layout.argumentRegisters()) {
StringRef Name = model::Register::getCSVName(ArgumentRegister);
if (GlobalVariable *CSV = M.getGlobalVariable(Name, true))
Summary.ABIResults.ArgumentsRegisters.at(CSV) = State::Yes;
}
for (Register ReturnValueRegister : Layout.returnValueRegisters()) {
StringRef Name = model::Register::getCSVName(ReturnValueRegister);
if (GlobalVariable *CSV = M.getGlobalVariable(Name, true))
Summary.ABIResults.FinalReturnValuesRegisters.at(CSV) = State::Yes;
}
std::set<llvm::GlobalVariable *> PreservedRegisters;
for (Register CalleeSavedRegister : Layout.CalleeSavedRegisters) {
StringRef Name = model::Register::getCSVName(CalleeSavedRegister);
if (GlobalVariable *CSV = M.getGlobalVariable(Name, true))
PreservedRegisters.insert(CSV);
}
std::erase_if(Summary.ClobberedRegisters, [&](const auto &E) {
return PreservedRegisters.count(E) != 0;
});
Summary.ElectedFSO = Layout.FinalStackOffset;
return Summary;
}
std::pair<const FunctionSummary *, bool>
FunctionSummaryOracle::getCallSite(MetaAddress Function,
MetaAddress CallerBlockAddress,
MetaAddress CalledLocalFunction,
llvm::StringRef CalledSymbol) const {
auto [Summary, IsTailCall] = getCallSiteImpl(Function, CallerBlockAddress);
if (Summary != nullptr) {
return { Summary, IsTailCall };
} else if (not CalledSymbol.empty()) {
return { &getDynamicFunction(CalledSymbol), false };
} else if (CalledLocalFunction.isValid()
and LocalFunctions.count(CalledLocalFunction) != 0) {
return { &getLocalFunction(CalledLocalFunction), false };
} else {
return { &getDefault(), false };
}
}
bool FunctionSummaryOracle::registerCallSite(MetaAddress Function,
MetaAddress CallSite,
FunctionSummary &&New,
bool IsTailCall) {
revng_assert(Function.isValid());
revng_assert(CallSite.isValid());
std::pair<MetaAddress, MetaAddress> Key = { Function, CallSite };
auto It = CallSites.find(Key);
if (It != CallSites.end()) {
auto &Recorded = It->second.first;
bool Changed = not New.containedOrEqual(Recorded);
New.combine(Recorded);
Recorded = std::move(New);
return Changed;
} else {
CallSiteDescriptor CSD = { std::move(New), IsTailCall };
CallSites.emplace(Key, std::move(CSD));
return true;
}
}
bool FunctionSummaryOracle::registerLocalFunction(MetaAddress PC,
FunctionSummary &&New) {
revng_assert(PC.isValid());
if (Log.isEnabled()) {
Log << "registerLocalFunction " << PC.toString() << " with summary:\n";
New.dump(Log);
Log << DoLog;
}
auto It = LocalFunctions.find(PC);
bool Changed = It == LocalFunctions.end();
if (not Changed) {
auto &Recorded = It->second;
Changed = not New.containedOrEqual(Recorded);
New.combine(Recorded);
Recorded = std::move(New);
} else {
LocalFunctions.emplace(PC, std::move(New));
}
return Changed;
}
bool FunctionSummaryOracle::registerDynamicFunction(llvm::StringRef Name,
FunctionSummary &&New) {
auto It = DynamicFunctions.find(Name.str());
if (It != DynamicFunctions.end()) {
auto &Recorded = It->second;
bool Changed = not New.containedOrEqual(Recorded);
New.combine(Recorded);
Recorded = std::move(New);
return Changed;
} else {
DynamicFunctions.emplace(Name, std::move(New));
return true;
}
}
void importModel(Module &M,
GeneratedCodeBasicInfo &GCBI,
const model::Binary &Binary,
FunctionSummaryOracle &Oracle) {
revng_log(Log, "Importing from model");
LoggerIndent Indent(Log);
llvm::SmallVector<GlobalVariable *, 16> ABICSVs;
for (GlobalVariable *CSV : GCBI.abiRegisters())
if (CSV != nullptr && !(GCBI.isSPReg(CSV)))
ABICSVs.emplace_back(CSV);
// Import the default prototype
revng_assert(Binary.DefaultPrototype.isValid());
Oracle.setDefault(importPrototype(M, ABICSVs, {}, Binary.DefaultPrototype));
std::map<llvm::BasicBlock *, MetaAddress> InlineFunctions;
// Import existing functions from model
for (const model::Function &Function : Binary.Functions) {
// Import call-site specific information
for (const model::CallSitePrototype &CallSite :
Function.CallSitePrototypes) {
Oracle.registerCallSite(Function.Entry,
CallSite.CallerBlockAddress,
importPrototype(M,
ABICSVs,
CallSite.Attributes,
CallSite.Prototype),
CallSite.IsTailCall);
}
auto Summary = importPrototype(M,
ABICSVs,
Function.Attributes,
Function.prototype(Binary));
// Create function to inline, if necessary
if (Summary.Attributes.count(model::FunctionAttribute::Inline))
InlineFunctions[GCBI.getBlockAt(Function.Entry)] = Function.Entry;
Oracle.registerLocalFunction(Function.Entry, std::move(Summary));
}
// Register all dynamic symbols
for (const auto &DynamicFunction : Binary.ImportedDynamicFunctions) {
const auto &Prototype = getPrototype(Binary, DynamicFunction);
Oracle.registerDynamicFunction(DynamicFunction.OriginalName,
importPrototype(M,
ABICSVs,
DynamicFunction.Attributes,
Prototype));
}
}
} // namespace efa