mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 05:06:06 +00:00
183 lines
6.4 KiB
C++
183 lines
6.4 KiB
C++
//===----------------------- CodeRegionGenerator.cpp ------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
/// \file
|
|
///
|
|
/// This file defines classes responsible for generating llvm-mca
|
|
/// CodeRegions from various types of input. llvm-mca only analyzes CodeRegions,
|
|
/// so the classes here provide the input-to-CodeRegions translation.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "CodeRegionGenerator.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
|
|
#include "llvm/MC/MCTargetOptions.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/SMLoc.h"
|
|
#include <memory>
|
|
|
|
namespace llvm {
|
|
namespace mca {
|
|
|
|
// This virtual dtor serves as the anchor for the CodeRegionGenerator class.
|
|
CodeRegionGenerator::~CodeRegionGenerator() {}
|
|
|
|
Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions(
|
|
const std::unique_ptr<MCInstPrinter> &IP, bool SkipFailures) {
|
|
MCTargetOptions Opts;
|
|
Opts.PreserveAsmComments = false;
|
|
CodeRegions &Regions = getRegions();
|
|
MCStreamerWrapper *Str = getMCStreamer();
|
|
|
|
// Need to initialize an MCTargetStreamer otherwise
|
|
// certain asm directives will cause a segfault.
|
|
// Using nulls() so that anything emitted by the MCTargetStreamer
|
|
// doesn't show up in the llvm-mca output.
|
|
raw_ostream &OSRef = nulls();
|
|
formatted_raw_ostream FOSRef(OSRef);
|
|
TheTarget.createAsmTargetStreamer(*Str, FOSRef, IP.get());
|
|
|
|
// Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM
|
|
// comments.
|
|
std::unique_ptr<MCAsmParser> Parser(
|
|
createMCAsmParser(Regions.getSourceMgr(), Ctx, *Str, MAI));
|
|
MCAsmLexer &Lexer = Parser->getLexer();
|
|
MCACommentConsumer *CCP = getCommentConsumer();
|
|
Lexer.setCommentConsumer(CCP);
|
|
// Enable support for MASM literal numbers (example: 05h, 101b).
|
|
Lexer.setLexMasmIntegers(true);
|
|
|
|
std::unique_ptr<MCTargetAsmParser> TAP(
|
|
TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts));
|
|
if (!TAP)
|
|
return make_error<StringError>(
|
|
"This target does not support assembly parsing.",
|
|
inconvertibleErrorCode());
|
|
Parser->setTargetParser(*TAP);
|
|
// Parser->Run() confusingly returns true on errors, in which case the errors
|
|
// were already shown to the user. SkipFailures implies continuing in the
|
|
// presence of any kind of failure within the parser, in which case failing
|
|
// input lines are not represented, but the rest of the input remains.
|
|
if (Parser->Run(false) && !SkipFailures) {
|
|
const char *Message = "Assembly input parsing had errors, use "
|
|
"-skip-unsupported-instructions=parse-failure "
|
|
"to drop failing lines from the input.";
|
|
return make_error<StringError>(Message, inconvertibleErrorCode());
|
|
}
|
|
|
|
if (CCP->hadErr())
|
|
return make_error<StringError>("There was an error parsing comments.",
|
|
inconvertibleErrorCode());
|
|
|
|
// Set the assembler dialect from the input. llvm-mca will use this as the
|
|
// default dialect when printing reports.
|
|
AssemblerDialect = Parser->getAssemblerDialect();
|
|
return Regions;
|
|
}
|
|
|
|
void AnalysisRegionCommentConsumer::HandleComment(SMLoc Loc,
|
|
StringRef CommentText) {
|
|
// Skip empty comments.
|
|
StringRef Comment(CommentText);
|
|
if (Comment.empty())
|
|
return;
|
|
|
|
// Skip spaces and tabs.
|
|
unsigned Position = Comment.find_first_not_of(" \t");
|
|
if (Position >= Comment.size())
|
|
// We reached the end of the comment. Bail out.
|
|
return;
|
|
|
|
Comment = Comment.drop_front(Position);
|
|
if (Comment.consume_front("LLVM-MCA-END")) {
|
|
// Skip spaces and tabs.
|
|
Position = Comment.find_first_not_of(" \t");
|
|
if (Position < Comment.size())
|
|
Comment = Comment.drop_front(Position);
|
|
Regions.endRegion(Comment, Loc);
|
|
return;
|
|
}
|
|
|
|
// Try to parse the LLVM-MCA-BEGIN comment.
|
|
if (!Comment.consume_front("LLVM-MCA-BEGIN"))
|
|
return;
|
|
|
|
// Skip spaces and tabs.
|
|
Position = Comment.find_first_not_of(" \t");
|
|
if (Position < Comment.size())
|
|
Comment = Comment.drop_front(Position);
|
|
// Use the rest of the string as a descriptor for this code snippet.
|
|
Regions.beginRegion(Comment, Loc);
|
|
}
|
|
|
|
void InstrumentRegionCommentConsumer::HandleComment(SMLoc Loc,
|
|
StringRef CommentText) {
|
|
// Skip empty comments.
|
|
StringRef Comment(CommentText);
|
|
if (Comment.empty())
|
|
return;
|
|
|
|
// Skip spaces and tabs.
|
|
unsigned Position = Comment.find_first_not_of(" \t");
|
|
if (Position >= Comment.size())
|
|
// We reached the end of the comment. Bail out.
|
|
return;
|
|
Comment = Comment.drop_front(Position);
|
|
|
|
// Bail out if not an MCA style comment
|
|
if (!Comment.consume_front("LLVM-MCA-"))
|
|
return;
|
|
|
|
// Skip AnalysisRegion comments
|
|
if (Comment.consume_front("BEGIN") || Comment.consume_front("END"))
|
|
return;
|
|
|
|
if (IM.shouldIgnoreInstruments())
|
|
return;
|
|
|
|
auto [InstrumentKind, Data] = Comment.split(" ");
|
|
|
|
// An error if not of the form LLVM-MCA-TARGET-KIND
|
|
if (!IM.supportsInstrumentType(InstrumentKind)) {
|
|
if (InstrumentKind.empty())
|
|
SM.PrintMessage(
|
|
Loc, llvm::SourceMgr::DK_Error,
|
|
"No instrumentation kind was provided in LLVM-MCA comment");
|
|
else
|
|
SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
|
|
"Unknown instrumentation type in LLVM-MCA comment: " +
|
|
InstrumentKind);
|
|
FoundError = true;
|
|
return;
|
|
}
|
|
|
|
UniqueInstrument I = IM.createInstrument(InstrumentKind, Data);
|
|
if (!I) {
|
|
if (Data.empty())
|
|
SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
|
|
"Failed to create " + InstrumentKind +
|
|
" instrument with no data");
|
|
else
|
|
SM.PrintMessage(Loc, llvm::SourceMgr::DK_Error,
|
|
"Failed to create " + InstrumentKind +
|
|
" instrument with data: " + Data);
|
|
FoundError = true;
|
|
return;
|
|
}
|
|
|
|
// End InstrumentType region if one is open
|
|
if (Regions.isRegionActive(InstrumentKind))
|
|
Regions.endRegion(InstrumentKind, Loc);
|
|
// Start new instrumentation region
|
|
Regions.beginRegion(InstrumentKind, Loc, std::move(I));
|
|
}
|
|
|
|
} // namespace mca
|
|
} // namespace llvm
|