1 //===-- llvm-lto2: test harness for the resolution-based LTO interface ----===// 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 program takes in a list of bitcode files, links them and performs 11 // link-time optimization according to the provided symbol resolutions using the 12 // resolution-based LTO interface, and outputs one or more object files. 13 // 14 // This program is intended to eventually replace llvm-lto which uses the legacy 15 // LTO interface. 16 // 17 //===----------------------------------------------------------------------===// 18 19 #include "llvm/Bitcode/BitcodeReader.h" 20 #include "llvm/CodeGen/CommandFlags.inc" 21 #include "llvm/IR/DiagnosticPrinter.h" 22 #include "llvm/LTO/Caching.h" 23 #include "llvm/LTO/LTO.h" 24 #include "llvm/Support/CommandLine.h" 25 #include "llvm/Support/FileSystem.h" 26 #include "llvm/Support/TargetSelect.h" 27 #include "llvm/Support/Threading.h" 28 29 using namespace llvm; 30 using namespace lto; 31 32 static cl::opt<char> 33 OptLevel("O", cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] " 34 "(default = '-O2')"), 35 cl::Prefix, cl::ZeroOrMore, cl::init('2')); 36 37 static cl::opt<char> CGOptLevel( 38 "cg-opt-level", 39 cl::desc("Codegen optimization level (0, 1, 2 or 3, default = '2')"), 40 cl::init('2')); 41 42 static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore, 43 cl::desc("<input bitcode files>")); 44 45 static cl::opt<std::string> OutputFilename("o", cl::Required, 46 cl::desc("Output filename"), 47 cl::value_desc("filename")); 48 49 static cl::opt<std::string> CacheDir("cache-dir", cl::desc("Cache Directory"), 50 cl::value_desc("directory")); 51 52 static cl::opt<std::string> OptPipeline("opt-pipeline", 53 cl::desc("Optimizer Pipeline"), 54 cl::value_desc("pipeline")); 55 56 static cl::opt<std::string> AAPipeline("aa-pipeline", 57 cl::desc("Alias Analysis Pipeline"), 58 cl::value_desc("aapipeline")); 59 60 static cl::opt<bool> SaveTemps("save-temps", cl::desc("Save temporary files")); 61 62 static cl::opt<bool> 63 ThinLTODistributedIndexes("thinlto-distributed-indexes", cl::init(false), 64 cl::desc("Write out individual index and " 65 "import files for the " 66 "distributed backend case")); 67 68 static cl::opt<int> Threads("thinlto-threads", 69 cl::init(llvm::heavyweight_hardware_concurrency())); 70 71 static cl::list<std::string> SymbolResolutions( 72 "r", 73 cl::desc("Specify a symbol resolution: filename,symbolname,resolution\n" 74 "where \"resolution\" is a sequence (which may be empty) of the\n" 75 "following characters:\n" 76 " p - prevailing: the linker has chosen this definition of the\n" 77 " symbol\n" 78 " l - local: the definition of this symbol is unpreemptable at\n" 79 " runtime and is known to be in this linkage unit\n" 80 " x - externally visible: the definition of this symbol is\n" 81 " visible outside of the LTO unit\n" 82 "A resolution for each symbol must be specified."), 83 cl::ZeroOrMore); 84 85 static cl::opt<std::string> OverrideTriple( 86 "override-triple", 87 cl::desc("Replace target triples in input files with this triple")); 88 89 static cl::opt<std::string> DefaultTriple( 90 "default-triple", 91 cl::desc( 92 "Replace unspecified target triples in input files with this triple")); 93 94 static cl::opt<std::string> 95 OptRemarksOutput("pass-remarks-output", 96 cl::desc("YAML output file for optimization remarks")); 97 98 static cl::opt<bool> OptRemarksWithHotness( 99 "pass-remarks-with-hotness", 100 cl::desc("Whether to include hotness informations in the remarks.\n" 101 "Has effect only if -pass-remarks-output is specified.")); 102 103 static cl::opt<std::string> 104 SamplePGOFile("lto-sample-profile-file", 105 cl::desc("Specify a SamplePGO profile file")); 106 107 static cl::opt<bool> 108 UseNewPM("use-new-pm", 109 cl::desc("Run LTO passes using the new pass manager"), 110 cl::init(false), cl::Hidden); 111 112 static cl::opt<bool> 113 DebugPassManager("debug-pass-manager", cl::init(false), cl::Hidden, 114 cl::desc("Print pass management debugging information")); 115 116 static cl::opt<std::string> 117 StatsFile("stats-file", cl::desc("Filename to write statistics to")); 118 119 static void check(Error E, std::string Msg) { 120 if (!E) 121 return; 122 handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) { 123 errs() << "llvm-lto2: " << Msg << ": " << EIB.message().c_str() << '\n'; 124 }); 125 exit(1); 126 } 127 128 template <typename T> static T check(Expected<T> E, std::string Msg) { 129 if (E) 130 return std::move(*E); 131 check(E.takeError(), Msg); 132 return T(); 133 } 134 135 static void check(std::error_code EC, std::string Msg) { 136 check(errorCodeToError(EC), Msg); 137 } 138 139 template <typename T> static T check(ErrorOr<T> E, std::string Msg) { 140 if (E) 141 return std::move(*E); 142 check(E.getError(), Msg); 143 return T(); 144 } 145 146 static int usage() { 147 errs() << "Available subcommands: dump-symtab run\n"; 148 return 1; 149 } 150 151 static int run(int argc, char **argv) { 152 cl::ParseCommandLineOptions(argc, argv, "Resolution-based LTO test harness"); 153 154 // FIXME: Workaround PR30396 which means that a symbol can appear 155 // more than once if it is defined in module-level assembly and 156 // has a GV declaration. We allow (file, symbol) pairs to have multiple 157 // resolutions and apply them in the order observed. 158 std::map<std::pair<std::string, std::string>, std::list<SymbolResolution>> 159 CommandLineResolutions; 160 for (std::string R : SymbolResolutions) { 161 StringRef Rest = R; 162 StringRef FileName, SymbolName; 163 std::tie(FileName, Rest) = Rest.split(','); 164 if (Rest.empty()) { 165 llvm::errs() << "invalid resolution: " << R << '\n'; 166 return 1; 167 } 168 std::tie(SymbolName, Rest) = Rest.split(','); 169 SymbolResolution Res; 170 for (char C : Rest) { 171 if (C == 'p') 172 Res.Prevailing = true; 173 else if (C == 'l') 174 Res.FinalDefinitionInLinkageUnit = true; 175 else if (C == 'x') 176 Res.VisibleToRegularObj = true; 177 else if (C == 'r') 178 Res.LinkerRedefined = true; 179 else { 180 llvm::errs() << "invalid character " << C << " in resolution: " << R 181 << '\n'; 182 return 1; 183 } 184 } 185 CommandLineResolutions[{FileName, SymbolName}].push_back(Res); 186 } 187 188 std::vector<std::unique_ptr<MemoryBuffer>> MBs; 189 190 Config Conf; 191 Conf.DiagHandler = [](const DiagnosticInfo &DI) { 192 DiagnosticPrinterRawOStream DP(errs()); 193 DI.print(DP); 194 errs() << '\n'; 195 if (DI.getSeverity() == DS_Error) 196 exit(1); 197 }; 198 199 Conf.CPU = MCPU; 200 Conf.Options = InitTargetOptionsFromCodeGenFlags(); 201 Conf.MAttrs = MAttrs; 202 if (auto RM = getRelocModel()) 203 Conf.RelocModel = *RM; 204 Conf.CodeModel = getCodeModel(); 205 206 Conf.DebugPassManager = DebugPassManager; 207 208 if (SaveTemps) 209 check(Conf.addSaveTemps(OutputFilename + "."), 210 "Config::addSaveTemps failed"); 211 212 // Optimization remarks. 213 Conf.RemarksFilename = OptRemarksOutput; 214 Conf.RemarksWithHotness = OptRemarksWithHotness; 215 216 Conf.SampleProfile = SamplePGOFile; 217 218 // Run a custom pipeline, if asked for. 219 Conf.OptPipeline = OptPipeline; 220 Conf.AAPipeline = AAPipeline; 221 222 Conf.OptLevel = OptLevel - '0'; 223 Conf.UseNewPM = UseNewPM; 224 switch (CGOptLevel) { 225 case '0': 226 Conf.CGOptLevel = CodeGenOpt::None; 227 break; 228 case '1': 229 Conf.CGOptLevel = CodeGenOpt::Less; 230 break; 231 case '2': 232 Conf.CGOptLevel = CodeGenOpt::Default; 233 break; 234 case '3': 235 Conf.CGOptLevel = CodeGenOpt::Aggressive; 236 break; 237 default: 238 llvm::errs() << "invalid cg optimization level: " << CGOptLevel << '\n'; 239 return 1; 240 } 241 242 if (FileType.getNumOccurrences()) 243 Conf.CGFileType = FileType; 244 245 Conf.OverrideTriple = OverrideTriple; 246 Conf.DefaultTriple = DefaultTriple; 247 Conf.StatsFile = StatsFile; 248 249 ThinBackend Backend; 250 if (ThinLTODistributedIndexes) 251 Backend = createWriteIndexesThinBackend(/* OldPrefix */ "", 252 /* NewPrefix */ "", 253 /* ShouldEmitImportsFiles */ true, 254 /* LinkedObjectsFile */ nullptr, 255 /* OnWrite */ {}); 256 else 257 Backend = createInProcessThinBackend(Threads); 258 LTO Lto(std::move(Conf), std::move(Backend)); 259 260 bool HasErrors = false; 261 for (std::string F : InputFilenames) { 262 std::unique_ptr<MemoryBuffer> MB = check(MemoryBuffer::getFile(F), F); 263 std::unique_ptr<InputFile> Input = 264 check(InputFile::create(MB->getMemBufferRef()), F); 265 266 std::vector<SymbolResolution> Res; 267 for (const InputFile::Symbol &Sym : Input->symbols()) { 268 auto I = CommandLineResolutions.find({F, Sym.getName()}); 269 if (I == CommandLineResolutions.end()) { 270 llvm::errs() << argv[0] << ": missing symbol resolution for " << F 271 << ',' << Sym.getName() << '\n'; 272 HasErrors = true; 273 } else { 274 Res.push_back(I->second.front()); 275 I->second.pop_front(); 276 if (I->second.empty()) 277 CommandLineResolutions.erase(I); 278 } 279 } 280 281 if (HasErrors) 282 continue; 283 284 MBs.push_back(std::move(MB)); 285 check(Lto.add(std::move(Input), Res), F); 286 } 287 288 if (!CommandLineResolutions.empty()) { 289 HasErrors = true; 290 for (auto UnusedRes : CommandLineResolutions) 291 llvm::errs() << argv[0] << ": unused symbol resolution for " 292 << UnusedRes.first.first << ',' << UnusedRes.first.second 293 << '\n'; 294 } 295 if (HasErrors) 296 return 1; 297 298 auto AddStream = 299 [&](size_t Task) -> std::unique_ptr<lto::NativeObjectStream> { 300 std::string Path = OutputFilename + "." + utostr(Task); 301 302 std::error_code EC; 303 auto S = llvm::make_unique<raw_fd_ostream>(Path, EC, sys::fs::F_None); 304 check(EC, Path); 305 return llvm::make_unique<lto::NativeObjectStream>(std::move(S)); 306 }; 307 308 auto AddBuffer = [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) { 309 *AddStream(Task)->OS << MB->getBuffer(); 310 }; 311 312 NativeObjectCache Cache; 313 if (!CacheDir.empty()) 314 Cache = check(localCache(CacheDir, AddBuffer), "failed to create cache"); 315 316 check(Lto.run(AddStream, Cache), "LTO::run failed"); 317 return 0; 318 } 319 320 static int dumpSymtab(int argc, char **argv) { 321 for (StringRef F : make_range(argv + 1, argv + argc)) { 322 std::unique_ptr<MemoryBuffer> MB = check(MemoryBuffer::getFile(F), F); 323 BitcodeFileContents BFC = check(getBitcodeFileContents(*MB), F); 324 325 if (BFC.Symtab.size() >= sizeof(irsymtab::storage::Header)) { 326 auto *Hdr = reinterpret_cast<const irsymtab::storage::Header *>( 327 BFC.Symtab.data()); 328 outs() << "version: " << Hdr->Version << '\n'; 329 if (Hdr->Version == irsymtab::storage::Header::kCurrentVersion) 330 outs() << "producer: " << Hdr->Producer.get(BFC.StrtabForSymtab) 331 << '\n'; 332 } 333 334 std::unique_ptr<InputFile> Input = 335 check(InputFile::create(MB->getMemBufferRef()), F); 336 337 outs() << "target triple: " << Input->getTargetTriple() << '\n'; 338 Triple TT(Input->getTargetTriple()); 339 340 outs() << "source filename: " << Input->getSourceFileName() << '\n'; 341 342 if (TT.isOSBinFormatCOFF()) 343 outs() << "linker opts: " << Input->getCOFFLinkerOpts() << '\n'; 344 345 std::vector<StringRef> ComdatTable = Input->getComdatTable(); 346 for (const InputFile::Symbol &Sym : Input->symbols()) { 347 switch (Sym.getVisibility()) { 348 case GlobalValue::HiddenVisibility: 349 outs() << 'H'; 350 break; 351 case GlobalValue::ProtectedVisibility: 352 outs() << 'P'; 353 break; 354 case GlobalValue::DefaultVisibility: 355 outs() << 'D'; 356 break; 357 } 358 359 auto PrintBool = [&](char C, bool B) { outs() << (B ? C : '-'); }; 360 PrintBool('U', Sym.isUndefined()); 361 PrintBool('C', Sym.isCommon()); 362 PrintBool('W', Sym.isWeak()); 363 PrintBool('I', Sym.isIndirect()); 364 PrintBool('O', Sym.canBeOmittedFromSymbolTable()); 365 PrintBool('T', Sym.isTLS()); 366 PrintBool('X', Sym.isExecutable()); 367 outs() << ' ' << Sym.getName() << '\n'; 368 369 if (Sym.isCommon()) 370 outs() << " size " << Sym.getCommonSize() << " align " 371 << Sym.getCommonAlignment() << '\n'; 372 373 int Comdat = Sym.getComdatIndex(); 374 if (Comdat != -1) 375 outs() << " comdat " << ComdatTable[Comdat] << '\n'; 376 377 if (TT.isOSBinFormatCOFF() && Sym.isWeak() && Sym.isIndirect()) 378 outs() << " fallback " << Sym.getCOFFWeakExternalFallback() << '\n'; 379 380 if (!Sym.getSectionName().empty()) 381 outs() << " section " << Sym.getSectionName() << "\n"; 382 } 383 384 outs() << '\n'; 385 } 386 387 return 0; 388 } 389 390 int main(int argc, char **argv) { 391 InitializeAllTargets(); 392 InitializeAllTargetMCs(); 393 InitializeAllAsmPrinters(); 394 InitializeAllAsmParsers(); 395 396 // FIXME: This should use llvm::cl subcommands, but it isn't currently 397 // possible to pass an argument not associated with a subcommand to a 398 // subcommand (e.g. -use-new-pm). 399 if (argc < 2) 400 return usage(); 401 402 StringRef Subcommand = argv[1]; 403 // Ensure that argv[0] is correct after adjusting argv/argc. 404 argv[1] = argv[0]; 405 if (Subcommand == "dump-symtab") 406 return dumpSymtab(argc - 1, argv + 1); 407 if (Subcommand == "run") 408 return run(argc - 1, argv + 1); 409 return usage(); 410 } 411