CodeRegionGenerator.cpp revision 360784
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
26namespace llvm {
27namespace mca {
28
29// This virtual dtor serves as the anchor for the CodeRegionGenerator class.
30CodeRegionGenerator::~CodeRegionGenerator() {}
31
32// A comment consumer that parses strings.  The only valid tokens are strings.
33class MCACommentConsumer : public AsmCommentConsumer {
34public:
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.
42class MCStreamerWrapper final : public MCStreamer {
43  CodeRegions &Regions;
44
45public:
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
75void 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
109Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions() {
110  MCTargetOptions Opts;
111  Opts.PreserveAsmComments = false;
112  MCStreamerWrapper Str(Ctx, Regions);
113
114  // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM
115  // comments.
116  std::unique_ptr<MCAsmParser> Parser(
117      createMCAsmParser(Regions.getSourceMgr(), Ctx, Str, MAI));
118  MCAsmLexer &Lexer = Parser->getLexer();
119  MCACommentConsumer CC(Regions);
120  Lexer.setCommentConsumer(&CC);
121  // Enable support for MASM literal numbers (example: 05h, 101b).
122  Lexer.setLexMasmIntegers(true);
123
124  std::unique_ptr<MCTargetAsmParser> TAP(
125      TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts));
126  if (!TAP)
127    return make_error<StringError>(
128        "This target does not support assembly parsing.",
129        inconvertibleErrorCode());
130  Parser->setTargetParser(*TAP);
131  Parser->Run(false);
132
133  // Set the assembler dialect from the input. llvm-mca will use this as the
134  // default dialect when printing reports.
135  AssemblerDialect = Parser->getAssemblerDialect();
136  return Regions;
137}
138
139} // namespace mca
140} // namespace llvm
141