211 lines
7.3 KiB
C++
211 lines
7.3 KiB
C++
//===-- Speculation.h - Speculative Compilation --*- C++ -*-===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Contains the definition to support speculative compilation when laziness is
|
|
// enabled.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#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;
|
|
|
|
// Track the Impls (JITDylib,Symbols) of Symbols while lazy call through
|
|
// trampolines are created. Operations are guarded by locks tp ensure that Imap
|
|
// stays in consistent state after read/write
|
|
|
|
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:
|
|
// FIX ME: find a right way to distinguish the pre-compile Symbols, and update
|
|
// the callsite
|
|
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;
|
|
};
|
|
|
|
// Defines Speculator Concept,
|
|
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;
|
|
// Copy CandidateSet is necessary, to avoid unsynchronized access to
|
|
// the datastructure.
|
|
{
|
|
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);
|
|
// try to distinguish already compiled & library symbols
|
|
if (!ImplSymbol.hasValue())
|
|
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 a given symbol, there may be no symbol qualified for speculatively
|
|
// compile try to fix this before jumping to this code if possible.
|
|
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;
|
|
|
|
/// Define symbols for this Speculator object (__orc_speculator) and the
|
|
/// speculation runtime entry point symbol (__orc_speculate_for) in the
|
|
/// given JITDylib.
|
|
Error addSpeculationRuntime(JITDylib &JD, MangleAndInterner &Mangle);
|
|
|
|
// Speculatively compile likely functions for the given Stub Address.
|
|
// destination of __orc_speculate_for jump
|
|
void speculateFor(TargetFAddr StubAddr) { launchCompile(StubAddr); }
|
|
|
|
// FIXME : Register with Stub Address, after JITLink Fix.
|
|
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());
|
|
};
|
|
// Include non-exported symbols also.
|
|
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, IRCompileLayer &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;
|
|
}
|
|
|
|
IRCompileLayer &NextLayer;
|
|
Speculator &S;
|
|
MangleAndInterner &Mangle;
|
|
ResultEval QueryAnalysis;
|
|
};
|
|
|
|
} // namespace orc
|
|
} // namespace llvm
|
|
|
|
#endif // LLVM_EXECUTIONENGINE_ORC_SPECULATION_H
|