1 //===----------------------- CodeRegionGenerator.cpp ------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// \file 10 /// 11 /// This file defines classes responsible for generating llvm-mca 12 /// CodeRegions from various types of input. llvm-mca only analyzes CodeRegions, 13 /// so the classes here provide the input-to-CodeRegions translation. 14 // 15 //===----------------------------------------------------------------------===// 16 17 #include "CodeRegionGenerator.h" 18 #include "llvm/ADT/ArrayRef.h" 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/MC/MCParser/MCTargetAsmParser.h" 21 #include "llvm/MC/MCStreamer.h" 22 #include "llvm/MC/MCTargetOptions.h" 23 #include "llvm/Support/Error.h" 24 #include "llvm/Support/SMLoc.h" 25 #include <memory> 26 27 namespace llvm { 28 namespace mca { 29 30 // This virtual dtor serves as the anchor for the CodeRegionGenerator class. 31 CodeRegionGenerator::~CodeRegionGenerator() {} 32 33 // A comment consumer that parses strings. The only valid tokens are strings. 34 class MCACommentConsumer : public AsmCommentConsumer { 35 public: 36 CodeRegions &Regions; 37 38 MCACommentConsumer(CodeRegions &R) : Regions(R) {} 39 void HandleComment(SMLoc Loc, StringRef CommentText) override; 40 }; 41 42 // This class provides the callbacks that occur when parsing input assembly. 43 class MCStreamerWrapper final : public MCStreamer { 44 CodeRegions &Regions; 45 46 public: 47 MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R) 48 : MCStreamer(Context), Regions(R) {} 49 50 // We only want to intercept the emission of new instructions. 51 virtual void EmitInstruction(const MCInst &Inst, 52 const MCSubtargetInfo & /* unused */, 53 bool /* unused */) override { 54 Regions.addInstruction(Inst); 55 } 56 57 bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { 58 return true; 59 } 60 61 void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, 62 unsigned ByteAlignment) override {} 63 void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, 64 uint64_t Size = 0, unsigned ByteAlignment = 0, 65 SMLoc Loc = SMLoc()) override {} 66 void EmitGPRel32Value(const MCExpr *Value) override {} 67 void BeginCOFFSymbolDef(const MCSymbol *Symbol) override {} 68 void EmitCOFFSymbolStorageClass(int StorageClass) override {} 69 void EmitCOFFSymbolType(int Type) override {} 70 void EndCOFFSymbolDef() override {} 71 72 ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const { 73 return Regions.getInstructionSequence(Index); 74 } 75 }; 76 77 void MCACommentConsumer::HandleComment(SMLoc Loc, StringRef CommentText) { 78 // Skip empty comments. 79 StringRef Comment(CommentText); 80 if (Comment.empty()) 81 return; 82 83 // Skip spaces and tabs. 84 unsigned Position = Comment.find_first_not_of(" \t"); 85 if (Position >= Comment.size()) 86 // We reached the end of the comment. Bail out. 87 return; 88 89 Comment = Comment.drop_front(Position); 90 if (Comment.consume_front("LLVM-MCA-END")) { 91 Regions.endRegion(Loc); 92 return; 93 } 94 95 // Try to parse the LLVM-MCA-BEGIN comment. 96 if (!Comment.consume_front("LLVM-MCA-BEGIN")) 97 return; 98 99 // Skip spaces and tabs. 100 Position = Comment.find_first_not_of(" \t"); 101 if (Position < Comment.size()) 102 Comment = Comment.drop_front(Position); 103 // Use the rest of the string as a descriptor for this code snippet. 104 Regions.beginRegion(Comment, Loc); 105 } 106 107 Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions() { 108 MCTargetOptions Opts; 109 Opts.PreserveAsmComments = false; 110 MCStreamerWrapper Str(Ctx, Regions); 111 112 // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM 113 // comments. 114 std::unique_ptr<MCAsmParser> Parser( 115 createMCAsmParser(Regions.getSourceMgr(), Ctx, Str, MAI)); 116 MCAsmLexer &Lexer = Parser->getLexer(); 117 MCACommentConsumer CC(Regions); 118 Lexer.setCommentConsumer(&CC); 119 120 // Create a target-specific parser and perform the parse. 121 std::unique_ptr<MCTargetAsmParser> TAP( 122 TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts)); 123 if (!TAP) 124 return make_error<StringError>( 125 "This target does not support assembly parsing.", 126 inconvertibleErrorCode()); 127 Parser->setTargetParser(*TAP); 128 Parser->Run(false); 129 130 // Get the assembler dialect from the input. llvm-mca will use this as the 131 // default dialect when printing reports. 132 AssemblerDialect = Parser->getAssemblerDialect(); 133 return Regions; 134 } 135 136 } // namespace mca 137 } // namespace llvm 138