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
17namespace llvm {
18namespace mca {
19
20RegisterFileStatistics::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
47void 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
59void RegisterFileStatistics::updateMoveElimInfo(const Instruction &Inst) {
60  if (!Inst.isOptimizableMove())
61    return;
62
63  assert(Inst.getDefs().size() == 1 && "Expected a single definition!");
64  assert(Inst.getUses().size() == 1 && "Expected a single register use!");
65  const WriteState &WS = Inst.getDefs()[0];
66  const ReadState &RS = Inst.getUses()[0];
67
68  MoveEliminationInfo &Info =
69      MoveElimInfo[Inst.getDefs()[0].getRegisterFileID()];
70  Info.TotalMoveEliminationCandidates++;
71  if (WS.isEliminated())
72    Info.CurrentMovesEliminated++;
73  if (WS.isWriteZero() && RS.isReadZero())
74    Info.TotalMovesThatPropagateZero++;
75}
76
77void RegisterFileStatistics::onEvent(const HWInstructionEvent &Event) {
78  switch (Event.Type) {
79  default:
80    break;
81  case HWInstructionEvent::Retired: {
82    const auto &RE = static_cast<const HWInstructionRetiredEvent &>(Event);
83    for (unsigned I = 0, E = PRFUsage.size(); I < E; ++I)
84      PRFUsage[I].CurrentlyUsedMappings -= RE.FreedPhysRegs[I];
85    break;
86  }
87  case HWInstructionEvent::Dispatched: {
88    const auto &DE = static_cast<const HWInstructionDispatchedEvent &>(Event);
89    updateRegisterFileUsage(DE.UsedPhysRegs);
90    updateMoveElimInfo(*DE.IR.getInstruction());
91  }
92  }
93}
94
95void RegisterFileStatistics::onCycleEnd() {
96  for (MoveEliminationInfo &MEI : MoveElimInfo) {
97    unsigned &CurrentMax = MEI.MaxMovesEliminatedPerCycle;
98    CurrentMax = std::max(CurrentMax, MEI.CurrentMovesEliminated);
99    MEI.TotalMovesEliminated += MEI.CurrentMovesEliminated;
100    MEI.CurrentMovesEliminated = 0;
101  }
102}
103
104void RegisterFileStatistics::printView(raw_ostream &OS) const {
105  std::string Buffer;
106  raw_string_ostream TempStream(Buffer);
107
108  TempStream << "\n\nRegister File statistics:";
109  const RegisterFileUsage &GlobalUsage = PRFUsage[0];
110  TempStream << "\nTotal number of mappings created:    "
111             << GlobalUsage.TotalMappings;
112  TempStream << "\nMax number of mappings used:         "
113             << GlobalUsage.MaxUsedMappings << '\n';
114
115  for (unsigned I = 1, E = PRFUsage.size(); I < E; ++I) {
116    const RegisterFileUsage &RFU = PRFUsage[I];
117    // Obtain the register file descriptor from the scheduling model.
118    assert(STI.getSchedModel().hasExtraProcessorInfo() &&
119           "Unable to find register file info!");
120    const MCExtraProcessorInfo &PI =
121        STI.getSchedModel().getExtraProcessorInfo();
122    assert(I <= PI.NumRegisterFiles && "Unexpected register file index!");
123    const MCRegisterFileDesc &RFDesc = PI.RegisterFiles[I];
124    // Skip invalid register files.
125    if (!RFDesc.NumPhysRegs)
126      continue;
127
128    TempStream << "\n*  Register File #" << I;
129    TempStream << " -- " << StringRef(RFDesc.Name) << ':';
130    TempStream << "\n   Number of physical registers:     ";
131    if (!RFDesc.NumPhysRegs)
132      TempStream << "unbounded";
133    else
134      TempStream << RFDesc.NumPhysRegs;
135    TempStream << "\n   Total number of mappings created: "
136               << RFU.TotalMappings;
137    TempStream << "\n   Max number of mappings used:      "
138               << RFU.MaxUsedMappings << '\n';
139    const MoveEliminationInfo &MEI = MoveElimInfo[I];
140
141    if (MEI.TotalMoveEliminationCandidates) {
142      TempStream << "   Number of optimizable moves:      "
143                 << MEI.TotalMoveEliminationCandidates;
144      double EliminatedMovProportion = (double)MEI.TotalMovesEliminated /
145                                       MEI.TotalMoveEliminationCandidates *
146                                       100.0;
147      double ZeroMovProportion = (double)MEI.TotalMovesThatPropagateZero /
148                                 MEI.TotalMoveEliminationCandidates * 100.0;
149      TempStream << "\n   Number of moves eliminated:       "
150                 << MEI.TotalMovesEliminated << "  "
151                 << format("(%.1f%%)",
152                           floor((EliminatedMovProportion * 10) + 0.5) / 10);
153      TempStream << "\n   Number of zero moves:             "
154                 << MEI.TotalMovesThatPropagateZero << "  "
155                 << format("(%.1f%%)",
156                           floor((ZeroMovProportion * 10) + 0.5) / 10);
157      TempStream << "\n   Max moves eliminated per cycle:   "
158                 << MEI.MaxMovesEliminatedPerCycle << '\n';
159    }
160  }
161
162  TempStream.flush();
163  OS << Buffer;
164}
165
166} // namespace mca
167} // namespace llvm
168