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
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(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(Index);
117  }
118};
119
120class InstrumentMCStreamer : public MCStreamerWrapper {
121  InstrumentManager &IM;
122
123public:
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(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.
146class CodeRegionGenerator {
147protected:
148  CodeRegionGenerator(const CodeRegionGenerator &) = delete;
149  CodeRegionGenerator &operator=(const CodeRegionGenerator &) = delete;
150  virtual Expected<const CodeRegions &>
151  parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) = 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) = 0;
168};
169
170/// Abstract CodeRegionGenerator with InstrumentRegionsRegions member
171class InstrumentRegionGenerator : public virtual CodeRegionGenerator {
172protected:
173  InstrumentRegions Regions;
174
175public:
176  InstrumentRegionGenerator(llvm::SourceMgr &SM) : Regions(SM) {}
177
178  virtual Expected<const InstrumentRegions &>
179  parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP) = 0;
180};
181
182/// This abstract class is responsible for parsing input ASM and
183/// generating a CodeRegions instance.
184class AsmCodeRegionGenerator : public virtual CodeRegionGenerator {
185  const Target &TheTarget;
186  const MCAsmInfo &MAI;
187  const MCSubtargetInfo &STI;
188  const MCInstrInfo &MCII;
189  unsigned AssemblerDialect; // This is set during parsing.
190
191protected:
192  MCContext &Ctx;
193
194public:
195  AsmCodeRegionGenerator(const Target &T, MCContext &C, const MCAsmInfo &A,
196                         const MCSubtargetInfo &S, const MCInstrInfo &I)
197      : TheTarget(T), MAI(A), STI(S), MCII(I), AssemblerDialect(0), Ctx(C) {}
198
199  virtual MCACommentConsumer *getCommentConsumer() = 0;
200  virtual CodeRegions &getRegions() = 0;
201  virtual MCStreamerWrapper *getMCStreamer() = 0;
202
203  unsigned getAssemblerDialect() const { return AssemblerDialect; }
204  Expected<const CodeRegions &>
205  parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) override;
206};
207
208class AsmAnalysisRegionGenerator final : public AnalysisRegionGenerator,
209                                         public AsmCodeRegionGenerator {
210  AnalysisRegionCommentConsumer CC;
211  MCStreamerWrapper Streamer;
212
213public:
214  AsmAnalysisRegionGenerator(const Target &T, llvm::SourceMgr &SM, MCContext &C,
215                             const MCAsmInfo &A, const MCSubtargetInfo &S,
216                             const MCInstrInfo &I)
217      : AnalysisRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I),
218        CC(Regions), Streamer(Ctx, Regions) {}
219
220  MCACommentConsumer *getCommentConsumer() override { return &CC; };
221  CodeRegions &getRegions() override { return Regions; };
222  MCStreamerWrapper *getMCStreamer() override { return &Streamer; }
223
224  Expected<const AnalysisRegions &>
225  parseAnalysisRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
226    Expected<const CodeRegions &> RegionsOrErr = parseCodeRegions(IP);
227    if (!RegionsOrErr)
228      return RegionsOrErr.takeError();
229    else
230      return static_cast<const AnalysisRegions &>(*RegionsOrErr);
231  }
232
233  Expected<const CodeRegions &>
234  parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
235    return AsmCodeRegionGenerator::parseCodeRegions(IP);
236  }
237};
238
239class AsmInstrumentRegionGenerator final : public InstrumentRegionGenerator,
240                                           public AsmCodeRegionGenerator {
241  InstrumentRegionCommentConsumer CC;
242  InstrumentMCStreamer Streamer;
243
244public:
245  AsmInstrumentRegionGenerator(const Target &T, llvm::SourceMgr &SM,
246                               MCContext &C, const MCAsmInfo &A,
247                               const MCSubtargetInfo &S, const MCInstrInfo &I,
248                               InstrumentManager &IM)
249      : InstrumentRegionGenerator(SM), AsmCodeRegionGenerator(T, C, A, S, I),
250        CC(SM, Regions, IM), Streamer(Ctx, Regions, IM) {}
251
252  MCACommentConsumer *getCommentConsumer() override { return &CC; };
253  CodeRegions &getRegions() override { return Regions; };
254  MCStreamerWrapper *getMCStreamer() override { return &Streamer; }
255
256  Expected<const InstrumentRegions &>
257  parseInstrumentRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
258    Expected<const CodeRegions &> RegionsOrErr = parseCodeRegions(IP);
259    if (!RegionsOrErr)
260      return RegionsOrErr.takeError();
261    else
262      return static_cast<const InstrumentRegions &>(*RegionsOrErr);
263  }
264
265  Expected<const CodeRegions &>
266  parseCodeRegions(const std::unique_ptr<MCInstPrinter> &IP) override {
267    return AsmCodeRegionGenerator::parseCodeRegions(IP);
268  }
269};
270
271} // namespace mca
272} // namespace llvm
273
274#endif // LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H
275