1 | #include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" |
2 | #include "llvm/ExecutionEngine/Orc/CompileUtils.h" |
3 | #include "llvm/ExecutionEngine/Orc/Core.h" |
4 | #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" |
5 | #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" |
6 | #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" |
7 | #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" |
8 | #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" |
9 | #include "llvm/ExecutionEngine/Orc/SpeculateAnalyses.h" |
10 | #include "llvm/ExecutionEngine/Orc/Speculation.h" |
11 | #include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h" |
12 | #include "llvm/ExecutionEngine/SectionMemoryManager.h" |
13 | #include "llvm/IRReader/IRReader.h" |
14 | #include "llvm/Support/CommandLine.h" |
15 | #include "llvm/Support/Debug.h" |
16 | #include "llvm/Support/InitLLVM.h" |
17 | #include "llvm/Support/SourceMgr.h" |
18 | #include "llvm/Support/TargetSelect.h" |
19 | #include "llvm/Support/ThreadPool.h" |
20 | |
21 | #include <list> |
22 | #include <string> |
23 | |
24 | using namespace llvm; |
25 | using namespace llvm::orc; |
26 | |
27 | static cl::list<std::string> InputFiles(cl::Positional, cl::OneOrMore, |
28 | cl::desc("input files" )); |
29 | |
30 | static cl::list<std::string> InputArgv("args" , cl::Positional, |
31 | cl::desc("<program arguments>..." ), |
32 | cl::PositionalEatsArgs); |
33 | |
34 | static cl::opt<unsigned> NumThreads("num-threads" , cl::Optional, |
35 | cl::desc("Number of compile threads" ), |
36 | cl::init(Val: 4)); |
37 | |
38 | ExitOnError ExitOnErr; |
39 | |
40 | // Add Layers |
41 | class SpeculativeJIT { |
42 | public: |
43 | static Expected<std::unique_ptr<SpeculativeJIT>> Create() { |
44 | auto JTMB = orc::JITTargetMachineBuilder::detectHost(); |
45 | if (!JTMB) |
46 | return JTMB.takeError(); |
47 | |
48 | auto DL = JTMB->getDefaultDataLayoutForTarget(); |
49 | if (!DL) |
50 | return DL.takeError(); |
51 | |
52 | auto EPC = SelfExecutorProcessControl::Create( |
53 | SSP: nullptr, |
54 | D: std::make_unique<DynamicThreadPoolTaskDispatcher>(args: std::nullopt)); |
55 | if (!EPC) |
56 | return EPC.takeError(); |
57 | |
58 | auto ES = std::make_unique<ExecutionSession>(args: std::move(*EPC)); |
59 | |
60 | auto LCTMgr = createLocalLazyCallThroughManager( |
61 | T: JTMB->getTargetTriple(), ES&: *ES, |
62 | ErrorHandlerAddr: ExecutorAddr::fromPtr(Ptr: explodeOnLazyCompileFailure)); |
63 | if (!LCTMgr) |
64 | return LCTMgr.takeError(); |
65 | |
66 | auto ISMBuilder = |
67 | createLocalIndirectStubsManagerBuilder(T: JTMB->getTargetTriple()); |
68 | if (!ISMBuilder) |
69 | return make_error<StringError>(Args: "No indirect stubs manager for target" , |
70 | Args: inconvertibleErrorCode()); |
71 | |
72 | auto ProcessSymbolsSearchGenerator = |
73 | DynamicLibrarySearchGenerator::GetForCurrentProcess( |
74 | GlobalPrefix: DL->getGlobalPrefix()); |
75 | if (!ProcessSymbolsSearchGenerator) |
76 | return ProcessSymbolsSearchGenerator.takeError(); |
77 | |
78 | std::unique_ptr<SpeculativeJIT> SJ(new SpeculativeJIT( |
79 | std::move(ES), std::move(*DL), std::move(*JTMB), std::move(*LCTMgr), |
80 | std::move(ISMBuilder), std::move(*ProcessSymbolsSearchGenerator))); |
81 | return std::move(SJ); |
82 | } |
83 | |
84 | ExecutionSession &getES() { return *ES; } |
85 | |
86 | Error addModule(ThreadSafeModule TSM) { |
87 | return CODLayer.add(JD&: MainJD, TSM: std::move(TSM)); |
88 | } |
89 | |
90 | Expected<ExecutorSymbolDef> lookup(StringRef UnmangledName) { |
91 | return ES->lookup(SearchOrder: {&MainJD}, Symbol: Mangle(UnmangledName)); |
92 | } |
93 | |
94 | ~SpeculativeJIT() { CompileThreads.wait(); } |
95 | |
96 | private: |
97 | using IndirectStubsManagerBuilderFunction = |
98 | std::function<std::unique_ptr<IndirectStubsManager>()>; |
99 | |
100 | static void explodeOnLazyCompileFailure() { |
101 | errs() << "Lazy compilation failed, Symbol Implmentation not found!\n" ; |
102 | exit(status: 1); |
103 | } |
104 | |
105 | SpeculativeJIT( |
106 | std::unique_ptr<ExecutionSession> ES, DataLayout DL, |
107 | orc::JITTargetMachineBuilder JTMB, |
108 | std::unique_ptr<LazyCallThroughManager> LCTMgr, |
109 | IndirectStubsManagerBuilderFunction ISMBuilder, |
110 | std::unique_ptr<DynamicLibrarySearchGenerator> ProcessSymbolsGenerator) |
111 | : ES(std::move(ES)), DL(std::move(DL)), |
112 | MainJD(this->ES->createBareJITDylib(Name: "<main>" )), LCTMgr(std::move(LCTMgr)), |
113 | CompileLayer(*this->ES, ObjLayer, |
114 | std::make_unique<ConcurrentIRCompiler>(args: std::move(JTMB))), |
115 | S(Imps, *this->ES), |
116 | SpeculateLayer(*this->ES, CompileLayer, S, Mangle, BlockFreqQuery()), |
117 | CODLayer(*this->ES, SpeculateLayer, *this->LCTMgr, |
118 | std::move(ISMBuilder)) { |
119 | MainJD.addGenerator(DefGenerator: std::move(ProcessSymbolsGenerator)); |
120 | this->CODLayer.setImplMap(&Imps); |
121 | ExitOnErr(S.addSpeculationRuntime(JD&: MainJD, Mangle)); |
122 | LocalCXXRuntimeOverrides CXXRuntimeoverrides; |
123 | ExitOnErr(CXXRuntimeoverrides.enable(JD&: MainJD, Mangler&: Mangle)); |
124 | } |
125 | |
126 | static std::unique_ptr<SectionMemoryManager> createMemMgr() { |
127 | return std::make_unique<SectionMemoryManager>(); |
128 | } |
129 | |
130 | std::unique_ptr<ExecutionSession> ES; |
131 | DataLayout DL; |
132 | MangleAndInterner Mangle{*ES, DL}; |
133 | DefaultThreadPool CompileThreads{llvm::hardware_concurrency(ThreadCount: NumThreads)}; |
134 | |
135 | JITDylib &MainJD; |
136 | |
137 | Triple TT; |
138 | std::unique_ptr<LazyCallThroughManager> 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, Overview: "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 = std::make_unique<LLVMContext>(); |
170 | auto M = parseIRFile(Filename: InputFile, Err, Context&: *Ctx); |
171 | if (!M) { |
172 | Err.print(ProgName: argv[0], S&: errs()); |
173 | return 1; |
174 | } |
175 | |
176 | ExitOnErr(SJ->addModule(TSM: ThreadSafeModule(std::move(M), std::move(Ctx)))); |
177 | } |
178 | |
179 | auto MainSym = ExitOnErr(SJ->lookup(UnmangledName: "main" )); |
180 | auto Main = MainSym.getAddress().toPtr<int (*)(int, char *[])>(); |
181 | |
182 | return runAsMain(Main, Args: InputArgv, ProgramName: StringRef(InputFiles.front())); |
183 | |
184 | return 0; |
185 | } |
186 | |