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