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