1 //===----------------------- CodeRegionGenerator.cpp ------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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.
14 //===----------------------------------------------------------------------===//
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/MCTargetOptions.h"
21 #include "llvm/Support/Error.h"
22 #include "llvm/Support/SMLoc.h"
28 // This virtual dtor serves as the anchor for the CodeRegionGenerator class.
29 CodeRegionGenerator::~CodeRegionGenerator() {}
31 Expected
<const CodeRegions
&> AsmCodeRegionGenerator::parseCodeRegions(
32 const std::unique_ptr
<MCInstPrinter
> &IP
) {
34 Opts
.PreserveAsmComments
= false;
35 CodeRegions
&Regions
= getRegions();
36 MCStreamerWrapper
*Str
= getMCStreamer();
38 // Need to initialize an MCTargetStreamer otherwise
39 // certain asm directives will cause a segfault.
40 // Using nulls() so that anything emitted by the MCTargetStreamer
41 // doesn't show up in the llvm-mca output.
42 raw_ostream
&OSRef
= nulls();
43 formatted_raw_ostream
FOSRef(OSRef
);
44 TheTarget
.createAsmTargetStreamer(*Str
, FOSRef
, IP
.get(),
45 /*IsVerboseAsm=*/true);
47 // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM
49 std::unique_ptr
<MCAsmParser
> Parser(
50 createMCAsmParser(Regions
.getSourceMgr(), Ctx
, *Str
, MAI
));
51 MCAsmLexer
&Lexer
= Parser
->getLexer();
52 MCACommentConsumer
*CCP
= getCommentConsumer();
53 Lexer
.setCommentConsumer(CCP
);
54 // Enable support for MASM literal numbers (example: 05h, 101b).
55 Lexer
.setLexMasmIntegers(true);
57 std::unique_ptr
<MCTargetAsmParser
> TAP(
58 TheTarget
.createMCAsmParser(STI
, *Parser
, MCII
, Opts
));
60 return make_error
<StringError
>(
61 "This target does not support assembly parsing.",
62 inconvertibleErrorCode());
63 Parser
->setTargetParser(*TAP
);
67 return make_error
<StringError
>("There was an error parsing comments.",
68 inconvertibleErrorCode());
70 // Set the assembler dialect from the input. llvm-mca will use this as the
71 // default dialect when printing reports.
72 AssemblerDialect
= Parser
->getAssemblerDialect();
76 void AnalysisRegionCommentConsumer::HandleComment(SMLoc Loc
,
77 StringRef CommentText
) {
78 // Skip empty comments.
79 StringRef
Comment(CommentText
);
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.
89 Comment
= Comment
.drop_front(Position
);
90 if (Comment
.consume_front("LLVM-MCA-END")) {
91 // Skip spaces and tabs.
92 Position
= Comment
.find_first_not_of(" \t");
93 if (Position
< Comment
.size())
94 Comment
= Comment
.drop_front(Position
);
95 Regions
.endRegion(Comment
, Loc
);
99 // Try to parse the LLVM-MCA-BEGIN comment.
100 if (!Comment
.consume_front("LLVM-MCA-BEGIN"))
103 // Skip spaces and tabs.
104 Position
= Comment
.find_first_not_of(" \t");
105 if (Position
< Comment
.size())
106 Comment
= Comment
.drop_front(Position
);
107 // Use the rest of the string as a descriptor for this code snippet.
108 Regions
.beginRegion(Comment
, Loc
);
111 void InstrumentRegionCommentConsumer::HandleComment(SMLoc Loc
,
112 StringRef CommentText
) {
113 // Skip empty comments.
114 StringRef
Comment(CommentText
);
118 // Skip spaces and tabs.
119 unsigned Position
= Comment
.find_first_not_of(" \t");
120 if (Position
>= Comment
.size())
121 // We reached the end of the comment. Bail out.
123 Comment
= Comment
.drop_front(Position
);
125 // Bail out if not an MCA style comment
126 if (!Comment
.consume_front("LLVM-MCA-"))
129 // Skip AnalysisRegion comments
130 if (Comment
.consume_front("BEGIN") || Comment
.consume_front("END"))
133 if (IM
.shouldIgnoreInstruments())
136 auto [InstrumentKind
, Data
] = Comment
.split(" ");
138 // An error if not of the form LLVM-MCA-TARGET-KIND
139 if (!IM
.supportsInstrumentType(InstrumentKind
)) {
140 if (InstrumentKind
.empty())
142 Loc
, llvm::SourceMgr::DK_Error
,
143 "No instrumentation kind was provided in LLVM-MCA comment");
145 SM
.PrintMessage(Loc
, llvm::SourceMgr::DK_Error
,
146 "Unknown instrumentation type in LLVM-MCA comment: " +
152 UniqueInstrument I
= IM
.createInstrument(InstrumentKind
, Data
);
155 SM
.PrintMessage(Loc
, llvm::SourceMgr::DK_Error
,
156 "Failed to create " + InstrumentKind
+
157 " instrument with no data");
159 SM
.PrintMessage(Loc
, llvm::SourceMgr::DK_Error
,
160 "Failed to create " + InstrumentKind
+
161 " instrument with data: " + Data
);
166 // End InstrumentType region if one is open
167 if (Regions
.isRegionActive(InstrumentKind
))
168 Regions
.endRegion(InstrumentKind
, Loc
);
169 // Start new instrumentation region
170 Regions
.beginRegion(InstrumentKind
, Loc
, std::move(I
));