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 shouldSkipRemark(bool UseDebugLoc, Remark &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(InputFormat, (*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 MaybeRemark = Parser.next(); 72 for (; MaybeRemark; MaybeRemark = Parser.next()) { 73 auto &Remark = **MaybeRemark; 74 if (Remark.RemarkName != "InstructionCount") 75 continue; 76 if (shouldSkipRemark(UseDebugLoc, Remark)) 77 continue; 78 auto *InstrCountArg = find_if(Remark.Args, [](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(Remark.Loc->SourceLine) + +":" + 86 std::to_string(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(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(InputFormat, (*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 MaybeRemark = Parser.next(); 123 for (; MaybeRemark; MaybeRemark = Parser.next()) { 124 auto &Remark = **MaybeRemark; 125 if (Remark.RemarkName != "AnnotationSummary") 126 continue; 127 if (shouldSkipRemark(UseDebugLoc, Remark)) 128 continue; 129 auto *RemarkNameArg = find_if(Remark.Args, [](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 Remark.Args, [](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(Remark.Loc->SourceLine) + +":" + 141 std::to_string(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(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