109467b48Spatrick //===- llvm-lto: a simple command-line program to link modules with LTO ---===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This program takes in a list of bitcode files, links them, performs link-time
1009467b48Spatrick // optimization, and outputs an object file.
1109467b48Spatrick //
1209467b48Spatrick //===----------------------------------------------------------------------===//
1309467b48Spatrick
1409467b48Spatrick #include "llvm-c/lto.h"
1509467b48Spatrick #include "llvm/ADT/ArrayRef.h"
1609467b48Spatrick #include "llvm/ADT/STLExtras.h"
1709467b48Spatrick #include "llvm/ADT/SmallString.h"
1809467b48Spatrick #include "llvm/ADT/StringExtras.h"
1909467b48Spatrick #include "llvm/ADT/StringRef.h"
2009467b48Spatrick #include "llvm/ADT/StringSet.h"
2109467b48Spatrick #include "llvm/ADT/Twine.h"
2209467b48Spatrick #include "llvm/Bitcode/BitcodeReader.h"
2309467b48Spatrick #include "llvm/Bitcode/BitcodeWriter.h"
24097a140dSpatrick #include "llvm/CodeGen/CommandFlags.h"
2509467b48Spatrick #include "llvm/IR/DiagnosticInfo.h"
2609467b48Spatrick #include "llvm/IR/DiagnosticPrinter.h"
2709467b48Spatrick #include "llvm/IR/LLVMContext.h"
2809467b48Spatrick #include "llvm/IR/Module.h"
2909467b48Spatrick #include "llvm/IR/ModuleSummaryIndex.h"
3009467b48Spatrick #include "llvm/IR/Verifier.h"
3109467b48Spatrick #include "llvm/IRReader/IRReader.h"
3209467b48Spatrick #include "llvm/LTO/legacy/LTOCodeGenerator.h"
3309467b48Spatrick #include "llvm/LTO/legacy/LTOModule.h"
3409467b48Spatrick #include "llvm/LTO/legacy/ThinLTOCodeGenerator.h"
3509467b48Spatrick #include "llvm/Support/Allocator.h"
3609467b48Spatrick #include "llvm/Support/Casting.h"
3709467b48Spatrick #include "llvm/Support/CommandLine.h"
3809467b48Spatrick #include "llvm/Support/Error.h"
3909467b48Spatrick #include "llvm/Support/ErrorHandling.h"
4009467b48Spatrick #include "llvm/Support/ErrorOr.h"
4109467b48Spatrick #include "llvm/Support/FileSystem.h"
4209467b48Spatrick #include "llvm/Support/InitLLVM.h"
4309467b48Spatrick #include "llvm/Support/MemoryBuffer.h"
4409467b48Spatrick #include "llvm/Support/Path.h"
4509467b48Spatrick #include "llvm/Support/SourceMgr.h"
4609467b48Spatrick #include "llvm/Support/TargetSelect.h"
4709467b48Spatrick #include "llvm/Support/ToolOutputFile.h"
4809467b48Spatrick #include "llvm/Support/raw_ostream.h"
49*d415bd75Srobert #include "llvm/Support/WithColor.h"
5009467b48Spatrick #include "llvm/Target/TargetOptions.h"
5109467b48Spatrick #include <algorithm>
5209467b48Spatrick #include <cassert>
5309467b48Spatrick #include <cstdint>
5409467b48Spatrick #include <cstdlib>
5509467b48Spatrick #include <list>
5609467b48Spatrick #include <map>
5709467b48Spatrick #include <memory>
5809467b48Spatrick #include <string>
5909467b48Spatrick #include <system_error>
6009467b48Spatrick #include <tuple>
6109467b48Spatrick #include <utility>
6209467b48Spatrick #include <vector>
6309467b48Spatrick
6409467b48Spatrick using namespace llvm;
6509467b48Spatrick
66097a140dSpatrick static codegen::RegisterCodeGenFlags CGF;
67097a140dSpatrick
6873471bf0Spatrick static cl::OptionCategory LTOCategory("LTO Options");
6973471bf0Spatrick
7009467b48Spatrick static cl::opt<char>
7173471bf0Spatrick OptLevel("O",
7273471bf0Spatrick cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
7309467b48Spatrick "(default = '-O2')"),
74*d415bd75Srobert cl::Prefix, cl::init('2'), cl::cat(LTOCategory));
7509467b48Spatrick
7609467b48Spatrick static cl::opt<bool>
7709467b48Spatrick IndexStats("thinlto-index-stats",
7809467b48Spatrick cl::desc("Print statistic for the index in every input files"),
7973471bf0Spatrick cl::init(false), cl::cat(LTOCategory));
8009467b48Spatrick
8109467b48Spatrick static cl::opt<bool> DisableVerify(
8209467b48Spatrick "disable-verify", cl::init(false),
8373471bf0Spatrick cl::desc("Do not run the verifier during the optimization pipeline"),
8473471bf0Spatrick cl::cat(LTOCategory));
8509467b48Spatrick
8609467b48Spatrick static cl::opt<bool> EnableFreestanding(
8709467b48Spatrick "lto-freestanding", cl::init(false),
8873471bf0Spatrick cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"),
8973471bf0Spatrick cl::cat(LTOCategory));
9009467b48Spatrick
9109467b48Spatrick static cl::opt<bool> UseDiagnosticHandler(
9209467b48Spatrick "use-diagnostic-handler", cl::init(false),
9373471bf0Spatrick cl::desc("Use a diagnostic handler to test the handler interface"),
9473471bf0Spatrick cl::cat(LTOCategory));
9509467b48Spatrick
9609467b48Spatrick static cl::opt<bool>
9709467b48Spatrick ThinLTO("thinlto", cl::init(false),
9873471bf0Spatrick cl::desc("Only write combined global index for ThinLTO backends"),
9973471bf0Spatrick cl::cat(LTOCategory));
10009467b48Spatrick
10109467b48Spatrick enum ThinLTOModes {
10209467b48Spatrick THINLINK,
10309467b48Spatrick THINDISTRIBUTE,
10409467b48Spatrick THINEMITIMPORTS,
10509467b48Spatrick THINPROMOTE,
10609467b48Spatrick THINIMPORT,
10709467b48Spatrick THININTERNALIZE,
10809467b48Spatrick THINOPT,
10909467b48Spatrick THINCODEGEN,
11009467b48Spatrick THINALL
11109467b48Spatrick };
11209467b48Spatrick
11309467b48Spatrick cl::opt<ThinLTOModes> ThinLTOMode(
11409467b48Spatrick "thinlto-action", cl::desc("Perform a single ThinLTO stage:"),
11509467b48Spatrick cl::values(
11609467b48Spatrick clEnumValN(
11709467b48Spatrick THINLINK, "thinlink",
11809467b48Spatrick "ThinLink: produces the index by linking only the summaries."),
11909467b48Spatrick clEnumValN(THINDISTRIBUTE, "distributedindexes",
12009467b48Spatrick "Produces individual indexes for distributed backends."),
12109467b48Spatrick clEnumValN(THINEMITIMPORTS, "emitimports",
12209467b48Spatrick "Emit imports files for distributed backends."),
12309467b48Spatrick clEnumValN(THINPROMOTE, "promote",
12409467b48Spatrick "Perform pre-import promotion (requires -thinlto-index)."),
12573471bf0Spatrick clEnumValN(THINIMPORT, "import",
12673471bf0Spatrick "Perform both promotion and "
12709467b48Spatrick "cross-module importing (requires "
12809467b48Spatrick "-thinlto-index)."),
12909467b48Spatrick clEnumValN(THININTERNALIZE, "internalize",
13009467b48Spatrick "Perform internalization driven by -exported-symbol "
13109467b48Spatrick "(requires -thinlto-index)."),
13209467b48Spatrick clEnumValN(THINOPT, "optimize", "Perform ThinLTO optimizations."),
13309467b48Spatrick clEnumValN(THINCODEGEN, "codegen", "CodeGen (expected to match llc)"),
13473471bf0Spatrick clEnumValN(THINALL, "run", "Perform ThinLTO end-to-end")),
13573471bf0Spatrick cl::cat(LTOCategory));
13609467b48Spatrick
13709467b48Spatrick static cl::opt<std::string>
13809467b48Spatrick ThinLTOIndex("thinlto-index",
13909467b48Spatrick cl::desc("Provide the index produced by a ThinLink, required "
14073471bf0Spatrick "to perform the promotion and/or importing."),
14173471bf0Spatrick cl::cat(LTOCategory));
14209467b48Spatrick
14309467b48Spatrick static cl::opt<std::string> ThinLTOPrefixReplace(
14409467b48Spatrick "thinlto-prefix-replace",
14509467b48Spatrick cl::desc("Control where files for distributed backends are "
14609467b48Spatrick "created. Expects 'oldprefix;newprefix' and if path "
14709467b48Spatrick "prefix of output file is oldprefix it will be "
14873471bf0Spatrick "replaced with newprefix."),
14973471bf0Spatrick cl::cat(LTOCategory));
15009467b48Spatrick
15109467b48Spatrick static cl::opt<std::string> ThinLTOModuleId(
15209467b48Spatrick "thinlto-module-id",
15309467b48Spatrick cl::desc("For the module ID for the file to process, useful to "
15473471bf0Spatrick "match what is in the index."),
15573471bf0Spatrick cl::cat(LTOCategory));
15609467b48Spatrick
15773471bf0Spatrick static cl::opt<std::string> ThinLTOCacheDir("thinlto-cache-dir",
15873471bf0Spatrick cl::desc("Enable ThinLTO caching."),
15973471bf0Spatrick cl::cat(LTOCategory));
16009467b48Spatrick
16173471bf0Spatrick static cl::opt<int> ThinLTOCachePruningInterval(
16273471bf0Spatrick "thinlto-cache-pruning-interval", cl::init(1200),
16373471bf0Spatrick cl::desc("Set ThinLTO cache pruning interval."), cl::cat(LTOCategory));
16409467b48Spatrick
16509467b48Spatrick static cl::opt<uint64_t> ThinLTOCacheMaxSizeBytes(
16609467b48Spatrick "thinlto-cache-max-size-bytes",
16773471bf0Spatrick cl::desc("Set ThinLTO cache pruning directory maximum size in bytes."),
16873471bf0Spatrick cl::cat(LTOCategory));
16909467b48Spatrick
17073471bf0Spatrick static cl::opt<int> ThinLTOCacheMaxSizeFiles(
17173471bf0Spatrick "thinlto-cache-max-size-files", cl::init(1000000),
17273471bf0Spatrick cl::desc("Set ThinLTO cache pruning directory maximum number of files."),
17373471bf0Spatrick cl::cat(LTOCategory));
17409467b48Spatrick
17573471bf0Spatrick static cl::opt<unsigned> ThinLTOCacheEntryExpiration(
17673471bf0Spatrick "thinlto-cache-entry-expiration", cl::init(604800) /* 1w */,
17773471bf0Spatrick cl::desc("Set ThinLTO cache entry expiration time."), cl::cat(LTOCategory));
17809467b48Spatrick
17909467b48Spatrick static cl::opt<std::string> ThinLTOSaveTempsPrefix(
18009467b48Spatrick "thinlto-save-temps",
18109467b48Spatrick cl::desc("Save ThinLTO temp files using filenames created by adding "
18273471bf0Spatrick "suffixes to the given file path prefix."),
18373471bf0Spatrick cl::cat(LTOCategory));
18409467b48Spatrick
18509467b48Spatrick static cl::opt<std::string> ThinLTOGeneratedObjectsDir(
18609467b48Spatrick "thinlto-save-objects",
18709467b48Spatrick cl::desc("Save ThinLTO generated object files using filenames created in "
18873471bf0Spatrick "the given directory."),
18973471bf0Spatrick cl::cat(LTOCategory));
19073471bf0Spatrick
19173471bf0Spatrick static cl::opt<bool> SaveLinkedModuleFile(
19273471bf0Spatrick "save-linked-module", cl::init(false),
19373471bf0Spatrick cl::desc("Write linked LTO module to file before optimize"),
19473471bf0Spatrick cl::cat(LTOCategory));
19509467b48Spatrick
19609467b48Spatrick static cl::opt<bool>
19709467b48Spatrick SaveModuleFile("save-merged-module", cl::init(false),
19873471bf0Spatrick cl::desc("Write merged LTO module to file before CodeGen"),
19973471bf0Spatrick cl::cat(LTOCategory));
20009467b48Spatrick
20109467b48Spatrick static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
20273471bf0Spatrick cl::desc("<input bitcode files>"),
20373471bf0Spatrick cl::cat(LTOCategory));
20409467b48Spatrick
20509467b48Spatrick static cl::opt<std::string> OutputFilename("o", cl::init(""),
20609467b48Spatrick cl::desc("Override output filename"),
20773471bf0Spatrick cl::value_desc("filename"),
20873471bf0Spatrick cl::cat(LTOCategory));
20909467b48Spatrick
21009467b48Spatrick static cl::list<std::string> ExportedSymbols(
21109467b48Spatrick "exported-symbol",
21209467b48Spatrick cl::desc("List of symbols to export from the resulting object file"),
213*d415bd75Srobert cl::cat(LTOCategory));
21409467b48Spatrick
21509467b48Spatrick static cl::list<std::string>
21609467b48Spatrick DSOSymbols("dso-symbol",
21709467b48Spatrick cl::desc("Symbol to put in the symtab in the resulting dso"),
218*d415bd75Srobert cl::cat(LTOCategory));
21909467b48Spatrick
22009467b48Spatrick static cl::opt<bool> ListSymbolsOnly(
22109467b48Spatrick "list-symbols-only", cl::init(false),
22273471bf0Spatrick cl::desc("Instead of running LTO, list the symbols in each IR file"),
22373471bf0Spatrick cl::cat(LTOCategory));
22409467b48Spatrick
22509467b48Spatrick static cl::opt<bool> ListDependentLibrariesOnly(
22609467b48Spatrick "list-dependent-libraries-only", cl::init(false),
22773471bf0Spatrick cl::desc(
22873471bf0Spatrick "Instead of running LTO, list the dependent libraries in each IR file"),
22973471bf0Spatrick cl::cat(LTOCategory));
23009467b48Spatrick
231*d415bd75Srobert static cl::opt<bool> QueryHasCtorDtor(
232*d415bd75Srobert "query-hasCtorDtor", cl::init(false),
233*d415bd75Srobert cl::desc("Queries LTOModule::hasCtorDtor() on each IR file"));
234*d415bd75Srobert
23573471bf0Spatrick static cl::opt<bool>
23673471bf0Spatrick SetMergedModule("set-merged-module", cl::init(false),
23773471bf0Spatrick cl::desc("Use the first input module as the merged module"),
23873471bf0Spatrick cl::cat(LTOCategory));
23909467b48Spatrick
24009467b48Spatrick static cl::opt<unsigned> Parallelism("j", cl::Prefix, cl::init(1),
24173471bf0Spatrick cl::desc("Number of backend threads"),
24273471bf0Spatrick cl::cat(LTOCategory));
24309467b48Spatrick
24409467b48Spatrick static cl::opt<bool> RestoreGlobalsLinkage(
24509467b48Spatrick "restore-linkage", cl::init(false),
24673471bf0Spatrick cl::desc("Restore original linkage of globals prior to CodeGen"),
24773471bf0Spatrick cl::cat(LTOCategory));
24809467b48Spatrick
24909467b48Spatrick static cl::opt<bool> CheckHasObjC(
25009467b48Spatrick "check-for-objc", cl::init(false),
25173471bf0Spatrick cl::desc("Only check if the module has objective-C defined in it"),
25273471bf0Spatrick cl::cat(LTOCategory));
25309467b48Spatrick
254097a140dSpatrick static cl::opt<bool> PrintMachOCPUOnly(
255097a140dSpatrick "print-macho-cpu-only", cl::init(false),
25673471bf0Spatrick cl::desc("Instead of running LTO, print the mach-o cpu in each IR file"),
25773471bf0Spatrick cl::cat(LTOCategory));
25873471bf0Spatrick
25973471bf0Spatrick static cl::opt<bool>
26073471bf0Spatrick DebugPassManager("debug-pass-manager", cl::init(false), cl::Hidden,
26173471bf0Spatrick cl::desc("Print pass management debugging information"),
26273471bf0Spatrick cl::cat(LTOCategory));
263097a140dSpatrick
264*d415bd75Srobert static cl::opt<bool>
265*d415bd75Srobert LTOSaveBeforeOpt("lto-save-before-opt", cl::init(false),
266*d415bd75Srobert cl::desc("Save the IR before running optimizations"));
267*d415bd75Srobert
26809467b48Spatrick namespace {
26909467b48Spatrick
27009467b48Spatrick struct ModuleInfo {
271*d415bd75Srobert BitVector CanBeHidden;
27209467b48Spatrick };
27309467b48Spatrick
27409467b48Spatrick } // end anonymous namespace
27509467b48Spatrick
handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,const char * Msg,void *)27609467b48Spatrick static void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,
27709467b48Spatrick const char *Msg, void *) {
27809467b48Spatrick errs() << "llvm-lto: ";
27909467b48Spatrick switch (Severity) {
28009467b48Spatrick case LTO_DS_NOTE:
28109467b48Spatrick errs() << "note: ";
28209467b48Spatrick break;
28309467b48Spatrick case LTO_DS_REMARK:
28409467b48Spatrick errs() << "remark: ";
28509467b48Spatrick break;
28609467b48Spatrick case LTO_DS_ERROR:
28709467b48Spatrick errs() << "error: ";
28809467b48Spatrick break;
28909467b48Spatrick case LTO_DS_WARNING:
29009467b48Spatrick errs() << "warning: ";
29109467b48Spatrick break;
29209467b48Spatrick }
29309467b48Spatrick errs() << Msg << "\n";
29409467b48Spatrick }
29509467b48Spatrick
29609467b48Spatrick static std::string CurrentActivity;
29709467b48Spatrick
29809467b48Spatrick namespace {
29909467b48Spatrick struct LLVMLTODiagnosticHandler : public DiagnosticHandler {
handleDiagnostics__anon0c592d740211::LLVMLTODiagnosticHandler30009467b48Spatrick bool handleDiagnostics(const DiagnosticInfo &DI) override {
30109467b48Spatrick raw_ostream &OS = errs();
30209467b48Spatrick OS << "llvm-lto: ";
30309467b48Spatrick switch (DI.getSeverity()) {
30409467b48Spatrick case DS_Error:
30509467b48Spatrick OS << "error";
30609467b48Spatrick break;
30709467b48Spatrick case DS_Warning:
30809467b48Spatrick OS << "warning";
30909467b48Spatrick break;
31009467b48Spatrick case DS_Remark:
31109467b48Spatrick OS << "remark";
31209467b48Spatrick break;
31309467b48Spatrick case DS_Note:
31409467b48Spatrick OS << "note";
31509467b48Spatrick break;
31609467b48Spatrick }
31709467b48Spatrick if (!CurrentActivity.empty())
31809467b48Spatrick OS << ' ' << CurrentActivity;
31909467b48Spatrick OS << ": ";
32009467b48Spatrick
32109467b48Spatrick DiagnosticPrinterRawOStream DP(OS);
32209467b48Spatrick DI.print(DP);
32309467b48Spatrick OS << '\n';
32409467b48Spatrick
32509467b48Spatrick if (DI.getSeverity() == DS_Error)
32609467b48Spatrick exit(1);
32709467b48Spatrick return true;
32809467b48Spatrick }
32909467b48Spatrick };
33009467b48Spatrick }
33109467b48Spatrick
error(const Twine & Msg)33209467b48Spatrick static void error(const Twine &Msg) {
33309467b48Spatrick errs() << "llvm-lto: " << Msg << '\n';
33409467b48Spatrick exit(1);
33509467b48Spatrick }
33609467b48Spatrick
error(std::error_code EC,const Twine & Prefix)33709467b48Spatrick static void error(std::error_code EC, const Twine &Prefix) {
33809467b48Spatrick if (EC)
33909467b48Spatrick error(Prefix + ": " + EC.message());
34009467b48Spatrick }
34109467b48Spatrick
34209467b48Spatrick template <typename T>
error(const ErrorOr<T> & V,const Twine & Prefix)34309467b48Spatrick static void error(const ErrorOr<T> &V, const Twine &Prefix) {
34409467b48Spatrick error(V.getError(), Prefix);
34509467b48Spatrick }
34609467b48Spatrick
maybeVerifyModule(const Module & Mod)34709467b48Spatrick static void maybeVerifyModule(const Module &Mod) {
34809467b48Spatrick if (!DisableVerify && verifyModule(Mod, &errs()))
34909467b48Spatrick error("Broken Module");
35009467b48Spatrick }
35109467b48Spatrick
35209467b48Spatrick static std::unique_ptr<LTOModule>
getLocalLTOModule(StringRef Path,std::unique_ptr<MemoryBuffer> & Buffer,const TargetOptions & Options)35309467b48Spatrick getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer,
35409467b48Spatrick const TargetOptions &Options) {
35509467b48Spatrick ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
35609467b48Spatrick MemoryBuffer::getFile(Path);
35709467b48Spatrick error(BufferOrErr, "error loading file '" + Path + "'");
35809467b48Spatrick Buffer = std::move(BufferOrErr.get());
35909467b48Spatrick CurrentActivity = ("loading file '" + Path + "'").str();
36009467b48Spatrick std::unique_ptr<LLVMContext> Context = std::make_unique<LLVMContext>();
36109467b48Spatrick Context->setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),
36209467b48Spatrick true);
36309467b48Spatrick ErrorOr<std::unique_ptr<LTOModule>> Ret = LTOModule::createInLocalContext(
36409467b48Spatrick std::move(Context), Buffer->getBufferStart(), Buffer->getBufferSize(),
36509467b48Spatrick Options, Path);
36609467b48Spatrick CurrentActivity = "";
36709467b48Spatrick maybeVerifyModule((*Ret)->getModule());
36809467b48Spatrick return std::move(*Ret);
36909467b48Spatrick }
37009467b48Spatrick
37109467b48Spatrick /// Print some statistics on the index for each input files.
printIndexStats()37273471bf0Spatrick static void printIndexStats() {
37309467b48Spatrick for (auto &Filename : InputFilenames) {
37409467b48Spatrick ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");
37509467b48Spatrick std::unique_ptr<ModuleSummaryIndex> Index =
37609467b48Spatrick ExitOnErr(getModuleSummaryIndexForFile(Filename));
37709467b48Spatrick // Skip files without a module summary.
37809467b48Spatrick if (!Index)
379*d415bd75Srobert report_fatal_error(Twine(Filename) + " does not contain an index");
38009467b48Spatrick
38109467b48Spatrick unsigned Calls = 0, Refs = 0, Functions = 0, Alias = 0, Globals = 0;
38209467b48Spatrick for (auto &Summaries : *Index) {
38309467b48Spatrick for (auto &Summary : Summaries.second.SummaryList) {
38409467b48Spatrick Refs += Summary->refs().size();
38509467b48Spatrick if (auto *FuncSummary = dyn_cast<FunctionSummary>(Summary.get())) {
38609467b48Spatrick Functions++;
38709467b48Spatrick Calls += FuncSummary->calls().size();
38809467b48Spatrick } else if (isa<AliasSummary>(Summary.get()))
38909467b48Spatrick Alias++;
39009467b48Spatrick else
39109467b48Spatrick Globals++;
39209467b48Spatrick }
39309467b48Spatrick }
39409467b48Spatrick outs() << "Index " << Filename << " contains "
39509467b48Spatrick << (Alias + Globals + Functions) << " nodes (" << Functions
39609467b48Spatrick << " functions, " << Alias << " alias, " << Globals
39709467b48Spatrick << " globals) and " << (Calls + Refs) << " edges (" << Refs
39809467b48Spatrick << " refs and " << Calls << " calls)\n";
39909467b48Spatrick }
40009467b48Spatrick }
40109467b48Spatrick
402*d415bd75Srobert /// Load each IR file and dump certain information based on active flags.
40309467b48Spatrick ///
40409467b48Spatrick /// The main point here is to provide lit-testable coverage for the LTOModule
405*d415bd75Srobert /// functionality that's exposed by the C API. Moreover, this provides testing
406*d415bd75Srobert /// coverage for modules that have been created in their own contexts.
testLTOModule(const TargetOptions & Options)407*d415bd75Srobert static void testLTOModule(const TargetOptions &Options) {
40809467b48Spatrick for (auto &Filename : InputFilenames) {
40909467b48Spatrick std::unique_ptr<MemoryBuffer> Buffer;
41009467b48Spatrick std::unique_ptr<LTOModule> Module =
41109467b48Spatrick getLocalLTOModule(Filename, Buffer, Options);
41209467b48Spatrick
413*d415bd75Srobert if (ListSymbolsOnly) {
41409467b48Spatrick // List the symbols.
41509467b48Spatrick outs() << Filename << ":\n";
41609467b48Spatrick for (int I = 0, E = Module->getSymbolCount(); I != E; ++I)
41709467b48Spatrick outs() << Module->getSymbolName(I) << "\n";
41809467b48Spatrick }
419*d415bd75Srobert if (QueryHasCtorDtor)
420*d415bd75Srobert outs() << Filename
421*d415bd75Srobert << ": hasCtorDtor = " << (Module->hasCtorDtor() ? "true" : "false")
422*d415bd75Srobert << "\n";
423*d415bd75Srobert }
42409467b48Spatrick }
42509467b48Spatrick
loadFile(StringRef Filename)42609467b48Spatrick static std::unique_ptr<MemoryBuffer> loadFile(StringRef Filename) {
42709467b48Spatrick ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename.str() +
42809467b48Spatrick "': ");
42909467b48Spatrick return ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Filename)));
43009467b48Spatrick }
43109467b48Spatrick
listDependentLibraries()43209467b48Spatrick static void listDependentLibraries() {
43309467b48Spatrick for (auto &Filename : InputFilenames) {
43409467b48Spatrick auto Buffer = loadFile(Filename);
43509467b48Spatrick std::string E;
43609467b48Spatrick std::unique_ptr<lto::InputFile> Input(LTOModule::createInputFile(
43709467b48Spatrick Buffer->getBufferStart(), Buffer->getBufferSize(), Filename.c_str(),
43809467b48Spatrick E));
43909467b48Spatrick if (!Input)
44009467b48Spatrick error(E);
44109467b48Spatrick
44209467b48Spatrick // List the dependent libraries.
44309467b48Spatrick outs() << Filename << ":\n";
44409467b48Spatrick for (size_t I = 0, C = LTOModule::getDependentLibraryCount(Input.get());
44509467b48Spatrick I != C; ++I) {
44609467b48Spatrick size_t L = 0;
44709467b48Spatrick const char *S = LTOModule::getDependentLibrary(Input.get(), I, &L);
44809467b48Spatrick assert(S);
44909467b48Spatrick outs() << StringRef(S, L) << "\n";
45009467b48Spatrick }
45109467b48Spatrick }
45209467b48Spatrick }
45309467b48Spatrick
printMachOCPUOnly()454097a140dSpatrick static void printMachOCPUOnly() {
455097a140dSpatrick LLVMContext Context;
456097a140dSpatrick Context.setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),
457097a140dSpatrick true);
45873471bf0Spatrick TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());
459097a140dSpatrick for (auto &Filename : InputFilenames) {
460097a140dSpatrick ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =
461097a140dSpatrick LTOModule::createFromFile(Context, Filename, Options);
462097a140dSpatrick if (!ModuleOrErr)
463097a140dSpatrick error(ModuleOrErr, "llvm-lto: ");
464097a140dSpatrick
465097a140dSpatrick Expected<uint32_t> CPUType = (*ModuleOrErr)->getMachOCPUType();
466097a140dSpatrick Expected<uint32_t> CPUSubType = (*ModuleOrErr)->getMachOCPUSubType();
467097a140dSpatrick if (!CPUType)
468097a140dSpatrick error("Error while printing mach-o cputype: " +
469097a140dSpatrick toString(CPUType.takeError()));
470097a140dSpatrick if (!CPUSubType)
471097a140dSpatrick error("Error while printing mach-o cpusubtype: " +
472097a140dSpatrick toString(CPUSubType.takeError()));
473097a140dSpatrick outs() << llvm::format("%s:\ncputype: %u\ncpusubtype: %u\n",
474097a140dSpatrick Filename.c_str(), *CPUType, *CPUSubType);
475097a140dSpatrick }
476097a140dSpatrick }
477097a140dSpatrick
47809467b48Spatrick /// Create a combined index file from the input IR files and write it.
47909467b48Spatrick ///
48009467b48Spatrick /// This is meant to enable testing of ThinLTO combined index generation,
48109467b48Spatrick /// currently available via the gold plugin via -thinlto.
createCombinedModuleSummaryIndex()48209467b48Spatrick static void createCombinedModuleSummaryIndex() {
48309467b48Spatrick ModuleSummaryIndex CombinedIndex(/*HaveGVs=*/false);
48409467b48Spatrick uint64_t NextModuleId = 0;
48509467b48Spatrick for (auto &Filename : InputFilenames) {
48609467b48Spatrick ExitOnError ExitOnErr("llvm-lto: error loading file '" + Filename + "': ");
48709467b48Spatrick std::unique_ptr<MemoryBuffer> MB =
48809467b48Spatrick ExitOnErr(errorOrToExpected(MemoryBuffer::getFileOrSTDIN(Filename)));
48909467b48Spatrick ExitOnErr(readModuleSummaryIndex(*MB, CombinedIndex, NextModuleId++));
49009467b48Spatrick }
491*d415bd75Srobert // In order to use this index for testing, specifically import testing, we
492*d415bd75Srobert // need to update any indirect call edges created from SamplePGO, so that they
493*d415bd75Srobert // point to the correct GUIDs.
494*d415bd75Srobert updateIndirectCalls(CombinedIndex);
49509467b48Spatrick std::error_code EC;
49609467b48Spatrick assert(!OutputFilename.empty());
49709467b48Spatrick raw_fd_ostream OS(OutputFilename + ".thinlto.bc", EC,
49809467b48Spatrick sys::fs::OpenFlags::OF_None);
49909467b48Spatrick error(EC, "error opening the file '" + OutputFilename + ".thinlto.bc'");
500*d415bd75Srobert writeIndexToFile(CombinedIndex, OS);
50109467b48Spatrick OS.close();
50209467b48Spatrick }
50309467b48Spatrick
50409467b48Spatrick /// Parse the thinlto_prefix_replace option into the \p OldPrefix and
50509467b48Spatrick /// \p NewPrefix strings, if it was specified.
getThinLTOOldAndNewPrefix(std::string & OldPrefix,std::string & NewPrefix)50609467b48Spatrick static void getThinLTOOldAndNewPrefix(std::string &OldPrefix,
50709467b48Spatrick std::string &NewPrefix) {
50809467b48Spatrick assert(ThinLTOPrefixReplace.empty() ||
50973471bf0Spatrick ThinLTOPrefixReplace.find(';') != StringRef::npos);
51009467b48Spatrick StringRef PrefixReplace = ThinLTOPrefixReplace;
51109467b48Spatrick std::pair<StringRef, StringRef> Split = PrefixReplace.split(";");
51209467b48Spatrick OldPrefix = Split.first.str();
51309467b48Spatrick NewPrefix = Split.second.str();
51409467b48Spatrick }
51509467b48Spatrick
51609467b48Spatrick /// Given the original \p Path to an output file, replace any path
51709467b48Spatrick /// prefix matching \p OldPrefix with \p NewPrefix. Also, create the
51809467b48Spatrick /// resulting directory if it does not yet exist.
getThinLTOOutputFile(const std::string & Path,const std::string & OldPrefix,const std::string & NewPrefix)51909467b48Spatrick static std::string getThinLTOOutputFile(const std::string &Path,
52009467b48Spatrick const std::string &OldPrefix,
52109467b48Spatrick const std::string &NewPrefix) {
52209467b48Spatrick if (OldPrefix.empty() && NewPrefix.empty())
52309467b48Spatrick return Path;
52409467b48Spatrick SmallString<128> NewPath(Path);
52509467b48Spatrick llvm::sys::path::replace_path_prefix(NewPath, OldPrefix, NewPrefix);
52609467b48Spatrick StringRef ParentPath = llvm::sys::path::parent_path(NewPath.str());
52709467b48Spatrick if (!ParentPath.empty()) {
52809467b48Spatrick // Make sure the new directory exists, creating it if necessary.
52909467b48Spatrick if (std::error_code EC = llvm::sys::fs::create_directories(ParentPath))
53009467b48Spatrick error(EC, "error creating the directory '" + ParentPath + "'");
53109467b48Spatrick }
532097a140dSpatrick return std::string(NewPath.str());
53309467b48Spatrick }
53409467b48Spatrick
53509467b48Spatrick namespace thinlto {
53609467b48Spatrick
53709467b48Spatrick std::vector<std::unique_ptr<MemoryBuffer>>
loadAllFilesForIndex(const ModuleSummaryIndex & Index)53809467b48Spatrick loadAllFilesForIndex(const ModuleSummaryIndex &Index) {
53909467b48Spatrick std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
54009467b48Spatrick
54109467b48Spatrick for (auto &ModPath : Index.modulePaths()) {
54209467b48Spatrick const auto &Filename = ModPath.first();
54309467b48Spatrick std::string CurrentActivity = ("loading file '" + Filename + "'").str();
54409467b48Spatrick auto InputOrErr = MemoryBuffer::getFile(Filename);
54509467b48Spatrick error(InputOrErr, "error " + CurrentActivity);
54609467b48Spatrick InputBuffers.push_back(std::move(*InputOrErr));
54709467b48Spatrick }
54809467b48Spatrick return InputBuffers;
54909467b48Spatrick }
55009467b48Spatrick
loadCombinedIndex()55109467b48Spatrick std::unique_ptr<ModuleSummaryIndex> loadCombinedIndex() {
55209467b48Spatrick if (ThinLTOIndex.empty())
55309467b48Spatrick report_fatal_error("Missing -thinlto-index for ThinLTO promotion stage");
55409467b48Spatrick ExitOnError ExitOnErr("llvm-lto: error loading file '" + ThinLTOIndex +
55509467b48Spatrick "': ");
55609467b48Spatrick return ExitOnErr(getModuleSummaryIndexForFile(ThinLTOIndex));
55709467b48Spatrick }
55809467b48Spatrick
loadInputFile(MemoryBufferRef Buffer)55909467b48Spatrick static std::unique_ptr<lto::InputFile> loadInputFile(MemoryBufferRef Buffer) {
56009467b48Spatrick ExitOnError ExitOnErr("llvm-lto: error loading input '" +
56109467b48Spatrick Buffer.getBufferIdentifier().str() + "': ");
56209467b48Spatrick return ExitOnErr(lto::InputFile::create(Buffer));
56309467b48Spatrick }
56409467b48Spatrick
loadModuleFromInput(lto::InputFile & File,LLVMContext & CTX)56509467b48Spatrick static std::unique_ptr<Module> loadModuleFromInput(lto::InputFile &File,
56609467b48Spatrick LLVMContext &CTX) {
56709467b48Spatrick auto &Mod = File.getSingleBitcodeModule();
56809467b48Spatrick auto ModuleOrErr = Mod.parseModule(CTX);
56909467b48Spatrick if (!ModuleOrErr) {
57009467b48Spatrick handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) {
57109467b48Spatrick SMDiagnostic Err = SMDiagnostic(Mod.getModuleIdentifier(),
57209467b48Spatrick SourceMgr::DK_Error, EIB.message());
57309467b48Spatrick Err.print("llvm-lto", errs());
57409467b48Spatrick });
57509467b48Spatrick report_fatal_error("Can't load module, abort.");
57609467b48Spatrick }
57709467b48Spatrick maybeVerifyModule(**ModuleOrErr);
57809467b48Spatrick if (ThinLTOModuleId.getNumOccurrences()) {
57909467b48Spatrick if (InputFilenames.size() != 1)
58009467b48Spatrick report_fatal_error("Can't override the module id for multiple files");
58109467b48Spatrick (*ModuleOrErr)->setModuleIdentifier(ThinLTOModuleId);
58209467b48Spatrick }
58309467b48Spatrick return std::move(*ModuleOrErr);
58409467b48Spatrick }
58509467b48Spatrick
writeModuleToFile(Module & TheModule,StringRef Filename)58609467b48Spatrick static void writeModuleToFile(Module &TheModule, StringRef Filename) {
58709467b48Spatrick std::error_code EC;
58809467b48Spatrick raw_fd_ostream OS(Filename, EC, sys::fs::OpenFlags::OF_None);
58909467b48Spatrick error(EC, "error opening the file '" + Filename + "'");
59009467b48Spatrick maybeVerifyModule(TheModule);
59109467b48Spatrick WriteBitcodeToFile(TheModule, OS, /* ShouldPreserveUseListOrder */ true);
59209467b48Spatrick }
59309467b48Spatrick
59409467b48Spatrick class ThinLTOProcessing {
59509467b48Spatrick public:
59609467b48Spatrick ThinLTOCodeGenerator ThinGenerator;
59709467b48Spatrick
ThinLTOProcessing(const TargetOptions & Options)59809467b48Spatrick ThinLTOProcessing(const TargetOptions &Options) {
599097a140dSpatrick ThinGenerator.setCodePICModel(codegen::getExplicitRelocModel());
60009467b48Spatrick ThinGenerator.setTargetOptions(Options);
60109467b48Spatrick ThinGenerator.setCacheDir(ThinLTOCacheDir);
60209467b48Spatrick ThinGenerator.setCachePruningInterval(ThinLTOCachePruningInterval);
60309467b48Spatrick ThinGenerator.setCacheEntryExpiration(ThinLTOCacheEntryExpiration);
60409467b48Spatrick ThinGenerator.setCacheMaxSizeFiles(ThinLTOCacheMaxSizeFiles);
60509467b48Spatrick ThinGenerator.setCacheMaxSizeBytes(ThinLTOCacheMaxSizeBytes);
60609467b48Spatrick ThinGenerator.setFreestanding(EnableFreestanding);
60773471bf0Spatrick ThinGenerator.setDebugPassManager(DebugPassManager);
60809467b48Spatrick
60909467b48Spatrick // Add all the exported symbols to the table of symbols to preserve.
61009467b48Spatrick for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
61109467b48Spatrick ThinGenerator.preserveSymbol(ExportedSymbols[i]);
61209467b48Spatrick }
61309467b48Spatrick
run()61409467b48Spatrick void run() {
61509467b48Spatrick switch (ThinLTOMode) {
61609467b48Spatrick case THINLINK:
61709467b48Spatrick return thinLink();
61809467b48Spatrick case THINDISTRIBUTE:
61909467b48Spatrick return distributedIndexes();
62009467b48Spatrick case THINEMITIMPORTS:
62109467b48Spatrick return emitImports();
62209467b48Spatrick case THINPROMOTE:
62309467b48Spatrick return promote();
62409467b48Spatrick case THINIMPORT:
62509467b48Spatrick return import();
62609467b48Spatrick case THININTERNALIZE:
62709467b48Spatrick return internalize();
62809467b48Spatrick case THINOPT:
62909467b48Spatrick return optimize();
63009467b48Spatrick case THINCODEGEN:
63109467b48Spatrick return codegen();
63209467b48Spatrick case THINALL:
63309467b48Spatrick return runAll();
63409467b48Spatrick }
63509467b48Spatrick }
63609467b48Spatrick
63709467b48Spatrick private:
63809467b48Spatrick /// Load the input files, create the combined index, and write it out.
thinLink()63909467b48Spatrick void thinLink() {
64009467b48Spatrick // Perform "ThinLink": just produce the index
64109467b48Spatrick if (OutputFilename.empty())
64209467b48Spatrick report_fatal_error(
64309467b48Spatrick "OutputFilename is necessary to store the combined index.\n");
64409467b48Spatrick
64509467b48Spatrick LLVMContext Ctx;
64609467b48Spatrick std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
64709467b48Spatrick for (unsigned i = 0; i < InputFilenames.size(); ++i) {
64809467b48Spatrick auto &Filename = InputFilenames[i];
64909467b48Spatrick std::string CurrentActivity = "loading file '" + Filename + "'";
65009467b48Spatrick auto InputOrErr = MemoryBuffer::getFile(Filename);
65109467b48Spatrick error(InputOrErr, "error " + CurrentActivity);
65209467b48Spatrick InputBuffers.push_back(std::move(*InputOrErr));
65309467b48Spatrick ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());
65409467b48Spatrick }
65509467b48Spatrick
65609467b48Spatrick auto CombinedIndex = ThinGenerator.linkCombinedIndex();
65709467b48Spatrick if (!CombinedIndex)
65809467b48Spatrick report_fatal_error("ThinLink didn't create an index");
65909467b48Spatrick std::error_code EC;
66009467b48Spatrick raw_fd_ostream OS(OutputFilename, EC, sys::fs::OpenFlags::OF_None);
66109467b48Spatrick error(EC, "error opening the file '" + OutputFilename + "'");
662*d415bd75Srobert writeIndexToFile(*CombinedIndex, OS);
66309467b48Spatrick }
66409467b48Spatrick
66509467b48Spatrick /// Load the combined index from disk, then compute and generate
66609467b48Spatrick /// individual index files suitable for ThinLTO distributed backend builds
66709467b48Spatrick /// on the files mentioned on the command line (these must match the index
66809467b48Spatrick /// content).
distributedIndexes()66909467b48Spatrick void distributedIndexes() {
67009467b48Spatrick if (InputFilenames.size() != 1 && !OutputFilename.empty())
67109467b48Spatrick report_fatal_error("Can't handle a single output filename and multiple "
67209467b48Spatrick "input files, do not provide an output filename and "
67309467b48Spatrick "the output files will be suffixed from the input "
67409467b48Spatrick "ones.");
67509467b48Spatrick
67609467b48Spatrick std::string OldPrefix, NewPrefix;
67709467b48Spatrick getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
67809467b48Spatrick
67909467b48Spatrick auto Index = loadCombinedIndex();
68009467b48Spatrick for (auto &Filename : InputFilenames) {
68109467b48Spatrick LLVMContext Ctx;
68209467b48Spatrick auto Buffer = loadFile(Filename);
68309467b48Spatrick auto Input = loadInputFile(Buffer->getMemBufferRef());
68409467b48Spatrick auto TheModule = loadModuleFromInput(*Input, Ctx);
68509467b48Spatrick
68609467b48Spatrick // Build a map of module to the GUIDs and summary objects that should
68709467b48Spatrick // be written to its index.
68809467b48Spatrick std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex;
68909467b48Spatrick ThinGenerator.gatherImportedSummariesForModule(
69009467b48Spatrick *TheModule, *Index, ModuleToSummariesForIndex, *Input);
69109467b48Spatrick
69209467b48Spatrick std::string OutputName = OutputFilename;
69309467b48Spatrick if (OutputName.empty()) {
69409467b48Spatrick OutputName = Filename + ".thinlto.bc";
69509467b48Spatrick }
69609467b48Spatrick OutputName = getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix);
69709467b48Spatrick std::error_code EC;
69809467b48Spatrick raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);
69909467b48Spatrick error(EC, "error opening the file '" + OutputName + "'");
700*d415bd75Srobert writeIndexToFile(*Index, OS, &ModuleToSummariesForIndex);
70109467b48Spatrick }
70209467b48Spatrick }
70309467b48Spatrick
70409467b48Spatrick /// Load the combined index from disk, compute the imports, and emit
70509467b48Spatrick /// the import file lists for each module to disk.
emitImports()70609467b48Spatrick void emitImports() {
70709467b48Spatrick if (InputFilenames.size() != 1 && !OutputFilename.empty())
70809467b48Spatrick report_fatal_error("Can't handle a single output filename and multiple "
70909467b48Spatrick "input files, do not provide an output filename and "
71009467b48Spatrick "the output files will be suffixed from the input "
71109467b48Spatrick "ones.");
71209467b48Spatrick
71309467b48Spatrick std::string OldPrefix, NewPrefix;
71409467b48Spatrick getThinLTOOldAndNewPrefix(OldPrefix, NewPrefix);
71509467b48Spatrick
71609467b48Spatrick auto Index = loadCombinedIndex();
71709467b48Spatrick for (auto &Filename : InputFilenames) {
71809467b48Spatrick LLVMContext Ctx;
71909467b48Spatrick auto Buffer = loadFile(Filename);
72009467b48Spatrick auto Input = loadInputFile(Buffer->getMemBufferRef());
72109467b48Spatrick auto TheModule = loadModuleFromInput(*Input, Ctx);
72209467b48Spatrick std::string OutputName = OutputFilename;
72309467b48Spatrick if (OutputName.empty()) {
72409467b48Spatrick OutputName = Filename + ".imports";
72509467b48Spatrick }
72609467b48Spatrick OutputName =
72709467b48Spatrick getThinLTOOutputFile(OutputName, OldPrefix, NewPrefix);
72809467b48Spatrick ThinGenerator.emitImports(*TheModule, OutputName, *Index, *Input);
72909467b48Spatrick }
73009467b48Spatrick }
73109467b48Spatrick
73209467b48Spatrick /// Load the combined index from disk, then load every file referenced by
73309467b48Spatrick /// the index and add them to the generator, finally perform the promotion
73409467b48Spatrick /// on the files mentioned on the command line (these must match the index
73509467b48Spatrick /// content).
promote()73609467b48Spatrick void promote() {
73709467b48Spatrick if (InputFilenames.size() != 1 && !OutputFilename.empty())
73809467b48Spatrick report_fatal_error("Can't handle a single output filename and multiple "
73909467b48Spatrick "input files, do not provide an output filename and "
74009467b48Spatrick "the output files will be suffixed from the input "
74109467b48Spatrick "ones.");
74209467b48Spatrick
74309467b48Spatrick auto Index = loadCombinedIndex();
74409467b48Spatrick for (auto &Filename : InputFilenames) {
74509467b48Spatrick LLVMContext Ctx;
74609467b48Spatrick auto Buffer = loadFile(Filename);
74709467b48Spatrick auto Input = loadInputFile(Buffer->getMemBufferRef());
74809467b48Spatrick auto TheModule = loadModuleFromInput(*Input, Ctx);
74909467b48Spatrick
75009467b48Spatrick ThinGenerator.promote(*TheModule, *Index, *Input);
75109467b48Spatrick
75209467b48Spatrick std::string OutputName = OutputFilename;
75309467b48Spatrick if (OutputName.empty()) {
75409467b48Spatrick OutputName = Filename + ".thinlto.promoted.bc";
75509467b48Spatrick }
75609467b48Spatrick writeModuleToFile(*TheModule, OutputName);
75709467b48Spatrick }
75809467b48Spatrick }
75909467b48Spatrick
76009467b48Spatrick /// Load the combined index from disk, then load every file referenced by
76109467b48Spatrick /// the index and add them to the generator, then performs the promotion and
76209467b48Spatrick /// cross module importing on the files mentioned on the command line
76309467b48Spatrick /// (these must match the index content).
import()76409467b48Spatrick void import() {
76509467b48Spatrick if (InputFilenames.size() != 1 && !OutputFilename.empty())
76609467b48Spatrick report_fatal_error("Can't handle a single output filename and multiple "
76709467b48Spatrick "input files, do not provide an output filename and "
76809467b48Spatrick "the output files will be suffixed from the input "
76909467b48Spatrick "ones.");
77009467b48Spatrick
77109467b48Spatrick auto Index = loadCombinedIndex();
77209467b48Spatrick auto InputBuffers = loadAllFilesForIndex(*Index);
77309467b48Spatrick for (auto &MemBuffer : InputBuffers)
77409467b48Spatrick ThinGenerator.addModule(MemBuffer->getBufferIdentifier(),
77509467b48Spatrick MemBuffer->getBuffer());
77609467b48Spatrick
77709467b48Spatrick for (auto &Filename : InputFilenames) {
77809467b48Spatrick LLVMContext Ctx;
77909467b48Spatrick auto Buffer = loadFile(Filename);
78009467b48Spatrick auto Input = loadInputFile(Buffer->getMemBufferRef());
78109467b48Spatrick auto TheModule = loadModuleFromInput(*Input, Ctx);
78209467b48Spatrick
78309467b48Spatrick ThinGenerator.crossModuleImport(*TheModule, *Index, *Input);
78409467b48Spatrick
78509467b48Spatrick std::string OutputName = OutputFilename;
78609467b48Spatrick if (OutputName.empty()) {
78709467b48Spatrick OutputName = Filename + ".thinlto.imported.bc";
78809467b48Spatrick }
78909467b48Spatrick writeModuleToFile(*TheModule, OutputName);
79009467b48Spatrick }
79109467b48Spatrick }
79209467b48Spatrick
internalize()79309467b48Spatrick void internalize() {
79409467b48Spatrick if (InputFilenames.size() != 1 && !OutputFilename.empty())
79509467b48Spatrick report_fatal_error("Can't handle a single output filename and multiple "
79609467b48Spatrick "input files, do not provide an output filename and "
79709467b48Spatrick "the output files will be suffixed from the input "
79809467b48Spatrick "ones.");
79909467b48Spatrick
80009467b48Spatrick if (ExportedSymbols.empty())
80109467b48Spatrick errs() << "Warning: -internalize will not perform without "
80209467b48Spatrick "-exported-symbol\n";
80309467b48Spatrick
80409467b48Spatrick auto Index = loadCombinedIndex();
80509467b48Spatrick auto InputBuffers = loadAllFilesForIndex(*Index);
80609467b48Spatrick for (auto &MemBuffer : InputBuffers)
80709467b48Spatrick ThinGenerator.addModule(MemBuffer->getBufferIdentifier(),
80809467b48Spatrick MemBuffer->getBuffer());
80909467b48Spatrick
81009467b48Spatrick for (auto &Filename : InputFilenames) {
81109467b48Spatrick LLVMContext Ctx;
81209467b48Spatrick auto Buffer = loadFile(Filename);
81309467b48Spatrick auto Input = loadInputFile(Buffer->getMemBufferRef());
81409467b48Spatrick auto TheModule = loadModuleFromInput(*Input, Ctx);
81509467b48Spatrick
81609467b48Spatrick ThinGenerator.internalize(*TheModule, *Index, *Input);
81709467b48Spatrick
81809467b48Spatrick std::string OutputName = OutputFilename;
81909467b48Spatrick if (OutputName.empty()) {
82009467b48Spatrick OutputName = Filename + ".thinlto.internalized.bc";
82109467b48Spatrick }
82209467b48Spatrick writeModuleToFile(*TheModule, OutputName);
82309467b48Spatrick }
82409467b48Spatrick }
82509467b48Spatrick
optimize()82609467b48Spatrick void optimize() {
82709467b48Spatrick if (InputFilenames.size() != 1 && !OutputFilename.empty())
82809467b48Spatrick report_fatal_error("Can't handle a single output filename and multiple "
82909467b48Spatrick "input files, do not provide an output filename and "
83009467b48Spatrick "the output files will be suffixed from the input "
83109467b48Spatrick "ones.");
83209467b48Spatrick if (!ThinLTOIndex.empty())
83309467b48Spatrick errs() << "Warning: -thinlto-index ignored for optimize stage";
83409467b48Spatrick
83509467b48Spatrick for (auto &Filename : InputFilenames) {
83609467b48Spatrick LLVMContext Ctx;
83709467b48Spatrick auto Buffer = loadFile(Filename);
83809467b48Spatrick auto Input = loadInputFile(Buffer->getMemBufferRef());
83909467b48Spatrick auto TheModule = loadModuleFromInput(*Input, Ctx);
84009467b48Spatrick
84109467b48Spatrick ThinGenerator.optimize(*TheModule);
84209467b48Spatrick
84309467b48Spatrick std::string OutputName = OutputFilename;
84409467b48Spatrick if (OutputName.empty()) {
84509467b48Spatrick OutputName = Filename + ".thinlto.imported.bc";
84609467b48Spatrick }
84709467b48Spatrick writeModuleToFile(*TheModule, OutputName);
84809467b48Spatrick }
84909467b48Spatrick }
85009467b48Spatrick
codegen()85109467b48Spatrick void codegen() {
85209467b48Spatrick if (InputFilenames.size() != 1 && !OutputFilename.empty())
85309467b48Spatrick report_fatal_error("Can't handle a single output filename and multiple "
85409467b48Spatrick "input files, do not provide an output filename and "
85509467b48Spatrick "the output files will be suffixed from the input "
85609467b48Spatrick "ones.");
85709467b48Spatrick if (!ThinLTOIndex.empty())
85809467b48Spatrick errs() << "Warning: -thinlto-index ignored for codegen stage";
85909467b48Spatrick
86009467b48Spatrick std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
86109467b48Spatrick for (auto &Filename : InputFilenames) {
86209467b48Spatrick LLVMContext Ctx;
86309467b48Spatrick auto InputOrErr = MemoryBuffer::getFile(Filename);
86409467b48Spatrick error(InputOrErr, "error " + CurrentActivity);
86509467b48Spatrick InputBuffers.push_back(std::move(*InputOrErr));
86609467b48Spatrick ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());
86709467b48Spatrick }
86809467b48Spatrick ThinGenerator.setCodeGenOnly(true);
86909467b48Spatrick ThinGenerator.run();
87009467b48Spatrick for (auto BinName :
87109467b48Spatrick zip(ThinGenerator.getProducedBinaries(), InputFilenames)) {
87209467b48Spatrick std::string OutputName = OutputFilename;
87309467b48Spatrick if (OutputName.empty())
87409467b48Spatrick OutputName = std::get<1>(BinName) + ".thinlto.o";
87509467b48Spatrick else if (OutputName == "-") {
87609467b48Spatrick outs() << std::get<0>(BinName)->getBuffer();
87709467b48Spatrick return;
87809467b48Spatrick }
87909467b48Spatrick
88009467b48Spatrick std::error_code EC;
88109467b48Spatrick raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);
88209467b48Spatrick error(EC, "error opening the file '" + OutputName + "'");
88309467b48Spatrick OS << std::get<0>(BinName)->getBuffer();
88409467b48Spatrick }
88509467b48Spatrick }
88609467b48Spatrick
88709467b48Spatrick /// Full ThinLTO process
runAll()88809467b48Spatrick void runAll() {
88909467b48Spatrick if (!OutputFilename.empty())
89009467b48Spatrick report_fatal_error("Do not provide an output filename for ThinLTO "
89109467b48Spatrick " processing, the output files will be suffixed from "
89209467b48Spatrick "the input ones.");
89309467b48Spatrick
89409467b48Spatrick if (!ThinLTOIndex.empty())
89509467b48Spatrick errs() << "Warning: -thinlto-index ignored for full ThinLTO process";
89609467b48Spatrick
89709467b48Spatrick LLVMContext Ctx;
89809467b48Spatrick std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
89909467b48Spatrick for (unsigned i = 0; i < InputFilenames.size(); ++i) {
90009467b48Spatrick auto &Filename = InputFilenames[i];
90109467b48Spatrick std::string CurrentActivity = "loading file '" + Filename + "'";
90209467b48Spatrick auto InputOrErr = MemoryBuffer::getFile(Filename);
90309467b48Spatrick error(InputOrErr, "error " + CurrentActivity);
90409467b48Spatrick InputBuffers.push_back(std::move(*InputOrErr));
90509467b48Spatrick ThinGenerator.addModule(Filename, InputBuffers.back()->getBuffer());
90609467b48Spatrick }
90709467b48Spatrick
90809467b48Spatrick if (!ThinLTOSaveTempsPrefix.empty())
90909467b48Spatrick ThinGenerator.setSaveTempsDir(ThinLTOSaveTempsPrefix);
91009467b48Spatrick
91109467b48Spatrick if (!ThinLTOGeneratedObjectsDir.empty()) {
91209467b48Spatrick ThinGenerator.setGeneratedObjectsDirectory(ThinLTOGeneratedObjectsDir);
91309467b48Spatrick ThinGenerator.run();
91409467b48Spatrick return;
91509467b48Spatrick }
91609467b48Spatrick
91709467b48Spatrick ThinGenerator.run();
91809467b48Spatrick
91909467b48Spatrick auto &Binaries = ThinGenerator.getProducedBinaries();
92009467b48Spatrick if (Binaries.size() != InputFilenames.size())
92109467b48Spatrick report_fatal_error("Number of output objects does not match the number "
92209467b48Spatrick "of inputs");
92309467b48Spatrick
92409467b48Spatrick for (unsigned BufID = 0; BufID < Binaries.size(); ++BufID) {
92509467b48Spatrick auto OutputName = InputFilenames[BufID] + ".thinlto.o";
92609467b48Spatrick std::error_code EC;
92709467b48Spatrick raw_fd_ostream OS(OutputName, EC, sys::fs::OpenFlags::OF_None);
92809467b48Spatrick error(EC, "error opening the file '" + OutputName + "'");
92909467b48Spatrick OS << Binaries[BufID]->getBuffer();
93009467b48Spatrick }
93109467b48Spatrick }
93209467b48Spatrick
93309467b48Spatrick /// Load the combined index from disk, then load every file referenced by
93409467b48Spatrick };
93509467b48Spatrick
93609467b48Spatrick } // end namespace thinlto
93709467b48Spatrick
main(int argc,char ** argv)93809467b48Spatrick int main(int argc, char **argv) {
93909467b48Spatrick InitLLVM X(argc, argv);
94073471bf0Spatrick cl::HideUnrelatedOptions({<OCategory, &getColorCategory()});
94109467b48Spatrick cl::ParseCommandLineOptions(argc, argv, "llvm LTO linker\n");
94209467b48Spatrick
94309467b48Spatrick if (OptLevel < '0' || OptLevel > '3')
94409467b48Spatrick error("optimization level must be between 0 and 3");
94509467b48Spatrick
94609467b48Spatrick // Initialize the configured targets.
94709467b48Spatrick InitializeAllTargets();
94809467b48Spatrick InitializeAllTargetMCs();
94909467b48Spatrick InitializeAllAsmPrinters();
95009467b48Spatrick InitializeAllAsmParsers();
95109467b48Spatrick
95209467b48Spatrick // set up the TargetOptions for the machine
95373471bf0Spatrick TargetOptions Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());
95409467b48Spatrick
955*d415bd75Srobert if (ListSymbolsOnly || QueryHasCtorDtor) {
956*d415bd75Srobert testLTOModule(Options);
95709467b48Spatrick return 0;
95809467b48Spatrick }
95909467b48Spatrick
96009467b48Spatrick if (ListDependentLibrariesOnly) {
96109467b48Spatrick listDependentLibraries();
96209467b48Spatrick return 0;
96309467b48Spatrick }
96409467b48Spatrick
96509467b48Spatrick if (IndexStats) {
96609467b48Spatrick printIndexStats();
96709467b48Spatrick return 0;
96809467b48Spatrick }
96909467b48Spatrick
97009467b48Spatrick if (CheckHasObjC) {
97109467b48Spatrick for (auto &Filename : InputFilenames) {
97209467b48Spatrick ExitOnError ExitOnErr(std::string(*argv) + ": error loading file '" +
97309467b48Spatrick Filename + "': ");
97409467b48Spatrick std::unique_ptr<MemoryBuffer> BufferOrErr =
97509467b48Spatrick ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(Filename)));
97609467b48Spatrick auto Buffer = std::move(BufferOrErr.get());
97709467b48Spatrick if (ExitOnErr(isBitcodeContainingObjCCategory(*Buffer)))
97809467b48Spatrick outs() << "Bitcode " << Filename << " contains ObjC\n";
97909467b48Spatrick else
98009467b48Spatrick outs() << "Bitcode " << Filename << " does not contain ObjC\n";
98109467b48Spatrick }
98209467b48Spatrick return 0;
98309467b48Spatrick }
98409467b48Spatrick
985097a140dSpatrick if (PrintMachOCPUOnly) {
986097a140dSpatrick printMachOCPUOnly();
987097a140dSpatrick return 0;
988097a140dSpatrick }
989097a140dSpatrick
99009467b48Spatrick if (ThinLTOMode.getNumOccurrences()) {
99109467b48Spatrick if (ThinLTOMode.getNumOccurrences() > 1)
99209467b48Spatrick report_fatal_error("You can't specify more than one -thinlto-action");
99309467b48Spatrick thinlto::ThinLTOProcessing ThinLTOProcessor(Options);
99409467b48Spatrick ThinLTOProcessor.run();
99509467b48Spatrick return 0;
99609467b48Spatrick }
99709467b48Spatrick
99809467b48Spatrick if (ThinLTO) {
99909467b48Spatrick createCombinedModuleSummaryIndex();
100009467b48Spatrick return 0;
100109467b48Spatrick }
100209467b48Spatrick
100309467b48Spatrick unsigned BaseArg = 0;
100409467b48Spatrick
100509467b48Spatrick LLVMContext Context;
100609467b48Spatrick Context.setDiagnosticHandler(std::make_unique<LLVMLTODiagnosticHandler>(),
100709467b48Spatrick true);
100809467b48Spatrick
100909467b48Spatrick LTOCodeGenerator CodeGen(Context);
101073471bf0Spatrick CodeGen.setDisableVerify(DisableVerify);
101109467b48Spatrick
101209467b48Spatrick if (UseDiagnosticHandler)
101309467b48Spatrick CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr);
101409467b48Spatrick
1015097a140dSpatrick CodeGen.setCodePICModel(codegen::getExplicitRelocModel());
101609467b48Spatrick CodeGen.setFreestanding(EnableFreestanding);
1017*d415bd75Srobert CodeGen.setDebugPassManager(DebugPassManager);
101809467b48Spatrick
101909467b48Spatrick CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF);
102009467b48Spatrick CodeGen.setTargetOptions(Options);
102109467b48Spatrick CodeGen.setShouldRestoreGlobalsLinkage(RestoreGlobalsLinkage);
102209467b48Spatrick
102309467b48Spatrick StringSet<MallocAllocator> DSOSymbolsSet;
102409467b48Spatrick for (unsigned i = 0; i < DSOSymbols.size(); ++i)
102509467b48Spatrick DSOSymbolsSet.insert(DSOSymbols[i]);
102609467b48Spatrick
102709467b48Spatrick std::vector<std::string> KeptDSOSyms;
102809467b48Spatrick
102909467b48Spatrick for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) {
103009467b48Spatrick CurrentActivity = "loading file '" + InputFilenames[i] + "'";
103109467b48Spatrick ErrorOr<std::unique_ptr<LTOModule>> ModuleOrErr =
103209467b48Spatrick LTOModule::createFromFile(Context, InputFilenames[i], Options);
103309467b48Spatrick std::unique_ptr<LTOModule> &Module = *ModuleOrErr;
103409467b48Spatrick CurrentActivity = "";
103509467b48Spatrick
103609467b48Spatrick unsigned NumSyms = Module->getSymbolCount();
103709467b48Spatrick for (unsigned I = 0; I < NumSyms; ++I) {
103809467b48Spatrick StringRef Name = Module->getSymbolName(I);
103909467b48Spatrick if (!DSOSymbolsSet.count(Name))
104009467b48Spatrick continue;
104109467b48Spatrick lto_symbol_attributes Attrs = Module->getSymbolAttributes(I);
104209467b48Spatrick unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK;
104309467b48Spatrick if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN)
1044097a140dSpatrick KeptDSOSyms.push_back(std::string(Name));
104509467b48Spatrick }
104609467b48Spatrick
104709467b48Spatrick // We use the first input module as the destination module when
104809467b48Spatrick // SetMergedModule is true.
104909467b48Spatrick if (SetMergedModule && i == BaseArg) {
105009467b48Spatrick // Transfer ownership to the code generator.
105109467b48Spatrick CodeGen.setModule(std::move(Module));
105209467b48Spatrick } else if (!CodeGen.addModule(Module.get())) {
105309467b48Spatrick // Print a message here so that we know addModule() did not abort.
105409467b48Spatrick error("error adding file '" + InputFilenames[i] + "'");
105509467b48Spatrick }
105609467b48Spatrick }
105709467b48Spatrick
105809467b48Spatrick // Add all the exported symbols to the table of symbols to preserve.
105909467b48Spatrick for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
106009467b48Spatrick CodeGen.addMustPreserveSymbol(ExportedSymbols[i]);
106109467b48Spatrick
106209467b48Spatrick // Add all the dso symbols to the table of symbols to expose.
106309467b48Spatrick for (unsigned i = 0; i < KeptDSOSyms.size(); ++i)
106409467b48Spatrick CodeGen.addMustPreserveSymbol(KeptDSOSyms[i]);
106509467b48Spatrick
106609467b48Spatrick // Set cpu and attrs strings for the default target/subtarget.
1067*d415bd75Srobert CodeGen.setCpu(codegen::getMCPU());
106809467b48Spatrick
106909467b48Spatrick CodeGen.setOptLevel(OptLevel - '0');
107073471bf0Spatrick CodeGen.setAttrs(codegen::getMAttrs());
107109467b48Spatrick
1072097a140dSpatrick if (auto FT = codegen::getExplicitFileType())
1073*d415bd75Srobert CodeGen.setFileType(*FT);
107409467b48Spatrick
107509467b48Spatrick if (!OutputFilename.empty()) {
1076*d415bd75Srobert if (LTOSaveBeforeOpt)
1077*d415bd75Srobert CodeGen.setSaveIRBeforeOptPath(OutputFilename + ".0.preopt.bc");
1078*d415bd75Srobert
107973471bf0Spatrick if (SaveLinkedModuleFile) {
108073471bf0Spatrick std::string ModuleFilename = OutputFilename;
108173471bf0Spatrick ModuleFilename += ".linked.bc";
108273471bf0Spatrick std::string ErrMsg;
108373471bf0Spatrick
108473471bf0Spatrick if (!CodeGen.writeMergedModules(ModuleFilename))
108573471bf0Spatrick error("writing linked module failed.");
108673471bf0Spatrick }
108773471bf0Spatrick
108873471bf0Spatrick if (!CodeGen.optimize()) {
108909467b48Spatrick // Diagnostic messages should have been printed by the handler.
109009467b48Spatrick error("error optimizing the code");
109109467b48Spatrick }
109209467b48Spatrick
109309467b48Spatrick if (SaveModuleFile) {
109409467b48Spatrick std::string ModuleFilename = OutputFilename;
109509467b48Spatrick ModuleFilename += ".merged.bc";
109609467b48Spatrick std::string ErrMsg;
109709467b48Spatrick
109809467b48Spatrick if (!CodeGen.writeMergedModules(ModuleFilename))
109909467b48Spatrick error("writing merged module failed.");
110009467b48Spatrick }
110109467b48Spatrick
110273471bf0Spatrick auto AddStream =
1103*d415bd75Srobert [&](size_t Task,
1104*d415bd75Srobert const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
110509467b48Spatrick std::string PartFilename = OutputFilename;
110609467b48Spatrick if (Parallelism != 1)
110773471bf0Spatrick PartFilename += "." + utostr(Task);
110873471bf0Spatrick
110909467b48Spatrick std::error_code EC;
111073471bf0Spatrick auto S =
111173471bf0Spatrick std::make_unique<raw_fd_ostream>(PartFilename, EC, sys::fs::OF_None);
111209467b48Spatrick if (EC)
111309467b48Spatrick error("error opening the file '" + PartFilename + "': " + EC.message());
1114*d415bd75Srobert return std::make_unique<CachedFileStream>(std::move(S));
111573471bf0Spatrick };
111609467b48Spatrick
111773471bf0Spatrick if (!CodeGen.compileOptimized(AddStream, Parallelism))
111809467b48Spatrick // Diagnostic messages should have been printed by the handler.
111909467b48Spatrick error("error compiling the code");
112009467b48Spatrick
112109467b48Spatrick } else {
112209467b48Spatrick if (Parallelism != 1)
112309467b48Spatrick error("-j must be specified together with -o");
112409467b48Spatrick
112509467b48Spatrick if (SaveModuleFile)
112609467b48Spatrick error(": -save-merged-module must be specified with -o");
112709467b48Spatrick
112809467b48Spatrick const char *OutputName = nullptr;
112973471bf0Spatrick if (!CodeGen.compile_to_file(&OutputName))
113009467b48Spatrick error("error compiling the code");
113109467b48Spatrick // Diagnostic messages should have been printed by the handler.
113209467b48Spatrick
113309467b48Spatrick outs() << "Wrote native object file '" << OutputName << "'\n";
113409467b48Spatrick }
113509467b48Spatrick
113609467b48Spatrick return 0;
113709467b48Spatrick }
1138