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/AsmLexer.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 hadErr()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: AnalysisRegionCommentConsumer(AnalysisRegions & R)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: InstrumentRegionCommentConsumer(llvm::SourceMgr & SM,InstrumentRegions & R,InstrumentManager & IM)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 getInstrumentManager()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: MCStreamerWrapper(MCContext & Context,mca::CodeRegions & R)91 MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R) 92 : MCStreamer(Context), Regions(R) {} 93 94 // We only want to intercept the emission of new instructions. emitInstruction(const MCInst & Inst,const MCSubtargetInfo &)95 void emitInstruction(const MCInst &Inst, 96 const MCSubtargetInfo & /* unused */) override { 97 Regions.addInstruction(Inst); 98 } 99 emitSymbolAttribute(MCSymbol * Symbol,MCSymbolAttr Attribute)100 bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { 101 return true; 102 } 103 emitCommonSymbol(MCSymbol * Symbol,uint64_t Size,Align ByteAlignment)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 {} beginCOFFSymbolDef(const MCSymbol * Symbol)109 void beginCOFFSymbolDef(const MCSymbol *Symbol) override {} emitCOFFSymbolStorageClass(int StorageClass)110 void emitCOFFSymbolStorageClass(int StorageClass) override {} emitCOFFSymbolType(int Type)111 void emitCOFFSymbolType(int Type) override {} endCOFFSymbolDef()112 void endCOFFSymbolDef() override {} 113 GetInstructionSequence(unsigned Index)114 ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const { 115 return Regions.getInstructionSequence(Index); 116 } 117 }; 118 119 class InstrumentMCStreamer : public MCStreamerWrapper { 120 InstrumentManager &IM; 121 122 public: InstrumentMCStreamer(MCContext & Context,mca::InstrumentRegions & R,InstrumentManager & IM)123 InstrumentMCStreamer(MCContext &Context, mca::InstrumentRegions &R, 124 InstrumentManager &IM) 125 : MCStreamerWrapper(Context, R), IM(IM) {} 126 emitInstruction(const MCInst & Inst,const MCSubtargetInfo & MCSI)127 void emitInstruction(const MCInst &Inst, 128 const MCSubtargetInfo &MCSI) override { 129 MCStreamerWrapper::emitInstruction(Inst, MCSI); 130 131 // We know that Regions is an InstrumentRegions by the constructor. 132 for (UniqueInstrument &I : IM.createInstruments(Inst)) { 133 StringRef InstrumentKind = I.get()->getDesc(); 134 // End InstrumentType region if one is open 135 if (Regions.isRegionActive(InstrumentKind)) 136 Regions.endRegion(InstrumentKind, Inst.getLoc()); 137 // Start new instrumentation region 138 Regions.beginRegion(InstrumentKind, Inst.getLoc(), std::move(I)); 139 } 140 } 141 }; 142 143 /// This abstract class is responsible for parsing the input given to 144 /// the llvm-mca driver, and converting that into a CodeRegions instance. 145 class CodeRegionGenerator { 146 protected: 147 CodeRegionGenerator(const CodeRegionGenerator &) = delete; 148 CodeRegionGenerator &operator=(const CodeRegionGenerator &) = delete; 149 virtual Expected<const CodeRegions &> 150 parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP, 151 bool SkipFailures) = 0; 152 153 public: CodeRegionGenerator()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: AnalysisRegionGenerator(llvm::SourceMgr & SM)164 AnalysisRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {} 165 166 virtual Expected<const AnalysisRegions &> 167 parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP, 168 bool SkipFailures) = 0; 169 }; 170 171 /// Abstract CodeRegionGenerator with InstrumentRegionsRegions member 172 class InstrumentRegionGenerator : public virtual CodeRegionGenerator { 173 protected: 174 InstrumentRegions Regions; 175 176 public: InstrumentRegionGenerator(llvm::SourceMgr & SM)177 InstrumentRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {} 178 179 virtual Expected<const InstrumentRegions &> 180 parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP, 181 bool SkipFailures) = 0; 182 }; 183 184 /// This abstract class is responsible for parsing input ASM and 185 /// generating a CodeRegions instance. 186 class AsmCodeRegionGenerator : public virtual CodeRegionGenerator { 187 const Target &TheTarget; 188 const MCAsmInfo &MAI; 189 const MCSubtargetInfo &STI; 190 const MCInstrInfo &MCII; 191 unsigned AssemblerDialect; // This is set during parsing. 192 193 protected: 194 MCContext &Ctx; 195 196 public: AsmCodeRegionGenerator(const Target & T,MCContext & C,const MCAsmInfo & A,const MCSubtargetInfo & S,const MCInstrInfo & I)197 AsmCodeRegionGenerator(const Target &T, MCContext &C, const MCAsmInfo &A, 198 const MCSubtargetInfo &S, const MCInstrInfo &I) 199 : TheTarget(T), MAI(A), STI(S), MCII(I), AssemblerDialect(0), Ctx(C) {} 200 201 virtual MCACommentConsumer *getCommentConsumer() = 0; 202 virtual CodeRegions &getRegions() = 0; 203 virtual MCStreamerWrapper *getMCStreamer() = 0; 204 getAssemblerDialect()205 unsigned getAssemblerDialect() const { return AssemblerDialect; } 206 Expected<const CodeRegions &> 207 parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP, 208 bool SkipFailures) override; 209 }; 210 211 class AsmAnalysisRegionGenerator final : public AnalysisRegionGenerator, 212 public AsmCodeRegionGenerator { 213 AnalysisRegionCommentConsumer CC; 214 MCStreamerWrapper Streamer; 215 216 public: AsmAnalysisRegionGenerator(const Target & T,llvm::SourceMgr & SM,MCContext & C,const MCAsmInfo & A,const MCSubtargetInfo & S,const MCInstrInfo & I)217 AsmAnalysisRegionGenerator(const Target &T, llvm::SourceMgr &SM, MCContext &C, 218 const MCAsmInfo &A, const MCSubtargetInfo &S, 219 const MCInstrInfo &I) 220 : AnalysisRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I), 221 CC(Regions), Streamer(Ctx, Regions) {} 222 getCommentConsumer()223 MCACommentConsumer *getCommentConsumer() override { return &CC; }; getRegions()224 CodeRegions &getRegions() override { return Regions; }; getMCStreamer()225 MCStreamerWrapper *getMCStreamer() override { return &Streamer; } 226 227 Expected<const AnalysisRegions &> parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> & IP,bool SkipFailures)228 parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP, 229 bool SkipFailures) override { 230 Expected<const CodeRegions &> RegionsOrErr = 231 parseCodeRegions(IP, SkipFailures); 232 if (!RegionsOrErr) 233 return RegionsOrErr.takeError(); 234 else 235 return static_cast<const AnalysisRegions &>(*RegionsOrErr); 236 } 237 238 Expected<const CodeRegions &> parseCodeRegions(const std::unique_ptr<MCInstPrinter> & IP,bool SkipFailures)239 parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP, 240 bool SkipFailures) override { 241 return AsmCodeRegionGenerator::parseCodeRegions(IP, SkipFailures); 242 } 243 }; 244 245 class AsmInstrumentRegionGenerator final : public InstrumentRegionGenerator, 246 public AsmCodeRegionGenerator { 247 InstrumentRegionCommentConsumer CC; 248 InstrumentMCStreamer Streamer; 249 250 public: AsmInstrumentRegionGenerator(const Target & T,llvm::SourceMgr & SM,MCContext & C,const MCAsmInfo & A,const MCSubtargetInfo & S,const MCInstrInfo & I,InstrumentManager & IM)251 AsmInstrumentRegionGenerator(const Target &T, llvm::SourceMgr &SM, 252 MCContext &C, const MCAsmInfo &A, 253 const MCSubtargetInfo &S, const MCInstrInfo &I, 254 InstrumentManager &IM) 255 : InstrumentRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I), 256 CC(SM, Regions, IM), Streamer(Ctx, Regions, IM) {} 257 getCommentConsumer()258 MCACommentConsumer *getCommentConsumer() override { return &CC; }; getRegions()259 CodeRegions &getRegions() override { return Regions; }; getMCStreamer()260 MCStreamerWrapper *getMCStreamer() override { return &Streamer; } 261 262 Expected<const InstrumentRegions &> parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> & IP,bool SkipFailures)263 parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP, 264 bool SkipFailures) override { 265 Expected<const CodeRegions &> RegionsOrErr = 266 parseCodeRegions(IP, SkipFailures); 267 if (!RegionsOrErr) 268 return RegionsOrErr.takeError(); 269 else 270 return static_cast<const InstrumentRegions &>(*RegionsOrErr); 271 } 272 273 Expected<const CodeRegions &> parseCodeRegions(const std::unique_ptr<MCInstPrinter> & IP,bool SkipFailures)274 parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP, 275 bool SkipFailures) override { 276 return AsmCodeRegionGenerator::parseCodeRegions(IP, SkipFailures); 277 } 278 }; 279 280 } // namespace mca 281 } // namespace llvm 282 283 #endif // LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H 284