brintos

brintos / llvm-project-archived public Read only

0
0
Text · 42.1 KiB · 30f2e53 Raw
1194 lines · cpp
1//===- llvm-lto: a simple command-line program to link modules with LTO ---===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This program takes in a list of bitcode files, links them, performs link-time10// optimization, and outputs an object file.11//12//===----------------------------------------------------------------------===//13 14#include "llvm-c/lto.h"15#include "llvm/ADT/ArrayRef.h"16#include "llvm/ADT/STLExtras.h"17#include "llvm/ADT/SmallString.h"18#include "llvm/ADT/StringExtras.h"19#include "llvm/ADT/StringRef.h"20#include "llvm/ADT/StringSet.h"21#include "llvm/ADT/Twine.h"22#include "llvm/Bitcode/BitcodeReader.h"23#include "llvm/Bitcode/BitcodeWriter.h"24#include "llvm/CodeGen/CommandFlags.h"25#include "llvm/IR/DiagnosticInfo.h"26#include "llvm/IR/DiagnosticPrinter.h"27#include "llvm/IR/LLVMContext.h"28#include "llvm/IR/Module.h"29#include "llvm/IR/ModuleSummaryIndex.h"30#include "llvm/IR/Verifier.h"31#include "llvm/IRReader/IRReader.h"32#include "llvm/LTO/legacy/LTOCodeGenerator.h"33#include "llvm/LTO/legacy/LTOModule.h"34#include "llvm/LTO/legacy/ThinLTOCodeGenerator.h"35#include "llvm/Support/Allocator.h"36#include "llvm/Support/Casting.h"37#include "llvm/Support/CommandLine.h"38#include "llvm/Support/Error.h"39#include "llvm/Support/ErrorHandling.h"40#include "llvm/Support/ErrorOr.h"41#include "llvm/Support/FileSystem.h"42#include "llvm/Support/InitLLVM.h"43#include "llvm/Support/MemoryBuffer.h"44#include "llvm/Support/Path.h"45#include "llvm/Support/SourceMgr.h"46#include "llvm/Support/TargetSelect.h"47#include "llvm/Support/ToolOutputFile.h"48#include "llvm/Support/WithColor.h"49#include "llvm/Support/raw_ostream.h"50#include "llvm/Target/TargetOptions.h"51#include <algorithm>52#include <cassert>53#include <cstdint>54#include <cstdlib>55#include <memory>56#include <string>57#include <system_error>58#include <tuple>59#include <utility>60#include <vector>61 62using namespace llvm;63 64static codegen::RegisterCodeGenFlags CGF;65 66static cl::OptionCategory LTOCategory("LTO Options");67 68static cl::opt<char>69    OptLevel("O",70             cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "71                      "(default = '-O2')"),72             cl::Prefix, cl::init('2'), cl::cat(LTOCategory));73 74static cl::opt<bool>75    IndexStats("thinlto-index-stats",76               cl::desc("Print statistic for the index in every input files"),77               cl::init(false), cl::cat(LTOCategory));78 79static cl::opt<bool> DisableVerify(80    "disable-verify", cl::init(false),81    cl::desc("Do not run the verifier during the optimization pipeline"),82    cl::cat(LTOCategory));83 84static cl::opt<bool> EnableFreestanding(85    "lto-freestanding", cl::init(false),86    cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"),87    cl::cat(LTOCategory));88 89static cl::opt<bool> UseDiagnosticHandler(90    "use-diagnostic-handler", cl::init(false),91    cl::desc("Use a diagnostic handler to test the handler interface"),92    cl::cat(LTOCategory));93 94static cl::opt<bool>95    ThinLTO("thinlto", cl::init(false),96            cl::desc("Only write combined global index for ThinLTO backends"),97            cl::cat(LTOCategory));98 99enum ThinLTOModes {100  THINLINK,101  THINDISTRIBUTE,102  THINEMITIMPORTS,103  THINPROMOTE,104  THINIMPORT,105  THININTERNALIZE,106  THINOPT,107  THINCODEGEN,108  THINALL109};110 111static cl::opt<ThinLTOModes> ThinLTOMode(112    "thinlto-action", cl::desc("Perform a single ThinLTO stage:"),113    cl::values(114        clEnumValN(115            THINLINK, "thinlink",116            "ThinLink: produces the index by linking only the summaries."),117        clEnumValN(THINDISTRIBUTE, "distributedindexes",118                   "Produces individual indexes for distributed backends."),119        clEnumValN(THINEMITIMPORTS, "emitimports",120                   "Emit imports files for distributed backends."),121        clEnumValN(THINPROMOTE, "promote",122                   "Perform pre-import promotion (requires -thinlto-index)."),123        clEnumValN(THINIMPORT, "import",124                   "Perform both promotion and "125                   "cross-module importing (requires "126                   "-thinlto-index)."),127        clEnumValN(THININTERNALIZE, "internalize",128                   "Perform internalization driven by -exported-symbol "129                   "(requires -thinlto-index)."),130        clEnumValN(THINOPT, "optimize", "Perform ThinLTO optimizations."),131        clEnumValN(THINCODEGEN, "codegen", "CodeGen (expected to match llc)"),132        clEnumValN(THINALL, "run", "Perform ThinLTO end-to-end")),133    cl::cat(LTOCategory));134 135static cl::opt<std::string>136    ThinLTOIndex("thinlto-index",137                 cl::desc("Provide the index produced by a ThinLink, required "138                          "to perform the promotion and/or importing."),139                 cl::cat(LTOCategory));140 141static cl::opt<std::string> ThinLTOPrefixReplace(142    "thinlto-prefix-replace",143    cl::desc("Control where files for distributed backends are "144             "created. Expects 'oldprefix;newprefix' and if path "145             "prefix of output file is oldprefix it will be "146             "replaced with newprefix."),147    cl::cat(LTOCategory));148 149static cl::opt<std::string> ThinLTOModuleId(150    "thinlto-module-id",151    cl::desc("For the module ID for the file to process, useful to "152             "match what is in the index."),153    cl::cat(LTOCategory));154 155static cl::opt<std::string> ThinLTOCacheDir("thinlto-cache-dir",156                                            cl::desc("Enable ThinLTO caching."),157                                            cl::cat(LTOCategory));158 159static cl::opt<int> ThinLTOCachePruningInterval(160    "thinlto-cache-pruning-interval", cl::init(1200),161    cl::desc("Set ThinLTO cache pruning interval."), cl::cat(LTOCategory));162 163static cl::opt<uint64_t> ThinLTOCacheMaxSizeBytes(164    "thinlto-cache-max-size-bytes",165    cl::desc("Set ThinLTO cache pruning directory maximum size in bytes."),166    cl::cat(LTOCategory));167 168static cl::opt<int> ThinLTOCacheMaxSizeFiles(169    "thinlto-cache-max-size-files", cl::init(1000000),170    cl::desc("Set ThinLTO cache pruning directory maximum number of files."),171    cl::cat(LTOCategory));172 173static cl::opt<unsigned> ThinLTOCacheEntryExpiration(174    "thinlto-cache-entry-expiration", cl::init(604800) /* 1w */,175    cl::desc("Set ThinLTO cache entry expiration time."), cl::cat(LTOCategory));176 177static cl::opt<std::string> ThinLTOSaveTempsPrefix(178    "thinlto-save-temps",179    cl::desc("Save ThinLTO temp files using filenames created by adding "180             "suffixes to the given file path prefix."),181    cl::cat(LTOCategory));182 183static cl::opt<std::string> ThinLTOGeneratedObjectsDir(184    "thinlto-save-objects",185    cl::desc("Save ThinLTO generated object files using filenames created in "186             "the given directory."),187    cl::cat(LTOCategory));188 189static cl::opt<bool> SaveLinkedModuleFile(190    "save-linked-module", cl::init(false),191    cl::desc("Write linked LTO module to file before optimize"),192    cl::cat(LTOCategory));193 194static cl::opt<bool>195    SaveModuleFile("save-merged-module", cl::init(false),196                   cl::desc("Write merged LTO module to file before CodeGen"),197                   cl::cat(LTOCategory));198 199static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,200                                            cl::desc("<input bitcode files>"),201                                            cl::cat(LTOCategory));202 203static cl::opt<std::string> OutputFilename("o", cl::init(""),204                                           cl::desc("Override output filename"),205                                           cl::value_desc("filename"),206                                           cl::cat(LTOCategory));207 208static cl::list<std::string> ExportedSymbols(209    "exported-symbol",210    cl::desc("List of symbols to export from the resulting object file"),211    cl::cat(LTOCategory));212 213static cl::list<std::string>214    DSOSymbols("dso-symbol",215               cl::desc("Symbol to put in the symtab in the resulting dso"),216               cl::cat(LTOCategory));217 218static cl::opt<bool> ListSymbolsOnly(219    "list-symbols-only", cl::init(false),220    cl::desc("Instead of running LTO, list the symbols in each IR file"),221    cl::cat(LTOCategory));222 223static cl::opt<bool> ListDependentLibrariesOnly(224    "list-dependent-libraries-only", cl::init(false),225    cl::desc(226        "Instead of running LTO, list the dependent libraries in each IR file"),227    cl::cat(LTOCategory));228 229static cl::opt<bool> QueryHasCtorDtor(230    "query-hasCtorDtor", cl::init(false),231    cl::desc("Queries LTOModule::hasCtorDtor() on each IR file"));232 233static cl::opt<bool>234    SetMergedModule("set-merged-module", cl::init(false),235                    cl::desc("Use the first input module as the merged module"),236                    cl::cat(LTOCategory));237 238static cl::opt<unsigned> Parallelism("j", cl::Prefix, cl::init(1),239                                     cl::desc("Number of backend threads"),240                                     cl::cat(LTOCategory));241 242static cl::opt<bool> RestoreGlobalsLinkage(243    "restore-linkage", cl::init(false),244    cl::desc("Restore original linkage of globals prior to CodeGen"),245    cl::cat(LTOCategory));246 247static cl::opt<bool> CheckHasObjC(248    "check-for-objc", cl::init(false),249    cl::desc("Only check if the module has objective-C defined in it"),250    cl::cat(LTOCategory));251 252static cl::opt<bool> PrintMachOCPUOnly(253    "print-macho-cpu-only", cl::init(false),254    cl::desc("Instead of running LTO, print the mach-o cpu in each IR file"),255    cl::cat(LTOCategory));256 257static cl::opt<bool>258    DebugPassManager("debug-pass-manager", cl::init(false), cl::Hidden,259                     cl::desc("Print pass management debugging information"),260                     cl::cat(LTOCategory));261 262static cl::opt<bool>263    LTOSaveBeforeOpt("lto-save-before-opt", cl::init(false),264                     cl::desc("Save the IR before running optimizations"));265 266namespace {267 268struct ModuleInfo {269  BitVector CanBeHidden;270};271 272} // end anonymous namespace273 274static void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,275                              const char *Msg, void *) {276  errs() << "llvm-lto: ";277  switch (Severity) {278  case LTO_DS_NOTE:279    errs() << "note: ";280    break;281  case LTO_DS_REMARK:282    errs() << "remark: ";283    break;284  case LTO_DS_ERROR:285    errs() << "error: ";286    break;287  case LTO_DS_WARNING:288    errs() << "warning: ";289    break;290  }291  errs() << Msg << "\n";292}293 294static std::string CurrentActivity;295 296namespace {297  struct LLVMLTODiagnosticHandler : public DiagnosticHandler {298    bool handleDiagnostics(const DiagnosticInfo &DI) override {299      raw_ostream &OS = errs();300      OS << "llvm-lto: ";301      switch (DI.getSeverity()) {302      case DS_Error:303        OS << "error";304        break;305      case DS_Warning:306        OS << "warning";307        break;308      case DS_Remark:309        OS << "remark";310        break;311      case DS_Note:312        OS << "note";313        break;314      }315      if (!CurrentActivity.empty())316        OS << ' ' << CurrentActivity;317      OS << ": ";318 319      DiagnosticPrinterRawOStream DP(OS);320      DI.print(DP);321      OS << '\n';322 323      if (DI.getSeverity() == DS_Error)324        exit(1);325      return true;326    }327  };328  }329 330static void error(const Twine &Msg) {331  errs() << "llvm-lto: " << Msg << '\n';332  exit(1);333}334 335static void error(std::error_code EC, const Twine &Prefix) {336  if (EC)337    error(Prefix + ": " + EC.message());338}339 340template <typename T>341static void error(const ErrorOr<T> &V, const Twine &Prefix) {342  error(V.getError(), Prefix);343}344 345static void maybeVerifyModule(const Module &Mod) {346  if (!DisableVerify && verifyModule(Mod, &errs()))347    error("Broken Module");348}349 350static std::unique_ptr<LTOModule>351getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer,352                  const TargetOptions &Options) {353  ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =354      MemoryBuffer::getFile(Path);355  error(BufferOrErr, "error loading file '" + Path + "'");356  Buffer = std::move(BufferOrErr.get());357  CurrentActivity = ("loading file '" + Path + "'").str();358  std::unique_ptr<LLVMContext> Context = std::make_unique<LLVMContext>();359  Context->setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),360                                true);361  ErrorOr<std::unique_ptr<LTOModule>> Ret = LTOModule::createInLocalContext(362      std::move(Context), Buffer->getBufferStart(), Buffer->getBufferSize(),363      Options, Path);364  CurrentActivity = "";365  maybeVerifyModule((*Ret)->getModule());366  return std::move(*Ret);367}368 369/// Print some statistics on the index for each input files.370static void printIndexStats() {371  for (auto &Filename : InputFilenames) {372    ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");373    std::unique_ptr<ModuleSummaryIndex> Index =374        ExitOnErr(getModuleSummaryIndexForFile(Filename));375    // Skip files without a module summary.376    if (!Index)377      report_fatal_error(Twine(Filename) + " does not contain an index");378 379    unsigned Calls = 0, Refs = 0, Functions = 0, Alias = 0, Globals = 0;380    for (auto &Summaries : *Index) {381      for (auto &Summary : Summaries.second.getSummaryList()) {382        Refs += Summary->refs().size();383        if (auto *FuncSummary = dyn_cast<FunctionSummary>(Summary.get())) {384          Functions++;385          Calls += FuncSummary->calls().size();386        } else if (isa<AliasSummary>(Summary.get()))387          Alias++;388        else389          Globals++;390      }391    }392    outs() << "Index " << Filename << " contains "393           << (Alias + Globals + Functions) << " nodes (" << Functions394           << " functions, " << Alias << " alias, " << Globals395           << " globals) and " << (Calls + Refs) << " edges (" << Refs396           << " refs and " << Calls << " calls)\n";397  }398}399 400/// Print the lto symbol attributes.401static void printLTOSymbolAttributes(lto_symbol_attributes Attrs) {402  outs() << "{ ";403  unsigned Permission = Attrs & LTO_SYMBOL_PERMISSIONS_MASK;404  switch (Permission) {405  case LTO_SYMBOL_PERMISSIONS_CODE:406    outs() << "function ";407    break;408  case LTO_SYMBOL_PERMISSIONS_DATA:409    outs() << "data ";410    break;411  case LTO_SYMBOL_PERMISSIONS_RODATA:412    outs() << "constant ";413    break;414  }415  unsigned Definition = Attrs & LTO_SYMBOL_DEFINITION_MASK;416  switch (Definition) {417  case LTO_SYMBOL_DEFINITION_REGULAR:418    outs() << "defined ";419    break;420  case LTO_SYMBOL_DEFINITION_TENTATIVE:421    outs() << "common ";422    break;423  case LTO_SYMBOL_DEFINITION_WEAK:424    outs() << "weak ";425    break;426  case LTO_SYMBOL_DEFINITION_UNDEFINED:427    outs() << "extern ";428    break;429  case LTO_SYMBOL_DEFINITION_WEAKUNDEF:430    outs() << "extern-weak ";431    break;432  }433  unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK;434  switch (Scope) {435  case LTO_SYMBOL_SCOPE_INTERNAL:436    outs() << "internal ";437    break;438  case LTO_SYMBOL_SCOPE_HIDDEN:439    outs() << "hidden ";440    break;441  case LTO_SYMBOL_SCOPE_PROTECTED:442    outs() << "protected ";443    break;444  case LTO_SYMBOL_SCOPE_DEFAULT:445    outs() << "default ";446    break;447  case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN:448    outs() << "omitted ";449    break;450  }451  if (Attrs & LTO_SYMBOL_COMDAT)452    outs() << "comdat ";453  if (Attrs & LTO_SYMBOL_ALIAS)454    outs() << "alias ";455  outs() << "}";456}457 458/// Load each IR file and dump certain information based on active flags.459///460/// The main point here is to provide lit-testable coverage for the LTOModule461/// functionality that's exposed by the C API. Moreover, this provides testing462/// coverage for modules that have been created in their own contexts.463static void testLTOModule(const TargetOptions &Options) {464  for (auto &Filename : InputFilenames) {465    std::unique_ptr<MemoryBuffer> Buffer;466    std::unique_ptr<LTOModule> Module =467        getLocalLTOModule(Filename, Buffer, Options);468 469    if (ListSymbolsOnly) {470      // List the symbols.471      outs() << Filename << ":\n";472      for (int I = 0, E = Module->getSymbolCount(); I != E; ++I) {473        outs() << Module->getSymbolName(I) << "    ";474        printLTOSymbolAttributes(Module->getSymbolAttributes(I));475        outs() << "\n";476      }477      for (int I = 0, E = Module->getAsmUndefSymbolCount(); I != E; ++I)478        outs() << Module->getAsmUndefSymbolName(I) << "    { asm extern }\n";479    }480    if (QueryHasCtorDtor)481      outs() << Filename482             << ": hasCtorDtor = " << (Module->hasCtorDtor() ? "true" : "false")483             << "\n";484  }485}486 487static std::unique_ptr<MemoryBuffer> loadFile(StringRef Filename) {488    ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename.str() +489        "': ");490    return ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Filename)));491}492 493static void listDependentLibraries() {494  for (auto &Filename : InputFilenames) {495    auto Buffer = loadFile(Filename);496    std::string E;497    std::unique_ptr<lto::InputFile> Input(LTOModule::createInputFile(498        Buffer->getBufferStart(), Buffer->getBufferSize(), Filename.c_str(),499        E));500    if (!Input)501      error(E);502 503    // List the dependent libraries.504    outs() << Filename << ":\n";505    for (size_t I = 0, C = LTOModule::getDependentLibraryCount(Input.get());506         I != C; ++I) {507      size_t L = 0;508      const char *S = LTOModule::getDependentLibrary(Input.get(), I, &L);509      assert(S);510      outs() << StringRef(S, L) << "\n";511    }512  }513}514 515static void printMachOCPUOnly() {516  LLVMContext Context;517  Context.setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),518                               true);519  TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());520  for (auto &Filename : InputFilenames) {521    ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =522        LTOModule::createFromFile(Context, Filename, Options);523    if (!ModuleOrErr)524      error(ModuleOrErr, "llvm-lto: ");525 526    Expected<uint32_t> CPUType = (*ModuleOrErr)->getMachOCPUType();527    Expected<uint32_t> CPUSubType = (*ModuleOrErr)->getMachOCPUSubType();528    if (!CPUType)529      error("Error while printing mach-o cputype: " +530            toString(CPUType.takeError()));531    if (!CPUSubType)532      error("Error while printing mach-o cpusubtype: " +533            toString(CPUSubType.takeError()));534    outs() << llvm::format("%s:\ncputype: %u\ncpusubtype: %u\n",535                           Filename.c_str(), *CPUType, *CPUSubType);536  }537}538 539/// Create a combined index file from the input IR files and write it.540///541/// This is meant to enable testing of ThinLTO combined index generation,542/// currently available via the gold plugin via -thinlto.543static void createCombinedModuleSummaryIndex() {544  ModuleSummaryIndex CombinedIndex(/*HaveGVs=*/false);545  for (auto &Filename : InputFilenames) {546    ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");547    std::unique_ptr<MemoryBuffer> MB =548        ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Filename)));549    ExitOnErr(readModuleSummaryIndex(*MB, CombinedIndex));550  }551  // In order to use this index for testing, specifically import testing, we552  // need to update any indirect call edges created from SamplePGO, so that they553  // point to the correct GUIDs.554  updateIndirectCalls(CombinedIndex);555  std::error_code EC;556  assert(!OutputFilename.empty());557  raw_fd_ostream OS(OutputFilename + ".thinlto.bc", EC,558                    sys::fs::OpenFlags::OF_None);559  error(EC, "error opening the file '" + OutputFilename + ".thinlto.bc'");560  writeIndexToFile(CombinedIndex, OS);561  OS.close();562}563 564/// Parse the thinlto_prefix_replace option into the \p OldPrefix and565/// \p NewPrefix strings, if it was specified.566static void getThinLTOOldAndNewPrefix(std::string &OldPrefix,567                                      std::string &NewPrefix) {568  assert(ThinLTOPrefixReplace.empty() ||569         ThinLTOPrefixReplace.find(';') != StringRef::npos);570  StringRef PrefixReplace = ThinLTOPrefixReplace;571  std::pair<StringRef, StringRef> Split = PrefixReplace.split(";");572  OldPrefix = Split.first.str();573  NewPrefix = Split.second.str();574}575 576/// Given the original \p Path to an output file, replace any path577/// prefix matching \p OldPrefix with \p NewPrefix. Also, create the578/// resulting directory if it does not yet exist.579static std::string getThinLTOOutputFile(StringRef Path, StringRef OldPrefix,580                                        StringRef NewPrefix) {581  if (OldPrefix.empty() && NewPrefix.empty())582    return std::string(Path);583  SmallString<128> NewPath(Path);584  llvm::sys::path::replace_path_prefix(NewPath, OldPrefix, NewPrefix);585  StringRef ParentPath = llvm::sys::path::parent_path(NewPath.str());586  if (!ParentPath.empty()) {587    // Make sure the new directory exists, creating it if necessary.588    if (std::error_code EC = llvm::sys::fs::create_directories(ParentPath))589      error(EC, "error creating the directory '" + ParentPath + "'");590  }591  return std::string(NewPath);592}593 594namespace thinlto {595 596std::vector<std::unique_ptr<MemoryBuffer>>597loadAllFilesForIndex(const ModuleSummaryIndex &Index) {598  std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;599 600  for (auto &ModPath : Index.modulePaths()) {601    const auto &Filename = ModPath.first();602    std::string CurrentActivity = ("loading file '" + Filename + "'").str();603    auto InputOrErr = MemoryBuffer::getFile(Filename);604    error(InputOrErr, "error " + CurrentActivity);605    InputBuffers.push_back(std::move(*InputOrErr));606  }607  return InputBuffers;608}609 610std::unique_ptr<ModuleSummaryIndex> loadCombinedIndex() {611  if (ThinLTOIndex.empty())612    report_fatal_error("Missing -thinlto-index for ThinLTO promotion stage");613  ExitOnError ExitOnErr("llvm-lto: error loading file '" + ThinLTOIndex +614                        "': ");615  return ExitOnErr(getModuleSummaryIndexForFile(ThinLTOIndex));616}617 618static std::unique_ptr<lto::InputFile> loadInputFile(MemoryBufferRef Buffer) {619  ExitOnError ExitOnErr("llvm-lto: error loading input '" +620                        Buffer.getBufferIdentifier().str() + "': ");621  return ExitOnErr(lto::InputFile::create(Buffer));622}623 624static std::unique_ptr<Module> loadModuleFromInput(lto::InputFile &File,625                                                   LLVMContext &CTX) {626  auto &Mod = File.getSingleBitcodeModule();627  auto ModuleOrErr = Mod.parseModule(CTX);628  if (!ModuleOrErr) {629    handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) {630      SMDiagnostic Err = SMDiagnostic(Mod.getModuleIdentifier(),631                                      SourceMgr::DK_Error, EIB.message());632      Err.print("llvm-lto", errs());633    });634    report_fatal_error("Can't load module, abort.");635  }636  maybeVerifyModule(**ModuleOrErr);637  if (ThinLTOModuleId.getNumOccurrences()) {638    if (InputFilenames.size() != 1)639      report_fatal_error("Can't override the module id for multiple files");640    (*ModuleOrErr)->setModuleIdentifier(ThinLTOModuleId);641  }642  return std::move(*ModuleOrErr);643}644 645static void writeModuleToFile(Module &TheModule, StringRef Filename) {646  std::error_code EC;647  raw_fd_ostream OS(Filename, EC, sys::fs::OpenFlags::OF_None);648  error(EC, "error opening the file '" + Filename + "'");649  maybeVerifyModule(TheModule);650  WriteBitcodeToFile(TheModule, OS, /* ShouldPreserveUseListOrder */ true);651}652 653class ThinLTOProcessing {654public:655  ThinLTOCodeGenerator ThinGenerator;656 657  ThinLTOProcessing(const TargetOptions &Options) {658    ThinGenerator.setCodePICModel(codegen::getExplicitRelocModel());659    ThinGenerator.setTargetOptions(Options);660    ThinGenerator.setCacheDir(ThinLTOCacheDir);661    ThinGenerator.setCachePruningInterval(ThinLTOCachePruningInterval);662    ThinGenerator.setCacheEntryExpiration(ThinLTOCacheEntryExpiration);663    ThinGenerator.setCacheMaxSizeFiles(ThinLTOCacheMaxSizeFiles);664    ThinGenerator.setCacheMaxSizeBytes(ThinLTOCacheMaxSizeBytes);665    ThinGenerator.setFreestanding(EnableFreestanding);666    ThinGenerator.setDebugPassManager(DebugPassManager);667 668    // Add all the exported symbols to the table of symbols to preserve.669    for (unsigned i = 0; i < ExportedSymbols.size(); ++i)670      ThinGenerator.preserveSymbol(ExportedSymbols[i]);671  }672 673  void run() {674    switch (ThinLTOMode) {675    case THINLINK:676      return thinLink();677    case THINDISTRIBUTE:678      return distributedIndexes();679    case THINEMITIMPORTS:680      return emitImports();681    case THINPROMOTE:682      return promote();683    case THINIMPORT:684      return import();685    case THININTERNALIZE:686      return internalize();687    case THINOPT:688      return optimize();689    case THINCODEGEN:690      return codegen();691    case THINALL:692      return runAll();693    }694  }695 696private:697  /// Load the input files, create the combined index, and write it out.698  void thinLink() {699    // Perform "ThinLink": just produce the index700    if (OutputFilename.empty())701      report_fatal_error(702          "OutputFilename is necessary to store the combined index.\n");703 704    LLVMContext Ctx;705    std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;706    for (unsigned i = 0; i < InputFilenames.size(); ++i) {707      auto &Filename = InputFilenames[i];708      std::string CurrentActivity = "loading file '" + Filename + "'";709      auto InputOrErr = MemoryBuffer::getFile(Filename);710      error(InputOrErr, "error " + CurrentActivity);711      InputBuffers.push_back(std::move(*InputOrErr));712      ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());713    }714 715    auto CombinedIndex = ThinGenerator.linkCombinedIndex();716    if (!CombinedIndex)717      report_fatal_error("ThinLink didn't create an index");718    std::error_code EC;719    raw_fd_ostream OS(OutputFilename, EC, sys::fs::OpenFlags::OF_None);720    error(EC, "error opening the file '" + OutputFilename + "'");721    writeIndexToFile(*CombinedIndex, OS);722  }723 724  /// Load the combined index from disk, then compute and generate725  /// individual index files suitable for ThinLTO distributed backend builds726  /// on the files mentioned on the command line (these must match the index727  /// content).728  void distributedIndexes() {729    if (InputFilenames.size() != 1 && !OutputFilename.empty())730      report_fatal_error("Can't handle a single output filename and multiple "731                         "input files, do not provide an output filename and "732                         "the output files will be suffixed from the input "733                         "ones.");734 735    std::string OldPrefix, NewPrefix;736    getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);737 738    auto Index = loadCombinedIndex();739    for (auto &Filename : InputFilenames) {740      LLVMContext Ctx;741      auto Buffer = loadFile(Filename);742      auto Input = loadInputFile(Buffer->getMemBufferRef());743      auto TheModule = loadModuleFromInput(*Input, Ctx);744 745      // Build a map of module to the GUIDs and summary objects that should746      // be written to its index.747      ModuleToSummariesForIndexTy ModuleToSummariesForIndex;748      GVSummaryPtrSet DecSummaries;749      ThinGenerator.gatherImportedSummariesForModule(750          *TheModule, *Index, ModuleToSummariesForIndex, DecSummaries, *Input);751 752      std::string OutputName = OutputFilename;753      if (OutputName.empty()) {754        OutputName = Filename + ".thinlto.bc";755      }756      OutputName = getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix);757      std::error_code EC;758      raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);759      error(EC, "error opening the file '" + OutputName + "'");760      writeIndexToFile(*Index, OS, &ModuleToSummariesForIndex, &DecSummaries);761    }762  }763 764  /// Load the combined index from disk, compute the imports, and emit765  /// the import file lists for each module to disk.766  void emitImports() {767    if (InputFilenames.size() != 1 && !OutputFilename.empty())768      report_fatal_error("Can't handle a single output filename and multiple "769                         "input files, do not provide an output filename and "770                         "the output files will be suffixed from the input "771                         "ones.");772 773    std::string OldPrefix, NewPrefix;774    getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);775 776    auto Index = loadCombinedIndex();777    for (auto &Filename : InputFilenames) {778      LLVMContext Ctx;779      auto Buffer = loadFile(Filename);780      auto Input = loadInputFile(Buffer->getMemBufferRef());781      auto TheModule = loadModuleFromInput(*Input, Ctx);782      std::string OutputName = OutputFilename;783      if (OutputName.empty()) {784        OutputName = Filename + ".imports";785      }786      OutputName =787          getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix);788      ThinGenerator.emitImports(*TheModule, OutputName, *Index, *Input);789    }790  }791 792  /// Load the combined index from disk, then load every file referenced by793  /// the index and add them to the generator, finally perform the promotion794  /// on the files mentioned on the command line (these must match the index795  /// content).796  void promote() {797    if (InputFilenames.size() != 1 && !OutputFilename.empty())798      report_fatal_error("Can't handle a single output filename and multiple "799                         "input files, do not provide an output filename and "800                         "the output files will be suffixed from the input "801                         "ones.");802 803    auto Index = loadCombinedIndex();804    for (auto &Filename : InputFilenames) {805      LLVMContext Ctx;806      auto Buffer = loadFile(Filename);807      auto Input = loadInputFile(Buffer->getMemBufferRef());808      auto TheModule = loadModuleFromInput(*Input, Ctx);809 810      ThinGenerator.promote(*TheModule, *Index, *Input);811 812      std::string OutputName = OutputFilename;813      if (OutputName.empty()) {814        OutputName = Filename + ".thinlto.promoted.bc";815      }816      writeModuleToFile(*TheModule, OutputName);817    }818  }819 820  /// Load the combined index from disk, then load every file referenced by821  /// the index and add them to the generator, then performs the promotion and822  /// cross module importing on the files mentioned on the command line823  /// (these must match the index content).824  void import() {825    if (InputFilenames.size() != 1 && !OutputFilename.empty())826      report_fatal_error("Can't handle a single output filename and multiple "827                         "input files, do not provide an output filename and "828                         "the output files will be suffixed from the input "829                         "ones.");830 831    auto Index = loadCombinedIndex();832    auto InputBuffers = loadAllFilesForIndex(*Index);833    for (auto &MemBuffer : InputBuffers)834      ThinGenerator.addModule(MemBuffer->getBufferIdentifier(),835                              MemBuffer->getBuffer());836 837    for (auto &Filename : InputFilenames) {838      LLVMContext Ctx;839      auto Buffer = loadFile(Filename);840      auto Input = loadInputFile(Buffer->getMemBufferRef());841      auto TheModule = loadModuleFromInput(*Input, Ctx);842 843      ThinGenerator.crossModuleImport(*TheModule, *Index, *Input);844 845      std::string OutputName = OutputFilename;846      if (OutputName.empty()) {847        OutputName = Filename + ".thinlto.imported.bc";848      }849      writeModuleToFile(*TheModule, OutputName);850    }851  }852 853  void internalize() {854    if (InputFilenames.size() != 1 && !OutputFilename.empty())855      report_fatal_error("Can't handle a single output filename and multiple "856                         "input files, do not provide an output filename and "857                         "the output files will be suffixed from the input "858                         "ones.");859 860    if (ExportedSymbols.empty())861      errs() << "Warning: -internalize will not perform without "862                "-exported-symbol\n";863 864    auto Index = loadCombinedIndex();865    auto InputBuffers = loadAllFilesForIndex(*Index);866    for (auto &MemBuffer : InputBuffers)867      ThinGenerator.addModule(MemBuffer->getBufferIdentifier(),868                              MemBuffer->getBuffer());869 870    for (auto &Filename : InputFilenames) {871      LLVMContext Ctx;872      auto Buffer = loadFile(Filename);873      auto Input = loadInputFile(Buffer->getMemBufferRef());874      auto TheModule = loadModuleFromInput(*Input, Ctx);875 876      ThinGenerator.internalize(*TheModule, *Index, *Input);877 878      std::string OutputName = OutputFilename;879      if (OutputName.empty()) {880        OutputName = Filename + ".thinlto.internalized.bc";881      }882      writeModuleToFile(*TheModule, OutputName);883    }884  }885 886  void optimize() {887    if (InputFilenames.size() != 1 && !OutputFilename.empty())888      report_fatal_error("Can't handle a single output filename and multiple "889                         "input files, do not provide an output filename and "890                         "the output files will be suffixed from the input "891                         "ones.");892    if (!ThinLTOIndex.empty())893      errs() << "Warning: -thinlto-index ignored for optimize stage";894 895    for (auto &Filename : InputFilenames) {896      LLVMContext Ctx;897      auto Buffer = loadFile(Filename);898      auto Input = loadInputFile(Buffer->getMemBufferRef());899      auto TheModule = loadModuleFromInput(*Input, Ctx);900 901      ThinGenerator.optimize(*TheModule);902 903      std::string OutputName = OutputFilename;904      if (OutputName.empty()) {905        OutputName = Filename + ".thinlto.imported.bc";906      }907      writeModuleToFile(*TheModule, OutputName);908    }909  }910 911  void codegen() {912    if (InputFilenames.size() != 1 && !OutputFilename.empty())913      report_fatal_error("Can't handle a single output filename and multiple "914                         "input files, do not provide an output filename and "915                         "the output files will be suffixed from the input "916                         "ones.");917    if (!ThinLTOIndex.empty())918      errs() << "Warning: -thinlto-index ignored for codegen stage";919 920    std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;921    for (auto &Filename : InputFilenames) {922      LLVMContext Ctx;923      auto InputOrErr = MemoryBuffer::getFile(Filename);924      error(InputOrErr, "error " + CurrentActivity);925      InputBuffers.push_back(std::move(*InputOrErr));926      ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());927    }928    ThinGenerator.setCodeGenOnly(true);929    ThinGenerator.run();930    for (auto BinName :931         zip(ThinGenerator.getProducedBinaries(), InputFilenames)) {932      std::string OutputName = OutputFilename;933      if (OutputName.empty())934        OutputName = std::get<1>(BinName) + ".thinlto.o";935      else if (OutputName == "-") {936        outs() << std::get<0>(BinName)->getBuffer();937        return;938      }939 940      std::error_code EC;941      raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);942      error(EC, "error opening the file '" + OutputName + "'");943      OS << std::get<0>(BinName)->getBuffer();944    }945  }946 947  /// Full ThinLTO process948  void runAll() {949    if (!OutputFilename.empty())950      report_fatal_error("Do not provide an output filename for ThinLTO "951                         " processing, the output files will be suffixed from "952                         "the input ones.");953 954    if (!ThinLTOIndex.empty())955      errs() << "Warning: -thinlto-index ignored for full ThinLTO process";956 957    LLVMContext Ctx;958    std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;959    for (unsigned i = 0; i < InputFilenames.size(); ++i) {960      auto &Filename = InputFilenames[i];961      std::string CurrentActivity = "loading file '" + Filename + "'";962      auto InputOrErr = MemoryBuffer::getFile(Filename);963      error(InputOrErr, "error " + CurrentActivity);964      InputBuffers.push_back(std::move(*InputOrErr));965      ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());966    }967 968    if (!ThinLTOSaveTempsPrefix.empty())969      ThinGenerator.setSaveTempsDir(ThinLTOSaveTempsPrefix);970 971    if (!ThinLTOGeneratedObjectsDir.empty()) {972      ThinGenerator.setGeneratedObjectsDirectory(ThinLTOGeneratedObjectsDir);973      ThinGenerator.run();974      return;975    }976 977    ThinGenerator.run();978 979    auto &Binaries = ThinGenerator.getProducedBinaries();980    if (Binaries.size() != InputFilenames.size())981      report_fatal_error("Number of output objects does not match the number "982                         "of inputs");983 984    for (unsigned BufID = 0; BufID < Binaries.size(); ++BufID) {985      auto OutputName = InputFilenames[BufID] + ".thinlto.o";986      std::error_code EC;987      raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);988      error(EC, "error opening the file '" + OutputName + "'");989      OS << Binaries[BufID]->getBuffer();990    }991  }992 993  /// Load the combined index from disk, then load every file referenced by994};995 996} // end namespace thinlto997 998int main(int argc, char **argv) {999  InitLLVM X(argc, argv);1000  cl::HideUnrelatedOptions({&LTOCategory, &getColorCategory()});1001  cl::ParseCommandLineOptions(argc, argv, "llvm LTO linker\n");1002 1003  if (OptLevel < '0' || OptLevel > '3')1004    error("optimization level must be between 0 and 3");1005 1006  // Initialize the configured targets.1007  InitializeAllTargets();1008  InitializeAllTargetMCs();1009  InitializeAllAsmPrinters();1010  InitializeAllAsmParsers();1011 1012  // set up the TargetOptions for the machine1013  TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());1014 1015  if (ListSymbolsOnly || QueryHasCtorDtor) {1016    testLTOModule(Options);1017    return 0;1018  }1019 1020  if (ListDependentLibrariesOnly) {1021    listDependentLibraries();1022    return 0;1023  }1024 1025  if (IndexStats) {1026    printIndexStats();1027    return 0;1028  }1029 1030  if (CheckHasObjC) {1031    for (auto &Filename : InputFilenames) {1032      ExitOnError ExitOnErr(std::string(*argv) + ": error loading file '" +1033                            Filename + "': ");1034      std::unique_ptr<MemoryBuffer> BufferOrErr =1035          ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(Filename)));1036      auto Buffer = std::move(BufferOrErr.get());1037      if (ExitOnErr(isBitcodeContainingObjCCategory(*Buffer)))1038        outs() << "Bitcode " << Filename << " contains ObjC\n";1039      else1040        outs() << "Bitcode " << Filename << " does not contain ObjC\n";1041    }1042    return 0;1043  }1044 1045  if (PrintMachOCPUOnly) {1046    printMachOCPUOnly();1047    return 0;1048  }1049 1050  if (ThinLTOMode.getNumOccurrences()) {1051    if (ThinLTOMode.getNumOccurrences() > 1)1052      report_fatal_error("You can't specify more than one -thinlto-action");1053    thinlto::ThinLTOProcessing ThinLTOProcessor(Options);1054    ThinLTOProcessor.run();1055    return 0;1056  }1057 1058  if (ThinLTO) {1059    createCombinedModuleSummaryIndex();1060    return 0;1061  }1062 1063  unsigned BaseArg = 0;1064 1065  LLVMContext Context;1066  Context.setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),1067                               true);1068 1069  LTOCodeGenerator CodeGen(Context);1070  CodeGen.setDisableVerify(DisableVerify);1071 1072  if (UseDiagnosticHandler)1073    CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr);1074 1075  CodeGen.setCodePICModel(codegen::getExplicitRelocModel());1076  CodeGen.setFreestanding(EnableFreestanding);1077  CodeGen.setDebugPassManager(DebugPassManager);1078 1079  CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF);1080  CodeGen.setTargetOptions(Options);1081  CodeGen.setShouldRestoreGlobalsLinkage(RestoreGlobalsLinkage);1082 1083  StringSet<MallocAllocator> DSOSymbolsSet(llvm::from_range, DSOSymbols);1084 1085  std::vector<std::string> KeptDSOSyms;1086 1087  for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) {1088    CurrentActivity = "loading file '" + InputFilenames[i] + "'";1089    ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =1090        LTOModule::createFromFile(Context, InputFilenames[i], Options);1091    std::unique_ptr<LTOModule> &Module = *ModuleOrErr;1092    CurrentActivity = "";1093 1094    unsigned NumSyms = Module->getSymbolCount();1095    for (unsigned I = 0; I < NumSyms; ++I) {1096      StringRef Name = Module->getSymbolName(I);1097      if (!DSOSymbolsSet.count(Name))1098        continue;1099      lto_symbol_attributes Attrs = Module->getSymbolAttributes(I);1100      unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK;1101      if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN)1102        KeptDSOSyms.push_back(std::string(Name));1103    }1104 1105    // We use the first input module as the destination module when1106    // SetMergedModule is true.1107    if (SetMergedModule && i == BaseArg) {1108      // Transfer ownership to the code generator.1109      CodeGen.setModule(std::move(Module));1110    } else if (!CodeGen.addModule(Module.get())) {1111      // Print a message here so that we know addModule() did not abort.1112      error("error adding file '" + InputFilenames[i] + "'");1113    }1114  }1115 1116  // Add all the exported symbols to the table of symbols to preserve.1117  for (unsigned i = 0; i < ExportedSymbols.size(); ++i)1118    CodeGen.addMustPreserveSymbol(ExportedSymbols[i]);1119 1120  // Add all the dso symbols to the table of symbols to expose.1121  for (unsigned i = 0; i < KeptDSOSyms.size(); ++i)1122    CodeGen.addMustPreserveSymbol(KeptDSOSyms[i]);1123 1124  // Set cpu and attrs strings for the default target/subtarget.1125  CodeGen.setCpu(codegen::getMCPU());1126 1127  CodeGen.setOptLevel(OptLevel - '0');1128  CodeGen.setAttrs(codegen::getMAttrs());1129 1130  if (auto FT = codegen::getExplicitFileType())1131    CodeGen.setFileType(*FT);1132 1133  if (!OutputFilename.empty()) {1134    if (LTOSaveBeforeOpt)1135      CodeGen.setSaveIRBeforeOptPath(OutputFilename + ".0.preopt.bc");1136 1137    if (SaveLinkedModuleFile) {1138      std::string ModuleFilename = OutputFilename;1139      ModuleFilename += ".linked.bc";1140 1141      if (!CodeGen.writeMergedModules(ModuleFilename))1142        error("writing linked module failed.");1143    }1144 1145    if (!CodeGen.optimize()) {1146      // Diagnostic messages should have been printed by the handler.1147      error("error optimizing the code");1148    }1149 1150    if (SaveModuleFile) {1151      std::string ModuleFilename = OutputFilename;1152      ModuleFilename += ".merged.bc";1153 1154      if (!CodeGen.writeMergedModules(ModuleFilename))1155        error("writing merged module failed.");1156    }1157 1158    auto AddStream =1159        [&](size_t Task,1160            const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {1161      std::string PartFilename = OutputFilename;1162      if (Parallelism != 1)1163        PartFilename += "." + utostr(Task);1164 1165      std::error_code EC;1166      auto S =1167          std::make_unique<raw_fd_ostream>(PartFilename, EC, sys::fs::OF_None);1168      if (EC)1169        error("error opening the file '" + PartFilename + "': " + EC.message());1170      return std::make_unique<CachedFileStream>(std::move(S));1171    };1172 1173    if (!CodeGen.compileOptimized(AddStream, Parallelism))1174      // Diagnostic messages should have been printed by the handler.1175      error("error compiling the code");1176 1177  } else {1178    if (Parallelism != 1)1179      error("-j must be specified together with -o");1180 1181    if (SaveModuleFile)1182      error(": -save-merged-module must be specified with -o");1183 1184    const char *OutputName = nullptr;1185    if (!CodeGen.compile_to_file(&OutputName))1186      error("error compiling the code");1187      // Diagnostic messages should have been printed by the handler.1188 1189    outs() << "Wrote native object file '" << OutputName << "'\n";1190  }1191 1192  return 0;1193}1194