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