/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/LTO/LTOBackend.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-LTOBackend.cpp - LLVM Link Time Optimizer Backend -------------------===// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
4 | | // |
5 | | // This file is distributed under the University of Illinois Open Source |
6 | | // License. See LICENSE.TXT for details. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | // |
10 | | // This file implements the "backend" phase of LTO, i.e. it performs |
11 | | // optimization and code generation on a loaded module. It is generally used |
12 | | // internally by the LTO class but can also be used independently, for example |
13 | | // to implement a standalone ThinLTO backend. |
14 | | // |
15 | | //===----------------------------------------------------------------------===// |
16 | | |
17 | | #include "llvm/LTO/LTOBackend.h" |
18 | | #include "llvm/Analysis/AliasAnalysis.h" |
19 | | #include "llvm/Analysis/CGSCCPassManager.h" |
20 | | #include "llvm/Analysis/TargetLibraryInfo.h" |
21 | | #include "llvm/Analysis/TargetTransformInfo.h" |
22 | | #include "llvm/Bitcode/BitcodeReader.h" |
23 | | #include "llvm/Bitcode/BitcodeWriter.h" |
24 | | #include "llvm/IR/LegacyPassManager.h" |
25 | | #include "llvm/IR/PassManager.h" |
26 | | #include "llvm/IR/Verifier.h" |
27 | | #include "llvm/LTO/LTO.h" |
28 | | #include "llvm/MC/SubtargetFeature.h" |
29 | | #include "llvm/Object/ModuleSymbolTable.h" |
30 | | #include "llvm/Passes/PassBuilder.h" |
31 | | #include "llvm/Support/Error.h" |
32 | | #include "llvm/Support/FileSystem.h" |
33 | | #include "llvm/Support/TargetRegistry.h" |
34 | | #include "llvm/Support/ThreadPool.h" |
35 | | #include "llvm/Target/TargetMachine.h" |
36 | | #include "llvm/Transforms/IPO.h" |
37 | | #include "llvm/Transforms/IPO/PassManagerBuilder.h" |
38 | | #include "llvm/Transforms/Scalar/LoopPassManager.h" |
39 | | #include "llvm/Transforms/Utils/FunctionImportUtils.h" |
40 | | #include "llvm/Transforms/Utils/SplitModule.h" |
41 | | |
42 | | using namespace llvm; |
43 | | using namespace lto; |
44 | | |
45 | 0 | LLVM_ATTRIBUTE_NORETURN static void reportOpenError(StringRef Path, Twine Msg) { |
46 | 0 | errs() << "failed to open " << Path << ": " << Msg << '\n'; |
47 | 0 | errs().flush(); |
48 | 0 | exit(1); |
49 | 0 | } |
50 | | |
51 | | Error Config::addSaveTemps(std::string OutputFileName, |
52 | 98 | bool UseInputModulePath) { |
53 | 98 | ShouldDiscardValueNames = false; |
54 | 98 | |
55 | 98 | std::error_code EC; |
56 | 98 | ResolutionFile = llvm::make_unique<raw_fd_ostream>( |
57 | 98 | OutputFileName + "resolution.txt", EC, sys::fs::OpenFlags::F_Text); |
58 | 98 | if (EC) |
59 | 0 | return errorCodeToError(EC); |
60 | 98 | |
61 | 98 | auto setHook = [&](std::string PathSuffix, ModuleHookFn &Hook) 98 { |
62 | 588 | // Keep track of the hook provided by the linker, which also needs to run. |
63 | 588 | ModuleHookFn LinkerHook = Hook; |
64 | 565 | Hook = [=](unsigned Task, const Module &M) { |
65 | 565 | // If the linker's hook returned false, we need to pass that result |
66 | 565 | // through. |
67 | 565 | if (LinkerHook && 565 !LinkerHook(Task, M)0 ) |
68 | 0 | return false; |
69 | 565 | |
70 | 565 | std::string PathPrefix; |
71 | 565 | // If this is the combined module (not a ThinLTO backend compile) or the |
72 | 565 | // user hasn't requested using the input module's path, emit to a file |
73 | 565 | // named from the provided OutputFileName with the Task ID appended. |
74 | 565 | if (M.getModuleIdentifier() == "ld-temp.o" || 565 !UseInputModulePath274 ) { |
75 | 524 | PathPrefix = OutputFileName + utostr(Task); |
76 | 524 | } else |
77 | 41 | PathPrefix = M.getModuleIdentifier(); |
78 | 565 | std::string Path = PathPrefix + "." + PathSuffix + ".bc"; |
79 | 565 | std::error_code EC; |
80 | 565 | raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::F_None); |
81 | 565 | // Because -save-temps is a debugging feature, we report the error |
82 | 565 | // directly and exit. |
83 | 565 | if (EC) |
84 | 0 | reportOpenError(Path, EC.message()); |
85 | 565 | WriteBitcodeToFile(&M, OS, /*ShouldPreserveUseListOrder=*/false); |
86 | 565 | return true; |
87 | 565 | }; |
88 | 588 | }; |
89 | 98 | |
90 | 98 | setHook("0.preopt", PreOptModuleHook); |
91 | 98 | setHook("1.promote", PostPromoteModuleHook); |
92 | 98 | setHook("2.internalize", PostInternalizeModuleHook); |
93 | 98 | setHook("3.import", PostImportModuleHook); |
94 | 98 | setHook("4.opt", PostOptModuleHook); |
95 | 98 | setHook("5.precodegen", PreCodeGenModuleHook); |
96 | 98 | |
97 | 31 | CombinedIndexHook = [=](const ModuleSummaryIndex &Index) { |
98 | 31 | std::string Path = OutputFileName + "index.bc"; |
99 | 31 | std::error_code EC; |
100 | 31 | raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::F_None); |
101 | 31 | // Because -save-temps is a debugging feature, we report the error |
102 | 31 | // directly and exit. |
103 | 31 | if (EC) |
104 | 0 | reportOpenError(Path, EC.message()); |
105 | 31 | WriteIndexToFile(Index, OS); |
106 | 31 | return true; |
107 | 31 | }; |
108 | 98 | |
109 | 98 | return Error::success(); |
110 | 98 | } |
111 | | |
112 | | namespace { |
113 | | |
114 | | std::unique_ptr<TargetMachine> |
115 | 312 | createTargetMachine(Config &Conf, const Target *TheTarget, Module &M) { |
116 | 312 | StringRef TheTriple = M.getTargetTriple(); |
117 | 312 | SubtargetFeatures Features; |
118 | 312 | Features.getDefaultSubtargetFeatures(Triple(TheTriple)); |
119 | 312 | for (const std::string &A : Conf.MAttrs) |
120 | 31 | Features.AddFeature(A); |
121 | 312 | |
122 | 312 | Reloc::Model RelocModel; |
123 | 312 | if (Conf.RelocModel) |
124 | 311 | RelocModel = *Conf.RelocModel; |
125 | 312 | else |
126 | 1 | RelocModel = |
127 | 18.4E | M.getPICLevel() == PICLevel::NotPIC ? Reloc::Static2 : Reloc::PIC_18.4E ; |
128 | 312 | |
129 | 312 | return std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine( |
130 | 312 | TheTriple, Conf.CPU, Features.getString(), Conf.Options, RelocModel, |
131 | 312 | Conf.CodeModel, Conf.CGOptLevel)); |
132 | 312 | } |
133 | | |
134 | | static void runNewPMPasses(Config &Conf, Module &Mod, TargetMachine *TM, |
135 | 4 | unsigned OptLevel, bool IsThinLTO) { |
136 | 4 | Optional<PGOOptions> PGOOpt; |
137 | 4 | if (!Conf.SampleProfile.empty()) |
138 | 1 | PGOOpt = PGOOptions("", "", Conf.SampleProfile, false, true); |
139 | 4 | |
140 | 4 | PassBuilder PB(TM, PGOOpt); |
141 | 4 | AAManager AA; |
142 | 4 | |
143 | 4 | // Parse a custom AA pipeline if asked to. |
144 | 4 | if (!PB.parseAAPipeline(AA, "default")) |
145 | 0 | report_fatal_error("Error parsing default AA pipeline"); |
146 | 4 | |
147 | 4 | LoopAnalysisManager LAM(Conf.DebugPassManager); |
148 | 4 | FunctionAnalysisManager FAM(Conf.DebugPassManager); |
149 | 4 | CGSCCAnalysisManager CGAM(Conf.DebugPassManager); |
150 | 4 | ModuleAnalysisManager MAM(Conf.DebugPassManager); |
151 | 4 | |
152 | 4 | // Register the AA manager first so that our version is the one used. |
153 | 4 | FAM.registerPass([&] { return std::move(AA); }); |
154 | 4 | |
155 | 4 | // Register all the basic analyses with the managers. |
156 | 4 | PB.registerModuleAnalyses(MAM); |
157 | 4 | PB.registerCGSCCAnalyses(CGAM); |
158 | 4 | PB.registerFunctionAnalyses(FAM); |
159 | 4 | PB.registerLoopAnalyses(LAM); |
160 | 4 | PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); |
161 | 4 | |
162 | 4 | ModulePassManager MPM(Conf.DebugPassManager); |
163 | 4 | // FIXME (davide): verify the input. |
164 | 4 | |
165 | 4 | PassBuilder::OptimizationLevel OL; |
166 | 4 | |
167 | 4 | switch (OptLevel) { |
168 | 0 | default: |
169 | 0 | llvm_unreachable("Invalid optimization level"); |
170 | 0 | case 0: |
171 | 0 | OL = PassBuilder::O0; |
172 | 0 | break; |
173 | 0 | case 1: |
174 | 0 | OL = PassBuilder::O1; |
175 | 0 | break; |
176 | 4 | case 2: |
177 | 4 | OL = PassBuilder::O2; |
178 | 4 | break; |
179 | 0 | case 3: |
180 | 0 | OL = PassBuilder::O3; |
181 | 0 | break; |
182 | 4 | } |
183 | 4 | |
184 | 4 | if (4 IsThinLTO4 ) |
185 | 2 | MPM = PB.buildThinLTODefaultPipeline(OL, Conf.DebugPassManager); |
186 | 4 | else |
187 | 2 | MPM = PB.buildLTODefaultPipeline(OL, Conf.DebugPassManager); |
188 | 4 | MPM.run(Mod, MAM); |
189 | 4 | |
190 | 4 | // FIXME (davide): verify the output. |
191 | 4 | } |
192 | | |
193 | | static void runNewPMCustomPasses(Module &Mod, TargetMachine *TM, |
194 | | std::string PipelineDesc, |
195 | | std::string AAPipelineDesc, |
196 | 8 | bool DisableVerify) { |
197 | 8 | PassBuilder PB(TM); |
198 | 8 | AAManager AA; |
199 | 8 | |
200 | 8 | // Parse a custom AA pipeline if asked to. |
201 | 8 | if (!AAPipelineDesc.empty()) |
202 | 4 | if (4 !PB.parseAAPipeline(AA, AAPipelineDesc)4 ) |
203 | 2 | report_fatal_error("unable to parse AA pipeline description: " + |
204 | 2 | AAPipelineDesc); |
205 | 6 | |
206 | 6 | LoopAnalysisManager LAM; |
207 | 6 | FunctionAnalysisManager FAM; |
208 | 6 | CGSCCAnalysisManager CGAM; |
209 | 6 | ModuleAnalysisManager MAM; |
210 | 6 | |
211 | 6 | // Register the AA manager first so that our version is the one used. |
212 | 6 | FAM.registerPass([&] { return std::move(AA); }); |
213 | 6 | |
214 | 6 | // Register all the basic analyses with the managers. |
215 | 6 | PB.registerModuleAnalyses(MAM); |
216 | 6 | PB.registerCGSCCAnalyses(CGAM); |
217 | 6 | PB.registerFunctionAnalyses(FAM); |
218 | 6 | PB.registerLoopAnalyses(LAM); |
219 | 6 | PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); |
220 | 6 | |
221 | 6 | ModulePassManager MPM; |
222 | 6 | |
223 | 6 | // Always verify the input. |
224 | 6 | MPM.addPass(VerifierPass()); |
225 | 6 | |
226 | 6 | // Now, add all the passes we've been requested to. |
227 | 6 | if (!PB.parsePassPipeline(MPM, PipelineDesc)) |
228 | 2 | report_fatal_error("unable to parse pass pipeline description: " + |
229 | 2 | PipelineDesc); |
230 | 4 | |
231 | 4 | if (4 !DisableVerify4 ) |
232 | 4 | MPM.addPass(VerifierPass()); |
233 | 8 | MPM.run(Mod, MAM); |
234 | 8 | } |
235 | | |
236 | | static void runOldPMPasses(Config &Conf, Module &Mod, TargetMachine *TM, |
237 | | bool IsThinLTO, ModuleSummaryIndex *ExportSummary, |
238 | 299 | const ModuleSummaryIndex *ImportSummary) { |
239 | 299 | legacy::PassManager passes; |
240 | 299 | passes.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis())); |
241 | 299 | |
242 | 299 | PassManagerBuilder PMB; |
243 | 299 | PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM->getTargetTriple())); |
244 | 299 | PMB.Inliner = createFunctionInliningPass(); |
245 | 299 | PMB.ExportSummary = ExportSummary; |
246 | 299 | PMB.ImportSummary = ImportSummary; |
247 | 299 | // Unconditionally verify input since it is not verified before this |
248 | 299 | // point and has unknown origin. |
249 | 299 | PMB.VerifyInput = true; |
250 | 299 | PMB.VerifyOutput = !Conf.DisableVerify; |
251 | 299 | PMB.LoopVectorize = true; |
252 | 299 | PMB.SLPVectorize = true; |
253 | 299 | PMB.OptLevel = Conf.OptLevel; |
254 | 299 | PMB.PGOSampleUse = Conf.SampleProfile; |
255 | 299 | if (IsThinLTO) |
256 | 129 | PMB.populateThinLTOPassManager(passes); |
257 | 299 | else |
258 | 170 | PMB.populateLTOPassManager(passes); |
259 | 299 | passes.run(Mod); |
260 | 299 | } |
261 | | |
262 | | bool opt(Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, |
263 | | bool IsThinLTO, ModuleSummaryIndex *ExportSummary, |
264 | 311 | const ModuleSummaryIndex *ImportSummary) { |
265 | 311 | // FIXME: Plumb the combined index into the new pass manager. |
266 | 311 | if (!Conf.OptPipeline.empty()) |
267 | 8 | runNewPMCustomPasses(Mod, TM, Conf.OptPipeline, Conf.AAPipeline, |
268 | 8 | Conf.DisableVerify); |
269 | 303 | else if (303 Conf.UseNewPM303 ) |
270 | 4 | runNewPMPasses(Conf, Mod, TM, Conf.OptLevel, IsThinLTO); |
271 | 303 | else |
272 | 299 | runOldPMPasses(Conf, Mod, TM, IsThinLTO, ExportSummary, ImportSummary); |
273 | 118 | return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod); |
274 | 311 | } |
275 | | |
276 | | void codegen(Config &Conf, TargetMachine *TM, AddStreamFn AddStream, |
277 | 311 | unsigned Task, Module &Mod) { |
278 | 311 | if (Conf.PreCodeGenModuleHook && 311 !Conf.PreCodeGenModuleHook(Task, Mod)123 ) |
279 | 3 | return; |
280 | 308 | |
281 | 308 | auto Stream = AddStream(Task); |
282 | 308 | legacy::PassManager CodeGenPasses; |
283 | 308 | if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS, Conf.CGFileType)) |
284 | 0 | report_fatal_error("Failed to setup codegen"); |
285 | 308 | CodeGenPasses.run(Mod); |
286 | 308 | } |
287 | | |
288 | | void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream, |
289 | | unsigned ParallelCodeGenParallelismLevel, |
290 | 3 | std::unique_ptr<Module> Mod) { |
291 | 3 | ThreadPool CodegenThreadPool(ParallelCodeGenParallelismLevel); |
292 | 3 | unsigned ThreadCount = 0; |
293 | 3 | const Target *T = &TM->getTarget(); |
294 | 3 | |
295 | 3 | SplitModule( |
296 | 3 | std::move(Mod), ParallelCodeGenParallelismLevel, |
297 | 6 | [&](std::unique_ptr<Module> MPart) { |
298 | 6 | // We want to clone the module in a new context to multi-thread the |
299 | 6 | // codegen. We do it by serializing partition modules to bitcode |
300 | 6 | // (while still on the main thread, in order to avoid data races) and |
301 | 6 | // spinning up new threads which deserialize the partitions into |
302 | 6 | // separate contexts. |
303 | 6 | // FIXME: Provide a more direct way to do this in LLVM. |
304 | 6 | SmallString<0> BC; |
305 | 6 | raw_svector_ostream BCOS(BC); |
306 | 6 | WriteBitcodeToFile(MPart.get(), BCOS); |
307 | 6 | |
308 | 6 | // Enqueue the task |
309 | 6 | CodegenThreadPool.async( |
310 | 6 | [&](const SmallString<0> &BC, unsigned ThreadId) { |
311 | 6 | LTOLLVMContext Ctx(C); |
312 | 6 | Expected<std::unique_ptr<Module>> MOrErr = parseBitcodeFile( |
313 | 6 | MemoryBufferRef(StringRef(BC.data(), BC.size()), "ld-temp.o"), |
314 | 6 | Ctx); |
315 | 6 | if (!MOrErr) |
316 | 0 | report_fatal_error("Failed to read bitcode"); |
317 | 6 | std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get()); |
318 | 6 | |
319 | 6 | std::unique_ptr<TargetMachine> TM = |
320 | 6 | createTargetMachine(C, T, *MPartInCtx); |
321 | 6 | |
322 | 6 | codegen(C, TM.get(), AddStream, ThreadId, *MPartInCtx); |
323 | 6 | }, |
324 | 6 | // Pass BC using std::move to ensure that it get moved rather than |
325 | 6 | // copied into the thread's context. |
326 | 6 | std::move(BC), ThreadCount++); |
327 | 6 | }, |
328 | 3 | false); |
329 | 3 | |
330 | 3 | // Because the inner lambda (which runs in a worker thread) captures our local |
331 | 3 | // variables, we need to wait for the worker threads to terminate before we |
332 | 3 | // can leave the function scope. |
333 | 3 | CodegenThreadPool.wait(); |
334 | 3 | } |
335 | | |
336 | 309 | Expected<const Target *> initAndLookupTarget(Config &C, Module &Mod) { |
337 | 309 | if (!C.OverrideTriple.empty()) |
338 | 1 | Mod.setTargetTriple(C.OverrideTriple); |
339 | 308 | else if (308 Mod.getTargetTriple().empty()308 ) |
340 | 0 | Mod.setTargetTriple(C.DefaultTriple); |
341 | 309 | |
342 | 309 | std::string Msg; |
343 | 309 | const Target *T = TargetRegistry::lookupTarget(Mod.getTargetTriple(), Msg); |
344 | 309 | if (!T) |
345 | 0 | return make_error<StringError>(Msg, inconvertibleErrorCode()); |
346 | 309 | return T; |
347 | 309 | } |
348 | | |
349 | | } |
350 | | |
351 | | static void |
352 | 176 | finalizeOptimizationRemarks(std::unique_ptr<ToolOutputFile> DiagOutputFile) { |
353 | 176 | // Make sure we flush the diagnostic remarks file in case the linker doesn't |
354 | 176 | // call the global destructors before exiting. |
355 | 176 | if (!DiagOutputFile) |
356 | 172 | return; |
357 | 4 | DiagOutputFile->keep(); |
358 | 4 | DiagOutputFile->os().flush(); |
359 | 4 | } |
360 | | |
361 | | Error lto::backend(Config &C, AddStreamFn AddStream, |
362 | | unsigned ParallelCodeGenParallelismLevel, |
363 | | std::unique_ptr<Module> Mod, |
364 | 180 | ModuleSummaryIndex &CombinedIndex) { |
365 | 180 | Expected<const Target *> TOrErr = initAndLookupTarget(C, *Mod); |
366 | 180 | if (!TOrErr) |
367 | 0 | return TOrErr.takeError(); |
368 | 180 | |
369 | 180 | std::unique_ptr<TargetMachine> TM = createTargetMachine(C, *TOrErr, *Mod); |
370 | 180 | |
371 | 180 | // Setup optimization remarks. |
372 | 180 | auto DiagFileOrErr = lto::setupOptimizationRemarks( |
373 | 180 | Mod->getContext(), C.RemarksFilename, C.RemarksWithHotness); |
374 | 180 | if (!DiagFileOrErr) |
375 | 0 | return DiagFileOrErr.takeError(); |
376 | 180 | auto DiagnosticOutputFile = std::move(*DiagFileOrErr); |
377 | 180 | |
378 | 180 | if (!C.CodeGenOnly180 ) { |
379 | 180 | if (!opt(C, TM.get(), 0, *Mod, /*IsThinLTO=*/false, |
380 | 180 | /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr)) { |
381 | 0 | finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); |
382 | 0 | return Error::success(); |
383 | 0 | } |
384 | 180 | } |
385 | 180 | |
386 | 180 | if (180 ParallelCodeGenParallelismLevel == 1180 ) { |
387 | 173 | codegen(C, TM.get(), AddStream, 0, *Mod); |
388 | 180 | } else { |
389 | 7 | splitCodeGen(C, TM.get(), AddStream, ParallelCodeGenParallelismLevel, |
390 | 7 | std::move(Mod)); |
391 | 7 | } |
392 | 180 | finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); |
393 | 180 | return Error::success(); |
394 | 180 | } |
395 | | |
396 | | Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream, |
397 | | Module &Mod, const ModuleSummaryIndex &CombinedIndex, |
398 | | const FunctionImporter::ImportMapTy &ImportList, |
399 | | const GVSummaryMapTy &DefinedGlobals, |
400 | 128 | MapVector<StringRef, BitcodeModule> &ModuleMap) { |
401 | 128 | Expected<const Target *> TOrErr = initAndLookupTarget(Conf, Mod); |
402 | 128 | if (!TOrErr) |
403 | 0 | return TOrErr.takeError(); |
404 | 128 | |
405 | 128 | std::unique_ptr<TargetMachine> TM = createTargetMachine(Conf, *TOrErr, Mod); |
406 | 128 | |
407 | 128 | if (Conf.CodeGenOnly128 ) { |
408 | 0 | codegen(Conf, TM.get(), AddStream, Task, Mod); |
409 | 0 | return Error::success(); |
410 | 0 | } |
411 | 128 | |
412 | 128 | if (128 Conf.PreOptModuleHook && 128 !Conf.PreOptModuleHook(Task, Mod)43 ) |
413 | 0 | return Error::success(); |
414 | 128 | |
415 | 128 | renameModuleForThinLTO(Mod, CombinedIndex); |
416 | 128 | |
417 | 128 | thinLTOResolveWeakForLinkerModule(Mod, DefinedGlobals); |
418 | 128 | |
419 | 128 | if (Conf.PostPromoteModuleHook && 128 !Conf.PostPromoteModuleHook(Task, Mod)46 ) |
420 | 0 | return Error::success(); |
421 | 128 | |
422 | 128 | if (128 !DefinedGlobals.empty()128 ) |
423 | 128 | thinLTOInternalizeModule(Mod, DefinedGlobals); |
424 | 128 | |
425 | 128 | if (Conf.PostInternalizeModuleHook && |
426 | 45 | !Conf.PostInternalizeModuleHook(Task, Mod)) |
427 | 0 | return Error::success(); |
428 | 128 | |
429 | 128 | auto ModuleLoader = [&](StringRef Identifier) 128 { |
430 | 40 | assert(Mod.getContext().isODRUniquingDebugTypes() && |
431 | 40 | "ODR Type uniquing should be enabled on the context"); |
432 | 40 | auto I = ModuleMap.find(Identifier); |
433 | 40 | assert(I != ModuleMap.end()); |
434 | 40 | return I->second.getLazyModule(Mod.getContext(), |
435 | 40 | /*ShouldLazyLoadMetadata=*/true, |
436 | 40 | /*IsImporting*/ true); |
437 | 40 | }; |
438 | 128 | |
439 | 128 | FunctionImporter Importer(CombinedIndex, ModuleLoader); |
440 | 128 | if (Error Err = Importer.importFunctions(Mod, ImportList).takeError()) |
441 | 0 | return Err; |
442 | 128 | |
443 | 128 | if (128 Conf.PostImportModuleHook && 128 !Conf.PostImportModuleHook(Task, Mod)46 ) |
444 | 0 | return Error::success(); |
445 | 128 | |
446 | 128 | if (128 !opt(Conf, TM.get(), Task, Mod, /*IsThinLTO=*/true, |
447 | 128 | /*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex)) |
448 | 0 | return Error::success(); |
449 | 128 | |
450 | 128 | codegen(Conf, TM.get(), AddStream, Task, Mod); |
451 | 128 | return Error::success(); |
452 | 128 | } |