10b57cec5SDimitry Andric //===----------------------- CodeRegionGenerator.cpp ------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// \file 90b57cec5SDimitry Andric /// 100b57cec5SDimitry Andric /// This file defines classes responsible for generating llvm-mca 110b57cec5SDimitry Andric /// CodeRegions from various types of input. llvm-mca only analyzes CodeRegions, 120b57cec5SDimitry Andric /// so the classes here provide the input-to-CodeRegions translation. 130b57cec5SDimitry Andric // 140b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #include "CodeRegionGenerator.h" 170b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 180b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 190b57cec5SDimitry Andric #include "llvm/MC/MCParser/MCTargetAsmParser.h" 200b57cec5SDimitry Andric #include "llvm/MC/MCTargetOptions.h" 210b57cec5SDimitry Andric #include "llvm/Support/Error.h" 220b57cec5SDimitry Andric #include "llvm/Support/SMLoc.h" 230b57cec5SDimitry Andric #include <memory> 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric namespace llvm { 260b57cec5SDimitry Andric namespace mca { 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric // This virtual dtor serves as the anchor for the CodeRegionGenerator class. 290b57cec5SDimitry Andric CodeRegionGenerator::~CodeRegionGenerator() {} 300b57cec5SDimitry Andric 31bdd1243dSDimitry Andric Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions( 32*0fca6ea1SDimitry Andric const std::unique_ptr<MCInstPrinter> &IP, bool SkipFailures) { 33bdd1243dSDimitry Andric MCTargetOptions Opts; 34bdd1243dSDimitry Andric Opts.PreserveAsmComments = false; 35bdd1243dSDimitry Andric CodeRegions &Regions = getRegions(); 3606c3fb27SDimitry Andric MCStreamerWrapper *Str = getMCStreamer(); 37bdd1243dSDimitry Andric 38bdd1243dSDimitry Andric // Need to initialize an MCTargetStreamer otherwise 39bdd1243dSDimitry Andric // certain asm directives will cause a segfault. 40bdd1243dSDimitry Andric // Using nulls() so that anything emitted by the MCTargetStreamer 41bdd1243dSDimitry Andric // doesn't show up in the llvm-mca output. 42bdd1243dSDimitry Andric raw_ostream &OSRef = nulls(); 43bdd1243dSDimitry Andric formatted_raw_ostream FOSRef(OSRef); 44*0fca6ea1SDimitry Andric TheTarget.createAsmTargetStreamer(*Str, FOSRef, IP.get()); 45bdd1243dSDimitry Andric 46bdd1243dSDimitry Andric // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM 47bdd1243dSDimitry Andric // comments. 48bdd1243dSDimitry Andric std::unique_ptr<MCAsmParser> Parser( 4906c3fb27SDimitry Andric createMCAsmParser(Regions.getSourceMgr(), Ctx, *Str, MAI)); 50bdd1243dSDimitry Andric MCAsmLexer &Lexer = Parser->getLexer(); 51bdd1243dSDimitry Andric MCACommentConsumer *CCP = getCommentConsumer(); 52bdd1243dSDimitry Andric Lexer.setCommentConsumer(CCP); 53bdd1243dSDimitry Andric // Enable support for MASM literal numbers (example: 05h, 101b). 54bdd1243dSDimitry Andric Lexer.setLexMasmIntegers(true); 55bdd1243dSDimitry Andric 56bdd1243dSDimitry Andric std::unique_ptr<MCTargetAsmParser> TAP( 57bdd1243dSDimitry Andric TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts)); 58bdd1243dSDimitry Andric if (!TAP) 59bdd1243dSDimitry Andric return make_error<StringError>( 60bdd1243dSDimitry Andric "This target does not support assembly parsing.", 61bdd1243dSDimitry Andric inconvertibleErrorCode()); 62bdd1243dSDimitry Andric Parser->setTargetParser(*TAP); 63*0fca6ea1SDimitry Andric // Parser->Run() confusingly returns true on errors, in which case the errors 64*0fca6ea1SDimitry Andric // were already shown to the user. SkipFailures implies continuing in the 65*0fca6ea1SDimitry Andric // presence of any kind of failure within the parser, in which case failing 66*0fca6ea1SDimitry Andric // input lines are not represented, but the rest of the input remains. 67*0fca6ea1SDimitry Andric if (Parser->Run(false) && !SkipFailures) { 68*0fca6ea1SDimitry Andric const char *Message = "Assembly input parsing had errors, use " 69*0fca6ea1SDimitry Andric "-skip-unsupported-instructions=parse-failure " 70*0fca6ea1SDimitry Andric "to drop failing lines from the input."; 71*0fca6ea1SDimitry Andric return make_error<StringError>(Message, inconvertibleErrorCode()); 72*0fca6ea1SDimitry Andric } 73bdd1243dSDimitry Andric 74bdd1243dSDimitry Andric if (CCP->hadErr()) 75bdd1243dSDimitry Andric return make_error<StringError>("There was an error parsing comments.", 76bdd1243dSDimitry Andric inconvertibleErrorCode()); 77bdd1243dSDimitry Andric 78bdd1243dSDimitry Andric // Set the assembler dialect from the input. llvm-mca will use this as the 79bdd1243dSDimitry Andric // default dialect when printing reports. 80bdd1243dSDimitry Andric AssemblerDialect = Parser->getAssemblerDialect(); 81bdd1243dSDimitry Andric return Regions; 82bdd1243dSDimitry Andric } 83bdd1243dSDimitry Andric 84bdd1243dSDimitry Andric void AnalysisRegionCommentConsumer::HandleComment(SMLoc Loc, 85bdd1243dSDimitry Andric StringRef CommentText) { 860b57cec5SDimitry Andric // Skip empty comments. 870b57cec5SDimitry Andric StringRef Comment(CommentText); 880b57cec5SDimitry Andric if (Comment.empty()) 890b57cec5SDimitry Andric return; 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric // Skip spaces and tabs. 920b57cec5SDimitry Andric unsigned Position = Comment.find_first_not_of(" \t"); 930b57cec5SDimitry Andric if (Position >= Comment.size()) 940b57cec5SDimitry Andric // We reached the end of the comment. Bail out. 950b57cec5SDimitry Andric return; 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric Comment = Comment.drop_front(Position); 980b57cec5SDimitry Andric if (Comment.consume_front("LLVM-MCA-END")) { 990b57cec5SDimitry Andric // Skip spaces and tabs. 1000b57cec5SDimitry Andric Position = Comment.find_first_not_of(" \t"); 1010b57cec5SDimitry Andric if (Position < Comment.size()) 1020b57cec5SDimitry Andric Comment = Comment.drop_front(Position); 1030b57cec5SDimitry Andric Regions.endRegion(Comment, Loc); 1040b57cec5SDimitry Andric return; 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric // Try to parse the LLVM-MCA-BEGIN comment. 1080b57cec5SDimitry Andric if (!Comment.consume_front("LLVM-MCA-BEGIN")) 1090b57cec5SDimitry Andric return; 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric // Skip spaces and tabs. 1120b57cec5SDimitry Andric Position = Comment.find_first_not_of(" \t"); 1130b57cec5SDimitry Andric if (Position < Comment.size()) 1140b57cec5SDimitry Andric Comment = Comment.drop_front(Position); 1150b57cec5SDimitry Andric // Use the rest of the string as a descriptor for this code snippet. 1160b57cec5SDimitry Andric Regions.beginRegion(Comment, Loc); 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric 119bdd1243dSDimitry Andric void InstrumentRegionCommentConsumer::HandleComment(SMLoc Loc, 120bdd1243dSDimitry Andric StringRef CommentText) { 121bdd1243dSDimitry Andric // Skip empty comments. 122bdd1243dSDimitry Andric StringRef Comment(CommentText); 123bdd1243dSDimitry Andric if (Comment.empty()) 124bdd1243dSDimitry Andric return; 1250b57cec5SDimitry Andric 126bdd1243dSDimitry Andric // Skip spaces and tabs. 127bdd1243dSDimitry Andric unsigned Position = Comment.find_first_not_of(" \t"); 128bdd1243dSDimitry Andric if (Position >= Comment.size()) 129bdd1243dSDimitry Andric // We reached the end of the comment. Bail out. 130bdd1243dSDimitry Andric return; 131bdd1243dSDimitry Andric Comment = Comment.drop_front(Position); 132fe6060f1SDimitry Andric 133bdd1243dSDimitry Andric // Bail out if not an MCA style comment 134bdd1243dSDimitry Andric if (!Comment.consume_front("LLVM-MCA-")) 135bdd1243dSDimitry Andric return; 1360b57cec5SDimitry Andric 137bdd1243dSDimitry Andric // Skip AnalysisRegion comments 138bdd1243dSDimitry Andric if (Comment.consume_front("BEGIN") || Comment.consume_front("END")) 139bdd1243dSDimitry Andric return; 1400b57cec5SDimitry Andric 141bdd1243dSDimitry Andric if (IM.shouldIgnoreInstruments()) 142bdd1243dSDimitry Andric return; 143bdd1243dSDimitry Andric 144bdd1243dSDimitry Andric auto [InstrumentKind, Data] = Comment.split(" "); 145bdd1243dSDimitry Andric 146bdd1243dSDimitry Andric // An error if not of the form LLVM-MCA-TARGET-KIND 147bdd1243dSDimitry Andric if (!IM.supportsInstrumentType(InstrumentKind)) { 148bdd1243dSDimitry Andric if (InstrumentKind.empty()) 149bdd1243dSDimitry Andric SM.PrintMessage( 150bdd1243dSDimitry Andric Loc, llvm::SourceMgr::DK_Error, 151bdd1243dSDimitry Andric "No instrumentation kind was provided in LLVM-MCA comment"); 152bdd1243dSDimitry Andric else 153bdd1243dSDimitry Andric SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error, 154bdd1243dSDimitry Andric "Unknown instrumentation type in LLVM-MCA comment: " + 155bdd1243dSDimitry Andric InstrumentKind); 156bdd1243dSDimitry Andric FoundError = true; 157bdd1243dSDimitry Andric return; 158bdd1243dSDimitry Andric } 159bdd1243dSDimitry Andric 16006c3fb27SDimitry Andric UniqueInstrument I = IM.createInstrument(InstrumentKind, Data); 161bdd1243dSDimitry Andric if (!I) { 162bdd1243dSDimitry Andric if (Data.empty()) 163bdd1243dSDimitry Andric SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error, 164bdd1243dSDimitry Andric "Failed to create " + InstrumentKind + 165bdd1243dSDimitry Andric " instrument with no data"); 166bdd1243dSDimitry Andric else 167bdd1243dSDimitry Andric SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error, 168bdd1243dSDimitry Andric "Failed to create " + InstrumentKind + 169bdd1243dSDimitry Andric " instrument with data: " + Data); 170bdd1243dSDimitry Andric FoundError = true; 171bdd1243dSDimitry Andric return; 172bdd1243dSDimitry Andric } 173bdd1243dSDimitry Andric 174bdd1243dSDimitry Andric // End InstrumentType region if one is open 175bdd1243dSDimitry Andric if (Regions.isRegionActive(InstrumentKind)) 176bdd1243dSDimitry Andric Regions.endRegion(InstrumentKind, Loc); 177bdd1243dSDimitry Andric // Start new instrumentation region 17806c3fb27SDimitry Andric Regions.beginRegion(InstrumentKind, Loc, std::move(I)); 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric } // namespace mca 1820b57cec5SDimitry Andric } // namespace llvm 183