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