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 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