//===- RemarkCount.cpp ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Count remarks using `instruction-count` for asm-printer remarks and // `annotation-count` for annotation-remarks // //===----------------------------------------------------------------------===// #include "RemarkUtilHelpers.h" #include "RemarkUtilRegistry.h" using namespace llvm; using namespace remarks; using namespace llvm::remarkutil; static cl::SubCommand InstructionCount( "instruction-count", "Function instruction count information (requires asm-printer remarks)"); static cl::SubCommand AnnotationCount("annotation-count", "Collect count information from annotation remarks (uses " "AnnotationRemarksPass)"); namespace instructioncount { INPUT_FORMAT_COMMAND_LINE_OPTIONS(InstructionCount) INPUT_OUTPUT_COMMAND_LINE_OPTIONS(InstructionCount) DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(InstructionCount) } // namespace instructioncount namespace annotationcount { INPUT_FORMAT_COMMAND_LINE_OPTIONS(AnnotationCount) static cl::opt AnnotationTypeToCollect( "annotation-type", cl::desc("annotation-type remark to collect count for"), cl::sub(AnnotationCount)); INPUT_OUTPUT_COMMAND_LINE_OPTIONS(AnnotationCount) DEBUG_LOC_INFO_COMMAND_LINE_OPTIONS(AnnotationCount) } // namespace annotationcount static bool shouldSkipRemark(bool UseDebugLoc, Remark &Remark) { return UseDebugLoc && !Remark.Loc.has_value(); } namespace instructioncount { /// Outputs all instruction count remarks in the file as a CSV. /// \returns Error::success() on success, and an Error otherwise. static Error tryInstructionCount() { // Create the output buffer. auto MaybeOF = getOutputFileWithFlags(OutputFileName, /*Flags = */ sys::fs::OF_TextWithCRLF); if (!MaybeOF) return MaybeOF.takeError(); auto OF = std::move(*MaybeOF); // Create a parser for the user-specified input format. auto MaybeBuf = getInputMemoryBuffer(InputFileName); if (!MaybeBuf) return MaybeBuf.takeError(); auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer()); if (!MaybeParser) return MaybeParser.takeError(); // Emit CSV header. if (UseDebugLoc) OF->os() << "Source,"; OF->os() << "Function,InstructionCount\n"; // Parse all remarks. Whenever we see an instruction count remark, output // the file name and the number of instructions. auto &Parser = **MaybeParser; auto MaybeRemark = Parser.next(); for (; MaybeRemark; MaybeRemark = Parser.next()) { auto &Remark = **MaybeRemark; if (Remark.RemarkName != "InstructionCount") continue; if (shouldSkipRemark(UseDebugLoc, Remark)) continue; auto *InstrCountArg = find_if(Remark.Args, [](const Argument &Arg) { return Arg.Key == "NumInstructions"; }); assert(InstrCountArg != Remark.Args.end() && "Expected instruction count remarks to have a NumInstructions key?"); if (UseDebugLoc) { std::string Loc = Remark.Loc->SourceFilePath.str() + ":" + std::to_string(Remark.Loc->SourceLine) + +":" + std::to_string(Remark.Loc->SourceColumn); OF->os() << Loc << ","; } OF->os() << Remark.FunctionName << "," << InstrCountArg->Val << "\n"; } auto E = MaybeRemark.takeError(); if (!E.isA()) return E; consumeError(std::move(E)); OF->keep(); return Error::success(); } } // namespace instructioncount namespace annotationcount { static Error tryAnnotationCount() { // Create the output buffer. auto MaybeOF = getOutputFileWithFlags(OutputFileName, /*Flags = */ sys::fs::OF_TextWithCRLF); if (!MaybeOF) return MaybeOF.takeError(); auto OF = std::move(*MaybeOF); // Create a parser for the user-specified input format. auto MaybeBuf = getInputMemoryBuffer(InputFileName); if (!MaybeBuf) return MaybeBuf.takeError(); auto MaybeParser = createRemarkParser(InputFormat, (*MaybeBuf)->getBuffer()); if (!MaybeParser) return MaybeParser.takeError(); // Emit CSV header. if (UseDebugLoc) OF->os() << "Source,"; OF->os() << "Function,Count\n"; // Parse all remarks. When we see the specified remark collect the count // information. auto &Parser = **MaybeParser; auto MaybeRemark = Parser.next(); for (; MaybeRemark; MaybeRemark = Parser.next()) { auto &Remark = **MaybeRemark; if (Remark.RemarkName != "AnnotationSummary") continue; if (shouldSkipRemark(UseDebugLoc, Remark)) continue; auto *RemarkNameArg = find_if(Remark.Args, [](const Argument &Arg) { return Arg.Key == "type" && Arg.Val == AnnotationTypeToCollect; }); if (RemarkNameArg == Remark.Args.end()) continue; auto *CountArg = find_if( Remark.Args, [](const Argument &Arg) { return Arg.Key == "count"; }); assert(CountArg != Remark.Args.end() && "Expected annotation-type remark to have a count key?"); if (UseDebugLoc) { std::string Loc = Remark.Loc->SourceFilePath.str() + ":" + std::to_string(Remark.Loc->SourceLine) + +":" + std::to_string(Remark.Loc->SourceColumn); OF->os() << Loc << ","; } OF->os() << Remark.FunctionName << "," << CountArg->Val << "\n"; } auto E = MaybeRemark.takeError(); if (!E.isA()) return E; consumeError(std::move(E)); OF->keep(); return Error::success(); } } // namespace annotationcount static CommandRegistration InstructionCountReg(&InstructionCount, instructioncount::tryInstructionCount); static CommandRegistration Yaml2Bitstream(&AnnotationCount, annotationcount::tryAnnotationCount);