| 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 | |
| 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 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 | |
| 119 | class InstrumentMCStreamer : public MCStreamerWrapper { |
| 120 | InstrumentManager &IM; |
| 121 | |
| 122 | public: |
| 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. |
| 145 | class CodeRegionGenerator { |
| 146 | protected: |
| 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 | |
| 153 | public: |
| 154 | CodeRegionGenerator() {} |
| 155 | virtual ~CodeRegionGenerator(); |
| 156 | }; |
| 157 | |
| 158 | /// Abastract CodeRegionGenerator with AnalysisRegions member |
| 159 | class AnalysisRegionGenerator : public virtual CodeRegionGenerator { |
| 160 | protected: |
| 161 | AnalysisRegions Regions; |
| 162 | |
| 163 | public: |
| 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 |
| 172 | class InstrumentRegionGenerator : public virtual CodeRegionGenerator { |
| 173 | protected: |
| 174 | InstrumentRegions Regions; |
| 175 | |
| 176 | public: |
| 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. |
| 186 | class 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 | |
| 193 | protected: |
| 194 | MCContext &Ctx; |
| 195 | |
| 196 | public: |
| 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 *() = 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 | |
| 211 | class AsmAnalysisRegionGenerator final : public AnalysisRegionGenerator, |
| 212 | public AsmCodeRegionGenerator { |
| 213 | AnalysisRegionCommentConsumer CC; |
| 214 | MCStreamerWrapper Streamer; |
| 215 | |
| 216 | public: |
| 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 *() 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 | |
| 245 | class AsmInstrumentRegionGenerator final : public InstrumentRegionGenerator, |
| 246 | public AsmCodeRegionGenerator { |
| 247 | InstrumentRegionCommentConsumer CC; |
| 248 | InstrumentMCStreamer Streamer; |
| 249 | |
| 250 | public: |
| 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 *() 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 | |