CodeRegionGenerator.cpp 5.2 KB

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