xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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