852 lines · cpp
1//===-- llvm-mca.cpp - Machine Code Analyzer -------------------*- C++ -* -===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This utility is a simple driver that allows static performance analysis on10// machine code similarly to how IACA (Intel Architecture Code Analyzer) works.11//12// llvm-mca [options] <file-name>13// -march <type>14// -mcpu <cpu>15// -o <file>16//17// The target defaults to the host target.18// The cpu defaults to the 'native' host cpu.19// The output defaults to standard output.20//21//===----------------------------------------------------------------------===//22 23#include "CodeRegion.h"24#include "CodeRegionGenerator.h"25#include "PipelinePrinter.h"26#include "Views/BottleneckAnalysis.h"27#include "Views/DispatchStatistics.h"28#include "Views/InstructionInfoView.h"29#include "Views/RegisterFileStatistics.h"30#include "Views/ResourcePressureView.h"31#include "Views/RetireControlUnitStatistics.h"32#include "Views/SchedulerStatistics.h"33#include "Views/SummaryView.h"34#include "Views/TimelineView.h"35#include "llvm/MC/MCAsmBackend.h"36#include "llvm/MC/MCAsmInfo.h"37#include "llvm/MC/MCCodeEmitter.h"38#include "llvm/MC/MCContext.h"39#include "llvm/MC/MCObjectFileInfo.h"40#include "llvm/MC/MCRegisterInfo.h"41#include "llvm/MC/MCSubtargetInfo.h"42#include "llvm/MC/MCTargetOptionsCommandFlags.h"43#include "llvm/MC/TargetRegistry.h"44#include "llvm/MCA/CodeEmitter.h"45#include "llvm/MCA/Context.h"46#include "llvm/MCA/CustomBehaviour.h"47#include "llvm/MCA/InstrBuilder.h"48#include "llvm/MCA/Pipeline.h"49#include "llvm/MCA/Stages/EntryStage.h"50#include "llvm/MCA/Stages/InstructionTables.h"51#include "llvm/MCA/Support.h"52#include "llvm/Support/CommandLine.h"53#include "llvm/Support/ErrorHandling.h"54#include "llvm/Support/ErrorOr.h"55#include "llvm/Support/FileSystem.h"56#include "llvm/Support/InitLLVM.h"57#include "llvm/Support/MemoryBuffer.h"58#include "llvm/Support/SourceMgr.h"59#include "llvm/Support/TargetSelect.h"60#include "llvm/Support/ToolOutputFile.h"61#include "llvm/Support/WithColor.h"62#include "llvm/TargetParser/Host.h"63 64using namespace llvm;65 66static mc::RegisterMCTargetOptionsFlags MOF;67 68static cl::OptionCategory ToolOptions("Tool Options");69static cl::OptionCategory ViewOptions("View Options");70 71static cl::opt<std::string> InputFilename(cl::Positional,72 cl::desc("<input file>"),73 cl::cat(ToolOptions), cl::init("-"));74 75static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),76 cl::init("-"), cl::cat(ToolOptions),77 cl::value_desc("filename"));78 79static cl::opt<std::string>80 ArchName("march",81 cl::desc("Target architecture. "82 "See -version for available targets"),83 cl::cat(ToolOptions));84 85static cl::opt<std::string>86 TripleNameOpt("mtriple",87 cl::desc("Target triple. See -version for available targets"),88 cl::cat(ToolOptions));89 90static cl::opt<std::string>91 MCPU("mcpu",92 cl::desc("Target a specific cpu type (-mcpu=help for details)"),93 cl::value_desc("cpu-name"), cl::cat(ToolOptions), cl::init("native"));94 95static cl::list<std::string>96 MATTRS("mattr", cl::CommaSeparated,97 cl::desc("Target specific attributes (-mattr=help for details)"),98 cl::value_desc("a1,+a2,-a3,..."), cl::cat(ToolOptions));99 100static cl::opt<bool> PrintJson("json",101 cl::desc("Print the output in json format"),102 cl::cat(ToolOptions), cl::init(false));103 104static cl::opt<int>105 OutputAsmVariant("output-asm-variant",106 cl::desc("Syntax variant to use for output printing"),107 cl::cat(ToolOptions), cl::init(-1));108 109static cl::opt<bool>110 PrintImmHex("print-imm-hex", cl::cat(ToolOptions), cl::init(false),111 cl::desc("Prefer hex format when printing immediate values"));112 113static cl::opt<unsigned> Iterations("iterations",114 cl::desc("Number of iterations to run"),115 cl::cat(ToolOptions), cl::init(0));116 117static cl::opt<unsigned>118 DispatchWidth("dispatch", cl::desc("Override the processor dispatch width"),119 cl::cat(ToolOptions), cl::init(0));120 121static cl::opt<unsigned>122 RegisterFileSize("register-file-size",123 cl::desc("Maximum number of physical registers which can "124 "be used for register mappings"),125 cl::cat(ToolOptions), cl::init(0));126 127static cl::opt<unsigned>128 MicroOpQueue("micro-op-queue-size", cl::Hidden,129 cl::desc("Number of entries in the micro-op queue"),130 cl::cat(ToolOptions), cl::init(0));131 132static cl::opt<unsigned>133 DecoderThroughput("decoder-throughput", cl::Hidden,134 cl::desc("Maximum throughput from the decoders "135 "(instructions per cycle)"),136 cl::cat(ToolOptions), cl::init(0));137 138static cl::opt<unsigned>139 CallLatency("call-latency", cl::Hidden,140 cl::desc("Number of cycles to assume for a call instruction"),141 cl::cat(ToolOptions), cl::init(100U));142 143enum class SkipType { NONE, LACK_SCHED, PARSE_FAILURE, ANY_FAILURE };144 145static cl::opt<enum SkipType> SkipUnsupportedInstructions(146 "skip-unsupported-instructions",147 cl::desc("Force analysis to continue in the presence of unsupported "148 "instructions"),149 cl::values(150 clEnumValN(SkipType::NONE, "none",151 "Exit with an error when an instruction is unsupported for "152 "any reason (default)"),153 clEnumValN(154 SkipType::LACK_SCHED, "lack-sched",155 "Skip instructions on input which lack scheduling information"),156 clEnumValN(157 SkipType::PARSE_FAILURE, "parse-failure",158 "Skip lines on the input which fail to parse for any reason"),159 clEnumValN(SkipType::ANY_FAILURE, "any",160 "Skip instructions or lines on input which are unsupported "161 "for any reason")),162 cl::init(SkipType::NONE), cl::cat(ViewOptions));163 164bool shouldSkip(enum SkipType skipType) {165 if (SkipUnsupportedInstructions == SkipType::NONE)166 return false;167 if (SkipUnsupportedInstructions == SkipType::ANY_FAILURE)168 return true;169 return skipType == SkipUnsupportedInstructions;170}171 172static cl::opt<bool>173 PrintRegisterFileStats("register-file-stats",174 cl::desc("Print register file statistics"),175 cl::cat(ViewOptions), cl::init(false));176 177static cl::opt<bool> PrintDispatchStats("dispatch-stats",178 cl::desc("Print dispatch statistics"),179 cl::cat(ViewOptions), cl::init(false));180 181static cl::opt<bool>182 PrintSummaryView("summary-view", cl::Hidden,183 cl::desc("Print summary view (enabled by default)"),184 cl::cat(ViewOptions), cl::init(true));185 186static cl::opt<bool> PrintSchedulerStats("scheduler-stats",187 cl::desc("Print scheduler statistics"),188 cl::cat(ViewOptions), cl::init(false));189 190static cl::opt<bool>191 PrintRetireStats("retire-stats",192 cl::desc("Print retire control unit statistics"),193 cl::cat(ViewOptions), cl::init(false));194 195static cl::opt<bool> PrintResourcePressureView(196 "resource-pressure",197 cl::desc("Print the resource pressure view (enabled by default)"),198 cl::cat(ViewOptions), cl::init(true));199 200static cl::opt<bool> PrintTimelineView("timeline",201 cl::desc("Print the timeline view"),202 cl::cat(ViewOptions), cl::init(false));203 204static cl::opt<unsigned> TimelineMaxIterations(205 "timeline-max-iterations",206 cl::desc("Maximum number of iterations to print in timeline view"),207 cl::cat(ViewOptions), cl::init(0));208 209static cl::opt<unsigned>210 TimelineMaxCycles("timeline-max-cycles",211 cl::desc("Maximum number of cycles in the timeline view, "212 "or 0 for unlimited. Defaults to 80 cycles"),213 cl::cat(ViewOptions), cl::init(80));214 215static cl::opt<bool>216 AssumeNoAlias("noalias",217 cl::desc("If set, assume that loads and stores do not alias"),218 cl::cat(ToolOptions), cl::init(true));219 220static cl::opt<unsigned> LoadQueueSize("lqueue",221 cl::desc("Size of the load queue"),222 cl::cat(ToolOptions), cl::init(0));223 224static cl::opt<unsigned> StoreQueueSize("squeue",225 cl::desc("Size of the store queue"),226 cl::cat(ToolOptions), cl::init(0));227 228enum class InstructionTablesType { NONE, NORMAL, FULL };229 230static cl::opt<enum InstructionTablesType> InstructionTablesOption(231 "instruction-tables", cl::desc("Print instruction tables"),232 cl::values(clEnumValN(InstructionTablesType::NONE, "none",233 "Do not print instruction tables"),234 clEnumValN(InstructionTablesType::NORMAL, "normal",235 "Print instruction tables"),236 clEnumValN(InstructionTablesType::NORMAL, "", ""),237 clEnumValN(InstructionTablesType::FULL, "full",238 "Print instruction tables with additional"239 " information: bypass latency, LLVM opcode,"240 " used resources")),241 cl::cat(ToolOptions), cl::init(InstructionTablesType::NONE),242 cl::ValueOptional);243 244static bool shouldPrintInstructionTables(enum InstructionTablesType ITType) {245 return InstructionTablesOption == ITType;246}247 248static bool shouldPrintInstructionTables() {249 return !shouldPrintInstructionTables(InstructionTablesType::NONE);250}251 252static cl::opt<bool> PrintInstructionInfoView(253 "instruction-info",254 cl::desc("Print the instruction info view (enabled by default)"),255 cl::cat(ViewOptions), cl::init(true));256 257static cl::opt<bool> EnableAllStats("all-stats",258 cl::desc("Print all hardware statistics"),259 cl::cat(ViewOptions), cl::init(false));260 261static cl::opt<bool>262 EnableAllViews("all-views",263 cl::desc("Print all views including hardware statistics"),264 cl::cat(ViewOptions), cl::init(false));265 266static cl::opt<bool> EnableBottleneckAnalysis(267 "bottleneck-analysis",268 cl::desc("Enable bottleneck analysis (disabled by default)"),269 cl::cat(ViewOptions), cl::init(false));270 271static cl::opt<bool> ShowEncoding(272 "show-encoding",273 cl::desc("Print encoding information in the instruction info view"),274 cl::cat(ViewOptions), cl::init(false));275 276static cl::opt<bool> ShowBarriers(277 "show-barriers",278 cl::desc("Print memory barrier information in the instruction info view"),279 cl::cat(ViewOptions), cl::init(false));280 281static cl::opt<bool> DisableCustomBehaviour(282 "disable-cb",283 cl::desc(284 "Disable custom behaviour (use the default class which does nothing)."),285 cl::cat(ViewOptions), cl::init(false));286 287static cl::opt<bool> DisableInstrumentManager(288 "disable-im",289 cl::desc("Disable instrumentation manager (use the default class which "290 "ignores instruments.)."),291 cl::cat(ViewOptions), cl::init(false));292 293namespace {294 295const Target *getTarget(Triple &TheTriple, const char *ProgName) {296 // Get the target specific parser.297 std::string Error;298 const Target *TheTarget =299 TargetRegistry::lookupTarget(ArchName, TheTriple, Error);300 if (!TheTarget) {301 errs() << ProgName << ": " << Error;302 return nullptr;303 }304 305 // Return the found target.306 return TheTarget;307}308 309ErrorOr<std::unique_ptr<ToolOutputFile>> getOutputStream() {310 if (OutputFilename == "")311 OutputFilename = "-";312 std::error_code EC;313 auto Out = std::make_unique<ToolOutputFile>(OutputFilename, EC,314 sys::fs::OF_TextWithCRLF);315 if (!EC)316 return std::move(Out);317 return EC;318}319} // end of anonymous namespace320 321static void processOptionImpl(cl::opt<bool> &O, const cl::opt<bool> &Default) {322 if (!O.getNumOccurrences() || O.getPosition() < Default.getPosition())323 O = Default.getValue();324}325 326static void processViewOptions(bool IsOutOfOrder) {327 if (!EnableAllViews.getNumOccurrences() &&328 !EnableAllStats.getNumOccurrences())329 return;330 331 if (EnableAllViews.getNumOccurrences()) {332 processOptionImpl(PrintSummaryView, EnableAllViews);333 if (IsOutOfOrder)334 processOptionImpl(EnableBottleneckAnalysis, EnableAllViews);335 processOptionImpl(PrintResourcePressureView, EnableAllViews);336 processOptionImpl(PrintTimelineView, EnableAllViews);337 processOptionImpl(PrintInstructionInfoView, EnableAllViews);338 }339 340 const cl::opt<bool> &Default =341 EnableAllViews.getPosition() < EnableAllStats.getPosition()342 ? EnableAllStats343 : EnableAllViews;344 processOptionImpl(PrintRegisterFileStats, Default);345 processOptionImpl(PrintDispatchStats, Default);346 processOptionImpl(PrintSchedulerStats, Default);347 if (IsOutOfOrder)348 processOptionImpl(PrintRetireStats, Default);349}350 351// Returns true on success.352static bool runPipeline(mca::Pipeline &P) {353 // Handle pipeline errors here.354 Expected<unsigned> Cycles = P.run();355 if (!Cycles) {356 WithColor::error() << toString(Cycles.takeError());357 return false;358 }359 return true;360}361 362int main(int argc, char **argv) {363 InitLLVM X(argc, argv);364 365 // Initialize targets and assembly parsers.366 InitializeAllTargetInfos();367 InitializeAllTargetMCs();368 InitializeAllAsmParsers();369 InitializeAllTargetMCAs();370 371 // Register the Target and CPU printer for --version.372 cl::AddExtraVersionPrinter(sys::printDefaultTargetAndDetectedCPU);373 374 // Enable printing of available targets when flag --version is specified.375 cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);376 377 cl::HideUnrelatedOptions({&ToolOptions, &ViewOptions});378 379 // Parse flags and initialize target options.380 cl::ParseCommandLineOptions(argc, argv,381 "llvm machine code performance analyzer.\n");382 383 Triple TheTriple(TripleNameOpt.empty()384 ? Triple::normalize(sys::getDefaultTargetTriple())385 : TripleNameOpt);386 387 // Get the target from the triple. If a triple is not specified, then select388 // the default triple for the host. If the triple doesn't correspond to any389 // registered target, then exit with an error message.390 const char *ProgName = argv[0];391 const Target *TheTarget = getTarget(TheTriple, ProgName);392 if (!TheTarget)393 return 1;394 395 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr =396 MemoryBuffer::getFileOrSTDIN(InputFilename);397 if (std::error_code EC = BufferPtr.getError()) {398 WithColor::error() << InputFilename << ": " << EC.message() << '\n';399 return 1;400 }401 402 if (MCPU == "native")403 MCPU = std::string(llvm::sys::getHostCPUName());404 405 // Package up features to be passed to target/subtarget406 std::string FeaturesStr;407 if (MATTRS.size()) {408 SubtargetFeatures Features;409 for (std::string &MAttr : MATTRS)410 Features.AddFeature(MAttr);411 FeaturesStr = Features.getString();412 }413 414 std::unique_ptr<MCSubtargetInfo> STI(415 TheTarget->createMCSubtargetInfo(TheTriple, MCPU, FeaturesStr));416 if (!STI) {417 WithColor::error() << "unable to create subtarget info\n";418 return 1;419 }420 421 if (!STI->isCPUStringValid(MCPU))422 return 1;423 424 if (!STI->getSchedModel().hasInstrSchedModel()) {425 WithColor::error()426 << "unable to find instruction-level scheduling information for"427 << " target triple '" << TheTriple.normalize() << "' and cpu '" << MCPU428 << "'.\n";429 430 if (STI->getSchedModel().InstrItineraries)431 WithColor::note()432 << "cpu '" << MCPU << "' provides itineraries. However, "433 << "instruction itineraries are currently unsupported.\n";434 return 1;435 }436 437 // Apply overrides to llvm-mca specific options.438 bool IsOutOfOrder = STI->getSchedModel().isOutOfOrder();439 processViewOptions(IsOutOfOrder);440 441 std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TheTriple));442 assert(MRI && "Unable to create target register info!");443 444 MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();445 std::unique_ptr<MCAsmInfo> MAI(446 TheTarget->createMCAsmInfo(*MRI, TheTriple, MCOptions));447 assert(MAI && "Unable to create target asm info!");448 449 SourceMgr SrcMgr;450 451 // Tell SrcMgr about this buffer, which is what the parser will pick up.452 SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc());453 454 std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());455 assert(MCII && "Unable to create instruction info!");456 457 std::unique_ptr<MCInstrAnalysis> MCIA(458 TheTarget->createMCInstrAnalysis(MCII.get()));459 460 // Need to initialize an MCInstPrinter as it is461 // required for initializing the MCTargetStreamer462 // which needs to happen within the CRG.parseAnalysisRegions() call below.463 // Without an MCTargetStreamer, certain assembly directives can trigger a464 // segfault. (For example, the .cv_fpo_proc directive on x86 will segfault if465 // we don't initialize the MCTargetStreamer.)466 unsigned IPtempOutputAsmVariant =467 OutputAsmVariant == -1 ? 0 : OutputAsmVariant;468 std::unique_ptr<MCInstPrinter> IPtemp(TheTarget->createMCInstPrinter(469 TheTriple, IPtempOutputAsmVariant, *MAI, *MCII, *MRI));470 if (!IPtemp) {471 WithColor::error()472 << "unable to create instruction printer for target triple '"473 << TheTriple.normalize() << "' with assembly variant "474 << IPtempOutputAsmVariant << ".\n";475 return 1;476 }477 478 // Parse the input and create CodeRegions that llvm-mca can analyze.479 MCContext ACtx(TheTriple, MAI.get(), MRI.get(), STI.get(), &SrcMgr);480 std::unique_ptr<MCObjectFileInfo> AMOFI(481 TheTarget->createMCObjectFileInfo(ACtx, /*PIC=*/false));482 ACtx.setObjectFileInfo(AMOFI.get());483 mca::AsmAnalysisRegionGenerator CRG(*TheTarget, SrcMgr, ACtx, *MAI, *STI,484 *MCII);485 Expected<const mca::AnalysisRegions &> RegionsOrErr =486 CRG.parseAnalysisRegions(std::move(IPtemp),487 shouldSkip(SkipType::PARSE_FAILURE));488 if (!RegionsOrErr) {489 if (auto Err =490 handleErrors(RegionsOrErr.takeError(), [](const StringError &E) {491 WithColor::error() << E.getMessage() << '\n';492 })) {493 // Default case.494 WithColor::error() << toString(std::move(Err)) << '\n';495 }496 return 1;497 }498 const mca::AnalysisRegions &Regions = *RegionsOrErr;499 500 // Early exit if errors were found by the code region parsing logic.501 if (!Regions.isValid())502 return 1;503 504 if (Regions.empty()) {505 WithColor::error() << "no assembly instructions found.\n";506 return 1;507 }508 509 std::unique_ptr<mca::InstrumentManager> IM;510 if (!DisableInstrumentManager) {511 IM = std::unique_ptr<mca::InstrumentManager>(512 TheTarget->createInstrumentManager(*STI, *MCII));513 if (!IM) {514 // If the target doesn't have its own IM implemented we use base class515 // with instruments enabled.516 IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII);517 }518 } else {519 // If the -disable-im flag is set then we use the default base class520 // implementation and disable the instruments.521 IM = std::make_unique<mca::InstrumentManager>(*STI, *MCII,522 /*EnableInstruments=*/false);523 }524 525 // Parse the input and create InstrumentRegion that llvm-mca526 // can use to improve analysis.527 MCContext ICtx(TheTriple, MAI.get(), MRI.get(), STI.get(), &SrcMgr);528 std::unique_ptr<MCObjectFileInfo> IMOFI(529 TheTarget->createMCObjectFileInfo(ICtx, /*PIC=*/false));530 ICtx.setObjectFileInfo(IMOFI.get());531 mca::AsmInstrumentRegionGenerator IRG(*TheTarget, SrcMgr, ICtx, *MAI, *STI,532 *MCII, *IM);533 Expected<const mca::InstrumentRegions &> InstrumentRegionsOrErr =534 IRG.parseInstrumentRegions(std::move(IPtemp),535 shouldSkip(SkipType::PARSE_FAILURE));536 if (!InstrumentRegionsOrErr) {537 if (auto Err = handleErrors(InstrumentRegionsOrErr.takeError(),538 [](const StringError &E) {539 WithColor::error() << E.getMessage() << '\n';540 })) {541 // Default case.542 WithColor::error() << toString(std::move(Err)) << '\n';543 }544 return 1;545 }546 const mca::InstrumentRegions &InstrumentRegions = *InstrumentRegionsOrErr;547 548 // Early exit if errors were found by the instrumentation parsing logic.549 if (!InstrumentRegions.isValid())550 return 1;551 552 // Now initialize the output file.553 auto OF = getOutputStream();554 if (std::error_code EC = OF.getError()) {555 WithColor::error() << EC.message() << '\n';556 return 1;557 }558 559 unsigned AssemblerDialect = CRG.getAssemblerDialect();560 if (OutputAsmVariant >= 0)561 AssemblerDialect = static_cast<unsigned>(OutputAsmVariant);562 std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(563 TheTriple, AssemblerDialect, *MAI, *MCII, *MRI));564 if (!IP) {565 WithColor::error()566 << "unable to create instruction printer for target triple '"567 << TheTriple.normalize() << "' with assembly variant "568 << AssemblerDialect << ".\n";569 return 1;570 }571 572 // Set the display preference for hex vs. decimal immediates.573 IP->setPrintImmHex(PrintImmHex);574 575 std::unique_ptr<ToolOutputFile> TOF = std::move(*OF);576 577 const MCSchedModel &SM = STI->getSchedModel();578 579 std::unique_ptr<mca::InstrPostProcess> IPP;580 if (!DisableCustomBehaviour) {581 // TODO: It may be a good idea to separate CB and IPP so that they can582 // be used independently of each other. What I mean by this is to add583 // an extra command-line arg --disable-ipp so that CB and IPP can be584 // toggled without needing to toggle both of them together.585 IPP = std::unique_ptr<mca::InstrPostProcess>(586 TheTarget->createInstrPostProcess(*STI, *MCII));587 }588 if (!IPP) {589 // If the target doesn't have its own IPP implemented (or the -disable-cb590 // flag is set) then we use the base class (which does nothing).591 IPP = std::make_unique<mca::InstrPostProcess>(*STI, *MCII);592 }593 594 // Create an instruction builder.595 mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get(), *IM, CallLatency);596 597 // Create a context to control ownership of the pipeline hardware.598 mca::Context MCA(*MRI, *STI);599 600 mca::PipelineOptions PO(MicroOpQueue, DecoderThroughput, DispatchWidth,601 RegisterFileSize, LoadQueueSize, StoreQueueSize,602 AssumeNoAlias, EnableBottleneckAnalysis);603 604 // Number each region in the sequence.605 unsigned RegionIdx = 0;606 607 std::unique_ptr<MCCodeEmitter> MCE(608 TheTarget->createMCCodeEmitter(*MCII, ACtx));609 assert(MCE && "Unable to create code emitter!");610 611 std::unique_ptr<MCAsmBackend> MAB(TheTarget->createMCAsmBackend(612 *STI, *MRI, mc::InitMCTargetOptionsFromFlags()));613 assert(MAB && "Unable to create asm backend!");614 615 json::Object JSONOutput;616 int NonEmptyRegions = 0;617 for (const std::unique_ptr<mca::AnalysisRegion> &Region : Regions) {618 // Skip empty code regions.619 if (Region->empty())620 continue;621 622 IB.clear();623 624 // Lower the MCInst sequence into an mca::Instruction sequence.625 ArrayRef<MCInst> Insts = Region->getInstructions();626 mca::CodeEmitter CE(*STI, *MAB, *MCE, Insts);627 628 IPP->resetState();629 630 DenseMap<const MCInst *, SmallVector<mca::Instrument *>> InstToInstruments;631 SmallVector<std::unique_ptr<mca::Instruction>> LoweredSequence;632 SmallPtrSet<const MCInst *, 16> DroppedInsts;633 for (const MCInst &MCI : Insts) {634 SMLoc Loc = MCI.getLoc();635 const SmallVector<mca::Instrument *> Instruments =636 InstrumentRegions.getActiveInstruments(Loc);637 638 Expected<std::unique_ptr<mca::Instruction>> Inst =639 IB.createInstruction(MCI, Instruments);640 if (!Inst) {641 if (auto NewE = handleErrors(642 Inst.takeError(),643 [&IP, &STI](const mca::InstructionError<MCInst> &IE) {644 std::string InstructionStr;645 raw_string_ostream SS(InstructionStr);646 if (shouldSkip(SkipType::LACK_SCHED))647 WithColor::warning()648 << IE.Message649 << ", skipping with -skip-unsupported-instructions, "650 "note accuracy will be impacted:\n";651 else652 WithColor::error()653 << IE.Message654 << ", use -skip-unsupported-instructions=lack-sched to "655 "ignore these on the input.\n";656 IP->printInst(&IE.Inst, 0, "", *STI, SS);657 SS.flush();658 WithColor::note()659 << "instruction: " << InstructionStr << '\n';660 })) {661 // Default case.662 WithColor::error() << toString(std::move(NewE));663 }664 if (shouldSkip(SkipType::LACK_SCHED)) {665 DroppedInsts.insert(&MCI);666 continue;667 }668 return 1;669 }670 671 IPP->postProcessInstruction(*Inst.get(), MCI);672 InstToInstruments.insert({&MCI, Instruments});673 LoweredSequence.emplace_back(std::move(Inst.get()));674 }675 676 Insts = Region->dropInstructions(DroppedInsts);677 678 // Skip empty regions.679 if (Insts.empty())680 continue;681 NonEmptyRegions++;682 683 mca::CircularSourceMgr S(LoweredSequence,684 shouldPrintInstructionTables() ? 1 : Iterations);685 686 if (shouldPrintInstructionTables()) {687 // Create a pipeline, stages, and a printer.688 auto P = std::make_unique<mca::Pipeline>();689 P->appendStage(std::make_unique<mca::EntryStage>(S));690 P->appendStage(std::make_unique<mca::InstructionTables>(SM));691 692 mca::PipelinePrinter Printer(*P, *Region, RegionIdx, *STI, PO);693 if (PrintJson) {694 Printer.addView(695 std::make_unique<mca::InstructionView>(*STI, *IP, Insts));696 }697 698 // Create the views for this pipeline, execute, and emit a report.699 if (PrintInstructionInfoView) {700 Printer.addView(std::make_unique<mca::InstructionInfoView>(701 *STI, *MCII, CE, ShowEncoding, Insts, *IP, LoweredSequence,702 ShowBarriers,703 shouldPrintInstructionTables(InstructionTablesType::FULL), *IM,704 InstToInstruments));705 }706 707 if (PrintResourcePressureView)708 Printer.addView(709 std::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts));710 711 if (!runPipeline(*P))712 return 1;713 714 if (PrintJson) {715 Printer.printReport(JSONOutput);716 } else {717 Printer.printReport(TOF->os());718 }719 720 ++RegionIdx;721 continue;722 }723 724 // Create the CustomBehaviour object for enforcing Target Specific725 // behaviours and dependencies that aren't expressed well enough726 // in the tablegen. CB cannot depend on the list of MCInst or727 // the source code (but it can depend on the list of728 // mca::Instruction or any objects that can be reconstructed729 // from the target information).730 std::unique_ptr<mca::CustomBehaviour> CB;731 if (!DisableCustomBehaviour)732 CB = std::unique_ptr<mca::CustomBehaviour>(733 TheTarget->createCustomBehaviour(*STI, S, *MCII));734 if (!CB)735 // If the target doesn't have its own CB implemented (or the -disable-cb736 // flag is set) then we use the base class (which does nothing).737 CB = std::make_unique<mca::CustomBehaviour>(*STI, S, *MCII);738 739 // Create a basic pipeline simulating an out-of-order backend.740 auto P = MCA.createDefaultPipeline(PO, S, *CB);741 742 mca::PipelinePrinter Printer(*P, *Region, RegionIdx, *STI, PO);743 744 // Targets can define their own custom Views that exist within their745 // /lib/Target/ directory so that the View can utilize their CustomBehaviour746 // or other backend symbols / functionality that are not already exposed747 // through one of the MC-layer classes. These Views will be initialized748 // using the CustomBehaviour::getViews() variants.749 // If a target makes a custom View that does not depend on their target750 // CB or their backend, they should put the View within751 // /tools/llvm-mca/Views/ instead.752 if (!DisableCustomBehaviour) {753 std::vector<std::unique_ptr<mca::View>> CBViews =754 CB->getStartViews(*IP, Insts);755 for (auto &CBView : CBViews)756 Printer.addView(std::move(CBView));757 }758 759 // When we output JSON, we add a view that contains the instructions760 // and CPU resource information.761 if (PrintJson) {762 auto IV = std::make_unique<mca::InstructionView>(*STI, *IP, Insts);763 Printer.addView(std::move(IV));764 }765 766 if (PrintSummaryView)767 Printer.addView(768 std::make_unique<mca::SummaryView>(SM, Insts, DispatchWidth));769 770 if (EnableBottleneckAnalysis) {771 if (!IsOutOfOrder) {772 WithColor::warning()773 << "bottleneck analysis is not supported for in-order CPU '" << MCPU774 << "'.\n";775 }776 Printer.addView(std::make_unique<mca::BottleneckAnalysis>(777 *STI, *IP, Insts, S.getNumIterations()));778 }779 780 if (PrintInstructionInfoView)781 Printer.addView(std::make_unique<mca::InstructionInfoView>(782 *STI, *MCII, CE, ShowEncoding, Insts, *IP, LoweredSequence,783 ShowBarriers, /*ShouldPrintFullInfo=*/false, *IM, InstToInstruments));784 785 // Fetch custom Views that are to be placed after the InstructionInfoView.786 // Refer to the comment paired with the CB->getStartViews(*IP, Insts); line787 // for more info.788 if (!DisableCustomBehaviour) {789 std::vector<std::unique_ptr<mca::View>> CBViews =790 CB->getPostInstrInfoViews(*IP, Insts);791 for (auto &CBView : CBViews)792 Printer.addView(std::move(CBView));793 }794 795 if (PrintDispatchStats)796 Printer.addView(std::make_unique<mca::DispatchStatistics>());797 798 if (PrintSchedulerStats)799 Printer.addView(std::make_unique<mca::SchedulerStatistics>(*STI));800 801 if (PrintRetireStats)802 Printer.addView(std::make_unique<mca::RetireControlUnitStatistics>(SM));803 804 if (PrintRegisterFileStats)805 Printer.addView(std::make_unique<mca::RegisterFileStatistics>(*STI));806 807 if (PrintResourcePressureView)808 Printer.addView(809 std::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts));810 811 if (PrintTimelineView) {812 unsigned TimelineIterations =813 TimelineMaxIterations ? TimelineMaxIterations : 10;814 Printer.addView(std::make_unique<mca::TimelineView>(815 *STI, *IP, Insts, std::min(TimelineIterations, S.getNumIterations()),816 TimelineMaxCycles));817 }818 819 // Fetch custom Views that are to be placed after all other Views.820 // Refer to the comment paired with the CB->getStartViews(*IP, Insts); line821 // for more info.822 if (!DisableCustomBehaviour) {823 std::vector<std::unique_ptr<mca::View>> CBViews =824 CB->getEndViews(*IP, Insts);825 for (auto &CBView : CBViews)826 Printer.addView(std::move(CBView));827 }828 829 if (!runPipeline(*P))830 return 1;831 832 if (PrintJson) {833 Printer.printReport(JSONOutput);834 } else {835 Printer.printReport(TOF->os());836 }837 838 ++RegionIdx;839 }840 841 if (NonEmptyRegions == 0) {842 WithColor::error() << "no assembly instructions found.\n";843 return 1;844 }845 846 if (PrintJson)847 TOF->os() << formatv("{0:2}", json::Value(std::move(JSONOutput))) << "\n";848 849 TOF->keep();850 return 0;851}852