2016-08-11 16:58:12 +02:00
|
|
|
//===-- llvm-lto2: test harness for the resolution-based LTO interface ----===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// 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
|
2016-08-11 16:58:12 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This program takes in a list of bitcode files, links them and performs
|
|
|
|
// link-time optimization according to the provided symbol resolutions using the
|
|
|
|
// resolution-based LTO interface, and outputs one or more object files.
|
|
|
|
//
|
|
|
|
// This program is intended to eventually replace llvm-lto which uses the legacy
|
|
|
|
// LTO interface.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-06-28 01:50:24 +02:00
|
|
|
#include "llvm/Bitcode/BitcodeReader.h"
|
2020-03-04 00:47:43 +01:00
|
|
|
#include "llvm/CodeGen/CommandFlags.h"
|
2020-12-08 19:30:45 +01:00
|
|
|
#include "llvm/Config/llvm-config.h"
|
2016-12-24 00:54:17 +01:00
|
|
|
#include "llvm/IR/DiagnosticPrinter.h"
|
2017-06-28 01:50:24 +02:00
|
|
|
#include "llvm/LTO/Caching.h"
|
2016-08-11 16:58:12 +02:00
|
|
|
#include "llvm/LTO/LTO.h"
|
2020-03-26 18:09:13 +01:00
|
|
|
#include "llvm/Passes/PassPlugin.h"
|
2020-11-17 19:37:59 +01:00
|
|
|
#include "llvm/Remarks/HotnessThresholdParser.h"
|
2016-08-11 16:58:12 +02:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2017-03-29 01:35:34 +02:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2018-10-16 19:37:45 +02:00
|
|
|
#include "llvm/Support/InitLLVM.h"
|
2020-03-26 18:09:13 +01:00
|
|
|
#include "llvm/Support/PluginLoader.h"
|
2016-08-11 16:58:12 +02:00
|
|
|
#include "llvm/Support/TargetSelect.h"
|
2016-10-19 19:35:01 +02:00
|
|
|
#include "llvm/Support/Threading.h"
|
2016-08-11 16:58:12 +02:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace lto;
|
|
|
|
|
2020-03-04 00:47:43 +01:00
|
|
|
static codegen::RegisterCodeGenFlags CGF;
|
|
|
|
|
2016-10-31 23:12:21 +01:00
|
|
|
static cl::opt<char>
|
|
|
|
OptLevel("O", cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
|
|
|
|
"(default = '-O2')"),
|
|
|
|
cl::Prefix, cl::ZeroOrMore, cl::init('2'));
|
|
|
|
|
2016-12-08 06:28:30 +01:00
|
|
|
static cl::opt<char> CGOptLevel(
|
|
|
|
"cg-opt-level",
|
|
|
|
cl::desc("Codegen optimization level (0, 1, 2 or 3, default = '2')"),
|
|
|
|
cl::init('2'));
|
|
|
|
|
2016-08-11 16:58:12 +02:00
|
|
|
static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
|
|
|
|
cl::desc("<input bitcode files>"));
|
|
|
|
|
|
|
|
static cl::opt<std::string> OutputFilename("o", cl::Required,
|
|
|
|
cl::desc("Output filename"),
|
|
|
|
cl::value_desc("filename"));
|
|
|
|
|
2016-08-23 23:30:12 +02:00
|
|
|
static cl::opt<std::string> CacheDir("cache-dir", cl::desc("Cache Directory"),
|
|
|
|
cl::value_desc("directory"));
|
|
|
|
|
2016-09-07 19:46:16 +02:00
|
|
|
static cl::opt<std::string> OptPipeline("opt-pipeline",
|
|
|
|
cl::desc("Optimizer Pipeline"),
|
|
|
|
cl::value_desc("pipeline"));
|
|
|
|
|
2016-09-16 23:03:21 +02:00
|
|
|
static cl::opt<std::string> AAPipeline("aa-pipeline",
|
|
|
|
cl::desc("Alias Analysis Pipeline"),
|
|
|
|
cl::value_desc("aapipeline"));
|
|
|
|
|
2016-08-11 16:58:12 +02:00
|
|
|
static cl::opt<bool> SaveTemps("save-temps", cl::desc("Save temporary files"));
|
|
|
|
|
2016-08-20 01:54:40 +02:00
|
|
|
static cl::opt<bool>
|
|
|
|
ThinLTODistributedIndexes("thinlto-distributed-indexes", cl::init(false),
|
|
|
|
cl::desc("Write out individual index and "
|
|
|
|
"import files for the "
|
|
|
|
"distributed backend case"));
|
|
|
|
|
2020-02-18 20:25:08 +01:00
|
|
|
// Default to using all available threads in the system, but using only one
|
2020-03-27 15:20:39 +01:00
|
|
|
// thread per core (no SMT).
|
|
|
|
// Use -thinlto-threads=all to use hardware_concurrency() instead, which means
|
|
|
|
// to use all hardware threads or cores in the system.
|
|
|
|
static cl::opt<std::string> Threads("thinlto-threads");
|
2016-08-20 01:54:40 +02:00
|
|
|
|
2016-08-11 16:58:12 +02:00
|
|
|
static cl::list<std::string> SymbolResolutions(
|
|
|
|
"r",
|
|
|
|
cl::desc("Specify a symbol resolution: filename,symbolname,resolution\n"
|
|
|
|
"where \"resolution\" is a sequence (which may be empty) of the\n"
|
|
|
|
"following characters:\n"
|
|
|
|
" p - prevailing: the linker has chosen this definition of the\n"
|
|
|
|
" symbol\n"
|
|
|
|
" l - local: the definition of this symbol is unpreemptable at\n"
|
|
|
|
" runtime and is known to be in this linkage unit\n"
|
|
|
|
" x - externally visible: the definition of this symbol is\n"
|
|
|
|
" visible outside of the LTO unit\n"
|
|
|
|
"A resolution for each symbol must be specified."),
|
|
|
|
cl::ZeroOrMore);
|
|
|
|
|
2016-12-08 06:28:30 +01:00
|
|
|
static cl::opt<std::string> OverrideTriple(
|
|
|
|
"override-triple",
|
|
|
|
cl::desc("Replace target triples in input files with this triple"));
|
|
|
|
|
|
|
|
static cl::opt<std::string> DefaultTriple(
|
|
|
|
"default-triple",
|
|
|
|
cl::desc(
|
|
|
|
"Replace unspecified target triples in input files with this triple"));
|
|
|
|
|
2019-06-14 18:20:51 +02:00
|
|
|
static cl::opt<bool> RemarksWithHotness(
|
2019-06-14 02:05:56 +02:00
|
|
|
"pass-remarks-with-hotness",
|
2019-06-14 18:20:51 +02:00
|
|
|
cl::desc("With PGO, include profile count in optimization remarks"),
|
|
|
|
cl::Hidden);
|
|
|
|
|
2020-11-17 19:37:59 +01:00
|
|
|
cl::opt<Optional<uint64_t>, false, remarks::HotnessThresholdParser>
|
|
|
|
RemarksHotnessThreshold(
|
|
|
|
"pass-remarks-hotness-threshold",
|
|
|
|
cl::desc("Minimum profile count required for an "
|
|
|
|
"optimization remark to be output."
|
|
|
|
" Use 'auto' to apply the threshold from profile summary."),
|
|
|
|
cl::value_desc("uint or 'auto'"), cl::init(0), cl::Hidden);
|
|
|
|
|
2019-06-14 18:20:51 +02:00
|
|
|
static cl::opt<std::string>
|
|
|
|
RemarksFilename("pass-remarks-output",
|
|
|
|
cl::desc("Output filename for pass remarks"),
|
|
|
|
cl::value_desc("filename"));
|
2017-02-12 06:05:35 +01:00
|
|
|
|
2019-03-12 22:22:27 +01:00
|
|
|
static cl::opt<std::string>
|
2019-06-14 18:20:51 +02:00
|
|
|
RemarksPasses("pass-remarks-filter",
|
|
|
|
cl::desc("Only record optimization remarks from passes whose "
|
|
|
|
"names match the given regular expression"),
|
|
|
|
cl::value_desc("regex"));
|
2019-03-12 22:22:27 +01:00
|
|
|
|
2019-06-17 18:06:00 +02:00
|
|
|
static cl::opt<std::string> RemarksFormat(
|
|
|
|
"pass-remarks-format",
|
|
|
|
cl::desc("The format used for serializing remarks (default: YAML)"),
|
|
|
|
cl::value_desc("format"), cl::init("yaml"));
|
|
|
|
|
2017-07-29 01:43:22 +02:00
|
|
|
static cl::opt<std::string>
|
|
|
|
SamplePGOFile("lto-sample-profile-file",
|
|
|
|
cl::desc("Specify a SamplePGO profile file"));
|
|
|
|
|
2019-02-27 18:24:33 +01:00
|
|
|
static cl::opt<std::string>
|
|
|
|
CSPGOFile("lto-cspgo-profile-file",
|
|
|
|
cl::desc("Specify a context sensitive PGO profile file"));
|
|
|
|
|
|
|
|
static cl::opt<bool>
|
|
|
|
RunCSIRInstr("lto-cspgo-gen",
|
|
|
|
cl::desc("Run PGO context sensitive IR instrumentation"),
|
|
|
|
cl::init(false), cl::Hidden);
|
|
|
|
|
[ThinLTO] Move -lto-use-new-pm to llvm-lto2, and change it to -use-new-pm.
Summary:
As we teach Clang to use ThinkLTO + new PM, it's good for the users to
inject through Config, instead of setting a flag in the LTOBackend
library. Move the flag to llvm-lto2.
As it moves to llvm-lto2, a new name -use-new-pm seems simpler and as
clear.
Reviewers: davide, tejohnson
Subscribers: mehdi_amini, Prazek, inglorion, eraman, chandlerc, llvm-commits
Differential Revision: https://reviews.llvm.org/D33799
llvm-svn: 304492
2017-06-02 01:13:44 +02:00
|
|
|
static cl::opt<bool>
|
|
|
|
UseNewPM("use-new-pm",
|
|
|
|
cl::desc("Run LTO passes using the new pass manager"),
|
2020-12-08 19:30:45 +01:00
|
|
|
cl::init(LLVM_ENABLE_NEW_PASS_MANAGER), cl::Hidden);
|
[ThinLTO] Move -lto-use-new-pm to llvm-lto2, and change it to -use-new-pm.
Summary:
As we teach Clang to use ThinkLTO + new PM, it's good for the users to
inject through Config, instead of setting a flag in the LTOBackend
library. Move the flag to llvm-lto2.
As it moves to llvm-lto2, a new name -use-new-pm seems simpler and as
clear.
Reviewers: davide, tejohnson
Subscribers: mehdi_amini, Prazek, inglorion, eraman, chandlerc, llvm-commits
Differential Revision: https://reviews.llvm.org/D33799
llvm-svn: 304492
2017-06-02 01:13:44 +02:00
|
|
|
|
2017-08-02 05:03:19 +02:00
|
|
|
static cl::opt<bool>
|
|
|
|
DebugPassManager("debug-pass-manager", cl::init(false), cl::Hidden,
|
|
|
|
cl::desc("Print pass management debugging information"));
|
|
|
|
|
2018-04-20 12:18:36 +02:00
|
|
|
static cl::opt<std::string>
|
|
|
|
StatsFile("stats-file", cl::desc("Filename to write statistics to"));
|
|
|
|
|
2020-03-26 18:09:13 +01:00
|
|
|
static cl::list<std::string>
|
|
|
|
PassPlugins("load-pass-plugin",
|
|
|
|
cl::desc("Load passes from plugin library"));
|
|
|
|
|
2021-01-22 14:13:54 +01:00
|
|
|
static cl::opt<bool> EnableFreestanding(
|
|
|
|
"lto-freestanding",
|
|
|
|
cl::desc("Enable Freestanding (disable builtins / TLI) during LTO"),
|
|
|
|
cl::init(false), cl::Hidden);
|
|
|
|
|
2016-08-11 16:58:12 +02:00
|
|
|
static void check(Error E, std::string Msg) {
|
|
|
|
if (!E)
|
|
|
|
return;
|
|
|
|
handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
|
2017-02-12 04:42:09 +01:00
|
|
|
errs() << "llvm-lto2: " << Msg << ": " << EIB.message().c_str() << '\n';
|
2016-08-11 16:58:12 +02:00
|
|
|
});
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T> static T check(Expected<T> E, std::string Msg) {
|
|
|
|
if (E)
|
|
|
|
return std::move(*E);
|
|
|
|
check(E.takeError(), Msg);
|
|
|
|
return T();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void check(std::error_code EC, std::string Msg) {
|
|
|
|
check(errorCodeToError(EC), Msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T> static T check(ErrorOr<T> E, std::string Msg) {
|
|
|
|
if (E)
|
|
|
|
return std::move(*E);
|
|
|
|
check(E.getError(), Msg);
|
|
|
|
return T();
|
|
|
|
}
|
|
|
|
|
2017-04-11 20:12:00 +02:00
|
|
|
static int usage() {
|
2017-04-12 20:27:00 +02:00
|
|
|
errs() << "Available subcommands: dump-symtab run\n";
|
2017-04-11 20:12:00 +02:00
|
|
|
return 1;
|
|
|
|
}
|
2016-08-11 16:58:12 +02:00
|
|
|
|
2017-04-11 20:12:00 +02:00
|
|
|
static int run(int argc, char **argv) {
|
2016-08-11 16:58:12 +02:00
|
|
|
cl::ParseCommandLineOptions(argc, argv, "Resolution-based LTO test harness");
|
|
|
|
|
2016-12-01 00:19:05 +01:00
|
|
|
// FIXME: Workaround PR30396 which means that a symbol can appear
|
|
|
|
// more than once if it is defined in module-level assembly and
|
|
|
|
// has a GV declaration. We allow (file, symbol) pairs to have multiple
|
|
|
|
// resolutions and apply them in the order observed.
|
|
|
|
std::map<std::pair<std::string, std::string>, std::list<SymbolResolution>>
|
2016-08-11 16:58:12 +02:00
|
|
|
CommandLineResolutions;
|
|
|
|
for (std::string R : SymbolResolutions) {
|
|
|
|
StringRef Rest = R;
|
|
|
|
StringRef FileName, SymbolName;
|
|
|
|
std::tie(FileName, Rest) = Rest.split(',');
|
|
|
|
if (Rest.empty()) {
|
|
|
|
llvm::errs() << "invalid resolution: " << R << '\n';
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
std::tie(SymbolName, Rest) = Rest.split(',');
|
|
|
|
SymbolResolution Res;
|
|
|
|
for (char C : Rest) {
|
|
|
|
if (C == 'p')
|
|
|
|
Res.Prevailing = true;
|
|
|
|
else if (C == 'l')
|
|
|
|
Res.FinalDefinitionInLinkageUnit = true;
|
|
|
|
else if (C == 'x')
|
|
|
|
Res.VisibleToRegularObj = true;
|
2017-06-05 18:24:25 +02:00
|
|
|
else if (C == 'r')
|
|
|
|
Res.LinkerRedefined = true;
|
2017-03-07 19:15:13 +01:00
|
|
|
else {
|
2016-08-11 16:58:12 +02:00
|
|
|
llvm::errs() << "invalid character " << C << " in resolution: " << R
|
|
|
|
<< '\n';
|
2017-03-07 19:15:13 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2016-08-11 16:58:12 +02:00
|
|
|
}
|
2020-01-28 20:23:46 +01:00
|
|
|
CommandLineResolutions[{std::string(FileName), std::string(SymbolName)}]
|
|
|
|
.push_back(Res);
|
2016-08-11 16:58:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<MemoryBuffer>> MBs;
|
|
|
|
|
|
|
|
Config Conf;
|
2016-12-24 00:54:17 +01:00
|
|
|
Conf.DiagHandler = [](const DiagnosticInfo &DI) {
|
|
|
|
DiagnosticPrinterRawOStream DP(errs());
|
|
|
|
DI.print(DP);
|
|
|
|
errs() << '\n';
|
2018-05-05 01:59:34 +02:00
|
|
|
if (DI.getSeverity() == DS_Error)
|
|
|
|
exit(1);
|
2016-08-11 16:58:12 +02:00
|
|
|
};
|
|
|
|
|
2020-03-04 00:47:43 +01:00
|
|
|
Conf.CPU = codegen::getMCPU();
|
2020-10-14 17:55:55 +02:00
|
|
|
Conf.Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple());
|
2020-03-04 00:47:43 +01:00
|
|
|
Conf.MAttrs = codegen::getMAttrs();
|
|
|
|
if (auto RM = codegen::getExplicitRelocModel())
|
|
|
|
Conf.RelocModel = RM.getValue();
|
|
|
|
Conf.CodeModel = codegen::getExplicitCodeModel();
|
2016-12-08 06:28:30 +01:00
|
|
|
|
2017-08-02 05:03:19 +02:00
|
|
|
Conf.DebugPassManager = DebugPassManager;
|
|
|
|
|
2016-08-11 16:58:12 +02:00
|
|
|
if (SaveTemps)
|
2016-08-18 02:12:33 +02:00
|
|
|
check(Conf.addSaveTemps(OutputFilename + "."),
|
|
|
|
"Config::addSaveTemps failed");
|
2016-08-11 16:58:12 +02:00
|
|
|
|
2017-02-12 04:31:30 +01:00
|
|
|
// Optimization remarks.
|
2019-06-14 18:20:51 +02:00
|
|
|
Conf.RemarksFilename = RemarksFilename;
|
|
|
|
Conf.RemarksPasses = RemarksPasses;
|
|
|
|
Conf.RemarksWithHotness = RemarksWithHotness;
|
2020-11-17 19:37:59 +01:00
|
|
|
Conf.RemarksHotnessThreshold = RemarksHotnessThreshold;
|
2019-06-17 18:06:00 +02:00
|
|
|
Conf.RemarksFormat = RemarksFormat;
|
2017-02-12 04:31:30 +01:00
|
|
|
|
2017-07-29 01:43:22 +02:00
|
|
|
Conf.SampleProfile = SamplePGOFile;
|
2019-02-27 18:24:33 +01:00
|
|
|
Conf.CSIRProfile = CSPGOFile;
|
|
|
|
Conf.RunCSIRInstr = RunCSIRInstr;
|
2017-07-29 01:43:22 +02:00
|
|
|
|
2016-09-07 19:46:16 +02:00
|
|
|
// Run a custom pipeline, if asked for.
|
|
|
|
Conf.OptPipeline = OptPipeline;
|
2016-09-16 23:03:21 +02:00
|
|
|
Conf.AAPipeline = AAPipeline;
|
2016-09-07 19:46:16 +02:00
|
|
|
|
2016-10-31 23:12:21 +01:00
|
|
|
Conf.OptLevel = OptLevel - '0';
|
[ThinLTO] Move -lto-use-new-pm to llvm-lto2, and change it to -use-new-pm.
Summary:
As we teach Clang to use ThinkLTO + new PM, it's good for the users to
inject through Config, instead of setting a flag in the LTOBackend
library. Move the flag to llvm-lto2.
As it moves to llvm-lto2, a new name -use-new-pm seems simpler and as
clear.
Reviewers: davide, tejohnson
Subscribers: mehdi_amini, Prazek, inglorion, eraman, chandlerc, llvm-commits
Differential Revision: https://reviews.llvm.org/D33799
llvm-svn: 304492
2017-06-02 01:13:44 +02:00
|
|
|
Conf.UseNewPM = UseNewPM;
|
2021-01-22 14:13:54 +01:00
|
|
|
Conf.Freestanding = EnableFreestanding;
|
2020-03-26 18:09:13 +01:00
|
|
|
for (auto &PluginFN : PassPlugins)
|
|
|
|
Conf.PassPlugins.push_back(PluginFN);
|
2016-12-08 06:28:30 +01:00
|
|
|
switch (CGOptLevel) {
|
|
|
|
case '0':
|
|
|
|
Conf.CGOptLevel = CodeGenOpt::None;
|
|
|
|
break;
|
|
|
|
case '1':
|
|
|
|
Conf.CGOptLevel = CodeGenOpt::Less;
|
|
|
|
break;
|
|
|
|
case '2':
|
|
|
|
Conf.CGOptLevel = CodeGenOpt::Default;
|
|
|
|
break;
|
|
|
|
case '3':
|
|
|
|
Conf.CGOptLevel = CodeGenOpt::Aggressive;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm::errs() << "invalid cg optimization level: " << CGOptLevel << '\n';
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-03-04 00:47:43 +01:00
|
|
|
if (auto FT = codegen::getExplicitFileType())
|
|
|
|
Conf.CGFileType = FT.getValue();
|
2017-02-15 21:36:36 +01:00
|
|
|
|
2016-12-08 06:28:30 +01:00
|
|
|
Conf.OverrideTriple = OverrideTriple;
|
|
|
|
Conf.DefaultTriple = DefaultTriple;
|
2018-04-20 12:18:36 +02:00
|
|
|
Conf.StatsFile = StatsFile;
|
2020-01-10 05:58:31 +01:00
|
|
|
Conf.PTO.LoopVectorization = Conf.OptLevel > 1;
|
|
|
|
Conf.PTO.SLPVectorization = Conf.OptLevel > 1;
|
2016-10-31 23:12:21 +01:00
|
|
|
|
2016-08-20 01:54:40 +02:00
|
|
|
ThinBackend Backend;
|
|
|
|
if (ThinLTODistributedIndexes)
|
2018-02-22 20:06:15 +01:00
|
|
|
Backend = createWriteIndexesThinBackend(/* OldPrefix */ "",
|
|
|
|
/* NewPrefix */ "",
|
|
|
|
/* ShouldEmitImportsFiles */ true,
|
|
|
|
/* LinkedObjectsFile */ nullptr,
|
|
|
|
/* OnWrite */ {});
|
2016-08-20 01:54:40 +02:00
|
|
|
else
|
2020-03-27 15:20:39 +01:00
|
|
|
Backend = createInProcessThinBackend(
|
|
|
|
llvm::heavyweight_hardware_concurrency(Threads));
|
2016-08-20 01:54:40 +02:00
|
|
|
LTO Lto(std::move(Conf), std::move(Backend));
|
2016-08-11 16:58:12 +02:00
|
|
|
|
|
|
|
bool HasErrors = false;
|
|
|
|
for (std::string F : InputFilenames) {
|
|
|
|
std::unique_ptr<MemoryBuffer> MB = check(MemoryBuffer::getFile(F), F);
|
|
|
|
std::unique_ptr<InputFile> Input =
|
|
|
|
check(InputFile::create(MB->getMemBufferRef()), F);
|
|
|
|
|
|
|
|
std::vector<SymbolResolution> Res;
|
|
|
|
for (const InputFile::Symbol &Sym : Input->symbols()) {
|
2020-01-28 20:23:46 +01:00
|
|
|
auto I = CommandLineResolutions.find({F, std::string(Sym.getName())});
|
2021-02-25 16:51:31 +01:00
|
|
|
// If it isn't found, look for ".", which would have been added
|
2019-08-02 15:10:52 +02:00
|
|
|
// (followed by a hash) when the symbol was promoted during module
|
|
|
|
// splitting if it was defined in one part and used in the other.
|
2021-02-25 16:51:31 +01:00
|
|
|
// Try looking up the symbol name before the suffix.
|
2019-08-02 15:10:52 +02:00
|
|
|
if (I == CommandLineResolutions.end()) {
|
2021-02-25 16:51:31 +01:00
|
|
|
auto SplitName = Sym.getName().rsplit(".");
|
2020-01-28 20:23:46 +01:00
|
|
|
I = CommandLineResolutions.find({F, std::string(SplitName.first)});
|
2019-08-02 15:10:52 +02:00
|
|
|
}
|
2016-08-11 16:58:12 +02:00
|
|
|
if (I == CommandLineResolutions.end()) {
|
|
|
|
llvm::errs() << argv[0] << ": missing symbol resolution for " << F
|
|
|
|
<< ',' << Sym.getName() << '\n';
|
|
|
|
HasErrors = true;
|
|
|
|
} else {
|
2016-12-01 00:19:05 +01:00
|
|
|
Res.push_back(I->second.front());
|
|
|
|
I->second.pop_front();
|
|
|
|
if (I->second.empty())
|
|
|
|
CommandLineResolutions.erase(I);
|
2016-08-11 16:58:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HasErrors)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
MBs.push_back(std::move(MB));
|
|
|
|
check(Lto.add(std::move(Input), Res), F);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!CommandLineResolutions.empty()) {
|
|
|
|
HasErrors = true;
|
|
|
|
for (auto UnusedRes : CommandLineResolutions)
|
|
|
|
llvm::errs() << argv[0] << ": unused symbol resolution for "
|
|
|
|
<< UnusedRes.first.first << ',' << UnusedRes.first.second
|
|
|
|
<< '\n';
|
|
|
|
}
|
|
|
|
if (HasErrors)
|
|
|
|
return 1;
|
|
|
|
|
2016-09-23 23:33:43 +02:00
|
|
|
auto AddStream =
|
|
|
|
[&](size_t Task) -> std::unique_ptr<lto::NativeObjectStream> {
|
2016-08-11 16:58:12 +02:00
|
|
|
std::string Path = OutputFilename + "." + utostr(Task);
|
2016-09-23 23:33:43 +02:00
|
|
|
|
|
|
|
std::error_code EC;
|
2019-08-15 17:54:37 +02:00
|
|
|
auto S = std::make_unique<raw_fd_ostream>(Path, EC, sys::fs::OF_None);
|
2016-09-23 23:33:43 +02:00
|
|
|
check(EC, Path);
|
2019-08-15 17:54:37 +02:00
|
|
|
return std::make_unique<lto::NativeObjectStream>(std::move(S));
|
2016-08-11 16:58:12 +02:00
|
|
|
};
|
|
|
|
|
2018-02-20 21:21:53 +01:00
|
|
|
auto AddBuffer = [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
|
2017-03-17 01:34:07 +01:00
|
|
|
*AddStream(Task)->OS << MB->getBuffer();
|
2016-09-23 23:33:43 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
NativeObjectCache Cache;
|
|
|
|
if (!CacheDir.empty())
|
2017-03-17 01:34:07 +01:00
|
|
|
Cache = check(localCache(CacheDir, AddBuffer), "failed to create cache");
|
2016-09-23 23:33:43 +02:00
|
|
|
|
|
|
|
check(Lto.run(AddStream, Cache), "LTO::run failed");
|
2017-04-11 20:12:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-04-12 20:27:00 +02:00
|
|
|
static int dumpSymtab(int argc, char **argv) {
|
|
|
|
for (StringRef F : make_range(argv + 1, argv + argc)) {
|
2020-01-28 20:23:46 +01:00
|
|
|
std::unique_ptr<MemoryBuffer> MB =
|
|
|
|
check(MemoryBuffer::getFile(F), std::string(F));
|
|
|
|
BitcodeFileContents BFC =
|
|
|
|
check(getBitcodeFileContents(*MB), std::string(F));
|
2017-06-28 01:50:24 +02:00
|
|
|
|
|
|
|
if (BFC.Symtab.size() >= sizeof(irsymtab::storage::Header)) {
|
|
|
|
auto *Hdr = reinterpret_cast<const irsymtab::storage::Header *>(
|
|
|
|
BFC.Symtab.data());
|
|
|
|
outs() << "version: " << Hdr->Version << '\n';
|
|
|
|
if (Hdr->Version == irsymtab::storage::Header::kCurrentVersion)
|
|
|
|
outs() << "producer: " << Hdr->Producer.get(BFC.StrtabForSymtab)
|
|
|
|
<< '\n';
|
|
|
|
}
|
|
|
|
|
2017-04-12 20:27:00 +02:00
|
|
|
std::unique_ptr<InputFile> Input =
|
2020-01-28 20:23:46 +01:00
|
|
|
check(InputFile::create(MB->getMemBufferRef()), std::string(F));
|
2017-04-12 20:27:00 +02:00
|
|
|
|
2017-04-14 04:55:06 +02:00
|
|
|
outs() << "target triple: " << Input->getTargetTriple() << '\n';
|
|
|
|
Triple TT(Input->getTargetTriple());
|
|
|
|
|
2017-04-12 20:27:00 +02:00
|
|
|
outs() << "source filename: " << Input->getSourceFileName() << '\n';
|
2017-04-14 04:55:06 +02:00
|
|
|
|
|
|
|
if (TT.isOSBinFormatCOFF())
|
|
|
|
outs() << "linker opts: " << Input->getCOFFLinkerOpts() << '\n';
|
2017-04-12 20:27:00 +02:00
|
|
|
|
[ELF] Implement Dependent Libraries Feature
This patch implements a limited form of autolinking primarily designed to allow
either the --dependent-library compiler option, or "comment lib" pragmas (
https://docs.microsoft.com/en-us/cpp/preprocessor/comment-c-cpp?view=vs-2017) in
C/C++ e.g. #pragma comment(lib, "foo"), to cause an ELF linker to automatically
add the specified library to the link when processing the input file generated
by the compiler.
Currently this extension is unique to LLVM and LLD. However, care has been taken
to design this feature so that it could be supported by other ELF linkers.
The design goals were to provide:
- A simple linking model for developers to reason about.
- The ability to to override autolinking from the linker command line.
- Source code compatibility, where possible, with "comment lib" pragmas in other
environments (MSVC in particular).
Dependent library support is implemented differently for ELF platforms than on
the other platforms. Primarily this difference is that on ELF we pass the
dependent library specifiers directly to the linker without manipulating them.
This is in contrast to other platforms where they are mapped to a specific
linker option by the compiler. This difference is a result of the greater
variety of ELF linkers and the fact that ELF linkers tend to handle libraries in
a more complicated fashion than on other platforms. This forces us to defer
handling the specifiers to the linker.
In order to achieve a level of source code compatibility with other platforms
we have restricted this feature to work with libraries that meet the following
"reasonable" requirements:
1. There are no competing defined symbols in a given set of libraries, or
if they exist, the program owner doesn't care which is linked to their
program.
2. There may be circular dependencies between libraries.
The binary representation is a mergeable string section (SHF_MERGE,
SHF_STRINGS), called .deplibs, with custom type SHT_LLVM_DEPENDENT_LIBRARIES
(0x6fff4c04). The compiler forms this section by concatenating the arguments of
the "comment lib" pragmas and --dependent-library options in the order they are
encountered. Partial (-r, -Ur) links are handled by concatenating .deplibs
sections with the normal mergeable string section rules. As an example, #pragma
comment(lib, "foo") would result in:
.section ".deplibs","MS",@llvm_dependent_libraries,1
.asciz "foo"
For LTO, equivalent information to the contents of a the .deplibs section can be
retrieved by the LLD for bitcode input files.
LLD processes the dependent library specifiers in the following way:
1. Dependent libraries which are found from the specifiers in .deplibs sections
of relocatable object files are added when the linker decides to include that
file (which could itself be in a library) in the link. Dependent libraries
behave as if they were appended to the command line after all other options. As
a consequence the set of dependent libraries are searched last to resolve
symbols.
2. It is an error if a file cannot be found for a given specifier.
3. Any command line options in effect at the end of the command line parsing apply
to the dependent libraries, e.g. --whole-archive.
4. The linker tries to add a library or relocatable object file from each of the
strings in a .deplibs section by; first, handling the string as if it was
specified on the command line; second, by looking for the string in each of the
library search paths in turn; third, by looking for a lib<string>.a or
lib<string>.so (depending on the current mode of the linker) in each of the
library search paths.
5. A new command line option --no-dependent-libraries tells LLD to ignore the
dependent libraries.
Rationale for the above points:
1. Adding the dependent libraries last makes the process simple to understand
from a developers perspective. All linkers are able to implement this scheme.
2. Error-ing for libraries that are not found seems like better behavior than
failing the link during symbol resolution.
3. It seems useful for the user to be able to apply command line options which
will affect all of the dependent libraries. There is a potential problem of
surprise for developers, who might not realize that these options would apply
to these "invisible" input files; however, despite the potential for surprise,
this is easy for developers to reason about and gives developers the control
that they may require.
4. This algorithm takes into account all of the different ways that ELF linkers
find input files. The different search methods are tried by the linker in most
obvious to least obvious order.
5. I considered adding finer grained control over which dependent libraries were
ignored (e.g. MSVC has /nodefaultlib:<library>); however, I concluded that this
is not necessary: if finer control is required developers can fall back to using
the command line directly.
RFC thread: http://lists.llvm.org/pipermail/llvm-dev/2019-March/131004.html.
Differential Revision: https://reviews.llvm.org/D60274
llvm-svn: 360984
2019-05-17 05:44:15 +02:00
|
|
|
if (TT.isOSBinFormatELF()) {
|
|
|
|
outs() << "dependent libraries:";
|
|
|
|
for (auto L : Input->getDependentLibraries())
|
|
|
|
outs() << " \"" << L << "\"";
|
|
|
|
outs() << '\n';
|
|
|
|
}
|
|
|
|
|
2021-07-20 22:22:00 +02:00
|
|
|
ArrayRef<std::pair<StringRef, Comdat::SelectionKind>> ComdatTable =
|
|
|
|
Input->getComdatTable();
|
2017-04-12 20:27:00 +02:00
|
|
|
for (const InputFile::Symbol &Sym : Input->symbols()) {
|
|
|
|
switch (Sym.getVisibility()) {
|
|
|
|
case GlobalValue::HiddenVisibility:
|
|
|
|
outs() << 'H';
|
|
|
|
break;
|
|
|
|
case GlobalValue::ProtectedVisibility:
|
|
|
|
outs() << 'P';
|
|
|
|
break;
|
|
|
|
case GlobalValue::DefaultVisibility:
|
|
|
|
outs() << 'D';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto PrintBool = [&](char C, bool B) { outs() << (B ? C : '-'); };
|
|
|
|
PrintBool('U', Sym.isUndefined());
|
|
|
|
PrintBool('C', Sym.isCommon());
|
|
|
|
PrintBool('W', Sym.isWeak());
|
|
|
|
PrintBool('I', Sym.isIndirect());
|
|
|
|
PrintBool('O', Sym.canBeOmittedFromSymbolTable());
|
|
|
|
PrintBool('T', Sym.isTLS());
|
2017-04-13 18:24:14 +02:00
|
|
|
PrintBool('X', Sym.isExecutable());
|
2017-04-12 20:27:00 +02:00
|
|
|
outs() << ' ' << Sym.getName() << '\n';
|
|
|
|
|
|
|
|
if (Sym.isCommon())
|
2017-04-13 18:24:14 +02:00
|
|
|
outs() << " size " << Sym.getCommonSize() << " align "
|
2017-04-12 20:27:00 +02:00
|
|
|
<< Sym.getCommonAlignment() << '\n';
|
|
|
|
|
|
|
|
int Comdat = Sym.getComdatIndex();
|
2021-07-20 22:22:00 +02:00
|
|
|
if (Comdat != -1) {
|
|
|
|
outs() << " comdat ";
|
|
|
|
switch (ComdatTable[Comdat].second) {
|
|
|
|
case Comdat::Any:
|
|
|
|
outs() << "any";
|
|
|
|
break;
|
|
|
|
case Comdat::ExactMatch:
|
|
|
|
outs() << "exactmatch";
|
|
|
|
break;
|
|
|
|
case Comdat::Largest:
|
|
|
|
outs() << "largest";
|
|
|
|
break;
|
|
|
|
case Comdat::NoDeduplicate:
|
|
|
|
outs() << "nodeduplicate";
|
|
|
|
break;
|
|
|
|
case Comdat::SameSize:
|
|
|
|
outs() << "samesize";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
outs() << ' ' << ComdatTable[Comdat].first << '\n';
|
|
|
|
}
|
2017-04-12 20:27:00 +02:00
|
|
|
|
2017-04-14 04:55:06 +02:00
|
|
|
if (TT.isOSBinFormatCOFF() && Sym.isWeak() && Sym.isIndirect())
|
2017-04-13 18:24:14 +02:00
|
|
|
outs() << " fallback " << Sym.getCOFFWeakExternalFallback() << '\n';
|
2017-07-25 21:42:32 +02:00
|
|
|
|
|
|
|
if (!Sym.getSectionName().empty())
|
|
|
|
outs() << " section " << Sym.getSectionName() << "\n";
|
2017-04-12 20:27:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
outs() << '\n';
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-04-11 20:12:00 +02:00
|
|
|
int main(int argc, char **argv) {
|
2018-10-16 19:37:45 +02:00
|
|
|
InitLLVM X(argc, argv);
|
2017-04-11 20:12:00 +02:00
|
|
|
InitializeAllTargets();
|
|
|
|
InitializeAllTargetMCs();
|
|
|
|
InitializeAllAsmPrinters();
|
|
|
|
InitializeAllAsmParsers();
|
|
|
|
|
|
|
|
// FIXME: This should use llvm::cl subcommands, but it isn't currently
|
|
|
|
// possible to pass an argument not associated with a subcommand to a
|
[ThinLTO] Move -lto-use-new-pm to llvm-lto2, and change it to -use-new-pm.
Summary:
As we teach Clang to use ThinkLTO + new PM, it's good for the users to
inject through Config, instead of setting a flag in the LTOBackend
library. Move the flag to llvm-lto2.
As it moves to llvm-lto2, a new name -use-new-pm seems simpler and as
clear.
Reviewers: davide, tejohnson
Subscribers: mehdi_amini, Prazek, inglorion, eraman, chandlerc, llvm-commits
Differential Revision: https://reviews.llvm.org/D33799
llvm-svn: 304492
2017-06-02 01:13:44 +02:00
|
|
|
// subcommand (e.g. -use-new-pm).
|
2017-04-11 20:12:00 +02:00
|
|
|
if (argc < 2)
|
|
|
|
return usage();
|
|
|
|
|
|
|
|
StringRef Subcommand = argv[1];
|
|
|
|
// Ensure that argv[0] is correct after adjusting argv/argc.
|
|
|
|
argv[1] = argv[0];
|
2017-04-12 20:27:00 +02:00
|
|
|
if (Subcommand == "dump-symtab")
|
|
|
|
return dumpSymtab(argc - 1, argv + 1);
|
2017-04-11 20:12:00 +02:00
|
|
|
if (Subcommand == "run")
|
|
|
|
return run(argc - 1, argv + 1);
|
|
|
|
return usage();
|
2016-08-11 16:58:12 +02:00
|
|
|
}
|