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/MCAsmLexer.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 void emitInstruction(const MCInst &Inst, 52 const MCSubtargetInfo & /* 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 // Skip spaces and tabs. 91 Position = Comment.find_first_not_of(" \t"); 92 if (Position < Comment.size()) 93 Comment = Comment.drop_front(Position); 94 Regions.endRegion(Comment, Loc); 95 return; 96 } 97 98 // Try to parse the LLVM-MCA-BEGIN comment. 99 if (!Comment.consume_front("LLVM-MCA-BEGIN")) 100 return; 101 102 // Skip spaces and tabs. 103 Position = Comment.find_first_not_of(" \t"); 104 if (Position < Comment.size()) 105 Comment = Comment.drop_front(Position); 106 // Use the rest of the string as a descriptor for this code snippet. 107 Regions.beginRegion(Comment, Loc); 108 } 109 110 Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions( 111 const std::unique_ptr<MCInstPrinter> &IP) { 112 MCTargetOptions Opts; 113 Opts.PreserveAsmComments = false; 114 MCStreamerWrapper Str(Ctx, Regions); 115 116 // Need to initialize an MCTargetStreamer otherwise 117 // certain asm directives will cause a segfault. 118 // Using nulls() so that anything emitted by the MCTargetStreamer 119 // doesn't show up in the llvm-mca output. 120 raw_ostream &OSRef = nulls(); 121 formatted_raw_ostream FOSRef(OSRef); 122 TheTarget.createAsmTargetStreamer(Str, FOSRef, IP.get(), 123 /*IsVerboseAsm=*/true); 124 125 // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM 126 // comments. 127 std::unique_ptr<MCAsmParser> Parser( 128 createMCAsmParser(Regions.getSourceMgr(), Ctx, Str, MAI)); 129 MCAsmLexer &Lexer = Parser->getLexer(); 130 MCACommentConsumer CC(Regions); 131 Lexer.setCommentConsumer(&CC); 132 // Enable support for MASM literal numbers (example: 05h, 101b). 133 Lexer.setLexMasmIntegers(true); 134 135 std::unique_ptr<MCTargetAsmParser> TAP( 136 TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts)); 137 if (!TAP) 138 return make_error<StringError>( 139 "This target does not support assembly parsing.", 140 inconvertibleErrorCode()); 141 Parser->setTargetParser(*TAP); 142 Parser->Run(false); 143 144 // Set the assembler dialect from the input. llvm-mca will use this as the 145 // default dialect when printing reports. 146 AssemblerDialect = Parser->getAssemblerDialect(); 147 return Regions; 148 } 149 150 } // namespace mca 151 } // namespace llvm 152