aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-mca/llvm-mca.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-mca/llvm-mca.cpp')
-rw-r--r--llvm/tools/llvm-mca/llvm-mca.cpp194
1 files changed, 144 insertions, 50 deletions
diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp
index 13a2c6363579..a473cd8f1719 100644
--- a/llvm/tools/llvm-mca/llvm-mca.cpp
+++ b/llvm/tools/llvm-mca/llvm-mca.cpp
@@ -32,6 +32,9 @@
#include "Views/SchedulerStatistics.h"
#include "Views/SummaryView.h"
#include "Views/TimelineView.h"
+#ifdef HAS_AMDGPU
+#include "lib/AMDGPU/AMDGPUCustomBehaviour.h"
+#endif
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCCodeEmitter.h"
@@ -42,6 +45,7 @@
#include "llvm/MC/MCTargetOptionsCommandFlags.h"
#include "llvm/MCA/CodeEmitter.h"
#include "llvm/MCA/Context.h"
+#include "llvm/MCA/CustomBehaviour.h"
#include "llvm/MCA/InstrBuilder.h"
#include "llvm/MCA/Pipeline.h"
#include "llvm/MCA/Stages/EntryStage.h"
@@ -91,15 +95,13 @@ static cl::opt<std::string>
cl::desc("Target a specific cpu type (-mcpu=help for details)"),
cl::value_desc("cpu-name"), cl::cat(ToolOptions), cl::init("native"));
-static cl::opt<std::string>
- MATTR("mattr",
- cl::desc("Additional target features."),
- cl::cat(ToolOptions));
+static cl::opt<std::string> MATTR("mattr",
+ cl::desc("Additional target features."),
+ cl::cat(ToolOptions));
-static cl::opt<bool>
- PrintJson("json",
- cl::desc("Print the output in json format"),
- cl::cat(ToolOptions), cl::init(false));
+static cl::opt<bool> PrintJson("json",
+ cl::desc("Print the output in json format"),
+ cl::cat(ToolOptions), cl::init(false));
static cl::opt<int>
OutputAsmVariant("output-asm-variant",
@@ -172,11 +174,11 @@ static cl::opt<unsigned> TimelineMaxIterations(
cl::desc("Maximum number of iterations to print in timeline view"),
cl::cat(ViewOptions), cl::init(0));
-static cl::opt<unsigned> TimelineMaxCycles(
- "timeline-max-cycles",
- cl::desc(
- "Maximum number of cycles in the timeline view. Defaults to 80 cycles"),
- cl::cat(ViewOptions), cl::init(80));
+static cl::opt<unsigned>
+ TimelineMaxCycles("timeline-max-cycles",
+ cl::desc("Maximum number of cycles in the timeline view, "
+ "or 0 for unlimited. Defaults to 80 cycles"),
+ cl::cat(ViewOptions), cl::init(80));
static cl::opt<bool>
AssumeNoAlias("noalias",
@@ -220,6 +222,12 @@ static cl::opt<bool> ShowEncoding(
cl::desc("Print encoding information in the instruction info view"),
cl::cat(ViewOptions), cl::init(false));
+static cl::opt<bool> DisableCustomBehaviour(
+ "disable-cb",
+ cl::desc(
+ "Disable custom behaviour (use the default class which does nothing)."),
+ cl::cat(ViewOptions), cl::init(false));
+
namespace {
const Target *getTarget(const char *ProgName) {
@@ -236,6 +244,9 @@ const Target *getTarget(const char *ProgName) {
return nullptr;
}
+ // Update TripleName with the updated triple from the target lookup.
+ TripleName = TheTriple.str();
+
// Return the found target.
return TheTarget;
}
@@ -244,8 +255,8 @@ ErrorOr<std::unique_ptr<ToolOutputFile>> getOutputStream() {
if (OutputFilename == "")
OutputFilename = "-";
std::error_code EC;
- auto Out =
- std::make_unique<ToolOutputFile>(OutputFilename, EC, sys::fs::OF_Text);
+ auto Out = std::make_unique<ToolOutputFile>(OutputFilename, EC,
+ sys::fs::OF_TextWithCRLF);
if (!EC)
return std::move(Out);
return EC;
@@ -257,14 +268,15 @@ static void processOptionImpl(cl::opt<bool> &O, const cl::opt<bool> &Default) {
O = Default.getValue();
}
-static void processViewOptions() {
+static void processViewOptions(bool IsOutOfOrder) {
if (!EnableAllViews.getNumOccurrences() &&
!EnableAllStats.getNumOccurrences())
return;
if (EnableAllViews.getNumOccurrences()) {
processOptionImpl(PrintSummaryView, EnableAllViews);
- processOptionImpl(EnableBottleneckAnalysis, EnableAllViews);
+ if (IsOutOfOrder)
+ processOptionImpl(EnableBottleneckAnalysis, EnableAllViews);
processOptionImpl(PrintResourcePressureView, EnableAllViews);
processOptionImpl(PrintTimelineView, EnableAllViews);
processOptionImpl(PrintInstructionInfoView, EnableAllViews);
@@ -277,7 +289,41 @@ static void processViewOptions() {
processOptionImpl(PrintRegisterFileStats, Default);
processOptionImpl(PrintDispatchStats, Default);
processOptionImpl(PrintSchedulerStats, Default);
- processOptionImpl(PrintRetireStats, Default);
+ if (IsOutOfOrder)
+ processOptionImpl(PrintRetireStats, Default);
+}
+
+std::unique_ptr<mca::InstrPostProcess>
+createInstrPostProcess(const Triple &TheTriple, const MCSubtargetInfo &STI,
+ const MCInstrInfo &MCII) {
+ // Might be a good idea to have a separate flag so that InstrPostProcess
+ // can be used with or without CustomBehaviour
+ if (DisableCustomBehaviour)
+ return std::make_unique<mca::InstrPostProcess>(STI, MCII);
+#ifdef HAS_AMDGPU
+ if (TheTriple.isAMDGPU())
+ return std::make_unique<mca::AMDGPUInstrPostProcess>(STI, MCII);
+#endif
+ return std::make_unique<mca::InstrPostProcess>(STI, MCII);
+}
+
+std::unique_ptr<mca::CustomBehaviour>
+createCustomBehaviour(const Triple &TheTriple, const MCSubtargetInfo &STI,
+ const mca::SourceMgr &SrcMgr, const MCInstrInfo &MCII) {
+ // Build the appropriate CustomBehaviour object for the current target.
+ // The CustomBehaviour class should never depend on the source code,
+ // but it can depend on the list of mca::Instruction and any classes
+ // that can be built using just the target info. If you need extra
+ // information from the source code or the list of MCInst, consider
+ // adding that information to the mca::Instruction class and setting
+ // it during InstrBuilder::createInstruction().
+ if (DisableCustomBehaviour)
+ return std::make_unique<mca::CustomBehaviour>(STI, SrcMgr, MCII);
+#ifdef HAS_AMDGPU
+ if (TheTriple.isAMDGPU())
+ return std::make_unique<mca::AMDGPUCustomBehaviour>(STI, SrcMgr, MCII);
+#endif
+ return std::make_unique<mca::CustomBehaviour>(STI, SrcMgr, MCII);
}
// Returns true on success.
@@ -327,9 +373,6 @@ int main(int argc, char **argv) {
return 1;
}
- // Apply overrides to llvm-mca specific options.
- processViewOptions();
-
if (MCPU == "native")
MCPU = std::string(llvm::sys::getHostCPUName());
@@ -339,10 +382,10 @@ int main(int argc, char **argv) {
if (!STI->isCPUStringValid(MCPU))
return 1;
- if (!PrintInstructionTables && !STI->getSchedModel().isOutOfOrder()) {
- WithColor::error() << "please specify an out-of-order cpu. '" << MCPU
- << "' is an in-order cpu.\n";
- return 1;
+ bool IsOutOfOrder = STI->getSchedModel().isOutOfOrder();
+ if (!PrintInstructionTables && !IsOutOfOrder) {
+ WithColor::warning() << "support for in-order CPU '" << MCPU
+ << "' is experimental.\n";
}
if (!STI->getSchedModel().hasInstrSchedModel()) {
@@ -358,6 +401,9 @@ int main(int argc, char **argv) {
return 1;
}
+ // Apply overrides to llvm-mca specific options.
+ processViewOptions(IsOutOfOrder);
+
std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
assert(MRI && "Unable to create target register info!");
@@ -366,15 +412,15 @@ int main(int argc, char **argv) {
TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
assert(MAI && "Unable to create target asm info!");
- MCObjectFileInfo MOFI;
SourceMgr SrcMgr;
// Tell SrcMgr about this buffer, which is what the parser will pick up.
SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc());
- MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr);
-
- MOFI.InitMCObjectFileInfo(TheTriple, /* PIC= */ false, Ctx);
+ MCContext Ctx(TheTriple, MAI.get(), MRI.get(), STI.get(), &SrcMgr);
+ std::unique_ptr<MCObjectFileInfo> MOFI(
+ TheTarget->createMCObjectFileInfo(Ctx, /*PIC=*/false));
+ Ctx.setObjectFileInfo(MOFI.get());
std::unique_ptr<buffer_ostream> BOS;
@@ -384,9 +430,28 @@ int main(int argc, char **argv) {
std::unique_ptr<MCInstrAnalysis> MCIA(
TheTarget->createMCInstrAnalysis(MCII.get()));
+ // Need to initialize an MCInstPrinter as it is
+ // required for initializing the MCTargetStreamer
+ // which needs to happen within the CRG.parseCodeRegions() call below.
+ // Without an MCTargetStreamer, certain assembly directives can trigger a
+ // segfault. (For example, the .cv_fpo_proc directive on x86 will segfault if
+ // we don't initialize the MCTargetStreamer.)
+ unsigned IPtempOutputAsmVariant =
+ OutputAsmVariant == -1 ? 0 : OutputAsmVariant;
+ std::unique_ptr<MCInstPrinter> IPtemp(TheTarget->createMCInstPrinter(
+ Triple(TripleName), IPtempOutputAsmVariant, *MAI, *MCII, *MRI));
+ if (!IPtemp) {
+ WithColor::error()
+ << "unable to create instruction printer for target triple '"
+ << TheTriple.normalize() << "' with assembly variant "
+ << IPtempOutputAsmVariant << ".\n";
+ return 1;
+ }
+
// 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();
+ Expected<const mca::CodeRegions &> RegionsOrErr =
+ CRG.parseCodeRegions(std::move(IPtemp));
if (!RegionsOrErr) {
if (auto Err =
handleErrors(RegionsOrErr.takeError(), [](const StringError &E) {
@@ -456,24 +521,19 @@ int main(int argc, char **argv) {
*STI, *MRI, mc::InitMCTargetOptionsFromFlags()));
assert(MAB && "Unable to create asm backend!");
+ json::Object JSONOutput;
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";
- }
+ IB.clear();
// Lower the MCInst sequence into an mca::Instruction sequence.
ArrayRef<MCInst> Insts = Region->getInstructions();
mca::CodeEmitter CE(*STI, *MAB, *MCE, Insts);
+ std::unique_ptr<mca::InstrPostProcess> IPP =
+ createInstrPostProcess(TheTriple, *STI, *MCII);
std::vector<std::unique_ptr<mca::Instruction>> LoweredSequence;
for (const MCInst &MCI : Insts) {
Expected<std::unique_ptr<mca::Instruction>> Inst =
@@ -496,6 +556,8 @@ int main(int argc, char **argv) {
return 1;
}
+ IPP->postProcessInstruction(Inst.get(), MCI);
+
LoweredSequence.emplace_back(std::move(Inst.get()));
}
@@ -506,7 +568,12 @@ int main(int argc, char **argv) {
auto P = std::make_unique<mca::Pipeline>();
P->appendStage(std::make_unique<mca::EntryStage>(S));
P->appendStage(std::make_unique<mca::InstructionTables>(SM));
- mca::PipelinePrinter Printer(*P, mca::View::OK_READABLE);
+
+ mca::PipelinePrinter Printer(*P, *Region, RegionIdx, *STI, PO);
+ if (PrintJson) {
+ Printer.addView(
+ std::make_unique<mca::InstructionView>(*STI, *IP, Insts));
+ }
// Create the views for this pipeline, execute, and emit a report.
if (PrintInstructionInfoView) {
@@ -519,26 +586,47 @@ int main(int argc, char **argv) {
if (!runPipeline(*P))
return 1;
- Printer.printReport(TOF->os());
+ if (PrintJson) {
+ Printer.printReport(JSONOutput);
+ } else {
+ Printer.printReport(TOF->os());
+ }
+
+ ++RegionIdx;
continue;
}
+ // Create the CustomBehaviour object for enforcing Target Specific
+ // behaviours and dependencies that aren't expressed well enough
+ // in the tablegen. CB cannot depend on the list of MCInst or
+ // the source code (but it can depend on the list of
+ // mca::Instruction or any objects that can be reconstructed
+ // from the target information).
+ std::unique_ptr<mca::CustomBehaviour> CB =
+ createCustomBehaviour(TheTriple, *STI, S, *MCII);
+
// Create a basic pipeline simulating an out-of-order backend.
- auto P = MCA.createDefaultPipeline(PO, S);
- mca::PipelinePrinter Printer(*P, PrintJson ? mca::View::OK_JSON
- : mca::View::OK_READABLE);
+ auto P = MCA.createDefaultPipeline(PO, S, *CB);
+
+ mca::PipelinePrinter Printer(*P, *Region, RegionIdx, *STI, PO);
// When we output JSON, we add a view that contains the instructions
// and CPU resource information.
- if (PrintJson)
- Printer.addView(
- std::make_unique<mca::InstructionView>(*STI, *IP, Insts, MCPU));
+ if (PrintJson) {
+ auto IV = std::make_unique<mca::InstructionView>(*STI, *IP, Insts);
+ Printer.addView(std::move(IV));
+ }
if (PrintSummaryView)
Printer.addView(
std::make_unique<mca::SummaryView>(SM, Insts, DispatchWidth));
if (EnableBottleneckAnalysis) {
+ if (!IsOutOfOrder) {
+ WithColor::warning()
+ << "bottleneck analysis is not supported for in-order CPU '" << MCPU
+ << "'.\n";
+ }
Printer.addView(std::make_unique<mca::BottleneckAnalysis>(
*STI, *IP, Insts, S.getNumIterations()));
}
@@ -574,12 +662,18 @@ int main(int argc, char **argv) {
if (!runPipeline(*P))
return 1;
- Printer.printReport(TOF->os());
+ if (PrintJson) {
+ Printer.printReport(JSONOutput);
+ } else {
+ Printer.printReport(TOF->os());
+ }
- // Clear the InstrBuilder internal state in preparation for another round.
- IB.clear();
+ ++RegionIdx;
}
+ if (PrintJson)
+ TOF->os() << formatv("{0:2}", json::Value(std::move(JSONOutput))) << "\n";
+
TOF->keep();
return 0;
}