123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134 |
- //===- llvm-lto: a simple command-line program to link modules with LTO ---===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This program takes in a list of bitcode files, links them, performs link-time
- // optimization, and outputs an object file.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm-c/lto.h"
- #include "llvm/ADT/ArrayRef.h"
- #include "llvm/ADT/STLExtras.h"
- #include "llvm/ADT/SmallString.h"
- #include "llvm/ADT/StringExtras.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/ADT/StringSet.h"
- #include "llvm/ADT/Twine.h"
- #include "llvm/Bitcode/BitcodeReader.h"
- #include "llvm/Bitcode/BitcodeWriter.h"
- #include "llvm/CodeGen/CommandFlags.h"
- #include "llvm/IR/DiagnosticInfo.h"
- #include "llvm/IR/DiagnosticPrinter.h"
- #include "llvm/IR/LLVMContext.h"
- #include "llvm/IR/Module.h"
- #include "llvm/IR/ModuleSummaryIndex.h"
- #include "llvm/IR/Verifier.h"
- #include "llvm/IRReader/IRReader.h"
- #include "llvm/LTO/legacy/LTOCodeGenerator.h"
- #include "llvm/LTO/legacy/LTOModule.h"
- #include "llvm/LTO/legacy/ThinLTOCodeGenerator.h"
- #include "llvm/Support/Allocator.h"
- #include "llvm/Support/Casting.h"
- #include "llvm/Support/CommandLine.h"
- #include "llvm/Support/Error.h"
- #include "llvm/Support/ErrorHandling.h"
- #include "llvm/Support/ErrorOr.h"
- #include "llvm/Support/FileSystem.h"
- #include "llvm/Support/InitLLVM.h"
- #include "llvm/Support/MemoryBuffer.h"
- #include "llvm/Support/Path.h"
- #include "llvm/Support/SourceMgr.h"
- #include "llvm/Support/TargetSelect.h"
- #include "llvm/Support/ToolOutputFile.h"
- #include "llvm/Support/raw_ostream.h"
- #include "llvm/Support/WithColor.h"
- #include "llvm/Target/TargetOptions.h"
- #include <algorithm>
- #include <cassert>
- #include <cstdint>
- #include <cstdlib>
- #include <list>
- #include <map>
- #include <memory>
- #include <string>
- #include <system_error>
- #include <tuple>
- #include <utility>
- #include <vector>
- using namespace llvm;
- static codegen::RegisterCodeGenFlags CGF;
- static cl::OptionCategory LTOCategory("LTO Options");
- static cl::opt<char>
- OptLevel("O",
- cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
- "(default = '-O2')"),
- cl::Prefix, cl::ZeroOrMore, cl::init('2'), cl::cat(LTOCategory));
- static cl::opt<bool>
- IndexStats("thinlto-index-stats",
- cl::desc("Print statistic for the index in every input files"),
- cl::init(false), cl::cat(LTOCategory));
- static cl::opt<bool> DisableVerify(
- "disable-verify", cl::init(false),
- cl::desc("Do not run the verifier during the optimization pipeline"),
- cl::cat(LTOCategory));
- static cl::opt<bool> EnableFreestanding(
- "lto-freestanding", cl::init(false),
- cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"),
- cl::cat(LTOCategory));
- static cl::opt<bool> UseDiagnosticHandler(
- "use-diagnostic-handler", cl::init(false),
- cl::desc("Use a diagnostic handler to test the handler interface"),
- cl::cat(LTOCategory));
- static cl::opt<bool>
- ThinLTO("thinlto", cl::init(false),
- cl::desc("Only write combined global index for ThinLTO backends"),
- cl::cat(LTOCategory));
- enum ThinLTOModes {
- THINLINK,
- THINDISTRIBUTE,
- THINEMITIMPORTS,
- THINPROMOTE,
- THINIMPORT,
- THININTERNALIZE,
- THINOPT,
- THINCODEGEN,
- THINALL
- };
- cl::opt<ThinLTOModes> ThinLTOMode(
- "thinlto-action", cl::desc("Perform a single ThinLTO stage:"),
- cl::values(
- clEnumValN(
- THINLINK, "thinlink",
- "ThinLink: produces the index by linking only the summaries."),
- clEnumValN(THINDISTRIBUTE, "distributedindexes",
- "Produces individual indexes for distributed backends."),
- clEnumValN(THINEMITIMPORTS, "emitimports",
- "Emit imports files for distributed backends."),
- clEnumValN(THINPROMOTE, "promote",
- "Perform pre-import promotion (requires -thinlto-index)."),
- clEnumValN(THINIMPORT, "import",
- "Perform both promotion and "
- "cross-module importing (requires "
- "-thinlto-index)."),
- clEnumValN(THININTERNALIZE, "internalize",
- "Perform internalization driven by -exported-symbol "
- "(requires -thinlto-index)."),
- clEnumValN(THINOPT, "optimize", "Perform ThinLTO optimizations."),
- clEnumValN(THINCODEGEN, "codegen", "CodeGen (expected to match llc)"),
- clEnumValN(THINALL, "run", "Perform ThinLTO end-to-end")),
- cl::cat(LTOCategory));
- static cl::opt<std::string>
- ThinLTOIndex("thinlto-index",
- cl::desc("Provide the index produced by a ThinLink, required "
- "to perform the promotion and/or importing."),
- cl::cat(LTOCategory));
- static cl::opt<std::string> ThinLTOPrefixReplace(
- "thinlto-prefix-replace",
- cl::desc("Control where files for distributed backends are "
- "created. Expects 'oldprefix;newprefix' and if path "
- "prefix of output file is oldprefix it will be "
- "replaced with newprefix."),
- cl::cat(LTOCategory));
- static cl::opt<std::string> ThinLTOModuleId(
- "thinlto-module-id",
- cl::desc("For the module ID for the file to process, useful to "
- "match what is in the index."),
- cl::cat(LTOCategory));
- static cl::opt<std::string> ThinLTOCacheDir("thinlto-cache-dir",
- cl::desc("Enable ThinLTO caching."),
- cl::cat(LTOCategory));
- static cl::opt<int> ThinLTOCachePruningInterval(
- "thinlto-cache-pruning-interval", cl::init(1200),
- cl::desc("Set ThinLTO cache pruning interval."), cl::cat(LTOCategory));
- static cl::opt<uint64_t> ThinLTOCacheMaxSizeBytes(
- "thinlto-cache-max-size-bytes",
- cl::desc("Set ThinLTO cache pruning directory maximum size in bytes."),
- cl::cat(LTOCategory));
- static cl::opt<int> ThinLTOCacheMaxSizeFiles(
- "thinlto-cache-max-size-files", cl::init(1000000),
- cl::desc("Set ThinLTO cache pruning directory maximum number of files."),
- cl::cat(LTOCategory));
- static cl::opt<unsigned> ThinLTOCacheEntryExpiration(
- "thinlto-cache-entry-expiration", cl::init(604800) /* 1w */,
- cl::desc("Set ThinLTO cache entry expiration time."), cl::cat(LTOCategory));
- static cl::opt<std::string> ThinLTOSaveTempsPrefix(
- "thinlto-save-temps",
- cl::desc("Save ThinLTO temp files using filenames created by adding "
- "suffixes to the given file path prefix."),
- cl::cat(LTOCategory));
- static cl::opt<std::string> ThinLTOGeneratedObjectsDir(
- "thinlto-save-objects",
- cl::desc("Save ThinLTO generated object files using filenames created in "
- "the given directory."),
- cl::cat(LTOCategory));
- static cl::opt<bool> SaveLinkedModuleFile(
- "save-linked-module", cl::init(false),
- cl::desc("Write linked LTO module to file before optimize"),
- cl::cat(LTOCategory));
- static cl::opt<bool>
- SaveModuleFile("save-merged-module", cl::init(false),
- cl::desc("Write merged LTO module to file before CodeGen"),
- cl::cat(LTOCategory));
- static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
- cl::desc("<input bitcode files>"),
- cl::cat(LTOCategory));
- static cl::opt<std::string> OutputFilename("o", cl::init(""),
- cl::desc("Override output filename"),
- cl::value_desc("filename"),
- cl::cat(LTOCategory));
- static cl::list<std::string> ExportedSymbols(
- "exported-symbol",
- cl::desc("List of symbols to export from the resulting object file"),
- cl::ZeroOrMore, cl::cat(LTOCategory));
- static cl::list<std::string>
- DSOSymbols("dso-symbol",
- cl::desc("Symbol to put in the symtab in the resulting dso"),
- cl::ZeroOrMore, cl::cat(LTOCategory));
- static cl::opt<bool> ListSymbolsOnly(
- "list-symbols-only", cl::init(false),
- cl::desc("Instead of running LTO, list the symbols in each IR file"),
- cl::cat(LTOCategory));
- static cl::opt<bool> ListDependentLibrariesOnly(
- "list-dependent-libraries-only", cl::init(false),
- cl::desc(
- "Instead of running LTO, list the dependent libraries in each IR file"),
- cl::cat(LTOCategory));
- static cl::opt<bool> QueryHasCtorDtor(
- "query-hasCtorDtor", cl::init(false),
- cl::desc("Queries LTOModule::hasCtorDtor() on each IR file"));
- static cl::opt<bool>
- SetMergedModule("set-merged-module", cl::init(false),
- cl::desc("Use the first input module as the merged module"),
- cl::cat(LTOCategory));
- static cl::opt<unsigned> Parallelism("j", cl::Prefix, cl::init(1),
- cl::desc("Number of backend threads"),
- cl::cat(LTOCategory));
- static cl::opt<bool> RestoreGlobalsLinkage(
- "restore-linkage", cl::init(false),
- cl::desc("Restore original linkage of globals prior to CodeGen"),
- cl::cat(LTOCategory));
- static cl::opt<bool> CheckHasObjC(
- "check-for-objc", cl::init(false),
- cl::desc("Only check if the module has objective-C defined in it"),
- cl::cat(LTOCategory));
- static cl::opt<bool> PrintMachOCPUOnly(
- "print-macho-cpu-only", cl::init(false),
- cl::desc("Instead of running LTO, print the mach-o cpu in each IR file"),
- cl::cat(LTOCategory));
- static cl::opt<bool> UseNewPM(
- "use-new-pm", cl::desc("Run LTO passes using the new pass manager"),
- cl::init(LLVM_ENABLE_NEW_PASS_MANAGER), cl::Hidden, cl::cat(LTOCategory));
- static cl::opt<bool>
- DebugPassManager("debug-pass-manager", cl::init(false), cl::Hidden,
- cl::desc("Print pass management debugging information"),
- cl::cat(LTOCategory));
- namespace {
- struct ModuleInfo {
- BitVector CanBeHidden;
- };
- } // end anonymous namespace
- static void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,
- const char *Msg, void *) {
- errs() << "llvm-lto: ";
- switch (Severity) {
- case LTO_DS_NOTE:
- errs() << "note: ";
- break;
- case LTO_DS_REMARK:
- errs() << "remark: ";
- break;
- case LTO_DS_ERROR:
- errs() << "error: ";
- break;
- case LTO_DS_WARNING:
- errs() << "warning: ";
- break;
- }
- errs() << Msg << "\n";
- }
- static std::string CurrentActivity;
- namespace {
- struct LLVMLTODiagnosticHandler : public DiagnosticHandler {
- bool handleDiagnostics(const DiagnosticInfo &DI) override {
- raw_ostream &OS = errs();
- OS << "llvm-lto: ";
- switch (DI.getSeverity()) {
- case DS_Error:
- OS << "error";
- break;
- case DS_Warning:
- OS << "warning";
- break;
- case DS_Remark:
- OS << "remark";
- break;
- case DS_Note:
- OS << "note";
- break;
- }
- if (!CurrentActivity.empty())
- OS << ' ' << CurrentActivity;
- OS << ": ";
-
- DiagnosticPrinterRawOStream DP(OS);
- DI.print(DP);
- OS << '\n';
-
- if (DI.getSeverity() == DS_Error)
- exit(1);
- return true;
- }
- };
- }
- static void error(const Twine &Msg) {
- errs() << "llvm-lto: " << Msg << '\n';
- exit(1);
- }
- static void error(std::error_code EC, const Twine &Prefix) {
- if (EC)
- error(Prefix + ": " + EC.message());
- }
- template <typename T>
- static void error(const ErrorOr<T> &V, const Twine &Prefix) {
- error(V.getError(), Prefix);
- }
- static void maybeVerifyModule(const Module &Mod) {
- if (!DisableVerify && verifyModule(Mod, &errs()))
- error("Broken Module");
- }
- static std::unique_ptr<LTOModule>
- getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer,
- const TargetOptions &Options) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
- MemoryBuffer::getFile(Path);
- error(BufferOrErr, "error loading file '" + Path + "'");
- Buffer = std::move(BufferOrErr.get());
- CurrentActivity = ("loading file '" + Path + "'").str();
- std::unique_ptr<LLVMContext> Context = std::make_unique<LLVMContext>();
- Context->setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),
- true);
- ErrorOr<std::unique_ptr<LTOModule>> Ret = LTOModule::createInLocalContext(
- std::move(Context), Buffer->getBufferStart(), Buffer->getBufferSize(),
- Options, Path);
- CurrentActivity = "";
- maybeVerifyModule((*Ret)->getModule());
- return std::move(*Ret);
- }
- /// Print some statistics on the index for each input files.
- static void printIndexStats() {
- for (auto &Filename : InputFilenames) {
- ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");
- std::unique_ptr<ModuleSummaryIndex> Index =
- ExitOnErr(getModuleSummaryIndexForFile(Filename));
- // Skip files without a module summary.
- if (!Index)
- report_fatal_error(Twine(Filename) + " does not contain an index");
- unsigned Calls = 0, Refs = 0, Functions = 0, Alias = 0, Globals = 0;
- for (auto &Summaries : *Index) {
- for (auto &Summary : Summaries.second.SummaryList) {
- Refs += Summary->refs().size();
- if (auto *FuncSummary = dyn_cast<FunctionSummary>(Summary.get())) {
- Functions++;
- Calls += FuncSummary->calls().size();
- } else if (isa<AliasSummary>(Summary.get()))
- Alias++;
- else
- Globals++;
- }
- }
- outs() << "Index " << Filename << " contains "
- << (Alias + Globals + Functions) << " nodes (" << Functions
- << " functions, " << Alias << " alias, " << Globals
- << " globals) and " << (Calls + Refs) << " edges (" << Refs
- << " refs and " << Calls << " calls)\n";
- }
- }
- /// Load each IR file and dump certain information based on active flags.
- ///
- /// The main point here is to provide lit-testable coverage for the LTOModule
- /// functionality that's exposed by the C API. Moreover, this provides testing
- /// coverage for modules that have been created in their own contexts.
- static void testLTOModule(const TargetOptions &Options) {
- for (auto &Filename : InputFilenames) {
- std::unique_ptr<MemoryBuffer> Buffer;
- std::unique_ptr<LTOModule> Module =
- getLocalLTOModule(Filename, Buffer, Options);
- if (ListSymbolsOnly) {
- // List the symbols.
- outs() << Filename << ":\n";
- for (int I = 0, E = Module->getSymbolCount(); I != E; ++I)
- outs() << Module->getSymbolName(I) << "\n";
- }
- if (QueryHasCtorDtor)
- outs() << Filename
- << ": hasCtorDtor = " << (Module->hasCtorDtor() ? "true" : "false")
- << "\n";
- }
- }
- static std::unique_ptr<MemoryBuffer> loadFile(StringRef Filename) {
- ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename.str() +
- "': ");
- return ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Filename)));
- }
- static void listDependentLibraries() {
- for (auto &Filename : InputFilenames) {
- auto Buffer = loadFile(Filename);
- std::string E;
- std::unique_ptr<lto::InputFile> Input(LTOModule::createInputFile(
- Buffer->getBufferStart(), Buffer->getBufferSize(), Filename.c_str(),
- E));
- if (!Input)
- error(E);
- // List the dependent libraries.
- outs() << Filename << ":\n";
- for (size_t I = 0, C = LTOModule::getDependentLibraryCount(Input.get());
- I != C; ++I) {
- size_t L = 0;
- const char *S = LTOModule::getDependentLibrary(Input.get(), I, &L);
- assert(S);
- outs() << StringRef(S, L) << "\n";
- }
- }
- }
- static void printMachOCPUOnly() {
- LLVMContext Context;
- Context.setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),
- true);
- TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());
- for (auto &Filename : InputFilenames) {
- ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =
- LTOModule::createFromFile(Context, Filename, Options);
- if (!ModuleOrErr)
- error(ModuleOrErr, "llvm-lto: ");
- Expected<uint32_t> CPUType = (*ModuleOrErr)->getMachOCPUType();
- Expected<uint32_t> CPUSubType = (*ModuleOrErr)->getMachOCPUSubType();
- if (!CPUType)
- error("Error while printing mach-o cputype: " +
- toString(CPUType.takeError()));
- if (!CPUSubType)
- error("Error while printing mach-o cpusubtype: " +
- toString(CPUSubType.takeError()));
- outs() << llvm::format("%s:\ncputype: %u\ncpusubtype: %u\n",
- Filename.c_str(), *CPUType, *CPUSubType);
- }
- }
- /// Create a combined index file from the input IR files and write it.
- ///
- /// This is meant to enable testing of ThinLTO combined index generation,
- /// currently available via the gold plugin via -thinlto.
- static void createCombinedModuleSummaryIndex() {
- ModuleSummaryIndex CombinedIndex(/*HaveGVs=*/false);
- uint64_t NextModuleId = 0;
- for (auto &Filename : InputFilenames) {
- ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");
- std::unique_ptr<MemoryBuffer> MB =
- ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Filename)));
- ExitOnErr(readModuleSummaryIndex(*MB, CombinedIndex, NextModuleId++));
- }
- // In order to use this index for testing, specifically import testing, we
- // need to update any indirect call edges created from SamplePGO, so that they
- // point to the correct GUIDs.
- updateIndirectCalls(CombinedIndex);
- std::error_code EC;
- assert(!OutputFilename.empty());
- raw_fd_ostream OS(OutputFilename + ".thinlto.bc", EC,
- sys::fs::OpenFlags::OF_None);
- error(EC, "error opening the file '" + OutputFilename + ".thinlto.bc'");
- writeIndexToFile(CombinedIndex, OS);
- OS.close();
- }
- /// Parse the thinlto_prefix_replace option into the \p OldPrefix and
- /// \p NewPrefix strings, if it was specified.
- static void getThinLTOOldAndNewPrefix(std::string &OldPrefix,
- std::string &NewPrefix) {
- assert(ThinLTOPrefixReplace.empty() ||
- ThinLTOPrefixReplace.find(';') != StringRef::npos);
- StringRef PrefixReplace = ThinLTOPrefixReplace;
- std::pair<StringRef, StringRef> Split = PrefixReplace.split(";");
- OldPrefix = Split.first.str();
- NewPrefix = Split.second.str();
- }
- /// Given the original \p Path to an output file, replace any path
- /// prefix matching \p OldPrefix with \p NewPrefix. Also, create the
- /// resulting directory if it does not yet exist.
- static std::string getThinLTOOutputFile(const std::string &Path,
- const std::string &OldPrefix,
- const std::string &NewPrefix) {
- if (OldPrefix.empty() && NewPrefix.empty())
- return Path;
- SmallString<128> NewPath(Path);
- llvm::sys::path::replace_path_prefix(NewPath, OldPrefix, NewPrefix);
- StringRef ParentPath = llvm::sys::path::parent_path(NewPath.str());
- if (!ParentPath.empty()) {
- // Make sure the new directory exists, creating it if necessary.
- if (std::error_code EC = llvm::sys::fs::create_directories(ParentPath))
- error(EC, "error creating the directory '" + ParentPath + "'");
- }
- return std::string(NewPath.str());
- }
- namespace thinlto {
- std::vector<std::unique_ptr<MemoryBuffer>>
- loadAllFilesForIndex(const ModuleSummaryIndex &Index) {
- std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
- for (auto &ModPath : Index.modulePaths()) {
- const auto &Filename = ModPath.first();
- std::string CurrentActivity = ("loading file '" + Filename + "'").str();
- auto InputOrErr = MemoryBuffer::getFile(Filename);
- error(InputOrErr, "error " + CurrentActivity);
- InputBuffers.push_back(std::move(*InputOrErr));
- }
- return InputBuffers;
- }
- std::unique_ptr<ModuleSummaryIndex> loadCombinedIndex() {
- if (ThinLTOIndex.empty())
- report_fatal_error("Missing -thinlto-index for ThinLTO promotion stage");
- ExitOnError ExitOnErr("llvm-lto: error loading file '" + ThinLTOIndex +
- "': ");
- return ExitOnErr(getModuleSummaryIndexForFile(ThinLTOIndex));
- }
- static std::unique_ptr<lto::InputFile> loadInputFile(MemoryBufferRef Buffer) {
- ExitOnError ExitOnErr("llvm-lto: error loading input '" +
- Buffer.getBufferIdentifier().str() + "': ");
- return ExitOnErr(lto::InputFile::create(Buffer));
- }
- static std::unique_ptr<Module> loadModuleFromInput(lto::InputFile &File,
- LLVMContext &CTX) {
- auto &Mod = File.getSingleBitcodeModule();
- auto ModuleOrErr = Mod.parseModule(CTX);
- if (!ModuleOrErr) {
- handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) {
- SMDiagnostic Err = SMDiagnostic(Mod.getModuleIdentifier(),
- SourceMgr::DK_Error, EIB.message());
- Err.print("llvm-lto", errs());
- });
- report_fatal_error("Can't load module, abort.");
- }
- maybeVerifyModule(**ModuleOrErr);
- if (ThinLTOModuleId.getNumOccurrences()) {
- if (InputFilenames.size() != 1)
- report_fatal_error("Can't override the module id for multiple files");
- (*ModuleOrErr)->setModuleIdentifier(ThinLTOModuleId);
- }
- return std::move(*ModuleOrErr);
- }
- static void writeModuleToFile(Module &TheModule, StringRef Filename) {
- std::error_code EC;
- raw_fd_ostream OS(Filename, EC, sys::fs::OpenFlags::OF_None);
- error(EC, "error opening the file '" + Filename + "'");
- maybeVerifyModule(TheModule);
- WriteBitcodeToFile(TheModule, OS, /* ShouldPreserveUseListOrder */ true);
- }
- class ThinLTOProcessing {
- public:
- ThinLTOCodeGenerator ThinGenerator;
- ThinLTOProcessing(const TargetOptions &Options) {
- ThinGenerator.setCodePICModel(codegen::getExplicitRelocModel());
- ThinGenerator.setTargetOptions(Options);
- ThinGenerator.setCacheDir(ThinLTOCacheDir);
- ThinGenerator.setCachePruningInterval(ThinLTOCachePruningInterval);
- ThinGenerator.setCacheEntryExpiration(ThinLTOCacheEntryExpiration);
- ThinGenerator.setCacheMaxSizeFiles(ThinLTOCacheMaxSizeFiles);
- ThinGenerator.setCacheMaxSizeBytes(ThinLTOCacheMaxSizeBytes);
- ThinGenerator.setFreestanding(EnableFreestanding);
- ThinGenerator.setUseNewPM(UseNewPM);
- ThinGenerator.setDebugPassManager(DebugPassManager);
- // Add all the exported symbols to the table of symbols to preserve.
- for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
- ThinGenerator.preserveSymbol(ExportedSymbols[i]);
- }
- void run() {
- switch (ThinLTOMode) {
- case THINLINK:
- return thinLink();
- case THINDISTRIBUTE:
- return distributedIndexes();
- case THINEMITIMPORTS:
- return emitImports();
- case THINPROMOTE:
- return promote();
- case THINIMPORT:
- return import();
- case THININTERNALIZE:
- return internalize();
- case THINOPT:
- return optimize();
- case THINCODEGEN:
- return codegen();
- case THINALL:
- return runAll();
- }
- }
- private:
- /// Load the input files, create the combined index, and write it out.
- void thinLink() {
- // Perform "ThinLink": just produce the index
- if (OutputFilename.empty())
- report_fatal_error(
- "OutputFilename is necessary to store the combined index.\n");
- LLVMContext Ctx;
- std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
- for (unsigned i = 0; i < InputFilenames.size(); ++i) {
- auto &Filename = InputFilenames[i];
- std::string CurrentActivity = "loading file '" + Filename + "'";
- auto InputOrErr = MemoryBuffer::getFile(Filename);
- error(InputOrErr, "error " + CurrentActivity);
- InputBuffers.push_back(std::move(*InputOrErr));
- ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());
- }
- auto CombinedIndex = ThinGenerator.linkCombinedIndex();
- if (!CombinedIndex)
- report_fatal_error("ThinLink didn't create an index");
- std::error_code EC;
- raw_fd_ostream OS(OutputFilename, EC, sys::fs::OpenFlags::OF_None);
- error(EC, "error opening the file '" + OutputFilename + "'");
- writeIndexToFile(*CombinedIndex, OS);
- }
- /// Load the combined index from disk, then compute and generate
- /// individual index files suitable for ThinLTO distributed backend builds
- /// on the files mentioned on the command line (these must match the index
- /// content).
- void distributedIndexes() {
- if (InputFilenames.size() != 1 && !OutputFilename.empty())
- report_fatal_error("Can't handle a single output filename and multiple "
- "input files, do not provide an output filename and "
- "the output files will be suffixed from the input "
- "ones.");
- std::string OldPrefix, NewPrefix;
- getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
- auto Index = loadCombinedIndex();
- for (auto &Filename : InputFilenames) {
- LLVMContext Ctx;
- auto Buffer = loadFile(Filename);
- auto Input = loadInputFile(Buffer->getMemBufferRef());
- auto TheModule = loadModuleFromInput(*Input, Ctx);
- // Build a map of module to the GUIDs and summary objects that should
- // be written to its index.
- std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex;
- ThinGenerator.gatherImportedSummariesForModule(
- *TheModule, *Index, ModuleToSummariesForIndex, *Input);
- std::string OutputName = OutputFilename;
- if (OutputName.empty()) {
- OutputName = Filename + ".thinlto.bc";
- }
- OutputName = getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix);
- std::error_code EC;
- raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);
- error(EC, "error opening the file '" + OutputName + "'");
- writeIndexToFile(*Index, OS, &ModuleToSummariesForIndex);
- }
- }
- /// Load the combined index from disk, compute the imports, and emit
- /// the import file lists for each module to disk.
- void emitImports() {
- if (InputFilenames.size() != 1 && !OutputFilename.empty())
- report_fatal_error("Can't handle a single output filename and multiple "
- "input files, do not provide an output filename and "
- "the output files will be suffixed from the input "
- "ones.");
- std::string OldPrefix, NewPrefix;
- getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
- auto Index = loadCombinedIndex();
- for (auto &Filename : InputFilenames) {
- LLVMContext Ctx;
- auto Buffer = loadFile(Filename);
- auto Input = loadInputFile(Buffer->getMemBufferRef());
- auto TheModule = loadModuleFromInput(*Input, Ctx);
- std::string OutputName = OutputFilename;
- if (OutputName.empty()) {
- OutputName = Filename + ".imports";
- }
- OutputName =
- getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix);
- ThinGenerator.emitImports(*TheModule, OutputName, *Index, *Input);
- }
- }
- /// Load the combined index from disk, then load every file referenced by
- /// the index and add them to the generator, finally perform the promotion
- /// on the files mentioned on the command line (these must match the index
- /// content).
- void promote() {
- if (InputFilenames.size() != 1 && !OutputFilename.empty())
- report_fatal_error("Can't handle a single output filename and multiple "
- "input files, do not provide an output filename and "
- "the output files will be suffixed from the input "
- "ones.");
- auto Index = loadCombinedIndex();
- for (auto &Filename : InputFilenames) {
- LLVMContext Ctx;
- auto Buffer = loadFile(Filename);
- auto Input = loadInputFile(Buffer->getMemBufferRef());
- auto TheModule = loadModuleFromInput(*Input, Ctx);
- ThinGenerator.promote(*TheModule, *Index, *Input);
- std::string OutputName = OutputFilename;
- if (OutputName.empty()) {
- OutputName = Filename + ".thinlto.promoted.bc";
- }
- writeModuleToFile(*TheModule, OutputName);
- }
- }
- /// Load the combined index from disk, then load every file referenced by
- /// the index and add them to the generator, then performs the promotion and
- /// cross module importing on the files mentioned on the command line
- /// (these must match the index content).
- void import() {
- if (InputFilenames.size() != 1 && !OutputFilename.empty())
- report_fatal_error("Can't handle a single output filename and multiple "
- "input files, do not provide an output filename and "
- "the output files will be suffixed from the input "
- "ones.");
- auto Index = loadCombinedIndex();
- auto InputBuffers = loadAllFilesForIndex(*Index);
- for (auto &MemBuffer : InputBuffers)
- ThinGenerator.addModule(MemBuffer->getBufferIdentifier(),
- MemBuffer->getBuffer());
- for (auto &Filename : InputFilenames) {
- LLVMContext Ctx;
- auto Buffer = loadFile(Filename);
- auto Input = loadInputFile(Buffer->getMemBufferRef());
- auto TheModule = loadModuleFromInput(*Input, Ctx);
- ThinGenerator.crossModuleImport(*TheModule, *Index, *Input);
- std::string OutputName = OutputFilename;
- if (OutputName.empty()) {
- OutputName = Filename + ".thinlto.imported.bc";
- }
- writeModuleToFile(*TheModule, OutputName);
- }
- }
- void internalize() {
- if (InputFilenames.size() != 1 && !OutputFilename.empty())
- report_fatal_error("Can't handle a single output filename and multiple "
- "input files, do not provide an output filename and "
- "the output files will be suffixed from the input "
- "ones.");
- if (ExportedSymbols.empty())
- errs() << "Warning: -internalize will not perform without "
- "-exported-symbol\n";
- auto Index = loadCombinedIndex();
- auto InputBuffers = loadAllFilesForIndex(*Index);
- for (auto &MemBuffer : InputBuffers)
- ThinGenerator.addModule(MemBuffer->getBufferIdentifier(),
- MemBuffer->getBuffer());
- for (auto &Filename : InputFilenames) {
- LLVMContext Ctx;
- auto Buffer = loadFile(Filename);
- auto Input = loadInputFile(Buffer->getMemBufferRef());
- auto TheModule = loadModuleFromInput(*Input, Ctx);
- ThinGenerator.internalize(*TheModule, *Index, *Input);
- std::string OutputName = OutputFilename;
- if (OutputName.empty()) {
- OutputName = Filename + ".thinlto.internalized.bc";
- }
- writeModuleToFile(*TheModule, OutputName);
- }
- }
- void optimize() {
- if (InputFilenames.size() != 1 && !OutputFilename.empty())
- report_fatal_error("Can't handle a single output filename and multiple "
- "input files, do not provide an output filename and "
- "the output files will be suffixed from the input "
- "ones.");
- if (!ThinLTOIndex.empty())
- errs() << "Warning: -thinlto-index ignored for optimize stage";
- for (auto &Filename : InputFilenames) {
- LLVMContext Ctx;
- auto Buffer = loadFile(Filename);
- auto Input = loadInputFile(Buffer->getMemBufferRef());
- auto TheModule = loadModuleFromInput(*Input, Ctx);
- ThinGenerator.optimize(*TheModule);
- std::string OutputName = OutputFilename;
- if (OutputName.empty()) {
- OutputName = Filename + ".thinlto.imported.bc";
- }
- writeModuleToFile(*TheModule, OutputName);
- }
- }
- void codegen() {
- if (InputFilenames.size() != 1 && !OutputFilename.empty())
- report_fatal_error("Can't handle a single output filename and multiple "
- "input files, do not provide an output filename and "
- "the output files will be suffixed from the input "
- "ones.");
- if (!ThinLTOIndex.empty())
- errs() << "Warning: -thinlto-index ignored for codegen stage";
- std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
- for (auto &Filename : InputFilenames) {
- LLVMContext Ctx;
- auto InputOrErr = MemoryBuffer::getFile(Filename);
- error(InputOrErr, "error " + CurrentActivity);
- InputBuffers.push_back(std::move(*InputOrErr));
- ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());
- }
- ThinGenerator.setCodeGenOnly(true);
- ThinGenerator.run();
- for (auto BinName :
- zip(ThinGenerator.getProducedBinaries(), InputFilenames)) {
- std::string OutputName = OutputFilename;
- if (OutputName.empty())
- OutputName = std::get<1>(BinName) + ".thinlto.o";
- else if (OutputName == "-") {
- outs() << std::get<0>(BinName)->getBuffer();
- return;
- }
- std::error_code EC;
- raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);
- error(EC, "error opening the file '" + OutputName + "'");
- OS << std::get<0>(BinName)->getBuffer();
- }
- }
- /// Full ThinLTO process
- void runAll() {
- if (!OutputFilename.empty())
- report_fatal_error("Do not provide an output filename for ThinLTO "
- " processing, the output files will be suffixed from "
- "the input ones.");
- if (!ThinLTOIndex.empty())
- errs() << "Warning: -thinlto-index ignored for full ThinLTO process";
- LLVMContext Ctx;
- std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
- for (unsigned i = 0; i < InputFilenames.size(); ++i) {
- auto &Filename = InputFilenames[i];
- std::string CurrentActivity = "loading file '" + Filename + "'";
- auto InputOrErr = MemoryBuffer::getFile(Filename);
- error(InputOrErr, "error " + CurrentActivity);
- InputBuffers.push_back(std::move(*InputOrErr));
- ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());
- }
- if (!ThinLTOSaveTempsPrefix.empty())
- ThinGenerator.setSaveTempsDir(ThinLTOSaveTempsPrefix);
- if (!ThinLTOGeneratedObjectsDir.empty()) {
- ThinGenerator.setGeneratedObjectsDirectory(ThinLTOGeneratedObjectsDir);
- ThinGenerator.run();
- return;
- }
- ThinGenerator.run();
- auto &Binaries = ThinGenerator.getProducedBinaries();
- if (Binaries.size() != InputFilenames.size())
- report_fatal_error("Number of output objects does not match the number "
- "of inputs");
- for (unsigned BufID = 0; BufID < Binaries.size(); ++BufID) {
- auto OutputName = InputFilenames[BufID] + ".thinlto.o";
- std::error_code EC;
- raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);
- error(EC, "error opening the file '" + OutputName + "'");
- OS << Binaries[BufID]->getBuffer();
- }
- }
- /// Load the combined index from disk, then load every file referenced by
- };
- } // end namespace thinlto
- int main(int argc, char **argv) {
- InitLLVM X(argc, argv);
- cl::HideUnrelatedOptions({<OCategory, &getColorCategory()});
- cl::ParseCommandLineOptions(argc, argv, "llvm LTO linker\n");
- if (OptLevel < '0' || OptLevel > '3')
- error("optimization level must be between 0 and 3");
- // Initialize the configured targets.
- InitializeAllTargets();
- InitializeAllTargetMCs();
- InitializeAllAsmPrinters();
- InitializeAllAsmParsers();
- // set up the TargetOptions for the machine
- TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());
- if (ListSymbolsOnly || QueryHasCtorDtor) {
- testLTOModule(Options);
- return 0;
- }
- if (ListDependentLibrariesOnly) {
- listDependentLibraries();
- return 0;
- }
- if (IndexStats) {
- printIndexStats();
- return 0;
- }
- if (CheckHasObjC) {
- for (auto &Filename : InputFilenames) {
- ExitOnError ExitOnErr(std::string(*argv) + ": error loading file '" +
- Filename + "': ");
- std::unique_ptr<MemoryBuffer> BufferOrErr =
- ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(Filename)));
- auto Buffer = std::move(BufferOrErr.get());
- if (ExitOnErr(isBitcodeContainingObjCCategory(*Buffer)))
- outs() << "Bitcode " << Filename << " contains ObjC\n";
- else
- outs() << "Bitcode " << Filename << " does not contain ObjC\n";
- }
- return 0;
- }
- if (PrintMachOCPUOnly) {
- printMachOCPUOnly();
- return 0;
- }
- if (ThinLTOMode.getNumOccurrences()) {
- if (ThinLTOMode.getNumOccurrences() > 1)
- report_fatal_error("You can't specify more than one -thinlto-action");
- thinlto::ThinLTOProcessing ThinLTOProcessor(Options);
- ThinLTOProcessor.run();
- return 0;
- }
- if (ThinLTO) {
- createCombinedModuleSummaryIndex();
- return 0;
- }
- unsigned BaseArg = 0;
- LLVMContext Context;
- Context.setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),
- true);
- LTOCodeGenerator CodeGen(Context);
- CodeGen.setDisableVerify(DisableVerify);
- if (UseDiagnosticHandler)
- CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr);
- CodeGen.setCodePICModel(codegen::getExplicitRelocModel());
- CodeGen.setFreestanding(EnableFreestanding);
- CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF);
- CodeGen.setTargetOptions(Options);
- CodeGen.setShouldRestoreGlobalsLinkage(RestoreGlobalsLinkage);
- StringSet<MallocAllocator> DSOSymbolsSet;
- for (unsigned i = 0; i < DSOSymbols.size(); ++i)
- DSOSymbolsSet.insert(DSOSymbols[i]);
- std::vector<std::string> KeptDSOSyms;
- for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) {
- CurrentActivity = "loading file '" + InputFilenames[i] + "'";
- ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =
- LTOModule::createFromFile(Context, InputFilenames[i], Options);
- std::unique_ptr<LTOModule> &Module = *ModuleOrErr;
- CurrentActivity = "";
- unsigned NumSyms = Module->getSymbolCount();
- for (unsigned I = 0; I < NumSyms; ++I) {
- StringRef Name = Module->getSymbolName(I);
- if (!DSOSymbolsSet.count(Name))
- continue;
- lto_symbol_attributes Attrs = Module->getSymbolAttributes(I);
- unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK;
- if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN)
- KeptDSOSyms.push_back(std::string(Name));
- }
- // We use the first input module as the destination module when
- // SetMergedModule is true.
- if (SetMergedModule && i == BaseArg) {
- // Transfer ownership to the code generator.
- CodeGen.setModule(std::move(Module));
- } else if (!CodeGen.addModule(Module.get())) {
- // Print a message here so that we know addModule() did not abort.
- error("error adding file '" + InputFilenames[i] + "'");
- }
- }
- // Add all the exported symbols to the table of symbols to preserve.
- for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
- CodeGen.addMustPreserveSymbol(ExportedSymbols[i]);
- // Add all the dso symbols to the table of symbols to expose.
- for (unsigned i = 0; i < KeptDSOSyms.size(); ++i)
- CodeGen.addMustPreserveSymbol(KeptDSOSyms[i]);
- // Set cpu and attrs strings for the default target/subtarget.
- CodeGen.setCpu(codegen::getMCPU());
- CodeGen.setOptLevel(OptLevel - '0');
- CodeGen.setAttrs(codegen::getMAttrs());
- CodeGen.setUseNewPM(UseNewPM);
- if (auto FT = codegen::getExplicitFileType())
- CodeGen.setFileType(FT.getValue());
- if (!OutputFilename.empty()) {
- if (SaveLinkedModuleFile) {
- std::string ModuleFilename = OutputFilename;
- ModuleFilename += ".linked.bc";
- std::string ErrMsg;
- if (!CodeGen.writeMergedModules(ModuleFilename))
- error("writing linked module failed.");
- }
- if (!CodeGen.optimize()) {
- // Diagnostic messages should have been printed by the handler.
- error("error optimizing the code");
- }
- if (SaveModuleFile) {
- std::string ModuleFilename = OutputFilename;
- ModuleFilename += ".merged.bc";
- std::string ErrMsg;
- if (!CodeGen.writeMergedModules(ModuleFilename))
- error("writing merged module failed.");
- }
- auto AddStream = [&](size_t Task) -> std::unique_ptr<CachedFileStream> {
- std::string PartFilename = OutputFilename;
- if (Parallelism != 1)
- PartFilename += "." + utostr(Task);
- std::error_code EC;
- auto S =
- std::make_unique<raw_fd_ostream>(PartFilename, EC, sys::fs::OF_None);
- if (EC)
- error("error opening the file '" + PartFilename + "': " + EC.message());
- return std::make_unique<CachedFileStream>(std::move(S));
- };
- if (!CodeGen.compileOptimized(AddStream, Parallelism))
- // Diagnostic messages should have been printed by the handler.
- error("error compiling the code");
- } else {
- if (Parallelism != 1)
- error("-j must be specified together with -o");
- if (SaveModuleFile)
- error(": -save-merged-module must be specified with -o");
- const char *OutputName = nullptr;
- if (!CodeGen.compile_to_file(&OutputName))
- error("error compiling the code");
- // Diagnostic messages should have been printed by the handler.
- outs() << "Wrote native object file '" << OutputName << "'\n";
- }
- return 0;
- }
|