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