1 //===- RemarkCount.cpp ----------------------------------------------------===//
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 // Count remarks using `instruction-count` for asm-printer remarks and
10 // `annotation-count` for annotation-remarks
11 //
12 //===----------------------------------------------------------------------===//
13 #include "RemarkUtilHelpers.h"
14 #include "RemarkUtilRegistry.h"
15 
16 using namespace llvm;
17 using namespace remarks;
18 using namespace llvm::remarkutil;
19 
20 static cl::SubCommand InstructionCount(
21     "instruction-count",
22     "Function instruction count information (requires asm-printer remarks)");
23 static cl::SubCommand
24     AnnotationCount("annotation-count",
25                     "Collect count information from annotation remarks (uses "
26                     "AnnotationRemarksPass)");
27 
28 namespace instructioncount {
29 INPUT_FORMAT_COMMAND_LINE_OPTIONS(InstructionCount)
30 INPUT_OUTPUT_COMMAND_LINE_OPTIONS(InstructionCount)
31 DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(InstructionCount)
32 } // namespace instructioncount
33 
34 namespace annotationcount {
35 INPUT_FORMAT_COMMAND_LINE_OPTIONS(AnnotationCount)
36 static cl::opt<std::string> AnnotationTypeToCollect(
37     "annotation-type", cl::desc("annotation-type remark to collect count for"),
38     cl::sub(AnnotationCount));
39 INPUT_OUTPUT_COMMAND_LINE_OPTIONS(AnnotationCount)
40 DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(AnnotationCount)
41 } // namespace annotationcount
42 
shouldSkipRemark(bool UseDebugLoc,Remark & Remark)43 static bool shouldSkipRemark(bool UseDebugLoc, Remark &Remark) {
44   return UseDebugLoc && !Remark.Loc.has_value();
45 }
46 
47 namespace instructioncount {
48 /// Outputs all instruction count remarks in the file as a CSV.
49 /// \returns Error::success() on success, and an Error otherwise.
tryInstructionCount()50 static Error tryInstructionCount() {
51   // Create the output buffer.
52   auto MaybeOF = getOutputFileWithFlags(OutputFileName,
53                                         /*Flags = */ sys::fs::OF_TextWithCRLF);
54   if (!MaybeOF)
55     return MaybeOF.takeError();
56   auto OF = std::move(*MaybeOF);
57   // Create a parser for the user-specified input format.
58   auto MaybeBuf = getInputMemoryBuffer(InputFileName);
59   if (!MaybeBuf)
60     return MaybeBuf.takeError();
61   auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
62   if (!MaybeParser)
63     return MaybeParser.takeError();
64   // Emit CSV header.
65   if (UseDebugLoc)
66     OF->os() << "Source,";
67   OF->os() << "Function,InstructionCount\n";
68   // Parse all remarks. Whenever we see an instruction count remark, output
69   // the file name and the number of instructions.
70   auto &Parser = **MaybeParser;
71   auto MaybeRemark = Parser.next();
72   for (; MaybeRemark; MaybeRemark = Parser.next()) {
73     auto &Remark = **MaybeRemark;
74     if (Remark.RemarkName != "InstructionCount")
75       continue;
76     if (shouldSkipRemark(UseDebugLoc, Remark))
77       continue;
78     auto *InstrCountArg = find_if(Remark.Args, [](const Argument &Arg) {
79       return Arg.Key == "NumInstructions";
80     });
81     assert(InstrCountArg != Remark.Args.end() &&
82            "Expected instruction count remarks to have a NumInstructions key?");
83     if (UseDebugLoc) {
84       std::string Loc = Remark.Loc->SourceFilePath.str() + ":" +
85                         std::to_string(Remark.Loc->SourceLine) + +":" +
86                         std::to_string(Remark.Loc->SourceColumn);
87       OF->os() << Loc << ",";
88     }
89     OF->os() << Remark.FunctionName << "," << InstrCountArg->Val << "\n";
90   }
91   auto E = MaybeRemark.takeError();
92   if (!E.isA<EndOfFileError>())
93     return E;
94   consumeError(std::move(E));
95   OF->keep();
96   return Error::success();
97 }
98 } // namespace instructioncount
99 
100 namespace annotationcount {
tryAnnotationCount()101 static Error tryAnnotationCount() {
102   // Create the output buffer.
103   auto MaybeOF = getOutputFileWithFlags(OutputFileName,
104                                         /*Flags = */ sys::fs::OF_TextWithCRLF);
105   if (!MaybeOF)
106     return MaybeOF.takeError();
107   auto OF = std::move(*MaybeOF);
108   // Create a parser for the user-specified input format.
109   auto MaybeBuf = getInputMemoryBuffer(InputFileName);
110   if (!MaybeBuf)
111     return MaybeBuf.takeError();
112   auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer());
113   if (!MaybeParser)
114     return MaybeParser.takeError();
115   // Emit CSV header.
116   if (UseDebugLoc)
117     OF->os() << "Source,";
118   OF->os() << "Function,Count\n";
119   // Parse all remarks. When we see the specified remark collect the count
120   // information.
121   auto &Parser = **MaybeParser;
122   auto MaybeRemark = Parser.next();
123   for (; MaybeRemark; MaybeRemark = Parser.next()) {
124     auto &Remark = **MaybeRemark;
125     if (Remark.RemarkName != "AnnotationSummary")
126       continue;
127     if (shouldSkipRemark(UseDebugLoc, Remark))
128       continue;
129     auto *RemarkNameArg = find_if(Remark.Args, [](const Argument &Arg) {
130       return Arg.Key == "type" && Arg.Val == AnnotationTypeToCollect;
131     });
132     if (RemarkNameArg == Remark.Args.end())
133       continue;
134     auto *CountArg = find_if(
135         Remark.Args, [](const Argument &Arg) { return Arg.Key == "count"; });
136     assert(CountArg != Remark.Args.end() &&
137            "Expected annotation-type remark to have a count key?");
138     if (UseDebugLoc) {
139       std::string Loc = Remark.Loc->SourceFilePath.str() + ":" +
140                         std::to_string(Remark.Loc->SourceLine) + +":" +
141                         std::to_string(Remark.Loc->SourceColumn);
142       OF->os() << Loc << ",";
143     }
144     OF->os() << Remark.FunctionName << "," << CountArg->Val << "\n";
145   }
146   auto E = MaybeRemark.takeError();
147   if (!E.isA<EndOfFileError>())
148     return E;
149   consumeError(std::move(E));
150   OF->keep();
151   return Error::success();
152 }
153 } // namespace annotationcount
154 
155 static CommandRegistration
156     InstructionCountReg(&InstructionCount,
157                         instructioncount::tryInstructionCount);
158 static CommandRegistration Yaml2Bitstream(&AnnotationCount,
159                                           annotationcount::tryAnnotationCount);
160