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/TargetLibraryInfo.h"
19 #include "llvm/Analysis/TargetTransformInfo.h"
20 #include "llvm/Bitcode/ReaderWriter.h"
21 #include "llvm/IR/LegacyPassManager.h"
22 #include "llvm/LTO/LTO.h"
23 #include "llvm/MC/SubtargetFeature.h"
24 #include "llvm/Support/Error.h"
25 #include "llvm/Support/FileSystem.h"
26 #include "llvm/Support/TargetRegistry.h"
27 #include "llvm/Support/ThreadPool.h"
28 #include "llvm/Target/TargetMachine.h"
29 #include "llvm/Transforms/IPO.h"
30 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
31 #include "llvm/Transforms/Utils/FunctionImportUtils.h"
32 #include "llvm/Transforms/Utils/SplitModule.h"
33 
34 using namespace llvm;
35 using namespace lto;
36 
37 Error Config::addSaveTemps(std::string OutputFileName,
38                            bool UseInputModulePath) {
39   ShouldDiscardValueNames = false;
40 
41   std::error_code EC;
42   ResolutionFile = llvm::make_unique<raw_fd_ostream>(
43       OutputFileName + "resolution.txt", EC, sys::fs::OpenFlags::F_Text);
44   if (EC)
45     return errorCodeToError(EC);
46 
47   auto setHook = [&](std::string PathSuffix, ModuleHookFn &Hook) {
48     // Keep track of the hook provided by the linker, which also needs to run.
49     ModuleHookFn LinkerHook = Hook;
50     Hook = [=](unsigned Task, const Module &M) {
51       // If the linker's hook returned false, we need to pass that result
52       // through.
53       if (LinkerHook && !LinkerHook(Task, M))
54         return false;
55 
56       std::string PathPrefix;
57       // If this is the combined module (not a ThinLTO backend compile) or the
58       // user hasn't requested using the input module's path, emit to a file
59       // named from the provided OutputFileName with the Task ID appended.
60       if (M.getModuleIdentifier() == "ld-temp.o" || !UseInputModulePath) {
61         PathPrefix = OutputFileName + utostr(Task);
62       } else
63         PathPrefix = M.getModuleIdentifier();
64       std::string Path = PathPrefix + "." + PathSuffix + ".bc";
65       std::error_code EC;
66       raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::F_None);
67       if (EC) {
68         // Because -save-temps is a debugging feature, we report the error
69         // directly and exit.
70         llvm::errs() << "failed to open " << Path << ": " << EC.message()
71                      << '\n';
72         exit(1);
73       }
74       WriteBitcodeToFile(&M, OS, /*ShouldPreserveUseListOrder=*/false);
75       return true;
76     };
77   };
78 
79   setHook("0.preopt", PreOptModuleHook);
80   setHook("1.promote", PostPromoteModuleHook);
81   setHook("2.internalize", PostInternalizeModuleHook);
82   setHook("3.import", PostImportModuleHook);
83   setHook("4.opt", PostOptModuleHook);
84   setHook("5.precodegen", PreCodeGenModuleHook);
85 
86   CombinedIndexHook = [=](const ModuleSummaryIndex &Index) {
87     std::string Path = OutputFileName + "index.bc";
88     std::error_code EC;
89     raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::F_None);
90     if (EC) {
91       // Because -save-temps is a debugging feature, we report the error
92       // directly and exit.
93       llvm::errs() << "failed to open " << Path << ": " << EC.message() << '\n';
94       exit(1);
95     }
96     WriteIndexToFile(Index, OS);
97     return true;
98   };
99 
100   return Error();
101 }
102 
103 namespace {
104 
105 std::unique_ptr<TargetMachine>
106 createTargetMachine(Config &C, StringRef TheTriple, const Target *TheTarget) {
107   SubtargetFeatures Features;
108   Features.getDefaultSubtargetFeatures(Triple(TheTriple));
109   for (const std::string &A : C.MAttrs)
110     Features.AddFeature(A);
111 
112   return std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine(
113       TheTriple, C.CPU, Features.getString(), C.Options, C.RelocModel,
114       C.CodeModel, C.CGOptLevel));
115 }
116 
117 bool opt(Config &C, TargetMachine *TM, unsigned Task, Module &M,
118          bool IsThinLto) {
119   M.setDataLayout(TM->createDataLayout());
120 
121   legacy::PassManager passes;
122   passes.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis()));
123 
124   PassManagerBuilder PMB;
125   PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM->getTargetTriple()));
126   PMB.Inliner = createFunctionInliningPass();
127   // Unconditionally verify input since it is not verified before this
128   // point and has unknown origin.
129   PMB.VerifyInput = true;
130   PMB.VerifyOutput = !C.DisableVerify;
131   PMB.LoopVectorize = true;
132   PMB.SLPVectorize = true;
133   PMB.OptLevel = C.OptLevel;
134   if (IsThinLto)
135     PMB.populateThinLTOPassManager(passes);
136   else
137     PMB.populateLTOPassManager(passes);
138   passes.run(M);
139 
140   if (C.PostOptModuleHook && !C.PostOptModuleHook(Task, M))
141     return false;
142 
143   return true;
144 }
145 
146 /// Monolithic LTO does not support caching (yet), this is a convenient wrapper
147 /// around AddOutput to workaround this.
148 static AddOutputFn getUncachedOutputWrapper(AddOutputFn &AddOutput,
149                                             unsigned Task) {
150   return [Task, &AddOutput](unsigned TaskId) {
151     auto Output = AddOutput(Task);
152     if (Output->isCachingEnabled() && Output->tryLoadFromCache(""))
153       report_fatal_error("Cache hit without a valid key?");
154     errs() << Task << " == " << TaskId << "\n";
155     assert(Task == TaskId && "Unexpexted TaskId mismatch");
156     return Output;
157   };
158 }
159 
160 void codegen(Config &C, TargetMachine *TM, AddOutputFn AddOutput, unsigned Task,
161              Module &M) {
162   if (C.PreCodeGenModuleHook && !C.PreCodeGenModuleHook(Task, M))
163     return;
164 
165   auto Output = AddOutput(Task);
166   std::unique_ptr<raw_pwrite_stream> OS = Output->getStream();
167   legacy::PassManager CodeGenPasses;
168   if (TM->addPassesToEmitFile(CodeGenPasses, *OS,
169                               TargetMachine::CGFT_ObjectFile))
170     report_fatal_error("Failed to setup codegen");
171   CodeGenPasses.run(M);
172 }
173 
174 void splitCodeGen(Config &C, TargetMachine *TM, AddOutputFn AddOutput,
175                   unsigned ParallelCodeGenParallelismLevel,
176                   std::unique_ptr<Module> M) {
177   ThreadPool CodegenThreadPool(ParallelCodeGenParallelismLevel);
178   unsigned ThreadCount = 0;
179   const Target *T = &TM->getTarget();
180 
181   SplitModule(
182       std::move(M), ParallelCodeGenParallelismLevel,
183       [&](std::unique_ptr<Module> MPart) {
184         // We want to clone the module in a new context to multi-thread the
185         // codegen. We do it by serializing partition modules to bitcode
186         // (while still on the main thread, in order to avoid data races) and
187         // spinning up new threads which deserialize the partitions into
188         // separate contexts.
189         // FIXME: Provide a more direct way to do this in LLVM.
190         SmallString<0> BC;
191         raw_svector_ostream BCOS(BC);
192         WriteBitcodeToFile(MPart.get(), BCOS);
193 
194         // Enqueue the task
195         CodegenThreadPool.async(
196             [&](const SmallString<0> &BC, unsigned ThreadId) {
197               LTOLLVMContext Ctx(C);
198               ErrorOr<std::unique_ptr<Module>> MOrErr = parseBitcodeFile(
199                   MemoryBufferRef(StringRef(BC.data(), BC.size()), "ld-temp.o"),
200                   Ctx);
201               if (!MOrErr)
202                 report_fatal_error("Failed to read bitcode");
203               std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get());
204 
205               std::unique_ptr<TargetMachine> TM =
206                   createTargetMachine(C, MPartInCtx->getTargetTriple(), T);
207 
208               codegen(C, TM.get(),
209                       getUncachedOutputWrapper(AddOutput, ThreadId), ThreadId,
210                       *MPartInCtx);
211             },
212             // Pass BC using std::move to ensure that it get moved rather than
213             // copied into the thread's context.
214             std::move(BC), ThreadCount++);
215       },
216       false);
217 }
218 
219 Expected<const Target *> initAndLookupTarget(Config &C, Module &M) {
220   if (!C.OverrideTriple.empty())
221     M.setTargetTriple(C.OverrideTriple);
222   else if (M.getTargetTriple().empty())
223     M.setTargetTriple(C.DefaultTriple);
224 
225   std::string Msg;
226   const Target *T = TargetRegistry::lookupTarget(M.getTargetTriple(), Msg);
227   if (!T)
228     return make_error<StringError>(Msg, inconvertibleErrorCode());
229   return T;
230 }
231 
232 }
233 
234 Error lto::backend(Config &C, AddOutputFn AddOutput,
235                    unsigned ParallelCodeGenParallelismLevel,
236                    std::unique_ptr<Module> M) {
237   Expected<const Target *> TOrErr = initAndLookupTarget(C, *M);
238   if (!TOrErr)
239     return TOrErr.takeError();
240 
241   std::unique_ptr<TargetMachine> TM =
242       createTargetMachine(C, M->getTargetTriple(), *TOrErr);
243 
244   if (!C.CodeGenOnly)
245     if (!opt(C, TM.get(), 0, *M, /*IsThinLto=*/false))
246       return Error();
247 
248   if (ParallelCodeGenParallelismLevel == 1) {
249     codegen(C, TM.get(), getUncachedOutputWrapper(AddOutput, 0), 0, *M);
250   } else {
251     splitCodeGen(C, TM.get(), AddOutput, ParallelCodeGenParallelismLevel,
252                  std::move(M));
253   }
254   return Error();
255 }
256 
257 Error lto::thinBackend(Config &Conf, unsigned Task, AddOutputFn AddOutput,
258                        Module &Mod, ModuleSummaryIndex &CombinedIndex,
259                        const FunctionImporter::ImportMapTy &ImportList,
260                        const GVSummaryMapTy &DefinedGlobals,
261                        MapVector<StringRef, MemoryBufferRef> &ModuleMap) {
262   Expected<const Target *> TOrErr = initAndLookupTarget(Conf, Mod);
263   if (!TOrErr)
264     return TOrErr.takeError();
265 
266   std::unique_ptr<TargetMachine> TM =
267       createTargetMachine(Conf, Mod.getTargetTriple(), *TOrErr);
268 
269   if (Conf.CodeGenOnly) {
270     codegen(Conf, TM.get(), AddOutput, Task, Mod);
271     return Error();
272   }
273 
274   if (Conf.PreOptModuleHook && !Conf.PreOptModuleHook(Task, Mod))
275     return Error();
276 
277   renameModuleForThinLTO(Mod, CombinedIndex);
278 
279   thinLTOResolveWeakForLinkerModule(Mod, DefinedGlobals);
280 
281   if (Conf.PostPromoteModuleHook && !Conf.PostPromoteModuleHook(Task, Mod))
282     return Error();
283 
284   if (!DefinedGlobals.empty())
285     thinLTOInternalizeModule(Mod, DefinedGlobals);
286 
287   if (Conf.PostInternalizeModuleHook &&
288       !Conf.PostInternalizeModuleHook(Task, Mod))
289     return Error();
290 
291   auto ModuleLoader = [&](StringRef Identifier) {
292     assert(Mod.getContext().isODRUniquingDebugTypes() &&
293            "ODR Type uniquing shoudl be enabled on the context");
294     return std::move(getLazyBitcodeModule(MemoryBuffer::getMemBuffer(
295                                               ModuleMap[Identifier], false),
296                                           Mod.getContext(),
297                                           /*ShouldLazyLoadMetadata=*/true)
298                          .get());
299   };
300 
301   FunctionImporter Importer(CombinedIndex, ModuleLoader);
302   Importer.importFunctions(Mod, ImportList);
303 
304   if (Conf.PostImportModuleHook && !Conf.PostImportModuleHook(Task, Mod))
305     return Error();
306 
307   if (!opt(Conf, TM.get(), Task, Mod, /*IsThinLto=*/true))
308     return Error();
309 
310   codegen(Conf, TM.get(), AddOutput, Task, Mod);
311   return Error();
312 }
313