1//===--- InfoByHwMode.h -----------------------------------------*- 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// 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#ifndef LLVM_UTILS_TABLEGEN_COMMON_INFOBYHWMODE_H
15#define LLVM_UTILS_TABLEGEN_COMMON_INFOBYHWMODE_H
16
17#include "CodeGenHwModes.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/ADT/StringRef.h"
20#include "llvm/CodeGenTypes/MachineValueType.h"
21#include "llvm/Support/Compiler.h"
22#include <cassert>
23#include <limits>
24#include <map>
25#include <string>
26#include <tuple>
27
28namespace llvm {
29
30class CodeGenRegBank;
31class CodeGenRegister;
32class CodeGenRegisterClass;
33class Record;
34class raw_ostream;
35
36template <typename InfoT> struct InfoByHwMode;
37
38std::string getModeName(unsigned Mode);
39
40enum : unsigned {
41 DefaultMode = CodeGenHwModes::DefaultMode,
42};
43
44template <typename InfoT>
45void union_modes(const InfoByHwMode<InfoT> &A, const InfoByHwMode<InfoT> &B,
46 SmallVectorImpl<unsigned> &Modes) {
47 auto AI = A.begin();
48 auto BI = B.begin();
49
50 // Skip default mode, but remember if we had one.
51 bool HasDefault = false;
52 if (AI != A.end() && AI->first == DefaultMode) {
53 HasDefault = true;
54 ++AI;
55 }
56 if (BI != B.end() && BI->first == DefaultMode) {
57 HasDefault = true;
58 ++BI;
59 }
60
61 while (AI != A.end()) {
62 // If we're done with B, finish A.
63 if (BI == B.end()) {
64 for (; AI != A.end(); ++AI)
65 Modes.push_back(Elt: AI->first);
66 break;
67 }
68
69 if (BI->first < AI->first) {
70 Modes.push_back(Elt: BI->first);
71 ++BI;
72 } else {
73 Modes.push_back(Elt: AI->first);
74 if (AI->first == BI->first)
75 ++BI;
76 ++AI;
77 }
78 }
79
80 // Finish B.
81 for (; BI != B.end(); ++BI)
82 Modes.push_back(Elt: BI->first);
83
84 // Make sure that the default mode is last on the list.
85 if (HasDefault)
86 Modes.push_back(Elt: DefaultMode);
87}
88
89template <typename InfoT> struct InfoByHwMode {
90 using MapType = std::map<unsigned, InfoT>;
91 using PairType = typename MapType::value_type;
92 using iterator = typename MapType::iterator;
93 using const_iterator = typename MapType::const_iterator;
94
95 explicit InfoByHwMode(const Record *Def = nullptr) : Def(Def) {};
96 InfoByHwMode(const MapType &M) : Map(M) {}
97
98 LLVM_ATTRIBUTE_ALWAYS_INLINE
99 iterator begin() { return Map.begin(); }
100 LLVM_ATTRIBUTE_ALWAYS_INLINE
101 iterator end() { return Map.end(); }
102 LLVM_ATTRIBUTE_ALWAYS_INLINE
103 const_iterator begin() const { return Map.begin(); }
104 LLVM_ATTRIBUTE_ALWAYS_INLINE
105 const_iterator end() const { return Map.end(); }
106 LLVM_ATTRIBUTE_ALWAYS_INLINE
107 size_t size() const { return Map.size(); }
108 LLVM_ATTRIBUTE_ALWAYS_INLINE
109 bool empty() const { return Map.empty(); }
110
111 LLVM_ATTRIBUTE_ALWAYS_INLINE
112 bool hasMode(unsigned M) const { return Map.find(M) != Map.end(); }
113 LLVM_ATTRIBUTE_ALWAYS_INLINE
114 bool hasDefault() const {
115 return !Map.empty() && Map.begin()->first == DefaultMode;
116 }
117
118 InfoT &get(unsigned Mode) {
119 auto F = Map.find(Mode);
120 if (F != Map.end())
121 return F->second;
122
123 // Copy and insert the default mode which should be first.
124 assert(hasDefault());
125 auto P = Map.try_emplace(Mode, Map.begin()->second);
126 return P.first->second;
127 }
128 const InfoT &get(unsigned Mode) const {
129 auto F = Map.find(Mode);
130 if (F != Map.end())
131 return F->second;
132 // Get the default mode which should be first.
133 F = Map.begin();
134 assert(F != Map.end() && F->first == DefaultMode);
135 return F->second;
136 }
137
138 LLVM_ATTRIBUTE_ALWAYS_INLINE
139 bool isSimple() const {
140 return Map.size() == 1 && Map.begin()->first == DefaultMode;
141 }
142 LLVM_ATTRIBUTE_ALWAYS_INLINE
143 const InfoT &getSimple() const {
144 assert(isSimple());
145 return Map.begin()->second;
146 }
147 void makeSimple(unsigned Mode) {
148 assert(hasMode(Mode) || hasDefault());
149 InfoT I = get(Mode);
150 Map.clear();
151 Map.try_emplace(DefaultMode, I);
152 }
153
154 const Record *getRecord() const { return Def; }
155
156protected:
157 MapType Map;
158 const Record *Def;
159};
160
161struct ValueTypeByHwMode : public InfoByHwMode<MVT> {
162 ValueTypeByHwMode(const Record *R, const CodeGenHwModes &CGH);
163 ValueTypeByHwMode(const Record *R, MVT T);
164 ValueTypeByHwMode(MVT T) { Map.try_emplace(k: DefaultMode, args&: T); }
165 ValueTypeByHwMode() = default;
166
167 bool operator==(const ValueTypeByHwMode &T) const;
168 bool operator<(const ValueTypeByHwMode &T) const;
169
170 bool isValid() const { return !Map.empty(); }
171 MVT getType(unsigned Mode) const { return get(Mode); }
172 void insertTypeForMode(unsigned Mode, MVT Type) {
173 Map.try_emplace(k: Mode, args&: Type);
174 }
175
176 static StringRef getMVTName(MVT T);
177 void writeToStream(raw_ostream &OS) const;
178 void dump() const;
179
180 unsigned PtrAddrSpace = std::numeric_limits<unsigned>::max();
181 bool isPointer() const {
182 return PtrAddrSpace != std::numeric_limits<unsigned>::max();
183 }
184};
185
186ValueTypeByHwMode getValueTypeByHwMode(const Record *Rec,
187 const CodeGenHwModes &CGH);
188
189raw_ostream &operator<<(raw_ostream &OS, const ValueTypeByHwMode &T);
190
191struct RegSizeInfo {
192 unsigned RegSize;
193 unsigned SpillSize;
194 unsigned SpillAlignment;
195
196 RegSizeInfo(const Record *R);
197 RegSizeInfo() = default;
198 bool operator<(const RegSizeInfo &I) const;
199 bool operator==(const RegSizeInfo &I) const {
200 return std::tie(args: RegSize, args: SpillSize, args: SpillAlignment) ==
201 std::tie(args: I.RegSize, args: I.SpillSize, args: I.SpillAlignment);
202 }
203 bool operator!=(const RegSizeInfo &I) const { return !(*this == I); }
204
205 bool isSubClassOf(const RegSizeInfo &I) const;
206 void writeToStream(raw_ostream &OS) const;
207};
208
209struct RegSizeInfoByHwMode : public InfoByHwMode<RegSizeInfo> {
210 RegSizeInfoByHwMode(const Record *R, const CodeGenHwModes &CGH);
211 RegSizeInfoByHwMode() = default;
212 bool operator<(const RegSizeInfoByHwMode &VI) const;
213 bool operator==(const RegSizeInfoByHwMode &VI) const;
214 bool operator!=(const RegSizeInfoByHwMode &VI) const {
215 return !(*this == VI);
216 }
217
218 bool isSubClassOf(const RegSizeInfoByHwMode &I) const;
219 bool hasStricterSpillThan(const RegSizeInfoByHwMode &I) const;
220
221 void writeToStream(raw_ostream &OS) const;
222
223 void insertRegSizeForMode(unsigned Mode, RegSizeInfo Info) {
224 Map.try_emplace(k: Mode, args&: Info);
225 }
226};
227
228raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfo &T);
229raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfoByHwMode &T);
230
231struct SubRegRange {
232 uint16_t Size;
233 uint16_t Offset;
234
235 SubRegRange(const Record *R);
236 SubRegRange(uint16_t Size, uint16_t Offset) : Size(Size), Offset(Offset) {}
237};
238
239struct SubRegRangeByHwMode : public InfoByHwMode<SubRegRange> {
240 SubRegRangeByHwMode(const Record *R, const CodeGenHwModes &CGH);
241 SubRegRangeByHwMode(SubRegRange Range) {
242 Map.try_emplace(k: DefaultMode, args&: Range);
243 }
244 SubRegRangeByHwMode() = default;
245
246 void insertSubRegRangeForMode(unsigned Mode, SubRegRange Info) {
247 Map.try_emplace(k: Mode, args&: Info);
248 }
249};
250
251struct EncodingInfoByHwMode : public InfoByHwMode<const Record *> {
252 EncodingInfoByHwMode(const Record *R, const CodeGenHwModes &CGH);
253 EncodingInfoByHwMode() = default;
254};
255
256struct RegClassByHwMode : public InfoByHwMode<const CodeGenRegisterClass *> {
257public:
258 RegClassByHwMode(const Record *R, const CodeGenRegBank &RegBank);
259 RegClassByHwMode() = default;
260};
261
262struct RegisterByHwMode : public InfoByHwMode<const CodeGenRegister *> {
263 RegisterByHwMode(const Record *R, CodeGenRegBank &RegBank);
264 RegisterByHwMode() = default;
265 /// Resolve the register by calling <target>::RegByHwMode::get<name>(HwMode).
266 void emitResolverCall(raw_ostream &OS, const Twine &HwMode) const;
267
268private:
269 StringRef Namespace;
270};
271
272} // namespace llvm
273
274#endif // LLVM_UTILS_TABLEGEN_COMMON_INFOBYHWMODE_H
275