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 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/MCA/CodeEmitter.h"
44#include "llvm/MCA/Context.h"
45#include "llvm/MCA/InstrBuilder.h"
46#include "llvm/MCA/Pipeline.h"
47#include "llvm/MCA/Stages/EntryStage.h"
48#include "llvm/MCA/Stages/InstructionTables.h"
49#include "llvm/MCA/Support.h"
50#include "llvm/Support/CommandLine.h"
51#include "llvm/Support/ErrorHandling.h"
52#include "llvm/Support/ErrorOr.h"
53#include "llvm/Support/FileSystem.h"
54#include "llvm/Support/Host.h"
55#include "llvm/Support/InitLLVM.h"
56#include "llvm/Support/MemoryBuffer.h"
57#include "llvm/Support/SourceMgr.h"
58#include "llvm/Support/TargetRegistry.h"
59#include "llvm/Support/TargetSelect.h"
60#include "llvm/Support/ToolOutputFile.h"
61#include "llvm/Support/WithColor.h"
62
63using namespace llvm;
64
65static mc::RegisterMCTargetOptionsFlags MOF;
66
67static cl::OptionCategory ToolOptions("Tool Options");
68static cl::OptionCategory ViewOptions("View Options");
69
70static cl::opt<std::string> InputFilename(cl::Positional,
71                                          cl::desc("<input file>"),
72                                          cl::cat(ToolOptions), cl::init("-"));
73
74static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
75                                           cl::init("-"), cl::cat(ToolOptions),
76                                           cl::value_desc("filename"));
77
78static cl::opt<std::string>
79    ArchName("march",
80             cl::desc("Target architecture. "
81                      "See -version for available targets"),
82             cl::cat(ToolOptions));
83
84static cl::opt<std::string>
85    TripleName("mtriple",
86               cl::desc("Target triple. See -version for available targets"),
87               cl::cat(ToolOptions));
88
89static cl::opt<std::string>
90    MCPU("mcpu",
91         cl::desc("Target a specific cpu type (-mcpu=help for details)"),
92         cl::value_desc("cpu-name"), cl::cat(ToolOptions), cl::init("native"));
93
94static cl::opt<std::string>
95    MATTR("mattr",
96          cl::desc("Additional target features."),
97          cl::cat(ToolOptions));
98
99static cl::opt<int>
100    OutputAsmVariant("output-asm-variant",
101                     cl::desc("Syntax variant to use for output printing"),
102                     cl::cat(ToolOptions), cl::init(-1));
103
104static cl::opt<bool>
105    PrintImmHex("print-imm-hex", cl::cat(ToolOptions), cl::init(false),
106                cl::desc("Prefer hex format when printing immediate values"));
107
108static cl::opt<unsigned> Iterations("iterations",
109                                    cl::desc("Number of iterations to run"),
110                                    cl::cat(ToolOptions), cl::init(0));
111
112static cl::opt<unsigned>
113    DispatchWidth("dispatch", cl::desc("Override the processor dispatch width"),
114                  cl::cat(ToolOptions), cl::init(0));
115
116static cl::opt<unsigned>
117    RegisterFileSize("register-file-size",
118                     cl::desc("Maximum number of physical registers which can "
119                              "be used for register mappings"),
120                     cl::cat(ToolOptions), cl::init(0));
121
122static cl::opt<unsigned>
123    MicroOpQueue("micro-op-queue-size", cl::Hidden,
124                 cl::desc("Number of entries in the micro-op queue"),
125                 cl::cat(ToolOptions), cl::init(0));
126
127static cl::opt<unsigned>
128    DecoderThroughput("decoder-throughput", cl::Hidden,
129                      cl::desc("Maximum throughput from the decoders "
130                               "(instructions per cycle)"),
131                      cl::cat(ToolOptions), cl::init(0));
132
133static cl::opt<bool>
134    PrintRegisterFileStats("register-file-stats",
135                           cl::desc("Print register file statistics"),
136                           cl::cat(ViewOptions), cl::init(false));
137
138static cl::opt<bool> PrintDispatchStats("dispatch-stats",
139                                        cl::desc("Print dispatch statistics"),
140                                        cl::cat(ViewOptions), cl::init(false));
141
142static cl::opt<bool>
143    PrintSummaryView("summary-view", cl::Hidden,
144                     cl::desc("Print summary view (enabled by default)"),
145                     cl::cat(ViewOptions), cl::init(true));
146
147static cl::opt<bool> PrintSchedulerStats("scheduler-stats",
148                                         cl::desc("Print scheduler statistics"),
149                                         cl::cat(ViewOptions), cl::init(false));
150
151static cl::opt<bool>
152    PrintRetireStats("retire-stats",
153                     cl::desc("Print retire control unit statistics"),
154                     cl::cat(ViewOptions), cl::init(false));
155
156static cl::opt<bool> PrintResourcePressureView(
157    "resource-pressure",
158    cl::desc("Print the resource pressure view (enabled by default)"),
159    cl::cat(ViewOptions), cl::init(true));
160
161static cl::opt<bool> PrintTimelineView("timeline",
162                                       cl::desc("Print the timeline view"),
163                                       cl::cat(ViewOptions), cl::init(false));
164
165static cl::opt<unsigned> TimelineMaxIterations(
166    "timeline-max-iterations",
167    cl::desc("Maximum number of iterations to print in timeline view"),
168    cl::cat(ViewOptions), cl::init(0));
169
170static cl::opt<unsigned> TimelineMaxCycles(
171    "timeline-max-cycles",
172    cl::desc(
173        "Maximum number of cycles in the timeline view. Defaults to 80 cycles"),
174    cl::cat(ViewOptions), cl::init(80));
175
176static cl::opt<bool>
177    AssumeNoAlias("noalias",
178                  cl::desc("If set, assume that loads and stores do not alias"),
179                  cl::cat(ToolOptions), cl::init(true));
180
181static cl::opt<unsigned> LoadQueueSize("lqueue",
182                                       cl::desc("Size of the load queue"),
183                                       cl::cat(ToolOptions), cl::init(0));
184
185static cl::opt<unsigned> StoreQueueSize("squeue",
186                                        cl::desc("Size of the store queue"),
187                                        cl::cat(ToolOptions), cl::init(0));
188
189static cl::opt<bool>
190    PrintInstructionTables("instruction-tables",
191                           cl::desc("Print instruction tables"),
192                           cl::cat(ToolOptions), cl::init(false));
193
194static cl::opt<bool> PrintInstructionInfoView(
195    "instruction-info",
196    cl::desc("Print the instruction info view (enabled by default)"),
197    cl::cat(ViewOptions), cl::init(true));
198
199static cl::opt<bool> EnableAllStats("all-stats",
200                                    cl::desc("Print all hardware statistics"),
201                                    cl::cat(ViewOptions), cl::init(false));
202
203static cl::opt<bool>
204    EnableAllViews("all-views",
205                   cl::desc("Print all views including hardware statistics"),
206                   cl::cat(ViewOptions), cl::init(false));
207
208static cl::opt<bool> EnableBottleneckAnalysis(
209    "bottleneck-analysis",
210    cl::desc("Enable bottleneck analysis (disabled by default)"),
211    cl::cat(ViewOptions), cl::init(false));
212
213static cl::opt<bool> ShowEncoding(
214    "show-encoding",
215    cl::desc("Print encoding information in the instruction info view"),
216    cl::cat(ViewOptions), cl::init(false));
217
218namespace {
219
220const Target *getTarget(const char *ProgName) {
221  if (TripleName.empty())
222    TripleName = Triple::normalize(sys::getDefaultTargetTriple());
223  Triple TheTriple(TripleName);
224
225  // Get the target specific parser.
226  std::string Error;
227  const Target *TheTarget =
228      TargetRegistry::lookupTarget(ArchName, TheTriple, Error);
229  if (!TheTarget) {
230    errs() << ProgName << ": " << Error;
231    return nullptr;
232  }
233
234  // Return the found target.
235  return TheTarget;
236}
237
238ErrorOr<std::unique_ptr<ToolOutputFile>> getOutputStream() {
239  if (OutputFilename == "")
240    OutputFilename = "-";
241  std::error_code EC;
242  auto Out =
243      std::make_unique<ToolOutputFile>(OutputFilename, EC, sys::fs::OF_Text);
244  if (!EC)
245    return std::move(Out);
246  return EC;
247}
248} // end of anonymous namespace
249
250static void processOptionImpl(cl::opt<bool> &O, const cl::opt<bool> &Default) {
251  if (!O.getNumOccurrences() || O.getPosition() < Default.getPosition())
252    O = Default.getValue();
253}
254
255static void processViewOptions() {
256  if (!EnableAllViews.getNumOccurrences() &&
257      !EnableAllStats.getNumOccurrences())
258    return;
259
260  if (EnableAllViews.getNumOccurrences()) {
261    processOptionImpl(PrintSummaryView, EnableAllViews);
262    processOptionImpl(EnableBottleneckAnalysis, EnableAllViews);
263    processOptionImpl(PrintResourcePressureView, EnableAllViews);
264    processOptionImpl(PrintTimelineView, EnableAllViews);
265    processOptionImpl(PrintInstructionInfoView, EnableAllViews);
266  }
267
268  const cl::opt<bool> &Default =
269      EnableAllViews.getPosition() < EnableAllStats.getPosition()
270          ? EnableAllStats
271          : EnableAllViews;
272  processOptionImpl(PrintRegisterFileStats, Default);
273  processOptionImpl(PrintDispatchStats, Default);
274  processOptionImpl(PrintSchedulerStats, Default);
275  processOptionImpl(PrintRetireStats, Default);
276}
277
278// Returns true on success.
279static bool runPipeline(mca::Pipeline &P) {
280  // Handle pipeline errors here.
281  Expected<unsigned> Cycles = P.run();
282  if (!Cycles) {
283    WithColor::error() << toString(Cycles.takeError());
284    return false;
285  }
286  return true;
287}
288
289int main(int argc, char **argv) {
290  InitLLVM X(argc, argv);
291
292  // Initialize targets and assembly parsers.
293  InitializeAllTargetInfos();
294  InitializeAllTargetMCs();
295  InitializeAllAsmParsers();
296
297  // Enable printing of available targets when flag --version is specified.
298  cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
299
300  cl::HideUnrelatedOptions({&ToolOptions, &ViewOptions});
301
302  // Parse flags and initialize target options.
303  cl::ParseCommandLineOptions(argc, argv,
304                              "llvm machine code performance analyzer.\n");
305
306  // Get the target from the triple. If a triple is not specified, then select
307  // the default triple for the host. If the triple doesn't correspond to any
308  // registered target, then exit with an error message.
309  const char *ProgName = argv[0];
310  const Target *TheTarget = getTarget(ProgName);
311  if (!TheTarget)
312    return 1;
313
314  // GetTarget() may replaced TripleName with a default triple.
315  // For safety, reconstruct the Triple object.
316  Triple TheTriple(TripleName);
317
318  ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr =
319      MemoryBuffer::getFileOrSTDIN(InputFilename);
320  if (std::error_code EC = BufferPtr.getError()) {
321    WithColor::error() << InputFilename << ": " << EC.message() << '\n';
322    return 1;
323  }
324
325  // Apply overrides to llvm-mca specific options.
326  processViewOptions();
327
328  if (!MCPU.compare("native"))
329    MCPU = std::string(llvm::sys::getHostCPUName());
330
331  std::unique_ptr<MCSubtargetInfo> STI(
332      TheTarget->createMCSubtargetInfo(TripleName, MCPU, MATTR));
333  if (!STI->isCPUStringValid(MCPU))
334    return 1;
335
336  if (!PrintInstructionTables && !STI->getSchedModel().isOutOfOrder()) {
337    WithColor::error() << "please specify an out-of-order cpu. '" << MCPU
338                       << "' is an in-order cpu.\n";
339    return 1;
340  }
341
342  if (!STI->getSchedModel().hasInstrSchedModel()) {
343    WithColor::error()
344        << "unable to find instruction-level scheduling information for"
345        << " target triple '" << TheTriple.normalize() << "' and cpu '" << MCPU
346        << "'.\n";
347
348    if (STI->getSchedModel().InstrItineraries)
349      WithColor::note()
350          << "cpu '" << MCPU << "' provides itineraries. However, "
351          << "instruction itineraries are currently unsupported.\n";
352    return 1;
353  }
354
355  std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
356  assert(MRI && "Unable to create target register info!");
357
358  MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();
359  std::unique_ptr<MCAsmInfo> MAI(
360      TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
361  assert(MAI && "Unable to create target asm info!");
362
363  MCObjectFileInfo MOFI;
364  SourceMgr SrcMgr;
365
366  // Tell SrcMgr about this buffer, which is what the parser will pick up.
367  SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc());
368
369  MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr);
370
371  MOFI.InitMCObjectFileInfo(TheTriple, /* PIC= */ false, Ctx);
372
373  std::unique_ptr<buffer_ostream> BOS;
374
375  std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
376
377  std::unique_ptr<MCInstrAnalysis> MCIA(
378      TheTarget->createMCInstrAnalysis(MCII.get()));
379
380  // Parse the input and create CodeRegions that llvm-mca can analyze.
381  mca::AsmCodeRegionGenerator CRG(*TheTarget, SrcMgr, Ctx, *MAI, *STI, *MCII);
382  Expected<const mca::CodeRegions &> RegionsOrErr = CRG.parseCodeRegions();
383  if (!RegionsOrErr) {
384    if (auto Err =
385            handleErrors(RegionsOrErr.takeError(), [](const StringError &E) {
386              WithColor::error() << E.getMessage() << '\n';
387            })) {
388      // Default case.
389      WithColor::error() << toString(std::move(Err)) << '\n';
390    }
391    return 1;
392  }
393  const mca::CodeRegions &Regions = *RegionsOrErr;
394
395  // Early exit if errors were found by the code region parsing logic.
396  if (!Regions.isValid())
397    return 1;
398
399  if (Regions.empty()) {
400    WithColor::error() << "no assembly instructions found.\n";
401    return 1;
402  }
403
404  // Now initialize the output file.
405  auto OF = getOutputStream();
406  if (std::error_code EC = OF.getError()) {
407    WithColor::error() << EC.message() << '\n';
408    return 1;
409  }
410
411  unsigned AssemblerDialect = CRG.getAssemblerDialect();
412  if (OutputAsmVariant >= 0)
413    AssemblerDialect = static_cast<unsigned>(OutputAsmVariant);
414  std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
415      Triple(TripleName), AssemblerDialect, *MAI, *MCII, *MRI));
416  if (!IP) {
417    WithColor::error()
418        << "unable to create instruction printer for target triple '"
419        << TheTriple.normalize() << "' with assembly variant "
420        << AssemblerDialect << ".\n";
421    return 1;
422  }
423
424  // Set the display preference for hex vs. decimal immediates.
425  IP->setPrintImmHex(PrintImmHex);
426
427  std::unique_ptr<ToolOutputFile> TOF = std::move(*OF);
428
429  const MCSchedModel &SM = STI->getSchedModel();
430
431  // Create an instruction builder.
432  mca::InstrBuilder IB(*STI, *MCII, *MRI, MCIA.get());
433
434  // Create a context to control ownership of the pipeline hardware.
435  mca::Context MCA(*MRI, *STI);
436
437  mca::PipelineOptions PO(MicroOpQueue, DecoderThroughput, DispatchWidth,
438                          RegisterFileSize, LoadQueueSize, StoreQueueSize,
439                          AssumeNoAlias, EnableBottleneckAnalysis);
440
441  // Number each region in the sequence.
442  unsigned RegionIdx = 0;
443
444  std::unique_ptr<MCCodeEmitter> MCE(
445      TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
446
447  std::unique_ptr<MCAsmBackend> MAB(TheTarget->createMCAsmBackend(
448      *STI, *MRI, mc::InitMCTargetOptionsFromFlags()));
449
450  for (const std::unique_ptr<mca::CodeRegion> &Region : Regions) {
451    // Skip empty code regions.
452    if (Region->empty())
453      continue;
454
455    // Don't print the header of this region if it is the default region, and
456    // it doesn't have an end location.
457    if (Region->startLoc().isValid() || Region->endLoc().isValid()) {
458      TOF->os() << "\n[" << RegionIdx++ << "] Code Region";
459      StringRef Desc = Region->getDescription();
460      if (!Desc.empty())
461        TOF->os() << " - " << Desc;
462      TOF->os() << "\n\n";
463    }
464
465    // Lower the MCInst sequence into an mca::Instruction sequence.
466    ArrayRef<MCInst> Insts = Region->getInstructions();
467    mca::CodeEmitter CE(*STI, *MAB, *MCE, Insts);
468    std::vector<std::unique_ptr<mca::Instruction>> LoweredSequence;
469    for (const MCInst &MCI : Insts) {
470      Expected<std::unique_ptr<mca::Instruction>> Inst =
471          IB.createInstruction(MCI);
472      if (!Inst) {
473        if (auto NewE = handleErrors(
474                Inst.takeError(),
475                [&IP, &STI](const mca::InstructionError<MCInst> &IE) {
476                  std::string InstructionStr;
477                  raw_string_ostream SS(InstructionStr);
478                  WithColor::error() << IE.Message << '\n';
479                  IP->printInst(&IE.Inst, 0, "", *STI, SS);
480                  SS.flush();
481                  WithColor::note()
482                      << "instruction: " << InstructionStr << '\n';
483                })) {
484          // Default case.
485          WithColor::error() << toString(std::move(NewE));
486        }
487        return 1;
488      }
489
490      LoweredSequence.emplace_back(std::move(Inst.get()));
491    }
492
493    mca::SourceMgr S(LoweredSequence, PrintInstructionTables ? 1 : Iterations);
494
495    if (PrintInstructionTables) {
496      //  Create a pipeline, stages, and a printer.
497      auto P = std::make_unique<mca::Pipeline>();
498      P->appendStage(std::make_unique<mca::EntryStage>(S));
499      P->appendStage(std::make_unique<mca::InstructionTables>(SM));
500      mca::PipelinePrinter Printer(*P);
501
502      // Create the views for this pipeline, execute, and emit a report.
503      if (PrintInstructionInfoView) {
504        Printer.addView(std::make_unique<mca::InstructionInfoView>(
505            *STI, *MCII, CE, ShowEncoding, Insts, *IP));
506      }
507      Printer.addView(
508          std::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts));
509
510      if (!runPipeline(*P))
511        return 1;
512
513      Printer.printReport(TOF->os());
514      continue;
515    }
516
517    // Create a basic pipeline simulating an out-of-order backend.
518    auto P = MCA.createDefaultPipeline(PO, S);
519    mca::PipelinePrinter Printer(*P);
520
521    if (PrintSummaryView)
522      Printer.addView(
523          std::make_unique<mca::SummaryView>(SM, Insts, DispatchWidth));
524
525    if (EnableBottleneckAnalysis) {
526      Printer.addView(std::make_unique<mca::BottleneckAnalysis>(
527          *STI, *IP, Insts, S.getNumIterations()));
528    }
529
530    if (PrintInstructionInfoView)
531      Printer.addView(std::make_unique<mca::InstructionInfoView>(
532          *STI, *MCII, CE, ShowEncoding, Insts, *IP));
533
534    if (PrintDispatchStats)
535      Printer.addView(std::make_unique<mca::DispatchStatistics>());
536
537    if (PrintSchedulerStats)
538      Printer.addView(std::make_unique<mca::SchedulerStatistics>(*STI));
539
540    if (PrintRetireStats)
541      Printer.addView(std::make_unique<mca::RetireControlUnitStatistics>(SM));
542
543    if (PrintRegisterFileStats)
544      Printer.addView(std::make_unique<mca::RegisterFileStatistics>(*STI));
545
546    if (PrintResourcePressureView)
547      Printer.addView(
548          std::make_unique<mca::ResourcePressureView>(*STI, *IP, Insts));
549
550    if (PrintTimelineView) {
551      unsigned TimelineIterations =
552          TimelineMaxIterations ? TimelineMaxIterations : 10;
553      Printer.addView(std::make_unique<mca::TimelineView>(
554          *STI, *IP, Insts, std::min(TimelineIterations, S.getNumIterations()),
555          TimelineMaxCycles));
556    }
557
558    if (!runPipeline(*P))
559      return 1;
560
561    Printer.printReport(TOF->os());
562
563    // Clear the InstrBuilder internal state in preparation for another round.
564    IB.clear();
565  }
566
567  TOF->keep();
568  return 0;
569}
570