Home | History | Annotate | Line # | Download | only in llvm-mca
      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/MCStreamer.h"
     21 #include "llvm/MC/MCTargetOptions.h"
     22 #include "llvm/Support/Error.h"
     23 #include "llvm/Support/SMLoc.h"
     24 #include <memory>
     25 
     26 namespace llvm {
     27 namespace mca {
     28 
     29 // This virtual dtor serves as the anchor for the CodeRegionGenerator class.
     30 CodeRegionGenerator::~CodeRegionGenerator() {}
     31 
     32 // A comment consumer that parses strings.  The only valid tokens are strings.
     33 class MCACommentConsumer : public AsmCommentConsumer {
     34 public:
     35   CodeRegions &Regions;
     36 
     37   MCACommentConsumer(CodeRegions &R) : Regions(R) {}
     38   void HandleComment(SMLoc Loc, StringRef CommentText) override;
     39 };
     40 
     41 // This class provides the callbacks that occur when parsing input assembly.
     42 class MCStreamerWrapper final : public MCStreamer {
     43   CodeRegions &Regions;
     44 
     45 public:
     46   MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R)
     47       : MCStreamer(Context), Regions(R) {}
     48 
     49   // We only want to intercept the emission of new instructions.
     50   virtual void emitInstruction(const MCInst &Inst,
     51                                const MCSubtargetInfo & /* unused */) override {
     52     Regions.addInstruction(Inst);
     53   }
     54 
     55   bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
     56     return true;
     57   }
     58 
     59   void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
     60                         unsigned ByteAlignment) override {}
     61   void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
     62                     uint64_t Size = 0, unsigned ByteAlignment = 0,
     63                     SMLoc Loc = SMLoc()) override {}
     64   void emitGPRel32Value(const MCExpr *Value) override {}
     65   void BeginCOFFSymbolDef(const MCSymbol *Symbol) override {}
     66   void EmitCOFFSymbolStorageClass(int StorageClass) override {}
     67   void EmitCOFFSymbolType(int Type) override {}
     68   void EndCOFFSymbolDef() override {}
     69 
     70   ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const {
     71     return Regions.getInstructionSequence(Index);
     72   }
     73 };
     74 
     75 void MCACommentConsumer::HandleComment(SMLoc Loc, StringRef CommentText) {
     76   // Skip empty comments.
     77   StringRef Comment(CommentText);
     78   if (Comment.empty())
     79     return;
     80 
     81   // Skip spaces and tabs.
     82   unsigned Position = Comment.find_first_not_of(" \t");
     83   if (Position >= Comment.size())
     84     // We reached the end of the comment. Bail out.
     85     return;
     86 
     87   Comment = Comment.drop_front(Position);
     88   if (Comment.consume_front("LLVM-MCA-END")) {
     89     // Skip spaces and tabs.
     90     Position = Comment.find_first_not_of(" \t");
     91     if (Position < Comment.size())
     92       Comment = Comment.drop_front(Position);
     93     Regions.endRegion(Comment, Loc);
     94     return;
     95   }
     96 
     97   // Try to parse the LLVM-MCA-BEGIN comment.
     98   if (!Comment.consume_front("LLVM-MCA-BEGIN"))
     99     return;
    100 
    101   // Skip spaces and tabs.
    102   Position = Comment.find_first_not_of(" \t");
    103   if (Position < Comment.size())
    104     Comment = Comment.drop_front(Position);
    105   // Use the rest of the string as a descriptor for this code snippet.
    106   Regions.beginRegion(Comment, Loc);
    107 }
    108 
    109 Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions(
    110     const std::unique_ptr<MCInstPrinter> &IP) {
    111   MCTargetOptions Opts;
    112   Opts.PreserveAsmComments = false;
    113   MCStreamerWrapper Str(Ctx, Regions);
    114 
    115   // Need to initialize an MCTargetStreamer otherwise
    116   // certain asm directives will cause a segfault.
    117   // Using nulls() so that anything emitted by the MCTagetStreamer
    118   // doesn't show up in the llvm-mca output.
    119   raw_ostream &OSRef = nulls();
    120   formatted_raw_ostream FOSRef(OSRef);
    121   TheTarget.createAsmTargetStreamer(Str, FOSRef, IP.get(),
    122                                     /*IsVerboseAsm=*/true);
    123 
    124   // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM
    125   // comments.
    126   std::unique_ptr<MCAsmParser> Parser(
    127       createMCAsmParser(Regions.getSourceMgr(), Ctx, Str, MAI));
    128   MCAsmLexer &Lexer = Parser->getLexer();
    129   MCACommentConsumer CC(Regions);
    130   Lexer.setCommentConsumer(&CC);
    131   // Enable support for MASM literal numbers (example: 05h, 101b).
    132   Lexer.setLexMasmIntegers(true);
    133 
    134   std::unique_ptr<MCTargetAsmParser> TAP(
    135       TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts));
    136   if (!TAP)
    137     return make_error<StringError>(
    138         "This target does not support assembly parsing.",
    139         inconvertibleErrorCode());
    140   Parser->setTargetParser(*TAP);
    141   Parser->Run(false);
    142 
    143   // Set the assembler dialect from the input. llvm-mca will use this as the
    144   // default dialect when printing reports.
    145   AssemblerDialect = Parser->getAssemblerDialect();
    146   return Regions;
    147 }
    148 
    149 } // namespace mca
    150 } // namespace llvm
    151