Index: test/tools/llvm-mca/X86/BtVer2/register-files-1.s =================================================================== --- test/tools/llvm-mca/X86/BtVer2/register-files-1.s +++ test/tools/llvm-mca/X86/BtVer2/register-files-1.s @@ -0,0 +1,29 @@ +# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=5 -verbose -timeline < %s | FileCheck %s + +vaddps %xmm0, %xmm0, %xmm0 +vmulps %xmm0, %xmm0, %xmm0 + +# CHECK: Iterations: 5 +# CHECK-NEXT: Instructions: 10 + +# CHECK: Dynamic Dispatch Stall Cycles: +# CHECK-NEXT: RAT - Register unavailable: 0 + +# CHECK: Register File statistics. +# CHECK-NEXT: Register File #0 +# CHECK-NEXT: Total number of mappings created: 10 +# CHECK-NEXT: Max number of mappings used: 10 + +# CHECK: Timeline view: +# CHECK-NEXT: 0123456789 +# CHECK-NEXT: Index 0123456789 01234567 +# CHECK: [0,0] DeeeER . . . . . vaddps %xmm0, %xmm0, %xmm0 +# CHECK-NEXT: [0,1] D===eeER . . . . . vmulps %xmm0, %xmm0, %xmm0 +# CHECK: [1,0] .D====eeeER . . . . vaddps %xmm0, %xmm0, %xmm0 +# CHECK-NEXT: [1,1] .D=======eeER . . . . vmulps %xmm0, %xmm0, %xmm0 +# CHECK: [2,0] . D========eeeER . . . vaddps %xmm0, %xmm0, %xmm0 +# CHECK-NEXT: [2,1] . D===========eeER . . . vmulps %xmm0, %xmm0, %xmm0 +# CHECK: [3,0] . D============eeeER . . vaddps %xmm0, %xmm0, %xmm0 +# CHECK-NEXT: [3,1] . D===============eeER . . vmulps %xmm0, %xmm0, %xmm0 +# CHECK: [4,0] . D================eeeER . vaddps %xmm0, %xmm0, %xmm0 +# CHECK-NEXT: [4,1] . D===================eeER vmulps %xmm0, %xmm0, %xmm0 Index: test/tools/llvm-mca/X86/BtVer2/register-files-2.s =================================================================== --- test/tools/llvm-mca/X86/BtVer2/register-files-2.s +++ test/tools/llvm-mca/X86/BtVer2/register-files-2.s @@ -0,0 +1,29 @@ +# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -register-file-size=5 -iterations=5 -verbose -timeline < %s | FileCheck %s + +vaddps %xmm0, %xmm0, %xmm0 +vmulps %xmm0, %xmm0, %xmm0 + +# CHECK: Iterations: 5 +# CHECK-NEXT: Instructions: 10 + +# CHECK: Dynamic Dispatch Stall Cycles: +# CHECK-NEXT: RAT - Register unavailable: 13 + +# CHECK: Register File statistics. +# CHECK-NEXT: Register File #0 +# CHECK-NEXT: Total number of mappings created: 10 +# CHECK-NEXT: Max number of mappings used: 5 + +# CHECK: Timeline view: +# CHECK-NEXT: 0123456789 +# CHECK-NEXT: Index 0123456789 01234567 +# CHECK: [0,0] DeeeER . . . . . vaddps %xmm0, %xmm0, %xmm0 +# CHECK-NEXT: [0,1] D===eeER . . . . . vmulps %xmm0, %xmm0, %xmm0 +# CHECK: [1,0] .D====eeeER . . . . vaddps %xmm0, %xmm0, %xmm0 +# CHECK-NEXT: [1,1] .D=======eeER . . . . vmulps %xmm0, %xmm0, %xmm0 +# CHECK: [2,0] . D========eeeER . . . vaddps %xmm0, %xmm0, %xmm0 +# CHECK-NEXT: [2,1] . D========eeER . . . vmulps %xmm0, %xmm0, %xmm0 +# CHECK: [3,0] . . D========eeeER . . vaddps %xmm0, %xmm0, %xmm0 +# CHECK-NEXT: [3,1] . . D========eeER . . vmulps %xmm0, %xmm0, %xmm0 +# CHECK: [4,0] . . . D========eeeER . vaddps %xmm0, %xmm0, %xmm0 +# CHECK-NEXT: [4,1] . . . D========eeER vmulps %xmm0, %xmm0, %xmm0 Index: tools/llvm-mca/Backend.h =================================================================== --- tools/llvm-mca/Backend.h +++ tools/llvm-mca/Backend.h @@ -88,12 +88,6 @@ return *It->second; } void eraseInstruction(unsigned Index) { Instructions.erase(Index); } - unsigned getTotalRegisterMappingsCreated() const { - return DU->getTotalRegisterMappingsCreated(); - } - unsigned getMaxUsedRegisterMappings() const { - return DU->getMaxUsedRegisterMappings(); - } void addEventListener(HWEventListener *Listener); void notifyCycleBegin(unsigned Cycle); Index: tools/llvm-mca/BackendStatistics.h =================================================================== --- tools/llvm-mca/BackendStatistics.h +++ tools/llvm-mca/BackendStatistics.h @@ -67,8 +67,6 @@ namespace mca { class BackendStatistics : public View { - // TODO: remove the dependency from Backend. - const Backend &B; const llvm::MCSubtargetInfo &STI; using Histogram = std::map; @@ -105,13 +103,22 @@ NumRetired = 0; } + // Used to track the number of physical registers used in a register file. + struct RegisterFileUsage { + unsigned TotalMappings; + unsigned MaxUsedMappings; + unsigned CurrentlyUsedMappings; + }; + + // There is one entry for each register file implemented by the processor. + llvm::SmallVector RegisterFiles; + void printRetireUnitStatistics(llvm::raw_ostream &OS) const; void printDispatchUnitStatistics(llvm::raw_ostream &OS) const; void printSchedulerStatistics(llvm::raw_ostream &OS) const; void printDispatchStalls(llvm::raw_ostream &OS) const; - void printRATStatistics(llvm::raw_ostream &OS, unsigned Mappings, - unsigned MaxUsedMappings) const; + void printRATStatistics(llvm::raw_ostream &OS) const; void printRCUStatistics(llvm::raw_ostream &OS, const Histogram &Histogram, unsigned Cycles) const; void printDispatchUnitUsage(llvm::raw_ostream &OS, const Histogram &Stats, @@ -122,9 +129,12 @@ const llvm::MCSchedModel &SM) const; public: - BackendStatistics(const Backend &backend, const llvm::MCSubtargetInfo &sti) - : B(backend), STI(sti), NumDispatched(0), NumIssued(0), NumRetired(0), - NumCycles(0), HWStalls(HWStallEvent::LastGenericEvent) {} + BackendStatistics(const llvm::MCSubtargetInfo &sti) + : STI(sti), NumDispatched(0), NumIssued(0), NumRetired(0), + NumCycles(0), HWStalls(HWStallEvent::LastGenericEvent), + // TODO: The view currently assumes a single register file. This will + // change in future. + RegisterFiles(1) {} void onInstructionEvent(const HWInstructionEvent &Event) override; @@ -147,12 +157,10 @@ void printView(llvm::raw_ostream &OS) const override { printDispatchStalls(OS); - printRATStatistics(OS, B.getTotalRegisterMappingsCreated(), - B.getMaxUsedRegisterMappings()); + printRATStatistics(OS); printDispatchUnitStatistics(OS); printSchedulerStatistics(OS); printRetireUnitStatistics(OS); - printSchedulerUsage(OS, STI.getSchedModel()); } }; Index: tools/llvm-mca/BackendStatistics.cpp =================================================================== --- tools/llvm-mca/BackendStatistics.cpp +++ tools/llvm-mca/BackendStatistics.cpp @@ -22,17 +22,32 @@ void BackendStatistics::onInstructionEvent(const HWInstructionEvent &Event) { switch (Event.Type) { - case HWInstructionEvent::Retired: + default: + break; + case HWInstructionEvent::Retired: { + const auto &RE = static_cast(Event); + for (unsigned I = 0, E = RegisterFiles.size(); I < E; ++I) + RegisterFiles[I].CurrentlyUsedMappings -= RE.FreedPhysRegs[I]; + ++NumRetired; break; + } case HWInstructionEvent::Issued: ++NumIssued; break; - case HWInstructionEvent::Dispatched: + case HWInstructionEvent::Dispatched: { + const auto &DE = static_cast(Event); + for (unsigned I = 0, E = RegisterFiles.size(); I < E; ++I) { + RegisterFileUsage &RFU = RegisterFiles[I]; + unsigned NumUsedPhysRegs = DE.UsedPhysRegs[I]; + RFU.CurrentlyUsedMappings += NumUsedPhysRegs; + RFU.TotalMappings += NumUsedPhysRegs; + RFU.MaxUsedMappings = + std::max(RFU.MaxUsedMappings, RFU.CurrentlyUsedMappings); + } + ++NumDispatched; - break; - default: - break; + } } } @@ -115,15 +130,19 @@ OS << Buffer; } -void BackendStatistics::printRATStatistics(raw_ostream &OS, - unsigned TotalMappings, - unsigned MaxUsedMappings) const { +void BackendStatistics::printRATStatistics(raw_ostream &OS) const { std::string Buffer; raw_string_ostream TempStream(Buffer); - TempStream << "\n\nRegister Alias Table:"; - TempStream << "\nTotal number of mappings created: " << TotalMappings; - TempStream << "\nMax number of mappings used: " << MaxUsedMappings - << '\n'; + + TempStream << "\n\nRegister File statistics."; + for (unsigned I = 0, E = RegisterFiles.size(); I < E; ++I) { + const RegisterFileUsage &RFU = RegisterFiles[I]; + TempStream << "\nRegister File #" << I; + TempStream << "\n Total number of mappings created: " << RFU.TotalMappings; + TempStream << "\n Max number of mappings used: " + << RFU.MaxUsedMappings; + } + TempStream.flush(); OS << Buffer; } Index: tools/llvm-mca/Dispatch.h =================================================================== --- tools/llvm-mca/Dispatch.h +++ tools/llvm-mca/Dispatch.h @@ -43,14 +43,9 @@ const unsigned TotalMappings; // Number of mappings that are currently in use. unsigned NumUsedMappings; - // Maximum number of register mappings used. - unsigned MaxUsedMappings; - // Total number of mappings allocated during the entire execution. - unsigned TotalMappingsCreated; RegisterMappingTracker(unsigned NumMappings) - : TotalMappings(NumMappings), NumUsedMappings(0), MaxUsedMappings(0), - TotalMappingsCreated(0) {} + : TotalMappings(NumMappings), NumUsedMappings(0) {} }; // This is where information related to the various register files is kept. @@ -105,11 +100,13 @@ // Allocates a new register mapping in every register file specified by the // register file mask. This method is called from addRegisterMapping. - void createNewMappings(unsigned RegisterFileMask); + void createNewMappings(unsigned RegisterFileMask, + llvm::MutableArrayRef UsedPhysRegs); // Removes a previously allocated mapping from each register file in the // RegisterFileMask set. This method is called from invalidateRegisterMapping. - void removeMappings(unsigned RegisterFileMask); + void removeMappings(unsigned RegisterFileMask, + llvm::MutableArrayRef FreedPhysRegs); public: RegisterFile(const llvm::MCRegisterInfo &mri, unsigned TempRegs = 0) @@ -121,12 +118,14 @@ // Creates a new register mapping for RegID. // This reserves a microarchitectural register in every register file that // contains RegID. - void addRegisterMapping(WriteState &WS); + void addRegisterMapping(WriteState &WS, + llvm::MutableArrayRef UsedPhysRegs); // Invalidates register mappings associated to the input WriteState object. // This releases previously allocated mappings for the physical register // associated to the WriteState. - void invalidateRegisterMapping(const WriteState &WS); + void invalidateRegisterMapping(const WriteState &WS, + llvm::MutableArrayRef FreedPhysRegs); // Checks if there are enough microarchitectural registers in the register // files. Returns a "response mask" where each bit is the response from a @@ -138,16 +137,7 @@ void collectWrites(llvm::SmallVectorImpl &Writes, unsigned RegID) const; void updateOnRead(ReadState &RS, unsigned RegID); - unsigned getMaxUsedRegisterMappings(unsigned RegisterFileIndex) const { - assert(RegisterFileIndex < getNumRegisterFiles() && - "Invalid register file index!"); - return RegisterFiles[RegisterFileIndex].MaxUsedMappings; - } - unsigned getTotalRegisterMappingsCreated(unsigned RegisterFileIndex) const { - assert(RegisterFileIndex < getNumRegisterFiles() && - "Invalid register file index!"); - return RegisterFiles[RegisterFileIndex].TotalMappingsCreated; - } + unsigned getNumRegisterFiles() const { return RegisterFiles.size(); } #ifndef NDEBUG @@ -260,7 +250,7 @@ bool checkScheduler(unsigned Index, const InstrDesc &Desc); void updateRAWDependencies(ReadState &RS, const llvm::MCSubtargetInfo &STI); - void notifyInstructionDispatched(unsigned IID); + void notifyInstructionDispatched(unsigned IID, llvm::ArrayRef UsedPhysRegs); public: DispatchUnit(Backend *B, const llvm::MCRegisterInfo &MRI, @@ -296,12 +286,6 @@ unsigned RegID) const { return RAT->collectWrites(Vec, RegID); } - unsigned getMaxUsedRegisterMappings(unsigned RegFileIndex = 0) const { - return RAT->getMaxUsedRegisterMappings(RegFileIndex); - } - unsigned getTotalRegisterMappingsCreated(unsigned RegFileIndex = 0) const { - return RAT->getTotalRegisterMappingsCreated(RegFileIndex); - } void cycleEvent(unsigned Cycle) { RCU->cycleEvent(); Index: tools/llvm-mca/Dispatch.cpp =================================================================== --- tools/llvm-mca/Dispatch.cpp +++ tools/llvm-mca/Dispatch.cpp @@ -45,7 +45,8 @@ } } -void RegisterFile::createNewMappings(unsigned RegisterFileMask) { +void RegisterFile::createNewMappings(unsigned RegisterFileMask, + MutableArrayRef UsedPhysRegs) { assert(RegisterFileMask && "RegisterFileMask cannot be zero!"); // Notify each register file that contains RegID. do { @@ -53,13 +54,13 @@ unsigned RegisterFileIndex = llvm::countTrailingZeros(NextRegisterFile); RegisterMappingTracker &RMT = RegisterFiles[RegisterFileIndex]; RMT.NumUsedMappings++; - RMT.MaxUsedMappings = std::max(RMT.MaxUsedMappings, RMT.NumUsedMappings); - RMT.TotalMappingsCreated++; + UsedPhysRegs[RegisterFileIndex]++; RegisterFileMask ^= NextRegisterFile; } while (RegisterFileMask); } -void RegisterFile::removeMappings(unsigned RegisterFileMask) { +void RegisterFile::removeMappings(unsigned RegisterFileMask, + MutableArrayRef FreedPhysRegs) { assert(RegisterFileMask && "RegisterFileMask cannot be zero!"); // Notify each register file that contains RegID. do { @@ -68,11 +69,13 @@ RegisterMappingTracker &RMT = RegisterFiles[RegisterFileIndex]; assert(RMT.NumUsedMappings); RMT.NumUsedMappings--; + FreedPhysRegs[RegisterFileIndex]++; RegisterFileMask ^= NextRegisterFile; } while (RegisterFileMask); } -void RegisterFile::addRegisterMapping(WriteState &WS) { +void RegisterFile::addRegisterMapping(WriteState &WS, + MutableArrayRef UsedPhysRegs) { unsigned RegID = WS.getRegisterID(); assert(RegID && "Adding an invalid register definition?"); @@ -81,7 +84,8 @@ for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) RegisterMappings[*I].first = &WS; - createNewMappings(Mapping.second); + createNewMappings(Mapping.second, UsedPhysRegs); + // If this is a partial update, then we are done. if (!WS.fullyUpdatesSuperRegs()) return; @@ -90,7 +94,8 @@ RegisterMappings[*I].first = &WS; } -void RegisterFile::invalidateRegisterMapping(const WriteState &WS) { +void RegisterFile::invalidateRegisterMapping( + const WriteState &WS, MutableArrayRef FreedPhysRegs) { unsigned RegID = WS.getRegisterID(); bool ShouldInvalidateSuperRegs = WS.fullyUpdatesSuperRegs(); @@ -102,7 +107,7 @@ if (!Mapping.first) return; - removeMappings(Mapping.second); + removeMappings(Mapping.second, FreedPhysRegs); if (Mapping.first == &WS) Mapping.first = nullptr; @@ -196,8 +201,6 @@ dbgs() << "Register File #" << I; const RegisterMappingTracker &RMT = RegisterFiles[I]; dbgs() << "\n TotalMappings: " << RMT.TotalMappings - << "\n TotalMappingsCreated: " << RMT.TotalMappingsCreated - << "\n MaxUsedMappings: " << RMT.MaxUsedMappings << "\n NumUsedMappings: " << RMT.NumUsedMappings << '\n'; } } @@ -220,21 +223,20 @@ return TokenID; } -void DispatchUnit::notifyInstructionDispatched(unsigned Index) { +void DispatchUnit::notifyInstructionDispatched( + unsigned Index, ArrayRef UsedRegs) { DEBUG(dbgs() << "[E] Instruction Dispatched: " << Index << '\n'); - Owner->notifyInstructionEvent( - HWInstructionEvent(HWInstructionEvent::Dispatched, Index)); + Owner->notifyInstructionEvent(HWInstructionDispatchedEvent(Index, UsedRegs)); } void DispatchUnit::notifyInstructionRetired(unsigned Index) { DEBUG(dbgs() << "[E] Instruction Retired: " << Index << '\n'); - Owner->notifyInstructionEvent( - HWInstructionEvent(HWInstructionEvent::Retired, Index)); - const Instruction &IS = Owner->getInstruction(Index); + SmallVector FreedRegs(RAT->getNumRegisterFiles()); for (const std::unique_ptr &WS : IS.getDefs()) - RAT->invalidateRegisterMapping(*WS.get()); + RAT->invalidateRegisterMapping(*WS.get(), FreedRegs); + Owner->notifyInstructionEvent(HWInstructionRetiredEvent(Index, FreedRegs)); Owner->eraseInstruction(Index); } @@ -364,8 +366,9 @@ updateRAWDependencies(*RS, STI); // Allocate new mappings. + SmallVector RegisterFiles(RAT->getNumRegisterFiles()); for (std::unique_ptr &WS : NewInst->getDefs()) - RAT->addRegisterMapping(*WS); + RAT->addRegisterMapping(*WS, RegisterFiles); // Set the cycles left before the write-back stage. const InstrDesc &D = NewInst->getDesc(); @@ -374,7 +377,7 @@ // Reserve slots in the RCU. unsigned RCUTokenID = RCU->reserveSlot(IID, NumMicroOps); NewInst->setRCUTokenID(RCUTokenID); - notifyInstructionDispatched(IID); + notifyInstructionDispatched(IID, RegisterFiles); SC->scheduleInstruction(IID, *NewInst); return RCUTokenID; Index: tools/llvm-mca/HWEventListener.h =================================================================== --- tools/llvm-mca/HWEventListener.h +++ tools/llvm-mca/HWEventListener.h @@ -68,6 +68,26 @@ llvm::ArrayRef> UsedResources; }; +class HWInstructionDispatchedEvent : public HWInstructionEvent { +public: + HWInstructionDispatchedEvent(unsigned Index, llvm::ArrayRef Regs) + : HWInstructionEvent(HWInstructionEvent::Dispatched, Index), + UsedPhysRegs(Regs) {} + // Number of physical register allocated for this instruction. There is one + // entry per register file. + llvm::ArrayRef UsedPhysRegs; +}; + +class HWInstructionRetiredEvent : public HWInstructionEvent { +public: + HWInstructionRetiredEvent(unsigned Index, llvm::ArrayRef Regs) + : HWInstructionEvent(HWInstructionEvent::Retired, Index), + FreedPhysRegs(Regs) {} + // Number of register writes that have been architecturally committed. There + // is one entry per register file. + llvm::ArrayRef FreedPhysRegs; +}; + // A HWStallEvent represents a pipeline stall caused by the lack of hardware // resources. class HWStallEvent { Index: tools/llvm-mca/llvm-mca.cpp =================================================================== --- tools/llvm-mca/llvm-mca.cpp +++ tools/llvm-mca/llvm-mca.cpp @@ -330,7 +330,7 @@ if (PrintModeVerbose) { std::unique_ptr BS = - llvm::make_unique(*B, *STI); + llvm::make_unique(*STI); Printer->addView(std::move(BS)); }