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)31bdd1243dSDimitry Andric Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions(
32bdd1243dSDimitry Andric     const std::unique_ptr<MCInstPrinter> &IP) {
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);
4406c3fb27SDimitry Andric   TheTarget.createAsmTargetStreamer(*Str, FOSRef, IP.get(),
45bdd1243dSDimitry Andric                                     /*IsVerboseAsm=*/true);
46bdd1243dSDimitry Andric 
47bdd1243dSDimitry Andric   // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM
48bdd1243dSDimitry Andric   // comments.
49bdd1243dSDimitry Andric   std::unique_ptr<MCAsmParser> Parser(
5006c3fb27SDimitry Andric       createMCAsmParser(Regions.getSourceMgr(), Ctx, *Str, MAI));
51bdd1243dSDimitry Andric   MCAsmLexer &Lexer = Parser->getLexer();
52bdd1243dSDimitry Andric   MCACommentConsumer *CCP = getCommentConsumer();
53bdd1243dSDimitry Andric   Lexer.setCommentConsumer(CCP);
54bdd1243dSDimitry Andric   // Enable support for MASM literal numbers (example: 05h, 101b).
55bdd1243dSDimitry Andric   Lexer.setLexMasmIntegers(true);
56bdd1243dSDimitry Andric 
57bdd1243dSDimitry Andric   std::unique_ptr<MCTargetAsmParser> TAP(
58bdd1243dSDimitry Andric       TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts));
59bdd1243dSDimitry Andric   if (!TAP)
60bdd1243dSDimitry Andric     return make_error<StringError>(
61bdd1243dSDimitry Andric         "This target does not support assembly parsing.",
62bdd1243dSDimitry Andric         inconvertibleErrorCode());
63bdd1243dSDimitry Andric   Parser->setTargetParser(*TAP);
64bdd1243dSDimitry Andric   Parser->Run(false);
65bdd1243dSDimitry Andric 
66bdd1243dSDimitry Andric   if (CCP->hadErr())
67bdd1243dSDimitry Andric     return make_error<StringError>("There was an error parsing comments.",
68bdd1243dSDimitry Andric                                    inconvertibleErrorCode());
69bdd1243dSDimitry Andric 
70bdd1243dSDimitry Andric   // Set the assembler dialect from the input. llvm-mca will use this as the
71bdd1243dSDimitry Andric   // default dialect when printing reports.
72bdd1243dSDimitry Andric   AssemblerDialect = Parser->getAssemblerDialect();
73bdd1243dSDimitry Andric   return Regions;
74bdd1243dSDimitry Andric }
75bdd1243dSDimitry Andric 
HandleComment(SMLoc Loc,StringRef CommentText)76bdd1243dSDimitry Andric void AnalysisRegionCommentConsumer::HandleComment(SMLoc Loc,
77bdd1243dSDimitry Andric                                                   StringRef CommentText) {
780b57cec5SDimitry Andric   // Skip empty comments.
790b57cec5SDimitry Andric   StringRef Comment(CommentText);
800b57cec5SDimitry Andric   if (Comment.empty())
810b57cec5SDimitry Andric     return;
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   // Skip spaces and tabs.
840b57cec5SDimitry Andric   unsigned Position = Comment.find_first_not_of(" \t");
850b57cec5SDimitry Andric   if (Position >= Comment.size())
860b57cec5SDimitry Andric     // We reached the end of the comment. Bail out.
870b57cec5SDimitry Andric     return;
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   Comment = Comment.drop_front(Position);
900b57cec5SDimitry Andric   if (Comment.consume_front("LLVM-MCA-END")) {
910b57cec5SDimitry Andric     // Skip spaces and tabs.
920b57cec5SDimitry Andric     Position = Comment.find_first_not_of(" \t");
930b57cec5SDimitry Andric     if (Position < Comment.size())
940b57cec5SDimitry Andric       Comment = Comment.drop_front(Position);
950b57cec5SDimitry Andric     Regions.endRegion(Comment, Loc);
960b57cec5SDimitry Andric     return;
970b57cec5SDimitry Andric   }
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric   // Try to parse the LLVM-MCA-BEGIN comment.
1000b57cec5SDimitry Andric   if (!Comment.consume_front("LLVM-MCA-BEGIN"))
1010b57cec5SDimitry Andric     return;
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   // Skip spaces and tabs.
1040b57cec5SDimitry Andric   Position = Comment.find_first_not_of(" \t");
1050b57cec5SDimitry Andric   if (Position < Comment.size())
1060b57cec5SDimitry Andric     Comment = Comment.drop_front(Position);
1070b57cec5SDimitry Andric   // Use the rest of the string as a descriptor for this code snippet.
1080b57cec5SDimitry Andric   Regions.beginRegion(Comment, Loc);
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric 
HandleComment(SMLoc Loc,StringRef CommentText)111bdd1243dSDimitry Andric void InstrumentRegionCommentConsumer::HandleComment(SMLoc Loc,
112bdd1243dSDimitry Andric                                                     StringRef CommentText) {
113bdd1243dSDimitry Andric   // Skip empty comments.
114bdd1243dSDimitry Andric   StringRef Comment(CommentText);
115bdd1243dSDimitry Andric   if (Comment.empty())
116bdd1243dSDimitry Andric     return;
1170b57cec5SDimitry Andric 
118bdd1243dSDimitry Andric   // Skip spaces and tabs.
119bdd1243dSDimitry Andric   unsigned Position = Comment.find_first_not_of(" \t");
120bdd1243dSDimitry Andric   if (Position >= Comment.size())
121bdd1243dSDimitry Andric     // We reached the end of the comment. Bail out.
122bdd1243dSDimitry Andric     return;
123bdd1243dSDimitry Andric   Comment = Comment.drop_front(Position);
124fe6060f1SDimitry Andric 
125bdd1243dSDimitry Andric   // Bail out if not an MCA style comment
126bdd1243dSDimitry Andric   if (!Comment.consume_front("LLVM-MCA-"))
127bdd1243dSDimitry Andric     return;
1280b57cec5SDimitry Andric 
129bdd1243dSDimitry Andric   // Skip AnalysisRegion comments
130bdd1243dSDimitry Andric   if (Comment.consume_front("BEGIN") || Comment.consume_front("END"))
131bdd1243dSDimitry Andric     return;
1320b57cec5SDimitry Andric 
133bdd1243dSDimitry Andric   if (IM.shouldIgnoreInstruments())
134bdd1243dSDimitry Andric     return;
135bdd1243dSDimitry Andric 
136bdd1243dSDimitry Andric   auto [InstrumentKind, Data] = Comment.split(" ");
137bdd1243dSDimitry Andric 
138bdd1243dSDimitry Andric   // An error if not of the form LLVM-MCA-TARGET-KIND
139bdd1243dSDimitry Andric   if (!IM.supportsInstrumentType(InstrumentKind)) {
140bdd1243dSDimitry Andric     if (InstrumentKind.empty())
141bdd1243dSDimitry Andric       SM.PrintMessage(
142bdd1243dSDimitry Andric           Loc, llvm::SourceMgr::DK_Error,
143bdd1243dSDimitry Andric           "No instrumentation kind was provided in LLVM-MCA comment");
144bdd1243dSDimitry Andric     else
145bdd1243dSDimitry Andric       SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
146bdd1243dSDimitry Andric                       "Unknown instrumentation type in LLVM-MCA comment: " +
147bdd1243dSDimitry Andric                           InstrumentKind);
148bdd1243dSDimitry Andric     FoundError = true;
149bdd1243dSDimitry Andric     return;
150bdd1243dSDimitry Andric   }
151bdd1243dSDimitry Andric 
15206c3fb27SDimitry Andric   UniqueInstrument I = IM.createInstrument(InstrumentKind, Data);
153bdd1243dSDimitry Andric   if (!I) {
154bdd1243dSDimitry Andric     if (Data.empty())
155bdd1243dSDimitry Andric       SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
156bdd1243dSDimitry Andric                       "Failed to create " + InstrumentKind +
157bdd1243dSDimitry Andric                           " instrument with no data");
158bdd1243dSDimitry Andric     else
159bdd1243dSDimitry Andric       SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
160bdd1243dSDimitry Andric                       "Failed to create " + InstrumentKind +
161bdd1243dSDimitry Andric                           " instrument with data: " + Data);
162bdd1243dSDimitry Andric     FoundError = true;
163bdd1243dSDimitry Andric     return;
164bdd1243dSDimitry Andric   }
165bdd1243dSDimitry Andric 
166bdd1243dSDimitry Andric   // End InstrumentType region if one is open
167bdd1243dSDimitry Andric   if (Regions.isRegionActive(InstrumentKind))
168bdd1243dSDimitry Andric     Regions.endRegion(InstrumentKind, Loc);
169bdd1243dSDimitry Andric   // Start new instrumentation region
17006c3fb27SDimitry Andric   Regions.beginRegion(InstrumentKind, Loc, std::move(I));
1710b57cec5SDimitry Andric }
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric } // namespace mca
1740b57cec5SDimitry Andric } // namespace llvm
175