| 1 | //===--------------------- RegisterFileStatistics.cpp -----------*- 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 | /// \file |
| 9 | /// |
| 10 | /// This file implements the RegisterFileStatistics interface. |
| 11 | /// |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "Views/RegisterFileStatistics.h" |
| 15 | #include "llvm/Support/Format.h" |
| 16 | |
| 17 | namespace llvm { |
| 18 | namespace mca { |
| 19 | |
| 20 | RegisterFileStatistics::RegisterFileStatistics(const MCSubtargetInfo &sti) |
| 21 | : STI(sti) { |
| 22 | const MCSchedModel &SM = STI.getSchedModel(); |
| 23 | RegisterFileUsage RFUEmpty = {.TotalMappings: 0, .MaxUsedMappings: 0, .CurrentlyUsedMappings: 0}; |
| 24 | MoveEliminationInfo MEIEmpty = {.TotalMoveEliminationCandidates: 0, .TotalMovesEliminated: 0, .TotalMovesThatPropagateZero: 0, .MaxMovesEliminatedPerCycle: 0, .CurrentMovesEliminated: 0}; |
| 25 | if (!SM.hasExtraProcessorInfo()) { |
| 26 | // Assume a single register file. |
| 27 | PRFUsage.emplace_back(Args&: RFUEmpty); |
| 28 | MoveElimInfo.emplace_back(Args&: MEIEmpty); |
| 29 | return; |
| 30 | } |
| 31 | |
| 32 | // Initialize a RegisterFileUsage for every user defined register file, plus |
| 33 | // the default register file which is always at index #0. |
| 34 | const MCExtraProcessorInfo &PI = SM.getExtraProcessorInfo(); |
| 35 | // There is always an "InvalidRegisterFile" entry in tablegen. That entry can |
| 36 | // be skipped. If there are no user defined register files, then reserve a |
| 37 | // single entry for the default register file at index #0. |
| 38 | unsigned NumRegFiles = std::max(a: PI.NumRegisterFiles, b: 1U); |
| 39 | |
| 40 | PRFUsage.resize(N: NumRegFiles); |
| 41 | llvm::fill(Range&: PRFUsage, Value&: RFUEmpty); |
| 42 | |
| 43 | MoveElimInfo.resize(N: NumRegFiles); |
| 44 | llvm::fill(Range&: MoveElimInfo, Value&: MEIEmpty); |
| 45 | } |
| 46 | |
| 47 | void RegisterFileStatistics::updateRegisterFileUsage( |
| 48 | ArrayRef<unsigned> UsedPhysRegs) { |
| 49 | for (unsigned I = 0, E = PRFUsage.size(); I < E; ++I) { |
| 50 | RegisterFileUsage &RFU = PRFUsage[I]; |
| 51 | unsigned NumUsedPhysRegs = UsedPhysRegs[I]; |
| 52 | RFU.CurrentlyUsedMappings += NumUsedPhysRegs; |
| 53 | RFU.TotalMappings += NumUsedPhysRegs; |
| 54 | RFU.MaxUsedMappings = |
| 55 | std::max(a: RFU.MaxUsedMappings, b: RFU.CurrentlyUsedMappings); |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | void RegisterFileStatistics::updateMoveElimInfo(const Instruction &Inst) { |
| 60 | if (!Inst.isOptimizableMove()) |
| 61 | return; |
| 62 | |
| 63 | if (Inst.getDefs().size() != Inst.getUses().size()) |
| 64 | return; |
| 65 | |
| 66 | for (size_t I = 0, E = Inst.getDefs().size(); I < E; ++I) { |
| 67 | const WriteState &WS = Inst.getDefs()[I]; |
| 68 | const ReadState &RS = Inst.getUses()[E - (I + 1)]; |
| 69 | |
| 70 | MoveEliminationInfo &Info = |
| 71 | MoveElimInfo[Inst.getDefs()[0].getRegisterFileID()]; |
| 72 | Info.TotalMoveEliminationCandidates++; |
| 73 | if (WS.isEliminated()) |
| 74 | Info.CurrentMovesEliminated++; |
| 75 | if (WS.isWriteZero() && RS.isReadZero()) |
| 76 | Info.TotalMovesThatPropagateZero++; |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | void RegisterFileStatistics::onEvent(const HWInstructionEvent &Event) { |
| 81 | switch (Event.Type) { |
| 82 | default: |
| 83 | break; |
| 84 | case HWInstructionEvent::Retired: { |
| 85 | const auto &RE = static_cast<const HWInstructionRetiredEvent &>(Event); |
| 86 | for (unsigned I = 0, E = PRFUsage.size(); I < E; ++I) |
| 87 | PRFUsage[I].CurrentlyUsedMappings -= RE.FreedPhysRegs[I]; |
| 88 | break; |
| 89 | } |
| 90 | case HWInstructionEvent::Dispatched: { |
| 91 | const auto &DE = static_cast<const HWInstructionDispatchedEvent &>(Event); |
| 92 | updateRegisterFileUsage(UsedPhysRegs: DE.UsedPhysRegs); |
| 93 | updateMoveElimInfo(Inst: *DE.IR.getInstruction()); |
| 94 | } |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | void RegisterFileStatistics::onCycleEnd() { |
| 99 | for (MoveEliminationInfo &MEI : MoveElimInfo) { |
| 100 | unsigned &CurrentMax = MEI.MaxMovesEliminatedPerCycle; |
| 101 | CurrentMax = std::max(a: CurrentMax, b: MEI.CurrentMovesEliminated); |
| 102 | MEI.TotalMovesEliminated += MEI.CurrentMovesEliminated; |
| 103 | MEI.CurrentMovesEliminated = 0; |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | void RegisterFileStatistics::printView(raw_ostream &OS) const { |
| 108 | std::string Buffer; |
| 109 | raw_string_ostream TempStream(Buffer); |
| 110 | |
| 111 | TempStream << "\n\nRegister File statistics:" ; |
| 112 | const RegisterFileUsage &GlobalUsage = PRFUsage[0]; |
| 113 | TempStream << "\nTotal number of mappings created: " |
| 114 | << GlobalUsage.TotalMappings; |
| 115 | TempStream << "\nMax number of mappings used: " |
| 116 | << GlobalUsage.MaxUsedMappings << '\n'; |
| 117 | |
| 118 | for (unsigned I = 1, E = PRFUsage.size(); I < E; ++I) { |
| 119 | const RegisterFileUsage &RFU = PRFUsage[I]; |
| 120 | // Obtain the register file descriptor from the scheduling model. |
| 121 | assert(STI.getSchedModel().hasExtraProcessorInfo() && |
| 122 | "Unable to find register file info!" ); |
| 123 | const MCExtraProcessorInfo &PI = |
| 124 | STI.getSchedModel().getExtraProcessorInfo(); |
| 125 | assert(I <= PI.NumRegisterFiles && "Unexpected register file index!" ); |
| 126 | const MCRegisterFileDesc &RFDesc = PI.RegisterFiles[I]; |
| 127 | // Skip invalid register files. |
| 128 | if (!RFDesc.NumPhysRegs) |
| 129 | continue; |
| 130 | |
| 131 | TempStream << "\n* Register File #" << I; |
| 132 | TempStream << " -- " << StringRef(RFDesc.Name) << ':'; |
| 133 | TempStream << "\n Number of physical registers: " ; |
| 134 | if (!RFDesc.NumPhysRegs) |
| 135 | TempStream << "unbounded" ; |
| 136 | else |
| 137 | TempStream << RFDesc.NumPhysRegs; |
| 138 | TempStream << "\n Total number of mappings created: " |
| 139 | << RFU.TotalMappings; |
| 140 | TempStream << "\n Max number of mappings used: " |
| 141 | << RFU.MaxUsedMappings << '\n'; |
| 142 | const MoveEliminationInfo &MEI = MoveElimInfo[I]; |
| 143 | |
| 144 | if (MEI.TotalMoveEliminationCandidates) { |
| 145 | TempStream << " Number of optimizable moves: " |
| 146 | << MEI.TotalMoveEliminationCandidates; |
| 147 | double EliminatedMovProportion = (double)MEI.TotalMovesEliminated / |
| 148 | MEI.TotalMoveEliminationCandidates * |
| 149 | 100.0; |
| 150 | double ZeroMovProportion = (double)MEI.TotalMovesThatPropagateZero / |
| 151 | MEI.TotalMoveEliminationCandidates * 100.0; |
| 152 | TempStream << "\n Number of moves eliminated: " |
| 153 | << MEI.TotalMovesEliminated << " " |
| 154 | << format(Fmt: "(%.1f%%)" , |
| 155 | Vals: floor(x: (EliminatedMovProportion * 10) + 0.5) / 10); |
| 156 | TempStream << "\n Number of zero moves: " |
| 157 | << MEI.TotalMovesThatPropagateZero << " " |
| 158 | << format(Fmt: "(%.1f%%)" , |
| 159 | Vals: floor(x: (ZeroMovProportion * 10) + 0.5) / 10); |
| 160 | TempStream << "\n Max moves eliminated per cycle: " |
| 161 | << MEI.MaxMovesEliminatedPerCycle << '\n'; |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | OS << Buffer; |
| 166 | } |
| 167 | |
| 168 | } // namespace mca |
| 169 | } // namespace llvm |
| 170 | |