xref: /llvm-project/llvm/tools/llvm-mca/CodeRegionGenerator.cpp (revision e9c851484bfeb270368bc71e9d7a4bec986f91e7)
123f7106eSMatt Davis //===----------------------- CodeRegionGenerator.cpp ------------*- C++ -*-===//
223f7106eSMatt Davis //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
623f7106eSMatt Davis //
723f7106eSMatt Davis //===----------------------------------------------------------------------===//
823f7106eSMatt Davis /// \file
923f7106eSMatt Davis ///
1023f7106eSMatt Davis /// This file defines classes responsible for generating llvm-mca
1123f7106eSMatt Davis /// CodeRegions from various types of input. llvm-mca only analyzes CodeRegions,
1223f7106eSMatt Davis /// so the classes here provide the input-to-CodeRegions translation.
1323f7106eSMatt Davis //
1423f7106eSMatt Davis //===----------------------------------------------------------------------===//
1523f7106eSMatt Davis 
1623f7106eSMatt Davis #include "CodeRegionGenerator.h"
1723f7106eSMatt Davis #include "llvm/ADT/ArrayRef.h"
1823f7106eSMatt Davis #include "llvm/ADT/StringRef.h"
1923f7106eSMatt Davis #include "llvm/MC/MCParser/MCTargetAsmParser.h"
2023f7106eSMatt Davis #include "llvm/MC/MCTargetOptions.h"
2123f7106eSMatt Davis #include "llvm/Support/Error.h"
2223f7106eSMatt Davis #include "llvm/Support/SMLoc.h"
2323f7106eSMatt Davis #include <memory>
2423f7106eSMatt Davis 
2523f7106eSMatt Davis namespace llvm {
2623f7106eSMatt Davis namespace mca {
2723f7106eSMatt Davis 
2823f7106eSMatt Davis // This virtual dtor serves as the anchor for the CodeRegionGenerator class.
2923f7106eSMatt Davis CodeRegionGenerator::~CodeRegionGenerator() {}
3023f7106eSMatt Davis 
3198e342dcSMichael Maitland Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions(
321de0535eSPeter Waller     const std::unique_ptr<MCInstPrinter> &IP, bool SkipFailures) {
3398e342dcSMichael Maitland   MCTargetOptions Opts;
3498e342dcSMichael Maitland   Opts.PreserveAsmComments = false;
3598e342dcSMichael Maitland   CodeRegions &Regions = getRegions();
36ecf372f9SMichael Maitland   MCStreamerWrapper *Str = getMCStreamer();
3798e342dcSMichael Maitland 
3898e342dcSMichael Maitland   // Need to initialize an MCTargetStreamer otherwise
3998e342dcSMichael Maitland   // certain asm directives will cause a segfault.
4098e342dcSMichael Maitland   // Using nulls() so that anything emitted by the MCTargetStreamer
4198e342dcSMichael Maitland   // doesn't show up in the llvm-mca output.
4298e342dcSMichael Maitland   raw_ostream &OSRef = nulls();
4398e342dcSMichael Maitland   formatted_raw_ostream FOSRef(OSRef);
44*e9c85148SFangrui Song   TheTarget.createAsmTargetStreamer(*Str, FOSRef, IP.get());
4598e342dcSMichael Maitland 
4698e342dcSMichael Maitland   // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM
4798e342dcSMichael Maitland   // comments.
4898e342dcSMichael Maitland   std::unique_ptr<MCAsmParser> Parser(
49ecf372f9SMichael Maitland       createMCAsmParser(Regions.getSourceMgr(), Ctx, *Str, MAI));
5098e342dcSMichael Maitland   MCAsmLexer &Lexer = Parser->getLexer();
5198e342dcSMichael Maitland   MCACommentConsumer *CCP = getCommentConsumer();
5298e342dcSMichael Maitland   Lexer.setCommentConsumer(CCP);
5398e342dcSMichael Maitland   // Enable support for MASM literal numbers (example: 05h, 101b).
5498e342dcSMichael Maitland   Lexer.setLexMasmIntegers(true);
5598e342dcSMichael Maitland 
5698e342dcSMichael Maitland   std::unique_ptr<MCTargetAsmParser> TAP(
5798e342dcSMichael Maitland       TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts));
5898e342dcSMichael Maitland   if (!TAP)
5998e342dcSMichael Maitland     return make_error<StringError>(
6098e342dcSMichael Maitland         "This target does not support assembly parsing.",
6198e342dcSMichael Maitland         inconvertibleErrorCode());
6298e342dcSMichael Maitland   Parser->setTargetParser(*TAP);
631de0535eSPeter Waller   // Parser->Run() confusingly returns true on errors, in which case the errors
641de0535eSPeter Waller   // were already shown to the user. SkipFailures implies continuing in the
651de0535eSPeter Waller   // presence of any kind of failure within the parser, in which case failing
661de0535eSPeter Waller   // input lines are not represented, but the rest of the input remains.
671de0535eSPeter Waller   if (Parser->Run(false) && !SkipFailures) {
681de0535eSPeter Waller     const char *Message = "Assembly input parsing had errors, use "
691de0535eSPeter Waller                           "-skip-unsupported-instructions=parse-failure "
701de0535eSPeter Waller                           "to drop failing lines from the input.";
711de0535eSPeter Waller     return make_error<StringError>(Message, inconvertibleErrorCode());
721de0535eSPeter Waller   }
7398e342dcSMichael Maitland 
7498e342dcSMichael Maitland   if (CCP->hadErr())
7598e342dcSMichael Maitland     return make_error<StringError>("There was an error parsing comments.",
7698e342dcSMichael Maitland                                    inconvertibleErrorCode());
7798e342dcSMichael Maitland 
7898e342dcSMichael Maitland   // Set the assembler dialect from the input. llvm-mca will use this as the
7998e342dcSMichael Maitland   // default dialect when printing reports.
8098e342dcSMichael Maitland   AssemblerDialect = Parser->getAssemblerDialect();
8198e342dcSMichael Maitland   return Regions;
8298e342dcSMichael Maitland }
8398e342dcSMichael Maitland 
8498e342dcSMichael Maitland void AnalysisRegionCommentConsumer::HandleComment(SMLoc Loc,
8598e342dcSMichael Maitland                                                   StringRef CommentText) {
8623f7106eSMatt Davis   // Skip empty comments.
8723f7106eSMatt Davis   StringRef Comment(CommentText);
8823f7106eSMatt Davis   if (Comment.empty())
8923f7106eSMatt Davis     return;
9023f7106eSMatt Davis 
9123f7106eSMatt Davis   // Skip spaces and tabs.
9223f7106eSMatt Davis   unsigned Position = Comment.find_first_not_of(" \t");
9323f7106eSMatt Davis   if (Position >= Comment.size())
9423f7106eSMatt Davis     // We reached the end of the comment. Bail out.
9523f7106eSMatt Davis     return;
9623f7106eSMatt Davis 
9723f7106eSMatt Davis   Comment = Comment.drop_front(Position);
9823f7106eSMatt Davis   if (Comment.consume_front("LLVM-MCA-END")) {
994e62554bSAndrea Di Biagio     // Skip spaces and tabs.
1004e62554bSAndrea Di Biagio     Position = Comment.find_first_not_of(" \t");
1014e62554bSAndrea Di Biagio     if (Position < Comment.size())
1024e62554bSAndrea Di Biagio       Comment = Comment.drop_front(Position);
1034e62554bSAndrea Di Biagio     Regions.endRegion(Comment, Loc);
10423f7106eSMatt Davis     return;
10523f7106eSMatt Davis   }
10623f7106eSMatt Davis 
10723f7106eSMatt Davis   // Try to parse the LLVM-MCA-BEGIN comment.
10823f7106eSMatt Davis   if (!Comment.consume_front("LLVM-MCA-BEGIN"))
10923f7106eSMatt Davis     return;
11023f7106eSMatt Davis 
11123f7106eSMatt Davis   // Skip spaces and tabs.
11223f7106eSMatt Davis   Position = Comment.find_first_not_of(" \t");
11323f7106eSMatt Davis   if (Position < Comment.size())
11423f7106eSMatt Davis     Comment = Comment.drop_front(Position);
11523f7106eSMatt Davis   // Use the rest of the string as a descriptor for this code snippet.
11623f7106eSMatt Davis   Regions.beginRegion(Comment, Loc);
11723f7106eSMatt Davis }
11823f7106eSMatt Davis 
11998e342dcSMichael Maitland void InstrumentRegionCommentConsumer::HandleComment(SMLoc Loc,
12098e342dcSMichael Maitland                                                     StringRef CommentText) {
12198e342dcSMichael Maitland   // Skip empty comments.
12298e342dcSMichael Maitland   StringRef Comment(CommentText);
12398e342dcSMichael Maitland   if (Comment.empty())
12498e342dcSMichael Maitland     return;
12523f7106eSMatt Davis 
12698e342dcSMichael Maitland   // Skip spaces and tabs.
12798e342dcSMichael Maitland   unsigned Position = Comment.find_first_not_of(" \t");
12898e342dcSMichael Maitland   if (Position >= Comment.size())
12998e342dcSMichael Maitland     // We reached the end of the comment. Bail out.
13098e342dcSMichael Maitland     return;
13198e342dcSMichael Maitland   Comment = Comment.drop_front(Position);
132e5d59db4SPatrick Holland 
13398e342dcSMichael Maitland   // Bail out if not an MCA style comment
13498e342dcSMichael Maitland   if (!Comment.consume_front("LLVM-MCA-"))
13598e342dcSMichael Maitland     return;
13623f7106eSMatt Davis 
13798e342dcSMichael Maitland   // Skip AnalysisRegion comments
13898e342dcSMichael Maitland   if (Comment.consume_front("BEGIN") || Comment.consume_front("END"))
13998e342dcSMichael Maitland     return;
14023f7106eSMatt Davis 
14198e342dcSMichael Maitland   if (IM.shouldIgnoreInstruments())
14298e342dcSMichael Maitland     return;
14398e342dcSMichael Maitland 
14498e342dcSMichael Maitland   auto [InstrumentKind, Data] = Comment.split(" ");
14598e342dcSMichael Maitland 
14698e342dcSMichael Maitland   // An error if not of the form LLVM-MCA-TARGET-KIND
14798e342dcSMichael Maitland   if (!IM.supportsInstrumentType(InstrumentKind)) {
14898e342dcSMichael Maitland     if (InstrumentKind.empty())
14998e342dcSMichael Maitland       SM.PrintMessage(
15098e342dcSMichael Maitland           Loc, llvm::SourceMgr::DK_Error,
15198e342dcSMichael Maitland           "No instrumentation kind was provided in LLVM-MCA comment");
15298e342dcSMichael Maitland     else
15398e342dcSMichael Maitland       SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
15498e342dcSMichael Maitland                       "Unknown instrumentation type in LLVM-MCA comment: " +
15598e342dcSMichael Maitland                           InstrumentKind);
15698e342dcSMichael Maitland     FoundError = true;
15798e342dcSMichael Maitland     return;
15898e342dcSMichael Maitland   }
15998e342dcSMichael Maitland 
16056674e8eSMichael Maitland   UniqueInstrument I = IM.createInstrument(InstrumentKind, Data);
16198e342dcSMichael Maitland   if (!I) {
16298e342dcSMichael Maitland     if (Data.empty())
16398e342dcSMichael Maitland       SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
16498e342dcSMichael Maitland                       "Failed to create " + InstrumentKind +
16598e342dcSMichael Maitland                           " instrument with no data");
16698e342dcSMichael Maitland     else
16798e342dcSMichael Maitland       SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
16898e342dcSMichael Maitland                       "Failed to create " + InstrumentKind +
16998e342dcSMichael Maitland                           " instrument with data: " + Data);
17098e342dcSMichael Maitland     FoundError = true;
17198e342dcSMichael Maitland     return;
17298e342dcSMichael Maitland   }
17398e342dcSMichael Maitland 
17498e342dcSMichael Maitland   // End InstrumentType region if one is open
17598e342dcSMichael Maitland   if (Regions.isRegionActive(InstrumentKind))
17698e342dcSMichael Maitland     Regions.endRegion(InstrumentKind, Loc);
17798e342dcSMichael Maitland   // Start new instrumentation region
17856674e8eSMichael Maitland   Regions.beginRegion(InstrumentKind, Loc, std::move(I));
17923f7106eSMatt Davis }
18023f7106eSMatt Davis 
18123f7106eSMatt Davis } // namespace mca
18223f7106eSMatt Davis } // namespace llvm
183