| //===- 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<std::string> 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<EndOfFileError>()) |
| 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<EndOfFileError>()) |
| 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); |