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