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