xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
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 {}
emitGPRel32Value(const MCExpr * Value)109   void emitGPRel32Value(const MCExpr *Value) override {}
beginCOFFSymbolDef(const MCSymbol * Symbol)110   void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
emitCOFFSymbolStorageClass(int StorageClass)111   void emitCOFFSymbolStorageClass(int StorageClass) override {}
emitCOFFSymbolType(int Type)112   void emitCOFFSymbolType(int Type) override {}
endCOFFSymbolDef()113   void endCOFFSymbolDef() override {}
114 
GetInstructionSequence(unsigned Index)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:
InstrumentMCStreamer(MCContext & Context,mca::InstrumentRegions & R,InstrumentManager & IM)124   InstrumentMCStreamer(MCContext &Context, mca::InstrumentRegions &R,
125                        InstrumentManager &IM)
126       : MCStreamerWrapper(Context, R), IM(IM) {}
127 
emitInstruction(const MCInst & Inst,const MCSubtargetInfo & MCSI)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,
152                    bool SkipFailures) = 0;
153 
154 public:
CodeRegionGenerator()155   CodeRegionGenerator() {}
156   virtual ~CodeRegionGenerator();
157 };
158 
159 /// Abastract CodeRegionGenerator with AnalysisRegions member
160 class AnalysisRegionGenerator : public virtual CodeRegionGenerator {
161 protected:
162   AnalysisRegions Regions;
163 
164 public:
AnalysisRegionGenerator(llvm::SourceMgr & SM)165   AnalysisRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {}
166 
167   virtual Expected<const AnalysisRegions &>
168   parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP,
169                        bool SkipFailures) = 0;
170 };
171 
172 /// Abstract CodeRegionGenerator with InstrumentRegionsRegions member
173 class InstrumentRegionGenerator : public virtual CodeRegionGenerator {
174 protected:
175   InstrumentRegions Regions;
176 
177 public:
InstrumentRegionGenerator(llvm::SourceMgr & SM)178   InstrumentRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {}
179 
180   virtual Expected<const InstrumentRegions &>
181   parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP,
182                          bool SkipFailures) = 0;
183 };
184 
185 /// This abstract class is responsible for parsing input ASM and
186 /// generating a CodeRegions instance.
187 class AsmCodeRegionGenerator : public virtual CodeRegionGenerator {
188   const Target &TheTarget;
189   const MCAsmInfo &MAI;
190   const MCSubtargetInfo &STI;
191   const MCInstrInfo &MCII;
192   unsigned AssemblerDialect; // This is set during parsing.
193 
194 protected:
195   MCContext &Ctx;
196 
197 public:
AsmCodeRegionGenerator(const Target & T,MCContext & C,const MCAsmInfo & A,const MCSubtargetInfo & S,const MCInstrInfo & I)198   AsmCodeRegionGenerator(const Target &T, MCContext &C, const MCAsmInfo &A,
199                          const MCSubtargetInfo &S, const MCInstrInfo &I)
200       : TheTarget(T), MAI(A), STI(S), MCII(I), AssemblerDialect(0), Ctx(C) {}
201 
202   virtual MCACommentConsumer *getCommentConsumer() = 0;
203   virtual CodeRegions &getRegions() = 0;
204   virtual MCStreamerWrapper *getMCStreamer() = 0;
205 
getAssemblerDialect()206   unsigned getAssemblerDialect() const { return AssemblerDialect; }
207   Expected<const CodeRegions &>
208   parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP,
209                    bool SkipFailures) override;
210 };
211 
212 class AsmAnalysisRegionGenerator final : public AnalysisRegionGenerator,
213                                          public AsmCodeRegionGenerator {
214   AnalysisRegionCommentConsumer CC;
215   MCStreamerWrapper Streamer;
216 
217 public:
AsmAnalysisRegionGenerator(const Target & T,llvm::SourceMgr & SM,MCContext & C,const MCAsmInfo & A,const MCSubtargetInfo & S,const MCInstrInfo & I)218   AsmAnalysisRegionGenerator(const Target &T, llvm::SourceMgr &SM, MCContext &C,
219                              const MCAsmInfo &A, const MCSubtargetInfo &S,
220                              const MCInstrInfo &I)
221       : AnalysisRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I),
222         CC(Regions), Streamer(Ctx, Regions) {}
223 
getCommentConsumer()224   MCACommentConsumer *getCommentConsumer() override { return &CC; };
getRegions()225   CodeRegions &getRegions() override { return Regions; };
getMCStreamer()226   MCStreamerWrapper *getMCStreamer() override { return &Streamer; }
227 
228   Expected<const AnalysisRegions &>
parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> & IP,bool SkipFailures)229   parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP,
230                        bool SkipFailures) override {
231     Expected<const CodeRegions &> RegionsOrErr =
232         parseCodeRegions(IP, SkipFailures);
233     if (!RegionsOrErr)
234       return RegionsOrErr.takeError();
235     else
236       return static_cast<const AnalysisRegions &>(*RegionsOrErr);
237   }
238 
239   Expected<const CodeRegions &>
parseCodeRegions(const std::unique_ptr<MCInstPrinter> & IP,bool SkipFailures)240   parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP,
241                    bool SkipFailures) override {
242     return AsmCodeRegionGenerator::parseCodeRegions(IP, SkipFailures);
243   }
244 };
245 
246 class AsmInstrumentRegionGenerator final : public InstrumentRegionGenerator,
247                                            public AsmCodeRegionGenerator {
248   InstrumentRegionCommentConsumer CC;
249   InstrumentMCStreamer Streamer;
250 
251 public:
AsmInstrumentRegionGenerator(const Target & T,llvm::SourceMgr & SM,MCContext & C,const MCAsmInfo & A,const MCSubtargetInfo & S,const MCInstrInfo & I,InstrumentManager & IM)252   AsmInstrumentRegionGenerator(const Target &T, llvm::SourceMgr &SM,
253                                MCContext &C, const MCAsmInfo &A,
254                                const MCSubtargetInfo &S, const MCInstrInfo &I,
255                                InstrumentManager &IM)
256       : InstrumentRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I),
257         CC(SM, Regions, IM), Streamer(Ctx, Regions, IM) {}
258 
getCommentConsumer()259   MCACommentConsumer *getCommentConsumer() override { return &CC; };
getRegions()260   CodeRegions &getRegions() override { return Regions; };
getMCStreamer()261   MCStreamerWrapper *getMCStreamer() override { return &Streamer; }
262 
263   Expected<const InstrumentRegions &>
parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> & IP,bool SkipFailures)264   parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP,
265                          bool SkipFailures) override {
266     Expected<const CodeRegions &> RegionsOrErr =
267         parseCodeRegions(IP, SkipFailures);
268     if (!RegionsOrErr)
269       return RegionsOrErr.takeError();
270     else
271       return static_cast<const InstrumentRegions &>(*RegionsOrErr);
272   }
273 
274   Expected<const CodeRegions &>
parseCodeRegions(const std::unique_ptr<MCInstPrinter> & IP,bool SkipFailures)275   parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP,
276                    bool SkipFailures) override {
277     return AsmCodeRegionGenerator::parseCodeRegions(IP, SkipFailures);
278   }
279 };
280 
281 } // namespace mca
282 } // namespace llvm
283 
284 #endif // LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H
285