2018-11-08 03:20:04 +08:00
|
|
|
//===----------------------- CodeRegionGenerator.cpp ------------*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2018-11-08 03:20:04 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// \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 {
|
|
|
|
public:
|
|
|
|
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;
|
|
|
|
|
|
|
|
public:
|
|
|
|
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,
|
2019-02-04 20:51:26 +08:00
|
|
|
const MCSubtargetInfo &/* unused */) override {
|
2018-11-08 03:20:04 +08:00
|
|
|
Regions.addInstruction(Inst);
|
|
|
|
}
|
|
|
|
|
|
|
|
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())
|
|
|
|
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")) {
|
2019-05-09 23:18:09 +08:00
|
|
|
// Skip spaces and tabs.
|
|
|
|
Position = Comment.find_first_not_of(" \t");
|
|
|
|
if (Position < Comment.size())
|
|
|
|
Comment = Comment.drop_front(Position);
|
|
|
|
Regions.endRegion(Comment, Loc);
|
2018-11-08 03:20:04 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
Lexer.setCommentConsumer(&CC);
|
2019-08-02 18:38:25 +08:00
|
|
|
// Enable support for MASM literal numbers (example: 05h, 101b).
|
|
|
|
Lexer.setLexMasmIntegers(true);
|
2018-11-08 03:20:04 +08:00
|
|
|
|
|
|
|
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(false);
|
|
|
|
|
2019-05-08 19:00:43 +08:00
|
|
|
// Set the assembler dialect from the input. llvm-mca will use this as the
|
2018-11-08 03:20:04 +08:00
|
|
|
// default dialect when printing reports.
|
|
|
|
AssemblerDialect = Parser->getAssemblerDialect();
|
|
|
|
return Regions;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace mca
|
|
|
|
} // namespace llvm
|