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