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 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. 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 { 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