1 | //===- TypeIndex.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 | |
9 | #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEINDEX_H |
10 | #define LLVM_DEBUGINFO_CODEVIEW_TYPEINDEX_H |
11 | |
12 | #include "llvm/ADT/DenseMapInfo.h" |
13 | #include "llvm/Support/Endian.h" |
14 | #include <cassert> |
15 | #include <cinttypes> |
16 | |
17 | namespace llvm { |
18 | |
19 | class ScopedPrinter; |
20 | class StringRef; |
21 | |
22 | namespace codeview { |
23 | |
24 | class TypeCollection; |
25 | |
26 | enum class SimpleTypeKind : uint32_t { |
27 | None = 0x0000, // uncharacterized type (no type) |
28 | Void = 0x0003, // void |
29 | NotTranslated = 0x0007, // type not translated by cvpack |
30 | HResult = 0x0008, // OLE/COM HRESULT |
31 | |
32 | SignedCharacter = 0x0010, // 8 bit signed |
33 | UnsignedCharacter = 0x0020, // 8 bit unsigned |
34 | NarrowCharacter = 0x0070, // really a char |
35 | WideCharacter = 0x0071, // wide char |
36 | Character16 = 0x007a, // char16_t |
37 | Character32 = 0x007b, // char32_t |
38 | Character8 = 0x007c, // char8_t |
39 | |
40 | SByte = 0x0068, // 8 bit signed int |
41 | Byte = 0x0069, // 8 bit unsigned int |
42 | Int16Short = 0x0011, // 16 bit signed |
43 | UInt16Short = 0x0021, // 16 bit unsigned |
44 | Int16 = 0x0072, // 16 bit signed int |
45 | UInt16 = 0x0073, // 16 bit unsigned int |
46 | Int32Long = 0x0012, // 32 bit signed |
47 | UInt32Long = 0x0022, // 32 bit unsigned |
48 | Int32 = 0x0074, // 32 bit signed int |
49 | UInt32 = 0x0075, // 32 bit unsigned int |
50 | Int64Quad = 0x0013, // 64 bit signed |
51 | UInt64Quad = 0x0023, // 64 bit unsigned |
52 | Int64 = 0x0076, // 64 bit signed int |
53 | UInt64 = 0x0077, // 64 bit unsigned int |
54 | Int128Oct = 0x0014, // 128 bit signed int |
55 | UInt128Oct = 0x0024, // 128 bit unsigned int |
56 | Int128 = 0x0078, // 128 bit signed int |
57 | UInt128 = 0x0079, // 128 bit unsigned int |
58 | |
59 | Float16 = 0x0046, // 16 bit real |
60 | Float32 = 0x0040, // 32 bit real |
61 | Float32PartialPrecision = 0x0045, // 32 bit PP real |
62 | Float48 = 0x0044, // 48 bit real |
63 | Float64 = 0x0041, // 64 bit real |
64 | Float80 = 0x0042, // 80 bit real |
65 | Float128 = 0x0043, // 128 bit real |
66 | |
67 | Complex16 = 0x0056, // 16 bit complex |
68 | Complex32 = 0x0050, // 32 bit complex |
69 | Complex32PartialPrecision = 0x0055, // 32 bit PP complex |
70 | Complex48 = 0x0054, // 48 bit complex |
71 | Complex64 = 0x0051, // 64 bit complex |
72 | Complex80 = 0x0052, // 80 bit complex |
73 | Complex128 = 0x0053, // 128 bit complex |
74 | |
75 | Boolean8 = 0x0030, // 8 bit boolean |
76 | Boolean16 = 0x0031, // 16 bit boolean |
77 | Boolean32 = 0x0032, // 32 bit boolean |
78 | Boolean64 = 0x0033, // 64 bit boolean |
79 | Boolean128 = 0x0034, // 128 bit boolean |
80 | }; |
81 | |
82 | enum class SimpleTypeMode : uint32_t { |
83 | Direct = 0x00000000, // Not a pointer |
84 | NearPointer = 0x00000100, // Near pointer |
85 | FarPointer = 0x00000200, // Far pointer |
86 | HugePointer = 0x00000300, // Huge pointer |
87 | NearPointer32 = 0x00000400, // 32 bit near pointer |
88 | FarPointer32 = 0x00000500, // 32 bit far pointer |
89 | NearPointer64 = 0x00000600, // 64 bit near pointer |
90 | NearPointer128 = 0x00000700 // 128 bit near pointer |
91 | }; |
92 | |
93 | /// A 32-bit type reference. Types are indexed by their order of appearance in |
94 | /// .debug$T plus 0x1000. Type indices less than 0x1000 are "simple" types, |
95 | /// composed of a SimpleTypeMode byte followed by a SimpleTypeKind byte. |
96 | class TypeIndex { |
97 | public: |
98 | static const uint32_t FirstNonSimpleIndex = 0x1000; |
99 | static const uint32_t SimpleKindMask = 0x000000ff; |
100 | static const uint32_t SimpleModeMask = 0x00000700; |
101 | static const uint32_t DecoratedItemIdMask = 0x80000000; |
102 | |
103 | public: |
104 | TypeIndex() : Index(static_cast<uint32_t>(SimpleTypeKind::None)) {} |
105 | explicit TypeIndex(uint32_t Index) : Index(Index) {} |
106 | explicit TypeIndex(SimpleTypeKind Kind) |
107 | : Index(static_cast<uint32_t>(Kind)) {} |
108 | TypeIndex(SimpleTypeKind Kind, SimpleTypeMode Mode) |
109 | : Index(static_cast<uint32_t>(Kind) | static_cast<uint32_t>(Mode)) {} |
110 | |
111 | uint32_t getIndex() const { return Index; } |
112 | void setIndex(uint32_t I) { Index = I; } |
113 | bool isSimple() const { return Index < FirstNonSimpleIndex; } |
114 | bool isDecoratedItemId() const { return !!(Index & DecoratedItemIdMask); } |
115 | |
116 | bool isNoneType() const { return *this == None(); } |
117 | |
118 | uint32_t toArrayIndex() const { |
119 | assert(!isSimple()); |
120 | return (getIndex() & ~DecoratedItemIdMask) - FirstNonSimpleIndex; |
121 | } |
122 | |
123 | static TypeIndex fromArrayIndex(uint32_t Index) { |
124 | return TypeIndex(Index + FirstNonSimpleIndex); |
125 | } |
126 | |
127 | static TypeIndex fromDecoratedArrayIndex(bool IsItem, uint32_t Index) { |
128 | return TypeIndex((Index + FirstNonSimpleIndex) | |
129 | (IsItem ? DecoratedItemIdMask : 0)); |
130 | } |
131 | |
132 | TypeIndex removeDecoration() { |
133 | return TypeIndex(Index & ~DecoratedItemIdMask); |
134 | } |
135 | |
136 | SimpleTypeKind getSimpleKind() const { |
137 | assert(isSimple()); |
138 | return static_cast<SimpleTypeKind>(Index & SimpleKindMask); |
139 | } |
140 | |
141 | SimpleTypeMode getSimpleMode() const { |
142 | assert(isSimple()); |
143 | return static_cast<SimpleTypeMode>(Index & SimpleModeMask); |
144 | } |
145 | |
146 | TypeIndex makeDirect() const { return TypeIndex{getSimpleKind()}; } |
147 | |
148 | static TypeIndex None() { return TypeIndex(SimpleTypeKind::None); } |
149 | static TypeIndex Void() { return TypeIndex(SimpleTypeKind::Void); } |
150 | static TypeIndex VoidPointer32() { |
151 | return TypeIndex(SimpleTypeKind::Void, SimpleTypeMode::NearPointer32); |
152 | } |
153 | static TypeIndex VoidPointer64() { |
154 | return TypeIndex(SimpleTypeKind::Void, SimpleTypeMode::NearPointer64); |
155 | } |
156 | |
157 | static TypeIndex NullptrT() { |
158 | // std::nullptr_t uses the pointer mode that doesn't indicate bit-width, |
159 | // presumably because std::nullptr_t is intended to be compatible with any |
160 | // pointer type. |
161 | return TypeIndex(SimpleTypeKind::Void, SimpleTypeMode::NearPointer); |
162 | } |
163 | |
164 | static TypeIndex SignedCharacter() { |
165 | return TypeIndex(SimpleTypeKind::SignedCharacter); |
166 | } |
167 | static TypeIndex UnsignedCharacter() { |
168 | return TypeIndex(SimpleTypeKind::UnsignedCharacter); |
169 | } |
170 | static TypeIndex NarrowCharacter() { |
171 | return TypeIndex(SimpleTypeKind::NarrowCharacter); |
172 | } |
173 | static TypeIndex WideCharacter() { |
174 | return TypeIndex(SimpleTypeKind::WideCharacter); |
175 | } |
176 | static TypeIndex Int16Short() { |
177 | return TypeIndex(SimpleTypeKind::Int16Short); |
178 | } |
179 | static TypeIndex UInt16Short() { |
180 | return TypeIndex(SimpleTypeKind::UInt16Short); |
181 | } |
182 | static TypeIndex Int32() { return TypeIndex(SimpleTypeKind::Int32); } |
183 | static TypeIndex UInt32() { return TypeIndex(SimpleTypeKind::UInt32); } |
184 | static TypeIndex Int32Long() { return TypeIndex(SimpleTypeKind::Int32Long); } |
185 | static TypeIndex UInt32Long() { |
186 | return TypeIndex(SimpleTypeKind::UInt32Long); |
187 | } |
188 | static TypeIndex Int64() { return TypeIndex(SimpleTypeKind::Int64); } |
189 | static TypeIndex UInt64() { return TypeIndex(SimpleTypeKind::UInt64); } |
190 | static TypeIndex Int64Quad() { return TypeIndex(SimpleTypeKind::Int64Quad); } |
191 | static TypeIndex UInt64Quad() { |
192 | return TypeIndex(SimpleTypeKind::UInt64Quad); |
193 | } |
194 | |
195 | static TypeIndex Float32() { return TypeIndex(SimpleTypeKind::Float32); } |
196 | static TypeIndex Float64() { return TypeIndex(SimpleTypeKind::Float64); } |
197 | |
198 | TypeIndex &operator+=(unsigned N) { |
199 | Index += N; |
200 | return *this; |
201 | } |
202 | |
203 | TypeIndex &operator++() { |
204 | Index += 1; |
205 | return *this; |
206 | } |
207 | |
208 | TypeIndex operator++(int) { |
209 | TypeIndex Copy = *this; |
210 | operator++(); |
211 | return Copy; |
212 | } |
213 | |
214 | TypeIndex &operator-=(unsigned N) { |
215 | assert(Index >= N); |
216 | Index -= N; |
217 | return *this; |
218 | } |
219 | |
220 | TypeIndex &operator--() { |
221 | Index -= 1; |
222 | return *this; |
223 | } |
224 | |
225 | TypeIndex operator--(int) { |
226 | TypeIndex Copy = *this; |
227 | operator--(); |
228 | return Copy; |
229 | } |
230 | |
231 | friend inline bool operator==(const TypeIndex &A, const TypeIndex &B) { |
232 | return A.getIndex() == B.getIndex(); |
233 | } |
234 | |
235 | friend inline bool operator!=(const TypeIndex &A, const TypeIndex &B) { |
236 | return A.getIndex() != B.getIndex(); |
237 | } |
238 | |
239 | friend inline bool operator<(const TypeIndex &A, const TypeIndex &B) { |
240 | return A.getIndex() < B.getIndex(); |
241 | } |
242 | |
243 | friend inline bool operator<=(const TypeIndex &A, const TypeIndex &B) { |
244 | return A.getIndex() <= B.getIndex(); |
245 | } |
246 | |
247 | friend inline bool operator>(const TypeIndex &A, const TypeIndex &B) { |
248 | return A.getIndex() > B.getIndex(); |
249 | } |
250 | |
251 | friend inline bool operator>=(const TypeIndex &A, const TypeIndex &B) { |
252 | return A.getIndex() >= B.getIndex(); |
253 | } |
254 | |
255 | friend inline TypeIndex operator+(const TypeIndex &A, uint32_t N) { |
256 | TypeIndex Result(A); |
257 | Result += N; |
258 | return Result; |
259 | } |
260 | |
261 | friend inline TypeIndex operator-(const TypeIndex &A, uint32_t N) { |
262 | assert(A.getIndex() >= N); |
263 | TypeIndex Result(A); |
264 | Result -= N; |
265 | return Result; |
266 | } |
267 | |
268 | friend inline uint32_t operator-(const TypeIndex &A, const TypeIndex &B) { |
269 | assert(A >= B); |
270 | return A.toArrayIndex() - B.toArrayIndex(); |
271 | } |
272 | |
273 | static StringRef simpleTypeName(TypeIndex TI); |
274 | |
275 | private: |
276 | support::ulittle32_t Index; |
277 | }; |
278 | |
279 | // Used for pseudo-indexing an array of type records. An array of such records |
280 | // sorted by TypeIndex can allow log(N) lookups even though such a type record |
281 | // stream does not provide random access. |
282 | struct TypeIndexOffset { |
283 | TypeIndex Type; |
284 | support::ulittle32_t Offset; |
285 | }; |
286 | |
287 | void printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, TypeIndex TI, |
288 | TypeCollection &Types); |
289 | } |
290 | |
291 | template <> struct DenseMapInfo<codeview::TypeIndex> { |
292 | static inline codeview::TypeIndex getEmptyKey() { |
293 | return codeview::TypeIndex{DenseMapInfo<uint32_t>::getEmptyKey()}; |
294 | } |
295 | static inline codeview::TypeIndex getTombstoneKey() { |
296 | return codeview::TypeIndex{DenseMapInfo<uint32_t>::getTombstoneKey()}; |
297 | } |
298 | static unsigned getHashValue(const codeview::TypeIndex &TI) { |
299 | return DenseMapInfo<uint32_t>::getHashValue(Val: TI.getIndex()); |
300 | } |
301 | static bool isEqual(const codeview::TypeIndex &LHS, |
302 | const codeview::TypeIndex &RHS) { |
303 | return LHS == RHS; |
304 | } |
305 | }; |
306 | |
307 | } // namespace llvm |
308 | |
309 | #endif |
310 | |