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 */, 52 bool /* unused */) override { 53 Regions.addInstruction(Inst); 54 } 55 56 bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { 57 return true; 58 } 59 60 void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, 61 unsigned ByteAlignment) override {} 62 void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, 63 uint64_t Size = 0, unsigned ByteAlignment = 0, 64 SMLoc Loc = SMLoc()) override {} 65 void EmitGPRel32Value(const MCExpr *Value) override {} 66 void BeginCOFFSymbolDef(const MCSymbol *Symbol) override {} 67 void EmitCOFFSymbolStorageClass(int StorageClass) override {} 68 void EmitCOFFSymbolType(int Type) override {} 69 void EndCOFFSymbolDef() override {} 70 71 ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const { 72 return Regions.getInstructionSequence(Index); 73 } 74 }; 75 76 void MCACommentConsumer::HandleComment(SMLoc Loc, StringRef CommentText) { 77 // Skip empty comments. 78 StringRef Comment(CommentText); 79 if (Comment.empty()) 80 return; 81 82 // Skip spaces and tabs. 83 unsigned Position = Comment.find_first_not_of(" \t"); 84 if (Position >= Comment.size()) 85 // We reached the end of the comment. Bail out. 86 return; 87 88 Comment = Comment.drop_front(Position); 89 if (Comment.consume_front("LLVM-MCA-END")) { 90 Regions.endRegion(Loc); 91 return; 92 } 93 94 // Try to parse the LLVM-MCA-BEGIN comment. 95 if (!Comment.consume_front("LLVM-MCA-BEGIN")) 96 return; 97 98 // Skip spaces and tabs. 99 Position = Comment.find_first_not_of(" \t"); 100 if (Position < Comment.size()) 101 Comment = Comment.drop_front(Position); 102 // Use the rest of the string as a descriptor for this code snippet. 103 Regions.beginRegion(Comment, Loc); 104 } 105 106 Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions() { 107 MCTargetOptions Opts; 108 Opts.PreserveAsmComments = false; 109 MCStreamerWrapper Str(Ctx, Regions); 110 111 // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM 112 // comments. 113 std::unique_ptr<MCAsmParser> Parser( 114 createMCAsmParser(Regions.getSourceMgr(), Ctx, Str, MAI)); 115 MCAsmLexer &Lexer = Parser->getLexer(); 116 MCACommentConsumer CC(Regions); 117 Lexer.setCommentConsumer(&CC); 118 119 // Create a target-specific parser and perform the parse. 120 std::unique_ptr<MCTargetAsmParser> TAP( 121 TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts)); 122 if (!TAP) 123 return make_error<StringError>( 124 "This target does not support assembly parsing.", 125 inconvertibleErrorCode()); 126 Parser->setTargetParser(*TAP); 127 Parser->Run(false); 128 129 // Get the assembler dialect from the input. llvm-mca will use this as the 130 // default dialect when printing reports. 131 AssemblerDialect = Parser->getAssemblerDialect(); 132 return Regions; 133 } 134 135 } // namespace mca 136 } // namespace llvm 137