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