blob: b9300b9399075aa4eacdba68964101e66a51429b [file] [log] [blame]
Teresa Johnson9ba95f92016-08-11 14:58:12 +00001//===-- llvm-lto2: test harness for the resolution-based LTO interface ----===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This program takes in a list of bitcode files, links them and performs
11// link-time optimization according to the provided symbol resolutions using the
12// resolution-based LTO interface, and outputs one or more object files.
13//
14// This program is intended to eventually replace llvm-lto which uses the legacy
15// LTO interface.
16//
17//===----------------------------------------------------------------------===//
18
19#include "llvm/LTO/LTO.h"
20#include "llvm/Support/CommandLine.h"
21#include "llvm/Support/TargetSelect.h"
22
23using namespace llvm;
24using namespace lto;
25using namespace object;
26
27static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
28 cl::desc("<input bitcode files>"));
29
30static cl::opt<std::string> OutputFilename("o", cl::Required,
31 cl::desc("Output filename"),
32 cl::value_desc("filename"));
33
34static cl::opt<bool> SaveTemps("save-temps", cl::desc("Save temporary files"));
35
36static cl::list<std::string> SymbolResolutions(
37 "r",
38 cl::desc("Specify a symbol resolution: filename,symbolname,resolution\n"
39 "where \"resolution\" is a sequence (which may be empty) of the\n"
40 "following characters:\n"
41 " p - prevailing: the linker has chosen this definition of the\n"
42 " symbol\n"
43 " l - local: the definition of this symbol is unpreemptable at\n"
44 " runtime and is known to be in this linkage unit\n"
45 " x - externally visible: the definition of this symbol is\n"
46 " visible outside of the LTO unit\n"
47 "A resolution for each symbol must be specified."),
48 cl::ZeroOrMore);
49
50static void check(Error E, std::string Msg) {
51 if (!E)
52 return;
53 handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
54 errs() << "llvm-lto: " << Msg << ": " << EIB.message().c_str() << '\n';
55 });
56 exit(1);
57}
58
59template <typename T> static T check(Expected<T> E, std::string Msg) {
60 if (E)
61 return std::move(*E);
62 check(E.takeError(), Msg);
63 return T();
64}
65
66static void check(std::error_code EC, std::string Msg) {
67 check(errorCodeToError(EC), Msg);
68}
69
70template <typename T> static T check(ErrorOr<T> E, std::string Msg) {
71 if (E)
72 return std::move(*E);
73 check(E.getError(), Msg);
74 return T();
75}
76
77int main(int argc, char **argv) {
78 InitializeAllTargets();
79 InitializeAllTargetMCs();
80 InitializeAllAsmPrinters();
81 InitializeAllAsmParsers();
82
83 cl::ParseCommandLineOptions(argc, argv, "Resolution-based LTO test harness");
84
85 std::map<std::pair<std::string, std::string>, SymbolResolution>
86 CommandLineResolutions;
87 for (std::string R : SymbolResolutions) {
88 StringRef Rest = R;
89 StringRef FileName, SymbolName;
90 std::tie(FileName, Rest) = Rest.split(',');
91 if (Rest.empty()) {
92 llvm::errs() << "invalid resolution: " << R << '\n';
93 return 1;
94 }
95 std::tie(SymbolName, Rest) = Rest.split(',');
96 SymbolResolution Res;
97 for (char C : Rest) {
98 if (C == 'p')
99 Res.Prevailing = true;
100 else if (C == 'l')
101 Res.FinalDefinitionInLinkageUnit = true;
102 else if (C == 'x')
103 Res.VisibleToRegularObj = true;
104 else
105 llvm::errs() << "invalid character " << C << " in resolution: " << R
106 << '\n';
107 }
108 CommandLineResolutions[{FileName, SymbolName}] = Res;
109 }
110
111 std::vector<std::unique_ptr<MemoryBuffer>> MBs;
112
113 Config Conf;
114 Conf.DiagHandler = [](const DiagnosticInfo &) {
115 exit(1);
116 };
117
118 if (SaveTemps)
119 check(Conf.addSaveTemps(OutputFilename), "Config::addSaveTemps failed");
120
121 LTO Lto(std::move(Conf));
122
123 bool HasErrors = false;
124 for (std::string F : InputFilenames) {
125 std::unique_ptr<MemoryBuffer> MB = check(MemoryBuffer::getFile(F), F);
126 std::unique_ptr<InputFile> Input =
127 check(InputFile::create(MB->getMemBufferRef()), F);
128
129 std::vector<SymbolResolution> Res;
130 for (const InputFile::Symbol &Sym : Input->symbols()) {
131 auto I = CommandLineResolutions.find({F, Sym.getName()});
132 if (I == CommandLineResolutions.end()) {
133 llvm::errs() << argv[0] << ": missing symbol resolution for " << F
134 << ',' << Sym.getName() << '\n';
135 HasErrors = true;
136 } else {
137 Res.push_back(I->second);
138 CommandLineResolutions.erase(I);
139 }
140 }
141
142 if (HasErrors)
143 continue;
144
145 MBs.push_back(std::move(MB));
146 check(Lto.add(std::move(Input), Res), F);
147 }
148
149 if (!CommandLineResolutions.empty()) {
150 HasErrors = true;
151 for (auto UnusedRes : CommandLineResolutions)
152 llvm::errs() << argv[0] << ": unused symbol resolution for "
153 << UnusedRes.first.first << ',' << UnusedRes.first.second
154 << '\n';
155 }
156 if (HasErrors)
157 return 1;
158
159 auto AddStream = [&](size_t Task) {
160 std::string Path = OutputFilename + "." + utostr(Task);
161 std::error_code EC;
162 auto S = llvm::make_unique<raw_fd_ostream>(Path, EC, sys::fs::F_None);
163 check(EC, Path);
164 return S;
165 };
166
167 check(Lto.run(AddStream), "LTO::run failed");
168}