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 
hadErr()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:
AnalysisRegionCommentConsumer(AnalysisRegions & R)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:
InstrumentRegionCommentConsumer(llvm::SourceMgr & SM,InstrumentRegions & R,InstrumentManager & IM)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 
getInstrumentManager()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:
MCStreamerWrapper(MCContext & Context,mca::CodeRegions & R)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.
emitInstruction(const MCInst & Inst,const MCSubtargetInfo &)9506c3fb27SDimitry Andric   void emitInstruction(const MCInst &Inst,
9606c3fb27SDimitry Andric                        const MCSubtargetInfo & /* unused */) override {
9706c3fb27SDimitry Andric     Regions.addInstruction(Inst);
9806c3fb27SDimitry Andric   }
9906c3fb27SDimitry Andric 
emitSymbolAttribute(MCSymbol * Symbol,MCSymbolAttr Attribute)10006c3fb27SDimitry Andric   bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
10106c3fb27SDimitry Andric     return true;
10206c3fb27SDimitry Andric   }
10306c3fb27SDimitry Andric 
emitCommonSymbol(MCSymbol * Symbol,uint64_t Size,Align ByteAlignment)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 {}
emitGPRel32Value(const MCExpr * Value)10906c3fb27SDimitry Andric   void emitGPRel32Value(const MCExpr *Value) override {}
beginCOFFSymbolDef(const MCSymbol * Symbol)11006c3fb27SDimitry Andric   void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
emitCOFFSymbolStorageClass(int StorageClass)11106c3fb27SDimitry Andric   void emitCOFFSymbolStorageClass(int StorageClass) override {}
emitCOFFSymbolType(int Type)11206c3fb27SDimitry Andric   void emitCOFFSymbolType(int Type) override {}
endCOFFSymbolDef()11306c3fb27SDimitry Andric   void endCOFFSymbolDef() override {}
11406c3fb27SDimitry Andric 
GetInstructionSequence(unsigned Index)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:
InstrumentMCStreamer(MCContext & Context,mca::InstrumentRegions & R,InstrumentManager & IM)12406c3fb27SDimitry Andric   InstrumentMCStreamer(MCContext &Context, mca::InstrumentRegions &R,
12506c3fb27SDimitry Andric                        InstrumentManager &IM)
12606c3fb27SDimitry Andric       : MCStreamerWrapper(Context, R), IM(IM) {}
12706c3fb27SDimitry Andric 
emitInstruction(const MCInst & Inst,const MCSubtargetInfo & MCSI)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 &>
151bdd1243dSDimitry Andric   parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) = 0;
152bdd1243dSDimitry Andric 
153bdd1243dSDimitry Andric public:
CodeRegionGenerator()154bdd1243dSDimitry Andric   CodeRegionGenerator() {}
155bdd1243dSDimitry Andric   virtual ~CodeRegionGenerator();
156bdd1243dSDimitry Andric };
157bdd1243dSDimitry Andric 
158bdd1243dSDimitry Andric /// Abastract CodeRegionGenerator with AnalysisRegions member
159bdd1243dSDimitry Andric class AnalysisRegionGenerator : public virtual CodeRegionGenerator {
160bdd1243dSDimitry Andric protected:
161bdd1243dSDimitry Andric   AnalysisRegions Regions;
162bdd1243dSDimitry Andric 
163bdd1243dSDimitry Andric public:
AnalysisRegionGenerator(llvm::SourceMgr & SM)164bdd1243dSDimitry Andric   AnalysisRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {}
165bdd1243dSDimitry Andric 
166bdd1243dSDimitry Andric   virtual Expected<const AnalysisRegions &>
167bdd1243dSDimitry Andric   parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP) = 0;
168bdd1243dSDimitry Andric };
169bdd1243dSDimitry Andric 
170bdd1243dSDimitry Andric /// Abstract CodeRegionGenerator with InstrumentRegionsRegions member
171bdd1243dSDimitry Andric class InstrumentRegionGenerator : public virtual CodeRegionGenerator {
172bdd1243dSDimitry Andric protected:
173bdd1243dSDimitry Andric   InstrumentRegions Regions;
174bdd1243dSDimitry Andric 
175bdd1243dSDimitry Andric public:
InstrumentRegionGenerator(llvm::SourceMgr & SM)176bdd1243dSDimitry Andric   InstrumentRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {}
177bdd1243dSDimitry Andric 
178bdd1243dSDimitry Andric   virtual Expected<const InstrumentRegions &>
179bdd1243dSDimitry Andric   parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP) = 0;
180bdd1243dSDimitry Andric };
181bdd1243dSDimitry Andric 
182bdd1243dSDimitry Andric /// This abstract class is responsible for parsing input ASM and
183bdd1243dSDimitry Andric /// generating a CodeRegions instance.
184bdd1243dSDimitry Andric class AsmCodeRegionGenerator : public virtual CodeRegionGenerator {
1850b57cec5SDimitry Andric   const Target &TheTarget;
1860b57cec5SDimitry Andric   const MCAsmInfo &MAI;
1870b57cec5SDimitry Andric   const MCSubtargetInfo &STI;
1880b57cec5SDimitry Andric   const MCInstrInfo &MCII;
1890b57cec5SDimitry Andric   unsigned AssemblerDialect; // This is set during parsing.
1900b57cec5SDimitry Andric 
19106c3fb27SDimitry Andric protected:
19206c3fb27SDimitry Andric   MCContext &Ctx;
19306c3fb27SDimitry Andric 
1940b57cec5SDimitry Andric public:
AsmCodeRegionGenerator(const Target & T,MCContext & C,const MCAsmInfo & A,const MCSubtargetInfo & S,const MCInstrInfo & I)195bdd1243dSDimitry Andric   AsmCodeRegionGenerator(const Target &T, MCContext &C, const MCAsmInfo &A,
196bdd1243dSDimitry Andric                          const MCSubtargetInfo &S, const MCInstrInfo &I)
19706c3fb27SDimitry Andric       : TheTarget(T), MAI(A), STI(S), MCII(I), AssemblerDialect(0), Ctx(C) {}
198bdd1243dSDimitry Andric 
199bdd1243dSDimitry Andric   virtual MCACommentConsumer *getCommentConsumer() = 0;
200bdd1243dSDimitry Andric   virtual CodeRegions &getRegions() = 0;
20106c3fb27SDimitry Andric   virtual MCStreamerWrapper *getMCStreamer() = 0;
2020b57cec5SDimitry Andric 
getAssemblerDialect()2030b57cec5SDimitry Andric   unsigned getAssemblerDialect() const { return AssemblerDialect; }
204fe6060f1SDimitry Andric   Expected<const CodeRegions &>
205fe6060f1SDimitry Andric   parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) override;
2060b57cec5SDimitry Andric };
2070b57cec5SDimitry Andric 
208bdd1243dSDimitry Andric class AsmAnalysisRegionGenerator final : public AnalysisRegionGenerator,
209bdd1243dSDimitry Andric                                          public AsmCodeRegionGenerator {
210bdd1243dSDimitry Andric   AnalysisRegionCommentConsumer CC;
21106c3fb27SDimitry Andric   MCStreamerWrapper Streamer;
212bdd1243dSDimitry Andric 
213bdd1243dSDimitry Andric public:
AsmAnalysisRegionGenerator(const Target & T,llvm::SourceMgr & SM,MCContext & C,const MCAsmInfo & A,const MCSubtargetInfo & S,const MCInstrInfo & I)214bdd1243dSDimitry Andric   AsmAnalysisRegionGenerator(const Target &T, llvm::SourceMgr &SM, MCContext &C,
215bdd1243dSDimitry Andric                              const MCAsmInfo &A, const MCSubtargetInfo &S,
216bdd1243dSDimitry Andric                              const MCInstrInfo &I)
217bdd1243dSDimitry Andric       : AnalysisRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I),
21806c3fb27SDimitry Andric         CC(Regions), Streamer(Ctx, Regions) {}
219bdd1243dSDimitry Andric 
getCommentConsumer()220bdd1243dSDimitry Andric   MCACommentConsumer *getCommentConsumer() override { return &CC; };
getRegions()221bdd1243dSDimitry Andric   CodeRegions &getRegions() override { return Regions; };
getMCStreamer()22206c3fb27SDimitry Andric   MCStreamerWrapper *getMCStreamer() override { return &Streamer; }
223bdd1243dSDimitry Andric 
224bdd1243dSDimitry Andric   Expected<const AnalysisRegions &>
parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> & IP)225bdd1243dSDimitry Andric   parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
226bdd1243dSDimitry Andric     Expected<const CodeRegions &> RegionsOrErr = parseCodeRegions(IP);
227bdd1243dSDimitry Andric     if (!RegionsOrErr)
228bdd1243dSDimitry Andric       return RegionsOrErr.takeError();
229bdd1243dSDimitry Andric     else
230bdd1243dSDimitry Andric       return static_cast<const AnalysisRegions &>(*RegionsOrErr);
231bdd1243dSDimitry Andric   }
232bdd1243dSDimitry Andric 
233bdd1243dSDimitry Andric   Expected<const CodeRegions &>
parseCodeRegions(const std::unique_ptr<MCInstPrinter> & IP)234bdd1243dSDimitry Andric   parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
235bdd1243dSDimitry Andric     return AsmCodeRegionGenerator::parseCodeRegions(IP);
236bdd1243dSDimitry Andric   }
237bdd1243dSDimitry Andric };
238bdd1243dSDimitry Andric 
239bdd1243dSDimitry Andric class AsmInstrumentRegionGenerator final : public InstrumentRegionGenerator,
240bdd1243dSDimitry Andric                                            public AsmCodeRegionGenerator {
241bdd1243dSDimitry Andric   InstrumentRegionCommentConsumer CC;
24206c3fb27SDimitry Andric   InstrumentMCStreamer Streamer;
243bdd1243dSDimitry Andric 
244bdd1243dSDimitry Andric public:
AsmInstrumentRegionGenerator(const Target & T,llvm::SourceMgr & SM,MCContext & C,const MCAsmInfo & A,const MCSubtargetInfo & S,const MCInstrInfo & I,InstrumentManager & IM)245bdd1243dSDimitry Andric   AsmInstrumentRegionGenerator(const Target &T, llvm::SourceMgr &SM,
246bdd1243dSDimitry Andric                                MCContext &C, const MCAsmInfo &A,
247bdd1243dSDimitry Andric                                const MCSubtargetInfo &S, const MCInstrInfo &I,
248bdd1243dSDimitry Andric                                InstrumentManager &IM)
249bdd1243dSDimitry Andric       : InstrumentRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I),
25006c3fb27SDimitry Andric         CC(SM, Regions, IM), Streamer(Ctx, Regions, IM) {}
251bdd1243dSDimitry Andric 
getCommentConsumer()252bdd1243dSDimitry Andric   MCACommentConsumer *getCommentConsumer() override { return &CC; };
getRegions()253bdd1243dSDimitry Andric   CodeRegions &getRegions() override { return Regions; };
getMCStreamer()25406c3fb27SDimitry Andric   MCStreamerWrapper *getMCStreamer() override { return &Streamer; }
255bdd1243dSDimitry Andric 
256bdd1243dSDimitry Andric   Expected<const InstrumentRegions &>
parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> & IP)257bdd1243dSDimitry Andric   parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
258bdd1243dSDimitry Andric     Expected<const CodeRegions &> RegionsOrErr = parseCodeRegions(IP);
259bdd1243dSDimitry Andric     if (!RegionsOrErr)
260bdd1243dSDimitry Andric       return RegionsOrErr.takeError();
261bdd1243dSDimitry Andric     else
262bdd1243dSDimitry Andric       return static_cast<const InstrumentRegions &>(*RegionsOrErr);
263bdd1243dSDimitry Andric   }
264bdd1243dSDimitry Andric 
265bdd1243dSDimitry Andric   Expected<const CodeRegions &>
parseCodeRegions(const std::unique_ptr<MCInstPrinter> & IP)266bdd1243dSDimitry Andric   parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
267bdd1243dSDimitry Andric     return AsmCodeRegionGenerator::parseCodeRegions(IP);
268bdd1243dSDimitry Andric   }
269bdd1243dSDimitry Andric };
270bdd1243dSDimitry Andric 
2710b57cec5SDimitry Andric } // namespace mca
2720b57cec5SDimitry Andric } // namespace llvm
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric #endif // LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H
275