Path: blob/main/contrib/llvm-project/llvm/tools/llvm-lto/llvm-lto.cpp
35259 views
//===- llvm-lto: a simple command-line program to link modules with LTO ---===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This program takes in a list of bitcode files, links them, performs link-time9// optimization, and outputs an object file.10//11//===----------------------------------------------------------------------===//1213#include "llvm-c/lto.h"14#include "llvm/ADT/ArrayRef.h"15#include "llvm/ADT/STLExtras.h"16#include "llvm/ADT/SmallString.h"17#include "llvm/ADT/StringExtras.h"18#include "llvm/ADT/StringRef.h"19#include "llvm/ADT/StringSet.h"20#include "llvm/ADT/Twine.h"21#include "llvm/Bitcode/BitcodeReader.h"22#include "llvm/Bitcode/BitcodeWriter.h"23#include "llvm/CodeGen/CommandFlags.h"24#include "llvm/IR/DiagnosticInfo.h"25#include "llvm/IR/DiagnosticPrinter.h"26#include "llvm/IR/LLVMContext.h"27#include "llvm/IR/Module.h"28#include "llvm/IR/ModuleSummaryIndex.h"29#include "llvm/IR/Verifier.h"30#include "llvm/IRReader/IRReader.h"31#include "llvm/LTO/legacy/LTOCodeGenerator.h"32#include "llvm/LTO/legacy/LTOModule.h"33#include "llvm/LTO/legacy/ThinLTOCodeGenerator.h"34#include "llvm/Support/Allocator.h"35#include "llvm/Support/Casting.h"36#include "llvm/Support/CommandLine.h"37#include "llvm/Support/Error.h"38#include "llvm/Support/ErrorHandling.h"39#include "llvm/Support/ErrorOr.h"40#include "llvm/Support/FileSystem.h"41#include "llvm/Support/InitLLVM.h"42#include "llvm/Support/MemoryBuffer.h"43#include "llvm/Support/Path.h"44#include "llvm/Support/SourceMgr.h"45#include "llvm/Support/TargetSelect.h"46#include "llvm/Support/ToolOutputFile.h"47#include "llvm/Support/raw_ostream.h"48#include "llvm/Support/WithColor.h"49#include "llvm/Target/TargetOptions.h"50#include <algorithm>51#include <cassert>52#include <cstdint>53#include <cstdlib>54#include <map>55#include <memory>56#include <string>57#include <system_error>58#include <tuple>59#include <utility>60#include <vector>6162using namespace llvm;6364static codegen::RegisterCodeGenFlags CGF;6566static cl::OptionCategory LTOCategory("LTO Options");6768static cl::opt<char>69OptLevel("O",70cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "71"(default = '-O2')"),72cl::Prefix, cl::init('2'), cl::cat(LTOCategory));7374static cl::opt<bool>75IndexStats("thinlto-index-stats",76cl::desc("Print statistic for the index in every input files"),77cl::init(false), cl::cat(LTOCategory));7879static cl::opt<bool> DisableVerify(80"disable-verify", cl::init(false),81cl::desc("Do not run the verifier during the optimization pipeline"),82cl::cat(LTOCategory));8384static cl::opt<bool> EnableFreestanding(85"lto-freestanding", cl::init(false),86cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"),87cl::cat(LTOCategory));8889static cl::opt<bool> UseDiagnosticHandler(90"use-diagnostic-handler", cl::init(false),91cl::desc("Use a diagnostic handler to test the handler interface"),92cl::cat(LTOCategory));9394static cl::opt<bool>95ThinLTO("thinlto", cl::init(false),96cl::desc("Only write combined global index for ThinLTO backends"),97cl::cat(LTOCategory));9899enum ThinLTOModes {100THINLINK,101THINDISTRIBUTE,102THINEMITIMPORTS,103THINPROMOTE,104THINIMPORT,105THININTERNALIZE,106THINOPT,107THINCODEGEN,108THINALL109};110111cl::opt<ThinLTOModes> ThinLTOMode(112"thinlto-action", cl::desc("Perform a single ThinLTO stage:"),113cl::values(114clEnumValN(115THINLINK, "thinlink",116"ThinLink: produces the index by linking only the summaries."),117clEnumValN(THINDISTRIBUTE, "distributedindexes",118"Produces individual indexes for distributed backends."),119clEnumValN(THINEMITIMPORTS, "emitimports",120"Emit imports files for distributed backends."),121clEnumValN(THINPROMOTE, "promote",122"Perform pre-import promotion (requires -thinlto-index)."),123clEnumValN(THINIMPORT, "import",124"Perform both promotion and "125"cross-module importing (requires "126"-thinlto-index)."),127clEnumValN(THININTERNALIZE, "internalize",128"Perform internalization driven by -exported-symbol "129"(requires -thinlto-index)."),130clEnumValN(THINOPT, "optimize", "Perform ThinLTO optimizations."),131clEnumValN(THINCODEGEN, "codegen", "CodeGen (expected to match llc)"),132clEnumValN(THINALL, "run", "Perform ThinLTO end-to-end")),133cl::cat(LTOCategory));134135static cl::opt<std::string>136ThinLTOIndex("thinlto-index",137cl::desc("Provide the index produced by a ThinLink, required "138"to perform the promotion and/or importing."),139cl::cat(LTOCategory));140141static cl::opt<std::string> ThinLTOPrefixReplace(142"thinlto-prefix-replace",143cl::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."),147cl::cat(LTOCategory));148149static cl::opt<std::string> ThinLTOModuleId(150"thinlto-module-id",151cl::desc("For the module ID for the file to process, useful to "152"match what is in the index."),153cl::cat(LTOCategory));154155static cl::opt<std::string> ThinLTOCacheDir("thinlto-cache-dir",156cl::desc("Enable ThinLTO caching."),157cl::cat(LTOCategory));158159static cl::opt<int> ThinLTOCachePruningInterval(160"thinlto-cache-pruning-interval", cl::init(1200),161cl::desc("Set ThinLTO cache pruning interval."), cl::cat(LTOCategory));162163static cl::opt<uint64_t> ThinLTOCacheMaxSizeBytes(164"thinlto-cache-max-size-bytes",165cl::desc("Set ThinLTO cache pruning directory maximum size in bytes."),166cl::cat(LTOCategory));167168static cl::opt<int> ThinLTOCacheMaxSizeFiles(169"thinlto-cache-max-size-files", cl::init(1000000),170cl::desc("Set ThinLTO cache pruning directory maximum number of files."),171cl::cat(LTOCategory));172173static cl::opt<unsigned> ThinLTOCacheEntryExpiration(174"thinlto-cache-entry-expiration", cl::init(604800) /* 1w */,175cl::desc("Set ThinLTO cache entry expiration time."), cl::cat(LTOCategory));176177static cl::opt<std::string> ThinLTOSaveTempsPrefix(178"thinlto-save-temps",179cl::desc("Save ThinLTO temp files using filenames created by adding "180"suffixes to the given file path prefix."),181cl::cat(LTOCategory));182183static cl::opt<std::string> ThinLTOGeneratedObjectsDir(184"thinlto-save-objects",185cl::desc("Save ThinLTO generated object files using filenames created in "186"the given directory."),187cl::cat(LTOCategory));188189static cl::opt<bool> SaveLinkedModuleFile(190"save-linked-module", cl::init(false),191cl::desc("Write linked LTO module to file before optimize"),192cl::cat(LTOCategory));193194static cl::opt<bool>195SaveModuleFile("save-merged-module", cl::init(false),196cl::desc("Write merged LTO module to file before CodeGen"),197cl::cat(LTOCategory));198199static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,200cl::desc("<input bitcode files>"),201cl::cat(LTOCategory));202203static cl::opt<std::string> OutputFilename("o", cl::init(""),204cl::desc("Override output filename"),205cl::value_desc("filename"),206cl::cat(LTOCategory));207208static cl::list<std::string> ExportedSymbols(209"exported-symbol",210cl::desc("List of symbols to export from the resulting object file"),211cl::cat(LTOCategory));212213static cl::list<std::string>214DSOSymbols("dso-symbol",215cl::desc("Symbol to put in the symtab in the resulting dso"),216cl::cat(LTOCategory));217218static cl::opt<bool> ListSymbolsOnly(219"list-symbols-only", cl::init(false),220cl::desc("Instead of running LTO, list the symbols in each IR file"),221cl::cat(LTOCategory));222223static cl::opt<bool> ListDependentLibrariesOnly(224"list-dependent-libraries-only", cl::init(false),225cl::desc(226"Instead of running LTO, list the dependent libraries in each IR file"),227cl::cat(LTOCategory));228229static cl::opt<bool> QueryHasCtorDtor(230"query-hasCtorDtor", cl::init(false),231cl::desc("Queries LTOModule::hasCtorDtor() on each IR file"));232233static cl::opt<bool>234SetMergedModule("set-merged-module", cl::init(false),235cl::desc("Use the first input module as the merged module"),236cl::cat(LTOCategory));237238static cl::opt<unsigned> Parallelism("j", cl::Prefix, cl::init(1),239cl::desc("Number of backend threads"),240cl::cat(LTOCategory));241242static cl::opt<bool> RestoreGlobalsLinkage(243"restore-linkage", cl::init(false),244cl::desc("Restore original linkage of globals prior to CodeGen"),245cl::cat(LTOCategory));246247static cl::opt<bool> CheckHasObjC(248"check-for-objc", cl::init(false),249cl::desc("Only check if the module has objective-C defined in it"),250cl::cat(LTOCategory));251252static cl::opt<bool> PrintMachOCPUOnly(253"print-macho-cpu-only", cl::init(false),254cl::desc("Instead of running LTO, print the mach-o cpu in each IR file"),255cl::cat(LTOCategory));256257static cl::opt<bool>258DebugPassManager("debug-pass-manager", cl::init(false), cl::Hidden,259cl::desc("Print pass management debugging information"),260cl::cat(LTOCategory));261262static cl::opt<bool>263LTOSaveBeforeOpt("lto-save-before-opt", cl::init(false),264cl::desc("Save the IR before running optimizations"));265266static cl::opt<bool> TryUseNewDbgInfoFormat(267"try-experimental-debuginfo-iterators",268cl::desc("Enable debuginfo iterator positions, if they're built in"),269cl::init(false), cl::Hidden);270271extern cl::opt<bool> UseNewDbgInfoFormat;272extern cl::opt<cl::boolOrDefault> LoadBitcodeIntoNewDbgInfoFormat;273extern cl::opt<cl::boolOrDefault> PreserveInputDbgFormat;274275namespace {276277struct ModuleInfo {278BitVector CanBeHidden;279};280281} // end anonymous namespace282283static void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,284const char *Msg, void *) {285errs() << "llvm-lto: ";286switch (Severity) {287case LTO_DS_NOTE:288errs() << "note: ";289break;290case LTO_DS_REMARK:291errs() << "remark: ";292break;293case LTO_DS_ERROR:294errs() << "error: ";295break;296case LTO_DS_WARNING:297errs() << "warning: ";298break;299}300errs() << Msg << "\n";301}302303static std::string CurrentActivity;304305namespace {306struct LLVMLTODiagnosticHandler : public DiagnosticHandler {307bool handleDiagnostics(const DiagnosticInfo &DI) override {308raw_ostream &OS = errs();309OS << "llvm-lto: ";310switch (DI.getSeverity()) {311case DS_Error:312OS << "error";313break;314case DS_Warning:315OS << "warning";316break;317case DS_Remark:318OS << "remark";319break;320case DS_Note:321OS << "note";322break;323}324if (!CurrentActivity.empty())325OS << ' ' << CurrentActivity;326OS << ": ";327328DiagnosticPrinterRawOStream DP(OS);329DI.print(DP);330OS << '\n';331332if (DI.getSeverity() == DS_Error)333exit(1);334return true;335}336};337}338339static void error(const Twine &Msg) {340errs() << "llvm-lto: " << Msg << '\n';341exit(1);342}343344static void error(std::error_code EC, const Twine &Prefix) {345if (EC)346error(Prefix + ": " + EC.message());347}348349template <typename T>350static void error(const ErrorOr<T> &V, const Twine &Prefix) {351error(V.getError(), Prefix);352}353354static void maybeVerifyModule(const Module &Mod) {355if (!DisableVerify && verifyModule(Mod, &errs()))356error("Broken Module");357}358359static std::unique_ptr<LTOModule>360getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer,361const TargetOptions &Options) {362ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =363MemoryBuffer::getFile(Path);364error(BufferOrErr, "error loading file '" + Path + "'");365Buffer = std::move(BufferOrErr.get());366CurrentActivity = ("loading file '" + Path + "'").str();367std::unique_ptr<LLVMContext> Context = std::make_unique<LLVMContext>();368Context->setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),369true);370ErrorOr<std::unique_ptr<LTOModule>> Ret = LTOModule::createInLocalContext(371std::move(Context), Buffer->getBufferStart(), Buffer->getBufferSize(),372Options, Path);373CurrentActivity = "";374maybeVerifyModule((*Ret)->getModule());375return std::move(*Ret);376}377378/// Print some statistics on the index for each input files.379static void printIndexStats() {380for (auto &Filename : InputFilenames) {381ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");382std::unique_ptr<ModuleSummaryIndex> Index =383ExitOnErr(getModuleSummaryIndexForFile(Filename));384// Skip files without a module summary.385if (!Index)386report_fatal_error(Twine(Filename) + " does not contain an index");387388unsigned Calls = 0, Refs = 0, Functions = 0, Alias = 0, Globals = 0;389for (auto &Summaries : *Index) {390for (auto &Summary : Summaries.second.SummaryList) {391Refs += Summary->refs().size();392if (auto *FuncSummary = dyn_cast<FunctionSummary>(Summary.get())) {393Functions++;394Calls += FuncSummary->calls().size();395} else if (isa<AliasSummary>(Summary.get()))396Alias++;397else398Globals++;399}400}401outs() << "Index " << Filename << " contains "402<< (Alias + Globals + Functions) << " nodes (" << Functions403<< " functions, " << Alias << " alias, " << Globals404<< " globals) and " << (Calls + Refs) << " edges (" << Refs405<< " refs and " << Calls << " calls)\n";406}407}408409/// Load each IR file and dump certain information based on active flags.410///411/// The main point here is to provide lit-testable coverage for the LTOModule412/// functionality that's exposed by the C API. Moreover, this provides testing413/// coverage for modules that have been created in their own contexts.414static void testLTOModule(const TargetOptions &Options) {415for (auto &Filename : InputFilenames) {416std::unique_ptr<MemoryBuffer> Buffer;417std::unique_ptr<LTOModule> Module =418getLocalLTOModule(Filename, Buffer, Options);419420if (ListSymbolsOnly) {421// List the symbols.422outs() << Filename << ":\n";423for (int I = 0, E = Module->getSymbolCount(); I != E; ++I)424outs() << Module->getSymbolName(I) << "\n";425}426if (QueryHasCtorDtor)427outs() << Filename428<< ": hasCtorDtor = " << (Module->hasCtorDtor() ? "true" : "false")429<< "\n";430}431}432433static std::unique_ptr<MemoryBuffer> loadFile(StringRef Filename) {434ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename.str() +435"': ");436return ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Filename)));437}438439static void listDependentLibraries() {440for (auto &Filename : InputFilenames) {441auto Buffer = loadFile(Filename);442std::string E;443std::unique_ptr<lto::InputFile> Input(LTOModule::createInputFile(444Buffer->getBufferStart(), Buffer->getBufferSize(), Filename.c_str(),445E));446if (!Input)447error(E);448449// List the dependent libraries.450outs() << Filename << ":\n";451for (size_t I = 0, C = LTOModule::getDependentLibraryCount(Input.get());452I != C; ++I) {453size_t L = 0;454const char *S = LTOModule::getDependentLibrary(Input.get(), I, &L);455assert(S);456outs() << StringRef(S, L) << "\n";457}458}459}460461static void printMachOCPUOnly() {462LLVMContext Context;463Context.setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),464true);465TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());466for (auto &Filename : InputFilenames) {467ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =468LTOModule::createFromFile(Context, Filename, Options);469if (!ModuleOrErr)470error(ModuleOrErr, "llvm-lto: ");471472Expected<uint32_t> CPUType = (*ModuleOrErr)->getMachOCPUType();473Expected<uint32_t> CPUSubType = (*ModuleOrErr)->getMachOCPUSubType();474if (!CPUType)475error("Error while printing mach-o cputype: " +476toString(CPUType.takeError()));477if (!CPUSubType)478error("Error while printing mach-o cpusubtype: " +479toString(CPUSubType.takeError()));480outs() << llvm::format("%s:\ncputype: %u\ncpusubtype: %u\n",481Filename.c_str(), *CPUType, *CPUSubType);482}483}484485/// Create a combined index file from the input IR files and write it.486///487/// This is meant to enable testing of ThinLTO combined index generation,488/// currently available via the gold plugin via -thinlto.489static void createCombinedModuleSummaryIndex() {490ModuleSummaryIndex CombinedIndex(/*HaveGVs=*/false);491for (auto &Filename : InputFilenames) {492ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");493std::unique_ptr<MemoryBuffer> MB =494ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Filename)));495ExitOnErr(readModuleSummaryIndex(*MB, CombinedIndex));496}497// In order to use this index for testing, specifically import testing, we498// need to update any indirect call edges created from SamplePGO, so that they499// point to the correct GUIDs.500updateIndirectCalls(CombinedIndex);501std::error_code EC;502assert(!OutputFilename.empty());503raw_fd_ostream OS(OutputFilename + ".thinlto.bc", EC,504sys::fs::OpenFlags::OF_None);505error(EC, "error opening the file '" + OutputFilename + ".thinlto.bc'");506writeIndexToFile(CombinedIndex, OS);507OS.close();508}509510/// Parse the thinlto_prefix_replace option into the \p OldPrefix and511/// \p NewPrefix strings, if it was specified.512static void getThinLTOOldAndNewPrefix(std::string &OldPrefix,513std::string &NewPrefix) {514assert(ThinLTOPrefixReplace.empty() ||515ThinLTOPrefixReplace.find(';') != StringRef::npos);516StringRef PrefixReplace = ThinLTOPrefixReplace;517std::pair<StringRef, StringRef> Split = PrefixReplace.split(";");518OldPrefix = Split.first.str();519NewPrefix = Split.second.str();520}521522/// Given the original \p Path to an output file, replace any path523/// prefix matching \p OldPrefix with \p NewPrefix. Also, create the524/// resulting directory if it does not yet exist.525static std::string getThinLTOOutputFile(StringRef Path, StringRef OldPrefix,526StringRef NewPrefix) {527if (OldPrefix.empty() && NewPrefix.empty())528return std::string(Path);529SmallString<128> NewPath(Path);530llvm::sys::path::replace_path_prefix(NewPath, OldPrefix, NewPrefix);531StringRef ParentPath = llvm::sys::path::parent_path(NewPath.str());532if (!ParentPath.empty()) {533// Make sure the new directory exists, creating it if necessary.534if (std::error_code EC = llvm::sys::fs::create_directories(ParentPath))535error(EC, "error creating the directory '" + ParentPath + "'");536}537return std::string(NewPath);538}539540namespace thinlto {541542std::vector<std::unique_ptr<MemoryBuffer>>543loadAllFilesForIndex(const ModuleSummaryIndex &Index) {544std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;545546for (auto &ModPath : Index.modulePaths()) {547const auto &Filename = ModPath.first();548std::string CurrentActivity = ("loading file '" + Filename + "'").str();549auto InputOrErr = MemoryBuffer::getFile(Filename);550error(InputOrErr, "error " + CurrentActivity);551InputBuffers.push_back(std::move(*InputOrErr));552}553return InputBuffers;554}555556std::unique_ptr<ModuleSummaryIndex> loadCombinedIndex() {557if (ThinLTOIndex.empty())558report_fatal_error("Missing -thinlto-index for ThinLTO promotion stage");559ExitOnError ExitOnErr("llvm-lto: error loading file '" + ThinLTOIndex +560"': ");561return ExitOnErr(getModuleSummaryIndexForFile(ThinLTOIndex));562}563564static std::unique_ptr<lto::InputFile> loadInputFile(MemoryBufferRef Buffer) {565ExitOnError ExitOnErr("llvm-lto: error loading input '" +566Buffer.getBufferIdentifier().str() + "': ");567return ExitOnErr(lto::InputFile::create(Buffer));568}569570static std::unique_ptr<Module> loadModuleFromInput(lto::InputFile &File,571LLVMContext &CTX) {572auto &Mod = File.getSingleBitcodeModule();573auto ModuleOrErr = Mod.parseModule(CTX);574if (!ModuleOrErr) {575handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) {576SMDiagnostic Err = SMDiagnostic(Mod.getModuleIdentifier(),577SourceMgr::DK_Error, EIB.message());578Err.print("llvm-lto", errs());579});580report_fatal_error("Can't load module, abort.");581}582maybeVerifyModule(**ModuleOrErr);583if (ThinLTOModuleId.getNumOccurrences()) {584if (InputFilenames.size() != 1)585report_fatal_error("Can't override the module id for multiple files");586(*ModuleOrErr)->setModuleIdentifier(ThinLTOModuleId);587}588return std::move(*ModuleOrErr);589}590591static void writeModuleToFile(Module &TheModule, StringRef Filename) {592std::error_code EC;593raw_fd_ostream OS(Filename, EC, sys::fs::OpenFlags::OF_None);594error(EC, "error opening the file '" + Filename + "'");595maybeVerifyModule(TheModule);596WriteBitcodeToFile(TheModule, OS, /* ShouldPreserveUseListOrder */ true);597}598599class ThinLTOProcessing {600public:601ThinLTOCodeGenerator ThinGenerator;602603ThinLTOProcessing(const TargetOptions &Options) {604ThinGenerator.setCodePICModel(codegen::getExplicitRelocModel());605ThinGenerator.setTargetOptions(Options);606ThinGenerator.setCacheDir(ThinLTOCacheDir);607ThinGenerator.setCachePruningInterval(ThinLTOCachePruningInterval);608ThinGenerator.setCacheEntryExpiration(ThinLTOCacheEntryExpiration);609ThinGenerator.setCacheMaxSizeFiles(ThinLTOCacheMaxSizeFiles);610ThinGenerator.setCacheMaxSizeBytes(ThinLTOCacheMaxSizeBytes);611ThinGenerator.setFreestanding(EnableFreestanding);612ThinGenerator.setDebugPassManager(DebugPassManager);613614// Add all the exported symbols to the table of symbols to preserve.615for (unsigned i = 0; i < ExportedSymbols.size(); ++i)616ThinGenerator.preserveSymbol(ExportedSymbols[i]);617}618619void run() {620switch (ThinLTOMode) {621case THINLINK:622return thinLink();623case THINDISTRIBUTE:624return distributedIndexes();625case THINEMITIMPORTS:626return emitImports();627case THINPROMOTE:628return promote();629case THINIMPORT:630return import();631case THININTERNALIZE:632return internalize();633case THINOPT:634return optimize();635case THINCODEGEN:636return codegen();637case THINALL:638return runAll();639}640}641642private:643/// Load the input files, create the combined index, and write it out.644void thinLink() {645// Perform "ThinLink": just produce the index646if (OutputFilename.empty())647report_fatal_error(648"OutputFilename is necessary to store the combined index.\n");649650LLVMContext Ctx;651std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;652for (unsigned i = 0; i < InputFilenames.size(); ++i) {653auto &Filename = InputFilenames[i];654std::string CurrentActivity = "loading file '" + Filename + "'";655auto InputOrErr = MemoryBuffer::getFile(Filename);656error(InputOrErr, "error " + CurrentActivity);657InputBuffers.push_back(std::move(*InputOrErr));658ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());659}660661auto CombinedIndex = ThinGenerator.linkCombinedIndex();662if (!CombinedIndex)663report_fatal_error("ThinLink didn't create an index");664std::error_code EC;665raw_fd_ostream OS(OutputFilename, EC, sys::fs::OpenFlags::OF_None);666error(EC, "error opening the file '" + OutputFilename + "'");667writeIndexToFile(*CombinedIndex, OS);668}669670/// Load the combined index from disk, then compute and generate671/// individual index files suitable for ThinLTO distributed backend builds672/// on the files mentioned on the command line (these must match the index673/// content).674void distributedIndexes() {675if (InputFilenames.size() != 1 && !OutputFilename.empty())676report_fatal_error("Can't handle a single output filename and multiple "677"input files, do not provide an output filename and "678"the output files will be suffixed from the input "679"ones.");680681std::string OldPrefix, NewPrefix;682getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);683684auto Index = loadCombinedIndex();685for (auto &Filename : InputFilenames) {686LLVMContext Ctx;687auto Buffer = loadFile(Filename);688auto Input = loadInputFile(Buffer->getMemBufferRef());689auto TheModule = loadModuleFromInput(*Input, Ctx);690691// Build a map of module to the GUIDs and summary objects that should692// be written to its index.693std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex;694GVSummaryPtrSet DecSummaries;695ThinGenerator.gatherImportedSummariesForModule(696*TheModule, *Index, ModuleToSummariesForIndex, DecSummaries, *Input);697698std::string OutputName = OutputFilename;699if (OutputName.empty()) {700OutputName = Filename + ".thinlto.bc";701}702OutputName = getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix);703std::error_code EC;704raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);705error(EC, "error opening the file '" + OutputName + "'");706writeIndexToFile(*Index, OS, &ModuleToSummariesForIndex, &DecSummaries);707}708}709710/// Load the combined index from disk, compute the imports, and emit711/// the import file lists for each module to disk.712void emitImports() {713if (InputFilenames.size() != 1 && !OutputFilename.empty())714report_fatal_error("Can't handle a single output filename and multiple "715"input files, do not provide an output filename and "716"the output files will be suffixed from the input "717"ones.");718719std::string OldPrefix, NewPrefix;720getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);721722auto Index = loadCombinedIndex();723for (auto &Filename : InputFilenames) {724LLVMContext Ctx;725auto Buffer = loadFile(Filename);726auto Input = loadInputFile(Buffer->getMemBufferRef());727auto TheModule = loadModuleFromInput(*Input, Ctx);728std::string OutputName = OutputFilename;729if (OutputName.empty()) {730OutputName = Filename + ".imports";731}732OutputName =733getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix);734ThinGenerator.emitImports(*TheModule, OutputName, *Index, *Input);735}736}737738/// Load the combined index from disk, then load every file referenced by739/// the index and add them to the generator, finally perform the promotion740/// on the files mentioned on the command line (these must match the index741/// content).742void promote() {743if (InputFilenames.size() != 1 && !OutputFilename.empty())744report_fatal_error("Can't handle a single output filename and multiple "745"input files, do not provide an output filename and "746"the output files will be suffixed from the input "747"ones.");748749auto Index = loadCombinedIndex();750for (auto &Filename : InputFilenames) {751LLVMContext Ctx;752auto Buffer = loadFile(Filename);753auto Input = loadInputFile(Buffer->getMemBufferRef());754auto TheModule = loadModuleFromInput(*Input, Ctx);755756ThinGenerator.promote(*TheModule, *Index, *Input);757758std::string OutputName = OutputFilename;759if (OutputName.empty()) {760OutputName = Filename + ".thinlto.promoted.bc";761}762writeModuleToFile(*TheModule, OutputName);763}764}765766/// Load the combined index from disk, then load every file referenced by767/// the index and add them to the generator, then performs the promotion and768/// cross module importing on the files mentioned on the command line769/// (these must match the index content).770void import() {771if (InputFilenames.size() != 1 && !OutputFilename.empty())772report_fatal_error("Can't handle a single output filename and multiple "773"input files, do not provide an output filename and "774"the output files will be suffixed from the input "775"ones.");776777auto Index = loadCombinedIndex();778auto InputBuffers = loadAllFilesForIndex(*Index);779for (auto &MemBuffer : InputBuffers)780ThinGenerator.addModule(MemBuffer->getBufferIdentifier(),781MemBuffer->getBuffer());782783for (auto &Filename : InputFilenames) {784LLVMContext Ctx;785auto Buffer = loadFile(Filename);786auto Input = loadInputFile(Buffer->getMemBufferRef());787auto TheModule = loadModuleFromInput(*Input, Ctx);788789ThinGenerator.crossModuleImport(*TheModule, *Index, *Input);790791std::string OutputName = OutputFilename;792if (OutputName.empty()) {793OutputName = Filename + ".thinlto.imported.bc";794}795writeModuleToFile(*TheModule, OutputName);796}797}798799void internalize() {800if (InputFilenames.size() != 1 && !OutputFilename.empty())801report_fatal_error("Can't handle a single output filename and multiple "802"input files, do not provide an output filename and "803"the output files will be suffixed from the input "804"ones.");805806if (ExportedSymbols.empty())807errs() << "Warning: -internalize will not perform without "808"-exported-symbol\n";809810auto Index = loadCombinedIndex();811auto InputBuffers = loadAllFilesForIndex(*Index);812for (auto &MemBuffer : InputBuffers)813ThinGenerator.addModule(MemBuffer->getBufferIdentifier(),814MemBuffer->getBuffer());815816for (auto &Filename : InputFilenames) {817LLVMContext Ctx;818auto Buffer = loadFile(Filename);819auto Input = loadInputFile(Buffer->getMemBufferRef());820auto TheModule = loadModuleFromInput(*Input, Ctx);821822ThinGenerator.internalize(*TheModule, *Index, *Input);823824std::string OutputName = OutputFilename;825if (OutputName.empty()) {826OutputName = Filename + ".thinlto.internalized.bc";827}828writeModuleToFile(*TheModule, OutputName);829}830}831832void optimize() {833if (InputFilenames.size() != 1 && !OutputFilename.empty())834report_fatal_error("Can't handle a single output filename and multiple "835"input files, do not provide an output filename and "836"the output files will be suffixed from the input "837"ones.");838if (!ThinLTOIndex.empty())839errs() << "Warning: -thinlto-index ignored for optimize stage";840841for (auto &Filename : InputFilenames) {842LLVMContext Ctx;843auto Buffer = loadFile(Filename);844auto Input = loadInputFile(Buffer->getMemBufferRef());845auto TheModule = loadModuleFromInput(*Input, Ctx);846847ThinGenerator.optimize(*TheModule);848849std::string OutputName = OutputFilename;850if (OutputName.empty()) {851OutputName = Filename + ".thinlto.imported.bc";852}853writeModuleToFile(*TheModule, OutputName);854}855}856857void codegen() {858if (InputFilenames.size() != 1 && !OutputFilename.empty())859report_fatal_error("Can't handle a single output filename and multiple "860"input files, do not provide an output filename and "861"the output files will be suffixed from the input "862"ones.");863if (!ThinLTOIndex.empty())864errs() << "Warning: -thinlto-index ignored for codegen stage";865866std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;867for (auto &Filename : InputFilenames) {868LLVMContext Ctx;869auto InputOrErr = MemoryBuffer::getFile(Filename);870error(InputOrErr, "error " + CurrentActivity);871InputBuffers.push_back(std::move(*InputOrErr));872ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());873}874ThinGenerator.setCodeGenOnly(true);875ThinGenerator.run();876for (auto BinName :877zip(ThinGenerator.getProducedBinaries(), InputFilenames)) {878std::string OutputName = OutputFilename;879if (OutputName.empty())880OutputName = std::get<1>(BinName) + ".thinlto.o";881else if (OutputName == "-") {882outs() << std::get<0>(BinName)->getBuffer();883return;884}885886std::error_code EC;887raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);888error(EC, "error opening the file '" + OutputName + "'");889OS << std::get<0>(BinName)->getBuffer();890}891}892893/// Full ThinLTO process894void runAll() {895if (!OutputFilename.empty())896report_fatal_error("Do not provide an output filename for ThinLTO "897" processing, the output files will be suffixed from "898"the input ones.");899900if (!ThinLTOIndex.empty())901errs() << "Warning: -thinlto-index ignored for full ThinLTO process";902903LLVMContext Ctx;904std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;905for (unsigned i = 0; i < InputFilenames.size(); ++i) {906auto &Filename = InputFilenames[i];907std::string CurrentActivity = "loading file '" + Filename + "'";908auto InputOrErr = MemoryBuffer::getFile(Filename);909error(InputOrErr, "error " + CurrentActivity);910InputBuffers.push_back(std::move(*InputOrErr));911ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());912}913914if (!ThinLTOSaveTempsPrefix.empty())915ThinGenerator.setSaveTempsDir(ThinLTOSaveTempsPrefix);916917if (!ThinLTOGeneratedObjectsDir.empty()) {918ThinGenerator.setGeneratedObjectsDirectory(ThinLTOGeneratedObjectsDir);919ThinGenerator.run();920return;921}922923ThinGenerator.run();924925auto &Binaries = ThinGenerator.getProducedBinaries();926if (Binaries.size() != InputFilenames.size())927report_fatal_error("Number of output objects does not match the number "928"of inputs");929930for (unsigned BufID = 0; BufID < Binaries.size(); ++BufID) {931auto OutputName = InputFilenames[BufID] + ".thinlto.o";932std::error_code EC;933raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);934error(EC, "error opening the file '" + OutputName + "'");935OS << Binaries[BufID]->getBuffer();936}937}938939/// Load the combined index from disk, then load every file referenced by940};941942} // end namespace thinlto943944int main(int argc, char **argv) {945InitLLVM X(argc, argv);946cl::HideUnrelatedOptions({<OCategory, &getColorCategory()});947cl::ParseCommandLineOptions(argc, argv, "llvm LTO linker\n");948// Load bitcode into the new debug info format by default.949if (LoadBitcodeIntoNewDbgInfoFormat == cl::boolOrDefault::BOU_UNSET)950LoadBitcodeIntoNewDbgInfoFormat = cl::boolOrDefault::BOU_TRUE;951952// RemoveDIs debug-info transition: tests may request that we /try/ to use the953// new debug-info format.954if (TryUseNewDbgInfoFormat) {955// Turn the new debug-info format on.956UseNewDbgInfoFormat = true;957}958// Since llvm-lto collects multiple IR modules together, for simplicity's sake959// we disable the "PreserveInputDbgFormat" flag to enforce a single debug info960// format.961PreserveInputDbgFormat = cl::boolOrDefault::BOU_FALSE;962963if (OptLevel < '0' || OptLevel > '3')964error("optimization level must be between 0 and 3");965966// Initialize the configured targets.967InitializeAllTargets();968InitializeAllTargetMCs();969InitializeAllAsmPrinters();970InitializeAllAsmParsers();971972// set up the TargetOptions for the machine973TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());974975if (ListSymbolsOnly || QueryHasCtorDtor) {976testLTOModule(Options);977return 0;978}979980if (ListDependentLibrariesOnly) {981listDependentLibraries();982return 0;983}984985if (IndexStats) {986printIndexStats();987return 0;988}989990if (CheckHasObjC) {991for (auto &Filename : InputFilenames) {992ExitOnError ExitOnErr(std::string(*argv) + ": error loading file '" +993Filename + "': ");994std::unique_ptr<MemoryBuffer> BufferOrErr =995ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(Filename)));996auto Buffer = std::move(BufferOrErr.get());997if (ExitOnErr(isBitcodeContainingObjCCategory(*Buffer)))998outs() << "Bitcode " << Filename << " contains ObjC\n";999else1000outs() << "Bitcode " << Filename << " does not contain ObjC\n";1001}1002return 0;1003}10041005if (PrintMachOCPUOnly) {1006printMachOCPUOnly();1007return 0;1008}10091010if (ThinLTOMode.getNumOccurrences()) {1011if (ThinLTOMode.getNumOccurrences() > 1)1012report_fatal_error("You can't specify more than one -thinlto-action");1013thinlto::ThinLTOProcessing ThinLTOProcessor(Options);1014ThinLTOProcessor.run();1015return 0;1016}10171018if (ThinLTO) {1019createCombinedModuleSummaryIndex();1020return 0;1021}10221023unsigned BaseArg = 0;10241025LLVMContext Context;1026Context.setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),1027true);10281029LTOCodeGenerator CodeGen(Context);1030CodeGen.setDisableVerify(DisableVerify);10311032if (UseDiagnosticHandler)1033CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr);10341035CodeGen.setCodePICModel(codegen::getExplicitRelocModel());1036CodeGen.setFreestanding(EnableFreestanding);1037CodeGen.setDebugPassManager(DebugPassManager);10381039CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF);1040CodeGen.setTargetOptions(Options);1041CodeGen.setShouldRestoreGlobalsLinkage(RestoreGlobalsLinkage);10421043StringSet<MallocAllocator> DSOSymbolsSet;1044for (unsigned i = 0; i < DSOSymbols.size(); ++i)1045DSOSymbolsSet.insert(DSOSymbols[i]);10461047std::vector<std::string> KeptDSOSyms;10481049for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) {1050CurrentActivity = "loading file '" + InputFilenames[i] + "'";1051ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =1052LTOModule::createFromFile(Context, InputFilenames[i], Options);1053std::unique_ptr<LTOModule> &Module = *ModuleOrErr;1054CurrentActivity = "";10551056unsigned NumSyms = Module->getSymbolCount();1057for (unsigned I = 0; I < NumSyms; ++I) {1058StringRef Name = Module->getSymbolName(I);1059if (!DSOSymbolsSet.count(Name))1060continue;1061lto_symbol_attributes Attrs = Module->getSymbolAttributes(I);1062unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK;1063if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN)1064KeptDSOSyms.push_back(std::string(Name));1065}10661067// We use the first input module as the destination module when1068// SetMergedModule is true.1069if (SetMergedModule && i == BaseArg) {1070// Transfer ownership to the code generator.1071CodeGen.setModule(std::move(Module));1072} else if (!CodeGen.addModule(Module.get())) {1073// Print a message here so that we know addModule() did not abort.1074error("error adding file '" + InputFilenames[i] + "'");1075}1076}10771078// Add all the exported symbols to the table of symbols to preserve.1079for (unsigned i = 0; i < ExportedSymbols.size(); ++i)1080CodeGen.addMustPreserveSymbol(ExportedSymbols[i]);10811082// Add all the dso symbols to the table of symbols to expose.1083for (unsigned i = 0; i < KeptDSOSyms.size(); ++i)1084CodeGen.addMustPreserveSymbol(KeptDSOSyms[i]);10851086// Set cpu and attrs strings for the default target/subtarget.1087CodeGen.setCpu(codegen::getMCPU());10881089CodeGen.setOptLevel(OptLevel - '0');1090CodeGen.setAttrs(codegen::getMAttrs());10911092if (auto FT = codegen::getExplicitFileType())1093CodeGen.setFileType(*FT);10941095if (!OutputFilename.empty()) {1096if (LTOSaveBeforeOpt)1097CodeGen.setSaveIRBeforeOptPath(OutputFilename + ".0.preopt.bc");10981099if (SaveLinkedModuleFile) {1100std::string ModuleFilename = OutputFilename;1101ModuleFilename += ".linked.bc";1102std::string ErrMsg;11031104if (!CodeGen.writeMergedModules(ModuleFilename))1105error("writing linked module failed.");1106}11071108if (!CodeGen.optimize()) {1109// Diagnostic messages should have been printed by the handler.1110error("error optimizing the code");1111}11121113if (SaveModuleFile) {1114std::string ModuleFilename = OutputFilename;1115ModuleFilename += ".merged.bc";1116std::string ErrMsg;11171118if (!CodeGen.writeMergedModules(ModuleFilename))1119error("writing merged module failed.");1120}11211122auto AddStream =1123[&](size_t Task,1124const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {1125std::string PartFilename = OutputFilename;1126if (Parallelism != 1)1127PartFilename += "." + utostr(Task);11281129std::error_code EC;1130auto S =1131std::make_unique<raw_fd_ostream>(PartFilename, EC, sys::fs::OF_None);1132if (EC)1133error("error opening the file '" + PartFilename + "': " + EC.message());1134return std::make_unique<CachedFileStream>(std::move(S));1135};11361137if (!CodeGen.compileOptimized(AddStream, Parallelism))1138// Diagnostic messages should have been printed by the handler.1139error("error compiling the code");11401141} else {1142if (Parallelism != 1)1143error("-j must be specified together with -o");11441145if (SaveModuleFile)1146error(": -save-merged-module must be specified with -o");11471148const char *OutputName = nullptr;1149if (!CodeGen.compile_to_file(&OutputName))1150error("error compiling the code");1151// Diagnostic messages should have been printed by the handler.11521153outs() << "Wrote native object file '" << OutputName << "'\n";1154}11551156return 0;1157}115811591160