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
16using namespace llvm;
17using namespace remarks;
18using namespace llvm::remarkutil;
19
20static cl::SubCommand InstructionCount(
21 "instruction-count",
22 "Function instruction count information (requires asm-printer remarks)");
23static cl::SubCommand
24 AnnotationCount("annotation-count",
25 "Collect count information from annotation remarks (uses "
26 "AnnotationRemarksPass)");
27
28namespace instructioncount {
29INPUT_FORMAT_COMMAND_LINE_OPTIONS(InstructionCount)
30INPUT_OUTPUT_COMMAND_LINE_OPTIONS(InstructionCount)
31DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(InstructionCount)
32} // namespace instructioncount
33
34namespace annotationcount {
35INPUT_FORMAT_COMMAND_LINE_OPTIONS(AnnotationCount)
36static cl::opt<std::string> AnnotationTypeToCollect(
37 "annotation-type", cl::desc("annotation-type remark to collect count for"),
38 cl::sub(AnnotationCount));
39INPUT_OUTPUT_COMMAND_LINE_OPTIONS(AnnotationCount)
40DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(AnnotationCount)
41} // namespace annotationcount
42
43static bool shouldSkipRemark(bool UseDebugLoc, Remark &Remark) {
44 return UseDebugLoc && !Remark.Loc.has_value();
45}
46
47namespace instructioncount {
48/// Outputs all instruction count remarks in the file as a CSV.
49/// \returns Error::success() on success, and an Error otherwise.
50static 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(ParserFormat: InputFormat, Buf: (*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(Range&: Remark.Args, P: [](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(val: Remark.Loc->SourceLine) + +":" +
86 std::to_string(val: 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(Err: std::move(E));
95 OF->keep();
96 return Error::success();
97}
98} // namespace instructioncount
99
100namespace annotationcount {
101static 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(ParserFormat: InputFormat, Buf: (*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(Range&: Remark.Args, P: [](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 Range&: Remark.Args, P: [](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(val: Remark.Loc->SourceLine) + +":" +
141 std::to_string(val: 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(Err: std::move(E));
150 OF->keep();
151 return Error::success();
152}
153} // namespace annotationcount
154
155static CommandRegistration
156 InstructionCountReg(&InstructionCount,
157 instructioncount::tryInstructionCount);
158static CommandRegistration Yaml2Bitstream(&AnnotationCount,
159 annotationcount::tryAnnotationCount);
160