2018-03-08 14:05:02 +01:00
|
|
|
//===-- llvm-mca.cpp - Machine Code Analyzer -------------------*- C++ -* -===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01: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-03-08 14:05:02 +01:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// 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 12:18:25 +02:00
|
|
|
// The cpu defaults to the 'native' host cpu.
|
2018-03-08 14:05:02 +01:00
|
|
|
// The output defaults to standard output.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-04-09 18:39:52 +02:00
|
|
|
#include "CodeRegion.h"
|
2018-11-07 20:20:04 +01:00
|
|
|
#include "CodeRegionGenerator.h"
|
2018-06-25 18:53:00 +02:00
|
|
|
#include "PipelinePrinter.h"
|
2019-04-17 08:02:05 +02:00
|
|
|
#include "Views/BottleneckAnalysis.h"
|
2018-08-24 22:24:53 +02:00
|
|
|
#include "Views/DispatchStatistics.h"
|
|
|
|
#include "Views/InstructionInfoView.h"
|
|
|
|
#include "Views/RegisterFileStatistics.h"
|
|
|
|
#include "Views/ResourcePressureView.h"
|
|
|
|
#include "Views/RetireControlUnitStatistics.h"
|
|
|
|
#include "Views/SchedulerStatistics.h"
|
|
|
|
#include "Views/SummaryView.h"
|
|
|
|
#include "Views/TimelineView.h"
|
2018-03-08 14:05:02 +01:00
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
|
|
|
#include "llvm/MC/MCContext.h"
|
|
|
|
#include "llvm/MC/MCObjectFileInfo.h"
|
|
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
2018-12-17 09:08:31 +01:00
|
|
|
#include "llvm/MCA/Context.h"
|
|
|
|
#include "llvm/MCA/Pipeline.h"
|
|
|
|
#include "llvm/MCA/Stages/EntryStage.h"
|
|
|
|
#include "llvm/MCA/Stages/InstructionTables.h"
|
|
|
|
#include "llvm/MCA/Support.h"
|
2018-03-08 14:05:02 +01:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2018-08-13 20:11:48 +02:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2018-03-08 17:08:43 +01:00
|
|
|
#include "llvm/Support/ErrorOr.h"
|
|
|
|
#include "llvm/Support/FileSystem.h"
|
2018-04-25 12:27:30 +02:00
|
|
|
#include "llvm/Support/Host.h"
|
2018-04-13 20:26:06 +02:00
|
|
|
#include "llvm/Support/InitLLVM.h"
|
2018-03-08 14:05:02 +01:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include "llvm/Support/SourceMgr.h"
|
|
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
|
|
#include "llvm/Support/TargetSelect.h"
|
2018-03-08 17:08:43 +01:00
|
|
|
#include "llvm/Support/ToolOutputFile.h"
|
2018-04-18 17:26:51 +02:00
|
|
|
#include "llvm/Support/WithColor.h"
|
2018-03-08 14:05:02 +01:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
2018-05-17 17:35:14 +02:00
|
|
|
static cl::OptionCategory ToolOptions("Tool Options");
|
|
|
|
static cl::OptionCategory ViewOptions("View Options");
|
2018-04-25 13:33:14 +02:00
|
|
|
|
2018-05-17 17:35:14 +02:00
|
|
|
static cl::opt<std::string> InputFilename(cl::Positional,
|
|
|
|
cl::desc("<input file>"),
|
|
|
|
cl::cat(ToolOptions), cl::init("-"));
|
2018-03-08 14:05:02 +01:00
|
|
|
|
|
|
|
static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
|
2018-05-17 17:35:14 +02:00
|
|
|
cl::init("-"), cl::cat(ToolOptions),
|
2018-03-08 14:05:02 +01:00
|
|
|
cl::value_desc("filename"));
|
|
|
|
|
|
|
|
static cl::opt<std::string>
|
2018-10-31 18:47:25 +01:00
|
|
|
ArchName("march", cl::desc("Target architecture. "
|
|
|
|
"See -version for available targets"),
|
2018-05-17 17:35:14 +02:00
|
|
|
cl::cat(ToolOptions));
|
2018-03-08 14:05:02 +01:00
|
|
|
|
|
|
|
static cl::opt<std::string>
|
2018-10-22 17:36:15 +02:00
|
|
|
TripleName("mtriple",
|
2018-10-31 18:47:25 +01:00
|
|
|
cl::desc("Target triple. See -version for available targets"),
|
2018-05-17 17:35:14 +02:00
|
|
|
cl::cat(ToolOptions));
|
2018-03-08 14:05:02 +01:00
|
|
|
|
|
|
|
static cl::opt<std::string>
|
|
|
|
MCPU("mcpu",
|
|
|
|
cl::desc("Target a specific cpu type (-mcpu=help for details)"),
|
2018-05-17 17:35:14 +02:00
|
|
|
cl::value_desc("cpu-name"), cl::cat(ToolOptions), cl::init("native"));
|
2018-03-08 14:05:02 +01:00
|
|
|
|
2018-04-24 18:19:08 +02:00
|
|
|
static cl::opt<int>
|
2018-03-08 14:05:02 +01:00
|
|
|
OutputAsmVariant("output-asm-variant",
|
2018-04-24 18:19:08 +02:00
|
|
|
cl::desc("Syntax variant to use for output printing"),
|
2018-05-17 17:35:14 +02:00
|
|
|
cl::cat(ToolOptions), cl::init(-1));
|
2018-03-08 14:05:02 +01:00
|
|
|
|
|
|
|
static cl::opt<unsigned> Iterations("iterations",
|
|
|
|
cl::desc("Number of iterations to run"),
|
2018-05-17 17:35:14 +02:00
|
|
|
cl::cat(ToolOptions), cl::init(0));
|
2018-03-08 14:05:02 +01:00
|
|
|
|
2018-05-17 17:35:14 +02:00
|
|
|
static cl::opt<unsigned>
|
|
|
|
DispatchWidth("dispatch", cl::desc("Override the processor dispatch width"),
|
|
|
|
cl::cat(ToolOptions), cl::init(0));
|
2018-03-08 14:05:02 +01:00
|
|
|
|
|
|
|
static cl::opt<unsigned>
|
|
|
|
RegisterFileSize("register-file-size",
|
2018-07-31 22:05:08 +02:00
|
|
|
cl::desc("Maximum number of physical registers which can "
|
2018-03-08 14:05:02 +01:00
|
|
|
"be used for register mappings"),
|
2018-05-17 17:35:14 +02:00
|
|
|
cl::cat(ToolOptions), cl::init(0));
|
2018-03-08 14:05:02 +01:00
|
|
|
|
2019-03-29 13:15:37 +01:00
|
|
|
static cl::opt<unsigned>
|
|
|
|
MicroOpQueue("micro-op-queue-size", cl::Hidden,
|
|
|
|
cl::desc("Number of entries in the micro-op queue"),
|
|
|
|
cl::cat(ToolOptions), cl::init(0));
|
|
|
|
|
|
|
|
static cl::opt<unsigned>
|
|
|
|
DecoderThroughput("decoder-throughput", cl::Hidden,
|
|
|
|
cl::desc("Maximum throughput from the decoders "
|
|
|
|
"(instructions per cycle)"),
|
|
|
|
cl::cat(ToolOptions), cl::init(0));
|
|
|
|
|
2018-04-03 18:46:23 +02:00
|
|
|
static cl::opt<bool>
|
|
|
|
PrintRegisterFileStats("register-file-stats",
|
|
|
|
cl::desc("Print register file statistics"),
|
2018-05-05 17:36:47 +02:00
|
|
|
cl::cat(ViewOptions), cl::init(false));
|
2018-04-03 18:46:23 +02:00
|
|
|
|
2018-04-25 12:27:30 +02:00
|
|
|
static cl::opt<bool> PrintDispatchStats("dispatch-stats",
|
|
|
|
cl::desc("Print dispatch statistics"),
|
2018-05-05 17:36:47 +02:00
|
|
|
cl::cat(ViewOptions), cl::init(false));
|
2018-04-10 16:55:14 +02:00
|
|
|
|
2018-06-15 16:01:43 +02:00
|
|
|
static cl::opt<bool>
|
|
|
|
PrintSummaryView("summary-view", cl::Hidden,
|
|
|
|
cl::desc("Print summary view (enabled by default)"),
|
|
|
|
cl::cat(ViewOptions), cl::init(true));
|
|
|
|
|
2018-04-25 12:27:30 +02:00
|
|
|
static cl::opt<bool> PrintSchedulerStats("scheduler-stats",
|
|
|
|
cl::desc("Print scheduler statistics"),
|
2018-05-05 17:36:47 +02:00
|
|
|
cl::cat(ViewOptions), cl::init(false));
|
2018-04-11 13:37:46 +02:00
|
|
|
|
2018-04-11 14:12:53 +02:00
|
|
|
static cl::opt<bool>
|
|
|
|
PrintRetireStats("retire-stats",
|
2018-04-25 12:27:30 +02:00
|
|
|
cl::desc("Print retire control unit statistics"),
|
2018-05-05 17:36:47 +02:00
|
|
|
cl::cat(ViewOptions), cl::init(false));
|
2018-04-11 14:12:53 +02:00
|
|
|
|
2018-05-05 17:36:47 +02: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 12:33:09 +01:00
|
|
|
|
2018-03-08 14:05:02 +01:00
|
|
|
static cl::opt<bool> PrintTimelineView("timeline",
|
|
|
|
cl::desc("Print the timeline view"),
|
2018-05-05 17:36:47 +02:00
|
|
|
cl::cat(ViewOptions), cl::init(false));
|
2018-03-08 14:05:02 +01:00
|
|
|
|
|
|
|
static cl::opt<unsigned> TimelineMaxIterations(
|
|
|
|
"timeline-max-iterations",
|
|
|
|
cl::desc("Maximum number of iterations to print in timeline view"),
|
2018-05-05 17:36:47 +02:00
|
|
|
cl::cat(ViewOptions), cl::init(0));
|
2018-03-08 14:05:02 +01: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 17:36:47 +02:00
|
|
|
cl::cat(ViewOptions), cl::init(80));
|
2018-03-08 14:05:02 +01:00
|
|
|
|
2018-05-17 17:35:14 +02: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 14:05:02 +01:00
|
|
|
|
2018-12-19 19:27:05 +01:00
|
|
|
static cl::opt<unsigned> LoadQueueSize("lqueue",
|
|
|
|
cl::desc("Size of the load queue"),
|
|
|
|
cl::cat(ToolOptions), cl::init(0));
|
2018-03-26 14:04:53 +02:00
|
|
|
|
2018-12-19 19:27:05 +01:00
|
|
|
static cl::opt<unsigned> StoreQueueSize("squeue",
|
|
|
|
cl::desc("Size of the store queue"),
|
|
|
|
cl::cat(ToolOptions), cl::init(0));
|
2018-03-08 14:05:02 +01:00
|
|
|
|
2018-03-26 14:04:53 +02:00
|
|
|
static cl::opt<bool>
|
|
|
|
PrintInstructionTables("instruction-tables",
|
|
|
|
cl::desc("Print instruction tables"),
|
2018-05-17 17:35:14 +02:00
|
|
|
cl::cat(ToolOptions), cl::init(false));
|
2018-03-26 14:04:53 +02:00
|
|
|
|
2018-05-05 17:36:47 +02: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 15:44:54 +02:00
|
|
|
|
2018-05-17 14:27:03 +02: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));
|
|
|
|
|
[MCA] Highlight kernel bottlenecks in the summary view.
This patch adds a new flag named -bottleneck-analysis to print out information
about throughput bottlenecks.
MCA knows how to identify and classify dynamic dispatch stalls. However, it
doesn't know how to analyze and highlight kernel bottlenecks. The goal of this
patch is to teach MCA how to correlate increases in backend pressure to backend
stalls (and therefore, the loss of throughput).
From a Scheduler point of view, backend pressure is a function of the scheduler
buffer usage (i.e. how the number of uOps in the scheduler buffers changes over
time). Backend pressure increases (or decreases) when there is a mismatch
between the number of opcodes dispatched, and the number of opcodes issued in
the same cycle. Since buffer resources are limited, continuous increases in
backend pressure would eventually leads to dispatch stalls. So, there is a
strong correlation between dispatch stalls, and how backpressure changed over
time.
This patch teaches how to identify situations where backend pressure increases
due to:
- unavailable pipeline resources.
- data dependencies.
Data dependencies may delay execution of instructions and therefore increase the
time that uOps have to spend in the scheduler buffers. That often translates to
an increase in backend pressure which may eventually lead to a bottleneck.
Contention on pipeline resources may also delay execution of instructions, and
lead to a temporary increase in backend pressure.
Internally, the Scheduler classifies instructions based on whether register /
memory operands are available or not.
An instruction is marked as "ready to execute" only if data dependencies are
fully resolved.
Every cycle, the Scheduler attempts to execute all instructions that are ready
to execute. If an instruction cannot execute because of unavailable pipeline
resources, then the Scheduler internally updates a BusyResourceUnits mask with
the ID of each unavailable resource.
ExecuteStage is responsible for tracking changes in backend pressure. If backend
pressure increases during a cycle because of contention on pipeline resources,
then ExecuteStage sends a "backend pressure" event to the listeners.
That event would contain information about instructions delayed by resource
pressure, as well as the BusyResourceUnits mask.
Note that ExecuteStage also knows how to identify situations where backpressure
increased because of delays introduced by data dependencies.
The SummaryView observes "backend pressure" events and prints out a "bottleneck
report".
Example of bottleneck report:
```
Cycles with backend pressure increase [ 99.89% ]
Throughput Bottlenecks:
Resource Pressure [ 0.00% ]
Data Dependencies: [ 99.89% ]
- Register Dependencies [ 0.00% ]
- Memory Dependencies [ 99.89% ]
```
A bottleneck report is printed out only if increases in backend pressure
eventually caused backend stalls.
About the time complexity:
Time complexity is linear in the number of instructions in the
Scheduler::PendingSet.
The average slowdown tends to be in the range of ~5-6%.
For memory intensive kernels, the slowdown can be significant if flag
-noalias=false is specified. In the worst case scenario I have observed a
slowdown of ~30% when flag -noalias=false was specified.
We can definitely recover part of that slowdown if we optimize class LSUnit (by
doing extra bookkeeping to speedup queries). For now, this new analysis is
disabled by default, and it can be enabled via flag -bottleneck-analysis. Users
of MCA as a library can enable the generation of pressure events through the
constructor of ExecuteStage.
This patch partially addresses https://bugs.llvm.org/show_bug.cgi?id=37494
Differential Revision: https://reviews.llvm.org/D58728
llvm-svn: 355308
2019-03-04 12:52:34 +01:00
|
|
|
static cl::opt<bool> EnableBottleneckAnalysis(
|
|
|
|
"bottleneck-analysis",
|
|
|
|
cl::desc("Enable bottleneck analysis (disabled by default)"),
|
|
|
|
cl::cat(ViewOptions), cl::init(false));
|
|
|
|
|
2018-04-08 17:10:19 +02:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
const Target *getTarget(const char *ProgName) {
|
2018-03-08 14:05:02 +01:00
|
|
|
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-08 17:10:19 +02:00
|
|
|
ErrorOr<std::unique_ptr<ToolOutputFile>> getOutputStream() {
|
2018-03-08 17:08:43 +01:00
|
|
|
if (OutputFilename == "")
|
|
|
|
OutputFilename = "-";
|
|
|
|
std::error_code EC;
|
2018-11-08 19:08:43 +01:00
|
|
|
auto Out =
|
|
|
|
llvm::make_unique<ToolOutputFile>(OutputFilename, EC, sys::fs::F_None);
|
2018-03-08 17:08:43 +01:00
|
|
|
if (!EC)
|
|
|
|
return std::move(Out);
|
|
|
|
return EC;
|
|
|
|
}
|
2018-03-08 14:05:02 +01:00
|
|
|
} // end of anonymous namespace
|
|
|
|
|
2018-05-17 14:27:03 +02: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()) {
|
2018-06-15 16:01:43 +02:00
|
|
|
processOptionImpl(PrintSummaryView, EnableAllViews);
|
2018-05-17 14:27:03 +02:00
|
|
|
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-10-24 12:56:47 +02:00
|
|
|
// Returns true on success.
|
[llvm-mca] Lower to mca::Instructon before the pipeline is run.
Before this change, the lowering of instructions from llvm::MCInst to
mca::Instruction was done as part of the first stage of the pipeline (i.e. the
FetchStage). In particular, FetchStage was responsible for picking the next
instruction from the source sequence, and lower it to an mca::Instruction with
the help of an object of class InstrBuilder.
The dependency on InstrBuilder was problematic for a number of reasons. Class
InstrBuilder only knows how to lower from llvm::MCInst to mca::Instruction.
That means, it is hard to support a different scenario where instructions
in input are not instances of class llvm::MCInst. Even if we managed to
specialize InstrBuilder, and generalize most of its internal logic, the
dependency on InstrBuilder in FetchStage would have caused more troubles (other
than complicating the pipeline logic).
With this patch, the lowering step is done before the pipeline is run. The
pipeline is no longer responsible for lowering from MCInst to mca::Instruction.
As a consequence of this, the FetchStage no longer needs to interact with an
InstrBuilder. The mca::SourceMgr class now simply wraps a reference to a
sequence of mca::Instruction objects.
This simplifies the logic of FetchStage, and increases the usability of it. As
a result, on a debug build, we see a 7-9% speedup; on a release build, the
speedup is around 3-4%.
llvm-svn: 345500
2018-10-29 14:29:22 +01:00
|
|
|
static bool runPipeline(mca::Pipeline &P) {
|
2018-10-24 12:56:47 +02:00
|
|
|
// Handle pipeline errors here.
|
2018-11-28 20:31:19 +01:00
|
|
|
Expected<unsigned> Cycles = P.run();
|
|
|
|
if (!Cycles) {
|
|
|
|
WithColor::error() << toString(Cycles.takeError());
|
2018-10-24 12:56:47 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-03-08 14:05:02 +01:00
|
|
|
int main(int argc, char **argv) {
|
2018-04-13 20:26:06 +02:00
|
|
|
InitLLVM X(argc, argv);
|
2018-03-08 14:05:02 +01:00
|
|
|
|
|
|
|
// Initialize targets and assembly parsers.
|
2018-11-08 18:32:45 +01:00
|
|
|
InitializeAllTargetInfos();
|
|
|
|
InitializeAllTargetMCs();
|
|
|
|
InitializeAllAsmParsers();
|
2018-03-08 14:05:02 +01:00
|
|
|
|
|
|
|
// Enable printing of available targets when flag --version is specified.
|
|
|
|
cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
|
|
|
|
|
2018-05-17 17:35:14 +02:00
|
|
|
cl::HideUnrelatedOptions({&ToolOptions, &ViewOptions});
|
|
|
|
|
2018-03-08 14:05:02 +01:00
|
|
|
// Parse flags and initialize target options.
|
|
|
|
cl::ParseCommandLineOptions(argc, argv,
|
|
|
|
"llvm machine code performance analyzer.\n");
|
2018-05-17 17:35:14 +02:00
|
|
|
|
2018-03-08 14:05:02 +01:00
|
|
|
// 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 17:26:51 +02:00
|
|
|
WithColor::error() << InputFilename << ": " << EC.message() << '\n';
|
2018-03-08 14:05:02 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-05-17 14:27:03 +02:00
|
|
|
// Apply overrides to llvm-mca specific options.
|
|
|
|
processViewOptions();
|
|
|
|
|
2018-03-08 14:05:02 +01: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 14:04:53 +02:00
|
|
|
|
2018-03-08 14:05:02 +01:00
|
|
|
std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
|
2018-04-25 12:18:25 +02:00
|
|
|
|
2018-06-20 12:08:11 +02:00
|
|
|
std::unique_ptr<MCInstrAnalysis> MCIA(
|
|
|
|
TheTarget->createMCInstrAnalysis(MCII.get()));
|
|
|
|
|
2018-04-25 12:18:25 +02:00
|
|
|
if (!MCPU.compare("native"))
|
2018-11-08 19:08:43 +01:00
|
|
|
MCPU = llvm::sys::getHostCPUName();
|
2018-04-25 12:18:25 +02:00
|
|
|
|
2018-03-08 14:05:02 +01:00
|
|
|
std::unique_ptr<MCSubtargetInfo> STI(
|
|
|
|
TheTarget->createMCSubtargetInfo(TripleName, MCPU, /* FeaturesStr */ ""));
|
|
|
|
if (!STI->isCPUStringValid(MCPU))
|
|
|
|
return 1;
|
|
|
|
|
2018-04-30 14:05:34 +02:00
|
|
|
if (!PrintInstructionTables && !STI->getSchedModel().isOutOfOrder()) {
|
2018-04-18 17:26:51 +02:00
|
|
|
WithColor::error() << "please specify an out-of-order cpu. '" << MCPU
|
|
|
|
<< "' is an in-order cpu.\n";
|
2018-03-08 14:05:02 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!STI->getSchedModel().hasInstrSchedModel()) {
|
2018-04-18 17:26:51 +02:00
|
|
|
WithColor::error()
|
|
|
|
<< "unable to find instruction-level scheduling information for"
|
2018-03-08 14:05:02 +01:00
|
|
|
<< " target triple '" << TheTriple.normalize() << "' and cpu '" << MCPU
|
|
|
|
<< "'.\n";
|
|
|
|
|
|
|
|
if (STI->getSchedModel().InstrItineraries)
|
2018-04-18 17:26:51 +02:00
|
|
|
WithColor::note()
|
|
|
|
<< "cpu '" << MCPU << "' provides itineraries. However, "
|
|
|
|
<< "instruction itineraries are currently unsupported.\n";
|
2018-03-08 14:05:02 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-11-07 20:20:04 +01:00
|
|
|
// Parse the input and create CodeRegions that llvm-mca can analyze.
|
|
|
|
mca::AsmCodeRegionGenerator CRG(*TheTarget, SrcMgr, Ctx, *MAI, *STI, *MCII);
|
|
|
|
Expected<const mca::CodeRegions &> RegionsOrErr = CRG.parseCodeRegions();
|
2018-12-19 19:27:05 +01:00
|
|
|
if (!RegionsOrErr) {
|
|
|
|
if (auto Err =
|
2018-12-19 19:57:43 +01:00
|
|
|
handleErrors(RegionsOrErr.takeError(), [](const StringError &E) {
|
|
|
|
WithColor::error() << E.getMessage() << '\n';
|
2018-12-19 19:27:05 +01:00
|
|
|
})) {
|
|
|
|
// Default case.
|
|
|
|
WithColor::error() << toString(std::move(Err)) << '\n';
|
|
|
|
}
|
2018-04-08 17:10:19 +02:00
|
|
|
return 1;
|
2018-11-07 20:20:04 +01:00
|
|
|
}
|
|
|
|
const mca::CodeRegions &Regions = *RegionsOrErr;
|
2018-04-09 18:39:52 +02:00
|
|
|
if (Regions.empty()) {
|
2018-04-18 17:26:51 +02:00
|
|
|
WithColor::error() << "no assembly instructions found.\n";
|
2018-03-08 14:05:02 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-03-08 17:08:43 +01:00
|
|
|
// Now initialize the output file.
|
|
|
|
auto OF = getOutputStream();
|
|
|
|
if (std::error_code EC = OF.getError()) {
|
2018-04-18 17:26:51 +02:00
|
|
|
WithColor::error() << EC.message() << '\n';
|
2018-03-08 17:08:43 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-11-07 20:20:04 +01:00
|
|
|
unsigned AssemblerDialect = CRG.getAssemblerDialect();
|
2018-04-24 18:19:08 +02:00
|
|
|
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-11-08 18:32:45 +01:00
|
|
|
std::unique_ptr<ToolOutputFile> TOF = std::move(*OF);
|
2018-03-08 17:08:43 +01:00
|
|
|
|
2018-03-08 14:05:02 +01:00
|
|
|
const MCSchedModel &SM = STI->getSchedModel();
|
|
|
|
|
2018-03-23 12:50:43 +01:00
|
|
|
// Create an instruction builder.
|
2018-12-17 15:00:37 +01:00
|
|
|
mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get());
|
2018-03-23 12:50:43 +01:00
|
|
|
|
2018-07-06 20:03:14 +02:00
|
|
|
// Create a context to control ownership of the pipeline hardware.
|
|
|
|
mca::Context MCA(*MRI, *STI);
|
|
|
|
|
2019-03-29 13:15:37 +01:00
|
|
|
mca::PipelineOptions PO(MicroOpQueue, DecoderThroughput, DispatchWidth,
|
|
|
|
RegisterFileSize, LoadQueueSize, StoreQueueSize,
|
|
|
|
AssumeNoAlias, EnableBottleneckAnalysis);
|
2018-07-06 20:03:14 +02:00
|
|
|
|
2018-04-09 18:39:52 +02:00
|
|
|
// Number each region in the sequence.
|
|
|
|
unsigned RegionIdx = 0;
|
2018-10-26 12:48:04 +02:00
|
|
|
|
2018-04-09 18:39:52 +02:00
|
|
|
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 15:44:54 +02:00
|
|
|
}
|
|
|
|
|
[llvm-mca] Lower to mca::Instructon before the pipeline is run.
Before this change, the lowering of instructions from llvm::MCInst to
mca::Instruction was done as part of the first stage of the pipeline (i.e. the
FetchStage). In particular, FetchStage was responsible for picking the next
instruction from the source sequence, and lower it to an mca::Instruction with
the help of an object of class InstrBuilder.
The dependency on InstrBuilder was problematic for a number of reasons. Class
InstrBuilder only knows how to lower from llvm::MCInst to mca::Instruction.
That means, it is hard to support a different scenario where instructions
in input are not instances of class llvm::MCInst. Even if we managed to
specialize InstrBuilder, and generalize most of its internal logic, the
dependency on InstrBuilder in FetchStage would have caused more troubles (other
than complicating the pipeline logic).
With this patch, the lowering step is done before the pipeline is run. The
pipeline is no longer responsible for lowering from MCInst to mca::Instruction.
As a consequence of this, the FetchStage no longer needs to interact with an
InstrBuilder. The mca::SourceMgr class now simply wraps a reference to a
sequence of mca::Instruction objects.
This simplifies the logic of FetchStage, and increases the usability of it. As
a result, on a debug build, we see a 7-9% speedup; on a release build, the
speedup is around 3-4%.
llvm-svn: 345500
2018-10-29 14:29:22 +01:00
|
|
|
// Lower the MCInst sequence into an mca::Instruction sequence.
|
2018-10-26 12:48:04 +02:00
|
|
|
ArrayRef<MCInst> Insts = Region->getInstructions();
|
[llvm-mca] Lower to mca::Instructon before the pipeline is run.
Before this change, the lowering of instructions from llvm::MCInst to
mca::Instruction was done as part of the first stage of the pipeline (i.e. the
FetchStage). In particular, FetchStage was responsible for picking the next
instruction from the source sequence, and lower it to an mca::Instruction with
the help of an object of class InstrBuilder.
The dependency on InstrBuilder was problematic for a number of reasons. Class
InstrBuilder only knows how to lower from llvm::MCInst to mca::Instruction.
That means, it is hard to support a different scenario where instructions
in input are not instances of class llvm::MCInst. Even if we managed to
specialize InstrBuilder, and generalize most of its internal logic, the
dependency on InstrBuilder in FetchStage would have caused more troubles (other
than complicating the pipeline logic).
With this patch, the lowering step is done before the pipeline is run. The
pipeline is no longer responsible for lowering from MCInst to mca::Instruction.
As a consequence of this, the FetchStage no longer needs to interact with an
InstrBuilder. The mca::SourceMgr class now simply wraps a reference to a
sequence of mca::Instruction objects.
This simplifies the logic of FetchStage, and increases the usability of it. As
a result, on a debug build, we see a 7-9% speedup; on a release build, the
speedup is around 3-4%.
llvm-svn: 345500
2018-10-29 14:29:22 +01:00
|
|
|
std::vector<std::unique_ptr<mca::Instruction>> LoweredSequence;
|
|
|
|
for (const MCInst &MCI : Insts) {
|
2018-11-08 18:32:45 +01:00
|
|
|
Expected<std::unique_ptr<mca::Instruction>> Inst =
|
2018-10-31 18:47:25 +01:00
|
|
|
IB.createInstruction(MCI);
|
[llvm-mca] Lower to mca::Instructon before the pipeline is run.
Before this change, the lowering of instructions from llvm::MCInst to
mca::Instruction was done as part of the first stage of the pipeline (i.e. the
FetchStage). In particular, FetchStage was responsible for picking the next
instruction from the source sequence, and lower it to an mca::Instruction with
the help of an object of class InstrBuilder.
The dependency on InstrBuilder was problematic for a number of reasons. Class
InstrBuilder only knows how to lower from llvm::MCInst to mca::Instruction.
That means, it is hard to support a different scenario where instructions
in input are not instances of class llvm::MCInst. Even if we managed to
specialize InstrBuilder, and generalize most of its internal logic, the
dependency on InstrBuilder in FetchStage would have caused more troubles (other
than complicating the pipeline logic).
With this patch, the lowering step is done before the pipeline is run. The
pipeline is no longer responsible for lowering from MCInst to mca::Instruction.
As a consequence of this, the FetchStage no longer needs to interact with an
InstrBuilder. The mca::SourceMgr class now simply wraps a reference to a
sequence of mca::Instruction objects.
This simplifies the logic of FetchStage, and increases the usability of it. As
a result, on a debug build, we see a 7-9% speedup; on a release build, the
speedup is around 3-4%.
llvm-svn: 345500
2018-10-29 14:29:22 +01:00
|
|
|
if (!Inst) {
|
2018-10-31 18:47:25 +01:00
|
|
|
if (auto NewE = handleErrors(
|
|
|
|
Inst.takeError(),
|
|
|
|
[&IP, &STI](const mca::InstructionError<MCInst> &IE) {
|
|
|
|
std::string InstructionStr;
|
|
|
|
raw_string_ostream SS(InstructionStr);
|
|
|
|
WithColor::error() << IE.Message << '\n';
|
|
|
|
IP->printInst(&IE.Inst, SS, "", *STI);
|
|
|
|
SS.flush();
|
|
|
|
WithColor::note() << "instruction: " << InstructionStr
|
|
|
|
<< '\n';
|
|
|
|
})) {
|
[llvm-mca] Lower to mca::Instructon before the pipeline is run.
Before this change, the lowering of instructions from llvm::MCInst to
mca::Instruction was done as part of the first stage of the pipeline (i.e. the
FetchStage). In particular, FetchStage was responsible for picking the next
instruction from the source sequence, and lower it to an mca::Instruction with
the help of an object of class InstrBuilder.
The dependency on InstrBuilder was problematic for a number of reasons. Class
InstrBuilder only knows how to lower from llvm::MCInst to mca::Instruction.
That means, it is hard to support a different scenario where instructions
in input are not instances of class llvm::MCInst. Even if we managed to
specialize InstrBuilder, and generalize most of its internal logic, the
dependency on InstrBuilder in FetchStage would have caused more troubles (other
than complicating the pipeline logic).
With this patch, the lowering step is done before the pipeline is run. The
pipeline is no longer responsible for lowering from MCInst to mca::Instruction.
As a consequence of this, the FetchStage no longer needs to interact with an
InstrBuilder. The mca::SourceMgr class now simply wraps a reference to a
sequence of mca::Instruction objects.
This simplifies the logic of FetchStage, and increases the usability of it. As
a result, on a debug build, we see a 7-9% speedup; on a release build, the
speedup is around 3-4%.
llvm-svn: 345500
2018-10-29 14:29:22 +01:00
|
|
|
// Default case.
|
|
|
|
WithColor::error() << toString(std::move(NewE));
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
LoweredSequence.emplace_back(std::move(Inst.get()));
|
|
|
|
}
|
|
|
|
|
2018-10-31 18:47:25 +01:00
|
|
|
mca::SourceMgr S(LoweredSequence, PrintInstructionTables ? 1 : Iterations);
|
2018-04-09 18:39:52 +02:00
|
|
|
|
|
|
|
if (PrintInstructionTables) {
|
2018-07-15 01:52:50 +02:00
|
|
|
// Create a pipeline, stages, and a printer.
|
2018-11-08 19:08:43 +01:00
|
|
|
auto P = llvm::make_unique<mca::Pipeline>();
|
|
|
|
P->appendStage(llvm::make_unique<mca::EntryStage>(S));
|
|
|
|
P->appendStage(llvm::make_unique<mca::InstructionTables>(SM));
|
2018-07-15 01:52:50 +02:00
|
|
|
mca::PipelinePrinter Printer(*P);
|
2018-04-09 18:39:52 +02:00
|
|
|
|
2018-07-15 01:52:50 +02:00
|
|
|
// Create the views for this pipeline, execute, and emit a report.
|
2018-04-09 18:39:52 +02:00
|
|
|
if (PrintInstructionInfoView) {
|
2018-11-08 19:08:43 +01:00
|
|
|
Printer.addView(llvm::make_unique<mca::InstructionInfoView>(
|
|
|
|
*STI, *MCII, Insts, *IP));
|
2018-04-09 18:39:52 +02:00
|
|
|
}
|
2018-11-08 19:08:43 +01:00
|
|
|
Printer.addView(
|
|
|
|
llvm::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts));
|
2018-10-24 12:56:47 +02:00
|
|
|
|
[llvm-mca] Lower to mca::Instructon before the pipeline is run.
Before this change, the lowering of instructions from llvm::MCInst to
mca::Instruction was done as part of the first stage of the pipeline (i.e. the
FetchStage). In particular, FetchStage was responsible for picking the next
instruction from the source sequence, and lower it to an mca::Instruction with
the help of an object of class InstrBuilder.
The dependency on InstrBuilder was problematic for a number of reasons. Class
InstrBuilder only knows how to lower from llvm::MCInst to mca::Instruction.
That means, it is hard to support a different scenario where instructions
in input are not instances of class llvm::MCInst. Even if we managed to
specialize InstrBuilder, and generalize most of its internal logic, the
dependency on InstrBuilder in FetchStage would have caused more troubles (other
than complicating the pipeline logic).
With this patch, the lowering step is done before the pipeline is run. The
pipeline is no longer responsible for lowering from MCInst to mca::Instruction.
As a consequence of this, the FetchStage no longer needs to interact with an
InstrBuilder. The mca::SourceMgr class now simply wraps a reference to a
sequence of mca::Instruction objects.
This simplifies the logic of FetchStage, and increases the usability of it. As
a result, on a debug build, we see a 7-9% speedup; on a release build, the
speedup is around 3-4%.
llvm-svn: 345500
2018-10-29 14:29:22 +01:00
|
|
|
if (!runPipeline(*P))
|
2018-10-24 12:56:47 +02:00
|
|
|
return 1;
|
|
|
|
|
2018-07-15 01:52:50 +02:00
|
|
|
Printer.printReport(TOF->os());
|
2018-04-09 18:39:52 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-07-06 20:03:14 +02:00
|
|
|
// Create a basic pipeline simulating an out-of-order backend.
|
|
|
|
auto P = MCA.createDefaultPipeline(PO, IB, S);
|
2018-06-25 18:53:00 +02:00
|
|
|
mca::PipelinePrinter Printer(*P);
|
2018-03-09 14:52:03 +01:00
|
|
|
|
2018-06-15 16:01:43 +02:00
|
|
|
if (PrintSummaryView)
|
2019-03-07 20:34:44 +01:00
|
|
|
Printer.addView(llvm::make_unique<mca::SummaryView>(
|
2019-04-17 08:02:05 +02:00
|
|
|
SM, Insts, DispatchWidth));
|
|
|
|
|
|
|
|
if (EnableBottleneckAnalysis)
|
|
|
|
Printer.addView(llvm::make_unique<mca::BottleneckAnalysis>(SM));
|
2018-06-15 16:01:43 +02:00
|
|
|
|
2018-04-09 18:39:52 +02:00
|
|
|
if (PrintInstructionInfoView)
|
|
|
|
Printer.addView(
|
2018-11-08 19:08:43 +01:00
|
|
|
llvm::make_unique<mca::InstructionInfoView>(*STI, *MCII, Insts, *IP));
|
2018-03-23 20:40:04 +01:00
|
|
|
|
2018-04-10 16:55:14 +02:00
|
|
|
if (PrintDispatchStats)
|
2018-11-08 19:08:43 +01:00
|
|
|
Printer.addView(llvm::make_unique<mca::DispatchStatistics>());
|
2018-04-10 16:55:14 +02:00
|
|
|
|
2018-04-11 14:12:53 +02:00
|
|
|
if (PrintSchedulerStats)
|
2018-11-08 19:08:43 +01:00
|
|
|
Printer.addView(llvm::make_unique<mca::SchedulerStatistics>(*STI));
|
2018-04-11 13:37:46 +02:00
|
|
|
|
2018-04-11 14:12:53 +02:00
|
|
|
if (PrintRetireStats)
|
2018-11-23 13:12:57 +01:00
|
|
|
Printer.addView(llvm::make_unique<mca::RetireControlUnitStatistics>(SM));
|
2018-03-08 17:08:43 +01:00
|
|
|
|
2018-04-09 18:39:52 +02:00
|
|
|
if (PrintRegisterFileStats)
|
2018-11-08 19:08:43 +01:00
|
|
|
Printer.addView(llvm::make_unique<mca::RegisterFileStatistics>(*STI));
|
2018-03-08 17:08:43 +01:00
|
|
|
|
2018-04-09 18:39:52 +02:00
|
|
|
if (PrintResourcePressureView)
|
2018-11-08 19:08:43 +01:00
|
|
|
Printer.addView(
|
|
|
|
llvm::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts));
|
2018-04-03 18:46:23 +02:00
|
|
|
|
2018-04-09 18:39:52 +02:00
|
|
|
if (PrintTimelineView) {
|
2018-10-26 12:48:04 +02:00
|
|
|
unsigned TimelineIterations =
|
|
|
|
TimelineMaxIterations ? TimelineMaxIterations : 10;
|
2018-11-08 19:08:43 +01:00
|
|
|
Printer.addView(llvm::make_unique<mca::TimelineView>(
|
2018-10-26 12:48:04 +02:00
|
|
|
*STI, *IP, Insts, std::min(TimelineIterations, S.getNumIterations()),
|
|
|
|
TimelineMaxCycles));
|
2018-04-09 18:39:52 +02:00
|
|
|
}
|
2018-03-08 17:08:43 +01:00
|
|
|
|
[llvm-mca] Lower to mca::Instructon before the pipeline is run.
Before this change, the lowering of instructions from llvm::MCInst to
mca::Instruction was done as part of the first stage of the pipeline (i.e. the
FetchStage). In particular, FetchStage was responsible for picking the next
instruction from the source sequence, and lower it to an mca::Instruction with
the help of an object of class InstrBuilder.
The dependency on InstrBuilder was problematic for a number of reasons. Class
InstrBuilder only knows how to lower from llvm::MCInst to mca::Instruction.
That means, it is hard to support a different scenario where instructions
in input are not instances of class llvm::MCInst. Even if we managed to
specialize InstrBuilder, and generalize most of its internal logic, the
dependency on InstrBuilder in FetchStage would have caused more troubles (other
than complicating the pipeline logic).
With this patch, the lowering step is done before the pipeline is run. The
pipeline is no longer responsible for lowering from MCInst to mca::Instruction.
As a consequence of this, the FetchStage no longer needs to interact with an
InstrBuilder. The mca::SourceMgr class now simply wraps a reference to a
sequence of mca::Instruction objects.
This simplifies the logic of FetchStage, and increases the usability of it. As
a result, on a debug build, we see a 7-9% speedup; on a release build, the
speedup is around 3-4%.
llvm-svn: 345500
2018-10-29 14:29:22 +01:00
|
|
|
if (!runPipeline(*P))
|
2018-10-24 12:56:47 +02:00
|
|
|
return 1;
|
|
|
|
|
2018-04-09 18:39:52 +02:00
|
|
|
Printer.printReport(TOF->os());
|
2018-07-02 22:39:57 +02:00
|
|
|
|
|
|
|
// Clear the InstrBuilder internal state in preparation for another round.
|
|
|
|
IB.clear();
|
2018-03-08 17:08:43 +01:00
|
|
|
}
|
2018-03-08 14:05:02 +01:00
|
|
|
|
2018-03-08 17:08:43 +01:00
|
|
|
TOF->keep();
|
2018-03-08 14:05:02 +01:00
|
|
|
return 0;
|
|
|
|
}
|