1//===--- InfoByHwMode.cpp -------------------------------------------------===//
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// Classes that implement data parameterized by HW modes for instruction
9// selection. Currently it is ValueTypeByHwMode (parameterized ValueType),
10// and RegSizeInfoByHwMode (parameterized register/spill size and alignment
11// data).
12//===----------------------------------------------------------------------===//
13
14#include "InfoByHwMode.h"
15#include "CodeGenRegisters.h"
16#include "CodeGenTarget.h"
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/Twine.h"
19#include "llvm/Support/Debug.h"
20#include "llvm/Support/raw_ostream.h"
21#include "llvm/TableGen/Error.h"
22#include "llvm/TableGen/Record.h"
23#include <string>
24
25using namespace llvm;
26
27std::string llvm::getModeName(unsigned Mode) {
28 if (Mode == DefaultMode)
29 return "*";
30 return (Twine('m') + Twine(Mode)).str();
31}
32
33ValueTypeByHwMode::ValueTypeByHwMode(const Record *R, const CodeGenHwModes &CGH)
34 : InfoByHwMode<llvm::MVT>(R) {
35 const HwModeSelect &MS = CGH.getHwModeSelect(R);
36 for (auto [ModeID, VT] : MS.Items) {
37 assert(VT && VT->isSubClassOf("ValueType"));
38 if (!Map.try_emplace(k: ModeID, args: MVT(llvm::getValueType(Rec: VT))).second)
39 PrintFatalError(ErrorLoc: R->getLoc(), Msg: "duplicate ValueType entry for HwMode " +
40 CGH.getModeName(Id: ModeID, IncludeDefault: true) + ": " +
41 VT->getName());
42 }
43 if (R->isSubClassOf(Name: "PtrValueType"))
44 PtrAddrSpace = R->getValueAsInt(FieldName: "AddrSpace");
45}
46
47ValueTypeByHwMode::ValueTypeByHwMode(const Record *R, MVT T)
48 : ValueTypeByHwMode(T) {
49 if (R->isSubClassOf(Name: "PtrValueType"))
50 PtrAddrSpace = R->getValueAsInt(FieldName: "AddrSpace");
51}
52
53bool ValueTypeByHwMode::operator==(const ValueTypeByHwMode &T) const {
54 assert(isValid() && T.isValid() && "Invalid type in assignment");
55 bool Simple = isSimple();
56 if (Simple != T.isSimple())
57 return false;
58 if (Simple)
59 return getSimple() == T.getSimple();
60
61 return Map == T.Map;
62}
63
64bool ValueTypeByHwMode::operator<(const ValueTypeByHwMode &T) const {
65 assert(isValid() && T.isValid() && "Invalid type in comparison");
66 // Default order for maps.
67 return Map < T.Map;
68}
69
70StringRef ValueTypeByHwMode::getMVTName(MVT T) {
71 StringRef N = llvm::getEnumName(T: T.SimpleTy);
72 N.consume_front(Prefix: "MVT::");
73 return N;
74}
75
76void ValueTypeByHwMode::writeToStream(raw_ostream &OS) const {
77 if (isSimple()) {
78 OS << getMVTName(T: getSimple());
79 return;
80 }
81
82 OS << '{';
83 ListSeparator LS(",");
84 for (const auto &[Mode, VT] : Map)
85 OS << LS << '(' << getModeName(Mode) << ':' << getMVTName(T: VT) << ')';
86 OS << '}';
87}
88
89LLVM_DUMP_METHOD
90void ValueTypeByHwMode::dump() const { dbgs() << *this << '\n'; }
91
92ValueTypeByHwMode llvm::getValueTypeByHwMode(const Record *Rec,
93 const CodeGenHwModes &CGH) {
94#ifndef NDEBUG
95 if (!Rec->isSubClassOf("ValueType"))
96 Rec->dump();
97#endif
98 assert(Rec->isSubClassOf("ValueType") &&
99 "Record must be derived from ValueType");
100 if (Rec->isSubClassOf(Name: "HwModeSelect"))
101 return ValueTypeByHwMode(Rec, CGH);
102 return ValueTypeByHwMode(Rec, llvm::getValueType(Rec));
103}
104
105RegSizeInfo::RegSizeInfo(const Record *R) {
106 RegSize = R->getValueAsInt(FieldName: "RegSize");
107 SpillSize = R->getValueAsInt(FieldName: "SpillSize");
108 SpillAlignment = R->getValueAsInt(FieldName: "SpillAlignment");
109}
110
111bool RegSizeInfo::operator<(const RegSizeInfo &I) const {
112 return std::tie(args: RegSize, args: SpillSize, args: SpillAlignment) <
113 std::tie(args: I.RegSize, args: I.SpillSize, args: I.SpillAlignment);
114}
115
116bool RegSizeInfo::isSubClassOf(const RegSizeInfo &I) const {
117 return RegSize <= I.RegSize && SpillAlignment &&
118 I.SpillAlignment % SpillAlignment == 0 && SpillSize <= I.SpillSize;
119}
120
121void RegSizeInfo::writeToStream(raw_ostream &OS) const {
122 OS << "[R=" << RegSize << ",S=" << SpillSize << ",A=" << SpillAlignment
123 << ']';
124}
125
126RegSizeInfoByHwMode::RegSizeInfoByHwMode(const Record *R,
127 const CodeGenHwModes &CGH)
128 : InfoByHwMode<llvm::RegSizeInfo>(R) {
129 const HwModeSelect &MS = CGH.getHwModeSelect(R);
130 for (auto [ModeID, RegInfo] : MS.Items) {
131 assert(RegInfo && RegInfo->isSubClassOf("RegInfo"));
132 if (!Map.try_emplace(k: ModeID, args: RegSizeInfo(RegInfo)).second)
133 PrintFatalError(ErrorLoc: R->getLoc(), Msg: "duplicate RegInfo entry for HwMode " +
134 CGH.getModeName(Id: ModeID, IncludeDefault: true) + ": " +
135 RegInfo->getName());
136 }
137}
138
139bool RegSizeInfoByHwMode::operator<(const RegSizeInfoByHwMode &I) const {
140 unsigned M0 = Map.begin()->first;
141 return get(Mode: M0) < I.get(Mode: M0);
142}
143
144bool RegSizeInfoByHwMode::operator==(const RegSizeInfoByHwMode &I) const {
145 unsigned M0 = Map.begin()->first;
146 return get(Mode: M0) == I.get(Mode: M0);
147}
148
149bool RegSizeInfoByHwMode::isSubClassOf(const RegSizeInfoByHwMode &I) const {
150 unsigned M0 = Map.begin()->first;
151 return get(Mode: M0).isSubClassOf(I: I.get(Mode: M0));
152}
153
154bool RegSizeInfoByHwMode::hasStricterSpillThan(
155 const RegSizeInfoByHwMode &I) const {
156 unsigned M0 = Map.begin()->first;
157 const RegSizeInfo &A0 = get(Mode: M0);
158 const RegSizeInfo &B0 = I.get(Mode: M0);
159 return std::tie(args: A0.SpillSize, args: A0.SpillAlignment) >
160 std::tie(args: B0.SpillSize, args: B0.SpillAlignment);
161}
162
163void RegSizeInfoByHwMode::writeToStream(raw_ostream &OS) const {
164 OS << '{';
165 ListSeparator LS(",");
166 for (const auto &[Mode, Info] : Map)
167 OS << LS << '(' << getModeName(Mode) << ':' << Info << ')';
168 OS << '}';
169}
170
171RegClassByHwMode::RegClassByHwMode(const Record *R,
172 const CodeGenRegBank &RegBank)
173 : InfoByHwMode<const llvm::CodeGenRegisterClass *>(R) {
174 const CodeGenHwModes &CGH = RegBank.getHwModes();
175 const HwModeSelect &MS = CGH.getHwModeSelect(R);
176
177 for (auto [ModeID, RegClassRec] : MS.Items) {
178 assert(RegClassRec && RegClassRec->isSubClassOf("RegisterClass") &&
179 "Register class must subclass RegisterClass");
180 const CodeGenRegisterClass *RegClass = RegBank.getRegClass(RegClassRec);
181 if (!Map.try_emplace(k: ModeID, args&: RegClass).second)
182 PrintFatalError(ErrorLoc: R->getLoc(), Msg: "duplicate RegisterClass entry for HwMode " +
183 CGH.getModeName(Id: ModeID, IncludeDefault: true) + ": " +
184 RegClass->getName());
185 }
186}
187
188SubRegRange::SubRegRange(const Record *R) {
189 Size = R->getValueAsInt(FieldName: "Size");
190 Offset = R->getValueAsInt(FieldName: "Offset");
191}
192
193SubRegRangeByHwMode::SubRegRangeByHwMode(const Record *R,
194 const CodeGenHwModes &CGH)
195 : InfoByHwMode<llvm::SubRegRange>(R) {
196 const HwModeSelect &MS = CGH.getHwModeSelect(R);
197 for (auto [ModeID, Range] : MS.Items) {
198 assert(Range && Range->isSubClassOf("SubRegRange"));
199 if (!Map.try_emplace(k: ModeID, args: SubRegRange(Range)).second)
200 PrintFatalError(ErrorLoc: R->getLoc(), Msg: "duplicate SubRegRange entry for HwMode " +
201 CGH.getModeName(Id: ModeID, IncludeDefault: true) + ": " +
202 Range->getName());
203 }
204}
205
206EncodingInfoByHwMode::EncodingInfoByHwMode(const Record *R,
207 const CodeGenHwModes &CGH)
208 : InfoByHwMode<const llvm::Record *>(R) {
209 const HwModeSelect &MS = CGH.getHwModeSelect(R);
210 for (auto [ModeID, Encoding] : MS.Items) {
211 assert(Encoding && Encoding->isSubClassOf("InstructionEncoding") &&
212 "Encoding must subclass InstructionEncoding");
213 if (!Map.try_emplace(k: ModeID, args&: Encoding).second)
214 PrintFatalError(ErrorLoc: R->getLoc(),
215 Msg: "duplicate InstructionEncoding entry for HwMode " +
216 CGH.getModeName(Id: ModeID, IncludeDefault: true) + ": " +
217 Encoding->getName());
218 }
219}
220
221RegisterByHwMode::RegisterByHwMode(const Record *R, CodeGenRegBank &RegBank)
222 : InfoByHwMode<const llvm::CodeGenRegister *>(R) {
223 const CodeGenHwModes &CGH = RegBank.getHwModes();
224 const HwModeSelect &MS = CGH.getHwModeSelect(R);
225 const Record *RCDef = R->getValueAsDef(FieldName: "RegClass");
226 Namespace = RegBank.getRegClasses().front().Namespace;
227 std::optional<RegClassByHwMode> RegClassByMode;
228 if (RCDef->isSubClassOf(Name: "RegClassByHwMode"))
229 RegClassByMode = RegClassByHwMode(RCDef, RegBank);
230 for (auto [ModeID, RegRecord] : MS.Items) {
231 assert(RegRecord && RegRecord->isSubClassOf("Register") &&
232 "Register value must subclass Register");
233 CodeGenRegister *Reg = RegBank.getReg(RegRecord);
234 const CodeGenRegisterClass *RC =
235 RegClassByMode ? RegClassByMode->get(Mode: ModeID)
236 : RegBank.getRegClass(RCDef, Loc: R->getLoc());
237 if (!RC->contains(Reg))
238 PrintFatalError(ErrorLoc: R->getLoc(), Msg: "Register " + Reg->getName() +
239 " for HwMode " +
240 CGH.getModeName(Id: ModeID, IncludeDefault: true) +
241 " is not a member of register class " +
242 RC->getName());
243 if (!Map.try_emplace(k: ModeID, args&: Reg).second)
244 PrintFatalError(ErrorLoc: R->getLoc(), Msg: "duplicate Register for HwMode " +
245 CGH.getModeName(Id: ModeID, IncludeDefault: true) + ": " +
246 Reg->getName());
247 }
248}
249
250void RegisterByHwMode::emitResolverCall(raw_ostream &OS,
251 const Twine &HwMode) const {
252 OS << Namespace << "::RegisterByHwMode::get" << Def->getName() << "("
253 << HwMode << ")";
254}
255
256raw_ostream &llvm::operator<<(raw_ostream &OS, const ValueTypeByHwMode &T) {
257 T.writeToStream(OS);
258 return OS;
259}
260
261raw_ostream &llvm::operator<<(raw_ostream &OS, const RegSizeInfo &T) {
262 T.writeToStream(OS);
263 return OS;
264}
265
266raw_ostream &llvm::operator<<(raw_ostream &OS, const RegSizeInfoByHwMode &T) {
267 T.writeToStream(OS);
268 return OS;
269}
270