blob: 4660af2c40aca37fca05172259029d6171867d05 [file] [log] [blame]
//===----------------------- CodeRegionGenerator.cpp ------------*- C++ -*-===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See 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/MCStreamer.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() {}
// A comment consumer that parses strings. The only valid tokens are strings.
class MCACommentConsumer : public AsmCommentConsumer {
CodeRegions &Regions;
MCACommentConsumer(CodeRegions &R) : Regions(R) {}
void HandleComment(SMLoc Loc, StringRef CommentText) override;
// This class provides the callbacks that occur when parsing input assembly.
class MCStreamerWrapper final : public MCStreamer {
CodeRegions &Regions;
MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R)
: MCStreamer(Context), Regions(R) {}
// We only want to intercept the emission of new instructions.
virtual void EmitInstruction(const MCInst &Inst,
const MCSubtargetInfo &/* unused */) override {
bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
return true;
void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
unsigned ByteAlignment) override {}
void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
uint64_t Size = 0, unsigned ByteAlignment = 0,
SMLoc Loc = SMLoc()) override {}
void EmitGPRel32Value(const MCExpr *Value) override {}
void BeginCOFFSymbolDef(const MCSymbol *Symbol) override {}
void EmitCOFFSymbolStorageClass(int StorageClass) override {}
void EmitCOFFSymbolType(int Type) override {}
void EndCOFFSymbolDef() override {}
ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const {
return Regions.getInstructionSequence(Index);
void MCACommentConsumer::HandleComment(SMLoc Loc, StringRef CommentText) {
// Skip empty comments.
StringRef Comment(CommentText);
if (Comment.empty())
// 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.
Comment = Comment.drop_front(Position);
if (Comment.consume_front("LLVM-MCA-END")) {
// Try to parse the LLVM-MCA-BEGIN comment.
if (!Comment.consume_front("LLVM-MCA-BEGIN"))
// 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);
Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions() {
MCTargetOptions Opts;
Opts.PreserveAsmComments = false;
MCStreamerWrapper Str(Ctx, Regions);
// 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 CC(Regions);
// Create a target-specific parser and perform the parse.
std::unique_ptr<MCTargetAsmParser> TAP(
TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts));
if (!TAP)
return make_error<StringError>(
"This target does not support assembly parsing.",
// Get the assembler dialect from the input. llvm-mca will use this as the
// default dialect when printing reports.
AssemblerDialect = Parser->getAssemblerDialect();
return Regions;
} // namespace mca
} // namespace llvm