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/AsmLexer.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
31namespace llvm {
32namespace mca {
33
34class MCACommentConsumer : public AsmCommentConsumer {
35protected:
36 bool FoundError = false;
37
38public:
39 MCACommentConsumer() = default;
40
41 bool hadErr() const { return FoundError; }
42};
43
44/// A comment consumer that parses strings. The only valid tokens are strings.
45class AnalysisRegionCommentConsumer : public MCACommentConsumer {
46 AnalysisRegions &Regions;
47
48public:
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.
63class InstrumentRegionCommentConsumer : public MCACommentConsumer {
64 llvm::SourceMgr &SM;
65
66 InstrumentRegions &Regions;
67
68 InstrumentManager &IM;
69
70public:
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
82 InstrumentManager &getInstrumentManager() { return IM; }
83};
84
85// This class provides the callbacks that occur when parsing input assembly.
86class MCStreamerWrapper : public MCStreamer {
87protected:
88 CodeRegions &Regions;
89
90public:
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 beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
110 void emitCOFFSymbolStorageClass(int StorageClass) override {}
111 void emitCOFFSymbolType(int Type) override {}
112 void endCOFFSymbolDef() override {}
113
114 ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const {
115 return Regions.getInstructionSequence(Idx: Index);
116 }
117};
118
119class InstrumentMCStreamer : public MCStreamerWrapper {
120 InstrumentManager &IM;
121
122public:
123 InstrumentMCStreamer(MCContext &Context, mca::InstrumentRegions &R,
124 InstrumentManager &IM)
125 : MCStreamerWrapper(Context, R), IM(IM) {}
126
127 void emitInstruction(const MCInst &Inst,
128 const MCSubtargetInfo &MCSI) override {
129 MCStreamerWrapper::emitInstruction(Inst, MCSI);
130
131 // We know that Regions is an InstrumentRegions by the constructor.
132 for (UniqueInstrument &I : IM.createInstruments(Inst)) {
133 StringRef InstrumentKind = I.get()->getDesc();
134 // End InstrumentType region if one is open
135 if (Regions.isRegionActive(Description: InstrumentKind))
136 Regions.endRegion(Description: InstrumentKind, Loc: Inst.getLoc());
137 // Start new instrumentation region
138 Regions.beginRegion(Description: InstrumentKind, Loc: Inst.getLoc(), Instrument: std::move(I));
139 }
140 }
141};
142
143/// This abstract class is responsible for parsing the input given to
144/// the llvm-mca driver, and converting that into a CodeRegions instance.
145class CodeRegionGenerator {
146protected:
147 CodeRegionGenerator(const CodeRegionGenerator &) = delete;
148 CodeRegionGenerator &operator=(const CodeRegionGenerator &) = delete;
149 virtual Expected<const CodeRegions &>
150 parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP,
151 bool SkipFailures) = 0;
152
153public:
154 CodeRegionGenerator() {}
155 virtual ~CodeRegionGenerator();
156};
157
158/// Abastract CodeRegionGenerator with AnalysisRegions member
159class AnalysisRegionGenerator : public virtual CodeRegionGenerator {
160protected:
161 AnalysisRegions Regions;
162
163public:
164 AnalysisRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {}
165
166 virtual Expected<const AnalysisRegions &>
167 parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP,
168 bool SkipFailures) = 0;
169};
170
171/// Abstract CodeRegionGenerator with InstrumentRegionsRegions member
172class InstrumentRegionGenerator : public virtual CodeRegionGenerator {
173protected:
174 InstrumentRegions Regions;
175
176public:
177 InstrumentRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {}
178
179 virtual Expected<const InstrumentRegions &>
180 parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP,
181 bool SkipFailures) = 0;
182};
183
184/// This abstract class is responsible for parsing input ASM and
185/// generating a CodeRegions instance.
186class AsmCodeRegionGenerator : public virtual CodeRegionGenerator {
187 const Target &TheTarget;
188 const MCAsmInfo &MAI;
189 const MCSubtargetInfo &STI;
190 const MCInstrInfo &MCII;
191 unsigned AssemblerDialect; // This is set during parsing.
192
193protected:
194 MCContext &Ctx;
195
196public:
197 AsmCodeRegionGenerator(const Target &T, MCContext &C, const MCAsmInfo &A,
198 const MCSubtargetInfo &S, const MCInstrInfo &I)
199 : TheTarget(T), MAI(A), STI(S), MCII(I), AssemblerDialect(0), Ctx(C) {}
200
201 virtual MCACommentConsumer *getCommentConsumer() = 0;
202 virtual CodeRegions &getRegions() = 0;
203 virtual MCStreamerWrapper *getMCStreamer() = 0;
204
205 unsigned getAssemblerDialect() const { return AssemblerDialect; }
206 Expected<const CodeRegions &>
207 parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP,
208 bool SkipFailures) override;
209};
210
211class AsmAnalysisRegionGenerator final : public AnalysisRegionGenerator,
212 public AsmCodeRegionGenerator {
213 AnalysisRegionCommentConsumer CC;
214 MCStreamerWrapper Streamer;
215
216public:
217 AsmAnalysisRegionGenerator(const Target &T, llvm::SourceMgr &SM, MCContext &C,
218 const MCAsmInfo &A, const MCSubtargetInfo &S,
219 const MCInstrInfo &I)
220 : AnalysisRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I),
221 CC(Regions), Streamer(Ctx, Regions) {}
222
223 MCACommentConsumer *getCommentConsumer() override { return &CC; };
224 CodeRegions &getRegions() override { return Regions; };
225 MCStreamerWrapper *getMCStreamer() override { return &Streamer; }
226
227 Expected<const AnalysisRegions &>
228 parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP,
229 bool SkipFailures) override {
230 Expected<const CodeRegions &> RegionsOrErr =
231 parseCodeRegions(IP, SkipFailures);
232 if (!RegionsOrErr)
233 return RegionsOrErr.takeError();
234 else
235 return static_cast<const AnalysisRegions &>(*RegionsOrErr);
236 }
237
238 Expected<const CodeRegions &>
239 parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP,
240 bool SkipFailures) override {
241 return AsmCodeRegionGenerator::parseCodeRegions(IP, SkipFailures);
242 }
243};
244
245class AsmInstrumentRegionGenerator final : public InstrumentRegionGenerator,
246 public AsmCodeRegionGenerator {
247 InstrumentRegionCommentConsumer CC;
248 InstrumentMCStreamer Streamer;
249
250public:
251 AsmInstrumentRegionGenerator(const Target &T, llvm::SourceMgr &SM,
252 MCContext &C, const MCAsmInfo &A,
253 const MCSubtargetInfo &S, const MCInstrInfo &I,
254 InstrumentManager &IM)
255 : InstrumentRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I),
256 CC(SM, Regions, IM), Streamer(Ctx, Regions, IM) {}
257
258 MCACommentConsumer *getCommentConsumer() override { return &CC; };
259 CodeRegions &getRegions() override { return Regions; };
260 MCStreamerWrapper *getMCStreamer() override { return &Streamer; }
261
262 Expected<const InstrumentRegions &>
263 parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP,
264 bool SkipFailures) override {
265 Expected<const CodeRegions &> RegionsOrErr =
266 parseCodeRegions(IP, SkipFailures);
267 if (!RegionsOrErr)
268 return RegionsOrErr.takeError();
269 else
270 return static_cast<const InstrumentRegions &>(*RegionsOrErr);
271 }
272
273 Expected<const CodeRegions &>
274 parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP,
275 bool SkipFailures) override {
276 return AsmCodeRegionGenerator::parseCodeRegions(IP, SkipFailures);
277 }
278};
279
280} // namespace mca
281} // namespace llvm
282
283#endif // LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H
284