10b57cec5SDimitry Andric //===----------------------- CodeRegionGenerator.h --------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// \file 90b57cec5SDimitry Andric /// 100b57cec5SDimitry Andric /// This file declares classes responsible for generating llvm-mca 110b57cec5SDimitry Andric /// CodeRegions from various types of input. llvm-mca only analyzes CodeRegions, 120b57cec5SDimitry Andric /// so the classes here provide the input-to-CodeRegions translation. 130b57cec5SDimitry Andric // 140b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #ifndef LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H 170b57cec5SDimitry Andric #define LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric #include "CodeRegion.h" 200b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h" 210b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 22bdd1243dSDimitry Andric #include "llvm/MC/MCParser/MCAsmLexer.h" 2306c3fb27SDimitry Andric #include "llvm/MC/MCStreamer.h" 240b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h" 25349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h" 26bdd1243dSDimitry Andric #include "llvm/MCA/CustomBehaviour.h" 270b57cec5SDimitry Andric #include "llvm/Support/Error.h" 280b57cec5SDimitry Andric #include "llvm/Support/SourceMgr.h" 290b57cec5SDimitry Andric #include <memory> 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric namespace llvm { 320b57cec5SDimitry Andric namespace mca { 330b57cec5SDimitry Andric 34bdd1243dSDimitry Andric class MCACommentConsumer : public AsmCommentConsumer { 350b57cec5SDimitry Andric protected: 3606c3fb27SDimitry Andric bool FoundError = false; 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric public: 3906c3fb27SDimitry Andric MCACommentConsumer() = default; 40bdd1243dSDimitry Andric 41bdd1243dSDimitry Andric bool hadErr() const { return FoundError; } 420b57cec5SDimitry Andric }; 430b57cec5SDimitry Andric 44bdd1243dSDimitry Andric /// A comment consumer that parses strings. The only valid tokens are strings. 45bdd1243dSDimitry Andric class AnalysisRegionCommentConsumer : public MCACommentConsumer { 46bdd1243dSDimitry Andric AnalysisRegions &Regions; 47bdd1243dSDimitry Andric 48bdd1243dSDimitry Andric public: 49bdd1243dSDimitry Andric AnalysisRegionCommentConsumer(AnalysisRegions &R) : Regions(R) {} 50bdd1243dSDimitry Andric 51bdd1243dSDimitry Andric /// Parses a comment. It begins a new region if it is of the form 52bdd1243dSDimitry Andric /// LLVM-MCA-BEGIN. It ends a region if it is of the form LLVM-MCA-END. 53bdd1243dSDimitry Andric /// Regions can be optionally named if they are of the form 54bdd1243dSDimitry Andric /// LLVM-MCA-BEGIN <name> or LLVM-MCA-END <name>. Subregions are 55bdd1243dSDimitry Andric /// permitted, but a region that begins while another region is active 56bdd1243dSDimitry Andric /// must be ended before the outer region is ended. If thre is only one 57bdd1243dSDimitry Andric /// active region, LLVM-MCA-END does not need to provide a name. 58bdd1243dSDimitry Andric void HandleComment(SMLoc Loc, StringRef CommentText) override; 59bdd1243dSDimitry Andric }; 60bdd1243dSDimitry Andric 61bdd1243dSDimitry Andric /// A comment consumer that parses strings to create InstrumentRegions. 62bdd1243dSDimitry Andric /// The only valid tokens are strings. 63bdd1243dSDimitry Andric class InstrumentRegionCommentConsumer : public MCACommentConsumer { 64bdd1243dSDimitry Andric llvm::SourceMgr &SM; 65bdd1243dSDimitry Andric 66bdd1243dSDimitry Andric InstrumentRegions &Regions; 67bdd1243dSDimitry Andric 68bdd1243dSDimitry Andric InstrumentManager &IM; 69bdd1243dSDimitry Andric 70bdd1243dSDimitry Andric public: 71bdd1243dSDimitry Andric InstrumentRegionCommentConsumer(llvm::SourceMgr &SM, InstrumentRegions &R, 72bdd1243dSDimitry Andric InstrumentManager &IM) 73bdd1243dSDimitry Andric : SM(SM), Regions(R), IM(IM) {} 74bdd1243dSDimitry Andric 75bdd1243dSDimitry Andric /// Parses a comment. It begins a new region if it is of the form 76bdd1243dSDimitry Andric /// LLVM-MCA-<INSTRUMENTATION_TYPE> <data> where INSTRUMENTATION_TYPE 77bdd1243dSDimitry Andric /// is a valid InstrumentKind. If there is already an active 78bdd1243dSDimitry Andric /// region of type INSTRUMENATION_TYPE, then it will end the active 79bdd1243dSDimitry Andric /// one and begin a new one using the new data. 80bdd1243dSDimitry Andric void HandleComment(SMLoc Loc, StringRef CommentText) override; 8106c3fb27SDimitry Andric 8206c3fb27SDimitry Andric InstrumentManager &getInstrumentManager() { return IM; } 8306c3fb27SDimitry Andric }; 8406c3fb27SDimitry Andric 8506c3fb27SDimitry Andric // This class provides the callbacks that occur when parsing input assembly. 8606c3fb27SDimitry Andric class MCStreamerWrapper : public MCStreamer { 8706c3fb27SDimitry Andric protected: 8806c3fb27SDimitry Andric CodeRegions &Regions; 8906c3fb27SDimitry Andric 9006c3fb27SDimitry Andric public: 9106c3fb27SDimitry Andric MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R) 9206c3fb27SDimitry Andric : MCStreamer(Context), Regions(R) {} 9306c3fb27SDimitry Andric 9406c3fb27SDimitry Andric // We only want to intercept the emission of new instructions. 9506c3fb27SDimitry Andric void emitInstruction(const MCInst &Inst, 9606c3fb27SDimitry Andric const MCSubtargetInfo & /* unused */) override { 9706c3fb27SDimitry Andric Regions.addInstruction(Inst); 9806c3fb27SDimitry Andric } 9906c3fb27SDimitry Andric 10006c3fb27SDimitry Andric bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { 10106c3fb27SDimitry Andric return true; 10206c3fb27SDimitry Andric } 10306c3fb27SDimitry Andric 10406c3fb27SDimitry Andric void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, 10506c3fb27SDimitry Andric Align ByteAlignment) override {} 10606c3fb27SDimitry Andric void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, 10706c3fb27SDimitry Andric uint64_t Size = 0, Align ByteAlignment = Align(1), 10806c3fb27SDimitry Andric SMLoc Loc = SMLoc()) override {} 10906c3fb27SDimitry Andric void emitGPRel32Value(const MCExpr *Value) override {} 11006c3fb27SDimitry Andric void beginCOFFSymbolDef(const MCSymbol *Symbol) override {} 11106c3fb27SDimitry Andric void emitCOFFSymbolStorageClass(int StorageClass) override {} 11206c3fb27SDimitry Andric void emitCOFFSymbolType(int Type) override {} 11306c3fb27SDimitry Andric void endCOFFSymbolDef() override {} 11406c3fb27SDimitry Andric 11506c3fb27SDimitry Andric ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const { 11606c3fb27SDimitry Andric return Regions.getInstructionSequence(Index); 11706c3fb27SDimitry Andric } 11806c3fb27SDimitry Andric }; 11906c3fb27SDimitry Andric 12006c3fb27SDimitry Andric class InstrumentMCStreamer : public MCStreamerWrapper { 12106c3fb27SDimitry Andric InstrumentManager &IM; 12206c3fb27SDimitry Andric 12306c3fb27SDimitry Andric public: 12406c3fb27SDimitry Andric InstrumentMCStreamer(MCContext &Context, mca::InstrumentRegions &R, 12506c3fb27SDimitry Andric InstrumentManager &IM) 12606c3fb27SDimitry Andric : MCStreamerWrapper(Context, R), IM(IM) {} 12706c3fb27SDimitry Andric 12806c3fb27SDimitry Andric void emitInstruction(const MCInst &Inst, 12906c3fb27SDimitry Andric const MCSubtargetInfo &MCSI) override { 13006c3fb27SDimitry Andric MCStreamerWrapper::emitInstruction(Inst, MCSI); 13106c3fb27SDimitry Andric 13206c3fb27SDimitry Andric // We know that Regions is an InstrumentRegions by the constructor. 13306c3fb27SDimitry Andric for (UniqueInstrument &I : IM.createInstruments(Inst)) { 13406c3fb27SDimitry Andric StringRef InstrumentKind = I.get()->getDesc(); 13506c3fb27SDimitry Andric // End InstrumentType region if one is open 13606c3fb27SDimitry Andric if (Regions.isRegionActive(InstrumentKind)) 13706c3fb27SDimitry Andric Regions.endRegion(InstrumentKind, Inst.getLoc()); 13806c3fb27SDimitry Andric // Start new instrumentation region 13906c3fb27SDimitry Andric Regions.beginRegion(InstrumentKind, Inst.getLoc(), std::move(I)); 14006c3fb27SDimitry Andric } 14106c3fb27SDimitry Andric } 142bdd1243dSDimitry Andric }; 143bdd1243dSDimitry Andric 144bdd1243dSDimitry Andric /// This abstract class is responsible for parsing the input given to 145bdd1243dSDimitry Andric /// the llvm-mca driver, and converting that into a CodeRegions instance. 146bdd1243dSDimitry Andric class CodeRegionGenerator { 147bdd1243dSDimitry Andric protected: 148bdd1243dSDimitry Andric CodeRegionGenerator(const CodeRegionGenerator &) = delete; 149bdd1243dSDimitry Andric CodeRegionGenerator &operator=(const CodeRegionGenerator &) = delete; 150bdd1243dSDimitry Andric virtual Expected<const CodeRegions &> 151*0fca6ea1SDimitry Andric parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP, 152*0fca6ea1SDimitry Andric bool SkipFailures) = 0; 153bdd1243dSDimitry Andric 154bdd1243dSDimitry Andric public: 155bdd1243dSDimitry Andric CodeRegionGenerator() {} 156bdd1243dSDimitry Andric virtual ~CodeRegionGenerator(); 157bdd1243dSDimitry Andric }; 158bdd1243dSDimitry Andric 159bdd1243dSDimitry Andric /// Abastract CodeRegionGenerator with AnalysisRegions member 160bdd1243dSDimitry Andric class AnalysisRegionGenerator : public virtual CodeRegionGenerator { 161bdd1243dSDimitry Andric protected: 162bdd1243dSDimitry Andric AnalysisRegions Regions; 163bdd1243dSDimitry Andric 164bdd1243dSDimitry Andric public: 165bdd1243dSDimitry Andric AnalysisRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {} 166bdd1243dSDimitry Andric 167bdd1243dSDimitry Andric virtual Expected<const AnalysisRegions &> 168*0fca6ea1SDimitry Andric parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP, 169*0fca6ea1SDimitry Andric bool SkipFailures) = 0; 170bdd1243dSDimitry Andric }; 171bdd1243dSDimitry Andric 172bdd1243dSDimitry Andric /// Abstract CodeRegionGenerator with InstrumentRegionsRegions member 173bdd1243dSDimitry Andric class InstrumentRegionGenerator : public virtual CodeRegionGenerator { 174bdd1243dSDimitry Andric protected: 175bdd1243dSDimitry Andric InstrumentRegions Regions; 176bdd1243dSDimitry Andric 177bdd1243dSDimitry Andric public: 178bdd1243dSDimitry Andric InstrumentRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {} 179bdd1243dSDimitry Andric 180bdd1243dSDimitry Andric virtual Expected<const InstrumentRegions &> 181*0fca6ea1SDimitry Andric parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP, 182*0fca6ea1SDimitry Andric bool SkipFailures) = 0; 183bdd1243dSDimitry Andric }; 184bdd1243dSDimitry Andric 185bdd1243dSDimitry Andric /// This abstract class is responsible for parsing input ASM and 186bdd1243dSDimitry Andric /// generating a CodeRegions instance. 187bdd1243dSDimitry Andric class AsmCodeRegionGenerator : public virtual CodeRegionGenerator { 1880b57cec5SDimitry Andric const Target &TheTarget; 1890b57cec5SDimitry Andric const MCAsmInfo &MAI; 1900b57cec5SDimitry Andric const MCSubtargetInfo &STI; 1910b57cec5SDimitry Andric const MCInstrInfo &MCII; 1920b57cec5SDimitry Andric unsigned AssemblerDialect; // This is set during parsing. 1930b57cec5SDimitry Andric 19406c3fb27SDimitry Andric protected: 19506c3fb27SDimitry Andric MCContext &Ctx; 19606c3fb27SDimitry Andric 1970b57cec5SDimitry Andric public: 198bdd1243dSDimitry Andric AsmCodeRegionGenerator(const Target &T, MCContext &C, const MCAsmInfo &A, 199bdd1243dSDimitry Andric const MCSubtargetInfo &S, const MCInstrInfo &I) 20006c3fb27SDimitry Andric : TheTarget(T), MAI(A), STI(S), MCII(I), AssemblerDialect(0), Ctx(C) {} 201bdd1243dSDimitry Andric 202bdd1243dSDimitry Andric virtual MCACommentConsumer *getCommentConsumer() = 0; 203bdd1243dSDimitry Andric virtual CodeRegions &getRegions() = 0; 20406c3fb27SDimitry Andric virtual MCStreamerWrapper *getMCStreamer() = 0; 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric unsigned getAssemblerDialect() const { return AssemblerDialect; } 207fe6060f1SDimitry Andric Expected<const CodeRegions &> 208*0fca6ea1SDimitry Andric parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP, 209*0fca6ea1SDimitry Andric bool SkipFailures) override; 2100b57cec5SDimitry Andric }; 2110b57cec5SDimitry Andric 212bdd1243dSDimitry Andric class AsmAnalysisRegionGenerator final : public AnalysisRegionGenerator, 213bdd1243dSDimitry Andric public AsmCodeRegionGenerator { 214bdd1243dSDimitry Andric AnalysisRegionCommentConsumer CC; 21506c3fb27SDimitry Andric MCStreamerWrapper Streamer; 216bdd1243dSDimitry Andric 217bdd1243dSDimitry Andric public: 218bdd1243dSDimitry Andric AsmAnalysisRegionGenerator(const Target &T, llvm::SourceMgr &SM, MCContext &C, 219bdd1243dSDimitry Andric const MCAsmInfo &A, const MCSubtargetInfo &S, 220bdd1243dSDimitry Andric const MCInstrInfo &I) 221bdd1243dSDimitry Andric : AnalysisRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I), 22206c3fb27SDimitry Andric CC(Regions), Streamer(Ctx, Regions) {} 223bdd1243dSDimitry Andric 224bdd1243dSDimitry Andric MCACommentConsumer *getCommentConsumer() override { return &CC; }; 225bdd1243dSDimitry Andric CodeRegions &getRegions() override { return Regions; }; 22606c3fb27SDimitry Andric MCStreamerWrapper *getMCStreamer() override { return &Streamer; } 227bdd1243dSDimitry Andric 228bdd1243dSDimitry Andric Expected<const AnalysisRegions &> 229*0fca6ea1SDimitry Andric parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP, 230*0fca6ea1SDimitry Andric bool SkipFailures) override { 231*0fca6ea1SDimitry Andric Expected<const CodeRegions &> RegionsOrErr = 232*0fca6ea1SDimitry Andric parseCodeRegions(IP, SkipFailures); 233bdd1243dSDimitry Andric if (!RegionsOrErr) 234bdd1243dSDimitry Andric return RegionsOrErr.takeError(); 235bdd1243dSDimitry Andric else 236bdd1243dSDimitry Andric return static_cast<const AnalysisRegions &>(*RegionsOrErr); 237bdd1243dSDimitry Andric } 238bdd1243dSDimitry Andric 239bdd1243dSDimitry Andric Expected<const CodeRegions &> 240*0fca6ea1SDimitry Andric parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP, 241*0fca6ea1SDimitry Andric bool SkipFailures) override { 242*0fca6ea1SDimitry Andric return AsmCodeRegionGenerator::parseCodeRegions(IP, SkipFailures); 243bdd1243dSDimitry Andric } 244bdd1243dSDimitry Andric }; 245bdd1243dSDimitry Andric 246bdd1243dSDimitry Andric class AsmInstrumentRegionGenerator final : public InstrumentRegionGenerator, 247bdd1243dSDimitry Andric public AsmCodeRegionGenerator { 248bdd1243dSDimitry Andric InstrumentRegionCommentConsumer CC; 24906c3fb27SDimitry Andric InstrumentMCStreamer Streamer; 250bdd1243dSDimitry Andric 251bdd1243dSDimitry Andric public: 252bdd1243dSDimitry Andric AsmInstrumentRegionGenerator(const Target &T, llvm::SourceMgr &SM, 253bdd1243dSDimitry Andric MCContext &C, const MCAsmInfo &A, 254bdd1243dSDimitry Andric const MCSubtargetInfo &S, const MCInstrInfo &I, 255bdd1243dSDimitry Andric InstrumentManager &IM) 256bdd1243dSDimitry Andric : InstrumentRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I), 25706c3fb27SDimitry Andric CC(SM, Regions, IM), Streamer(Ctx, Regions, IM) {} 258bdd1243dSDimitry Andric 259bdd1243dSDimitry Andric MCACommentConsumer *getCommentConsumer() override { return &CC; }; 260bdd1243dSDimitry Andric CodeRegions &getRegions() override { return Regions; }; 26106c3fb27SDimitry Andric MCStreamerWrapper *getMCStreamer() override { return &Streamer; } 262bdd1243dSDimitry Andric 263bdd1243dSDimitry Andric Expected<const InstrumentRegions &> 264*0fca6ea1SDimitry Andric parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP, 265*0fca6ea1SDimitry Andric bool SkipFailures) override { 266*0fca6ea1SDimitry Andric Expected<const CodeRegions &> RegionsOrErr = 267*0fca6ea1SDimitry Andric parseCodeRegions(IP, SkipFailures); 268bdd1243dSDimitry Andric if (!RegionsOrErr) 269bdd1243dSDimitry Andric return RegionsOrErr.takeError(); 270bdd1243dSDimitry Andric else 271bdd1243dSDimitry Andric return static_cast<const InstrumentRegions &>(*RegionsOrErr); 272bdd1243dSDimitry Andric } 273bdd1243dSDimitry Andric 274bdd1243dSDimitry Andric Expected<const CodeRegions &> 275*0fca6ea1SDimitry Andric parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP, 276*0fca6ea1SDimitry Andric bool SkipFailures) override { 277*0fca6ea1SDimitry Andric return AsmCodeRegionGenerator::parseCodeRegions(IP, SkipFailures); 278bdd1243dSDimitry Andric } 279bdd1243dSDimitry Andric }; 280bdd1243dSDimitry Andric 2810b57cec5SDimitry Andric } // namespace mca 2820b57cec5SDimitry Andric } // namespace llvm 2830b57cec5SDimitry Andric 2840b57cec5SDimitry Andric #endif // LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H 285