llvm.org GIT mirror llvm / 1969d26
[llvm-mca] Move the AssembleInput logic into its own class. Summary: This patch introduces a CodeRegionGenerator class which is responsible for parsing some type of input and creating a 'CodeRegions' instance for use by llvm-mca. In the future, we will also have a CodeRegionGenerator subclass for converting an input object file into CodeRegions. For now, we only have the subclass for converting input assembly into CodeRegions. This is mostly a NFC patch, as the logic remains close to the original, but now encapsulated in its own class and moved outside of llvm-mca.cpp. Reviewers: andreadb, courbet, RKSimon Reviewed By: andreadb Subscribers: mgorny, tschuett, gbedwell, llvm-commits Differential Revision: https://reviews.llvm.org/D54179 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@346344 91177308-0d34-0410-b5e6-96231b3b80d8 Matt Davis 10 months ago
5 changed file(s) with 219 addition(s) and 104 deletion(s). Raw diff Collapse all Expand all
1313 add_llvm_tool(llvm-mca
1414 llvm-mca.cpp
1515 CodeRegion.cpp
16 CodeRegionGenerator.cpp
1617 PipelinePrinter.cpp
1718 Views/DispatchStatistics.cpp
1819 Views/InstructionInfoView.cpp
105105 void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc);
106106 void endRegion(llvm::SMLoc Loc);
107107 void addInstruction(const llvm::MCInst &Instruction);
108 llvm::SourceMgr &getSourceMgr() const { return SM; }
108109
109110 CodeRegions(llvm::SourceMgr &S) : SM(S) {
110111 // Create a default region for the input code sequence.
0 //===----------------------- CodeRegionGenerator.cpp ------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
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/MCTargetAsmParser.h"
20 #include "llvm/MC/MCStreamer.h"
21 #include "llvm/MC/MCTargetOptions.h"
22 #include "llvm/Support/Error.h"
23 #include "llvm/Support/SMLoc.h"
24 #include
25
26 namespace llvm {
27 namespace mca {
28
29 // This virtual dtor serves as the anchor for the CodeRegionGenerator class.
30 CodeRegionGenerator::~CodeRegionGenerator() {}
31
32 // A comment consumer that parses strings. The only valid tokens are strings.
33 class MCACommentConsumer : public AsmCommentConsumer {
34 public:
35 CodeRegions &Regions;
36
37 MCACommentConsumer(CodeRegions &R) : Regions(R) {}
38 void HandleComment(SMLoc Loc, StringRef CommentText) override;
39 };
40
41 // This class provides the callbacks that occur when parsing input assembly.
42 class MCStreamerWrapper final : public MCStreamer {
43 CodeRegions &Regions;
44
45 public:
46 MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R)
47 : MCStreamer(Context), Regions(R) {}
48
49 // We only want to intercept the emission of new instructions.
50 virtual void EmitInstruction(const MCInst &Inst,
51 const MCSubtargetInfo & /* unused */,
52 bool /* unused */) override {
53 Regions.addInstruction(Inst);
54 }
55
56 bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
57 return true;
58 }
59
60 void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
61 unsigned ByteAlignment) override {}
62 void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
63 uint64_t Size = 0, unsigned ByteAlignment = 0,
64 SMLoc Loc = SMLoc()) override {}
65 void EmitGPRel32Value(const MCExpr *Value) override {}
66 void BeginCOFFSymbolDef(const MCSymbol *Symbol) override {}
67 void EmitCOFFSymbolStorageClass(int StorageClass) override {}
68 void EmitCOFFSymbolType(int Type) override {}
69 void EndCOFFSymbolDef() override {}
70
71 ArrayRef GetInstructionSequence(unsigned Index) const {
72 return Regions.getInstructionSequence(Index);
73 }
74 };
75
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 Regions.endRegion(Loc);
91 return;
92 }
93
94 // Try to parse the LLVM-MCA-BEGIN comment.
95 if (!Comment.consume_front("LLVM-MCA-BEGIN"))
96 return;
97
98 // Skip spaces and tabs.
99 Position = Comment.find_first_not_of(" \t");
100 if (Position < Comment.size())
101 Comment = Comment.drop_front(Position);
102 // Use the rest of the string as a descriptor for this code snippet.
103 Regions.beginRegion(Comment, Loc);
104 }
105
106 Expected AsmCodeRegionGenerator::parseCodeRegions() {
107 MCTargetOptions Opts;
108 Opts.PreserveAsmComments = false;
109 MCStreamerWrapper Str(Ctx, Regions);
110
111 // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM
112 // comments.
113 std::unique_ptr Parser(
114 createMCAsmParser(Regions.getSourceMgr(), Ctx, Str, MAI));
115 MCAsmLexer &Lexer = Parser->getLexer();
116 MCACommentConsumer CC(Regions);
117 Lexer.setCommentConsumer(&CC);
118
119 // Create a target-specific parser and perform the parse.
120 std::unique_ptr TAP(
121 TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts));
122 if (!TAP)
123 return make_error(
124 "This target does not support assembly parsing.",
125 inconvertibleErrorCode());
126 Parser->setTargetParser(*TAP);
127 Parser->Run(false);
128
129 // Get the assembler dialect from the input. llvm-mca will use this as the
130 // default dialect when printing reports.
131 AssemblerDialect = Parser->getAssemblerDialect();
132 return Regions;
133 }
134
135 } // namespace mca
136 } // namespace llvm
0 //===----------------------- CodeRegionGenerator.h --------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 /// \file
9 ///
10 /// This file declares 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 #ifndef LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H
17 #define LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H
18
19 #include "CodeRegion.h"
20 #include "llvm/MC/MCAsmInfo.h"
21 #include "llvm/MC/MCContext.h"
22 #include "llvm/MC/MCSubtargetInfo.h"
23 #include "llvm/Support/Error.h"
24 #include "llvm/Support/SourceMgr.h"
25 #include "llvm/Support/TargetRegistry.h"
26 #include
27
28 namespace llvm {
29 namespace mca {
30
31 /// This class is responsible for parsing the input given to the llvm-mca
32 /// driver, and converting that into a CodeRegions instance.
33 class CodeRegionGenerator {
34 protected:
35 CodeRegions Regions;
36 CodeRegionGenerator(const CodeRegionGenerator &) = delete;
37 CodeRegionGenerator &operator=(const CodeRegionGenerator &) = delete;
38
39 public:
40 CodeRegionGenerator(SourceMgr &SM) : Regions(SM) {}
41 virtual ~CodeRegionGenerator();
42 virtual Expected parseCodeRegions() = 0;
43 };
44
45 /// This class is responsible for parsing input ASM and generating
46 /// a CodeRegions instance.
47 class AsmCodeRegionGenerator final : public CodeRegionGenerator {
48 const Target &TheTarget;
49 MCContext &Ctx;
50 const MCAsmInfo &MAI;
51 const MCSubtargetInfo &STI;
52 const MCInstrInfo &MCII;
53 unsigned AssemblerDialect; // This is set during parsing.
54
55 public:
56 AsmCodeRegionGenerator(const Target &T, SourceMgr &SM, MCContext &C,
57 const MCAsmInfo &A, const MCSubtargetInfo &S,
58 const MCInstrInfo &I)
59 : CodeRegionGenerator(SM), TheTarget(T), Ctx(C), MAI(A), STI(S), MCII(I),
60 AssemblerDialect(0) {}
61
62 unsigned getAssemblerDialect() const { return AssemblerDialect; }
63 Expected parseCodeRegions() override;
64 };
65
66 } // namespace mca
67 } // namespace llvm
68
69 #endif // LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H
2121 //===----------------------------------------------------------------------===//
2222
2323 #include "CodeRegion.h"
24 #include "CodeRegionGenerator.h"
2425 #include "PipelinePrinter.h"
2526 #include "Stages/FetchStage.h"
2627 #include "Stages/InstructionTables.h"
3839 #include "llvm/MC/MCAsmInfo.h"
3940 #include "llvm/MC/MCContext.h"
4041 #include "llvm/MC/MCObjectFileInfo.h"
41 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
4242 #include "llvm/MC/MCRegisterInfo.h"
43 #include "llvm/MC/MCStreamer.h"
4443 #include "llvm/Support/CommandLine.h"
4544 #include "llvm/Support/ErrorHandling.h"
4645 #include "llvm/Support/ErrorOr.h"
198197 return TheTarget;
199198 }
200199
201 // A comment consumer that parses strings.
202 // The only valid tokens are strings.
203 class MCACommentConsumer : public AsmCommentConsumer {
204 public:
205 mca::CodeRegions &Regions;
206
207 MCACommentConsumer(mca::CodeRegions &R) : Regions(R) {}
208 void HandleComment(SMLoc Loc, StringRef CommentText) override {
209 // Skip empty comments.
210 StringRef Comment(CommentText);
211 if (Comment.empty())
212 return;
213
214 // Skip spaces and tabs
215 unsigned Position = Comment.find_first_not_of(" \t");
216 if (Position >= Comment.size())
217 // We reached the end of the comment. Bail out.
218 return;
219
220 Comment = Comment.drop_front(Position);
221 if (Comment.consume_front("LLVM-MCA-END")) {
222 Regions.endRegion(Loc);
223 return;
224 }
225
226 // Now try to parse string LLVM-MCA-BEGIN
227 if (!Comment.consume_front("LLVM-MCA-BEGIN"))
228 return;
229
230 // Skip spaces and tabs
231 Position = Comment.find_first_not_of(" \t");
232 if (Position < Comment.size())
233 Comment = Comment.drop_front(Position);
234 // Use the rest of the string as a descriptor for this code snippet.
235 Regions.beginRegion(Comment, Loc);
236 }
237 };
238
239 int AssembleInput(MCAsmParser &Parser, const Target *TheTarget,
240 MCSubtargetInfo &STI, MCInstrInfo &MCII,
241 MCTargetOptions &MCOptions) {
242 std::unique_ptr TAP(
243 TheTarget->createMCAsmParser(STI, Parser, MCII, MCOptions));
244
245 if (!TAP) {
246 WithColor::error() << "this target does not support assembly parsing.\n";
247 return 1;
248 }
249
250 Parser.setTargetParser(*TAP);
251 return Parser.Run(false);
252 }
253
254200 ErrorOr> getOutputStream() {
255201 if (OutputFilename == "")
256202 OutputFilename = "-";
261207 return std::move(Out);
262208 return EC;
263209 }
264
265 class MCStreamerWrapper final : public MCStreamer {
266 mca::CodeRegions &Regions;
267
268 public:
269 MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R)
270 : MCStreamer(Context), Regions(R) {}
271
272 // We only want to intercept the emission of new instructions.
273 virtual void EmitInstruction(const MCInst &Inst,
274 const MCSubtargetInfo & /* unused */,
275 bool /* unused */) override {
276 Regions.addInstruction(Inst);
277 }
278
279 bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
280 return true;
281 }
282
283 void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
284 unsigned ByteAlignment) override {}
285 void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
286 uint64_t Size = 0, unsigned ByteAlignment = 0,
287 SMLoc Loc = SMLoc()) override {}
288 void EmitGPRel32Value(const MCExpr *Value) override {}
289 void BeginCOFFSymbolDef(const MCSymbol *Symbol) override {}
290 void EmitCOFFSymbolStorageClass(int StorageClass) override {}
291 void EmitCOFFSymbolType(int Type) override {}
292 void EndCOFFSymbolDef() override {}
293
294 ArrayRef GetInstructionSequence(unsigned Index) const {
295 return Regions.getInstructionSequence(Index);
296 }
297 };
298210 } // end of anonymous namespace
299211
300212 static void processOptionImpl(cl::opt &O, const cl::opt &Default) {
351263 cl::ParseCommandLineOptions(argc, argv,
352264 "llvm machine code performance analyzer.\n");
353265
354 MCTargetOptions MCOptions;
355 MCOptions.PreserveAsmComments = false;
356
357266 // Get the target from the triple. If a triple is not specified, then select
358267 // the default triple for the host. If the triple doesn't correspond to any
359268 // registered target, then exit with an error message.
393302
394303 std::unique_ptr BOS;
395304
396 mca::CodeRegions Regions(SrcMgr);
397 MCStreamerWrapper Str(Ctx, Regions);
398
399305 std::unique_ptr MCII(TheTarget->createMCInstrInfo());
400306
401307 std::unique_ptr MCIA(
428334 return 1;
429335 }
430336
431 std::unique_ptr P(createMCAsmParser(SrcMgr, Ctx, Str, *MAI));
432 MCAsmLexer &Lexer = P->getLexer();
433 MCACommentConsumer CC(Regions);
434 Lexer.setCommentConsumer(&CC);
435
436 if (AssembleInput(*P, TheTarget, *STI, *MCII, MCOptions))
437 return 1;
438
337 // Parse the input and create CodeRegions that llvm-mca can analyze.
338 mca::AsmCodeRegionGenerator CRG(*TheTarget, SrcMgr, Ctx, *MAI, *STI, *MCII);
339 Expected RegionsOrErr = CRG.parseCodeRegions();
340 if (auto Err = RegionsOrErr.takeError()) {
341 WithColor::error() << Err << "\n";
342 return 1;
343 }
344 const mca::CodeRegions &Regions = *RegionsOrErr;
439345 if (Regions.empty()) {
440346 WithColor::error() << "no assembly instructions found.\n";
441347 return 1;
448354 return 1;
449355 }
450356
451 unsigned AssemblerDialect = P->getAssemblerDialect();
357 unsigned AssemblerDialect = CRG.getAssemblerDialect();
452358 if (OutputAsmVariant >= 0)
453359 AssemblerDialect = static_cast(OutputAsmVariant);
454360 std::unique_ptr IP(TheTarget->createMCInstPrinter(