1 | //===- RegisterBankEmitter.cpp - Generate a Register Bank Desc. -*- 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 | // |
9 | // This tablegen backend is responsible for emitting a description of a target |
10 | // register bank for a code generator. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "Common/CodeGenRegisters.h" |
15 | #include "Common/CodeGenTarget.h" |
16 | #include "Common/InfoByHwMode.h" |
17 | #include "llvm/ADT/BitVector.h" |
18 | #include "llvm/Support/Debug.h" |
19 | #include "llvm/TableGen/Error.h" |
20 | #include "llvm/TableGen/Record.h" |
21 | #include "llvm/TableGen/TableGenBackend.h" |
22 | |
23 | #define DEBUG_TYPE "register-bank-emitter" |
24 | |
25 | using namespace llvm; |
26 | |
27 | namespace { |
28 | class RegisterBank { |
29 | |
30 | /// A vector of register classes that are included in the register bank. |
31 | typedef std::vector<const CodeGenRegisterClass *> RegisterClassesTy; |
32 | |
33 | private: |
34 | const Record &TheDef; |
35 | |
36 | /// The register classes that are covered by the register bank. |
37 | RegisterClassesTy RCs; |
38 | |
39 | /// The register class with the largest register size. |
40 | std::vector<const CodeGenRegisterClass *> RCsWithLargestRegSize; |
41 | |
42 | public: |
43 | RegisterBank(const Record &TheDef, unsigned NumModeIds) |
44 | : TheDef(TheDef), RCsWithLargestRegSize(NumModeIds) {} |
45 | |
46 | /// Get the human-readable name for the bank. |
47 | StringRef getName() const { return TheDef.getValueAsString(FieldName: "Name" ); } |
48 | /// Get the name of the enumerator in the ID enumeration. |
49 | std::string getEnumeratorName() const { |
50 | return (TheDef.getName() + "ID" ).str(); |
51 | } |
52 | |
53 | /// Get the name of the array holding the register class coverage data; |
54 | std::string getCoverageArrayName() const { |
55 | return (TheDef.getName() + "CoverageData" ).str(); |
56 | } |
57 | |
58 | /// Get the name of the global instance variable. |
59 | StringRef getInstanceVarName() const { return TheDef.getName(); } |
60 | |
61 | const Record &getDef() const { return TheDef; } |
62 | |
63 | /// Get the register classes listed in the RegisterBank.RegisterClasses field. |
64 | std::vector<const CodeGenRegisterClass *> |
65 | getExplicitlySpecifiedRegisterClasses( |
66 | const CodeGenRegBank &RegisterClassHierarchy) const { |
67 | std::vector<const CodeGenRegisterClass *> RCs; |
68 | for (const auto *RCDef : getDef().getValueAsListOfDefs(FieldName: "RegisterClasses" )) |
69 | RCs.push_back(x: RegisterClassHierarchy.getRegClass(RCDef)); |
70 | return RCs; |
71 | } |
72 | |
73 | /// Add a register class to the bank without duplicates. |
74 | void addRegisterClass(const CodeGenRegisterClass *RC) { |
75 | if (llvm::is_contained(Range&: RCs, Element: RC)) |
76 | return; |
77 | |
78 | // FIXME? We really want the register size rather than the spill size |
79 | // since the spill size may be bigger on some targets with |
80 | // limited load/store instructions. However, we don't store the |
81 | // register size anywhere (we could sum the sizes of the subregisters |
82 | // but there may be additional bits too) and we can't derive it from |
83 | // the VT's reliably due to Untyped. |
84 | unsigned NumModeIds = RCsWithLargestRegSize.size(); |
85 | for (unsigned M = 0; M < NumModeIds; ++M) { |
86 | if (RCsWithLargestRegSize[M] == nullptr) |
87 | RCsWithLargestRegSize[M] = RC; |
88 | else if (RCsWithLargestRegSize[M]->RSI.get(Mode: M).SpillSize < |
89 | RC->RSI.get(Mode: M).SpillSize) |
90 | RCsWithLargestRegSize[M] = RC; |
91 | assert(RCsWithLargestRegSize[M] && "RC was nullptr?" ); |
92 | } |
93 | |
94 | RCs.emplace_back(args&: RC); |
95 | } |
96 | |
97 | const CodeGenRegisterClass *getRCWithLargestRegSize(unsigned HwMode) const { |
98 | return RCsWithLargestRegSize[HwMode]; |
99 | } |
100 | |
101 | iterator_range<typename RegisterClassesTy::const_iterator> |
102 | register_classes() const { |
103 | return llvm::make_range(x: RCs.begin(), y: RCs.end()); |
104 | } |
105 | }; |
106 | |
107 | class RegisterBankEmitter { |
108 | private: |
109 | CodeGenTarget Target; |
110 | RecordKeeper &Records; |
111 | |
112 | void emitHeader(raw_ostream &OS, const StringRef TargetName, |
113 | const std::vector<RegisterBank> &Banks); |
114 | void emitBaseClassDefinition(raw_ostream &OS, const StringRef TargetName, |
115 | const std::vector<RegisterBank> &Banks); |
116 | void emitBaseClassImplementation(raw_ostream &OS, const StringRef TargetName, |
117 | std::vector<RegisterBank> &Banks); |
118 | |
119 | public: |
120 | RegisterBankEmitter(RecordKeeper &R) : Target(R), Records(R) {} |
121 | |
122 | void run(raw_ostream &OS); |
123 | }; |
124 | |
125 | } // end anonymous namespace |
126 | |
127 | /// Emit code to declare the ID enumeration and external global instance |
128 | /// variables. |
129 | void RegisterBankEmitter::(raw_ostream &OS, |
130 | const StringRef TargetName, |
131 | const std::vector<RegisterBank> &Banks) { |
132 | // <Target>RegisterBankInfo.h |
133 | OS << "namespace llvm {\n" |
134 | << "namespace " << TargetName << " {\n" |
135 | << "enum : unsigned {\n" ; |
136 | |
137 | OS << " InvalidRegBankID = ~0u,\n" ; |
138 | unsigned ID = 0; |
139 | for (const auto &Bank : Banks) |
140 | OS << " " << Bank.getEnumeratorName() << " = " << ID++ << ",\n" ; |
141 | OS << " NumRegisterBanks,\n" |
142 | << "};\n" |
143 | << "} // end namespace " << TargetName << "\n" |
144 | << "} // end namespace llvm\n" ; |
145 | } |
146 | |
147 | /// Emit declarations of the <Target>GenRegisterBankInfo class. |
148 | void RegisterBankEmitter::emitBaseClassDefinition( |
149 | raw_ostream &OS, const StringRef TargetName, |
150 | const std::vector<RegisterBank> &Banks) { |
151 | OS << "private:\n" |
152 | << " static const RegisterBank *RegBanks[];\n" |
153 | << " static const unsigned Sizes[];\n\n" |
154 | << "protected:\n" |
155 | << " " << TargetName << "GenRegisterBankInfo(unsigned HwMode = 0);\n" |
156 | << "\n" ; |
157 | } |
158 | |
159 | /// Visit each register class belonging to the given register bank. |
160 | /// |
161 | /// A class belongs to the bank iff any of these apply: |
162 | /// * It is explicitly specified |
163 | /// * It is a subclass of a class that is a member. |
164 | /// * It is a class containing subregisters of the registers of a class that |
165 | /// is a member. This is known as a subreg-class. |
166 | /// |
167 | /// This function must be called for each explicitly specified register class. |
168 | /// |
169 | /// \param RC The register class to search. |
170 | /// \param Kind A debug string containing the path the visitor took to reach RC. |
171 | /// \param VisitFn The action to take for each class visited. It may be called |
172 | /// multiple times for a given class if there are multiple paths |
173 | /// to the class. |
174 | static void visitRegisterBankClasses( |
175 | const CodeGenRegBank &RegisterClassHierarchy, |
176 | const CodeGenRegisterClass *RC, const Twine &Kind, |
177 | std::function<void(const CodeGenRegisterClass *, StringRef)> VisitFn, |
178 | SmallPtrSetImpl<const CodeGenRegisterClass *> &VisitedRCs) { |
179 | |
180 | // Make sure we only visit each class once to avoid infinite loops. |
181 | if (!VisitedRCs.insert(Ptr: RC).second) |
182 | return; |
183 | |
184 | // Visit each explicitly named class. |
185 | VisitFn(RC, Kind.str()); |
186 | |
187 | for (const auto &PossibleSubclass : RegisterClassHierarchy.getRegClasses()) { |
188 | std::string TmpKind = |
189 | (Kind + " (" + PossibleSubclass.getName() + ")" ).str(); |
190 | |
191 | // Visit each subclass of an explicitly named class. |
192 | if (RC != &PossibleSubclass && RC->hasSubClass(RC: &PossibleSubclass)) |
193 | visitRegisterBankClasses(RegisterClassHierarchy, RC: &PossibleSubclass, |
194 | Kind: TmpKind + " " + RC->getName() + " subclass" , |
195 | VisitFn, VisitedRCs); |
196 | |
197 | // Visit each class that contains only subregisters of RC with a common |
198 | // subregister-index. |
199 | // |
200 | // More precisely, PossibleSubclass is a subreg-class iff Reg:SubIdx is in |
201 | // PossibleSubclass for all registers Reg from RC using any |
202 | // subregister-index SubReg |
203 | for (const auto &SubIdx : RegisterClassHierarchy.getSubRegIndices()) { |
204 | BitVector BV(RegisterClassHierarchy.getRegClasses().size()); |
205 | PossibleSubclass.getSuperRegClasses(SubIdx: &SubIdx, Out&: BV); |
206 | if (BV.test(Idx: RC->EnumValue)) { |
207 | std::string TmpKind2 = (Twine(TmpKind) + " " + RC->getName() + |
208 | " class-with-subregs: " + RC->getName()) |
209 | .str(); |
210 | VisitFn(&PossibleSubclass, TmpKind2); |
211 | } |
212 | } |
213 | } |
214 | } |
215 | |
216 | void RegisterBankEmitter::emitBaseClassImplementation( |
217 | raw_ostream &OS, StringRef TargetName, std::vector<RegisterBank> &Banks) { |
218 | const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank(); |
219 | const CodeGenHwModes &CGH = Target.getHwModes(); |
220 | |
221 | OS << "namespace llvm {\n" |
222 | << "namespace " << TargetName << " {\n" ; |
223 | for (const auto &Bank : Banks) { |
224 | std::vector<std::vector<const CodeGenRegisterClass *>> RCsGroupedByWord( |
225 | (RegisterClassHierarchy.getRegClasses().size() + 31) / 32); |
226 | |
227 | for (const auto &RC : Bank.register_classes()) |
228 | RCsGroupedByWord[RC->EnumValue / 32].push_back(x: RC); |
229 | |
230 | OS << "const uint32_t " << Bank.getCoverageArrayName() << "[] = {\n" ; |
231 | unsigned LowestIdxInWord = 0; |
232 | for (const auto &RCs : RCsGroupedByWord) { |
233 | OS << " // " << LowestIdxInWord << "-" << (LowestIdxInWord + 31) |
234 | << "\n" ; |
235 | for (const auto &RC : RCs) { |
236 | OS << " (1u << (" << RC->getQualifiedIdName() << " - " |
237 | << LowestIdxInWord << ")) |\n" ; |
238 | } |
239 | OS << " 0,\n" ; |
240 | LowestIdxInWord += 32; |
241 | } |
242 | OS << "};\n" ; |
243 | } |
244 | OS << "\n" ; |
245 | |
246 | for (const auto &Bank : Banks) { |
247 | std::string QualifiedBankID = |
248 | (TargetName + "::" + Bank.getEnumeratorName()).str(); |
249 | OS << "constexpr RegisterBank " << Bank.getInstanceVarName() << "(/* ID */ " |
250 | << QualifiedBankID << ", /* Name */ \"" << Bank.getName() << "\", " |
251 | << "/* CoveredRegClasses */ " << Bank.getCoverageArrayName() |
252 | << ", /* NumRegClasses */ " |
253 | << RegisterClassHierarchy.getRegClasses().size() << ");\n" ; |
254 | } |
255 | OS << "} // end namespace " << TargetName << "\n" |
256 | << "\n" ; |
257 | |
258 | OS << "const RegisterBank *" << TargetName |
259 | << "GenRegisterBankInfo::RegBanks[] = {\n" ; |
260 | for (const auto &Bank : Banks) |
261 | OS << " &" << TargetName << "::" << Bank.getInstanceVarName() << ",\n" ; |
262 | OS << "};\n\n" ; |
263 | |
264 | unsigned NumModeIds = CGH.getNumModeIds(); |
265 | OS << "const unsigned " << TargetName << "GenRegisterBankInfo::Sizes[] = {\n" ; |
266 | for (unsigned M = 0; M < NumModeIds; ++M) { |
267 | OS << " // Mode = " << M << " (" ; |
268 | if (M == DefaultMode) |
269 | OS << "Default" ; |
270 | else |
271 | OS << CGH.getMode(Id: M).Name; |
272 | OS << ")\n" ; |
273 | for (const auto &Bank : Banks) { |
274 | const CodeGenRegisterClass &RC = *Bank.getRCWithLargestRegSize(HwMode: M); |
275 | unsigned Size = RC.RSI.get(Mode: M).SpillSize; |
276 | OS << " " << Size << ",\n" ; |
277 | } |
278 | } |
279 | OS << "};\n\n" ; |
280 | |
281 | OS << TargetName << "GenRegisterBankInfo::" << TargetName |
282 | << "GenRegisterBankInfo(unsigned HwMode)\n" |
283 | << " : RegisterBankInfo(RegBanks, " << TargetName |
284 | << "::NumRegisterBanks, Sizes, HwMode) {\n" |
285 | << " // Assert that RegBank indices match their ID's\n" |
286 | << "#ifndef NDEBUG\n" |
287 | << " for (auto RB : enumerate(RegBanks))\n" |
288 | << " assert(RB.index() == RB.value()->getID() && \"Index != ID\");\n" |
289 | << "#endif // NDEBUG\n" |
290 | << "}\n" |
291 | << "} // end namespace llvm\n" ; |
292 | } |
293 | |
294 | void RegisterBankEmitter::run(raw_ostream &OS) { |
295 | StringRef TargetName = Target.getName(); |
296 | const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank(); |
297 | const CodeGenHwModes &CGH = Target.getHwModes(); |
298 | |
299 | Records.startTimer(Name: "Analyze records" ); |
300 | std::vector<RegisterBank> Banks; |
301 | for (const auto &V : Records.getAllDerivedDefinitions(ClassName: "RegisterBank" )) { |
302 | SmallPtrSet<const CodeGenRegisterClass *, 8> VisitedRCs; |
303 | RegisterBank Bank(*V, CGH.getNumModeIds()); |
304 | |
305 | for (const CodeGenRegisterClass *RC : |
306 | Bank.getExplicitlySpecifiedRegisterClasses(RegisterClassHierarchy)) { |
307 | visitRegisterBankClasses( |
308 | RegisterClassHierarchy, RC, Kind: "explicit" , |
309 | VisitFn: [&Bank](const CodeGenRegisterClass *RC, StringRef Kind) { |
310 | LLVM_DEBUG(dbgs() |
311 | << "Added " << RC->getName() << "(" << Kind << ")\n" ); |
312 | Bank.addRegisterClass(RC); |
313 | }, |
314 | VisitedRCs); |
315 | } |
316 | |
317 | Banks.push_back(x: Bank); |
318 | } |
319 | |
320 | // Warn about ambiguous MIR caused by register bank/class name clashes. |
321 | Records.startTimer(Name: "Warn ambiguous" ); |
322 | for (const auto &Class : RegisterClassHierarchy.getRegClasses()) { |
323 | for (const auto &Bank : Banks) { |
324 | if (Bank.getName().lower() == StringRef(Class.getName()).lower()) { |
325 | PrintWarning(WarningLoc: Bank.getDef().getLoc(), Msg: "Register bank names should be " |
326 | "distinct from register classes " |
327 | "to avoid ambiguous MIR" ); |
328 | PrintNote(NoteLoc: Bank.getDef().getLoc(), Msg: "RegisterBank was declared here" ); |
329 | PrintNote(NoteLoc: Class.getDef()->getLoc(), Msg: "RegisterClass was declared here" ); |
330 | } |
331 | } |
332 | } |
333 | |
334 | Records.startTimer(Name: "Emit output" ); |
335 | emitSourceFileHeader(Desc: "Register Bank Source Fragments" , OS); |
336 | OS << "#ifdef GET_REGBANK_DECLARATIONS\n" |
337 | << "#undef GET_REGBANK_DECLARATIONS\n" ; |
338 | emitHeader(OS, TargetName, Banks); |
339 | OS << "#endif // GET_REGBANK_DECLARATIONS\n\n" |
340 | << "#ifdef GET_TARGET_REGBANK_CLASS\n" |
341 | << "#undef GET_TARGET_REGBANK_CLASS\n" ; |
342 | emitBaseClassDefinition(OS, TargetName, Banks); |
343 | OS << "#endif // GET_TARGET_REGBANK_CLASS\n\n" |
344 | << "#ifdef GET_TARGET_REGBANK_IMPL\n" |
345 | << "#undef GET_TARGET_REGBANK_IMPL\n" ; |
346 | emitBaseClassImplementation(OS, TargetName, Banks); |
347 | OS << "#endif // GET_TARGET_REGBANK_IMPL\n" ; |
348 | } |
349 | |
350 | static TableGen::Emitter::OptClass<RegisterBankEmitter> |
351 | X("gen-register-bank" , "Generate registers bank descriptions" ); |
352 | |