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, 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 void codegen(Config &C, TargetMachine *TM, AddOutputFn AddOutput, unsigned Task,
147              Module &M) {
148   if (C.PreCodeGenModuleHook && !C.PreCodeGenModuleHook(Task, M))
149     return;
150 
151   auto Output = AddOutput(Task);
152   std::unique_ptr<raw_pwrite_stream> OS = Output->getStream();
153   legacy::PassManager CodeGenPasses;
154   if (TM->addPassesToEmitFile(CodeGenPasses, *OS,
155                               TargetMachine::CGFT_ObjectFile))
156     report_fatal_error("Failed to setup codegen");
157   CodeGenPasses.run(M);
158 }
159 
160 void splitCodeGen(Config &C, TargetMachine *TM, AddOutputFn AddOutput,
161                   unsigned ParallelCodeGenParallelismLevel,
162                   std::unique_ptr<Module> M) {
163   ThreadPool CodegenThreadPool(ParallelCodeGenParallelismLevel);
164   unsigned ThreadCount = 0;
165   const Target *T = &TM->getTarget();
166 
167   SplitModule(
168       std::move(M), ParallelCodeGenParallelismLevel,
169       [&](std::unique_ptr<Module> MPart) {
170         // We want to clone the module in a new context to multi-thread the
171         // codegen. We do it by serializing partition modules to bitcode
172         // (while still on the main thread, in order to avoid data races) and
173         // spinning up new threads which deserialize the partitions into
174         // separate contexts.
175         // FIXME: Provide a more direct way to do this in LLVM.
176         SmallString<0> BC;
177         raw_svector_ostream BCOS(BC);
178         WriteBitcodeToFile(MPart.get(), BCOS);
179 
180         // Enqueue the task
181         CodegenThreadPool.async(
182             [&](const SmallString<0> &BC, unsigned ThreadId) {
183               LTOLLVMContext Ctx(C);
184               ErrorOr<std::unique_ptr<Module>> MOrErr = parseBitcodeFile(
185                   MemoryBufferRef(StringRef(BC.data(), BC.size()), "ld-temp.o"),
186                   Ctx);
187               if (!MOrErr)
188                 report_fatal_error("Failed to read bitcode");
189               std::unique_ptr<Module> MPartInCtx = std::move(MOrErr.get());
190 
191               std::unique_ptr<TargetMachine> TM =
192                   createTargetMachine(C, MPartInCtx->getTargetTriple(), T);
193               codegen(C, TM.get(), AddOutput, ThreadId, *MPartInCtx);
194             },
195             // Pass BC using std::move to ensure that it get moved rather than
196             // copied into the thread's context.
197             std::move(BC), ThreadCount++);
198       },
199       false);
200 }
201 
202 Expected<const Target *> initAndLookupTarget(Config &C, Module &M) {
203   if (!C.OverrideTriple.empty())
204     M.setTargetTriple(C.OverrideTriple);
205   else if (M.getTargetTriple().empty())
206     M.setTargetTriple(C.DefaultTriple);
207 
208   std::string Msg;
209   const Target *T = TargetRegistry::lookupTarget(M.getTargetTriple(), Msg);
210   if (!T)
211     return make_error<StringError>(Msg, inconvertibleErrorCode());
212   return T;
213 }
214 
215 }
216 
217 Error lto::backend(Config &C, AddOutputFn AddOutput,
218                    unsigned ParallelCodeGenParallelismLevel,
219                    std::unique_ptr<Module> M) {
220   Expected<const Target *> TOrErr = initAndLookupTarget(C, *M);
221   if (!TOrErr)
222     return TOrErr.takeError();
223 
224   std::unique_ptr<TargetMachine> TM =
225       createTargetMachine(C, M->getTargetTriple(), *TOrErr);
226 
227   if (!opt(C, TM.get(), 0, *M, /*IsThinLto=*/false))
228     return Error();
229 
230   if (ParallelCodeGenParallelismLevel == 1)
231     codegen(C, TM.get(), AddOutput, 0, *M);
232   else
233     splitCodeGen(C, TM.get(), AddOutput, ParallelCodeGenParallelismLevel,
234                  std::move(M));
235   return Error();
236 }
237 
238 Error lto::thinBackend(Config &Conf, unsigned Task, AddOutputFn AddOutput,
239                        Module &Mod, ModuleSummaryIndex &CombinedIndex,
240                        const FunctionImporter::ImportMapTy &ImportList,
241                        const GVSummaryMapTy &DefinedGlobals,
242                        MapVector<StringRef, MemoryBufferRef> &ModuleMap) {
243   Expected<const Target *> TOrErr = initAndLookupTarget(Conf, Mod);
244   if (!TOrErr)
245     return TOrErr.takeError();
246 
247   std::unique_ptr<TargetMachine> TM =
248       createTargetMachine(Conf, Mod.getTargetTriple(), *TOrErr);
249 
250   if (Conf.PreOptModuleHook && !Conf.PreOptModuleHook(Task, Mod))
251     return Error();
252 
253   renameModuleForThinLTO(Mod, CombinedIndex);
254 
255   thinLTOResolveWeakForLinkerModule(Mod, DefinedGlobals);
256 
257   if (Conf.PostPromoteModuleHook && !Conf.PostPromoteModuleHook(Task, Mod))
258     return Error();
259 
260   if (!DefinedGlobals.empty())
261     thinLTOInternalizeModule(Mod, DefinedGlobals);
262 
263   if (Conf.PostInternalizeModuleHook &&
264       !Conf.PostInternalizeModuleHook(Task, Mod))
265     return Error();
266 
267   auto ModuleLoader = [&](StringRef Identifier) {
268     return std::move(getLazyBitcodeModule(MemoryBuffer::getMemBuffer(
269                                               ModuleMap[Identifier], false),
270                                           Mod.getContext(),
271                                           /*ShouldLazyLoadMetadata=*/true)
272                          .get());
273   };
274 
275   FunctionImporter Importer(CombinedIndex, ModuleLoader);
276   Importer.importFunctions(Mod, ImportList);
277 
278   if (Conf.PostImportModuleHook && !Conf.PostImportModuleHook(Task, Mod))
279     return Error();
280 
281   if (!opt(Conf, TM.get(), Task, Mod, /*IsThinLto=*/true))
282     return Error();
283 
284   codegen(Conf, TM.get(), AddOutput, Task, Mod);
285   return Error();
286 }
287