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/MCTargetAsmParser.h"
20#include "llvm/MC/MCTargetOptions.h"
21#include "llvm/Support/Error.h"
22#include "llvm/Support/SMLoc.h"
23#include <memory>
24
25namespace llvm {
26namespace mca {
27
28// This virtual dtor serves as the anchor for the CodeRegionGenerator class.
29CodeRegionGenerator::~CodeRegionGenerator() {}
30
31Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions(
32 const std::unique_ptr<MCInstPrinter> &IP) {
33 MCTargetOptions Opts;
34 Opts.PreserveAsmComments = false;
35 CodeRegions &Regions = getRegions();
36 MCStreamerWrapper *Str = getMCStreamer();
37
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(S&: *Str, OS&: FOSRef, InstPrint: IP.get(),
45 /*IsVerboseAsm=*/true);
46
47 // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM
48 // comments.
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);
56
57 std::unique_ptr<MCTargetAsmParser> TAP(
58 TheTarget.createMCAsmParser(STI, Parser&: *Parser, MII: MCII, Options: Opts));
59 if (!TAP)
60 return make_error<StringError>(
61 Args: "This target does not support assembly parsing.",
62 Args: inconvertibleErrorCode());
63 Parser->setTargetParser(*TAP);
64 Parser->Run(NoInitialTextSection: false);
65
66 if (CCP->hadErr())
67 return make_error<StringError>(Args: "There was an error parsing comments.",
68 Args: inconvertibleErrorCode());
69
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();
73 return Regions;
74}
75
76void AnalysisRegionCommentConsumer::HandleComment(SMLoc Loc,
77 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(Chars: " \t");
85 if (Position >= Comment.size())
86 // We reached the end of the comment. Bail out.
87 return;
88
89 Comment = Comment.drop_front(N: Position);
90 if (Comment.consume_front(Prefix: "LLVM-MCA-END")) {
91 // Skip spaces and tabs.
92 Position = Comment.find_first_not_of(Chars: " \t");
93 if (Position < Comment.size())
94 Comment = Comment.drop_front(N: Position);
95 Regions.endRegion(Description: Comment, Loc);
96 return;
97 }
98
99 // Try to parse the LLVM-MCA-BEGIN comment.
100 if (!Comment.consume_front(Prefix: "LLVM-MCA-BEGIN"))
101 return;
102
103 // Skip spaces and tabs.
104 Position = Comment.find_first_not_of(Chars: " \t");
105 if (Position < Comment.size())
106 Comment = Comment.drop_front(N: Position);
107 // Use the rest of the string as a descriptor for this code snippet.
108 Regions.beginRegion(Description: Comment, Loc);
109}
110
111void InstrumentRegionCommentConsumer::HandleComment(SMLoc Loc,
112 StringRef CommentText) {
113 // Skip empty comments.
114 StringRef Comment(CommentText);
115 if (Comment.empty())
116 return;
117
118 // Skip spaces and tabs.
119 unsigned Position = Comment.find_first_not_of(Chars: " \t");
120 if (Position >= Comment.size())
121 // We reached the end of the comment. Bail out.
122 return;
123 Comment = Comment.drop_front(N: Position);
124
125 // Bail out if not an MCA style comment
126 if (!Comment.consume_front(Prefix: "LLVM-MCA-"))
127 return;
128
129 // Skip AnalysisRegion comments
130 if (Comment.consume_front(Prefix: "BEGIN") || Comment.consume_front(Prefix: "END"))
131 return;
132
133 if (IM.shouldIgnoreInstruments())
134 return;
135
136 auto [InstrumentKind, Data] = Comment.split(Separator: " ");
137
138 // An error if not of the form LLVM-MCA-TARGET-KIND
139 if (!IM.supportsInstrumentType(Type: InstrumentKind)) {
140 if (InstrumentKind.empty())
141 SM.PrintMessage(
142 Loc, Kind: llvm::SourceMgr::DK_Error,
143 Msg: "No instrumentation kind was provided in LLVM-MCA comment");
144 else
145 SM.PrintMessage(Loc, Kind: llvm::SourceMgr::DK_Error,
146 Msg: "Unknown instrumentation type in LLVM-MCA comment: " +
147 InstrumentKind);
148 FoundError = true;
149 return;
150 }
151
152 UniqueInstrument I = IM.createInstrument(Desc: InstrumentKind, Data);
153 if (!I) {
154 if (Data.empty())
155 SM.PrintMessage(Loc, Kind: llvm::SourceMgr::DK_Error,
156 Msg: "Failed to create " + InstrumentKind +
157 " instrument with no data");
158 else
159 SM.PrintMessage(Loc, Kind: llvm::SourceMgr::DK_Error,
160 Msg: "Failed to create " + InstrumentKind +
161 " instrument with data: " + Data);
162 FoundError = true;
163 return;
164 }
165
166 // End InstrumentType region if one is open
167 if (Regions.isRegionActive(Description: InstrumentKind))
168 Regions.endRegion(Description: InstrumentKind, Loc);
169 // Start new instrumentation region
170 Regions.beginRegion(Description: InstrumentKind, Loc, Instrument: std::move(I));
171}
172
173} // namespace mca
174} // namespace llvm
175

source code of llvm/tools/llvm-mca/CodeRegionGenerator.cpp