2018-03-08 21:05:02 +08:00
|
|
|
//===-- llvm-mca.cpp - Machine Code Analyzer -------------------*- C++ -* -===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This utility is a simple driver that allows static performance analysis on
|
|
|
|
// machine code similarly to how IACA (Intel Architecture Code Analyzer) works.
|
|
|
|
//
|
|
|
|
// llvm-mca [options] <file-name>
|
|
|
|
// -march <type>
|
|
|
|
// -mcpu <cpu>
|
|
|
|
// -o <file>
|
|
|
|
//
|
|
|
|
// The target defaults to the host target.
|
2018-04-25 18:18:25 +08:00
|
|
|
// The cpu defaults to the 'native' host cpu.
|
2018-03-08 21:05:02 +08:00
|
|
|
// The output defaults to standard output.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-03-09 20:50:42 +08:00
|
|
|
#include "BackendPrinter.h"
|
2018-04-10 00:39:52 +08:00
|
|
|
#include "CodeRegion.h"
|
2018-04-10 22:55:14 +08:00
|
|
|
#include "DispatchStatistics.h"
|
[llvm-mca] Introduce a pipeline Stage class and FetchStage.
Summary:
This is just an idea, really two ideas. I expect some push-back,
but I realize that posting a diff is the most comprehensive way to express
these concepts.
This patch introduces a Stage class which represents the
various stages of an instruction pipeline. As a start, I have created a simple
FetchStage that is based on existing logic for how MCA produces
instructions, but now encapsulated in a Stage. The idea should become more concrete
once we introduce additional stages. The idea being, that when a stage completes,
the next stage in the pipeline will be executed. Stages are chained together
as a singly linked list to closely model a real pipeline. For now there is only one stage,
so the stage-to-stage flow of instructions isn't immediately obvious.
Eventually, Stage will also handle event notifications, but that functionality
is not complete, and not destined for this patch. Ideally, an interested party
can register for notifications from a particular stage. Callbacks will be issued to
these listeners at various points in the execution of the stage.
For now, eventing functionality remains similar to what it has been in mca::Backend.
We will be building-up the Stage class as we move on, such as adding debug output.
This patch also removes the unique_ptr<Instruction> return value from
InstrBuilder::createInstruction. An Instruction pointer is still produced,
but now it's up to the caller to decide how that item should be managed post-allocation
(e.g., smart pointer). This allows the Fetch stage to create instructions and
manage the lifetime of those instructions as it wishes, and not have to be bound to any
specific managed pointer type. Other callers of createInstruction might have different
requirements, and thus can manage the pointer to fit their needs. Another idea would be to push the
ownership to the RCU.
Currently, the FetchStage will wrap the Instruction
pointer in a shared_ptr. This allows us to remove the Instruction container in
Backend, which was probably going to disappear, or move, at some point anyways.
Note that I did run these changes through valgrind, to make sure we are not leaking
memory. While the shared_ptr comes with some additional overhead it relieves us
from having to manage a list of generated instructions, and/or make lookup calls
to remove the instructions.
I realize that both the Stage class and the Instruction pointer management
(mentioned directly above) are separate but related ideas, and probably should
land as separate patches; I am happy to do that if either idea is decent.
The main reason these two ideas are together is that
Stage::execute() can mutate an InstRef. For the fetch stage, the InstRef is populated
as the primary action of that stage (execute()). I didn't want to change the Stage interface
to support the idea of generating an instruction. Ideally, instructions are to
be pushed through the pipeline. I didn't want to draw too much of a
specialization just for the fetch stage. Excuse the word-salad.
Reviewers: andreadb, courbet, RKSimon
Reviewed By: andreadb
Subscribers: llvm-commits, mgorny, javed.absar, tschuett, gbedwell
Differential Revision: https://reviews.llvm.org/D46741
llvm-svn: 332390
2018-05-16 04:21:04 +08:00
|
|
|
#include "FetchStage.h"
|
2018-03-24 03:40:04 +08:00
|
|
|
#include "InstructionInfoView.h"
|
2018-03-26 20:04:53 +08:00
|
|
|
#include "InstructionTables.h"
|
2018-04-04 00:46:23 +08:00
|
|
|
#include "RegisterFileStatistics.h"
|
2018-03-09 20:50:42 +08:00
|
|
|
#include "ResourcePressureView.h"
|
2018-04-11 20:12:53 +08:00
|
|
|
#include "RetireControlUnitStatistics.h"
|
2018-04-11 19:37:46 +08:00
|
|
|
#include "SchedulerStatistics.h"
|
2018-03-09 21:52:03 +08:00
|
|
|
#include "SummaryView.h"
|
2018-03-09 20:50:42 +08:00
|
|
|
#include "TimelineView.h"
|
2018-03-08 21:05:02 +08:00
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
|
|
|
#include "llvm/MC/MCContext.h"
|
|
|
|
#include "llvm/MC/MCObjectFileInfo.h"
|
|
|
|
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
|
|
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
|
|
|
#include "llvm/MC/MCStreamer.h"
|
|
|
|
#include "llvm/Support/CommandLine.h"
|
2018-03-09 00:08:43 +08:00
|
|
|
#include "llvm/Support/ErrorOr.h"
|
|
|
|
#include "llvm/Support/FileSystem.h"
|
2018-04-25 18:27:30 +08:00
|
|
|
#include "llvm/Support/Host.h"
|
2018-04-14 02:26:06 +08:00
|
|
|
#include "llvm/Support/InitLLVM.h"
|
2018-03-08 21:05:02 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include "llvm/Support/SourceMgr.h"
|
|
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
|
|
#include "llvm/Support/TargetSelect.h"
|
2018-03-09 00:08:43 +08:00
|
|
|
#include "llvm/Support/ToolOutputFile.h"
|
2018-04-18 23:26:51 +08:00
|
|
|
#include "llvm/Support/WithColor.h"
|
2018-03-08 21:05:02 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
2018-05-17 23:35:14 +08:00
|
|
|
static cl::OptionCategory ToolOptions("Tool Options");
|
|
|
|
static cl::OptionCategory ViewOptions("View Options");
|
2018-04-25 19:33:14 +08:00
|
|
|
|
2018-05-17 23:35:14 +08:00
|
|
|
static cl::opt<std::string> InputFilename(cl::Positional,
|
|
|
|
cl::desc("<input file>"),
|
|
|
|
cl::cat(ToolOptions), cl::init("-"));
|
2018-03-08 21:05:02 +08:00
|
|
|
|
|
|
|
static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
|
2018-05-17 23:35:14 +08:00
|
|
|
cl::init("-"), cl::cat(ToolOptions),
|
2018-03-08 21:05:02 +08:00
|
|
|
cl::value_desc("filename"));
|
|
|
|
|
|
|
|
static cl::opt<std::string>
|
2018-05-17 23:35:14 +08:00
|
|
|
ArchName("march",
|
|
|
|
cl::desc("Target arch to assemble for, "
|
|
|
|
"see -version for available targets"),
|
|
|
|
cl::cat(ToolOptions));
|
2018-03-08 21:05:02 +08:00
|
|
|
|
|
|
|
static cl::opt<std::string>
|
2018-05-17 23:35:14 +08:00
|
|
|
TripleName("mtriple",
|
|
|
|
cl::desc("Target triple to assemble for, "
|
|
|
|
"see -version for available targets"),
|
|
|
|
cl::cat(ToolOptions));
|
2018-03-08 21:05:02 +08:00
|
|
|
|
|
|
|
static cl::opt<std::string>
|
|
|
|
MCPU("mcpu",
|
|
|
|
cl::desc("Target a specific cpu type (-mcpu=help for details)"),
|
2018-05-17 23:35:14 +08:00
|
|
|
cl::value_desc("cpu-name"), cl::cat(ToolOptions), cl::init("native"));
|
2018-03-08 21:05:02 +08:00
|
|
|
|
2018-04-25 00:19:08 +08:00
|
|
|
static cl::opt<int>
|
2018-03-08 21:05:02 +08:00
|
|
|
OutputAsmVariant("output-asm-variant",
|
2018-04-25 00:19:08 +08:00
|
|
|
cl::desc("Syntax variant to use for output printing"),
|
2018-05-17 23:35:14 +08:00
|
|
|
cl::cat(ToolOptions), cl::init(-1));
|
2018-03-08 21:05:02 +08:00
|
|
|
|
|
|
|
static cl::opt<unsigned> Iterations("iterations",
|
|
|
|
cl::desc("Number of iterations to run"),
|
2018-05-17 23:35:14 +08:00
|
|
|
cl::cat(ToolOptions), cl::init(0));
|
2018-03-08 21:05:02 +08:00
|
|
|
|
2018-05-17 23:35:14 +08:00
|
|
|
static cl::opt<unsigned>
|
|
|
|
DispatchWidth("dispatch", cl::desc("Override the processor dispatch width"),
|
|
|
|
cl::cat(ToolOptions), cl::init(0));
|
2018-03-08 21:05:02 +08:00
|
|
|
|
|
|
|
static cl::opt<unsigned>
|
|
|
|
RegisterFileSize("register-file-size",
|
|
|
|
cl::desc("Maximum number of temporary registers which can "
|
|
|
|
"be used for register mappings"),
|
2018-05-17 23:35:14 +08:00
|
|
|
cl::cat(ToolOptions), cl::init(0));
|
2018-03-08 21:05:02 +08:00
|
|
|
|
2018-04-04 00:46:23 +08:00
|
|
|
static cl::opt<bool>
|
|
|
|
PrintRegisterFileStats("register-file-stats",
|
|
|
|
cl::desc("Print register file statistics"),
|
2018-05-05 23:36:47 +08:00
|
|
|
cl::cat(ViewOptions), cl::init(false));
|
2018-04-04 00:46:23 +08:00
|
|
|
|
2018-04-25 18:27:30 +08:00
|
|
|
static cl::opt<bool> PrintDispatchStats("dispatch-stats",
|
|
|
|
cl::desc("Print dispatch statistics"),
|
2018-05-05 23:36:47 +08:00
|
|
|
cl::cat(ViewOptions), cl::init(false));
|
2018-04-10 22:55:14 +08:00
|
|
|
|
2018-04-25 18:27:30 +08:00
|
|
|
static cl::opt<bool> PrintSchedulerStats("scheduler-stats",
|
|
|
|
cl::desc("Print scheduler statistics"),
|
2018-05-05 23:36:47 +08:00
|
|
|
cl::cat(ViewOptions), cl::init(false));
|
2018-04-11 19:37:46 +08:00
|
|
|
|
2018-04-11 20:12:53 +08:00
|
|
|
static cl::opt<bool>
|
|
|
|
PrintRetireStats("retire-stats",
|
2018-04-25 18:27:30 +08:00
|
|
|
cl::desc("Print retire control unit statistics"),
|
2018-05-05 23:36:47 +08:00
|
|
|
cl::cat(ViewOptions), cl::init(false));
|
2018-04-11 20:12:53 +08:00
|
|
|
|
2018-05-05 23:36:47 +08:00
|
|
|
static cl::opt<bool> PrintResourcePressureView(
|
|
|
|
"resource-pressure",
|
|
|
|
cl::desc("Print the resource pressure view (enabled by default)"),
|
|
|
|
cl::cat(ViewOptions), cl::init(true));
|
2018-03-23 19:33:09 +08:00
|
|
|
|
2018-03-08 21:05:02 +08:00
|
|
|
static cl::opt<bool> PrintTimelineView("timeline",
|
|
|
|
cl::desc("Print the timeline view"),
|
2018-05-05 23:36:47 +08:00
|
|
|
cl::cat(ViewOptions), cl::init(false));
|
2018-03-08 21:05:02 +08:00
|
|
|
|
|
|
|
static cl::opt<unsigned> TimelineMaxIterations(
|
|
|
|
"timeline-max-iterations",
|
|
|
|
cl::desc("Maximum number of iterations to print in timeline view"),
|
2018-05-05 23:36:47 +08:00
|
|
|
cl::cat(ViewOptions), cl::init(0));
|
2018-03-08 21:05:02 +08:00
|
|
|
|
|
|
|
static cl::opt<unsigned> TimelineMaxCycles(
|
|
|
|
"timeline-max-cycles",
|
|
|
|
cl::desc(
|
|
|
|
"Maximum number of cycles in the timeline view. Defaults to 80 cycles"),
|
2018-05-05 23:36:47 +08:00
|
|
|
cl::cat(ViewOptions), cl::init(80));
|
2018-03-08 21:05:02 +08:00
|
|
|
|
2018-05-17 23:35:14 +08:00
|
|
|
static cl::opt<bool>
|
|
|
|
AssumeNoAlias("noalias",
|
|
|
|
cl::desc("If set, assume that loads and stores do not alias"),
|
|
|
|
cl::cat(ToolOptions), cl::init(true));
|
2018-03-08 21:05:02 +08:00
|
|
|
|
|
|
|
static cl::opt<unsigned>
|
2018-05-17 23:35:14 +08:00
|
|
|
LoadQueueSize("lqueue",
|
|
|
|
cl::desc("Size of the load queue (unbound by default)"),
|
|
|
|
cl::cat(ToolOptions), cl::init(0));
|
2018-03-26 20:04:53 +08:00
|
|
|
|
2018-03-08 21:05:02 +08:00
|
|
|
static cl::opt<unsigned>
|
2018-05-17 23:35:14 +08:00
|
|
|
StoreQueueSize("squeue",
|
|
|
|
cl::desc("Size of the store queue (unbound by default)"),
|
|
|
|
cl::cat(ToolOptions), cl::init(0));
|
2018-03-08 21:05:02 +08:00
|
|
|
|
2018-03-26 20:04:53 +08:00
|
|
|
static cl::opt<bool>
|
|
|
|
PrintInstructionTables("instruction-tables",
|
|
|
|
cl::desc("Print instruction tables"),
|
2018-05-17 23:35:14 +08:00
|
|
|
cl::cat(ToolOptions), cl::init(false));
|
2018-03-26 20:04:53 +08:00
|
|
|
|
2018-05-05 23:36:47 +08:00
|
|
|
static cl::opt<bool> PrintInstructionInfoView(
|
|
|
|
"instruction-info",
|
|
|
|
cl::desc("Print the instruction info view (enabled by default)"),
|
|
|
|
cl::cat(ViewOptions), cl::init(true));
|
2018-03-26 21:44:54 +08:00
|
|
|
|
2018-05-17 20:27:03 +08:00
|
|
|
static cl::opt<bool> EnableAllStats("all-stats",
|
|
|
|
cl::desc("Print all hardware statistics"),
|
|
|
|
cl::cat(ViewOptions), cl::init(false));
|
|
|
|
|
|
|
|
static cl::opt<bool>
|
|
|
|
EnableAllViews("all-views",
|
|
|
|
cl::desc("Print all views including hardware statistics"),
|
|
|
|
cl::cat(ViewOptions), cl::init(false));
|
|
|
|
|
2018-04-08 23:10:19 +08:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
const Target *getTarget(const char *ProgName) {
|
2018-03-08 21:05:02 +08:00
|
|
|
TripleName = Triple::normalize(TripleName);
|
|
|
|
if (TripleName.empty())
|
|
|
|
TripleName = Triple::normalize(sys::getDefaultTargetTriple());
|
|
|
|
Triple TheTriple(TripleName);
|
|
|
|
|
|
|
|
// Get the target specific parser.
|
|
|
|
std::string Error;
|
|
|
|
const Target *TheTarget =
|
|
|
|
TargetRegistry::lookupTarget(ArchName, TheTriple, Error);
|
|
|
|
if (!TheTarget) {
|
|
|
|
errs() << ProgName << ": " << Error;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the found target.
|
|
|
|
return TheTarget;
|
|
|
|
}
|
|
|
|
|
2018-04-10 00:39:52 +08:00
|
|
|
// A comment consumer that parses strings.
|
|
|
|
// The only valid tokens are strings.
|
|
|
|
class MCACommentConsumer : public AsmCommentConsumer {
|
|
|
|
public:
|
|
|
|
mca::CodeRegions &Regions;
|
|
|
|
|
|
|
|
MCACommentConsumer(mca::CodeRegions &R) : Regions(R) {}
|
|
|
|
void HandleComment(SMLoc Loc, StringRef CommentText) override {
|
|
|
|
// 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")) {
|
|
|
|
Regions.endRegion(Loc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now try to parse string LLVM-MCA-BEGIN
|
|
|
|
if (!Comment.consume_front("LLVM-MCA-BEGIN"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Skip spaces and tabs
|
|
|
|
Position = Comment.find_first_not_of(" \t");
|
|
|
|
if (Position < Comment.size())
|
2018-04-10 01:06:57 +08:00
|
|
|
Comment = Comment.drop_front(Position);
|
2018-04-10 00:39:52 +08:00
|
|
|
// Use the rest of the string as a descriptor for this code snippet.
|
|
|
|
Regions.beginRegion(Comment, Loc);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-04-08 23:10:19 +08:00
|
|
|
int AssembleInput(const char *ProgName, MCAsmParser &Parser,
|
|
|
|
const Target *TheTarget, MCSubtargetInfo &STI,
|
|
|
|
MCInstrInfo &MCII, MCTargetOptions &MCOptions) {
|
2018-03-08 21:05:02 +08:00
|
|
|
std::unique_ptr<MCTargetAsmParser> TAP(
|
2018-04-08 23:10:19 +08:00
|
|
|
TheTarget->createMCAsmParser(STI, Parser, MCII, MCOptions));
|
2018-03-08 21:05:02 +08:00
|
|
|
|
|
|
|
if (!TAP) {
|
2018-05-04 21:52:12 +08:00
|
|
|
WithColor::error() << "this target does not support assembly parsing.\n";
|
2018-03-08 21:05:02 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-04-08 23:10:19 +08:00
|
|
|
Parser.setTargetParser(*TAP);
|
|
|
|
return Parser.Run(false);
|
2018-03-08 21:05:02 +08:00
|
|
|
}
|
|
|
|
|
2018-04-08 23:10:19 +08:00
|
|
|
ErrorOr<std::unique_ptr<ToolOutputFile>> getOutputStream() {
|
2018-03-09 00:08:43 +08:00
|
|
|
if (OutputFilename == "")
|
|
|
|
OutputFilename = "-";
|
|
|
|
std::error_code EC;
|
|
|
|
auto Out =
|
|
|
|
llvm::make_unique<ToolOutputFile>(OutputFilename, EC, sys::fs::F_None);
|
|
|
|
if (!EC)
|
|
|
|
return std::move(Out);
|
|
|
|
return EC;
|
|
|
|
}
|
|
|
|
|
2018-03-08 21:05:02 +08:00
|
|
|
class MCStreamerWrapper final : public MCStreamer {
|
2018-04-10 00:39:52 +08:00
|
|
|
mca::CodeRegions &Regions;
|
2018-03-08 21:05:02 +08:00
|
|
|
|
|
|
|
public:
|
2018-04-10 00:39:52 +08:00
|
|
|
MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R)
|
|
|
|
: MCStreamer(Context), Regions(R) {}
|
2018-03-08 21:05:02 +08:00
|
|
|
|
|
|
|
// We only want to intercept the emission of new instructions.
|
|
|
|
virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
|
|
|
|
bool /* unused */) override {
|
2018-04-10 00:39:52 +08:00
|
|
|
Regions.addInstruction(llvm::make_unique<const MCInst>(Inst));
|
2018-03-08 21:05:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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) 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 {}
|
|
|
|
|
2018-04-10 00:39:52 +08:00
|
|
|
const std::vector<std::unique_ptr<const MCInst>> &
|
|
|
|
GetInstructionSequence(unsigned Index) const {
|
|
|
|
return Regions.getInstructionSequence(Index);
|
|
|
|
}
|
2018-03-08 21:05:02 +08:00
|
|
|
};
|
|
|
|
} // end of anonymous namespace
|
|
|
|
|
2018-05-17 20:27:03 +08:00
|
|
|
static void processOptionImpl(cl::opt<bool> &O, const cl::opt<bool> &Default) {
|
|
|
|
if (!O.getNumOccurrences() || O.getPosition() < Default.getPosition())
|
|
|
|
O = Default.getValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void processViewOptions() {
|
|
|
|
if (!EnableAllViews.getNumOccurrences() &&
|
|
|
|
!EnableAllStats.getNumOccurrences())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (EnableAllViews.getNumOccurrences()) {
|
|
|
|
processOptionImpl(PrintResourcePressureView, EnableAllViews);
|
|
|
|
processOptionImpl(PrintTimelineView, EnableAllViews);
|
|
|
|
processOptionImpl(PrintInstructionInfoView, EnableAllViews);
|
|
|
|
}
|
|
|
|
|
|
|
|
const cl::opt<bool> &Default =
|
|
|
|
EnableAllViews.getPosition() < EnableAllStats.getPosition()
|
|
|
|
? EnableAllStats
|
|
|
|
: EnableAllViews;
|
|
|
|
processOptionImpl(PrintRegisterFileStats, Default);
|
|
|
|
processOptionImpl(PrintDispatchStats, Default);
|
|
|
|
processOptionImpl(PrintSchedulerStats, Default);
|
|
|
|
processOptionImpl(PrintRetireStats, Default);
|
|
|
|
}
|
|
|
|
|
2018-03-08 21:05:02 +08:00
|
|
|
int main(int argc, char **argv) {
|
2018-04-14 02:26:06 +08:00
|
|
|
InitLLVM X(argc, argv);
|
2018-03-08 21:05:02 +08:00
|
|
|
|
|
|
|
// Initialize targets and assembly parsers.
|
|
|
|
llvm::InitializeAllTargetInfos();
|
|
|
|
llvm::InitializeAllTargetMCs();
|
|
|
|
llvm::InitializeAllAsmParsers();
|
|
|
|
|
|
|
|
// Enable printing of available targets when flag --version is specified.
|
|
|
|
cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
|
|
|
|
|
2018-05-17 23:35:14 +08:00
|
|
|
cl::HideUnrelatedOptions({&ToolOptions, &ViewOptions});
|
|
|
|
|
2018-03-08 21:05:02 +08:00
|
|
|
// Parse flags and initialize target options.
|
|
|
|
cl::ParseCommandLineOptions(argc, argv,
|
|
|
|
"llvm machine code performance analyzer.\n");
|
2018-05-17 23:35:14 +08:00
|
|
|
|
2018-03-08 21:05:02 +08:00
|
|
|
MCTargetOptions MCOptions;
|
|
|
|
MCOptions.PreserveAsmComments = false;
|
|
|
|
|
|
|
|
// Get the target from the triple. If a triple is not specified, then select
|
|
|
|
// the default triple for the host. If the triple doesn't correspond to any
|
|
|
|
// registered target, then exit with an error message.
|
|
|
|
const char *ProgName = argv[0];
|
|
|
|
const Target *TheTarget = getTarget(ProgName);
|
|
|
|
if (!TheTarget)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
// GetTarget() may replaced TripleName with a default triple.
|
|
|
|
// For safety, reconstruct the Triple object.
|
|
|
|
Triple TheTriple(TripleName);
|
|
|
|
|
|
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr =
|
|
|
|
MemoryBuffer::getFileOrSTDIN(InputFilename);
|
|
|
|
if (std::error_code EC = BufferPtr.getError()) {
|
2018-04-18 23:26:51 +08:00
|
|
|
WithColor::error() << InputFilename << ": " << EC.message() << '\n';
|
2018-03-08 21:05:02 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-05-17 20:27:03 +08:00
|
|
|
// Apply overrides to llvm-mca specific options.
|
|
|
|
processViewOptions();
|
|
|
|
|
2018-03-08 21:05:02 +08:00
|
|
|
SourceMgr SrcMgr;
|
|
|
|
|
|
|
|
// Tell SrcMgr about this buffer, which is what the parser will pick up.
|
|
|
|
SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc());
|
|
|
|
|
|
|
|
std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
|
|
|
|
assert(MRI && "Unable to create target register info!");
|
|
|
|
|
|
|
|
std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName));
|
|
|
|
assert(MAI && "Unable to create target asm info!");
|
|
|
|
|
|
|
|
MCObjectFileInfo MOFI;
|
|
|
|
MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr);
|
|
|
|
MOFI.InitMCObjectFileInfo(TheTriple, /* PIC= */ false, Ctx);
|
|
|
|
|
|
|
|
std::unique_ptr<buffer_ostream> BOS;
|
2018-03-26 20:04:53 +08:00
|
|
|
|
2018-04-10 00:39:52 +08:00
|
|
|
mca::CodeRegions Regions(SrcMgr);
|
|
|
|
MCStreamerWrapper Str(Ctx, Regions);
|
2018-03-08 21:05:02 +08:00
|
|
|
|
|
|
|
std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
|
2018-04-25 18:18:25 +08:00
|
|
|
|
|
|
|
if (!MCPU.compare("native"))
|
|
|
|
MCPU = llvm::sys::getHostCPUName();
|
|
|
|
|
2018-03-08 21:05:02 +08:00
|
|
|
std::unique_ptr<MCSubtargetInfo> STI(
|
|
|
|
TheTarget->createMCSubtargetInfo(TripleName, MCPU, /* FeaturesStr */ ""));
|
|
|
|
if (!STI->isCPUStringValid(MCPU))
|
|
|
|
return 1;
|
|
|
|
|
2018-04-30 20:05:34 +08:00
|
|
|
if (!PrintInstructionTables && !STI->getSchedModel().isOutOfOrder()) {
|
2018-04-18 23:26:51 +08:00
|
|
|
WithColor::error() << "please specify an out-of-order cpu. '" << MCPU
|
|
|
|
<< "' is an in-order cpu.\n";
|
2018-03-08 21:05:02 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!STI->getSchedModel().hasInstrSchedModel()) {
|
2018-04-18 23:26:51 +08:00
|
|
|
WithColor::error()
|
|
|
|
<< "unable to find instruction-level scheduling information for"
|
2018-03-08 21:05:02 +08:00
|
|
|
<< " target triple '" << TheTriple.normalize() << "' and cpu '" << MCPU
|
|
|
|
<< "'.\n";
|
|
|
|
|
|
|
|
if (STI->getSchedModel().InstrItineraries)
|
2018-04-18 23:26:51 +08:00
|
|
|
WithColor::note()
|
|
|
|
<< "cpu '" << MCPU << "' provides itineraries. However, "
|
|
|
|
<< "instruction itineraries are currently unsupported.\n";
|
2018-03-08 21:05:02 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-04-08 23:10:19 +08:00
|
|
|
std::unique_ptr<MCAsmParser> P(createMCAsmParser(SrcMgr, Ctx, Str, *MAI));
|
2018-04-10 00:39:52 +08:00
|
|
|
MCAsmLexer &Lexer = P->getLexer();
|
|
|
|
MCACommentConsumer CC(Regions);
|
|
|
|
Lexer.setCommentConsumer(&CC);
|
|
|
|
|
2018-04-08 23:10:19 +08:00
|
|
|
if (AssembleInput(ProgName, *P, TheTarget, *STI, *MCII, MCOptions))
|
|
|
|
return 1;
|
2018-03-08 21:05:02 +08:00
|
|
|
|
2018-04-10 00:39:52 +08:00
|
|
|
if (Regions.empty()) {
|
2018-04-18 23:26:51 +08:00
|
|
|
WithColor::error() << "no assembly instructions found.\n";
|
2018-03-08 21:05:02 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-03-09 00:08:43 +08:00
|
|
|
// Now initialize the output file.
|
|
|
|
auto OF = getOutputStream();
|
|
|
|
if (std::error_code EC = OF.getError()) {
|
2018-04-18 23:26:51 +08:00
|
|
|
WithColor::error() << EC.message() << '\n';
|
2018-03-09 00:08:43 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-04-25 00:19:08 +08:00
|
|
|
unsigned AssemblerDialect = P->getAssemblerDialect();
|
|
|
|
if (OutputAsmVariant >= 0)
|
|
|
|
AssemblerDialect = static_cast<unsigned>(OutputAsmVariant);
|
|
|
|
std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
|
|
|
|
Triple(TripleName), AssemblerDialect, *MAI, *MCII, *MRI));
|
|
|
|
if (!IP) {
|
|
|
|
WithColor::error()
|
|
|
|
<< "unable to create instruction printer for target triple '"
|
|
|
|
<< TheTriple.normalize() << "' with assembly variant "
|
|
|
|
<< AssemblerDialect << ".\n";
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-03-09 00:08:43 +08:00
|
|
|
std::unique_ptr<llvm::ToolOutputFile> TOF = std::move(*OF);
|
|
|
|
|
2018-03-08 21:05:02 +08:00
|
|
|
const MCSchedModel &SM = STI->getSchedModel();
|
|
|
|
|
|
|
|
unsigned Width = SM.IssueWidth;
|
|
|
|
if (DispatchWidth)
|
|
|
|
Width = DispatchWidth;
|
|
|
|
|
2018-03-23 19:50:43 +08:00
|
|
|
// Create an instruction builder.
|
2018-04-08 23:10:19 +08:00
|
|
|
mca::InstrBuilder IB(*STI, *MCII);
|
2018-03-23 19:50:43 +08:00
|
|
|
|
2018-04-10 00:39:52 +08:00
|
|
|
// Number each region in the sequence.
|
|
|
|
unsigned RegionIdx = 0;
|
|
|
|
for (const std::unique_ptr<mca::CodeRegion> &Region : Regions) {
|
|
|
|
// Skip empty code regions.
|
|
|
|
if (Region->empty())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Don't print the header of this region if it is the default region, and
|
|
|
|
// it doesn't have an end location.
|
|
|
|
if (Region->startLoc().isValid() || Region->endLoc().isValid()) {
|
|
|
|
TOF->os() << "\n[" << RegionIdx++ << "] Code Region";
|
|
|
|
StringRef Desc = Region->getDescription();
|
|
|
|
if (!Desc.empty())
|
|
|
|
TOF->os() << " - " << Desc;
|
|
|
|
TOF->os() << "\n\n";
|
2018-03-26 21:44:54 +08:00
|
|
|
}
|
|
|
|
|
2018-04-10 00:39:52 +08:00
|
|
|
mca::SourceMgr S(Region->getInstructions(),
|
|
|
|
PrintInstructionTables ? 1 : Iterations);
|
|
|
|
|
|
|
|
if (PrintInstructionTables) {
|
|
|
|
mca::InstructionTables IT(STI->getSchedModel(), IB, S);
|
|
|
|
|
|
|
|
if (PrintInstructionInfoView) {
|
|
|
|
IT.addView(
|
|
|
|
llvm::make_unique<mca::InstructionInfoView>(*STI, *MCII, S, *IP));
|
|
|
|
}
|
2018-03-26 20:04:53 +08:00
|
|
|
|
2018-04-10 00:39:52 +08:00
|
|
|
IT.addView(llvm::make_unique<mca::ResourcePressureView>(*STI, *IP, S));
|
|
|
|
IT.run();
|
|
|
|
IT.printReport(TOF->os());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
[llvm-mca] Introduce a pipeline Stage class and FetchStage.
Summary:
This is just an idea, really two ideas. I expect some push-back,
but I realize that posting a diff is the most comprehensive way to express
these concepts.
This patch introduces a Stage class which represents the
various stages of an instruction pipeline. As a start, I have created a simple
FetchStage that is based on existing logic for how MCA produces
instructions, but now encapsulated in a Stage. The idea should become more concrete
once we introduce additional stages. The idea being, that when a stage completes,
the next stage in the pipeline will be executed. Stages are chained together
as a singly linked list to closely model a real pipeline. For now there is only one stage,
so the stage-to-stage flow of instructions isn't immediately obvious.
Eventually, Stage will also handle event notifications, but that functionality
is not complete, and not destined for this patch. Ideally, an interested party
can register for notifications from a particular stage. Callbacks will be issued to
these listeners at various points in the execution of the stage.
For now, eventing functionality remains similar to what it has been in mca::Backend.
We will be building-up the Stage class as we move on, such as adding debug output.
This patch also removes the unique_ptr<Instruction> return value from
InstrBuilder::createInstruction. An Instruction pointer is still produced,
but now it's up to the caller to decide how that item should be managed post-allocation
(e.g., smart pointer). This allows the Fetch stage to create instructions and
manage the lifetime of those instructions as it wishes, and not have to be bound to any
specific managed pointer type. Other callers of createInstruction might have different
requirements, and thus can manage the pointer to fit their needs. Another idea would be to push the
ownership to the RCU.
Currently, the FetchStage will wrap the Instruction
pointer in a shared_ptr. This allows us to remove the Instruction container in
Backend, which was probably going to disappear, or move, at some point anyways.
Note that I did run these changes through valgrind, to make sure we are not leaking
memory. While the shared_ptr comes with some additional overhead it relieves us
from having to manage a list of generated instructions, and/or make lookup calls
to remove the instructions.
I realize that both the Stage class and the Instruction pointer management
(mentioned directly above) are separate but related ideas, and probably should
land as separate patches; I am happy to do that if either idea is decent.
The main reason these two ideas are together is that
Stage::execute() can mutate an InstRef. For the fetch stage, the InstRef is populated
as the primary action of that stage (execute()). I didn't want to change the Stage interface
to support the idea of generating an instruction. Ideally, instructions are to
be pushed through the pipeline. I didn't want to draw too much of a
specialization just for the fetch stage. Excuse the word-salad.
Reviewers: andreadb, courbet, RKSimon
Reviewed By: andreadb
Subscribers: llvm-commits, mgorny, javed.absar, tschuett, gbedwell
Differential Revision: https://reviews.llvm.org/D46741
llvm-svn: 332390
2018-05-16 04:21:04 +08:00
|
|
|
// Ideally, I'd like to expose the pipeline building here,
|
|
|
|
// by registering all of the Stage instances.
|
|
|
|
// But for now, it's just this single puppy.
|
|
|
|
std::unique_ptr<mca::FetchStage> Fetch =
|
|
|
|
llvm::make_unique<mca::FetchStage>(IB, S);
|
|
|
|
mca::Backend B(*STI, *MRI, std::move(Fetch), Width, RegisterFileSize,
|
|
|
|
LoadQueueSize, StoreQueueSize, AssumeNoAlias);
|
2018-04-10 00:39:52 +08:00
|
|
|
mca::BackendPrinter Printer(B);
|
2018-03-09 21:52:03 +08:00
|
|
|
|
2018-04-10 00:39:52 +08:00
|
|
|
Printer.addView(llvm::make_unique<mca::SummaryView>(S, Width));
|
|
|
|
if (PrintInstructionInfoView)
|
|
|
|
Printer.addView(
|
|
|
|
llvm::make_unique<mca::InstructionInfoView>(*STI, *MCII, S, *IP));
|
2018-03-24 03:40:04 +08:00
|
|
|
|
2018-04-10 22:55:14 +08:00
|
|
|
if (PrintDispatchStats)
|
2018-04-11 20:31:44 +08:00
|
|
|
Printer.addView(llvm::make_unique<mca::DispatchStatistics>());
|
2018-04-10 22:55:14 +08:00
|
|
|
|
2018-04-11 20:12:53 +08:00
|
|
|
if (PrintSchedulerStats)
|
2018-04-11 19:37:46 +08:00
|
|
|
Printer.addView(llvm::make_unique<mca::SchedulerStatistics>(*STI));
|
|
|
|
|
2018-04-11 20:12:53 +08:00
|
|
|
if (PrintRetireStats)
|
|
|
|
Printer.addView(llvm::make_unique<mca::RetireControlUnitStatistics>());
|
2018-03-09 00:08:43 +08:00
|
|
|
|
2018-04-10 00:39:52 +08:00
|
|
|
if (PrintRegisterFileStats)
|
|
|
|
Printer.addView(llvm::make_unique<mca::RegisterFileStatistics>(*STI));
|
2018-03-09 00:08:43 +08:00
|
|
|
|
2018-04-10 00:39:52 +08:00
|
|
|
if (PrintResourcePressureView)
|
|
|
|
Printer.addView(
|
|
|
|
llvm::make_unique<mca::ResourcePressureView>(*STI, *IP, S));
|
2018-04-04 00:46:23 +08:00
|
|
|
|
2018-04-10 00:39:52 +08:00
|
|
|
if (PrintTimelineView) {
|
|
|
|
Printer.addView(llvm::make_unique<mca::TimelineView>(
|
|
|
|
*STI, *IP, S, TimelineMaxIterations, TimelineMaxCycles));
|
|
|
|
}
|
2018-03-09 00:08:43 +08:00
|
|
|
|
2018-04-10 00:39:52 +08:00
|
|
|
B.run();
|
|
|
|
Printer.printReport(TOF->os());
|
2018-03-09 00:08:43 +08:00
|
|
|
}
|
2018-03-08 21:05:02 +08:00
|
|
|
|
2018-03-09 00:08:43 +08:00
|
|
|
TOF->keep();
|
2018-03-08 21:05:02 +08:00
|
|
|
return 0;
|
|
|
|
}
|