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/MCSubtargetInfo.h"
24 #include "llvm/MC/TargetRegistry.h"
25 #include "llvm/MCA/CustomBehaviour.h"
26 #include "llvm/Support/Error.h"
27 #include "llvm/Support/SourceMgr.h"
28 #include <memory>
29 
30 namespace llvm {
31 namespace mca {
32 
33 class MCACommentConsumer : public AsmCommentConsumer {
34 protected:
35   bool FoundError;
36 
37 public:
38   MCACommentConsumer() : FoundError(false) {}
39 
40   bool hadErr() const { return FoundError; }
41 };
42 
43 /// A comment consumer that parses strings.  The only valid tokens are strings.
44 class AnalysisRegionCommentConsumer : public MCACommentConsumer {
45   AnalysisRegions &Regions;
46 
47 public:
48   AnalysisRegionCommentConsumer(AnalysisRegions &R) : Regions(R) {}
49 
50   /// Parses a comment. It begins a new region if it is of the form
51   /// LLVM-MCA-BEGIN. It ends a region if it is of the form LLVM-MCA-END.
52   /// Regions can be optionally named if they are of the form
53   /// LLVM-MCA-BEGIN <name> or LLVM-MCA-END <name>. Subregions are
54   /// permitted, but a region that begins while another region is active
55   /// must be ended before the outer region is ended. If thre is only one
56   /// active region, LLVM-MCA-END does not need to provide a name.
57   void HandleComment(SMLoc Loc, StringRef CommentText) override;
58 };
59 
60 /// A comment consumer that parses strings to create InstrumentRegions.
61 /// The only valid tokens are strings.
62 class InstrumentRegionCommentConsumer : public MCACommentConsumer {
63   llvm::SourceMgr &SM;
64 
65   InstrumentRegions &Regions;
66 
67   InstrumentManager &IM;
68 
69 public:
70   InstrumentRegionCommentConsumer(llvm::SourceMgr &SM, InstrumentRegions &R,
71                                   InstrumentManager &IM)
72       : SM(SM), Regions(R), IM(IM) {}
73 
74   /// Parses a comment. It begins a new region if it is of the form
75   /// LLVM-MCA-<INSTRUMENTATION_TYPE> <data> where INSTRUMENTATION_TYPE
76   /// is a valid InstrumentKind. If there is already an active
77   /// region of type INSTRUMENATION_TYPE, then it will end the active
78   /// one and begin a new one using the new data.
79   void HandleComment(SMLoc Loc, StringRef CommentText) override;
80 };
81 
82 /// This abstract class is responsible for parsing the input given to
83 /// the llvm-mca driver, and converting that into a CodeRegions instance.
84 class CodeRegionGenerator {
85 protected:
86   CodeRegionGenerator(const CodeRegionGenerator &) = delete;
87   CodeRegionGenerator &operator=(const CodeRegionGenerator &) = delete;
88   virtual Expected<const CodeRegions &>
89   parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) = 0;
90 
91 public:
92   CodeRegionGenerator() {}
93   virtual ~CodeRegionGenerator();
94 };
95 
96 /// Abastract CodeRegionGenerator with AnalysisRegions member
97 class AnalysisRegionGenerator : public virtual CodeRegionGenerator {
98 protected:
99   AnalysisRegions Regions;
100 
101 public:
102   AnalysisRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {}
103 
104   virtual Expected<const AnalysisRegions &>
105   parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP) = 0;
106 };
107 
108 /// Abstract CodeRegionGenerator with InstrumentRegionsRegions member
109 class InstrumentRegionGenerator : public virtual CodeRegionGenerator {
110 protected:
111   InstrumentRegions Regions;
112 
113 public:
114   InstrumentRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {}
115 
116   virtual Expected<const InstrumentRegions &>
117   parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP) = 0;
118 };
119 
120 /// This abstract class is responsible for parsing input ASM and
121 /// generating a CodeRegions instance.
122 class AsmCodeRegionGenerator : public virtual CodeRegionGenerator {
123   const Target &TheTarget;
124   MCContext &Ctx;
125   const MCAsmInfo &MAI;
126   const MCSubtargetInfo &STI;
127   const MCInstrInfo &MCII;
128   unsigned AssemblerDialect; // This is set during parsing.
129 
130 public:
131   AsmCodeRegionGenerator(const Target &T, MCContext &C, const MCAsmInfo &A,
132                          const MCSubtargetInfo &S, const MCInstrInfo &I)
133       : TheTarget(T), Ctx(C), MAI(A), STI(S), MCII(I), AssemblerDialect(0) {}
134 
135   virtual MCACommentConsumer *getCommentConsumer() = 0;
136   virtual CodeRegions &getRegions() = 0;
137 
138   unsigned getAssemblerDialect() const { return AssemblerDialect; }
139   Expected<const CodeRegions &>
140   parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) override;
141 };
142 
143 class AsmAnalysisRegionGenerator final : public AnalysisRegionGenerator,
144                                          public AsmCodeRegionGenerator {
145   AnalysisRegionCommentConsumer CC;
146 
147 public:
148   AsmAnalysisRegionGenerator(const Target &T, llvm::SourceMgr &SM, MCContext &C,
149                              const MCAsmInfo &A, const MCSubtargetInfo &S,
150                              const MCInstrInfo &I)
151       : AnalysisRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I),
152         CC(Regions) {}
153 
154   MCACommentConsumer *getCommentConsumer() override { return &CC; };
155   CodeRegions &getRegions() override { return Regions; };
156 
157   Expected<const AnalysisRegions &>
158   parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
159     Expected<const CodeRegions &> RegionsOrErr = parseCodeRegions(IP);
160     if (!RegionsOrErr)
161       return RegionsOrErr.takeError();
162     else
163       return static_cast<const AnalysisRegions &>(*RegionsOrErr);
164   }
165 
166   Expected<const CodeRegions &>
167   parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
168     return AsmCodeRegionGenerator::parseCodeRegions(IP);
169   }
170 };
171 
172 class AsmInstrumentRegionGenerator final : public InstrumentRegionGenerator,
173                                            public AsmCodeRegionGenerator {
174   InstrumentRegionCommentConsumer CC;
175 
176 public:
177   AsmInstrumentRegionGenerator(const Target &T, llvm::SourceMgr &SM,
178                                MCContext &C, const MCAsmInfo &A,
179                                const MCSubtargetInfo &S, const MCInstrInfo &I,
180                                InstrumentManager &IM)
181       : InstrumentRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I),
182         CC(SM, Regions, IM) {}
183 
184   MCACommentConsumer *getCommentConsumer() override { return &CC; };
185   CodeRegions &getRegions() override { return Regions; };
186 
187   Expected<const InstrumentRegions &>
188   parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
189     Expected<const CodeRegions &> RegionsOrErr = parseCodeRegions(IP);
190     if (!RegionsOrErr)
191       return RegionsOrErr.takeError();
192     else
193       return static_cast<const InstrumentRegions &>(*RegionsOrErr);
194   }
195 
196   Expected<const CodeRegions &>
197   parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
198     return AsmCodeRegionGenerator::parseCodeRegions(IP);
199   }
200 };
201 
202 } // namespace mca
203 } // namespace llvm
204 
205 #endif // LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H
206