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