1 //===----------------------- CodeRegionGenerator.cpp ------------*- 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 defines 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 #include "CodeRegionGenerator.h"
17 #include "llvm/ADT/ArrayRef.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
20 #include "llvm/MC/MCStreamer.h"
21 #include "llvm/MC/MCTargetOptions.h"
22 #include "llvm/Support/Error.h"
23 #include "llvm/Support/SMLoc.h"
24 #include <memory>
25 
26 namespace llvm {
27 namespace mca {
28 
29 // This virtual dtor serves as the anchor for the CodeRegionGenerator class.
30 CodeRegionGenerator::~CodeRegionGenerator() {}
31 
32 // A comment consumer that parses strings.  The only valid tokens are strings.
33 class MCACommentConsumer : public AsmCommentConsumer {
34 public:
35   CodeRegions &Regions;
36 
37   MCACommentConsumer(CodeRegions &R) : Regions(R) {}
38   void HandleComment(SMLoc Loc, StringRef CommentText) override;
39 };
40 
41 // This class provides the callbacks that occur when parsing input assembly.
42 class MCStreamerWrapper final : public MCStreamer {
43   CodeRegions &Regions;
44 
45 public:
46   MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R)
47       : MCStreamer(Context), Regions(R) {}
48 
49   // We only want to intercept the emission of new instructions.
50   virtual void EmitInstruction(const MCInst &Inst,
51                                const MCSubtargetInfo & /* unused */,
52                                bool /* unused */) override {
53     Regions.addInstruction(Inst);
54   }
55 
56   bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
57     return true;
58   }
59 
60   void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
61                         unsigned ByteAlignment) override {}
62   void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
63                     uint64_t Size = 0, unsigned ByteAlignment = 0,
64                     SMLoc Loc = SMLoc()) override {}
65   void EmitGPRel32Value(const MCExpr *Value) override {}
66   void BeginCOFFSymbolDef(const MCSymbol *Symbol) override {}
67   void EmitCOFFSymbolStorageClass(int StorageClass) override {}
68   void EmitCOFFSymbolType(int Type) override {}
69   void EndCOFFSymbolDef() override {}
70 
71   ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const {
72     return Regions.getInstructionSequence(Index);
73   }
74 };
75 
76 void MCACommentConsumer::HandleComment(SMLoc Loc, StringRef CommentText) {
77   // Skip empty comments.
78   StringRef Comment(CommentText);
79   if (Comment.empty())
80     return;
81 
82   // Skip spaces and tabs.
83   unsigned Position = Comment.find_first_not_of(" \t");
84   if (Position >= Comment.size())
85     // We reached the end of the comment. Bail out.
86     return;
87 
88   Comment = Comment.drop_front(Position);
89   if (Comment.consume_front("LLVM-MCA-END")) {
90     Regions.endRegion(Loc);
91     return;
92   }
93 
94   // Try to parse the LLVM-MCA-BEGIN comment.
95   if (!Comment.consume_front("LLVM-MCA-BEGIN"))
96     return;
97 
98   // Skip spaces and tabs.
99   Position = Comment.find_first_not_of(" \t");
100   if (Position < Comment.size())
101     Comment = Comment.drop_front(Position);
102   // Use the rest of the string as a descriptor for this code snippet.
103   Regions.beginRegion(Comment, Loc);
104 }
105 
106 Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions() {
107   MCTargetOptions Opts;
108   Opts.PreserveAsmComments = false;
109   MCStreamerWrapper Str(Ctx, Regions);
110 
111   // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM
112   // comments.
113   std::unique_ptr<MCAsmParser> Parser(
114       createMCAsmParser(Regions.getSourceMgr(), Ctx, Str, MAI));
115   MCAsmLexer &Lexer = Parser->getLexer();
116   MCACommentConsumer CC(Regions);
117   Lexer.setCommentConsumer(&CC);
118 
119   // Create a target-specific parser and perform the parse.
120   std::unique_ptr<MCTargetAsmParser> TAP(
121       TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts));
122   if (!TAP)
123     return make_error<StringError>(
124         "This target does not support assembly parsing.",
125         inconvertibleErrorCode());
126   Parser->setTargetParser(*TAP);
127   Parser->Run(false);
128 
129   // Get the assembler dialect from the input.  llvm-mca will use this as the
130   // default dialect when printing reports.
131   AssemblerDialect = Parser->getAssemblerDialect();
132   return Regions;
133 }
134 
135 } // namespace mca
136 } // namespace llvm
137