1 //===----------------------- CodeRegionGenerator.h --------------*- C++ -*-===// 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 /// \file 9 /// 10 /// This file declares classes responsible for generating llvm-mca 11 /// CodeRegions from various types of input. llvm-mca only analyzes CodeRegions, 12 /// so the classes here provide the input-to-CodeRegions translation. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #ifndef LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H 17 #define LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H 18 19 #include "CodeRegion.h" 20 #include "llvm/MC/MCAsmInfo.h" 21 #include "llvm/MC/MCContext.h" 22 #include "llvm/MC/MCParser/MCAsmLexer.h" 23 #include "llvm/MC/MCStreamer.h" 24 #include "llvm/MC/MCSubtargetInfo.h" 25 #include "llvm/MC/TargetRegistry.h" 26 #include "llvm/MCA/CustomBehaviour.h" 27 #include "llvm/Support/Error.h" 28 #include "llvm/Support/SourceMgr.h" 29 #include <memory> 30 31 namespace llvm { 32 namespace mca { 33 34 class MCACommentConsumer : public AsmCommentConsumer { 35 protected: 36 bool FoundError = false; 37 38 public: 39 MCACommentConsumer() = default; 40 41 bool hadErr() const { return FoundError; } 42 }; 43 44 /// A comment consumer that parses strings. The only valid tokens are strings. 45 class AnalysisRegionCommentConsumer : public MCACommentConsumer { 46 AnalysisRegions &Regions; 47 48 public: 49 AnalysisRegionCommentConsumer(AnalysisRegions &R) : Regions(R) {} 50 51 /// Parses a comment. It begins a new region if it is of the form 52 /// LLVM-MCA-BEGIN. It ends a region if it is of the form LLVM-MCA-END. 53 /// Regions can be optionally named if they are of the form 54 /// LLVM-MCA-BEGIN <name> or LLVM-MCA-END <name>. Subregions are 55 /// permitted, but a region that begins while another region is active 56 /// must be ended before the outer region is ended. If thre is only one 57 /// active region, LLVM-MCA-END does not need to provide a name. 58 void HandleComment(SMLoc Loc, StringRef CommentText) override; 59 }; 60 61 /// A comment consumer that parses strings to create InstrumentRegions. 62 /// The only valid tokens are strings. 63 class InstrumentRegionCommentConsumer : public MCACommentConsumer { 64 llvm::SourceMgr &SM; 65 66 InstrumentRegions &Regions; 67 68 InstrumentManager &IM; 69 70 public: 71 InstrumentRegionCommentConsumer(llvm::SourceMgr &SM, InstrumentRegions &R, 72 InstrumentManager &IM) 73 : SM(SM), Regions(R), IM(IM) {} 74 75 /// Parses a comment. It begins a new region if it is of the form 76 /// LLVM-MCA-<INSTRUMENTATION_TYPE> <data> where INSTRUMENTATION_TYPE 77 /// is a valid InstrumentKind. If there is already an active 78 /// region of type INSTRUMENATION_TYPE, then it will end the active 79 /// one and begin a new one using the new data. 80 void HandleComment(SMLoc Loc, StringRef CommentText) override; 81 82 InstrumentManager &getInstrumentManager() { return IM; } 83 }; 84 85 // This class provides the callbacks that occur when parsing input assembly. 86 class MCStreamerWrapper : public MCStreamer { 87 protected: 88 CodeRegions &Regions; 89 90 public: 91 MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R) 92 : MCStreamer(Context), Regions(R) {} 93 94 // We only want to intercept the emission of new instructions. 95 void emitInstruction(const MCInst &Inst, 96 const MCSubtargetInfo & /* unused */) override { 97 Regions.addInstruction(Inst); 98 } 99 100 bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { 101 return true; 102 } 103 104 void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, 105 Align ByteAlignment) override {} 106 void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, 107 uint64_t Size = 0, Align ByteAlignment = Align(1), 108 SMLoc Loc = SMLoc()) override {} 109 void emitGPRel32Value(const MCExpr *Value) override {} 110 void beginCOFFSymbolDef(const MCSymbol *Symbol) override {} 111 void emitCOFFSymbolStorageClass(int StorageClass) override {} 112 void emitCOFFSymbolType(int Type) override {} 113 void endCOFFSymbolDef() override {} 114 115 ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const { 116 return Regions.getInstructionSequence(Index); 117 } 118 }; 119 120 class InstrumentMCStreamer : public MCStreamerWrapper { 121 InstrumentManager &IM; 122 123 public: 124 InstrumentMCStreamer(MCContext &Context, mca::InstrumentRegions &R, 125 InstrumentManager &IM) 126 : MCStreamerWrapper(Context, R), IM(IM) {} 127 128 void emitInstruction(const MCInst &Inst, 129 const MCSubtargetInfo &MCSI) override { 130 MCStreamerWrapper::emitInstruction(Inst, MCSI); 131 132 // We know that Regions is an InstrumentRegions by the constructor. 133 for (UniqueInstrument &I : IM.createInstruments(Inst)) { 134 StringRef InstrumentKind = I.get()->getDesc(); 135 // End InstrumentType region if one is open 136 if (Regions.isRegionActive(InstrumentKind)) 137 Regions.endRegion(InstrumentKind, Inst.getLoc()); 138 // Start new instrumentation region 139 Regions.beginRegion(InstrumentKind, Inst.getLoc(), std::move(I)); 140 } 141 } 142 }; 143 144 /// This abstract class is responsible for parsing the input given to 145 /// the llvm-mca driver, and converting that into a CodeRegions instance. 146 class CodeRegionGenerator { 147 protected: 148 CodeRegionGenerator(const CodeRegionGenerator &) = delete; 149 CodeRegionGenerator &operator=(const CodeRegionGenerator &) = delete; 150 virtual Expected<const CodeRegions &> 151 parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) = 0; 152 153 public: 154 CodeRegionGenerator() {} 155 virtual ~CodeRegionGenerator(); 156 }; 157 158 /// Abastract CodeRegionGenerator with AnalysisRegions member 159 class AnalysisRegionGenerator : public virtual CodeRegionGenerator { 160 protected: 161 AnalysisRegions Regions; 162 163 public: 164 AnalysisRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {} 165 166 virtual Expected<const AnalysisRegions &> 167 parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP) = 0; 168 }; 169 170 /// Abstract CodeRegionGenerator with InstrumentRegionsRegions member 171 class InstrumentRegionGenerator : public virtual CodeRegionGenerator { 172 protected: 173 InstrumentRegions Regions; 174 175 public: 176 InstrumentRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {} 177 178 virtual Expected<const InstrumentRegions &> 179 parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP) = 0; 180 }; 181 182 /// This abstract class is responsible for parsing input ASM and 183 /// generating a CodeRegions instance. 184 class AsmCodeRegionGenerator : public virtual CodeRegionGenerator { 185 const Target &TheTarget; 186 const MCAsmInfo &MAI; 187 const MCSubtargetInfo &STI; 188 const MCInstrInfo &MCII; 189 unsigned AssemblerDialect; // This is set during parsing. 190 191 protected: 192 MCContext &Ctx; 193 194 public: 195 AsmCodeRegionGenerator(const Target &T, MCContext &C, const MCAsmInfo &A, 196 const MCSubtargetInfo &S, const MCInstrInfo &I) 197 : TheTarget(T), MAI(A), STI(S), MCII(I), AssemblerDialect(0), Ctx(C) {} 198 199 virtual MCACommentConsumer *getCommentConsumer() = 0; 200 virtual CodeRegions &getRegions() = 0; 201 virtual MCStreamerWrapper *getMCStreamer() = 0; 202 203 unsigned getAssemblerDialect() const { return AssemblerDialect; } 204 Expected<const CodeRegions &> 205 parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) override; 206 }; 207 208 class AsmAnalysisRegionGenerator final : public AnalysisRegionGenerator, 209 public AsmCodeRegionGenerator { 210 AnalysisRegionCommentConsumer CC; 211 MCStreamerWrapper Streamer; 212 213 public: 214 AsmAnalysisRegionGenerator(const Target &T, llvm::SourceMgr &SM, MCContext &C, 215 const MCAsmInfo &A, const MCSubtargetInfo &S, 216 const MCInstrInfo &I) 217 : AnalysisRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I), 218 CC(Regions), Streamer(Ctx, Regions) {} 219 220 MCACommentConsumer *getCommentConsumer() override { return &CC; }; 221 CodeRegions &getRegions() override { return Regions; }; 222 MCStreamerWrapper *getMCStreamer() override { return &Streamer; } 223 224 Expected<const AnalysisRegions &> 225 parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP) override { 226 Expected<const CodeRegions &> RegionsOrErr = parseCodeRegions(IP); 227 if (!RegionsOrErr) 228 return RegionsOrErr.takeError(); 229 else 230 return static_cast<const AnalysisRegions &>(*RegionsOrErr); 231 } 232 233 Expected<const CodeRegions &> 234 parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) override { 235 return AsmCodeRegionGenerator::parseCodeRegions(IP); 236 } 237 }; 238 239 class AsmInstrumentRegionGenerator final : public InstrumentRegionGenerator, 240 public AsmCodeRegionGenerator { 241 InstrumentRegionCommentConsumer CC; 242 InstrumentMCStreamer Streamer; 243 244 public: 245 AsmInstrumentRegionGenerator(const Target &T, llvm::SourceMgr &SM, 246 MCContext &C, const MCAsmInfo &A, 247 const MCSubtargetInfo &S, const MCInstrInfo &I, 248 InstrumentManager &IM) 249 : InstrumentRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I), 250 CC(SM, Regions, IM), Streamer(Ctx, Regions, IM) {} 251 252 MCACommentConsumer *getCommentConsumer() override { return &CC; }; 253 CodeRegions &getRegions() override { return Regions; }; 254 MCStreamerWrapper *getMCStreamer() override { return &Streamer; } 255 256 Expected<const InstrumentRegions &> 257 parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP) override { 258 Expected<const CodeRegions &> RegionsOrErr = parseCodeRegions(IP); 259 if (!RegionsOrErr) 260 return RegionsOrErr.takeError(); 261 else 262 return static_cast<const InstrumentRegions &>(*RegionsOrErr); 263 } 264 265 Expected<const CodeRegions &> 266 parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) override { 267 return AsmCodeRegionGenerator::parseCodeRegions(IP); 268 } 269 }; 270 271 } // namespace mca 272 } // namespace llvm 273 274 #endif // LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H 275