blob: 0c4bc94d8e4449f728c18e6a7e0bc68b2455cd28 [file] [log] [blame]
Hal Finkel52031b72016-10-05 22:10:35 +00001//===------------------ llvm-opt-report/OptReport.cpp ---------------------===//
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/// \file
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000011/// This file implements a tool that can parse the YAML optimization
Hal Finkel52031b72016-10-05 22:10:35 +000012/// records and generate an optimization summary annotated source listing
13/// report.
14///
15//===----------------------------------------------------------------------===//
16
Hal Finkel5aa02482016-10-05 22:25:33 +000017#include "llvm/Demangle/Demangle.h"
Rui Ueyama197194b2018-04-13 18:26:06 +000018#include "llvm/Support/CommandLine.h"
Hal Finkel52031b72016-10-05 22:10:35 +000019#include "llvm/Support/Error.h"
20#include "llvm/Support/ErrorOr.h"
21#include "llvm/Support/FileSystem.h"
22#include "llvm/Support/Format.h"
Rui Ueyama197194b2018-04-13 18:26:06 +000023#include "llvm/Support/InitLLVM.h"
Hal Finkel52031b72016-10-05 22:10:35 +000024#include "llvm/Support/LineIterator.h"
Hal Finkel52031b72016-10-05 22:10:35 +000025#include "llvm/Support/MemoryBuffer.h"
26#include "llvm/Support/Path.h"
27#include "llvm/Support/Program.h"
Jonas Devlieghere2cd41eb2018-04-21 21:11:59 +000028#include "llvm/Support/WithColor.h"
Hal Finkel52031b72016-10-05 22:10:35 +000029#include "llvm/Support/YAMLTraits.h"
Rui Ueyama197194b2018-04-13 18:26:06 +000030#include "llvm/Support/raw_ostream.h"
Francis Visoiu Mistrih2e76cab2018-10-10 18:43:42 +000031#include "llvm-c/OptRemarks.h"
Hal Finkel5aa02482016-10-05 22:25:33 +000032#include <cstdlib>
33#include <map>
34#include <set>
Hal Finkel52031b72016-10-05 22:10:35 +000035
36using namespace llvm;
37using namespace llvm::yaml;
38
39static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
40
41// Mark all our options with this category, everything else (except for -version
42// and -help) will be hidden.
43static cl::OptionCategory
44 OptReportCategory("llvm-opt-report options");
45
46static cl::opt<std::string>
47 InputFileName(cl::Positional, cl::desc("<input>"), cl::init("-"),
48 cl::cat(OptReportCategory));
49
50static cl::opt<std::string>
51 OutputFileName("o", cl::desc("Output file"), cl::init("-"),
52 cl::cat(OptReportCategory));
53
54static cl::opt<std::string>
55 InputRelDir("r", cl::desc("Root for relative input paths"), cl::init(""),
56 cl::cat(OptReportCategory));
57
58static cl::opt<bool>
59 Succinct("s", cl::desc("Don't include vectorization factors, etc."),
60 cl::init(false), cl::cat(OptReportCategory));
61
Hal Finkel5aa02482016-10-05 22:25:33 +000062static cl::opt<bool>
Hal Finkel16d29e32016-10-07 01:30:59 +000063 NoDemangle("no-demangle", cl::desc("Don't demangle function names"),
64 cl::init(false), cl::cat(OptReportCategory));
Hal Finkel5aa02482016-10-05 22:25:33 +000065
Hal Finkel52031b72016-10-05 22:10:35 +000066namespace {
67// For each location in the source file, the common per-transformation state
68// collected.
69struct OptReportLocationItemInfo {
70 bool Analyzed = false;
71 bool Transformed = false;
72
73 OptReportLocationItemInfo &operator |= (
74 const OptReportLocationItemInfo &RHS) {
75 Analyzed |= RHS.Analyzed;
76 Transformed |= RHS.Transformed;
77
78 return *this;
79 }
Hal Finkel5aa02482016-10-05 22:25:33 +000080
81 bool operator < (const OptReportLocationItemInfo &RHS) const {
82 if (Analyzed < RHS.Analyzed)
83 return true;
84 else if (Analyzed > RHS.Analyzed)
85 return false;
86 else if (Transformed < RHS.Transformed)
87 return true;
88 return false;
89 }
Hal Finkel52031b72016-10-05 22:10:35 +000090};
91
92// The per-location information collected for producing an optimization report.
93struct OptReportLocationInfo {
94 OptReportLocationItemInfo Inlined;
95 OptReportLocationItemInfo Unrolled;
96 OptReportLocationItemInfo Vectorized;
97
98 int VectorizationFactor = 1;
99 int InterleaveCount = 1;
100 int UnrollCount = 1;
101
102 OptReportLocationInfo &operator |= (const OptReportLocationInfo &RHS) {
103 Inlined |= RHS.Inlined;
104 Unrolled |= RHS.Unrolled;
105 Vectorized |= RHS.Vectorized;
106
107 VectorizationFactor =
108 std::max(VectorizationFactor, RHS.VectorizationFactor);
109 InterleaveCount = std::max(InterleaveCount, RHS.InterleaveCount);
110 UnrollCount = std::max(UnrollCount, RHS.UnrollCount);
111
112 return *this;
113 }
Hal Finkel5aa02482016-10-05 22:25:33 +0000114
115 bool operator < (const OptReportLocationInfo &RHS) const {
116 if (Inlined < RHS.Inlined)
117 return true;
118 else if (RHS.Inlined < Inlined)
119 return false;
120 else if (Unrolled < RHS.Unrolled)
121 return true;
122 else if (RHS.Unrolled < Unrolled)
123 return false;
124 else if (Vectorized < RHS.Vectorized)
125 return true;
126 else if (RHS.Vectorized < Vectorized || Succinct)
127 return false;
128 else if (VectorizationFactor < RHS.VectorizationFactor)
129 return true;
130 else if (VectorizationFactor > RHS.VectorizationFactor)
131 return false;
132 else if (InterleaveCount < RHS.InterleaveCount)
133 return true;
134 else if (InterleaveCount > RHS.InterleaveCount)
135 return false;
Hal Finkelfd448402016-10-24 05:07:18 +0000136 else if (UnrollCount < RHS.UnrollCount)
Hal Finkel5aa02482016-10-05 22:25:33 +0000137 return true;
138 return false;
139 }
Hal Finkel52031b72016-10-05 22:10:35 +0000140};
141
Hal Finkel5aa02482016-10-05 22:25:33 +0000142typedef std::map<std::string, std::map<int, std::map<std::string, std::map<int,
143 OptReportLocationInfo>>>> LocationInfoTy;
Hal Finkel52031b72016-10-05 22:10:35 +0000144} // anonymous namespace
145
Francis Visoiu Mistrih2e76cab2018-10-10 18:43:42 +0000146static bool readLocationInfo(LocationInfoTy &LocationInfo) {
147 ErrorOr<std::unique_ptr<MemoryBuffer>> Buf =
148 MemoryBuffer::getFile(InputFileName.c_str());
149 if (std::error_code EC = Buf.getError()) {
150 WithColor::error() << "Can't open file " << InputFileName << ": "
151 << EC.message() << "\n";
152 return false;
153 }
Hal Finkel52031b72016-10-05 22:10:35 +0000154
Francis Visoiu Mistrih2e76cab2018-10-10 18:43:42 +0000155 StringRef Buffer = (*Buf)->getBuffer();
156 LLVMOptRemarkParserRef Parser =
157 LLVMOptRemarkParserCreate(Buffer.data(), Buffer.size());
Hal Finkel52031b72016-10-05 22:10:35 +0000158
Francis Visoiu Mistrih2e76cab2018-10-10 18:43:42 +0000159 LLVMOptRemarkEntry *Remark = nullptr;
160 while ((Remark = LLVMOptRemarkParserGetNext(Parser))) {
161 bool Transformed =
162 StringRef(Remark->RemarkType.Str, Remark->RemarkType.Len) == "!Passed";
163 StringRef Pass(Remark->PassName.Str, Remark->PassName.Len);
164 StringRef File(Remark->DebugLoc.SourceFile.Str,
165 Remark->DebugLoc.SourceFile.Len);
166 StringRef Function(Remark->FunctionName.Str, Remark->FunctionName.Len);
167 uint32_t Line = Remark->DebugLoc.SourceLineNumber;
168 uint32_t Column = Remark->DebugLoc.SourceColumnNumber;
169 ArrayRef<LLVMOptRemarkArg> Args(Remark->Args, Remark->NumArgs);
Hal Finkel52031b72016-10-05 22:10:35 +0000170
171 int VectorizationFactor = 1;
172 int InterleaveCount = 1;
173 int UnrollCount = 1;
174
Francis Visoiu Mistrih2e76cab2018-10-10 18:43:42 +0000175 for (const LLVMOptRemarkArg &Arg : Args) {
176 StringRef ArgKeyName(Arg.Key.Str, Arg.Key.Len);
177 StringRef ArgValue(Arg.Value.Str, Arg.Value.Len);
178 if (ArgKeyName == "VectorizationFactor")
179 ArgValue.getAsInteger(10, VectorizationFactor);
180 else if (ArgKeyName == "InterleaveCount")
181 ArgValue.getAsInteger(10, InterleaveCount);
182 else if (ArgKeyName == "UnrollCount")
183 ArgValue.getAsInteger(10, UnrollCount);
Hal Finkel52031b72016-10-05 22:10:35 +0000184 }
185
186 if (Line < 1 || File.empty())
187 continue;
188
189 // We track information on both actual and potential transformations. This
190 // way, if there are multiple possible things on a line that are, or could
191 // have been transformed, we can indicate that explicitly in the output.
Hal Finkel4d6f3082016-10-06 11:58:52 +0000192 auto UpdateLLII = [Transformed](OptReportLocationItemInfo &LLII) {
Hal Finkel52031b72016-10-05 22:10:35 +0000193 LLII.Analyzed = true;
Hal Finkel4d6f3082016-10-06 11:58:52 +0000194 if (Transformed)
Hal Finkel52031b72016-10-05 22:10:35 +0000195 LLII.Transformed = true;
Hal Finkel52031b72016-10-05 22:10:35 +0000196 };
197
198 if (Pass == "inline") {
Hal Finkel5aa02482016-10-05 22:25:33 +0000199 auto &LI = LocationInfo[File][Line][Function][Column];
Hal Finkel4d6f3082016-10-06 11:58:52 +0000200 UpdateLLII(LI.Inlined);
Hal Finkel52031b72016-10-05 22:10:35 +0000201 } else if (Pass == "loop-unroll") {
Hal Finkel5aa02482016-10-05 22:25:33 +0000202 auto &LI = LocationInfo[File][Line][Function][Column];
Hal Finkel4d6f3082016-10-06 11:58:52 +0000203 LI.UnrollCount = UnrollCount;
204 UpdateLLII(LI.Unrolled);
Hal Finkel52031b72016-10-05 22:10:35 +0000205 } else if (Pass == "loop-vectorize") {
Hal Finkel5aa02482016-10-05 22:25:33 +0000206 auto &LI = LocationInfo[File][Line][Function][Column];
Hal Finkel4d6f3082016-10-06 11:58:52 +0000207 LI.VectorizationFactor = VectorizationFactor;
208 LI.InterleaveCount = InterleaveCount;
209 UpdateLLII(LI.Vectorized);
Hal Finkel52031b72016-10-05 22:10:35 +0000210 }
211 }
Hal Finkel52031b72016-10-05 22:10:35 +0000212
Francis Visoiu Mistrih2e76cab2018-10-10 18:43:42 +0000213 bool HasError = LLVMOptRemarkParserHasError(Parser);
214 if (HasError)
215 WithColor::error() << LLVMOptRemarkParserGetErrorMessage(Parser) << "\n";
Hal Finkel52031b72016-10-05 22:10:35 +0000216
Francis Visoiu Mistrih2e76cab2018-10-10 18:43:42 +0000217 LLVMOptRemarkParserDispose(Parser);
218 return !HasError;
Hal Finkel52031b72016-10-05 22:10:35 +0000219}
220
221static bool writeReport(LocationInfoTy &LocationInfo) {
222 std::error_code EC;
223 llvm::raw_fd_ostream OS(OutputFileName, EC,
224 llvm::sys::fs::F_Text);
225 if (EC) {
Jonas Devlieghere2cd41eb2018-04-21 21:11:59 +0000226 WithColor::error() << "Can't open file " << OutputFileName << ": "
227 << EC.message() << "\n";
Hal Finkel52031b72016-10-05 22:10:35 +0000228 return false;
229 }
230
231 bool FirstFile = true;
232 for (auto &FI : LocationInfo) {
233 SmallString<128> FileName(FI.first);
Pavel Labath1ad53ca2019-01-16 09:55:32 +0000234 if (!InputRelDir.empty())
235 sys::fs::make_absolute(InputRelDir, FileName);
Hal Finkel52031b72016-10-05 22:10:35 +0000236
237 const auto &FileInfo = FI.second;
238
239 ErrorOr<std::unique_ptr<MemoryBuffer>> Buf =
240 MemoryBuffer::getFile(FileName);
241 if (std::error_code EC = Buf.getError()) {
Jonas Devlieghere2cd41eb2018-04-21 21:11:59 +0000242 WithColor::error() << "Can't open file " << FileName << ": "
243 << EC.message() << "\n";
Hal Finkel52031b72016-10-05 22:10:35 +0000244 return false;
245 }
246
247 if (FirstFile)
248 FirstFile = false;
249 else
250 OS << "\n";
251
252 OS << "< " << FileName << "\n";
253
254 // Figure out how many characters we need for the vectorization factors
255 // and similar.
256 OptReportLocationInfo MaxLI;
Hal Finkel5aa02482016-10-05 22:25:33 +0000257 for (auto &FLI : FileInfo)
258 for (auto &FI : FLI.second)
259 for (auto &LI : FI.second)
260 MaxLI |= LI.second;
Hal Finkel52031b72016-10-05 22:10:35 +0000261
Hal Finkelf4952802016-10-08 00:26:54 +0000262 bool NothingInlined = !MaxLI.Inlined.Transformed;
263 bool NothingUnrolled = !MaxLI.Unrolled.Transformed;
264 bool NothingVectorized = !MaxLI.Vectorized.Transformed;
265
Hal Finkel52031b72016-10-05 22:10:35 +0000266 unsigned VFDigits = llvm::utostr(MaxLI.VectorizationFactor).size();
267 unsigned ICDigits = llvm::utostr(MaxLI.InterleaveCount).size();
268 unsigned UCDigits = llvm::utostr(MaxLI.UnrollCount).size();
269
270 // Figure out how many characters we need for the line numbers.
271 int64_t NumLines = 0;
272 for (line_iterator LI(*Buf.get(), false); LI != line_iterator(); ++LI)
273 ++NumLines;
274
275 unsigned LNDigits = llvm::utostr(NumLines).size();
276
277 for (line_iterator LI(*Buf.get(), false); LI != line_iterator(); ++LI) {
278 int64_t L = LI.line_number();
Hal Finkel52031b72016-10-05 22:10:35 +0000279 auto LII = FileInfo.find(L);
Hal Finkel52031b72016-10-05 22:10:35 +0000280
Hal Finkel5aa02482016-10-05 22:25:33 +0000281 auto PrintLine = [&](bool PrintFuncName,
282 const std::set<std::string> &FuncNameSet) {
283 OptReportLocationInfo LLI;
284
285 std::map<int, OptReportLocationInfo> ColsInfo;
286 unsigned InlinedCols = 0, UnrolledCols = 0, VectorizedCols = 0;
287
Hal Finkelec85fc52017-01-07 20:21:17 +0000288 if (LII != FileInfo.end() && !FuncNameSet.empty()) {
Hal Finkel5aa02482016-10-05 22:25:33 +0000289 const auto &LineInfo = LII->second;
290
291 for (auto &CI : LineInfo.find(*FuncNameSet.begin())->second) {
292 int Col = CI.first;
293 ColsInfo[Col] = CI.second;
294 InlinedCols += CI.second.Inlined.Analyzed;
295 UnrolledCols += CI.second.Unrolled.Analyzed;
296 VectorizedCols += CI.second.Vectorized.Analyzed;
297 LLI |= CI.second;
298 }
Hal Finkel52031b72016-10-05 22:10:35 +0000299 }
Hal Finkel5aa02482016-10-05 22:25:33 +0000300
301 if (PrintFuncName) {
302 OS << " > ";
303
304 bool FirstFunc = true;
305 for (const auto &FuncName : FuncNameSet) {
306 if (FirstFunc)
307 FirstFunc = false;
308 else
309 OS << ", ";
310
311 bool Printed = false;
Hal Finkel16d29e32016-10-07 01:30:59 +0000312 if (!NoDemangle) {
Hal Finkel5aa02482016-10-05 22:25:33 +0000313 int Status = 0;
314 char *Demangled =
315 itaniumDemangle(FuncName.c_str(), nullptr, nullptr, &Status);
316 if (Demangled && Status == 0) {
317 OS << Demangled;
318 Printed = true;
319 }
320
321 if (Demangled)
322 std::free(Demangled);
323 }
324
325 if (!Printed)
326 OS << FuncName;
Jonas Devlieghere2cd41eb2018-04-21 21:11:59 +0000327 }
Hal Finkel5aa02482016-10-05 22:25:33 +0000328
329 OS << ":\n";
330 }
331
332 // We try to keep the output as concise as possible. If only one thing on
333 // a given line could have been inlined, vectorized, etc. then we can put
334 // the marker on the source line itself. If there are multiple options
335 // then we want to distinguish them by placing the marker for each
336 // transformation on a separate line following the source line. When we
337 // do this, we use a '^' character to point to the appropriate column in
338 // the source line.
339
340 std::string USpaces(Succinct ? 0 : UCDigits, ' ');
341 std::string VSpaces(Succinct ? 0 : VFDigits + ICDigits + 1, ' ');
342
343 auto UStr = [UCDigits](OptReportLocationInfo &LLI) {
344 std::string R;
345 raw_string_ostream RS(R);
Hal Finkel5d41f032016-10-07 02:01:03 +0000346
347 if (!Succinct) {
348 RS << LLI.UnrollCount;
349 RS << std::string(UCDigits - RS.str().size(), ' ');
350 }
351
Hal Finkel5aa02482016-10-05 22:25:33 +0000352 return RS.str();
353 };
354
355 auto VStr = [VFDigits,
356 ICDigits](OptReportLocationInfo &LLI) -> std::string {
357 std::string R;
358 raw_string_ostream RS(R);
Hal Finkel5d41f032016-10-07 02:01:03 +0000359
360 if (!Succinct) {
361 RS << LLI.VectorizationFactor << "," << LLI.InterleaveCount;
362 RS << std::string(VFDigits + ICDigits + 1 - RS.str().size(), ' ');
363 }
364
Hal Finkel5aa02482016-10-05 22:25:33 +0000365 return RS.str();
366 };
367
Hal Finkel47faf3b2016-10-06 11:11:11 +0000368 OS << llvm::format_decimal(L, LNDigits) << " ";
Hal Finkelf4952802016-10-08 00:26:54 +0000369 OS << (LLI.Inlined.Transformed && InlinedCols < 2 ? "I" :
370 (NothingInlined ? "" : " "));
Hal Finkel5aa02482016-10-05 22:25:33 +0000371 OS << (LLI.Unrolled.Transformed && UnrolledCols < 2 ?
Hal Finkelf4952802016-10-08 00:26:54 +0000372 "U" + UStr(LLI) : (NothingUnrolled ? "" : " " + USpaces));
Hal Finkel5aa02482016-10-05 22:25:33 +0000373 OS << (LLI.Vectorized.Transformed && VectorizedCols < 2 ?
Hal Finkelf4952802016-10-08 00:26:54 +0000374 "V" + VStr(LLI) : (NothingVectorized ? "" : " " + VSpaces));
Hal Finkel5aa02482016-10-05 22:25:33 +0000375
376 OS << " | " << *LI << "\n";
377
378 for (auto &J : ColsInfo) {
379 if ((J.second.Inlined.Transformed && InlinedCols > 1) ||
380 (J.second.Unrolled.Transformed && UnrolledCols > 1) ||
381 (J.second.Vectorized.Transformed && VectorizedCols > 1)) {
382 OS << std::string(LNDigits + 1, ' ');
383 OS << (J.second.Inlined.Transformed &&
Hal Finkelf4952802016-10-08 00:26:54 +0000384 InlinedCols > 1 ? "I" : (NothingInlined ? "" : " "));
Hal Finkel5aa02482016-10-05 22:25:33 +0000385 OS << (J.second.Unrolled.Transformed &&
Hal Finkelf4952802016-10-08 00:26:54 +0000386 UnrolledCols > 1 ? "U" + UStr(J.second) :
387 (NothingUnrolled ? "" : " " + USpaces));
Hal Finkel5aa02482016-10-05 22:25:33 +0000388 OS << (J.second.Vectorized.Transformed &&
Hal Finkelf4952802016-10-08 00:26:54 +0000389 VectorizedCols > 1 ? "V" + VStr(J.second) :
390 (NothingVectorized ? "" : " " + VSpaces));
Hal Finkel5aa02482016-10-05 22:25:33 +0000391
392 OS << " | " << std::string(J.first - 1, ' ') << "^\n";
393 }
394 }
395 };
396
397 // We need to figure out if the optimizations for this line were the same
398 // in each function context. If not, then we want to group the similar
399 // function contexts together and display each group separately. If
400 // they're all the same, then we only display the line once without any
401 // additional markings.
402 std::map<std::map<int, OptReportLocationInfo>,
403 std::set<std::string>> UniqueLIs;
404
Hal Finkelec85fc52017-01-07 20:21:17 +0000405 OptReportLocationInfo AllLI;
Hal Finkel5aa02482016-10-05 22:25:33 +0000406 if (LII != FileInfo.end()) {
407 const auto &FuncLineInfo = LII->second;
Hal Finkelec85fc52017-01-07 20:21:17 +0000408 for (const auto &FLII : FuncLineInfo) {
Hal Finkel5aa02482016-10-05 22:25:33 +0000409 UniqueLIs[FLII.second].insert(FLII.first);
Hal Finkelec85fc52017-01-07 20:21:17 +0000410
411 for (const auto &OI : FLII.second)
412 AllLI |= OI.second;
413 }
Hal Finkel52031b72016-10-05 22:10:35 +0000414 }
415
Hal Finkelec85fc52017-01-07 20:21:17 +0000416 bool NothingHappened = !AllLI.Inlined.Transformed &&
417 !AllLI.Unrolled.Transformed &&
418 !AllLI.Vectorized.Transformed;
419 if (UniqueLIs.size() > 1 && !NothingHappened) {
Hal Finkel5aa02482016-10-05 22:25:33 +0000420 OS << " [[\n";
421 for (const auto &FSLI : UniqueLIs)
422 PrintLine(true, FSLI.second);
423 OS << " ]]\n";
424 } else if (UniqueLIs.size() == 1) {
425 PrintLine(false, UniqueLIs.begin()->second);
426 } else {
427 PrintLine(false, std::set<std::string>());
Hal Finkel52031b72016-10-05 22:10:35 +0000428 }
429 }
430 }
431
432 return true;
433}
434
435int main(int argc, const char **argv) {
Rui Ueyama197194b2018-04-13 18:26:06 +0000436 InitLLVM X(argc, argv);
Hal Finkel52031b72016-10-05 22:10:35 +0000437
438 cl::HideUnrelatedOptions(OptReportCategory);
439 cl::ParseCommandLineOptions(
440 argc, argv,
441 "A tool to generate an optimization report from YAML optimization"
442 " record files.\n");
443
Rafael Espindola39c150e2017-09-07 23:30:48 +0000444 if (Help) {
Hal Finkel52031b72016-10-05 22:10:35 +0000445 cl::PrintHelpMessage();
Rafael Espindola39c150e2017-09-07 23:30:48 +0000446 return 0;
447 }
Hal Finkel52031b72016-10-05 22:10:35 +0000448
449 LocationInfoTy LocationInfo;
450 if (!readLocationInfo(LocationInfo))
451 return 1;
452 if (!writeReport(LocationInfo))
Jonas Devlieghere2cd41eb2018-04-21 21:11:59 +0000453 return 1;
Hal Finkel52031b72016-10-05 22:10:35 +0000454
455 return 0;
456}