xref: /llvm-project/llvm/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h (revision 76bdc608980b307a354580dfbbed844fee0b75a8)
1 //===-ThinLTOCodeGenerator.h - LLVM Link Time Optimizer -------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file declares the ThinLTOCodeGenerator class, similar to the
10 // LTOCodeGenerator but for the ThinLTO scheme. It provides an interface for
11 // linker plugin.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_LTO_LEGACY_THINLTOCODEGENERATOR_H
16 #define LLVM_LTO_LEGACY_THINLTOCODEGENERATOR_H
17 
18 #include "llvm-c/lto.h"
19 #include "llvm/ADT/StringSet.h"
20 #include "llvm/IR/ModuleSummaryIndex.h"
21 #include "llvm/LTO/LTO.h"
22 #include "llvm/Support/CachePruning.h"
23 #include "llvm/Support/CodeGen.h"
24 #include "llvm/Support/MemoryBuffer.h"
25 #include "llvm/Target/TargetOptions.h"
26 #include "llvm/TargetParser/Triple.h"
27 
28 #include <string>
29 
30 namespace llvm {
31 class StringRef;
32 class TargetMachine;
33 
34 /// ThinLTOCodeGeneratorImpl - Namespace used for ThinLTOCodeGenerator
35 /// implementation details. It should be considered private to the
36 /// implementation.
37 namespace ThinLTOCodeGeneratorImpl {
38 struct TargetMachineBuilder;
39 }
40 
41 /// Helper to gather options relevant to the target machine creation
42 struct ThinLTOCodeGeneratorImpl::TargetMachineBuilder {
43   Triple TheTriple;
44   std::string MCpu;
45   std::string MAttr;
46   TargetOptions Options;
47   std::optional<Reloc::Model> RelocModel;
48   CodeGenOptLevel CGOptLevel = CodeGenOptLevel::Aggressive;
49 
50   std::unique_ptr<TargetMachine> create() const;
51 };
52 
53 /// This class define an interface similar to the LTOCodeGenerator, but adapted
54 /// for ThinLTO processing.
55 /// The ThinLTOCodeGenerator is not intended to be reuse for multiple
56 /// compilation: the model is that the client adds modules to the generator and
57 /// ask to perform the ThinLTO optimizations / codegen, and finally destroys the
58 /// codegenerator.
59 class ThinLTOCodeGenerator {
60 public:
61   /// Add given module to the code generator.
62   void addModule(StringRef Identifier, StringRef Data);
63 
64   /**
65    * Adds to a list of all global symbols that must exist in the final generated
66    * code. If a symbol is not listed there, it will be optimized away if it is
67    * inlined into every usage.
68    */
69   void preserveSymbol(StringRef Name);
70 
71   /**
72    * Adds to a list of all global symbols that are cross-referenced between
73    * ThinLTO files. If the ThinLTO CodeGenerator can ensure that every
74    * references from a ThinLTO module to this symbol is optimized away, then
75    * the symbol can be discarded.
76    */
77   void crossReferenceSymbol(StringRef Name);
78 
79   /**
80    * Process all the modules that were added to the code generator in parallel.
81    *
82    * Client can access the resulting object files using getProducedBinaries(),
83    * unless setGeneratedObjectsDirectory() has been called, in which case
84    * results are available through getProducedBinaryFiles().
85    */
86   void run();
87 
88   /**
89    * Return the "in memory" binaries produced by the code generator. This is
90    * filled after run() unless setGeneratedObjectsDirectory() has been
91    * called, in which case results are available through
92    * getProducedBinaryFiles().
93    */
94   std::vector<std::unique_ptr<MemoryBuffer>> &getProducedBinaries() {
95     return ProducedBinaries;
96   }
97 
98   /**
99    * Return the "on-disk" binaries produced by the code generator. This is
100    * filled after run() when setGeneratedObjectsDirectory() has been
101    * called, in which case results are available through getProducedBinaries().
102    */
103   std::vector<std::string> &getProducedBinaryFiles() {
104     return ProducedBinaryFiles;
105   }
106 
107   /**
108    * \defgroup Options setters
109    * @{
110    */
111 
112   /**
113    * \defgroup Cache controlling options
114    *
115    * These entry points control the ThinLTO cache. The cache is intended to
116    * support incremental build, and thus needs to be persistent accross build.
117    * The client enabled the cache by supplying a path to an existing directory.
118    * The code generator will use this to store objects files that may be reused
119    * during a subsequent build.
120    * To avoid filling the disk space, a few knobs are provided:
121    *  - The pruning interval limit the frequency at which the garbage collector
122    *    will try to scan the cache directory to prune it from expired entries.
123    *    Setting to -1 disable the pruning (default). Setting to 0 will force
124    *    pruning to occur.
125    *  - The pruning expiration time indicates to the garbage collector how old
126    *    an entry needs to be to be removed.
127    *  - Finally, the garbage collector can be instructed to prune the cache till
128    *    the occupied space goes below a threshold.
129    * @{
130    */
131 
132   struct CachingOptions {
133     std::string Path;                    // Path to the cache, empty to disable.
134     CachePruningPolicy Policy;
135   };
136 
137   /// Provide a path to a directory where to store the cached files for
138   /// incremental build.
139   void setCacheDir(std::string Path) { CacheOptions.Path = std::move(Path); }
140 
141   /// Cache policy: interval (seconds) between two prunes of the cache. Set to a
142   /// negative value to disable pruning. A value of 0 will force pruning to
143   /// occur.
144   void setCachePruningInterval(int Interval) {
145     if(Interval < 0)
146       CacheOptions.Policy.Interval.reset();
147     else
148       CacheOptions.Policy.Interval = std::chrono::seconds(Interval);
149   }
150 
151   /// Cache policy: expiration (in seconds) for an entry.
152   /// A value of 0 will be ignored.
153   void setCacheEntryExpiration(unsigned Expiration) {
154     if (Expiration)
155       CacheOptions.Policy.Expiration = std::chrono::seconds(Expiration);
156   }
157 
158   /**
159    * Sets the maximum cache size that can be persistent across build, in terms
160    * of percentage of the available space on the disk. Set to 100 to indicate
161    * no limit, 50 to indicate that the cache size will not be left over
162    * half the available space. A value over 100 will be reduced to 100, and a
163    * value of 0 will be ignored.
164    *
165    *
166    * The formula looks like:
167    *  AvailableSpace = FreeSpace + ExistingCacheSize
168    *  NewCacheSize = AvailableSpace * P/100
169    *
170    */
171   void setMaxCacheSizeRelativeToAvailableSpace(unsigned Percentage) {
172     if (Percentage)
173       CacheOptions.Policy.MaxSizePercentageOfAvailableSpace = Percentage;
174   }
175 
176   /// Cache policy: the maximum size for the cache directory in bytes. A value
177   /// over the amount of available space on the disk will be reduced to the
178   /// amount of available space. A value of 0 will be ignored.
179   void setCacheMaxSizeBytes(uint64_t MaxSizeBytes) {
180     if (MaxSizeBytes)
181       CacheOptions.Policy.MaxSizeBytes = MaxSizeBytes;
182   }
183 
184   /// Cache policy: the maximum number of files in the cache directory. A value
185   /// of 0 will be ignored.
186   void setCacheMaxSizeFiles(unsigned MaxSizeFiles) {
187     if (MaxSizeFiles)
188       CacheOptions.Policy.MaxSizeFiles = MaxSizeFiles;
189   }
190 
191   /**@}*/
192 
193   /// Set the path to a directory where to save temporaries at various stages of
194   /// the processing.
195   void setSaveTempsDir(std::string Path) { SaveTempsDir = std::move(Path); }
196 
197   /// Set the path to a directory where to save generated object files. This
198   /// path can be used by a linker to request on-disk files instead of in-memory
199   /// buffers. When set, results are available through getProducedBinaryFiles()
200   /// instead of getProducedBinaries().
201   void setGeneratedObjectsDirectory(std::string Path) {
202     SavedObjectsDirectoryPath = std::move(Path);
203   }
204 
205   /// CPU to use to initialize the TargetMachine
206   void setCpu(std::string Cpu) { TMBuilder.MCpu = std::move(Cpu); }
207 
208   /// Subtarget attributes
209   void setAttr(std::string MAttr) { TMBuilder.MAttr = std::move(MAttr); }
210 
211   /// TargetMachine options
212   void setTargetOptions(TargetOptions Options) {
213     TMBuilder.Options = std::move(Options);
214   }
215 
216   /// Enable the Freestanding mode: indicate that the optimizer should not
217   /// assume builtins are present on the target.
218   void setFreestanding(bool Enabled) { Freestanding = Enabled; }
219 
220   /// CodeModel
221   void setCodePICModel(std::optional<Reloc::Model> Model) {
222     TMBuilder.RelocModel = Model;
223   }
224 
225   /// CodeGen optimization level
226   void setCodeGenOptLevel(CodeGenOptLevel CGOptLevel) {
227     TMBuilder.CGOptLevel = CGOptLevel;
228   }
229 
230   /// IR optimization level: from 0 to 3.
231   void setOptLevel(unsigned NewOptLevel) {
232     OptLevel = (NewOptLevel > 3) ? 3 : NewOptLevel;
233   }
234 
235   /// Enable or disable debug output for the new pass manager.
236   void setDebugPassManager(unsigned Enabled) { DebugPassManager = Enabled; }
237 
238   /// Disable CodeGen, only run the stages till codegen and stop. The output
239   /// will be bitcode.
240   void disableCodeGen(bool Disable) { DisableCodeGen = Disable; }
241 
242   /// Perform CodeGen only: disable all other stages.
243   void setCodeGenOnly(bool CGOnly) { CodeGenOnly = CGOnly; }
244 
245   /**@}*/
246 
247   /**
248    * \defgroup Set of APIs to run individual stages in isolation.
249    * @{
250    */
251 
252   /**
253    * Produce the combined summary index from all the bitcode files:
254    * "thin-link".
255    */
256   std::unique_ptr<ModuleSummaryIndex> linkCombinedIndex();
257 
258   /**
259    * Perform promotion and renaming of exported internal functions,
260    * and additionally resolve weak and linkonce symbols.
261    * Index is updated to reflect linkage changes from weak resolution.
262    */
263   void promote(Module &Module, ModuleSummaryIndex &Index,
264                const lto::InputFile &File);
265 
266   /**
267    * Compute and emit the imported files for module at \p ModulePath.
268    */
269   void emitImports(Module &Module, StringRef OutputName,
270                    ModuleSummaryIndex &Index,
271                    const lto::InputFile &File);
272 
273   /**
274    * Perform cross-module importing for the module identified by
275    * ModuleIdentifier.
276    */
277   void crossModuleImport(Module &Module, ModuleSummaryIndex &Index,
278                          const lto::InputFile &File);
279 
280   /**
281    * Compute the list of summaries and the subset of declaration summaries
282    * needed for importing into module.
283    */
284   void gatherImportedSummariesForModule(
285       Module &Module, ModuleSummaryIndex &Index,
286       ModuleToSummariesForIndexTy &ModuleToSummariesForIndex,
287       GVSummaryPtrSet &DecSummaries, const lto::InputFile &File);
288 
289   /**
290    * Perform internalization. Index is updated to reflect linkage changes.
291    */
292   void internalize(Module &Module, ModuleSummaryIndex &Index,
293                    const lto::InputFile &File);
294 
295   /**
296    * Perform post-importing ThinLTO optimizations.
297    */
298   void optimize(Module &Module);
299 
300   /**
301    * Write temporary object file to SavedObjectDirectoryPath, write symlink
302    * to Cache directory if needed. Returns the path to the generated file in
303    * SavedObjectsDirectoryPath.
304    */
305   std::string writeGeneratedObject(int count, StringRef CacheEntryPath,
306                                    const MemoryBuffer &OutputBuffer);
307   /**@}*/
308 
309 private:
310   /// Helper factory to build a TargetMachine
311   ThinLTOCodeGeneratorImpl::TargetMachineBuilder TMBuilder;
312 
313   /// Vector holding the in-memory buffer containing the produced binaries, when
314   /// SavedObjectsDirectoryPath isn't set.
315   std::vector<std::unique_ptr<MemoryBuffer>> ProducedBinaries;
316 
317   /// Path to generated files in the supplied SavedObjectsDirectoryPath if any.
318   std::vector<std::string> ProducedBinaryFiles;
319 
320   /// Vector holding the input buffers containing the bitcode modules to
321   /// process.
322   std::vector<std::unique_ptr<lto::InputFile>> Modules;
323 
324   /// Set of symbols that need to be preserved outside of the set of bitcode
325   /// files.
326   StringSet<> PreservedSymbols;
327 
328   /// Set of symbols that are cross-referenced between bitcode files.
329   StringSet<> CrossReferencedSymbols;
330 
331   /// Control the caching behavior.
332   CachingOptions CacheOptions;
333 
334   /// Path to a directory to save the temporary bitcode files.
335   std::string SaveTempsDir;
336 
337   /// Path to a directory to save the generated object files.
338   std::string SavedObjectsDirectoryPath;
339 
340   /// Flag to enable/disable CodeGen. When set to true, the process stops after
341   /// optimizations and a bitcode is produced.
342   bool DisableCodeGen = false;
343 
344   /// Flag to indicate that only the CodeGen will be performed, no cross-module
345   /// importing or optimization.
346   bool CodeGenOnly = false;
347 
348   /// Flag to indicate that the optimizer should not assume builtins are present
349   /// on the target.
350   bool Freestanding = false;
351 
352   /// IR Optimization Level [0-3].
353   unsigned OptLevel = 3;
354 
355   /// Flag to indicate whether debug output should be enabled for the new pass
356   /// manager.
357   bool DebugPassManager = false;
358 };
359 }
360 #endif
361