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 std::vector<const PairType *> Pairs;
83 for (const auto &P : Map)
84 Pairs.push_back(x: &P);
85 llvm::sort(C&: Pairs, Comp: deref<std::less<PairType>>());
86
87 OS << '{';
88 ListSeparator LS(",");
89 for (const PairType *P : Pairs)
90 OS << LS << '(' << getModeName(Mode: P->first) << ':'
91 << getMVTName(T: P->second).str() << ')';
92 OS << '}';
93}
94
95LLVM_DUMP_METHOD
96void ValueTypeByHwMode::dump() const { dbgs() << *this << '\n'; }
97
98ValueTypeByHwMode llvm::getValueTypeByHwMode(const Record *Rec,
99 const CodeGenHwModes &CGH) {
100#ifndef NDEBUG
101 if (!Rec->isSubClassOf("ValueType"))
102 Rec->dump();
103#endif
104 assert(Rec->isSubClassOf("ValueType") &&
105 "Record must be derived from ValueType");
106 if (Rec->isSubClassOf(Name: "HwModeSelect"))
107 return ValueTypeByHwMode(Rec, CGH);
108 return ValueTypeByHwMode(Rec, llvm::getValueType(Rec));
109}
110
111RegSizeInfo::RegSizeInfo(const Record *R) {
112 RegSize = R->getValueAsInt(FieldName: "RegSize");
113 SpillSize = R->getValueAsInt(FieldName: "SpillSize");
114 SpillAlignment = R->getValueAsInt(FieldName: "SpillAlignment");
115}
116
117bool RegSizeInfo::operator<(const RegSizeInfo &I) const {
118 return std::tie(args: RegSize, args: SpillSize, args: SpillAlignment) <
119 std::tie(args: I.RegSize, args: I.SpillSize, args: I.SpillAlignment);
120}
121
122bool RegSizeInfo::isSubClassOf(const RegSizeInfo &I) const {
123 return RegSize <= I.RegSize && SpillAlignment &&
124 I.SpillAlignment % SpillAlignment == 0 && SpillSize <= I.SpillSize;
125}
126
127void RegSizeInfo::writeToStream(raw_ostream &OS) const {
128 OS << "[R=" << RegSize << ",S=" << SpillSize << ",A=" << SpillAlignment
129 << ']';
130}
131
132RegSizeInfoByHwMode::RegSizeInfoByHwMode(const Record *R,
133 const CodeGenHwModes &CGH)
134 : InfoByHwMode<llvm::RegSizeInfo>(R) {
135 const HwModeSelect &MS = CGH.getHwModeSelect(R);
136 for (auto [ModeID, RegInfo] : MS.Items) {
137 assert(RegInfo && RegInfo->isSubClassOf("RegInfo"));
138 if (!Map.try_emplace(k: ModeID, args: RegSizeInfo(RegInfo)).second)
139 PrintFatalError(ErrorLoc: R->getLoc(), Msg: "duplicate RegInfo entry for HwMode " +
140 CGH.getModeName(Id: ModeID, IncludeDefault: true) + ": " +
141 RegInfo->getName());
142 }
143}
144
145bool RegSizeInfoByHwMode::operator<(const RegSizeInfoByHwMode &I) const {
146 unsigned M0 = Map.begin()->first;
147 return get(Mode: M0) < I.get(Mode: M0);
148}
149
150bool RegSizeInfoByHwMode::operator==(const RegSizeInfoByHwMode &I) const {
151 unsigned M0 = Map.begin()->first;
152 return get(Mode: M0) == I.get(Mode: M0);
153}
154
155bool RegSizeInfoByHwMode::isSubClassOf(const RegSizeInfoByHwMode &I) const {
156 unsigned M0 = Map.begin()->first;
157 return get(Mode: M0).isSubClassOf(I: I.get(Mode: M0));
158}
159
160bool RegSizeInfoByHwMode::hasStricterSpillThan(
161 const RegSizeInfoByHwMode &I) const {
162 unsigned M0 = Map.begin()->first;
163 const RegSizeInfo &A0 = get(Mode: M0);
164 const RegSizeInfo &B0 = I.get(Mode: M0);
165 return std::tie(args: A0.SpillSize, args: A0.SpillAlignment) >
166 std::tie(args: B0.SpillSize, args: B0.SpillAlignment);
167}
168
169void RegSizeInfoByHwMode::writeToStream(raw_ostream &OS) const {
170 using PairType = decltype(Map)::value_type;
171 std::vector<const PairType *> Pairs;
172 for (const auto &P : Map)
173 Pairs.push_back(x: &P);
174 llvm::sort(C&: Pairs, Comp: deref<std::less<PairType>>());
175
176 OS << '{';
177 ListSeparator LS(",");
178 for (const PairType *P : Pairs)
179 OS << LS << '(' << getModeName(Mode: P->first) << ':' << P->second << ')';
180 OS << '}';
181}
182
183RegClassByHwMode::RegClassByHwMode(const Record *R,
184 const CodeGenRegBank &RegBank)
185 : InfoByHwMode<const llvm::CodeGenRegisterClass *>(R) {
186 const CodeGenHwModes &CGH = RegBank.getHwModes();
187 const HwModeSelect &MS = CGH.getHwModeSelect(R);
188
189 for (auto [ModeID, RegClassRec] : MS.Items) {
190 assert(RegClassRec && RegClassRec->isSubClassOf("RegisterClass") &&
191 "Register class must subclass RegisterClass");
192 const CodeGenRegisterClass *RegClass = RegBank.getRegClass(RegClassRec);
193 if (!Map.try_emplace(k: ModeID, args&: RegClass).second)
194 PrintFatalError(ErrorLoc: R->getLoc(), Msg: "duplicate RegisterClass entry for HwMode " +
195 CGH.getModeName(Id: ModeID, IncludeDefault: true) + ": " +
196 RegClass->getName());
197 }
198}
199
200SubRegRange::SubRegRange(const Record *R) {
201 Size = R->getValueAsInt(FieldName: "Size");
202 Offset = R->getValueAsInt(FieldName: "Offset");
203}
204
205SubRegRangeByHwMode::SubRegRangeByHwMode(const Record *R,
206 const CodeGenHwModes &CGH)
207 : InfoByHwMode<llvm::SubRegRange>(R) {
208 const HwModeSelect &MS = CGH.getHwModeSelect(R);
209 for (auto [ModeID, Range] : MS.Items) {
210 assert(Range && Range->isSubClassOf("SubRegRange"));
211 if (!Map.try_emplace(k: ModeID, args: SubRegRange(Range)).second)
212 PrintFatalError(ErrorLoc: R->getLoc(), Msg: "duplicate SubRegRange entry for HwMode " +
213 CGH.getModeName(Id: ModeID, IncludeDefault: true) + ": " +
214 Range->getName());
215 }
216}
217
218EncodingInfoByHwMode::EncodingInfoByHwMode(const Record *R,
219 const CodeGenHwModes &CGH)
220 : InfoByHwMode<const llvm::Record *>(R) {
221 const HwModeSelect &MS = CGH.getHwModeSelect(R);
222 for (auto [ModeID, Encoding] : MS.Items) {
223 assert(Encoding && Encoding->isSubClassOf("InstructionEncoding") &&
224 "Encoding must subclass InstructionEncoding");
225 if (!Map.try_emplace(k: ModeID, args&: Encoding).second)
226 PrintFatalError(ErrorLoc: R->getLoc(),
227 Msg: "duplicate InstructionEncoding entry for HwMode " +
228 CGH.getModeName(Id: ModeID, IncludeDefault: true) + ": " +
229 Encoding->getName());
230 }
231}
232
233RegisterByHwMode::RegisterByHwMode(const Record *R, CodeGenRegBank &RegBank)
234 : InfoByHwMode<const llvm::CodeGenRegister *>(R) {
235 const CodeGenHwModes &CGH = RegBank.getHwModes();
236 const HwModeSelect &MS = CGH.getHwModeSelect(R);
237 const Record *RCDef = R->getValueAsDef(FieldName: "RegClass");
238 Namespace = RegBank.getRegClasses().front().Namespace;
239 std::optional<RegClassByHwMode> RegClassByMode;
240 if (RCDef->isSubClassOf(Name: "RegClassByHwMode"))
241 RegClassByMode = RegClassByHwMode(RCDef, RegBank);
242 for (auto [ModeID, RegRecord] : MS.Items) {
243 assert(RegRecord && RegRecord->isSubClassOf("Register") &&
244 "Register value must subclass Register");
245 CodeGenRegister *Reg = RegBank.getReg(RegRecord);
246 const CodeGenRegisterClass *RC =
247 RegClassByMode ? RegClassByMode->get(Mode: ModeID)
248 : RegBank.getRegClass(RCDef, Loc: R->getLoc());
249 if (!RC->contains(Reg))
250 PrintFatalError(ErrorLoc: R->getLoc(), Msg: "Register " + Reg->getName() +
251 " for HwMode " +
252 CGH.getModeName(Id: ModeID, IncludeDefault: true) +
253 " is not a member of register class " +
254 RC->getName());
255 if (!Map.try_emplace(k: ModeID, args&: Reg).second)
256 PrintFatalError(ErrorLoc: R->getLoc(), Msg: "duplicate Register for HwMode " +
257 CGH.getModeName(Id: ModeID, IncludeDefault: true) + ": " +
258 Reg->getName());
259 }
260}
261
262void RegisterByHwMode::emitResolverCall(raw_ostream &OS,
263 const Twine &HwMode) const {
264 OS << Namespace << "::RegisterByHwMode::get" << Def->getName() << "("
265 << HwMode << ")";
266}
267
268raw_ostream &llvm::operator<<(raw_ostream &OS, const ValueTypeByHwMode &T) {
269 T.writeToStream(OS);
270 return OS;
271}
272
273raw_ostream &llvm::operator<<(raw_ostream &OS, const RegSizeInfo &T) {
274 T.writeToStream(OS);
275 return OS;
276}
277
278raw_ostream &llvm::operator<<(raw_ostream &OS, const RegSizeInfoByHwMode &T) {
279 T.writeToStream(OS);
280 return OS;
281}
282