1 //===-- llvm-mca.cpp - Machine Code Analyzer -------------------*- C++ -* -===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This utility is a simple driver that allows static performance analysis on 11 // machine code similarly to how IACA (Intel Architecture Code Analyzer) works. 12 // 13 // llvm-mca [options] <file-name> 14 // -march <type> 15 // -mcpu <cpu> 16 // -o <file> 17 // 18 // The target defaults to the host target. 19 // The cpu defaults to the 'native' host cpu. 20 // The output defaults to standard output. 21 // 22 //===----------------------------------------------------------------------===// 23 24 #include "BackendPrinter.h" 25 #include "CodeRegion.h" 26 #include "DispatchStage.h" 27 #include "DispatchStatistics.h" 28 #include "ExecuteStage.h" 29 #include "FetchStage.h" 30 #include "InstructionInfoView.h" 31 #include "InstructionTables.h" 32 #include "RegisterFile.h" 33 #include "RegisterFileStatistics.h" 34 #include "ResourcePressureView.h" 35 #include "RetireControlUnit.h" 36 #include "RetireControlUnitStatistics.h" 37 #include "RetireStage.h" 38 #include "Scheduler.h" 39 #include "SchedulerStatistics.h" 40 #include "SummaryView.h" 41 #include "TimelineView.h" 42 #include "llvm/MC/MCAsmInfo.h" 43 #include "llvm/MC/MCContext.h" 44 #include "llvm/MC/MCObjectFileInfo.h" 45 #include "llvm/MC/MCParser/MCTargetAsmParser.h" 46 #include "llvm/MC/MCRegisterInfo.h" 47 #include "llvm/MC/MCStreamer.h" 48 #include "llvm/Support/CommandLine.h" 49 #include "llvm/Support/ErrorOr.h" 50 #include "llvm/Support/FileSystem.h" 51 #include "llvm/Support/Host.h" 52 #include "llvm/Support/InitLLVM.h" 53 #include "llvm/Support/MemoryBuffer.h" 54 #include "llvm/Support/SourceMgr.h" 55 #include "llvm/Support/TargetRegistry.h" 56 #include "llvm/Support/TargetSelect.h" 57 #include "llvm/Support/ToolOutputFile.h" 58 #include "llvm/Support/WithColor.h" 59 60 using namespace llvm; 61 62 static cl::OptionCategory ToolOptions("Tool Options"); 63 static cl::OptionCategory ViewOptions("View Options"); 64 65 static cl::opt<std::string> InputFilename(cl::Positional, 66 cl::desc("<input file>"), 67 cl::cat(ToolOptions), cl::init("-")); 68 69 static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"), 70 cl::init("-"), cl::cat(ToolOptions), 71 cl::value_desc("filename")); 72 73 static cl::opt<std::string> 74 ArchName("march", cl::desc("Target arch to assemble for, " 75 "see -version for available targets"), 76 cl::cat(ToolOptions)); 77 78 static cl::opt<std::string> 79 TripleName("mtriple", cl::desc("Target triple to assemble for, " 80 "see -version for available targets"), 81 cl::cat(ToolOptions)); 82 83 static cl::opt<std::string> 84 MCPU("mcpu", 85 cl::desc("Target a specific cpu type (-mcpu=help for details)"), 86 cl::value_desc("cpu-name"), cl::cat(ToolOptions), cl::init("native")); 87 88 static cl::opt<int> 89 OutputAsmVariant("output-asm-variant", 90 cl::desc("Syntax variant to use for output printing"), 91 cl::cat(ToolOptions), cl::init(-1)); 92 93 static cl::opt<unsigned> Iterations("iterations", 94 cl::desc("Number of iterations to run"), 95 cl::cat(ToolOptions), cl::init(0)); 96 97 static cl::opt<unsigned> 98 DispatchWidth("dispatch", cl::desc("Override the processor dispatch width"), 99 cl::cat(ToolOptions), cl::init(0)); 100 101 static cl::opt<unsigned> 102 RegisterFileSize("register-file-size", 103 cl::desc("Maximum number of temporary registers which can " 104 "be used for register mappings"), 105 cl::cat(ToolOptions), cl::init(0)); 106 107 static cl::opt<bool> 108 PrintRegisterFileStats("register-file-stats", 109 cl::desc("Print register file statistics"), 110 cl::cat(ViewOptions), cl::init(false)); 111 112 static cl::opt<bool> PrintDispatchStats("dispatch-stats", 113 cl::desc("Print dispatch statistics"), 114 cl::cat(ViewOptions), cl::init(false)); 115 116 static cl::opt<bool> 117 PrintSummaryView("summary-view", cl::Hidden, 118 cl::desc("Print summary view (enabled by default)"), 119 cl::cat(ViewOptions), cl::init(true)); 120 121 static cl::opt<bool> PrintSchedulerStats("scheduler-stats", 122 cl::desc("Print scheduler statistics"), 123 cl::cat(ViewOptions), cl::init(false)); 124 125 static cl::opt<bool> 126 PrintRetireStats("retire-stats", 127 cl::desc("Print retire control unit statistics"), 128 cl::cat(ViewOptions), cl::init(false)); 129 130 static cl::opt<bool> PrintResourcePressureView( 131 "resource-pressure", 132 cl::desc("Print the resource pressure view (enabled by default)"), 133 cl::cat(ViewOptions), cl::init(true)); 134 135 static cl::opt<bool> PrintTimelineView("timeline", 136 cl::desc("Print the timeline view"), 137 cl::cat(ViewOptions), cl::init(false)); 138 139 static cl::opt<unsigned> TimelineMaxIterations( 140 "timeline-max-iterations", 141 cl::desc("Maximum number of iterations to print in timeline view"), 142 cl::cat(ViewOptions), cl::init(0)); 143 144 static cl::opt<unsigned> TimelineMaxCycles( 145 "timeline-max-cycles", 146 cl::desc( 147 "Maximum number of cycles in the timeline view. Defaults to 80 cycles"), 148 cl::cat(ViewOptions), cl::init(80)); 149 150 static cl::opt<bool> 151 AssumeNoAlias("noalias", 152 cl::desc("If set, assume that loads and stores do not alias"), 153 cl::cat(ToolOptions), cl::init(true)); 154 155 static cl::opt<unsigned> 156 LoadQueueSize("lqueue", 157 cl::desc("Size of the load queue (unbound by default)"), 158 cl::cat(ToolOptions), cl::init(0)); 159 160 static cl::opt<unsigned> 161 StoreQueueSize("squeue", 162 cl::desc("Size of the store queue (unbound by default)"), 163 cl::cat(ToolOptions), cl::init(0)); 164 165 static cl::opt<bool> 166 PrintInstructionTables("instruction-tables", 167 cl::desc("Print instruction tables"), 168 cl::cat(ToolOptions), cl::init(false)); 169 170 static cl::opt<bool> PrintInstructionInfoView( 171 "instruction-info", 172 cl::desc("Print the instruction info view (enabled by default)"), 173 cl::cat(ViewOptions), cl::init(true)); 174 175 static cl::opt<bool> EnableAllStats("all-stats", 176 cl::desc("Print all hardware statistics"), 177 cl::cat(ViewOptions), cl::init(false)); 178 179 static cl::opt<bool> 180 EnableAllViews("all-views", 181 cl::desc("Print all views including hardware statistics"), 182 cl::cat(ViewOptions), cl::init(false)); 183 184 namespace { 185 186 const Target *getTarget(const char *ProgName) { 187 TripleName = Triple::normalize(TripleName); 188 if (TripleName.empty()) 189 TripleName = Triple::normalize(sys::getDefaultTargetTriple()); 190 Triple TheTriple(TripleName); 191 192 // Get the target specific parser. 193 std::string Error; 194 const Target *TheTarget = 195 TargetRegistry::lookupTarget(ArchName, TheTriple, Error); 196 if (!TheTarget) { 197 errs() << ProgName << ": " << Error; 198 return nullptr; 199 } 200 201 // Return the found target. 202 return TheTarget; 203 } 204 205 // A comment consumer that parses strings. 206 // The only valid tokens are strings. 207 class MCACommentConsumer : public AsmCommentConsumer { 208 public: 209 mca::CodeRegions &Regions; 210 211 MCACommentConsumer(mca::CodeRegions &R) : Regions(R) {} 212 void HandleComment(SMLoc Loc, StringRef CommentText) override { 213 // Skip empty comments. 214 StringRef Comment(CommentText); 215 if (Comment.empty()) 216 return; 217 218 // Skip spaces and tabs 219 unsigned Position = Comment.find_first_not_of(" \t"); 220 if (Position >= Comment.size()) 221 // we reached the end of the comment. Bail out. 222 return; 223 224 Comment = Comment.drop_front(Position); 225 if (Comment.consume_front("LLVM-MCA-END")) { 226 Regions.endRegion(Loc); 227 return; 228 } 229 230 // Now try to parse string LLVM-MCA-BEGIN 231 if (!Comment.consume_front("LLVM-MCA-BEGIN")) 232 return; 233 234 // Skip spaces and tabs 235 Position = Comment.find_first_not_of(" \t"); 236 if (Position < Comment.size()) 237 Comment = Comment.drop_front(Position); 238 // Use the rest of the string as a descriptor for this code snippet. 239 Regions.beginRegion(Comment, Loc); 240 } 241 }; 242 243 int AssembleInput(const char *ProgName, MCAsmParser &Parser, 244 const Target *TheTarget, MCSubtargetInfo &STI, 245 MCInstrInfo &MCII, MCTargetOptions &MCOptions) { 246 std::unique_ptr<MCTargetAsmParser> TAP( 247 TheTarget->createMCAsmParser(STI, Parser, MCII, MCOptions)); 248 249 if (!TAP) { 250 WithColor::error() << "this target does not support assembly parsing.\n"; 251 return 1; 252 } 253 254 Parser.setTargetParser(*TAP); 255 return Parser.Run(false); 256 } 257 258 ErrorOr<std::unique_ptr<ToolOutputFile>> getOutputStream() { 259 if (OutputFilename == "") 260 OutputFilename = "-"; 261 std::error_code EC; 262 auto Out = 263 llvm::make_unique<ToolOutputFile>(OutputFilename, EC, sys::fs::F_None); 264 if (!EC) 265 return std::move(Out); 266 return EC; 267 } 268 269 class MCStreamerWrapper final : public MCStreamer { 270 mca::CodeRegions &Regions; 271 272 public: 273 MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R) 274 : MCStreamer(Context), Regions(R) {} 275 276 // We only want to intercept the emission of new instructions. 277 virtual void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, 278 bool /* unused */) override { 279 Regions.addInstruction(llvm::make_unique<const MCInst>(Inst)); 280 } 281 282 bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { 283 return true; 284 } 285 286 void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, 287 unsigned ByteAlignment) override {} 288 void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, 289 uint64_t Size = 0, unsigned ByteAlignment = 0) override {} 290 void EmitGPRel32Value(const MCExpr *Value) override {} 291 void BeginCOFFSymbolDef(const MCSymbol *Symbol) override {} 292 void EmitCOFFSymbolStorageClass(int StorageClass) override {} 293 void EmitCOFFSymbolType(int Type) override {} 294 void EndCOFFSymbolDef() override {} 295 296 const std::vector<std::unique_ptr<const MCInst>> & 297 GetInstructionSequence(unsigned Index) const { 298 return Regions.getInstructionSequence(Index); 299 } 300 }; 301 } // end of anonymous namespace 302 303 static void processOptionImpl(cl::opt<bool> &O, const cl::opt<bool> &Default) { 304 if (!O.getNumOccurrences() || O.getPosition() < Default.getPosition()) 305 O = Default.getValue(); 306 } 307 308 static void processViewOptions() { 309 if (!EnableAllViews.getNumOccurrences() && 310 !EnableAllStats.getNumOccurrences()) 311 return; 312 313 if (EnableAllViews.getNumOccurrences()) { 314 processOptionImpl(PrintSummaryView, EnableAllViews); 315 processOptionImpl(PrintResourcePressureView, EnableAllViews); 316 processOptionImpl(PrintTimelineView, EnableAllViews); 317 processOptionImpl(PrintInstructionInfoView, EnableAllViews); 318 } 319 320 const cl::opt<bool> &Default = 321 EnableAllViews.getPosition() < EnableAllStats.getPosition() 322 ? EnableAllStats 323 : EnableAllViews; 324 processOptionImpl(PrintSummaryView, Default); 325 processOptionImpl(PrintRegisterFileStats, Default); 326 processOptionImpl(PrintDispatchStats, Default); 327 processOptionImpl(PrintSchedulerStats, Default); 328 processOptionImpl(PrintRetireStats, Default); 329 } 330 331 int main(int argc, char **argv) { 332 InitLLVM X(argc, argv); 333 334 // Initialize targets and assembly parsers. 335 llvm::InitializeAllTargetInfos(); 336 llvm::InitializeAllTargetMCs(); 337 llvm::InitializeAllAsmParsers(); 338 339 // Enable printing of available targets when flag --version is specified. 340 cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); 341 342 cl::HideUnrelatedOptions({&ToolOptions, &ViewOptions}); 343 344 // Parse flags and initialize target options. 345 cl::ParseCommandLineOptions(argc, argv, 346 "llvm machine code performance analyzer.\n"); 347 348 MCTargetOptions MCOptions; 349 MCOptions.PreserveAsmComments = false; 350 351 // Get the target from the triple. If a triple is not specified, then select 352 // the default triple for the host. If the triple doesn't correspond to any 353 // registered target, then exit with an error message. 354 const char *ProgName = argv[0]; 355 const Target *TheTarget = getTarget(ProgName); 356 if (!TheTarget) 357 return 1; 358 359 // GetTarget() may replaced TripleName with a default triple. 360 // For safety, reconstruct the Triple object. 361 Triple TheTriple(TripleName); 362 363 ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr = 364 MemoryBuffer::getFileOrSTDIN(InputFilename); 365 if (std::error_code EC = BufferPtr.getError()) { 366 WithColor::error() << InputFilename << ": " << EC.message() << '\n'; 367 return 1; 368 } 369 370 // Apply overrides to llvm-mca specific options. 371 processViewOptions(); 372 373 SourceMgr SrcMgr; 374 375 // Tell SrcMgr about this buffer, which is what the parser will pick up. 376 SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc()); 377 378 std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); 379 assert(MRI && "Unable to create target register info!"); 380 381 std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); 382 assert(MAI && "Unable to create target asm info!"); 383 384 MCObjectFileInfo MOFI; 385 MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr); 386 MOFI.InitMCObjectFileInfo(TheTriple, /* PIC= */ false, Ctx); 387 388 std::unique_ptr<buffer_ostream> BOS; 389 390 mca::CodeRegions Regions(SrcMgr); 391 MCStreamerWrapper Str(Ctx, Regions); 392 393 std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo()); 394 395 std::unique_ptr<MCInstrAnalysis> MCIA( 396 TheTarget->createMCInstrAnalysis(MCII.get())); 397 398 if (!MCPU.compare("native")) 399 MCPU = llvm::sys::getHostCPUName(); 400 401 std::unique_ptr<MCSubtargetInfo> STI( 402 TheTarget->createMCSubtargetInfo(TripleName, MCPU, /* FeaturesStr */ "")); 403 if (!STI->isCPUStringValid(MCPU)) 404 return 1; 405 406 if (!PrintInstructionTables && !STI->getSchedModel().isOutOfOrder()) { 407 WithColor::error() << "please specify an out-of-order cpu. '" << MCPU 408 << "' is an in-order cpu.\n"; 409 return 1; 410 } 411 412 if (!STI->getSchedModel().hasInstrSchedModel()) { 413 WithColor::error() 414 << "unable to find instruction-level scheduling information for" 415 << " target triple '" << TheTriple.normalize() << "' and cpu '" << MCPU 416 << "'.\n"; 417 418 if (STI->getSchedModel().InstrItineraries) 419 WithColor::note() 420 << "cpu '" << MCPU << "' provides itineraries. However, " 421 << "instruction itineraries are currently unsupported.\n"; 422 return 1; 423 } 424 425 std::unique_ptr<MCAsmParser> P(createMCAsmParser(SrcMgr, Ctx, Str, *MAI)); 426 MCAsmLexer &Lexer = P->getLexer(); 427 MCACommentConsumer CC(Regions); 428 Lexer.setCommentConsumer(&CC); 429 430 if (AssembleInput(ProgName, *P, TheTarget, *STI, *MCII, MCOptions)) 431 return 1; 432 433 if (Regions.empty()) { 434 WithColor::error() << "no assembly instructions found.\n"; 435 return 1; 436 } 437 438 // Now initialize the output file. 439 auto OF = getOutputStream(); 440 if (std::error_code EC = OF.getError()) { 441 WithColor::error() << EC.message() << '\n'; 442 return 1; 443 } 444 445 unsigned AssemblerDialect = P->getAssemblerDialect(); 446 if (OutputAsmVariant >= 0) 447 AssemblerDialect = static_cast<unsigned>(OutputAsmVariant); 448 std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter( 449 Triple(TripleName), AssemblerDialect, *MAI, *MCII, *MRI)); 450 if (!IP) { 451 WithColor::error() 452 << "unable to create instruction printer for target triple '" 453 << TheTriple.normalize() << "' with assembly variant " 454 << AssemblerDialect << ".\n"; 455 return 1; 456 } 457 458 std::unique_ptr<llvm::ToolOutputFile> TOF = std::move(*OF); 459 460 const MCSchedModel &SM = STI->getSchedModel(); 461 462 unsigned Width = SM.IssueWidth; 463 if (DispatchWidth) 464 Width = DispatchWidth; 465 466 // Create an instruction builder. 467 mca::InstrBuilder IB(*STI, *MCII, *MRI, *MCIA); 468 469 // Number each region in the sequence. 470 unsigned RegionIdx = 0; 471 for (const std::unique_ptr<mca::CodeRegion> &Region : Regions) { 472 // Skip empty code regions. 473 if (Region->empty()) 474 continue; 475 476 // Don't print the header of this region if it is the default region, and 477 // it doesn't have an end location. 478 if (Region->startLoc().isValid() || Region->endLoc().isValid()) { 479 TOF->os() << "\n[" << RegionIdx++ << "] Code Region"; 480 StringRef Desc = Region->getDescription(); 481 if (!Desc.empty()) 482 TOF->os() << " - " << Desc; 483 TOF->os() << "\n\n"; 484 } 485 486 mca::SourceMgr S(Region->getInstructions(), 487 PrintInstructionTables ? 1 : Iterations); 488 489 if (PrintInstructionTables) { 490 mca::InstructionTables IT(SM, IB, S); 491 492 if (PrintInstructionInfoView) { 493 IT.addView( 494 llvm::make_unique<mca::InstructionInfoView>(*STI, *MCII, S, *IP)); 495 } 496 497 IT.addView(llvm::make_unique<mca::ResourcePressureView>(*STI, *IP, S)); 498 IT.run(); 499 IT.printReport(TOF->os()); 500 continue; 501 } 502 503 // Create the hardware components required for the pipeline. 504 mca::RetireControlUnit RCU(SM); 505 mca::RegisterFile PRF(SM, *MRI, RegisterFileSize); 506 mca::Scheduler HWS(SM, LoadQueueSize, StoreQueueSize, AssumeNoAlias); 507 508 // Create the pipeline and add stages to it. 509 auto B = llvm::make_unique<mca::Backend>( 510 Width, RegisterFileSize, LoadQueueSize, StoreQueueSize, AssumeNoAlias); 511 B->appendStage(llvm::make_unique<mca::FetchStage>(IB, S)); 512 B->appendStage(llvm::make_unique<mca::DispatchStage>( 513 B.get(), *STI, *MRI, RegisterFileSize, Width, RCU, PRF, HWS)); 514 B->appendStage(llvm::make_unique<mca::RetireStage>(B.get(), RCU, PRF)); 515 B->appendStage(llvm::make_unique<mca::ExecuteStage>(B.get(), RCU, HWS)); 516 mca::BackendPrinter Printer(*B); 517 518 if (PrintSummaryView) 519 Printer.addView(llvm::make_unique<mca::SummaryView>(SM, S, Width)); 520 521 if (PrintInstructionInfoView) 522 Printer.addView( 523 llvm::make_unique<mca::InstructionInfoView>(*STI, *MCII, S, *IP)); 524 525 if (PrintDispatchStats) 526 Printer.addView(llvm::make_unique<mca::DispatchStatistics>()); 527 528 if (PrintSchedulerStats) 529 Printer.addView(llvm::make_unique<mca::SchedulerStatistics>(*STI)); 530 531 if (PrintRetireStats) 532 Printer.addView(llvm::make_unique<mca::RetireControlUnitStatistics>()); 533 534 if (PrintRegisterFileStats) 535 Printer.addView(llvm::make_unique<mca::RegisterFileStatistics>(*STI)); 536 537 if (PrintResourcePressureView) 538 Printer.addView( 539 llvm::make_unique<mca::ResourcePressureView>(*STI, *IP, S)); 540 541 if (PrintTimelineView) { 542 Printer.addView(llvm::make_unique<mca::TimelineView>( 543 *STI, *IP, S, TimelineMaxIterations, TimelineMaxCycles)); 544 } 545 546 B->run(); 547 Printer.printReport(TOF->os()); 548 } 549 550 TOF->keep(); 551 return 0; 552 } 553