[clang-repl] [codegen] Reduce the state in TBAA. NFC for static compilation. (#98138)
[llvm-project.git] / bolt / tools / driver / llvm-bolt.cpp
blob9b03524e9f18e8771f38a7926b3b9c50945d1153
1 //===- bolt/tools/driver/llvm-bolt.cpp - Feedback-directed optimizer ------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This is a binary optimizer that will take 'perf' output and change
10 // basic block layout for better performance (a.k.a. branch straightening),
11 // plus some other optimizations that are better performed on a binary.
13 //===----------------------------------------------------------------------===//
15 #include "bolt/Profile/DataAggregator.h"
16 #include "bolt/Rewrite/MachORewriteInstance.h"
17 #include "bolt/Rewrite/RewriteInstance.h"
18 #include "bolt/Utils/CommandLineOpts.h"
19 #include "llvm/MC/TargetRegistry.h"
20 #include "llvm/Object/Binary.h"
21 #include "llvm/Support/CommandLine.h"
22 #include "llvm/Support/Errc.h"
23 #include "llvm/Support/Error.h"
24 #include "llvm/Support/ManagedStatic.h"
25 #include "llvm/Support/Path.h"
26 #include "llvm/Support/PrettyStackTrace.h"
27 #include "llvm/Support/Signals.h"
28 #include "llvm/Support/TargetSelect.h"
30 #define DEBUG_TYPE "bolt"
32 using namespace llvm;
33 using namespace object;
34 using namespace bolt;
36 namespace opts {
38 static cl::OptionCategory *BoltCategories[] = {&BoltCategory,
39 &BoltOptCategory,
40 &BoltRelocCategory,
41 &BoltInstrCategory,
42 &BoltOutputCategory};
44 static cl::OptionCategory *BoltDiffCategories[] = {&BoltDiffCategory};
46 static cl::OptionCategory *Perf2BoltCategories[] = {&AggregatorCategory,
47 &BoltOutputCategory};
49 static cl::opt<std::string> InputFilename(cl::Positional,
50 cl::desc("<executable>"),
51 cl::Required, cl::cat(BoltCategory),
52 cl::sub(cl::SubCommand::getAll()));
54 static cl::opt<std::string>
55 InputDataFilename("data",
56 cl::desc("<data file>"),
57 cl::Optional,
58 cl::cat(BoltCategory));
60 static cl::alias
61 BoltProfile("b",
62 cl::desc("alias for -data"),
63 cl::aliasopt(InputDataFilename),
64 cl::cat(BoltCategory));
66 cl::opt<std::string>
67 LogFile("log-file",
68 cl::desc("redirect journaling to a file instead of stdout/stderr"),
69 cl::Hidden, cl::cat(BoltCategory));
71 static cl::opt<std::string>
72 InputDataFilename2("data2",
73 cl::desc("<data file>"),
74 cl::Optional,
75 cl::cat(BoltCategory));
77 static cl::opt<std::string>
78 InputFilename2(
79 cl::Positional,
80 cl::desc("<executable>"),
81 cl::Optional,
82 cl::cat(BoltDiffCategory));
84 } // namespace opts
86 static StringRef ToolName;
88 static void report_error(StringRef Message, std::error_code EC) {
89 assert(EC);
90 errs() << ToolName << ": '" << Message << "': " << EC.message() << ".\n";
91 exit(1);
94 static void report_error(StringRef Message, Error E) {
95 assert(E);
96 errs() << ToolName << ": '" << Message << "': " << toString(std::move(E))
97 << ".\n";
98 exit(1);
101 static void printBoltRevision(llvm::raw_ostream &OS) {
102 OS << "BOLT revision " << BoltRevision << "\n";
105 void perf2boltMode(int argc, char **argv) {
106 cl::HideUnrelatedOptions(ArrayRef(opts::Perf2BoltCategories));
107 cl::AddExtraVersionPrinter(printBoltRevision);
108 cl::ParseCommandLineOptions(
109 argc, argv,
110 "perf2bolt - BOLT data aggregator\n"
111 "\nEXAMPLE: perf2bolt -p=perf.data executable -o data.fdata\n");
112 if (opts::PerfData.empty()) {
113 errs() << ToolName << ": expected -perfdata=<filename> option.\n";
114 exit(1);
116 if (!opts::InputDataFilename.empty()) {
117 errs() << ToolName << ": unknown -data option.\n";
118 exit(1);
120 if (!sys::fs::exists(opts::PerfData))
121 report_error(opts::PerfData, errc::no_such_file_or_directory);
122 if (!DataAggregator::checkPerfDataMagic(opts::PerfData)) {
123 errs() << ToolName << ": '" << opts::PerfData
124 << "': expected valid perf.data file.\n";
125 exit(1);
127 if (opts::OutputFilename.empty()) {
128 errs() << ToolName << ": expected -o=<output file> option.\n";
129 exit(1);
131 opts::AggregateOnly = true;
134 void boltDiffMode(int argc, char **argv) {
135 cl::HideUnrelatedOptions(ArrayRef(opts::BoltDiffCategories));
136 cl::AddExtraVersionPrinter(printBoltRevision);
137 cl::ParseCommandLineOptions(
138 argc, argv,
139 "llvm-boltdiff - BOLT binary diff tool\n"
140 "\nEXAMPLE: llvm-boltdiff -data=a.fdata -data2=b.fdata exec1 exec2\n");
141 if (opts::InputDataFilename2.empty()) {
142 errs() << ToolName << ": expected -data2=<filename> option.\n";
143 exit(1);
145 if (opts::InputDataFilename.empty()) {
146 errs() << ToolName << ": expected -data=<filename> option.\n";
147 exit(1);
149 if (opts::InputFilename2.empty()) {
150 errs() << ToolName << ": expected second binary name.\n";
151 exit(1);
153 if (opts::InputFilename.empty()) {
154 errs() << ToolName << ": expected binary.\n";
155 exit(1);
157 opts::DiffOnly = true;
160 void boltMode(int argc, char **argv) {
161 cl::HideUnrelatedOptions(ArrayRef(opts::BoltCategories));
162 // Register the target printer for --version.
163 cl::AddExtraVersionPrinter(printBoltRevision);
164 cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
166 cl::ParseCommandLineOptions(argc, argv,
167 "BOLT - Binary Optimization and Layout Tool\n");
169 if (opts::OutputFilename.empty()) {
170 errs() << ToolName << ": expected -o=<output file> option.\n";
171 exit(1);
175 static std::string GetExecutablePath(const char *Argv0) {
176 SmallString<256> ExecutablePath(Argv0);
177 // Do a PATH lookup if Argv0 isn't a valid path.
178 if (!llvm::sys::fs::exists(ExecutablePath))
179 if (llvm::ErrorOr<std::string> P =
180 llvm::sys::findProgramByName(ExecutablePath))
181 ExecutablePath = *P;
182 return std::string(ExecutablePath);
185 int main(int argc, char **argv) {
186 // Print a stack trace if we signal out.
187 sys::PrintStackTraceOnErrorSignal(argv[0]);
188 PrettyStackTraceProgram X(argc, argv);
190 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
192 std::string ToolPath = GetExecutablePath(argv[0]);
194 // Initialize targets and assembly printers/parsers.
195 llvm::InitializeAllTargetInfos();
196 llvm::InitializeAllTargetMCs();
197 llvm::InitializeAllAsmParsers();
198 llvm::InitializeAllDisassemblers();
200 llvm::InitializeAllTargets();
201 llvm::InitializeAllAsmPrinters();
203 ToolName = argv[0];
205 if (llvm::sys::path::filename(ToolName) == "perf2bolt")
206 perf2boltMode(argc, argv);
207 else if (llvm::sys::path::filename(ToolName) == "llvm-boltdiff")
208 boltDiffMode(argc, argv);
209 else
210 boltMode(argc, argv);
212 if (!sys::fs::exists(opts::InputFilename))
213 report_error(opts::InputFilename, errc::no_such_file_or_directory);
215 // Initialize journaling streams
216 raw_ostream *BOLTJournalOut = &outs();
217 raw_ostream *BOLTJournalErr = &errs();
218 // RAII obj to keep log file open throughout execution
219 std::unique_ptr<raw_fd_ostream> LogFileStream;
220 if (!opts::LogFile.empty()) {
221 std::error_code LogEC;
222 LogFileStream = std::make_unique<raw_fd_ostream>(
223 opts::LogFile, LogEC, sys::fs::OpenFlags::OF_None);
224 if (LogEC) {
225 errs() << "BOLT-ERROR: cannot open requested log file for writing: "
226 << LogEC.message() << "\n";
227 exit(1);
229 BOLTJournalOut = LogFileStream.get();
230 BOLTJournalErr = LogFileStream.get();
233 // Attempt to open the binary.
234 if (!opts::DiffOnly) {
235 Expected<OwningBinary<Binary>> BinaryOrErr =
236 createBinary(opts::InputFilename);
237 if (Error E = BinaryOrErr.takeError())
238 report_error(opts::InputFilename, std::move(E));
239 Binary &Binary = *BinaryOrErr.get().getBinary();
241 if (auto *e = dyn_cast<ELFObjectFileBase>(&Binary)) {
242 auto RIOrErr = RewriteInstance::create(e, argc, argv, ToolPath,
243 *BOLTJournalOut, *BOLTJournalErr);
244 if (Error E = RIOrErr.takeError())
245 report_error(opts::InputFilename, std::move(E));
246 RewriteInstance &RI = *RIOrErr.get();
247 if (!opts::PerfData.empty()) {
248 if (!opts::AggregateOnly) {
249 errs() << ToolName
250 << ": WARNING: reading perf data directly is unsupported, "
251 "please use "
252 "-aggregate-only or perf2bolt.\n!!! Proceed on your own "
253 "risk. !!!\n";
255 if (Error E = RI.setProfile(opts::PerfData))
256 report_error(opts::PerfData, std::move(E));
258 if (!opts::InputDataFilename.empty()) {
259 if (Error E = RI.setProfile(opts::InputDataFilename))
260 report_error(opts::InputDataFilename, std::move(E));
262 if (opts::AggregateOnly && opts::PerfData.empty()) {
263 errs() << ToolName << ": missing required -perfdata option.\n";
264 exit(1);
267 if (Error E = RI.run())
268 report_error(opts::InputFilename, std::move(E));
269 } else if (auto *O = dyn_cast<MachOObjectFile>(&Binary)) {
270 auto MachORIOrErr = MachORewriteInstance::create(O, ToolPath);
271 if (Error E = MachORIOrErr.takeError())
272 report_error(opts::InputFilename, std::move(E));
273 MachORewriteInstance &MachORI = *MachORIOrErr.get();
275 if (!opts::InputDataFilename.empty())
276 if (Error E = MachORI.setProfile(opts::InputDataFilename))
277 report_error(opts::InputDataFilename, std::move(E));
279 MachORI.run();
280 } else {
281 report_error(opts::InputFilename, object_error::invalid_file_type);
284 return EXIT_SUCCESS;
287 // Bolt-diff
288 Expected<OwningBinary<Binary>> BinaryOrErr1 =
289 createBinary(opts::InputFilename);
290 Expected<OwningBinary<Binary>> BinaryOrErr2 =
291 createBinary(opts::InputFilename2);
292 if (Error E = BinaryOrErr1.takeError())
293 report_error(opts::InputFilename, std::move(E));
294 if (Error E = BinaryOrErr2.takeError())
295 report_error(opts::InputFilename2, std::move(E));
296 Binary &Binary1 = *BinaryOrErr1.get().getBinary();
297 Binary &Binary2 = *BinaryOrErr2.get().getBinary();
298 if (auto *ELFObj1 = dyn_cast<ELFObjectFileBase>(&Binary1)) {
299 if (auto *ELFObj2 = dyn_cast<ELFObjectFileBase>(&Binary2)) {
300 auto RI1OrErr = RewriteInstance::create(ELFObj1, argc, argv, ToolPath);
301 if (Error E = RI1OrErr.takeError())
302 report_error(opts::InputFilename, std::move(E));
303 RewriteInstance &RI1 = *RI1OrErr.get();
304 if (Error E = RI1.setProfile(opts::InputDataFilename))
305 report_error(opts::InputDataFilename, std::move(E));
306 auto RI2OrErr = RewriteInstance::create(ELFObj2, argc, argv, ToolPath);
307 if (Error E = RI2OrErr.takeError())
308 report_error(opts::InputFilename2, std::move(E));
309 RewriteInstance &RI2 = *RI2OrErr.get();
310 if (Error E = RI2.setProfile(opts::InputDataFilename2))
311 report_error(opts::InputDataFilename2, std::move(E));
312 outs() << "BOLT-DIFF: *** Analyzing binary 1: " << opts::InputFilename
313 << "\n";
314 outs() << "BOLT-DIFF: *** Binary 1 fdata: " << opts::InputDataFilename
315 << "\n";
316 if (Error E = RI1.run())
317 report_error(opts::InputFilename, std::move(E));
318 outs() << "BOLT-DIFF: *** Analyzing binary 2: " << opts::InputFilename2
319 << "\n";
320 outs() << "BOLT-DIFF: *** Binary 2 fdata: "
321 << opts::InputDataFilename2 << "\n";
322 if (Error E = RI2.run())
323 report_error(opts::InputFilename2, std::move(E));
324 RI1.compare(RI2);
325 } else {
326 report_error(opts::InputFilename2, object_error::invalid_file_type);
328 } else {
329 report_error(opts::InputFilename, object_error::invalid_file_type);
332 return EXIT_SUCCESS;