10b57cec5SDimitry Andric //===----------------------- CodeRegionGenerator.cpp ------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric /// \file
90b57cec5SDimitry Andric ///
100b57cec5SDimitry Andric /// This file defines classes responsible for generating llvm-mca
110b57cec5SDimitry Andric /// CodeRegions from various types of input. llvm-mca only analyzes CodeRegions,
120b57cec5SDimitry Andric /// so the classes here provide the input-to-CodeRegions translation.
130b57cec5SDimitry Andric //
140b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
150b57cec5SDimitry Andric
160b57cec5SDimitry Andric #include "CodeRegionGenerator.h"
170b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
180b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
190b57cec5SDimitry Andric #include "llvm/MC/MCParser/MCTargetAsmParser.h"
200b57cec5SDimitry Andric #include "llvm/MC/MCTargetOptions.h"
210b57cec5SDimitry Andric #include "llvm/Support/Error.h"
220b57cec5SDimitry Andric #include "llvm/Support/SMLoc.h"
230b57cec5SDimitry Andric #include <memory>
240b57cec5SDimitry Andric
250b57cec5SDimitry Andric namespace llvm {
260b57cec5SDimitry Andric namespace mca {
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric // This virtual dtor serves as the anchor for the CodeRegionGenerator class.
~CodeRegionGenerator()290b57cec5SDimitry Andric CodeRegionGenerator::~CodeRegionGenerator() {}
300b57cec5SDimitry Andric
parseCodeRegions(const std::unique_ptr<MCInstPrinter> & IP,bool SkipFailures)31bdd1243dSDimitry Andric Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions(
32*0fca6ea1SDimitry Andric const std::unique_ptr<MCInstPrinter> &IP, bool SkipFailures) {
33bdd1243dSDimitry Andric MCTargetOptions Opts;
34bdd1243dSDimitry Andric Opts.PreserveAsmComments = false;
35bdd1243dSDimitry Andric CodeRegions &Regions = getRegions();
3606c3fb27SDimitry Andric MCStreamerWrapper *Str = getMCStreamer();
37bdd1243dSDimitry Andric
38bdd1243dSDimitry Andric // Need to initialize an MCTargetStreamer otherwise
39bdd1243dSDimitry Andric // certain asm directives will cause a segfault.
40bdd1243dSDimitry Andric // Using nulls() so that anything emitted by the MCTargetStreamer
41bdd1243dSDimitry Andric // doesn't show up in the llvm-mca output.
42bdd1243dSDimitry Andric raw_ostream &OSRef = nulls();
43bdd1243dSDimitry Andric formatted_raw_ostream FOSRef(OSRef);
44*0fca6ea1SDimitry Andric TheTarget.createAsmTargetStreamer(*Str, FOSRef, IP.get());
45bdd1243dSDimitry Andric
46bdd1243dSDimitry Andric // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM
47bdd1243dSDimitry Andric // comments.
48bdd1243dSDimitry Andric std::unique_ptr<MCAsmParser> Parser(
4906c3fb27SDimitry Andric createMCAsmParser(Regions.getSourceMgr(), Ctx, *Str, MAI));
50bdd1243dSDimitry Andric MCAsmLexer &Lexer = Parser->getLexer();
51bdd1243dSDimitry Andric MCACommentConsumer *CCP = getCommentConsumer();
52bdd1243dSDimitry Andric Lexer.setCommentConsumer(CCP);
53bdd1243dSDimitry Andric // Enable support for MASM literal numbers (example: 05h, 101b).
54bdd1243dSDimitry Andric Lexer.setLexMasmIntegers(true);
55bdd1243dSDimitry Andric
56bdd1243dSDimitry Andric std::unique_ptr<MCTargetAsmParser> TAP(
57bdd1243dSDimitry Andric TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts));
58bdd1243dSDimitry Andric if (!TAP)
59bdd1243dSDimitry Andric return make_error<StringError>(
60bdd1243dSDimitry Andric "This target does not support assembly parsing.",
61bdd1243dSDimitry Andric inconvertibleErrorCode());
62bdd1243dSDimitry Andric Parser->setTargetParser(*TAP);
63*0fca6ea1SDimitry Andric // Parser->Run() confusingly returns true on errors, in which case the errors
64*0fca6ea1SDimitry Andric // were already shown to the user. SkipFailures implies continuing in the
65*0fca6ea1SDimitry Andric // presence of any kind of failure within the parser, in which case failing
66*0fca6ea1SDimitry Andric // input lines are not represented, but the rest of the input remains.
67*0fca6ea1SDimitry Andric if (Parser->Run(false) && !SkipFailures) {
68*0fca6ea1SDimitry Andric const char *Message = "Assembly input parsing had errors, use "
69*0fca6ea1SDimitry Andric "-skip-unsupported-instructions=parse-failure "
70*0fca6ea1SDimitry Andric "to drop failing lines from the input.";
71*0fca6ea1SDimitry Andric return make_error<StringError>(Message, inconvertibleErrorCode());
72*0fca6ea1SDimitry Andric }
73bdd1243dSDimitry Andric
74bdd1243dSDimitry Andric if (CCP->hadErr())
75bdd1243dSDimitry Andric return make_error<StringError>("There was an error parsing comments.",
76bdd1243dSDimitry Andric inconvertibleErrorCode());
77bdd1243dSDimitry Andric
78bdd1243dSDimitry Andric // Set the assembler dialect from the input. llvm-mca will use this as the
79bdd1243dSDimitry Andric // default dialect when printing reports.
80bdd1243dSDimitry Andric AssemblerDialect = Parser->getAssemblerDialect();
81bdd1243dSDimitry Andric return Regions;
82bdd1243dSDimitry Andric }
83bdd1243dSDimitry Andric
HandleComment(SMLoc Loc,StringRef CommentText)84bdd1243dSDimitry Andric void AnalysisRegionCommentConsumer::HandleComment(SMLoc Loc,
85bdd1243dSDimitry Andric StringRef CommentText) {
860b57cec5SDimitry Andric // Skip empty comments.
870b57cec5SDimitry Andric StringRef Comment(CommentText);
880b57cec5SDimitry Andric if (Comment.empty())
890b57cec5SDimitry Andric return;
900b57cec5SDimitry Andric
910b57cec5SDimitry Andric // Skip spaces and tabs.
920b57cec5SDimitry Andric unsigned Position = Comment.find_first_not_of(" \t");
930b57cec5SDimitry Andric if (Position >= Comment.size())
940b57cec5SDimitry Andric // We reached the end of the comment. Bail out.
950b57cec5SDimitry Andric return;
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric Comment = Comment.drop_front(Position);
980b57cec5SDimitry Andric if (Comment.consume_front("LLVM-MCA-END")) {
990b57cec5SDimitry Andric // Skip spaces and tabs.
1000b57cec5SDimitry Andric Position = Comment.find_first_not_of(" \t");
1010b57cec5SDimitry Andric if (Position < Comment.size())
1020b57cec5SDimitry Andric Comment = Comment.drop_front(Position);
1030b57cec5SDimitry Andric Regions.endRegion(Comment, Loc);
1040b57cec5SDimitry Andric return;
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric // Try to parse the LLVM-MCA-BEGIN comment.
1080b57cec5SDimitry Andric if (!Comment.consume_front("LLVM-MCA-BEGIN"))
1090b57cec5SDimitry Andric return;
1100b57cec5SDimitry Andric
1110b57cec5SDimitry Andric // Skip spaces and tabs.
1120b57cec5SDimitry Andric Position = Comment.find_first_not_of(" \t");
1130b57cec5SDimitry Andric if (Position < Comment.size())
1140b57cec5SDimitry Andric Comment = Comment.drop_front(Position);
1150b57cec5SDimitry Andric // Use the rest of the string as a descriptor for this code snippet.
1160b57cec5SDimitry Andric Regions.beginRegion(Comment, Loc);
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric
HandleComment(SMLoc Loc,StringRef CommentText)119bdd1243dSDimitry Andric void InstrumentRegionCommentConsumer::HandleComment(SMLoc Loc,
120bdd1243dSDimitry Andric StringRef CommentText) {
121bdd1243dSDimitry Andric // Skip empty comments.
122bdd1243dSDimitry Andric StringRef Comment(CommentText);
123bdd1243dSDimitry Andric if (Comment.empty())
124bdd1243dSDimitry Andric return;
1250b57cec5SDimitry Andric
126bdd1243dSDimitry Andric // Skip spaces and tabs.
127bdd1243dSDimitry Andric unsigned Position = Comment.find_first_not_of(" \t");
128bdd1243dSDimitry Andric if (Position >= Comment.size())
129bdd1243dSDimitry Andric // We reached the end of the comment. Bail out.
130bdd1243dSDimitry Andric return;
131bdd1243dSDimitry Andric Comment = Comment.drop_front(Position);
132fe6060f1SDimitry Andric
133bdd1243dSDimitry Andric // Bail out if not an MCA style comment
134bdd1243dSDimitry Andric if (!Comment.consume_front("LLVM-MCA-"))
135bdd1243dSDimitry Andric return;
1360b57cec5SDimitry Andric
137bdd1243dSDimitry Andric // Skip AnalysisRegion comments
138bdd1243dSDimitry Andric if (Comment.consume_front("BEGIN") || Comment.consume_front("END"))
139bdd1243dSDimitry Andric return;
1400b57cec5SDimitry Andric
141bdd1243dSDimitry Andric if (IM.shouldIgnoreInstruments())
142bdd1243dSDimitry Andric return;
143bdd1243dSDimitry Andric
144bdd1243dSDimitry Andric auto [InstrumentKind, Data] = Comment.split(" ");
145bdd1243dSDimitry Andric
146bdd1243dSDimitry Andric // An error if not of the form LLVM-MCA-TARGET-KIND
147bdd1243dSDimitry Andric if (!IM.supportsInstrumentType(InstrumentKind)) {
148bdd1243dSDimitry Andric if (InstrumentKind.empty())
149bdd1243dSDimitry Andric SM.PrintMessage(
150bdd1243dSDimitry Andric Loc, llvm::SourceMgr::DK_Error,
151bdd1243dSDimitry Andric "No instrumentation kind was provided in LLVM-MCA comment");
152bdd1243dSDimitry Andric else
153bdd1243dSDimitry Andric SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
154bdd1243dSDimitry Andric "Unknown instrumentation type in LLVM-MCA comment: " +
155bdd1243dSDimitry Andric InstrumentKind);
156bdd1243dSDimitry Andric FoundError = true;
157bdd1243dSDimitry Andric return;
158bdd1243dSDimitry Andric }
159bdd1243dSDimitry Andric
16006c3fb27SDimitry Andric UniqueInstrument I = IM.createInstrument(InstrumentKind, Data);
161bdd1243dSDimitry Andric if (!I) {
162bdd1243dSDimitry Andric if (Data.empty())
163bdd1243dSDimitry Andric SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
164bdd1243dSDimitry Andric "Failed to create " + InstrumentKind +
165bdd1243dSDimitry Andric " instrument with no data");
166bdd1243dSDimitry Andric else
167bdd1243dSDimitry Andric SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
168bdd1243dSDimitry Andric "Failed to create " + InstrumentKind +
169bdd1243dSDimitry Andric " instrument with data: " + Data);
170bdd1243dSDimitry Andric FoundError = true;
171bdd1243dSDimitry Andric return;
172bdd1243dSDimitry Andric }
173bdd1243dSDimitry Andric
174bdd1243dSDimitry Andric // End InstrumentType region if one is open
175bdd1243dSDimitry Andric if (Regions.isRegionActive(InstrumentKind))
176bdd1243dSDimitry Andric Regions.endRegion(InstrumentKind, Loc);
177bdd1243dSDimitry Andric // Start new instrumentation region
17806c3fb27SDimitry Andric Regions.beginRegion(InstrumentKind, Loc, std::move(I));
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric
1810b57cec5SDimitry Andric } // namespace mca
1820b57cec5SDimitry Andric } // namespace llvm
183