#ifndef LLVM_EXECUTIONENGINE_ORC_SPECULATION_H
#define LLVM_EXECUTIONENGINE_ORC_SPECULATION_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ExecutionEngine/Orc/Core.h"
#include "llvm/ExecutionEngine/Orc/DebugUtils.h"
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
#include "llvm/Support/Debug.h"
#include <mutex>
#include <type_traits>
#include <utility>
namespace llvm {
namespace orc {
class Speculator;
class ImplSymbolMap {
friend class Speculator;
public:
using AliaseeDetails = std::pair<SymbolStringPtr, JITDylib *>;
using Alias = SymbolStringPtr;
using ImapTy = DenseMap<Alias, AliaseeDetails>;
void trackImpls(SymbolAliasMap ImplMaps, JITDylib *SrcJD);
private:
Optional<AliaseeDetails> getImplFor(const SymbolStringPtr &StubSymbol) {
std::lock_guard<std::mutex> Lockit(ConcurrentAccess);
auto Position = Maps.find(StubSymbol);
if (Position != Maps.end())
return Position->getSecond();
else
return None;
}
std::mutex ConcurrentAccess;
ImapTy Maps;
};
class Speculator {
public:
using TargetFAddr = JITTargetAddress;
using FunctionCandidatesMap = DenseMap<SymbolStringPtr, SymbolNameSet>;
using StubAddrLikelies = DenseMap<TargetFAddr, SymbolNameSet>;
private:
void registerSymbolsWithAddr(TargetFAddr ImplAddr,
SymbolNameSet likelySymbols) {
std::lock_guard<std::mutex> Lockit(ConcurrentAccess);
GlobalSpecMap.insert({ImplAddr, std::move(likelySymbols)});
}
void launchCompile(JITTargetAddress FAddr) {
SymbolNameSet CandidateSet;
{
std::lock_guard<std::mutex> Lockit(ConcurrentAccess);
auto It = GlobalSpecMap.find(FAddr);
if (It == GlobalSpecMap.end())
return;
CandidateSet = It->getSecond();
}
SymbolDependenceMap SpeculativeLookUpImpls;
for (auto &Callee : CandidateSet) {
auto ImplSymbol = AliaseeImplTable.getImplFor(Callee);
if (!ImplSymbol)
continue;
const auto &ImplSymbolName = ImplSymbol.getPointer()->first;
JITDylib *ImplJD = ImplSymbol.getPointer()->second;
auto &SymbolsInJD = SpeculativeLookUpImpls[ImplJD];
SymbolsInJD.insert(ImplSymbolName);
}
DEBUG_WITH_TYPE("orc", {
for (auto &I : SpeculativeLookUpImpls) {
llvm::dbgs() << "\n In " << I.first->getName() << " JITDylib ";
for (auto &N : I.second)
llvm::dbgs() << "\n Likely Symbol : " << N;
}
});
for (auto &LookupPair : SpeculativeLookUpImpls)
ES.lookup(
LookupKind::Static,
makeJITDylibSearchOrder(LookupPair.first,
JITDylibLookupFlags::MatchAllSymbols),
SymbolLookupSet(LookupPair.second), SymbolState::Ready,
[this](Expected<SymbolMap> Result) {
if (auto Err = Result.takeError())
ES.reportError(std::move(Err));
},
NoDependenciesToRegister);
}
public:
Speculator(ImplSymbolMap &Impl, ExecutionSession &ref)
: AliaseeImplTable(Impl), ES(ref), GlobalSpecMap(0) {}
Speculator(const Speculator &) = delete;
Speculator(Speculator &&) = delete;
Speculator &operator=(const Speculator &) = delete;
Speculator &operator=(Speculator &&) = delete;
Error addSpeculationRuntime(JITDylib &JD, MangleAndInterner &Mangle);
void speculateFor(TargetFAddr StubAddr) { launchCompile(StubAddr); }
void registerSymbols(FunctionCandidatesMap Candidates, JITDylib *JD) {
for (auto &SymPair : Candidates) {
auto Target = SymPair.first;
auto Likely = SymPair.second;
auto OnReadyFixUp = [Likely, Target,
this](Expected<SymbolMap> ReadySymbol) {
if (ReadySymbol) {
auto RAddr = (*ReadySymbol)[Target].getAddress();
registerSymbolsWithAddr(RAddr, std::move(Likely));
} else
this->getES().reportError(ReadySymbol.takeError());
};
ES.lookup(
LookupKind::Static,
makeJITDylibSearchOrder(JD, JITDylibLookupFlags::MatchAllSymbols),
SymbolLookupSet(Target, SymbolLookupFlags::WeaklyReferencedSymbol),
SymbolState::Ready, OnReadyFixUp, NoDependenciesToRegister);
}
}
ExecutionSession &getES() { return ES; }
private:
static void speculateForEntryPoint(Speculator *Ptr, uint64_t StubId);
std::mutex ConcurrentAccess;
ImplSymbolMap &AliaseeImplTable;
ExecutionSession &ES;
StubAddrLikelies GlobalSpecMap;
};
class IRSpeculationLayer : public IRLayer {
public:
using IRlikiesStrRef = Optional<DenseMap<StringRef, DenseSet<StringRef>>>;
using ResultEval = std::function<IRlikiesStrRef(Function &)>;
using TargetAndLikelies = DenseMap<SymbolStringPtr, SymbolNameSet>;
IRSpeculationLayer(ExecutionSession &ES, IRLayer &BaseLayer, Speculator &Spec,
MangleAndInterner &Mangle, ResultEval Interpreter)
: IRLayer(ES, BaseLayer.getManglingOptions()), NextLayer(BaseLayer),
S(Spec), Mangle(Mangle), QueryAnalysis(Interpreter) {}
void emit(std::unique_ptr<MaterializationResponsibility> R,
ThreadSafeModule TSM) override;
private:
TargetAndLikelies
internToJITSymbols(DenseMap<StringRef, DenseSet<StringRef>> IRNames) {
assert(!IRNames.empty() && "No IRNames received to Intern?");
TargetAndLikelies InternedNames;
for (auto &NamePair : IRNames) {
DenseSet<SymbolStringPtr> TargetJITNames;
for (auto &TargetNames : NamePair.second)
TargetJITNames.insert(Mangle(TargetNames));
InternedNames[Mangle(NamePair.first)] = std::move(TargetJITNames);
}
return InternedNames;
}
IRLayer &NextLayer;
Speculator &S;
MangleAndInterner &Mangle;
ResultEval QueryAnalysis;
};
} }
#endif