10b57cec5SDimitry Andric //===-- llvm-mca.cpp - Machine Code Analyzer -------------------*- C++ -* -===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This utility is a simple driver that allows static performance analysis on 100b57cec5SDimitry Andric // machine code similarly to how IACA (Intel Architecture Code Analyzer) works. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric // llvm-mca [options] <file-name> 130b57cec5SDimitry Andric // -march <type> 140b57cec5SDimitry Andric // -mcpu <cpu> 150b57cec5SDimitry Andric // -o <file> 160b57cec5SDimitry Andric // 170b57cec5SDimitry Andric // The target defaults to the host target. 180b57cec5SDimitry Andric // The cpu defaults to the 'native' host cpu. 190b57cec5SDimitry Andric // The output defaults to standard output. 200b57cec5SDimitry Andric // 210b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #include "CodeRegion.h" 240b57cec5SDimitry Andric #include "CodeRegionGenerator.h" 250b57cec5SDimitry Andric #include "PipelinePrinter.h" 260b57cec5SDimitry Andric #include "Views/BottleneckAnalysis.h" 270b57cec5SDimitry Andric #include "Views/DispatchStatistics.h" 280b57cec5SDimitry Andric #include "Views/InstructionInfoView.h" 290b57cec5SDimitry Andric #include "Views/RegisterFileStatistics.h" 300b57cec5SDimitry Andric #include "Views/ResourcePressureView.h" 310b57cec5SDimitry Andric #include "Views/RetireControlUnitStatistics.h" 320b57cec5SDimitry Andric #include "Views/SchedulerStatistics.h" 330b57cec5SDimitry Andric #include "Views/SummaryView.h" 340b57cec5SDimitry Andric #include "Views/TimelineView.h" 358bcb0991SDimitry Andric #include "llvm/MC/MCAsmBackend.h" 360b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h" 378bcb0991SDimitry Andric #include "llvm/MC/MCCodeEmitter.h" 380b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 390b57cec5SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h" 400b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h" 418bcb0991SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h" 425ffd83dbSDimitry Andric #include "llvm/MC/MCTargetOptionsCommandFlags.h" 43349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h" 448bcb0991SDimitry Andric #include "llvm/MCA/CodeEmitter.h" 450b57cec5SDimitry Andric #include "llvm/MCA/Context.h" 46fe6060f1SDimitry Andric #include "llvm/MCA/CustomBehaviour.h" 478bcb0991SDimitry Andric #include "llvm/MCA/InstrBuilder.h" 480b57cec5SDimitry Andric #include "llvm/MCA/Pipeline.h" 490b57cec5SDimitry Andric #include "llvm/MCA/Stages/EntryStage.h" 500b57cec5SDimitry Andric #include "llvm/MCA/Stages/InstructionTables.h" 510b57cec5SDimitry Andric #include "llvm/MCA/Support.h" 520b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 530b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 540b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h" 550b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 560b57cec5SDimitry Andric #include "llvm/Support/InitLLVM.h" 570b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 580b57cec5SDimitry Andric #include "llvm/Support/SourceMgr.h" 590b57cec5SDimitry Andric #include "llvm/Support/TargetSelect.h" 600b57cec5SDimitry Andric #include "llvm/Support/ToolOutputFile.h" 610b57cec5SDimitry Andric #include "llvm/Support/WithColor.h" 6206c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h" 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric using namespace llvm; 650b57cec5SDimitry Andric 665ffd83dbSDimitry Andric static mc::RegisterMCTargetOptionsFlags MOF; 675ffd83dbSDimitry Andric 680b57cec5SDimitry Andric static cl::OptionCategory ToolOptions("Tool Options"); 690b57cec5SDimitry Andric static cl::OptionCategory ViewOptions("View Options"); 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric static cl::opt<std::string> InputFilename(cl::Positional, 720b57cec5SDimitry Andric cl::desc("<input file>"), 730b57cec5SDimitry Andric cl::cat(ToolOptions), cl::init("-")); 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"), 760b57cec5SDimitry Andric cl::init("-"), cl::cat(ToolOptions), 770b57cec5SDimitry Andric cl::value_desc("filename")); 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric static cl::opt<std::string> 800b57cec5SDimitry Andric ArchName("march", 810b57cec5SDimitry Andric cl::desc("Target architecture. " 820b57cec5SDimitry Andric "See -version for available targets"), 830b57cec5SDimitry Andric cl::cat(ToolOptions)); 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric static cl::opt<std::string> 860b57cec5SDimitry Andric TripleName("mtriple", 870b57cec5SDimitry Andric cl::desc("Target triple. See -version for available targets"), 880b57cec5SDimitry Andric cl::cat(ToolOptions)); 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric static cl::opt<std::string> 910b57cec5SDimitry Andric MCPU("mcpu", 920b57cec5SDimitry Andric cl::desc("Target a specific cpu type (-mcpu=help for details)"), 930b57cec5SDimitry Andric cl::value_desc("cpu-name"), cl::cat(ToolOptions), cl::init("native")); 940b57cec5SDimitry Andric 95753f127fSDimitry Andric static cl::list<std::string> 96753f127fSDimitry Andric MATTRS("mattr", cl::CommaSeparated, 97753f127fSDimitry Andric cl::desc("Target specific attributes (-mattr=help for details)"), 98753f127fSDimitry Andric cl::value_desc("a1,+a2,-a3,..."), cl::cat(ToolOptions)); 998bcb0991SDimitry Andric 100fe6060f1SDimitry Andric static cl::opt<bool> PrintJson("json", 101e8d8bef9SDimitry Andric cl::desc("Print the output in json format"), 102e8d8bef9SDimitry Andric cl::cat(ToolOptions), cl::init(false)); 103e8d8bef9SDimitry Andric 1040b57cec5SDimitry Andric static cl::opt<int> 1050b57cec5SDimitry Andric OutputAsmVariant("output-asm-variant", 1060b57cec5SDimitry Andric cl::desc("Syntax variant to use for output printing"), 1070b57cec5SDimitry Andric cl::cat(ToolOptions), cl::init(-1)); 1080b57cec5SDimitry Andric 1098bcb0991SDimitry Andric static cl::opt<bool> 1108bcb0991SDimitry Andric PrintImmHex("print-imm-hex", cl::cat(ToolOptions), cl::init(false), 1118bcb0991SDimitry Andric cl::desc("Prefer hex format when printing immediate values")); 1128bcb0991SDimitry Andric 1130b57cec5SDimitry Andric static cl::opt<unsigned> Iterations("iterations", 1140b57cec5SDimitry Andric cl::desc("Number of iterations to run"), 1150b57cec5SDimitry Andric cl::cat(ToolOptions), cl::init(0)); 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric static cl::opt<unsigned> 1180b57cec5SDimitry Andric DispatchWidth("dispatch", cl::desc("Override the processor dispatch width"), 1190b57cec5SDimitry Andric cl::cat(ToolOptions), cl::init(0)); 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric static cl::opt<unsigned> 1220b57cec5SDimitry Andric RegisterFileSize("register-file-size", 1230b57cec5SDimitry Andric cl::desc("Maximum number of physical registers which can " 1240b57cec5SDimitry Andric "be used for register mappings"), 1250b57cec5SDimitry Andric cl::cat(ToolOptions), cl::init(0)); 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric static cl::opt<unsigned> 1280b57cec5SDimitry Andric MicroOpQueue("micro-op-queue-size", cl::Hidden, 1290b57cec5SDimitry Andric cl::desc("Number of entries in the micro-op queue"), 1300b57cec5SDimitry Andric cl::cat(ToolOptions), cl::init(0)); 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric static cl::opt<unsigned> 1330b57cec5SDimitry Andric DecoderThroughput("decoder-throughput", cl::Hidden, 1340b57cec5SDimitry Andric cl::desc("Maximum throughput from the decoders " 1350b57cec5SDimitry Andric "(instructions per cycle)"), 1360b57cec5SDimitry Andric cl::cat(ToolOptions), cl::init(0)); 1370b57cec5SDimitry Andric 138*0fca6ea1SDimitry Andric static cl::opt<unsigned> 139*0fca6ea1SDimitry Andric CallLatency("call-latency", cl::Hidden, 140*0fca6ea1SDimitry Andric cl::desc("Number of cycles to assume for a call instruction"), 141*0fca6ea1SDimitry Andric cl::cat(ToolOptions), cl::init(100U)); 142*0fca6ea1SDimitry Andric 143*0fca6ea1SDimitry Andric enum class SkipType { NONE, LACK_SCHED, PARSE_FAILURE, ANY_FAILURE }; 144*0fca6ea1SDimitry Andric 145*0fca6ea1SDimitry Andric static cl::opt<enum SkipType> SkipUnsupportedInstructions( 146*0fca6ea1SDimitry Andric "skip-unsupported-instructions", 147*0fca6ea1SDimitry Andric cl::desc("Force analysis to continue in the presence of unsupported " 148*0fca6ea1SDimitry Andric "instructions"), 149*0fca6ea1SDimitry Andric cl::values( 150*0fca6ea1SDimitry Andric clEnumValN(SkipType::NONE, "none", 151*0fca6ea1SDimitry Andric "Exit with an error when an instruction is unsupported for " 152*0fca6ea1SDimitry Andric "any reason (default)"), 153*0fca6ea1SDimitry Andric clEnumValN( 154*0fca6ea1SDimitry Andric SkipType::LACK_SCHED, "lack-sched", 155*0fca6ea1SDimitry Andric "Skip instructions on input which lack scheduling information"), 156*0fca6ea1SDimitry Andric clEnumValN( 157*0fca6ea1SDimitry Andric SkipType::PARSE_FAILURE, "parse-failure", 158*0fca6ea1SDimitry Andric "Skip lines on the input which fail to parse for any reason"), 159*0fca6ea1SDimitry Andric clEnumValN(SkipType::ANY_FAILURE, "any", 160*0fca6ea1SDimitry Andric "Skip instructions or lines on input which are unsupported " 161*0fca6ea1SDimitry Andric "for any reason")), 162*0fca6ea1SDimitry Andric cl::init(SkipType::NONE), cl::cat(ViewOptions)); 163*0fca6ea1SDimitry Andric 164*0fca6ea1SDimitry Andric bool shouldSkip(enum SkipType skipType) { 165*0fca6ea1SDimitry Andric if (SkipUnsupportedInstructions == SkipType::NONE) 166*0fca6ea1SDimitry Andric return false; 167*0fca6ea1SDimitry Andric if (SkipUnsupportedInstructions == SkipType::ANY_FAILURE) 168*0fca6ea1SDimitry Andric return true; 169*0fca6ea1SDimitry Andric return skipType == SkipUnsupportedInstructions; 170*0fca6ea1SDimitry Andric } 171*0fca6ea1SDimitry Andric 1720b57cec5SDimitry Andric static cl::opt<bool> 1730b57cec5SDimitry Andric PrintRegisterFileStats("register-file-stats", 1740b57cec5SDimitry Andric cl::desc("Print register file statistics"), 1750b57cec5SDimitry Andric cl::cat(ViewOptions), cl::init(false)); 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric static cl::opt<bool> PrintDispatchStats("dispatch-stats", 1780b57cec5SDimitry Andric cl::desc("Print dispatch statistics"), 1790b57cec5SDimitry Andric cl::cat(ViewOptions), cl::init(false)); 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric static cl::opt<bool> 1820b57cec5SDimitry Andric PrintSummaryView("summary-view", cl::Hidden, 1830b57cec5SDimitry Andric cl::desc("Print summary view (enabled by default)"), 1840b57cec5SDimitry Andric cl::cat(ViewOptions), cl::init(true)); 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric static cl::opt<bool> PrintSchedulerStats("scheduler-stats", 1870b57cec5SDimitry Andric cl::desc("Print scheduler statistics"), 1880b57cec5SDimitry Andric cl::cat(ViewOptions), cl::init(false)); 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric static cl::opt<bool> 1910b57cec5SDimitry Andric PrintRetireStats("retire-stats", 1920b57cec5SDimitry Andric cl::desc("Print retire control unit statistics"), 1930b57cec5SDimitry Andric cl::cat(ViewOptions), cl::init(false)); 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric static cl::opt<bool> PrintResourcePressureView( 1960b57cec5SDimitry Andric "resource-pressure", 1970b57cec5SDimitry Andric cl::desc("Print the resource pressure view (enabled by default)"), 1980b57cec5SDimitry Andric cl::cat(ViewOptions), cl::init(true)); 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric static cl::opt<bool> PrintTimelineView("timeline", 2010b57cec5SDimitry Andric cl::desc("Print the timeline view"), 2020b57cec5SDimitry Andric cl::cat(ViewOptions), cl::init(false)); 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric static cl::opt<unsigned> TimelineMaxIterations( 2050b57cec5SDimitry Andric "timeline-max-iterations", 2060b57cec5SDimitry Andric cl::desc("Maximum number of iterations to print in timeline view"), 2070b57cec5SDimitry Andric cl::cat(ViewOptions), cl::init(0)); 2080b57cec5SDimitry Andric 209fe6060f1SDimitry Andric static cl::opt<unsigned> 210fe6060f1SDimitry Andric TimelineMaxCycles("timeline-max-cycles", 211fe6060f1SDimitry Andric cl::desc("Maximum number of cycles in the timeline view, " 212fe6060f1SDimitry Andric "or 0 for unlimited. Defaults to 80 cycles"), 2130b57cec5SDimitry Andric cl::cat(ViewOptions), cl::init(80)); 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric static cl::opt<bool> 2160b57cec5SDimitry Andric AssumeNoAlias("noalias", 2170b57cec5SDimitry Andric cl::desc("If set, assume that loads and stores do not alias"), 2180b57cec5SDimitry Andric cl::cat(ToolOptions), cl::init(true)); 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric static cl::opt<unsigned> LoadQueueSize("lqueue", 2210b57cec5SDimitry Andric cl::desc("Size of the load queue"), 2220b57cec5SDimitry Andric cl::cat(ToolOptions), cl::init(0)); 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric static cl::opt<unsigned> StoreQueueSize("squeue", 2250b57cec5SDimitry Andric cl::desc("Size of the store queue"), 2260b57cec5SDimitry Andric cl::cat(ToolOptions), cl::init(0)); 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric static cl::opt<bool> 2290b57cec5SDimitry Andric PrintInstructionTables("instruction-tables", 2300b57cec5SDimitry Andric cl::desc("Print instruction tables"), 2310b57cec5SDimitry Andric cl::cat(ToolOptions), cl::init(false)); 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric static cl::opt<bool> PrintInstructionInfoView( 2340b57cec5SDimitry Andric "instruction-info", 2350b57cec5SDimitry Andric cl::desc("Print the instruction info view (enabled by default)"), 2360b57cec5SDimitry Andric cl::cat(ViewOptions), cl::init(true)); 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric static cl::opt<bool> EnableAllStats("all-stats", 2390b57cec5SDimitry Andric cl::desc("Print all hardware statistics"), 2400b57cec5SDimitry Andric cl::cat(ViewOptions), cl::init(false)); 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric static cl::opt<bool> 2430b57cec5SDimitry Andric EnableAllViews("all-views", 2440b57cec5SDimitry Andric cl::desc("Print all views including hardware statistics"), 2450b57cec5SDimitry Andric cl::cat(ViewOptions), cl::init(false)); 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric static cl::opt<bool> EnableBottleneckAnalysis( 2480b57cec5SDimitry Andric "bottleneck-analysis", 2490b57cec5SDimitry Andric cl::desc("Enable bottleneck analysis (disabled by default)"), 2500b57cec5SDimitry Andric cl::cat(ViewOptions), cl::init(false)); 2510b57cec5SDimitry Andric 2528bcb0991SDimitry Andric static cl::opt<bool> ShowEncoding( 2538bcb0991SDimitry Andric "show-encoding", 2548bcb0991SDimitry Andric cl::desc("Print encoding information in the instruction info view"), 2558bcb0991SDimitry Andric cl::cat(ViewOptions), cl::init(false)); 2568bcb0991SDimitry Andric 25704eeddc0SDimitry Andric static cl::opt<bool> ShowBarriers( 25804eeddc0SDimitry Andric "show-barriers", 25904eeddc0SDimitry Andric cl::desc("Print memory barrier information in the instruction info view"), 26004eeddc0SDimitry Andric cl::cat(ViewOptions), cl::init(false)); 26104eeddc0SDimitry Andric 262fe6060f1SDimitry Andric static cl::opt<bool> DisableCustomBehaviour( 263fe6060f1SDimitry Andric "disable-cb", 264fe6060f1SDimitry Andric cl::desc( 265fe6060f1SDimitry Andric "Disable custom behaviour (use the default class which does nothing)."), 266fe6060f1SDimitry Andric cl::cat(ViewOptions), cl::init(false)); 267fe6060f1SDimitry Andric 268bdd1243dSDimitry Andric static cl::opt<bool> DisableInstrumentManager( 269bdd1243dSDimitry Andric "disable-im", 270bdd1243dSDimitry Andric cl::desc("Disable instrumentation manager (use the default class which " 271bdd1243dSDimitry Andric "ignores instruments.)."), 272bdd1243dSDimitry Andric cl::cat(ViewOptions), cl::init(false)); 273bdd1243dSDimitry Andric 2740b57cec5SDimitry Andric namespace { 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric const Target *getTarget(const char *ProgName) { 2770b57cec5SDimitry Andric if (TripleName.empty()) 2780b57cec5SDimitry Andric TripleName = Triple::normalize(sys::getDefaultTargetTriple()); 2790b57cec5SDimitry Andric Triple TheTriple(TripleName); 2800b57cec5SDimitry Andric 2810b57cec5SDimitry Andric // Get the target specific parser. 2820b57cec5SDimitry Andric std::string Error; 2830b57cec5SDimitry Andric const Target *TheTarget = 2840b57cec5SDimitry Andric TargetRegistry::lookupTarget(ArchName, TheTriple, Error); 2850b57cec5SDimitry Andric if (!TheTarget) { 2860b57cec5SDimitry Andric errs() << ProgName << ": " << Error; 2870b57cec5SDimitry Andric return nullptr; 2880b57cec5SDimitry Andric } 2890b57cec5SDimitry Andric 290fe6060f1SDimitry Andric // Update TripleName with the updated triple from the target lookup. 291fe6060f1SDimitry Andric TripleName = TheTriple.str(); 292fe6060f1SDimitry Andric 2930b57cec5SDimitry Andric // Return the found target. 2940b57cec5SDimitry Andric return TheTarget; 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric ErrorOr<std::unique_ptr<ToolOutputFile>> getOutputStream() { 2980b57cec5SDimitry Andric if (OutputFilename == "") 2990b57cec5SDimitry Andric OutputFilename = "-"; 3000b57cec5SDimitry Andric std::error_code EC; 301fe6060f1SDimitry Andric auto Out = std::make_unique<ToolOutputFile>(OutputFilename, EC, 302fe6060f1SDimitry Andric sys::fs::OF_TextWithCRLF); 3030b57cec5SDimitry Andric if (!EC) 3040b57cec5SDimitry Andric return std::move(Out); 3050b57cec5SDimitry Andric return EC; 3060b57cec5SDimitry Andric } 3070b57cec5SDimitry Andric } // end of anonymous namespace 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric static void processOptionImpl(cl::opt<bool> &O, const cl::opt<bool> &Default) { 3100b57cec5SDimitry Andric if (!O.getNumOccurrences() || O.getPosition() < Default.getPosition()) 3110b57cec5SDimitry Andric O = Default.getValue(); 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric 314fe6060f1SDimitry Andric static void processViewOptions(bool IsOutOfOrder) { 3150b57cec5SDimitry Andric if (!EnableAllViews.getNumOccurrences() && 3160b57cec5SDimitry Andric !EnableAllStats.getNumOccurrences()) 3170b57cec5SDimitry Andric return; 3180b57cec5SDimitry Andric 3190b57cec5SDimitry Andric if (EnableAllViews.getNumOccurrences()) { 3200b57cec5SDimitry Andric processOptionImpl(PrintSummaryView, EnableAllViews); 321fe6060f1SDimitry Andric if (IsOutOfOrder) 3220b57cec5SDimitry Andric processOptionImpl(EnableBottleneckAnalysis, EnableAllViews); 3230b57cec5SDimitry Andric processOptionImpl(PrintResourcePressureView, EnableAllViews); 3240b57cec5SDimitry Andric processOptionImpl(PrintTimelineView, EnableAllViews); 3250b57cec5SDimitry Andric processOptionImpl(PrintInstructionInfoView, EnableAllViews); 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric const cl::opt<bool> &Default = 3290b57cec5SDimitry Andric EnableAllViews.getPosition() < EnableAllStats.getPosition() 3300b57cec5SDimitry Andric ? EnableAllStats 3310b57cec5SDimitry Andric : EnableAllViews; 3320b57cec5SDimitry Andric processOptionImpl(PrintRegisterFileStats, Default); 3330b57cec5SDimitry Andric processOptionImpl(PrintDispatchStats, Default); 3340b57cec5SDimitry Andric processOptionImpl(PrintSchedulerStats, Default); 335fe6060f1SDimitry Andric if (IsOutOfOrder) 3360b57cec5SDimitry Andric processOptionImpl(PrintRetireStats, Default); 3370b57cec5SDimitry Andric } 3380b57cec5SDimitry Andric 3390b57cec5SDimitry Andric // Returns true on success. 3400b57cec5SDimitry Andric static bool runPipeline(mca::Pipeline &P) { 3410b57cec5SDimitry Andric // Handle pipeline errors here. 3420b57cec5SDimitry Andric Expected<unsigned> Cycles = P.run(); 3430b57cec5SDimitry Andric if (!Cycles) { 3440b57cec5SDimitry Andric WithColor::error() << toString(Cycles.takeError()); 3450b57cec5SDimitry Andric return false; 3460b57cec5SDimitry Andric } 3470b57cec5SDimitry Andric return true; 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric int main(int argc, char **argv) { 3510b57cec5SDimitry Andric InitLLVM X(argc, argv); 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric // Initialize targets and assembly parsers. 3540b57cec5SDimitry Andric InitializeAllTargetInfos(); 3550b57cec5SDimitry Andric InitializeAllTargetMCs(); 3560b57cec5SDimitry Andric InitializeAllAsmParsers(); 357349cc55cSDimitry Andric InitializeAllTargetMCAs(); 3580b57cec5SDimitry Andric 359bdd1243dSDimitry Andric // Register the Target and CPU printer for --version. 360bdd1243dSDimitry Andric cl::AddExtraVersionPrinter(sys::printDefaultTargetAndDetectedCPU); 361bdd1243dSDimitry Andric 3620b57cec5SDimitry Andric // Enable printing of available targets when flag --version is specified. 3630b57cec5SDimitry Andric cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric cl::HideUnrelatedOptions({&ToolOptions, &ViewOptions}); 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric // Parse flags and initialize target options. 3680b57cec5SDimitry Andric cl::ParseCommandLineOptions(argc, argv, 3690b57cec5SDimitry Andric "llvm machine code performance analyzer.\n"); 3700b57cec5SDimitry Andric 3710b57cec5SDimitry Andric // Get the target from the triple. If a triple is not specified, then select 3720b57cec5SDimitry Andric // the default triple for the host. If the triple doesn't correspond to any 3730b57cec5SDimitry Andric // registered target, then exit with an error message. 3740b57cec5SDimitry Andric const char *ProgName = argv[0]; 3750b57cec5SDimitry Andric const Target *TheTarget = getTarget(ProgName); 3760b57cec5SDimitry Andric if (!TheTarget) 3770b57cec5SDimitry Andric return 1; 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric // GetTarget() may replaced TripleName with a default triple. 3800b57cec5SDimitry Andric // For safety, reconstruct the Triple object. 3810b57cec5SDimitry Andric Triple TheTriple(TripleName); 3820b57cec5SDimitry Andric 3830b57cec5SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr = 3840b57cec5SDimitry Andric MemoryBuffer::getFileOrSTDIN(InputFilename); 3850b57cec5SDimitry Andric if (std::error_code EC = BufferPtr.getError()) { 3860b57cec5SDimitry Andric WithColor::error() << InputFilename << ": " << EC.message() << '\n'; 3870b57cec5SDimitry Andric return 1; 3880b57cec5SDimitry Andric } 3890b57cec5SDimitry Andric 390e8d8bef9SDimitry Andric if (MCPU == "native") 3915ffd83dbSDimitry Andric MCPU = std::string(llvm::sys::getHostCPUName()); 3920b57cec5SDimitry Andric 393753f127fSDimitry Andric // Package up features to be passed to target/subtarget 394753f127fSDimitry Andric std::string FeaturesStr; 395753f127fSDimitry Andric if (MATTRS.size()) { 396753f127fSDimitry Andric SubtargetFeatures Features; 397753f127fSDimitry Andric for (std::string &MAttr : MATTRS) 398753f127fSDimitry Andric Features.AddFeature(MAttr); 399753f127fSDimitry Andric FeaturesStr = Features.getString(); 400753f127fSDimitry Andric } 401753f127fSDimitry Andric 4020b57cec5SDimitry Andric std::unique_ptr<MCSubtargetInfo> STI( 403753f127fSDimitry Andric TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr)); 404e8d8bef9SDimitry Andric assert(STI && "Unable to create subtarget info!"); 4050b57cec5SDimitry Andric if (!STI->isCPUStringValid(MCPU)) 4060b57cec5SDimitry Andric return 1; 4070b57cec5SDimitry Andric 4080b57cec5SDimitry Andric if (!STI->getSchedModel().hasInstrSchedModel()) { 4090b57cec5SDimitry Andric WithColor::error() 4100b57cec5SDimitry Andric << "unable to find instruction-level scheduling information for" 4110b57cec5SDimitry Andric << " target triple '" << TheTriple.normalize() << "' and cpu '" << MCPU 4120b57cec5SDimitry Andric << "'.\n"; 4130b57cec5SDimitry Andric 4140b57cec5SDimitry Andric if (STI->getSchedModel().InstrItineraries) 4150b57cec5SDimitry Andric WithColor::note() 4160b57cec5SDimitry Andric << "cpu '" << MCPU << "' provides itineraries. However, " 4170b57cec5SDimitry Andric << "instruction itineraries are currently unsupported.\n"; 4180b57cec5SDimitry Andric return 1; 4190b57cec5SDimitry Andric } 4200b57cec5SDimitry Andric 421fe6060f1SDimitry Andric // Apply overrides to llvm-mca specific options. 4220eae32dcSDimitry Andric bool IsOutOfOrder = STI->getSchedModel().isOutOfOrder(); 423fe6060f1SDimitry Andric processViewOptions(IsOutOfOrder); 424fe6060f1SDimitry Andric 4258bcb0991SDimitry Andric std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); 4268bcb0991SDimitry Andric assert(MRI && "Unable to create target register info!"); 4278bcb0991SDimitry Andric 4285ffd83dbSDimitry Andric MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags(); 429480093f4SDimitry Andric std::unique_ptr<MCAsmInfo> MAI( 430480093f4SDimitry Andric TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); 4318bcb0991SDimitry Andric assert(MAI && "Unable to create target asm info!"); 4328bcb0991SDimitry Andric 4338bcb0991SDimitry Andric SourceMgr SrcMgr; 4348bcb0991SDimitry Andric 4358bcb0991SDimitry Andric // Tell SrcMgr about this buffer, which is what the parser will pick up. 4368bcb0991SDimitry Andric SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc()); 4378bcb0991SDimitry Andric 4388bcb0991SDimitry Andric std::unique_ptr<buffer_ostream> BOS; 4398bcb0991SDimitry Andric 4408bcb0991SDimitry Andric std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); 441e8d8bef9SDimitry Andric assert(MCII && "Unable to create instruction info!"); 4428bcb0991SDimitry Andric 4438bcb0991SDimitry Andric std::unique_ptr<MCInstrAnalysis> MCIA( 4448bcb0991SDimitry Andric TheTarget->createMCInstrAnalysis(MCII.get())); 4458bcb0991SDimitry Andric 446fe6060f1SDimitry Andric // Need to initialize an MCInstPrinter as it is 447fe6060f1SDimitry Andric // required for initializing the MCTargetStreamer 448bdd1243dSDimitry Andric // which needs to happen within the CRG.parseAnalysisRegions() call below. 449fe6060f1SDimitry Andric // Without an MCTargetStreamer, certain assembly directives can trigger a 450fe6060f1SDimitry Andric // segfault. (For example, the .cv_fpo_proc directive on x86 will segfault if 451fe6060f1SDimitry Andric // we don't initialize the MCTargetStreamer.) 452fe6060f1SDimitry Andric unsigned IPtempOutputAsmVariant = 453fe6060f1SDimitry Andric OutputAsmVariant == -1 ? 0 : OutputAsmVariant; 454fe6060f1SDimitry Andric std::unique_ptr<MCInstPrinter> IPtemp(TheTarget->createMCInstPrinter( 455fe6060f1SDimitry Andric Triple(TripleName), IPtempOutputAsmVariant, *MAI, *MCII, *MRI)); 456fe6060f1SDimitry Andric if (!IPtemp) { 457fe6060f1SDimitry Andric WithColor::error() 458fe6060f1SDimitry Andric << "unable to create instruction printer for target triple '" 459fe6060f1SDimitry Andric << TheTriple.normalize() << "' with assembly variant " 460fe6060f1SDimitry Andric << IPtempOutputAsmVariant << ".\n"; 461fe6060f1SDimitry Andric return 1; 462fe6060f1SDimitry Andric } 463fe6060f1SDimitry Andric 4640b57cec5SDimitry Andric // Parse the input and create CodeRegions that llvm-mca can analyze. 4652efbaac7SDimitry Andric MCContext ACtx(TheTriple, MAI.get(), MRI.get(), STI.get(), &SrcMgr); 4662efbaac7SDimitry Andric std::unique_ptr<MCObjectFileInfo> AMOFI( 4672efbaac7SDimitry Andric TheTarget->createMCObjectFileInfo(ACtx, /*PIC=*/false)); 4682efbaac7SDimitry Andric ACtx.setObjectFileInfo(AMOFI.get()); 4692efbaac7SDimitry Andric mca::AsmAnalysisRegionGenerator CRG(*TheTarget, SrcMgr, ACtx, *MAI, *STI, 470bdd1243dSDimitry Andric *MCII); 471bdd1243dSDimitry Andric Expected<const mca::AnalysisRegions &> RegionsOrErr = 472*0fca6ea1SDimitry Andric CRG.parseAnalysisRegions(std::move(IPtemp), 473*0fca6ea1SDimitry Andric shouldSkip(SkipType::PARSE_FAILURE)); 4740b57cec5SDimitry Andric if (!RegionsOrErr) { 4750b57cec5SDimitry Andric if (auto Err = 4760b57cec5SDimitry Andric handleErrors(RegionsOrErr.takeError(), [](const StringError &E) { 4770b57cec5SDimitry Andric WithColor::error() << E.getMessage() << '\n'; 4780b57cec5SDimitry Andric })) { 4790b57cec5SDimitry Andric // Default case. 4800b57cec5SDimitry Andric WithColor::error() << toString(std::move(Err)) << '\n'; 4810b57cec5SDimitry Andric } 4820b57cec5SDimitry Andric return 1; 4830b57cec5SDimitry Andric } 484bdd1243dSDimitry Andric const mca::AnalysisRegions &Regions = *RegionsOrErr; 4850b57cec5SDimitry Andric 4860b57cec5SDimitry Andric // Early exit if errors were found by the code region parsing logic. 4870b57cec5SDimitry Andric if (!Regions.isValid()) 4880b57cec5SDimitry Andric return 1; 4890b57cec5SDimitry Andric 4900b57cec5SDimitry Andric if (Regions.empty()) { 4910b57cec5SDimitry Andric WithColor::error() << "no assembly instructions found.\n"; 4920b57cec5SDimitry Andric return 1; 4930b57cec5SDimitry Andric } 4940b57cec5SDimitry Andric 495bdd1243dSDimitry Andric std::unique_ptr<mca::InstrumentManager> IM; 496bdd1243dSDimitry Andric if (!DisableInstrumentManager) { 497bdd1243dSDimitry Andric IM = std::unique_ptr<mca::InstrumentManager>( 498bdd1243dSDimitry Andric TheTarget->createInstrumentManager(*STI, *MCII)); 499bdd1243dSDimitry Andric } 500bdd1243dSDimitry Andric if (!IM) { 501bdd1243dSDimitry Andric // If the target doesn't have its own IM implemented (or the -disable-cb 502bdd1243dSDimitry Andric // flag is set) then we use the base class (which does nothing). 503bdd1243dSDimitry Andric IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII); 504bdd1243dSDimitry Andric } 505bdd1243dSDimitry Andric 506bdd1243dSDimitry Andric // Parse the input and create InstrumentRegion that llvm-mca 507bdd1243dSDimitry Andric // can use to improve analysis. 5082efbaac7SDimitry Andric MCContext ICtx(TheTriple, MAI.get(), MRI.get(), STI.get(), &SrcMgr); 5092efbaac7SDimitry Andric std::unique_ptr<MCObjectFileInfo> IMOFI( 5102efbaac7SDimitry Andric TheTarget->createMCObjectFileInfo(ICtx, /*PIC=*/false)); 5112efbaac7SDimitry Andric ICtx.setObjectFileInfo(IMOFI.get()); 5122efbaac7SDimitry Andric mca::AsmInstrumentRegionGenerator IRG(*TheTarget, SrcMgr, ICtx, *MAI, *STI, 513bdd1243dSDimitry Andric *MCII, *IM); 514bdd1243dSDimitry Andric Expected<const mca::InstrumentRegions &> InstrumentRegionsOrErr = 515*0fca6ea1SDimitry Andric IRG.parseInstrumentRegions(std::move(IPtemp), 516*0fca6ea1SDimitry Andric shouldSkip(SkipType::PARSE_FAILURE)); 517bdd1243dSDimitry Andric if (!InstrumentRegionsOrErr) { 518bdd1243dSDimitry Andric if (auto Err = handleErrors(InstrumentRegionsOrErr.takeError(), 519bdd1243dSDimitry Andric [](const StringError &E) { 520bdd1243dSDimitry Andric WithColor::error() << E.getMessage() << '\n'; 521bdd1243dSDimitry Andric })) { 522bdd1243dSDimitry Andric // Default case. 523bdd1243dSDimitry Andric WithColor::error() << toString(std::move(Err)) << '\n'; 524bdd1243dSDimitry Andric } 525bdd1243dSDimitry Andric return 1; 526bdd1243dSDimitry Andric } 527bdd1243dSDimitry Andric const mca::InstrumentRegions &InstrumentRegions = *InstrumentRegionsOrErr; 528bdd1243dSDimitry Andric 529bdd1243dSDimitry Andric // Early exit if errors were found by the instrumentation parsing logic. 530bdd1243dSDimitry Andric if (!InstrumentRegions.isValid()) 531bdd1243dSDimitry Andric return 1; 532bdd1243dSDimitry Andric 5330b57cec5SDimitry Andric // Now initialize the output file. 5340b57cec5SDimitry Andric auto OF = getOutputStream(); 5350b57cec5SDimitry Andric if (std::error_code EC = OF.getError()) { 5360b57cec5SDimitry Andric WithColor::error() << EC.message() << '\n'; 5370b57cec5SDimitry Andric return 1; 5380b57cec5SDimitry Andric } 5390b57cec5SDimitry Andric 5400b57cec5SDimitry Andric unsigned AssemblerDialect = CRG.getAssemblerDialect(); 5410b57cec5SDimitry Andric if (OutputAsmVariant >= 0) 5420b57cec5SDimitry Andric AssemblerDialect = static_cast<unsigned>(OutputAsmVariant); 5430b57cec5SDimitry Andric std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( 5440b57cec5SDimitry Andric Triple(TripleName), AssemblerDialect, *MAI, *MCII, *MRI)); 5450b57cec5SDimitry Andric if (!IP) { 5460b57cec5SDimitry Andric WithColor::error() 5470b57cec5SDimitry Andric << "unable to create instruction printer for target triple '" 5480b57cec5SDimitry Andric << TheTriple.normalize() << "' with assembly variant " 5490b57cec5SDimitry Andric << AssemblerDialect << ".\n"; 5500b57cec5SDimitry Andric return 1; 5510b57cec5SDimitry Andric } 5520b57cec5SDimitry Andric 5538bcb0991SDimitry Andric // Set the display preference for hex vs. decimal immediates. 5548bcb0991SDimitry Andric IP->setPrintImmHex(PrintImmHex); 5558bcb0991SDimitry Andric 5560b57cec5SDimitry Andric std::unique_ptr<ToolOutputFile> TOF = std::move(*OF); 5570b57cec5SDimitry Andric 5580b57cec5SDimitry Andric const MCSchedModel &SM = STI->getSchedModel(); 5590b57cec5SDimitry Andric 56081ad6265SDimitry Andric std::unique_ptr<mca::InstrPostProcess> IPP; 56181ad6265SDimitry Andric if (!DisableCustomBehaviour) { 56281ad6265SDimitry Andric // TODO: It may be a good idea to separate CB and IPP so that they can 56381ad6265SDimitry Andric // be used independently of each other. What I mean by this is to add 56481ad6265SDimitry Andric // an extra command-line arg --disable-ipp so that CB and IPP can be 56581ad6265SDimitry Andric // toggled without needing to toggle both of them together. 56681ad6265SDimitry Andric IPP = std::unique_ptr<mca::InstrPostProcess>( 56781ad6265SDimitry Andric TheTarget->createInstrPostProcess(*STI, *MCII)); 56881ad6265SDimitry Andric } 56981ad6265SDimitry Andric if (!IPP) { 57081ad6265SDimitry Andric // If the target doesn't have its own IPP implemented (or the -disable-cb 57181ad6265SDimitry Andric // flag is set) then we use the base class (which does nothing). 57281ad6265SDimitry Andric IPP = std::make_unique<mca::InstrPostProcess>(*STI, *MCII); 57381ad6265SDimitry Andric } 57481ad6265SDimitry Andric 5750b57cec5SDimitry Andric // Create an instruction builder. 576*0fca6ea1SDimitry Andric mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get(), *IM, CallLatency); 5770b57cec5SDimitry Andric 5780b57cec5SDimitry Andric // Create a context to control ownership of the pipeline hardware. 5790b57cec5SDimitry Andric mca::Context MCA(*MRI, *STI); 5800b57cec5SDimitry Andric 5810b57cec5SDimitry Andric mca::PipelineOptions PO(MicroOpQueue, DecoderThroughput, DispatchWidth, 5820b57cec5SDimitry Andric RegisterFileSize, LoadQueueSize, StoreQueueSize, 5830b57cec5SDimitry Andric AssumeNoAlias, EnableBottleneckAnalysis); 5840b57cec5SDimitry Andric 5850b57cec5SDimitry Andric // Number each region in the sequence. 5860b57cec5SDimitry Andric unsigned RegionIdx = 0; 5870b57cec5SDimitry Andric 5888bcb0991SDimitry Andric std::unique_ptr<MCCodeEmitter> MCE( 5892efbaac7SDimitry Andric TheTarget->createMCCodeEmitter(*MCII, ACtx)); 590e8d8bef9SDimitry Andric assert(MCE && "Unable to create code emitter!"); 5918bcb0991SDimitry Andric 5928bcb0991SDimitry Andric std::unique_ptr<MCAsmBackend> MAB(TheTarget->createMCAsmBackend( 5935ffd83dbSDimitry Andric *STI, *MRI, mc::InitMCTargetOptionsFromFlags())); 594e8d8bef9SDimitry Andric assert(MAB && "Unable to create asm backend!"); 5958bcb0991SDimitry Andric 596fe6060f1SDimitry Andric json::Object JSONOutput; 597*0fca6ea1SDimitry Andric int NonEmptyRegions = 0; 598bdd1243dSDimitry Andric for (const std::unique_ptr<mca::AnalysisRegion> &Region : Regions) { 5990b57cec5SDimitry Andric // Skip empty code regions. 6000b57cec5SDimitry Andric if (Region->empty()) 6010b57cec5SDimitry Andric continue; 6020b57cec5SDimitry Andric 603fe6060f1SDimitry Andric IB.clear(); 6040b57cec5SDimitry Andric 6050b57cec5SDimitry Andric // Lower the MCInst sequence into an mca::Instruction sequence. 6060b57cec5SDimitry Andric ArrayRef<MCInst> Insts = Region->getInstructions(); 6078bcb0991SDimitry Andric mca::CodeEmitter CE(*STI, *MAB, *MCE, Insts); 608349cc55cSDimitry Andric 60981ad6265SDimitry Andric IPP->resetState(); 610349cc55cSDimitry Andric 611*0fca6ea1SDimitry Andric DenseMap<const MCInst *, SmallVector<mca::Instrument *>> InstToInstruments; 61204eeddc0SDimitry Andric SmallVector<std::unique_ptr<mca::Instruction>> LoweredSequence; 613*0fca6ea1SDimitry Andric SmallPtrSet<const MCInst *, 16> DroppedInsts; 6140b57cec5SDimitry Andric for (const MCInst &MCI : Insts) { 615bdd1243dSDimitry Andric SMLoc Loc = MCI.getLoc(); 61606c3fb27SDimitry Andric const SmallVector<mca::Instrument *> Instruments = 617bdd1243dSDimitry Andric InstrumentRegions.getActiveInstruments(Loc); 618bdd1243dSDimitry Andric 6190b57cec5SDimitry Andric Expected<std::unique_ptr<mca::Instruction>> Inst = 620bdd1243dSDimitry Andric IB.createInstruction(MCI, Instruments); 6210b57cec5SDimitry Andric if (!Inst) { 6220b57cec5SDimitry Andric if (auto NewE = handleErrors( 6230b57cec5SDimitry Andric Inst.takeError(), 6240b57cec5SDimitry Andric [&IP, &STI](const mca::InstructionError<MCInst> &IE) { 6250b57cec5SDimitry Andric std::string InstructionStr; 6260b57cec5SDimitry Andric raw_string_ostream SS(InstructionStr); 627*0fca6ea1SDimitry Andric if (shouldSkip(SkipType::LACK_SCHED)) 628*0fca6ea1SDimitry Andric WithColor::warning() 629*0fca6ea1SDimitry Andric << IE.Message 630*0fca6ea1SDimitry Andric << ", skipping with -skip-unsupported-instructions, " 631*0fca6ea1SDimitry Andric "note accuracy will be impacted:\n"; 632*0fca6ea1SDimitry Andric else 633*0fca6ea1SDimitry Andric WithColor::error() 634*0fca6ea1SDimitry Andric << IE.Message 635*0fca6ea1SDimitry Andric << ", use -skip-unsupported-instructions=lack-sched to " 636*0fca6ea1SDimitry Andric "ignore these on the input.\n"; 637480093f4SDimitry Andric IP->printInst(&IE.Inst, 0, "", *STI, SS); 6380b57cec5SDimitry Andric SS.flush(); 6390b57cec5SDimitry Andric WithColor::note() 6400b57cec5SDimitry Andric << "instruction: " << InstructionStr << '\n'; 6410b57cec5SDimitry Andric })) { 6420b57cec5SDimitry Andric // Default case. 6430b57cec5SDimitry Andric WithColor::error() << toString(std::move(NewE)); 6440b57cec5SDimitry Andric } 645*0fca6ea1SDimitry Andric if (shouldSkip(SkipType::LACK_SCHED)) { 646*0fca6ea1SDimitry Andric DroppedInsts.insert(&MCI); 647*0fca6ea1SDimitry Andric continue; 648*0fca6ea1SDimitry Andric } 6490b57cec5SDimitry Andric return 1; 6500b57cec5SDimitry Andric } 6510b57cec5SDimitry Andric 652fe6060f1SDimitry Andric IPP->postProcessInstruction(Inst.get(), MCI); 653*0fca6ea1SDimitry Andric InstToInstruments.insert({&MCI, Instruments}); 6540b57cec5SDimitry Andric LoweredSequence.emplace_back(std::move(Inst.get())); 6550b57cec5SDimitry Andric } 6560b57cec5SDimitry Andric 657*0fca6ea1SDimitry Andric Insts = Region->dropInstructions(DroppedInsts); 658*0fca6ea1SDimitry Andric 659*0fca6ea1SDimitry Andric // Skip empty regions. 660*0fca6ea1SDimitry Andric if (Insts.empty()) 661*0fca6ea1SDimitry Andric continue; 662*0fca6ea1SDimitry Andric NonEmptyRegions++; 663*0fca6ea1SDimitry Andric 66481ad6265SDimitry Andric mca::CircularSourceMgr S(LoweredSequence, 66581ad6265SDimitry Andric PrintInstructionTables ? 1 : Iterations); 6660b57cec5SDimitry Andric 6670b57cec5SDimitry Andric if (PrintInstructionTables) { 6680b57cec5SDimitry Andric // Create a pipeline, stages, and a printer. 6698bcb0991SDimitry Andric auto P = std::make_unique<mca::Pipeline>(); 6708bcb0991SDimitry Andric P->appendStage(std::make_unique<mca::EntryStage>(S)); 6718bcb0991SDimitry Andric P->appendStage(std::make_unique<mca::InstructionTables>(SM)); 672fe6060f1SDimitry Andric 673fe6060f1SDimitry Andric mca::PipelinePrinter Printer(*P, *Region, RegionIdx, *STI, PO); 674fe6060f1SDimitry Andric if (PrintJson) { 675fe6060f1SDimitry Andric Printer.addView( 676fe6060f1SDimitry Andric std::make_unique<mca::InstructionView>(*STI, *IP, Insts)); 677fe6060f1SDimitry Andric } 6780b57cec5SDimitry Andric 6790b57cec5SDimitry Andric // Create the views for this pipeline, execute, and emit a report. 6800b57cec5SDimitry Andric if (PrintInstructionInfoView) { 6818bcb0991SDimitry Andric Printer.addView(std::make_unique<mca::InstructionInfoView>( 68204eeddc0SDimitry Andric *STI, *MCII, CE, ShowEncoding, Insts, *IP, LoweredSequence, 68306c3fb27SDimitry Andric ShowBarriers, *IM, InstToInstruments)); 6840b57cec5SDimitry Andric } 6850b57cec5SDimitry Andric Printer.addView( 6868bcb0991SDimitry Andric std::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts)); 6870b57cec5SDimitry Andric 6880b57cec5SDimitry Andric if (!runPipeline(*P)) 6890b57cec5SDimitry Andric return 1; 6900b57cec5SDimitry Andric 691fe6060f1SDimitry Andric if (PrintJson) { 692fe6060f1SDimitry Andric Printer.printReport(JSONOutput); 693fe6060f1SDimitry Andric } else { 6940b57cec5SDimitry Andric Printer.printReport(TOF->os()); 695fe6060f1SDimitry Andric } 696fe6060f1SDimitry Andric 697fe6060f1SDimitry Andric ++RegionIdx; 6980b57cec5SDimitry Andric continue; 6990b57cec5SDimitry Andric } 7000b57cec5SDimitry Andric 701fe6060f1SDimitry Andric // Create the CustomBehaviour object for enforcing Target Specific 702fe6060f1SDimitry Andric // behaviours and dependencies that aren't expressed well enough 703fe6060f1SDimitry Andric // in the tablegen. CB cannot depend on the list of MCInst or 704fe6060f1SDimitry Andric // the source code (but it can depend on the list of 705fe6060f1SDimitry Andric // mca::Instruction or any objects that can be reconstructed 706fe6060f1SDimitry Andric // from the target information). 707349cc55cSDimitry Andric std::unique_ptr<mca::CustomBehaviour> CB; 708349cc55cSDimitry Andric if (!DisableCustomBehaviour) 709349cc55cSDimitry Andric CB = std::unique_ptr<mca::CustomBehaviour>( 710349cc55cSDimitry Andric TheTarget->createCustomBehaviour(*STI, S, *MCII)); 711349cc55cSDimitry Andric if (!CB) 712349cc55cSDimitry Andric // If the target doesn't have its own CB implemented (or the -disable-cb 713349cc55cSDimitry Andric // flag is set) then we use the base class (which does nothing). 714349cc55cSDimitry Andric CB = std::make_unique<mca::CustomBehaviour>(*STI, S, *MCII); 715fe6060f1SDimitry Andric 7160b57cec5SDimitry Andric // Create a basic pipeline simulating an out-of-order backend. 717fe6060f1SDimitry Andric auto P = MCA.createDefaultPipeline(PO, S, *CB); 718fe6060f1SDimitry Andric 719fe6060f1SDimitry Andric mca::PipelinePrinter Printer(*P, *Region, RegionIdx, *STI, PO); 720e8d8bef9SDimitry Andric 721349cc55cSDimitry Andric // Targets can define their own custom Views that exist within their 722349cc55cSDimitry Andric // /lib/Target/ directory so that the View can utilize their CustomBehaviour 723349cc55cSDimitry Andric // or other backend symbols / functionality that are not already exposed 724349cc55cSDimitry Andric // through one of the MC-layer classes. These Views will be initialized 725349cc55cSDimitry Andric // using the CustomBehaviour::getViews() variants. 726349cc55cSDimitry Andric // If a target makes a custom View that does not depend on their target 727349cc55cSDimitry Andric // CB or their backend, they should put the View within 728349cc55cSDimitry Andric // /tools/llvm-mca/Views/ instead. 729349cc55cSDimitry Andric if (!DisableCustomBehaviour) { 730349cc55cSDimitry Andric std::vector<std::unique_ptr<mca::View>> CBViews = 731349cc55cSDimitry Andric CB->getStartViews(*IP, Insts); 732349cc55cSDimitry Andric for (auto &CBView : CBViews) 733349cc55cSDimitry Andric Printer.addView(std::move(CBView)); 734349cc55cSDimitry Andric } 735349cc55cSDimitry Andric 736e8d8bef9SDimitry Andric // When we output JSON, we add a view that contains the instructions 737e8d8bef9SDimitry Andric // and CPU resource information. 738fe6060f1SDimitry Andric if (PrintJson) { 739fe6060f1SDimitry Andric auto IV = std::make_unique<mca::InstructionView>(*STI, *IP, Insts); 740fe6060f1SDimitry Andric Printer.addView(std::move(IV)); 741fe6060f1SDimitry Andric } 7420b57cec5SDimitry Andric 7430b57cec5SDimitry Andric if (PrintSummaryView) 7440b57cec5SDimitry Andric Printer.addView( 7458bcb0991SDimitry Andric std::make_unique<mca::SummaryView>(SM, Insts, DispatchWidth)); 7460b57cec5SDimitry Andric 7470b57cec5SDimitry Andric if (EnableBottleneckAnalysis) { 748fe6060f1SDimitry Andric if (!IsOutOfOrder) { 749fe6060f1SDimitry Andric WithColor::warning() 750fe6060f1SDimitry Andric << "bottleneck analysis is not supported for in-order CPU '" << MCPU 751fe6060f1SDimitry Andric << "'.\n"; 752fe6060f1SDimitry Andric } 7538bcb0991SDimitry Andric Printer.addView(std::make_unique<mca::BottleneckAnalysis>( 7540b57cec5SDimitry Andric *STI, *IP, Insts, S.getNumIterations())); 7550b57cec5SDimitry Andric } 7560b57cec5SDimitry Andric 7570b57cec5SDimitry Andric if (PrintInstructionInfoView) 7588bcb0991SDimitry Andric Printer.addView(std::make_unique<mca::InstructionInfoView>( 75904eeddc0SDimitry Andric *STI, *MCII, CE, ShowEncoding, Insts, *IP, LoweredSequence, 76006c3fb27SDimitry Andric ShowBarriers, *IM, InstToInstruments)); 7610b57cec5SDimitry Andric 762349cc55cSDimitry Andric // Fetch custom Views that are to be placed after the InstructionInfoView. 763349cc55cSDimitry Andric // Refer to the comment paired with the CB->getStartViews(*IP, Insts); line 764349cc55cSDimitry Andric // for more info. 765349cc55cSDimitry Andric if (!DisableCustomBehaviour) { 766349cc55cSDimitry Andric std::vector<std::unique_ptr<mca::View>> CBViews = 767349cc55cSDimitry Andric CB->getPostInstrInfoViews(*IP, Insts); 768349cc55cSDimitry Andric for (auto &CBView : CBViews) 769349cc55cSDimitry Andric Printer.addView(std::move(CBView)); 770349cc55cSDimitry Andric } 771349cc55cSDimitry Andric 7720b57cec5SDimitry Andric if (PrintDispatchStats) 7738bcb0991SDimitry Andric Printer.addView(std::make_unique<mca::DispatchStatistics>()); 7740b57cec5SDimitry Andric 7750b57cec5SDimitry Andric if (PrintSchedulerStats) 7768bcb0991SDimitry Andric Printer.addView(std::make_unique<mca::SchedulerStatistics>(*STI)); 7770b57cec5SDimitry Andric 7780b57cec5SDimitry Andric if (PrintRetireStats) 7798bcb0991SDimitry Andric Printer.addView(std::make_unique<mca::RetireControlUnitStatistics>(SM)); 7800b57cec5SDimitry Andric 7810b57cec5SDimitry Andric if (PrintRegisterFileStats) 7828bcb0991SDimitry Andric Printer.addView(std::make_unique<mca::RegisterFileStatistics>(*STI)); 7830b57cec5SDimitry Andric 7840b57cec5SDimitry Andric if (PrintResourcePressureView) 7850b57cec5SDimitry Andric Printer.addView( 7868bcb0991SDimitry Andric std::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts)); 7870b57cec5SDimitry Andric 7880b57cec5SDimitry Andric if (PrintTimelineView) { 7890b57cec5SDimitry Andric unsigned TimelineIterations = 7900b57cec5SDimitry Andric TimelineMaxIterations ? TimelineMaxIterations : 10; 7918bcb0991SDimitry Andric Printer.addView(std::make_unique<mca::TimelineView>( 7920b57cec5SDimitry Andric *STI, *IP, Insts, std::min(TimelineIterations, S.getNumIterations()), 7930b57cec5SDimitry Andric TimelineMaxCycles)); 7940b57cec5SDimitry Andric } 7950b57cec5SDimitry Andric 796349cc55cSDimitry Andric // Fetch custom Views that are to be placed after all other Views. 797349cc55cSDimitry Andric // Refer to the comment paired with the CB->getStartViews(*IP, Insts); line 798349cc55cSDimitry Andric // for more info. 799349cc55cSDimitry Andric if (!DisableCustomBehaviour) { 800349cc55cSDimitry Andric std::vector<std::unique_ptr<mca::View>> CBViews = 801349cc55cSDimitry Andric CB->getEndViews(*IP, Insts); 802349cc55cSDimitry Andric for (auto &CBView : CBViews) 803349cc55cSDimitry Andric Printer.addView(std::move(CBView)); 804349cc55cSDimitry Andric } 805349cc55cSDimitry Andric 8060b57cec5SDimitry Andric if (!runPipeline(*P)) 8070b57cec5SDimitry Andric return 1; 8080b57cec5SDimitry Andric 809fe6060f1SDimitry Andric if (PrintJson) { 810fe6060f1SDimitry Andric Printer.printReport(JSONOutput); 811fe6060f1SDimitry Andric } else { 8120b57cec5SDimitry Andric Printer.printReport(TOF->os()); 8130b57cec5SDimitry Andric } 8140b57cec5SDimitry Andric 815fe6060f1SDimitry Andric ++RegionIdx; 816fe6060f1SDimitry Andric } 817fe6060f1SDimitry Andric 818*0fca6ea1SDimitry Andric if (NonEmptyRegions == 0) { 819*0fca6ea1SDimitry Andric WithColor::error() << "no assembly instructions found.\n"; 820*0fca6ea1SDimitry Andric return 1; 821*0fca6ea1SDimitry Andric } 822*0fca6ea1SDimitry Andric 823fe6060f1SDimitry Andric if (PrintJson) 824fe6060f1SDimitry Andric TOF->os() << formatv("{0:2}", json::Value(std::move(JSONOutput))) << "\n"; 825fe6060f1SDimitry Andric 8260b57cec5SDimitry Andric TOF->keep(); 8270b57cec5SDimitry Andric return 0; 8280b57cec5SDimitry Andric } 829