xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-mca/Views/RegisterFileStatistics.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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 
RegisterFileStatistics(const MCSubtargetInfo & sti)20 RegisterFileStatistics::RegisterFileStatistics(const MCSubtargetInfo &sti)
21     : STI(sti) {
22   const MCSchedModel &SM = STI.getSchedModel();
23   RegisterFileUsage RFUEmpty = {0, 0, 0};
24   MoveEliminationInfo MEIEmpty = {0, 0, 0, 0, 0};
25   if (!SM.hasExtraProcessorInfo()) {
26     // Assume a single register file.
27     PRFUsage.emplace_back(RFUEmpty);
28     MoveElimInfo.emplace_back(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(PI.NumRegisterFiles, 1U);
39 
40   PRFUsage.resize(NumRegFiles);
41   std::fill(PRFUsage.begin(), PRFUsage.end(), RFUEmpty);
42 
43   MoveElimInfo.resize(NumRegFiles);
44   std::fill(MoveElimInfo.begin(), MoveElimInfo.end(), MEIEmpty);
45 }
46 
updateRegisterFileUsage(ArrayRef<unsigned> UsedPhysRegs)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(RFU.MaxUsedMappings, RFU.CurrentlyUsedMappings);
56   }
57 }
58 
updateMoveElimInfo(const Instruction & Inst)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 
onEvent(const HWInstructionEvent & Event)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(DE.UsedPhysRegs);
93     updateMoveElimInfo(*DE.IR.getInstruction());
94   }
95   }
96 }
97 
onCycleEnd()98 void RegisterFileStatistics::onCycleEnd() {
99   for (MoveEliminationInfo &MEI : MoveElimInfo) {
100     unsigned &CurrentMax = MEI.MaxMovesEliminatedPerCycle;
101     CurrentMax = std::max(CurrentMax, MEI.CurrentMovesEliminated);
102     MEI.TotalMovesEliminated += MEI.CurrentMovesEliminated;
103     MEI.CurrentMovesEliminated = 0;
104   }
105 }
106 
printView(raw_ostream & OS) const107 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("(%.1f%%)",
155                            floor((EliminatedMovProportion * 10) + 0.5) / 10);
156       TempStream << "\n   Number of zero moves:             "
157                  << MEI.TotalMovesThatPropagateZero << "  "
158                  << format("(%.1f%%)",
159                            floor((ZeroMovProportion * 10) + 0.5) / 10);
160       TempStream << "\n   Max moves eliminated per cycle:   "
161                  << MEI.MaxMovesEliminatedPerCycle << '\n';
162     }
163   }
164 
165   TempStream.flush();
166   OS << Buffer;
167 }
168 
169 } // namespace mca
170 } // namespace llvm
171