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