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/MCAsmLexer.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 &)51 void emitInstruction(const MCInst &Inst,
52 const MCSubtargetInfo & /* unused */) override {
53 Regions.addInstruction(Inst);
54 }
55
emitSymbolAttribute(MCSymbol * Symbol,MCSymbolAttr Attribute)56 bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
57 return true;
58 }
59
emitCommonSymbol(MCSymbol * Symbol,uint64_t Size,unsigned ByteAlignment)60 void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
61 unsigned ByteAlignment) override {}
emitZerofill(MCSection * Section,MCSymbol * Symbol=nullptr,uint64_t Size=0,unsigned ByteAlignment=0,SMLoc Loc=SMLoc ())62 void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
63 uint64_t Size = 0, unsigned ByteAlignment = 0,
64 SMLoc Loc = SMLoc()) override {}
emitGPRel32Value(const MCExpr * Value)65 void emitGPRel32Value(const MCExpr *Value) override {}
beginCOFFSymbolDef(const MCSymbol * Symbol)66 void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
emitCOFFSymbolStorageClass(int StorageClass)67 void emitCOFFSymbolStorageClass(int StorageClass) override {}
emitCOFFSymbolType(int Type)68 void emitCOFFSymbolType(int Type) override {}
endCOFFSymbolDef()69 void endCOFFSymbolDef() override {}
70
GetInstructionSequence(unsigned Index) const71 ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const {
72 return Regions.getInstructionSequence(Index);
73 }
74 };
75
HandleComment(SMLoc Loc,StringRef CommentText)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 // Skip spaces and tabs.
91 Position = Comment.find_first_not_of(" \t");
92 if (Position < Comment.size())
93 Comment = Comment.drop_front(Position);
94 Regions.endRegion(Comment, Loc);
95 return;
96 }
97
98 // Try to parse the LLVM-MCA-BEGIN comment.
99 if (!Comment.consume_front("LLVM-MCA-BEGIN"))
100 return;
101
102 // Skip spaces and tabs.
103 Position = Comment.find_first_not_of(" \t");
104 if (Position < Comment.size())
105 Comment = Comment.drop_front(Position);
106 // Use the rest of the string as a descriptor for this code snippet.
107 Regions.beginRegion(Comment, Loc);
108 }
109
parseCodeRegions(const std::unique_ptr<MCInstPrinter> & IP)110 Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions(
111 const std::unique_ptr<MCInstPrinter> &IP) {
112 MCTargetOptions Opts;
113 Opts.PreserveAsmComments = false;
114 MCStreamerWrapper Str(Ctx, Regions);
115
116 // Need to initialize an MCTargetStreamer otherwise
117 // certain asm directives will cause a segfault.
118 // Using nulls() so that anything emitted by the MCTargetStreamer
119 // doesn't show up in the llvm-mca output.
120 raw_ostream &OSRef = nulls();
121 formatted_raw_ostream FOSRef(OSRef);
122 TheTarget.createAsmTargetStreamer(Str, FOSRef, IP.get(),
123 /*IsVerboseAsm=*/true);
124
125 // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM
126 // comments.
127 std::unique_ptr<MCAsmParser> Parser(
128 createMCAsmParser(Regions.getSourceMgr(), Ctx, Str, MAI));
129 MCAsmLexer &Lexer = Parser->getLexer();
130 MCACommentConsumer CC(Regions);
131 Lexer.setCommentConsumer(&CC);
132 // Enable support for MASM literal numbers (example: 05h, 101b).
133 Lexer.setLexMasmIntegers(true);
134
135 std::unique_ptr<MCTargetAsmParser> TAP(
136 TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts));
137 if (!TAP)
138 return make_error<StringError>(
139 "This target does not support assembly parsing.",
140 inconvertibleErrorCode());
141 Parser->setTargetParser(*TAP);
142 Parser->Run(false);
143
144 // Set the assembler dialect from the input. llvm-mca will use this as the
145 // default dialect when printing reports.
146 AssemblerDialect = Parser->getAssemblerDialect();
147 return Regions;
148 }
149
150 } // namespace mca
151 } // namespace llvm
152