12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079 |
- //===- 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/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::opt<char>
- OptLevel("O", cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
- "(default = '-O2')"),
- cl::Prefix, cl::ZeroOrMore, cl::init('2'));
- static cl::opt<bool>
- IndexStats("thinlto-index-stats",
- cl::desc("Print statistic for the index in every input files"),
- cl::init(false));
- static cl::opt<bool> DisableVerify(
- "disable-verify", cl::init(false),
- cl::desc("Do not run the verifier during the optimization pipeline"));
- static cl::opt<bool> EnableFreestanding(
- "lto-freestanding", cl::init(false),
- cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"));
- static cl::opt<bool> UseDiagnosticHandler(
- "use-diagnostic-handler", cl::init(false),
- cl::desc("Use a diagnostic handler to test the handler interface"));
- static cl::opt<bool>
- ThinLTO("thinlto", cl::init(false),
- cl::desc("Only write combined global index for ThinLTO backends"));
- 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")));
- 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."));
- 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."));
- 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."));
- static cl::opt<std::string>
- ThinLTOCacheDir("thinlto-cache-dir", cl::desc("Enable ThinLTO caching."));
- static cl::opt<int>
- ThinLTOCachePruningInterval("thinlto-cache-pruning-interval",
- cl::init(1200), cl::desc("Set ThinLTO cache pruning interval."));
- static cl::opt<uint64_t> ThinLTOCacheMaxSizeBytes(
- "thinlto-cache-max-size-bytes",
- cl::desc("Set ThinLTO cache pruning directory maximum size in bytes."));
- static cl::opt<int>
- ThinLTOCacheMaxSizeFiles("thinlto-cache-max-size-files", cl::init(1000000),
- cl::desc("Set ThinLTO cache pruning directory maximum number of files."));
- static cl::opt<unsigned>
- ThinLTOCacheEntryExpiration("thinlto-cache-entry-expiration", cl::init(604800) /* 1w */,
- cl::desc("Set ThinLTO cache entry expiration time."));
- 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."));
- static cl::opt<std::string> ThinLTOGeneratedObjectsDir(
- "thinlto-save-objects",
- cl::desc("Save ThinLTO generated object files using filenames created in "
- "the given directory."));
- static cl::opt<bool> SaveLinkedModuleFile(
- "save-linked-module", cl::init(false),
- cl::desc("Write linked LTO module to file before optimize"));
- static cl::opt<bool>
- SaveModuleFile("save-merged-module", cl::init(false),
- cl::desc("Write merged LTO module to file before CodeGen"));
- static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
- cl::desc("<input bitcode files>"));
- static cl::opt<std::string> OutputFilename("o", cl::init(""),
- cl::desc("Override output filename"),
- cl::value_desc("filename"));
- static cl::list<std::string> ExportedSymbols(
- "exported-symbol",
- cl::desc("List of symbols to export from the resulting object file"),
- cl::ZeroOrMore);
- static cl::list<std::string>
- DSOSymbols("dso-symbol",
- cl::desc("Symbol to put in the symtab in the resulting dso"),
- cl::ZeroOrMore);
- static cl::opt<bool> ListSymbolsOnly(
- "list-symbols-only", cl::init(false),
- cl::desc("Instead of running LTO, list the symbols in each IR file"));
- 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"));
- static cl::opt<bool> SetMergedModule(
- "set-merged-module", cl::init(false),
- cl::desc("Use the first input module as the merged module"));
- static cl::opt<unsigned> Parallelism("j", cl::Prefix, cl::init(1),
- cl::desc("Number of backend threads"));
- static cl::opt<bool> RestoreGlobalsLinkage(
- "restore-linkage", cl::init(false),
- cl::desc("Restore original linkage of globals prior to CodeGen"));
- static cl::opt<bool> CheckHasObjC(
- "check-for-objc", cl::init(false),
- cl::desc("Only check if the module has objective-C defined in it"));
- 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"));
- namespace {
- struct ModuleInfo {
- std::vector<bool> 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(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";
- }
- }
- /// List symbols in each IR file.
- ///
- /// The main point here is to provide lit-testable coverage for the LTOModule
- /// functionality that's exposed by the C API to list symbols. Moreover, this
- /// provides testing coverage for modules that have been created in their own
- /// contexts.
- static void listSymbols(const TargetOptions &Options) {
- for (auto &Filename : InputFilenames) {
- std::unique_ptr<MemoryBuffer> Buffer;
- std::unique_ptr<LTOModule> Module =
- getLocalLTOModule(Filename, Buffer, Options);
- // List the symbols.
- outs() << Filename << ":\n";
- for (int I = 0, E = Module->getSymbolCount(); I != E; ++I)
- outs() << Module->getSymbolName(I) << "\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++));
- }
- 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);
- // 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::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) {
- listSymbols(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().c_str());
- CodeGen.setOptLevel(OptLevel - '0');
- CodeGen.setAttrs(codegen::getMAttrs());
- 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.");
- }
- std::list<ToolOutputFile> OSs;
- std::vector<raw_pwrite_stream *> OSPtrs;
- for (unsigned I = 0; I != Parallelism; ++I) {
- std::string PartFilename = OutputFilename;
- if (Parallelism != 1)
- PartFilename += "." + utostr(I);
- std::error_code EC;
- OSs.emplace_back(PartFilename, EC, sys::fs::OF_None);
- if (EC)
- error("error opening the file '" + PartFilename + "': " + EC.message());
- OSPtrs.push_back(&OSs.back().os());
- }
- if (!CodeGen.compileOptimized(OSPtrs))
- // Diagnostic messages should have been printed by the handler.
- error("error compiling the code");
- for (ToolOutputFile &OS : OSs)
- OS.keep();
- } 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;
- }
|