183 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8/// \file9///10/// This file defines classes responsible for generating llvm-mca11/// 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/MCTargetOptions.h"21#include "llvm/Support/Error.h"22#include "llvm/Support/SMLoc.h"23#include <memory>24 25namespace llvm {26namespace mca {27 28// This virtual dtor serves as the anchor for the CodeRegionGenerator class.29CodeRegionGenerator::~CodeRegionGenerator() = default;30 31Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions(32 const std::unique_ptr<MCInstPrinter> &IP, bool SkipFailures) {33 MCTargetOptions Opts;34 Opts.PreserveAsmComments = false;35 CodeRegions &Regions = getRegions();36 MCStreamerWrapper *Str = getMCStreamer();37 38 // Need to initialize an MCTargetStreamer otherwise39 // certain asm directives will cause a segfault.40 // Using nulls() so that anything emitted by the MCTargetStreamer41 // doesn't show up in the llvm-mca output.42 raw_ostream &OSRef = nulls();43 formatted_raw_ostream FOSRef(OSRef);44 TheTarget.createAsmTargetStreamer(*Str, FOSRef, IP.get());45 46 // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM47 // comments.48 std::unique_ptr<MCAsmParser> Parser(49 createMCAsmParser(Regions.getSourceMgr(), Ctx, *Str, MAI));50 AsmLexer &Lexer = Parser->getLexer();51 MCACommentConsumer *CCP = getCommentConsumer();52 Lexer.setCommentConsumer(CCP);53 // Enable support for MASM literal numbers (example: 05h, 101b).54 Lexer.setLexMasmIntegers(true);55 56 std::unique_ptr<MCTargetAsmParser> TAP(57 TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts));58 if (!TAP)59 return make_error<StringError>(60 "This target does not support assembly parsing.",61 inconvertibleErrorCode());62 Parser->setTargetParser(*TAP);63 // Parser->Run() confusingly returns true on errors, in which case the errors64 // were already shown to the user. SkipFailures implies continuing in the65 // presence of any kind of failure within the parser, in which case failing66 // input lines are not represented, but the rest of the input remains.67 if (Parser->Run(false) && !SkipFailures) {68 const char *Message = "Assembly input parsing had errors, use "69 "-skip-unsupported-instructions=parse-failure "70 "to drop failing lines from the input.";71 return make_error<StringError>(Message, inconvertibleErrorCode());72 }73 74 if (CCP->hadErr())75 return make_error<StringError>("There was an error parsing comments.",76 inconvertibleErrorCode());77 78 // Set the assembler dialect from the input. llvm-mca will use this as the79 // default dialect when printing reports.80 AssemblerDialect = Parser->getAssemblerDialect();81 return Regions;82}83 84void AnalysisRegionCommentConsumer::HandleComment(SMLoc Loc,85 StringRef CommentText) {86 // Skip empty comments.87 StringRef Comment(CommentText);88 if (Comment.empty())89 return;90 91 // Skip spaces and tabs.92 unsigned Position = Comment.find_first_not_of(" \t");93 if (Position >= Comment.size())94 // We reached the end of the comment. Bail out.95 return;96 97 Comment = Comment.drop_front(Position);98 if (Comment.consume_front("LLVM-MCA-END")) {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 Regions.endRegion(Comment, Loc);104 return;105 }106 107 // Try to parse the LLVM-MCA-BEGIN comment.108 if (!Comment.consume_front("LLVM-MCA-BEGIN"))109 return;110 111 // Skip spaces and tabs.112 Position = Comment.find_first_not_of(" \t");113 if (Position < Comment.size())114 Comment = Comment.drop_front(Position);115 // Use the rest of the string as a descriptor for this code snippet.116 Regions.beginRegion(Comment, Loc);117}118 119void InstrumentRegionCommentConsumer::HandleComment(SMLoc Loc,120 StringRef CommentText) {121 // Skip empty comments.122 StringRef Comment(CommentText);123 if (Comment.empty())124 return;125 126 // Skip spaces and tabs.127 unsigned Position = Comment.find_first_not_of(" \t");128 if (Position >= Comment.size())129 // We reached the end of the comment. Bail out.130 return;131 Comment = Comment.drop_front(Position);132 133 // Bail out if not an MCA style comment134 if (!Comment.consume_front("LLVM-MCA-"))135 return;136 137 // Skip AnalysisRegion comments138 if (Comment.consume_front("BEGIN") || Comment.consume_front("END"))139 return;140 141 if (IM.shouldIgnoreInstruments())142 return;143 144 auto [InstrumentKind, Data] = Comment.split(" ");145 146 // An error if not of the form LLVM-MCA-TARGET-KIND147 if (!IM.supportsInstrumentType(InstrumentKind)) {148 if (InstrumentKind.empty())149 SM.PrintMessage(150 Loc, llvm::SourceMgr::DK_Error,151 "No instrumentation kind was provided in LLVM-MCA comment");152 else153 SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,154 "Unknown instrumentation type in LLVM-MCA comment: " +155 InstrumentKind);156 FoundError = true;157 return;158 }159 160 UniqueInstrument I = IM.createInstrument(InstrumentKind, Data);161 if (!I) {162 if (Data.empty())163 SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,164 "Failed to create " + InstrumentKind +165 " instrument with no data");166 else167 SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,168 "Failed to create " + InstrumentKind +169 " instrument with data: " + Data);170 FoundError = true;171 return;172 }173 174 // End InstrumentType region if one is open175 if (Regions.isRegionActive(InstrumentKind))176 Regions.endRegion(InstrumentKind, Loc);177 // Start new instrumentation region178 Regions.beginRegion(InstrumentKind, Loc, std::move(I));179}180 181} // namespace mca182} // namespace llvm183