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 : public AsmCommentConsumer { |
35 | protected: |
36 | bool = false; |
37 | |
38 | public: |
39 | () = default; |
40 | |
41 | bool () const { return FoundError; } |
42 | }; |
43 | |
44 | /// A comment consumer that parses strings. The only valid tokens are strings. |
45 | class : public MCACommentConsumer { |
46 | AnalysisRegions &; |
47 | |
48 | public: |
49 | (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 ) override; |
59 | }; |
60 | |
61 | /// A comment consumer that parses strings to create InstrumentRegions. |
62 | /// The only valid tokens are strings. |
63 | class : public MCACommentConsumer { |
64 | llvm::SourceMgr &; |
65 | |
66 | InstrumentRegions &; |
67 | |
68 | InstrumentManager &; |
69 | |
70 | public: |
71 | (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 ) override; |
81 | |
82 | InstrumentManager &() { 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: |
91 | MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R) |
92 | : MCStreamer(Context), Regions(R) {} |
93 | |
94 | // We only want to intercept the emission of new instructions. |
95 | void emitInstruction(const MCInst &Inst, |
96 | const MCSubtargetInfo & /* unused */) override { |
97 | Regions.addInstruction(Instruction: Inst); |
98 | } |
99 | |
100 | bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { |
101 | return true; |
102 | } |
103 | |
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 {} |
109 | void emitGPRel32Value(const MCExpr *Value) override {} |
110 | void beginCOFFSymbolDef(const MCSymbol *Symbol) override {} |
111 | void emitCOFFSymbolStorageClass(int StorageClass) override {} |
112 | void emitCOFFSymbolType(int Type) override {} |
113 | void endCOFFSymbolDef() override {} |
114 | |
115 | ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const { |
116 | return Regions.getInstructionSequence(Idx: Index); |
117 | } |
118 | }; |
119 | |
120 | class InstrumentMCStreamer : public MCStreamerWrapper { |
121 | InstrumentManager &IM; |
122 | |
123 | public: |
124 | InstrumentMCStreamer(MCContext &Context, mca::InstrumentRegions &R, |
125 | InstrumentManager &IM) |
126 | : MCStreamerWrapper(Context, R), IM(IM) {} |
127 | |
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(Description: InstrumentKind)) |
137 | Regions.endRegion(Description: InstrumentKind, Loc: Inst.getLoc()); |
138 | // Start new instrumentation region |
139 | Regions.beginRegion(Description: InstrumentKind, Loc: Inst.getLoc(), Instrument: 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: |
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: |
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: |
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: |
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 *() = 0; |
203 | virtual CodeRegions &getRegions() = 0; |
204 | virtual MCStreamerWrapper *getMCStreamer() = 0; |
205 | |
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: |
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 | |
224 | MCACommentConsumer *() override { return &CC; }; |
225 | CodeRegions &getRegions() override { return Regions; }; |
226 | MCStreamerWrapper *getMCStreamer() override { return &Streamer; } |
227 | |
228 | Expected<const AnalysisRegions &> |
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 &> |
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: |
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 | |
259 | MCACommentConsumer *() override { return &CC; }; |
260 | CodeRegions &getRegions() override { return Regions; }; |
261 | MCStreamerWrapper *getMCStreamer() override { return &Streamer; } |
262 | |
263 | Expected<const InstrumentRegions &> |
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 &> |
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 | |