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