//===--------------------- RegisterFileStatistics.cpp -----------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// \file /// /// This file implements the RegisterFileStatistics interface. /// //===----------------------------------------------------------------------===// #include "Views/RegisterFileStatistics.h" #include "llvm/Support/Format.h" namespace llvm { namespace mca { RegisterFileStatistics::RegisterFileStatistics(const MCSubtargetInfo &sti) : STI(sti) { const MCSchedModel &SM = STI.getSchedModel(); RegisterFileUsage RFUEmpty = {0, 0, 0}; MoveEliminationInfo MEIEmpty = {0, 0, 0, 0, 0}; if (!SM.hasExtraProcessorInfo()) { // Assume a single register file. PRFUsage.emplace_back(RFUEmpty); MoveElimInfo.emplace_back(MEIEmpty); return; } // Initialize a RegisterFileUsage for every user defined register file, plus // the default register file which is always at index #0. const MCExtraProcessorInfo &PI = SM.getExtraProcessorInfo(); // There is always an "InvalidRegisterFile" entry in tablegen. That entry can // be skipped. If there are no user defined register files, then reserve a // single entry for the default register file at index #0. unsigned NumRegFiles = std::max(PI.NumRegisterFiles, 1U); PRFUsage.resize(NumRegFiles); std::fill(PRFUsage.begin(), PRFUsage.end(), RFUEmpty); MoveElimInfo.resize(NumRegFiles); std::fill(MoveElimInfo.begin(), MoveElimInfo.end(), MEIEmpty); } void RegisterFileStatistics::updateRegisterFileUsage( ArrayRef UsedPhysRegs) { for (unsigned I = 0, E = PRFUsage.size(); I < E; ++I) { RegisterFileUsage &RFU = PRFUsage[I]; unsigned NumUsedPhysRegs = UsedPhysRegs[I]; RFU.CurrentlyUsedMappings += NumUsedPhysRegs; RFU.TotalMappings += NumUsedPhysRegs; RFU.MaxUsedMappings = std::max(RFU.MaxUsedMappings, RFU.CurrentlyUsedMappings); } } void RegisterFileStatistics::updateMoveElimInfo(const Instruction &Inst) { if (!Inst.isOptimizableMove()) return; assert(Inst.getDefs().size() == 1 && "Expected a single definition!"); assert(Inst.getUses().size() == 1 && "Expected a single register use!"); const WriteState &WS = Inst.getDefs()[0]; const ReadState &RS = Inst.getUses()[0]; MoveEliminationInfo &Info = MoveElimInfo[Inst.getDefs()[0].getRegisterFileID()]; Info.TotalMoveEliminationCandidates++; if (WS.isEliminated()) Info.CurrentMovesEliminated++; if (WS.isWriteZero() && RS.isReadZero()) Info.TotalMovesThatPropagateZero++; } void RegisterFileStatistics::onEvent(const HWInstructionEvent &Event) { switch (Event.Type) { default: break; case HWInstructionEvent::Retired: { const auto &RE = static_cast(Event); for (unsigned I = 0, E = PRFUsage.size(); I < E; ++I) PRFUsage[I].CurrentlyUsedMappings -= RE.FreedPhysRegs[I]; break; } case HWInstructionEvent::Dispatched: { const auto &DE = static_cast(Event); updateRegisterFileUsage(DE.UsedPhysRegs); updateMoveElimInfo(*DE.IR.getInstruction()); } } } void RegisterFileStatistics::onCycleEnd() { for (MoveEliminationInfo &MEI : MoveElimInfo) { unsigned &CurrentMax = MEI.MaxMovesEliminatedPerCycle; CurrentMax = std::max(CurrentMax, MEI.CurrentMovesEliminated); MEI.TotalMovesEliminated += MEI.CurrentMovesEliminated; MEI.CurrentMovesEliminated = 0; } } void RegisterFileStatistics::printView(raw_ostream &OS) const { std::string Buffer; raw_string_ostream TempStream(Buffer); TempStream << "\n\nRegister File statistics:"; const RegisterFileUsage &GlobalUsage = PRFUsage[0]; TempStream << "\nTotal number of mappings created: " << GlobalUsage.TotalMappings; TempStream << "\nMax number of mappings used: " << GlobalUsage.MaxUsedMappings << '\n'; for (unsigned I = 1, E = PRFUsage.size(); I < E; ++I) { const RegisterFileUsage &RFU = PRFUsage[I]; // Obtain the register file descriptor from the scheduling model. assert(STI.getSchedModel().hasExtraProcessorInfo() && "Unable to find register file info!"); const MCExtraProcessorInfo &PI = STI.getSchedModel().getExtraProcessorInfo(); assert(I <= PI.NumRegisterFiles && "Unexpected register file index!"); const MCRegisterFileDesc &RFDesc = PI.RegisterFiles[I]; // Skip invalid register files. if (!RFDesc.NumPhysRegs) continue; TempStream << "\n* Register File #" << I; TempStream << " -- " << StringRef(RFDesc.Name) << ':'; TempStream << "\n Number of physical registers: "; if (!RFDesc.NumPhysRegs) TempStream << "unbounded"; else TempStream << RFDesc.NumPhysRegs; TempStream << "\n Total number of mappings created: " << RFU.TotalMappings; TempStream << "\n Max number of mappings used: " << RFU.MaxUsedMappings << '\n'; const MoveEliminationInfo &MEI = MoveElimInfo[I]; if (MEI.TotalMoveEliminationCandidates) { TempStream << " Number of optimizable moves: " << MEI.TotalMoveEliminationCandidates; double EliminatedMovProportion = (double)MEI.TotalMovesEliminated / MEI.TotalMoveEliminationCandidates * 100.0; double ZeroMovProportion = (double)MEI.TotalMovesThatPropagateZero / MEI.TotalMoveEliminationCandidates * 100.0; TempStream << "\n Number of moves eliminated: " << MEI.TotalMovesEliminated << " " << format("(%.1f%%)", floor((EliminatedMovProportion * 10) + 0.5) / 10); TempStream << "\n Number of zero moves: " << MEI.TotalMovesThatPropagateZero << " " << format("(%.1f%%)", floor((ZeroMovProportion * 10) + 0.5) / 10); TempStream << "\n Max moves eliminated per cycle: " << MEI.MaxMovesEliminatedPerCycle << '\n'; } } TempStream.flush(); OS << Buffer; } } // namespace mca } // namespace llvm