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