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 | |
43 | static bool (bool UseDebugLoc, 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. |
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(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 = Parser.next(); |
72 | for (; MaybeRemark; MaybeRemark = Parser.next()) { |
73 | auto & = **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 | |
100 | namespace annotationcount { |
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(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 = Parser.next(); |
123 | for (; MaybeRemark; MaybeRemark = Parser.next()) { |
124 | auto & = **MaybeRemark; |
125 | if (Remark.RemarkName != "AnnotationSummary" ) |
126 | continue; |
127 | if (shouldSkipRemark(UseDebugLoc, Remark)) |
128 | continue; |
129 | auto * = 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 | |
155 | static CommandRegistration |
156 | InstructionCountReg(&InstructionCount, |
157 | instructioncount::tryInstructionCount); |
158 | static CommandRegistration Yaml2Bitstream(&AnnotationCount, |
159 | annotationcount::tryAnnotationCount); |
160 | |