llvm.org GIT mirror llvm / 25b5b89
Speculative Compilation [ORC] Remove Speculator Variants for Different Program Representations [ORC] Block Freq Analysis Speculative Compilation with Naive Block Frequency Add Applications to OrcSpeculation ORC v2 with Block Freq Query & Example Deleted BenchMark Programs Signed-off-by: preejackie <praveenvelliengiri@gmail.com> ORCv2 comments resolved [ORCV2] NFC ORCv2 NFC [ORCv2] Speculative compilation - CFGWalkQuery ORCv2 Adapting IRSpeculationLayer to new locking scheme git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@367756 91177308-0d34-0410-b5e6-96231b3b80d8 Praveen Velliengiri 2 months ago
12 changed file(s) with 701 addition(s) and 9 deletion(s). Raw diff Collapse all Expand all
44 add_subdirectory(LLJITExamples)
55 add_subdirectory(Kaleidoscope)
66 add_subdirectory(ModuleMaker)
7 add_subdirectory(SpeculativeJIT)
78
89 if(LLVM_ENABLE_EH AND (NOT WIN32) AND (NOT "${LLVM_NATIVE_ARCH}" STREQUAL "ARM"))
910 add_subdirectory(ExceptionDemo)
0 set(LLVM_LINK_COMPONENTS
1 Core
2 IRReader
3 OrcJIT
4 ExecutionEngine
5 Support
6 nativecodegen
7 Analysis
8 Passes
9 )
10
11 add_llvm_example(SpeculativeJIT
12 SpeculativeJIT.cpp
13 )
0 #include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
1 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
2 #include "llvm/ExecutionEngine/Orc/Core.h"
3 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
4 #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
5 #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
6 #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
7 #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
8 #include "llvm/ExecutionEngine/Orc/SpeculateAnalyses.h"
9 #include "llvm/ExecutionEngine/Orc/Speculation.h"
10 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
11 #include "llvm/IRReader/IRReader.h"
12 #include "llvm/Support/CommandLine.h"
13 #include "llvm/Support/Debug.h"
14 #include "llvm/Support/InitLLVM.h"
15 #include "llvm/Support/SourceMgr.h"
16 #include "llvm/Support/TargetSelect.h"
17 #include "llvm/Support/ThreadPool.h"
18
19 #include
20 #include
21
22 using namespace llvm;
23 using namespace llvm::orc;
24
25 static cl::list InputFiles(cl::Positional, cl::OneOrMore,
26 cl::desc("input files"));
27
28 static cl::list InputArgv("args", cl::Positional,
29 cl::desc("..."),
30 cl::ZeroOrMore, cl::PositionalEatsArgs);
31
32 static cl::opt NumThreads("num-threads", cl::Optional,
33 cl::desc("Number of compile threads"),
34 cl::init(4));
35
36 ExitOnError ExitOnErr;
37
38 // Add Layers
39 class SpeculativeJIT {
40 public:
41 static Expected> Create() {
42 auto JTMB = orc::JITTargetMachineBuilder::detectHost();
43 if (!JTMB)
44 return JTMB.takeError();
45
46 auto DL = JTMB->getDefaultDataLayoutForTarget();
47 if (!DL)
48 return DL.takeError();
49
50 auto ES = llvm::make_unique();
51
52 auto LCTMgr = createLocalLazyCallThroughManager(
53 JTMB->getTargetTriple(), *ES,
54 pointerToJITTargetAddress(explodeOnLazyCompileFailure));
55 if (!LCTMgr)
56 return LCTMgr.takeError();
57
58 auto ISMBuilder =
59 createLocalIndirectStubsManagerBuilder(JTMB->getTargetTriple());
60 if (!ISMBuilder)
61 return make_error("No indirect stubs manager for target",
62 inconvertibleErrorCode());
63
64 auto ProcessSymbolsSearchGenerator =
65 DynamicLibrarySearchGenerator::GetForCurrentProcess(
66 DL->getGlobalPrefix());
67 if (!ProcessSymbolsSearchGenerator)
68 return ProcessSymbolsSearchGenerator.takeError();
69
70 std::unique_ptr SJ(new SpeculativeJIT(
71 std::move(ES), std::move(*DL), std::move(*JTMB), std::move(*LCTMgr),
72 std::move(ISMBuilder), std::move(*ProcessSymbolsSearchGenerator)));
73 return std::move(SJ);
74 }
75
76 ExecutionSession &getES() { return *ES; }
77
78 Error addModule(JITDylib &JD, ThreadSafeModule TSM) {
79 return CODLayer.add(JD, std::move(TSM));
80 }
81
82 Expected lookup(StringRef UnmangledName) {
83 return ES->lookup({&ES->getMainJITDylib()}, Mangle(UnmangledName));
84 }
85
86 ~SpeculativeJIT() { CompileThreads.wait(); }
87
88 private:
89 using IndirectStubsManagerBuilderFunction =
90 std::function()>;
91
92 static void explodeOnLazyCompileFailure() {
93 errs() << "Lazy compilation failed, Symbol Implmentation not found!\n";
94 exit(1);
95 }
96
97 SpeculativeJIT(std::unique_ptr ES, DataLayout DL,
98 orc::JITTargetMachineBuilder JTMB,
99 std::unique_ptr LCTMgr,
100 IndirectStubsManagerBuilderFunction ISMBuilder,
101 DynamicLibrarySearchGenerator ProcessSymbolsGenerator)
102 : ES(std::move(ES)), DL(std::move(DL)), LCTMgr(std::move(LCTMgr)),
103 CompileLayer(*this->ES, ObjLayer,
104 ConcurrentIRCompiler(std::move(JTMB))),
105 S(Imps, *this->ES),
106 SpeculateLayer(*this->ES, CompileLayer, S, BlockFreqQuery()),
107 CODLayer(*this->ES, SpeculateLayer, *this->LCTMgr,
108 std::move(ISMBuilder)) {
109 this->ES->getMainJITDylib().setGenerator(
110 std::move(ProcessSymbolsGenerator));
111 this->CODLayer.setImplMap(&Imps);
112 this->ES->setDispatchMaterialization(
113
114 [this](JITDylib &JD, std::unique_ptr MU) {
115 // FIXME: Switch to move capture once we have c 14.
116 auto SharedMU = std::shared_ptr(std::move(MU));
117 auto Work = [SharedMU, &JD]() { SharedMU->doMaterialize(JD); };
118 CompileThreads.async(std::move(Work));
119 });
120 JITEvaluatedSymbol SpeculatorSymbol(JITTargetAddress(&S),
121 JITSymbolFlags::Exported);
122 ExitOnErr(this->ES->getMainJITDylib().define(
123 absoluteSymbols({{Mangle("__orc_speculator"), SpeculatorSymbol}})));
124 LocalCXXRuntimeOverrides CXXRuntimeoverrides;
125 ExitOnErr(CXXRuntimeoverrides.enable(this->ES->getMainJITDylib(), Mangle));
126 }
127
128 static std::unique_ptr createMemMgr() {
129 return llvm::make_unique();
130 }
131
132 std::unique_ptr ES;
133 DataLayout DL;
134 MangleAndInterner Mangle{*ES, DL};
135 ThreadPool CompileThreads{NumThreads};
136
137 Triple TT;
138 std::unique_ptr LCTMgr;
139 IRCompileLayer CompileLayer;
140 ImplSymbolMap Imps;
141 Speculator S;
142 RTDyldObjectLinkingLayer ObjLayer{*ES, createMemMgr};
143 IRSpeculationLayer SpeculateLayer;
144 CompileOnDemandLayer CODLayer;
145 };
146
147 int main(int argc, char *argv[]) {
148 // Initialize LLVM.
149 InitLLVM X(argc, argv);
150
151 InitializeNativeTarget();
152 InitializeNativeTargetAsmPrinter();
153
154 cl::ParseCommandLineOptions(argc, argv, "SpeculativeJIT");
155 ExitOnErr.setBanner(std::string(argv[0]) + ": ");
156
157 if (NumThreads < 1) {
158 errs() << "Speculative compilation requires one or more dedicated compile "
159 "threads\n";
160 return 1;
161 }
162
163 // Create a JIT instance.
164 auto SJ = ExitOnErr(SpeculativeJIT::Create());
165
166 // Load the IR inputs.
167 for (const auto &InputFile : InputFiles) {
168 SMDiagnostic Err;
169 auto Ctx = llvm::make_unique();
170 auto M = parseIRFile(InputFile, Err, *Ctx);
171 if (!M) {
172 Err.print(argv[0], errs());
173 return 1;
174 }
175
176 ExitOnErr(SJ->addModule(SJ->getES().getMainJITDylib(),
177 ThreadSafeModule(std::move(M), std::move(Ctx))));
178 }
179
180 // Build an argv array for the JIT'd main.
181 std::vector ArgV;
182 ArgV.push_back(argv[0]);
183 for (const auto &InputArg : InputArgv)
184 ArgV.push_back(InputArg.data());
185 ArgV.push_back(nullptr);
186
187 // Look up the JIT'd main, cast it to a function pointer, then call it.
188
189 auto MainSym = ExitOnErr(SJ->lookup("main"));
190 int (*Main)(int, const char *[]) =
191 (int (*)(int, const char *[]))MainSym.getAddress();
192
193 Main(ArgV.size() - 1, ArgV.data());
194
195 return 0;
196 }
2525 #include "llvm/ExecutionEngine/Orc/LazyReexports.h"
2626 #include "llvm/ExecutionEngine/Orc/Legacy.h"
2727 #include "llvm/ExecutionEngine/Orc/OrcError.h"
28 #include "llvm/ExecutionEngine/Orc/Speculation.h"
2829 #include "llvm/ExecutionEngine/RuntimeDyld.h"
2930 #include "llvm/IR/Attributes.h"
3031 #include "llvm/IR/Constant.h"
9091 /// Sets the partition function.
9192 void setPartitionFunction(PartitionFunction Partition);
9293
94 /// Sets the ImplSymbolMap
95 void setImplMap(ImplSymbolMap *Imp);
9396 /// Emits the given module. This should not be called by clients: it will be
9497 /// called by the JIT when a definition added via the add method is requested.
9598 void emit(MaterializationResponsibility R, ThreadSafeModule TSM) override;
127130 PerDylibResourcesMap DylibResources;
128131 PartitionFunction Partition = compileRequested;
129132 SymbolLinkagePromoter PromoteSymbols;
133 ImplSymbolMap *AliaseeImpls = nullptr;
130134 };
131135
132136 /// Compile-on-demand layer.
1717
1818 #include "llvm/ExecutionEngine/Orc/Core.h"
1919 #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
20 #include "llvm/ExecutionEngine/Orc/Speculation.h"
2021
2122 namespace llvm {
2223
158159 IndirectStubsManager &ISManager,
159160 JITDylib &SourceJD,
160161 SymbolAliasMap CallableAliases,
161 VModuleKey K);
162 ImplSymbolMap *SrcJDLoc, VModuleKey K);
162163
163164 StringRef getName() const override;
164165
173174 SymbolAliasMap CallableAliases;
174175 std::shared_ptr
175176 NotifyResolved;
177 ImplSymbolMap *AliaseeTable;
176178 };
177179
178180 /// Define lazy-reexports based on the given SymbolAliasMap. Each lazy re-export
181183 inline std::unique_ptr
182184 lazyReexports(LazyCallThroughManager &LCTManager,
183185 IndirectStubsManager &ISManager, JITDylib &SourceJD,
184 SymbolAliasMap CallableAliases, VModuleKey K = VModuleKey()) {
186 SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc = nullptr,
187 VModuleKey K = VModuleKey()) {
185188 return llvm::make_unique(
186 LCTManager, ISManager, SourceJD, std::move(CallableAliases),
189 LCTManager, ISManager, SourceJD, std::move(CallableAliases), SrcJDLoc,
187190 std::move(K));
188191 }
189192
0 //===-- SpeculateAnalyses.h --*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 // \file
8 /// Contains the Analyses and Result Interpretation to select likely functions
9 /// to Speculatively compile before they are called. [Experimentation]
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_EXECUTIONENGINE_ORC_SPECULATEANALYSES_H
13 #define LLVM_EXECUTIONENGINE_ORC_SPECULATEANALYSES_H
14
15 #include "llvm/ExecutionEngine/Orc/Core.h"
16 #include "llvm/ExecutionEngine/Orc/Speculation.h"
17
18 #include
19
20 namespace {
21 using namespace llvm;
22 std::vector findBBwithCalls(const Function &F,
23 bool IndirectCall = false) {
24 std::vector BBs;
25
26 auto findCallInst = [&IndirectCall](const Instruction &I) {
27 if (auto Call = dyn_cast(&I)) {
28 if (Call->isIndirectCall())
29 return IndirectCall;
30 else
31 return true;
32 } else
33 return false;
34 };
35 for (auto &BB : F)
36 if (findCallInst(*BB.getTerminator()) ||
37 llvm::any_of(BB.instructionsWithoutDebug(), findCallInst))
38 BBs.emplace_back(&BB);
39
40 return BBs;
41 }
42 } // namespace
43
44 namespace llvm {
45
46 namespace orc {
47
48 // Direct calls in high frequency basic blocks are extracted.
49 class BlockFreqQuery {
50 private:
51 void findCalles(const BasicBlock *, DenseSet &);
52 size_t numBBToGet(size_t);
53
54 public:
55 using ResultTy = Optional>>;
56
57 // Find likely next executables based on IR Block Frequency
58 ResultTy operator()(Function &F, FunctionAnalysisManager &FAM);
59 };
60
61 // Walk the CFG by exploting BranchProbabilityInfo
62 class CFGWalkQuery {
63 public:
64 using ResultTy = Optional>>;
65 ResultTy operator()(Function &F, FunctionAnalysisManager &FAM);
66 };
67
68 } // namespace orc
69 } // namespace llvm
70
71 #endif // LLVM_EXECUTIONENGINE_ORC_SPECULATEANALYSES_H
0 //===-- Speculation.h - Speculative Compilation --*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // Contains the definition to support speculative compilation when laziness is
9 // enabled.
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_EXECUTIONENGINE_ORC_SPECULATION_H
13 #define LLVM_EXECUTIONENGINE_ORC_SPECULATION_H
14
15 #include "llvm/ADT/ArrayRef.h"
16 #include "llvm/ADT/DenseMap.h"
17 #include "llvm/ADT/Optional.h"
18 #include "llvm/ExecutionEngine/Orc/Core.h"
19 #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
20 #include "llvm/IR/PassManager.h"
21 #include "llvm/Passes/PassBuilder.h"
22
23 #include
24 #include
25 #include
26 #include
27
28 namespace llvm {
29 namespace orc {
30
31 class Speculator;
32
33 // Track the Impls (JITDylib,Symbols) of Symbols while lazy call through
34 // trampolines are created. Operations are guarded by locks tp ensure that Imap
35 // stays in consistent state after read/write
36
37 class ImplSymbolMap {
38 friend class Speculator;
39
40 public:
41 using AliaseeDetails = std::pair;
42 using Alias = SymbolStringPtr;
43 using ImapTy = DenseMap;
44 void trackImpls(SymbolAliasMap ImplMaps, JITDylib *SrcJD);
45
46 private:
47 // FIX ME: find a right way to distinguish the pre-compile Symbols, and update
48 // the callsite
49 Optional getImplFor(const SymbolStringPtr &StubSymbol) {
50 std::lock_guard Lockit(ConcurrentAccess);
51 auto Position = Maps.find(StubSymbol);
52 if (Position != Maps.end())
53 return Position->getSecond();
54 else
55 return None;
56 }
57
58 std::mutex ConcurrentAccess;
59 ImapTy Maps;
60 };
61
62 // Defines Speculator Concept,
63 class Speculator {
64 public:
65 using TargetFAddr = JITTargetAddress;
66 using FunctionCandidatesMap = DenseMap;
67 using StubAddrLikelies = DenseMap;
68
69 private:
70 void registerSymbolsWithAddr(TargetFAddr ImplAddr,
71 SymbolNameSet likelySymbols) {
72 std::lock_guard Lockit(ConcurrentAccess);
73 GlobalSpecMap.insert({ImplAddr, std::move(likelySymbols)});
74 }
75
76 void launchCompile(JITTargetAddress FAddr) {
77 SymbolNameSet CandidateSet;
78 // Copy CandidateSet is necessary, to avoid unsynchronized access to
79 // the datastructure.
80 {
81 std::lock_guard Lockit(ConcurrentAccess);
82 auto It = GlobalSpecMap.find(FAddr);
83 // Kill this when jump on first call instrumentation is in place;
84 auto Iv = AlreadyExecuted.insert(FAddr);
85 if (It == GlobalSpecMap.end() || Iv.second == false)
86 return;
87 else
88 CandidateSet = It->getSecond();
89 }
90
91 // Try to distinguish pre-compiled symbols!
92 for (auto &Callee : CandidateSet) {
93 auto ImplSymbol = AliaseeImplTable.getImplFor(Callee);
94 if (!ImplSymbol.hasValue())
95 continue;
96 const auto &ImplSymbolName = ImplSymbol.getPointer()->first;
97 auto *ImplJD = ImplSymbol.getPointer()->second;
98 ES.lookup(JITDylibSearchList({{ImplJD, true}}),
99 SymbolNameSet({ImplSymbolName}), SymbolState::Ready,
100 [this](Expected Result) {
101 if (auto Err = Result.takeError())
102 ES.reportError(std::move(Err));
103 },
104 NoDependenciesToRegister);
105 }
106 }
107
108 public:
109 Speculator(ImplSymbolMap &Impl, ExecutionSession &ref)
110 : AliaseeImplTable(Impl), ES(ref), GlobalSpecMap(0) {}
111 Speculator(const Speculator &) = delete;
112 Speculator(Speculator &&) = delete;
113 Speculator &operator=(const Speculator &) = delete;
114 Speculator &operator=(Speculator &&) = delete;
115 ~Speculator() {}
116
117 // Speculatively compile likely functions for the given Stub Address.
118 // destination of __orc_speculate_for jump
119 void speculateFor(TargetFAddr StubAddr) { launchCompile(StubAddr); }
120
121 // FIXME : Register with Stub Address, after JITLink Fix.
122 void registerSymbols(FunctionCandidatesMap Candidates, JITDylib *JD) {
123 for (auto &SymPair : Candidates) {
124 auto Target = SymPair.first;
125 auto Likely = SymPair.second;
126
127 auto OnReadyFixUp = [Likely, Target,
128 this](Expected ReadySymbol) {
129 if (ReadySymbol) {
130 auto RAddr = (*ReadySymbol)[Target].getAddress();
131 registerSymbolsWithAddr(RAddr, std::move(Likely));
132 } else
133 this->getES().reportError(ReadySymbol.takeError());
134 };
135 // Include non-exported symbols also.
136 ES.lookup(JITDylibSearchList({{JD, true}}), SymbolNameSet({Target}),
137 SymbolState::Ready, OnReadyFixUp, NoDependenciesToRegister);
138 }
139 }
140
141 ExecutionSession &getES() { return ES; }
142
143 private:
144 std::mutex ConcurrentAccess;
145 ImplSymbolMap &AliaseeImplTable;
146 ExecutionSession &ES;
147 DenseSet AlreadyExecuted;
148 StubAddrLikelies GlobalSpecMap;
149 };
150 // replace DenseMap with Pair
151 class IRSpeculationLayer : public IRLayer {
152 public:
153 using IRlikiesStrRef = Optional>>;
154 using ResultEval =
155 std::function;
156 using TargetAndLikelies = DenseMap;
157
158 IRSpeculationLayer(ExecutionSession &ES, IRCompileLayer &BaseLayer,
159 Speculator &Spec, ResultEval Interpreter)
160 : IRLayer(ES), NextLayer(BaseLayer), S(Spec), QueryAnalysis(Interpreter) {
161 PB.registerFunctionAnalyses(FAM);
162 }
163
164 template <
165 typename AnalysisTy,
166 typename std::enable_if<
167 std::is_base_of, AnalysisTy>::value,
168 bool>::type = true>
169 void registerAnalysis() {
170 FAM.registerPass([]() { return AnalysisTy(); });
171 }
172
173 void emit(MaterializationResponsibility R, ThreadSafeModule TSM);
174
175 private:
176 TargetAndLikelies
177 internToJITSymbols(DenseMap> IRNames) {
178 assert(!IRNames.empty() && "No IRNames received to Intern?");
179 TargetAndLikelies InternedNames;
180 DenseSet TargetJITNames;
181 ExecutionSession &Es = getExecutionSession();
182 for (auto &NamePair : IRNames) {
183 for (auto &TargetNames : NamePair.second)
184 TargetJITNames.insert(Es.intern(TargetNames));
185
186 InternedNames.insert(
187 {Es.intern(NamePair.first), std::move(TargetJITNames)});
188 }
189 return InternedNames;
190 }
191
192 IRCompileLayer &NextLayer;
193 Speculator &S;
194 PassBuilder PB;
195 FunctionAnalysisManager FAM;
196 ResultEval QueryAnalysis;
197 };
198
199 // Runtime Function Interface
200 extern "C" {
201 void __orc_speculate_for(Speculator *, uint64_t stub_id);
202 }
203
204 } // namespace orc
205 } // namespace llvm
206
207 #endif // LLVM_EXECUTIONENGINE_ORC_SPECULATION_H
2020 RPCUtils.cpp
2121 RTDyldObjectLinkingLayer.cpp
2222 ThreadSafeModule.cpp
23
23 Speculation.cpp
24 SpeculateAnalyses.cpp
2425 ADDITIONAL_HEADER_DIRS
2526 ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
2627
3031
3132 target_link_libraries(LLVMOrcJIT
3233 PRIVATE
34 LLVMAnalysis
3335 LLVMBitReader
3436 LLVMBitWriter
3537 )
117117 this->Partition = std::move(Partition);
118118 }
119119
120 void CompileOnDemandLayer::setImplMap(ImplSymbolMap *Imp) {
121 this->AliaseeImpls = Imp;
122 }
120123 void CompileOnDemandLayer::emit(MaterializationResponsibility R,
121124 ThreadSafeModule TSM) {
122125 assert(TSM && "Null module");
160163
161164 R.replace(reexports(PDR.getImplDylib(), std::move(NonCallables), true));
162165 R.replace(lazyReexports(LCTMgr, PDR.getISManager(), PDR.getImplDylib(),
163 std::move(Callables)));
166 std::move(Callables), AliaseeImpls));
164167 }
165168
166169 CompileOnDemandLayer::PerDylibResources &
4949 SourceJD = I->second.first;
5050 SymbolName = I->second.second;
5151 }
52
5352 auto LookupResult =
5453 ES.lookup(JITDylibSearchList({{SourceJD, true}}), SymbolName);
5554
120119
121120 LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit(
122121 LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager,
123 JITDylib &SourceJD, SymbolAliasMap CallableAliases, VModuleKey K)
122 JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc,
123 VModuleKey K)
124124 : MaterializationUnit(extractFlags(CallableAliases), std::move(K)),
125125 LCTManager(LCTManager), ISManager(ISManager), SourceJD(SourceJD),
126126 CallableAliases(std::move(CallableAliases)),
128128 [&ISManager](JITDylib &JD, const SymbolStringPtr &SymbolName,
129129 JITTargetAddress ResolvedAddr) {
130130 return ISManager.updatePointer(*SymbolName, ResolvedAddr);
131 })) {}
131 })),
132 AliaseeTable(SrcJDLoc) {}
132133
133134 StringRef LazyReexportsMaterializationUnit::getName() const {
134135 return "";
148149
149150 if (!CallableAliases.empty())
150151 R.replace(lazyReexports(LCTManager, ISManager, SourceJD,
151 std::move(CallableAliases)));
152 std::move(CallableAliases), AliaseeTable));
152153
153154 IndirectStubsManager::StubInitsMap StubInits;
154155 for (auto &Alias : RequestedAliases) {
166167 StubInits[*Alias.first] =
167168 std::make_pair(*CallThroughTrampoline, Alias.second.AliasFlags);
168169 }
170
171 if (AliaseeTable != nullptr && !RequestedAliases.empty())
172 AliaseeTable->trackImpls(RequestedAliases, &SourceJD);
169173
170174 if (auto Err = ISManager.createStubs(StubInits)) {
171175 SourceJD.getExecutionSession().reportError(std::move(Err));
0 //===-- SpeculateAnalyses.cpp --*- C++ -*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7
8 #include "llvm/ExecutionEngine/Orc/SpeculateAnalyses.h"
9 #include "llvm/ADT/DenseMap.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/ADT/SmallVector.h"
12 #include "llvm/Analysis/BlockFrequencyInfo.h"
13
14 // Implementations of Queries shouldn't need to lock the resources
15 // such as LLVMContext, each argument (function) has a non-shared LLVMContext
16 namespace llvm {
17 namespace orc {
18
19 // Collect direct calls only
20 void BlockFreqQuery::findCalles(const BasicBlock *BB,
21 DenseSet &CallesNames) {
22 assert(BB != nullptr && "Traversing Null BB to find calls?");
23
24 auto getCalledFunction = [&CallesNames](const CallBase *Call) {
25 auto CalledValue = Call->getCalledOperand()->stripPointerCasts();
26 if (auto DirectCall = dyn_cast(CalledValue))
27 CallesNames.insert(DirectCall->getName());
28 };
29 for (auto &I : BB->instructionsWithoutDebug())
30 if (auto CI = dyn_cast(&I))
31 getCalledFunction(CI);
32
33 if (auto II = dyn_cast(BB->getTerminator()))
34 getCalledFunction(II);
35 }
36
37 // blind calculation
38 size_t BlockFreqQuery::numBBToGet(size_t numBB) {
39 // small CFG
40 if (numBB < 4)
41 return numBB;
42 // mid-size CFG
43 else if (numBB < 20)
44 return (numBB / 2);
45 else
46 return (numBB / 2) + (numBB / 4);
47 }
48
49 BlockFreqQuery::ResultTy BlockFreqQuery::
50 operator()(Function &F, FunctionAnalysisManager &FAM) {
51 DenseMap> CallerAndCalles;
52 DenseSet Calles;
53 SmallVector, 8> BBFreqs;
54
55 auto IBBs = findBBwithCalls(F);
56
57 if (IBBs.empty())
58 return None;
59
60 auto &BFI = FAM.getResult(F);
61
62 for (const auto I : IBBs)
63 BBFreqs.push_back({I, BFI.getBlockFreq(I).getFrequency()});
64
65 assert(IBBs.size() == BBFreqs.size() && "BB Count Mismatch");
66
67 llvm::sort(BBFreqs.begin(), BBFreqs.end(),
68 [](decltype(BBFreqs)::const_reference BBF,
69 decltype(BBFreqs)::const_reference BBS) {
70 return BBF.second > BBS.second ? true : false;
71 });
72
73 // ignoring number of direct calls in a BB
74 auto Topk = numBBToGet(BBFreqs.size());
75
76 for (size_t i = 0; i < Topk; i++)
77 findCalles(BBFreqs[i].first, Calles);
78
79 assert(!Calles.empty() && "Running Analysis on Function with no calls?");
80
81 CallerAndCalles.insert({F.getName(), std::move(Calles)});
82
83 return CallerAndCalles;
84 }
85 } // namespace orc
86 } // namespace llvm
0 //===---------- speculation.cpp - Utilities for Speculation ----------===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7
8 #include "llvm/ExecutionEngine/Orc/Speculation.h"
9
10 #include "llvm/IR/BasicBlock.h"
11 #include "llvm/IR/Function.h"
12 #include "llvm/IR/IRBuilder.h"
13 #include "llvm/IR/Instruction.h"
14 #include "llvm/IR/Instructions.h"
15 #include "llvm/IR/LLVMContext.h"
16 #include "llvm/IR/Module.h"
17 #include "llvm/IR/Type.h"
18 #include "llvm/IR/Verifier.h"
19
20 #include
21
22 namespace llvm {
23
24 namespace orc {
25
26 // ImplSymbolMap methods
27 void ImplSymbolMap::trackImpls(SymbolAliasMap ImplMaps, JITDylib *SrcJD) {
28 assert(SrcJD && "Tracking on Null Source .impl dylib");
29 std::lock_guard Lockit(ConcurrentAccess);
30 for (auto &I : ImplMaps) {
31 auto It = Maps.insert({I.first, {I.second.Aliasee, SrcJD}});
32 // check rationale when independent dylibs have same symbol name?
33 assert(It.second && "ImplSymbols are already tracked for this Symbol?");
34 (void)(It);
35 }
36 }
37
38 // If two modules, share the same LLVMContext, different threads must
39 // not access those modules concurrently, doing so leave the
40 // LLVMContext in in-consistent state.
41 // But here since each TSM has a unique Context associated with it,
42 // on locking is necessary!
43 void IRSpeculationLayer::emit(MaterializationResponsibility R,
44 ThreadSafeModule TSM) {
45
46 assert(TSM && "Speculation Layer received Null Module ?");
47 assert(TSM.getContext().getContext() != nullptr &&
48 "Module with null LLVMContext?");
49
50 // Instrumentation of runtime calls
51 auto &InContext = *TSM.getContext().getContext();
52 auto SpeculatorVTy = StructType::create(InContext, "Class.Speculator");
53 auto RuntimeCallTy = FunctionType::get(
54 Type::getVoidTy(InContext),
55 {SpeculatorVTy->getPointerTo(), Type::getInt64Ty(InContext)}, false);
56 auto RuntimeCall =
57 Function::Create(RuntimeCallTy, Function::LinkageTypes::ExternalLinkage,
58 "__orc_speculate_for", TSM.getModuleUnlocked());
59 auto SpeclAddr = new GlobalVariable(
60 *TSM.getModuleUnlocked(), SpeculatorVTy, false,
61 GlobalValue::LinkageTypes::ExternalLinkage, nullptr, "__orc_speculator");
62
63 IRBuilder<> Mutator(InContext);
64
65 // QueryAnalysis allowed to transform the IR source, one such example is
66 // Simplify CFG helps the static branch prediction heuristics!
67 for (auto &Fn : TSM.getModuleUnlocked()->getFunctionList()) {
68 if (!Fn.isDeclaration()) {
69 auto IRNames = QueryAnalysis(Fn, FAM);
70 // Instrument and register if Query has result
71 if (IRNames.hasValue()) {
72 Mutator.SetInsertPoint(&(Fn.getEntryBlock().front()));
73 auto ImplAddrToUint =
74 Mutator.CreatePtrToInt(&Fn, Type::getInt64Ty(InContext));
75 Mutator.CreateCall(RuntimeCallTy, RuntimeCall,
76 {SpeclAddr, ImplAddrToUint});
77 S.registerSymbols(internToJITSymbols(IRNames.getValue()),
78 &R.getTargetJITDylib());
79 }
80 }
81 }
82 // No locking needed read only operation.
83 assert(!(verifyModule(*TSM.getModuleUnlocked())) &&
84 "Speculation Instrumentation breaks IR?");
85
86 NextLayer.emit(std::move(R), std::move(TSM));
87 }
88
89 // Runtime Function Implementation
90 extern "C" void __orc_speculate_for(Speculator *Ptr, uint64_t StubId) {
91 assert(Ptr && " Null Address Received in orc_speculate_for ");
92 Ptr->speculateFor(StubId);
93 }
94
95 } // namespace orc
96 } // namespace llvm