| //===- TypeIndex.h ----------------------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEINDEX_H |
| #define LLVM_DEBUGINFO_CODEVIEW_TYPEINDEX_H |
| |
| #include "llvm/ADT/DenseMapInfo.h" |
| #include "llvm/Support/Endian.h" |
| #include <cassert> |
| #include <cinttypes> |
| #include <functional> |
| |
| namespace llvm { |
| |
| class ScopedPrinter; |
| |
| namespace codeview { |
| |
| class TypeCollection; |
| |
| enum class SimpleTypeKind : uint32_t { |
| None = 0x0000, // uncharacterized type (no type) |
| Void = 0x0003, // void |
| NotTranslated = 0x0007, // type not translated by cvpack |
| HResult = 0x0008, // OLE/COM HRESULT |
| |
| SignedCharacter = 0x0010, // 8 bit signed |
| UnsignedCharacter = 0x0020, // 8 bit unsigned |
| NarrowCharacter = 0x0070, // really a char |
| WideCharacter = 0x0071, // wide char |
| Character16 = 0x007a, // char16_t |
| Character32 = 0x007b, // char32_t |
| |
| SByte = 0x0068, // 8 bit signed int |
| Byte = 0x0069, // 8 bit unsigned int |
| Int16Short = 0x0011, // 16 bit signed |
| UInt16Short = 0x0021, // 16 bit unsigned |
| Int16 = 0x0072, // 16 bit signed int |
| UInt16 = 0x0073, // 16 bit unsigned int |
| Int32Long = 0x0012, // 32 bit signed |
| UInt32Long = 0x0022, // 32 bit unsigned |
| Int32 = 0x0074, // 32 bit signed int |
| UInt32 = 0x0075, // 32 bit unsigned int |
| Int64Quad = 0x0013, // 64 bit signed |
| UInt64Quad = 0x0023, // 64 bit unsigned |
| Int64 = 0x0076, // 64 bit signed int |
| UInt64 = 0x0077, // 64 bit unsigned int |
| Int128Oct = 0x0014, // 128 bit signed int |
| UInt128Oct = 0x0024, // 128 bit unsigned int |
| Int128 = 0x0078, // 128 bit signed int |
| UInt128 = 0x0079, // 128 bit unsigned int |
| |
| Float16 = 0x0046, // 16 bit real |
| Float32 = 0x0040, // 32 bit real |
| Float32PartialPrecision = 0x0045, // 32 bit PP real |
| Float48 = 0x0044, // 48 bit real |
| Float64 = 0x0041, // 64 bit real |
| Float80 = 0x0042, // 80 bit real |
| Float128 = 0x0043, // 128 bit real |
| |
| Complex16 = 0x0056, // 16 bit complex |
| Complex32 = 0x0050, // 32 bit complex |
| Complex32PartialPrecision = 0x0055, // 32 bit PP complex |
| Complex48 = 0x0054, // 48 bit complex |
| Complex64 = 0x0051, // 64 bit complex |
| Complex80 = 0x0052, // 80 bit complex |
| Complex128 = 0x0053, // 128 bit complex |
| |
| Boolean8 = 0x0030, // 8 bit boolean |
| Boolean16 = 0x0031, // 16 bit boolean |
| Boolean32 = 0x0032, // 32 bit boolean |
| Boolean64 = 0x0033, // 64 bit boolean |
| Boolean128 = 0x0034, // 128 bit boolean |
| }; |
| |
| enum class SimpleTypeMode : uint32_t { |
| Direct = 0x00000000, // Not a pointer |
| NearPointer = 0x00000100, // Near pointer |
| FarPointer = 0x00000200, // Far pointer |
| HugePointer = 0x00000300, // Huge pointer |
| NearPointer32 = 0x00000400, // 32 bit near pointer |
| FarPointer32 = 0x00000500, // 32 bit far pointer |
| NearPointer64 = 0x00000600, // 64 bit near pointer |
| NearPointer128 = 0x00000700 // 128 bit near pointer |
| }; |
| |
| /// A 32-bit type reference. Types are indexed by their order of appearance in |
| /// .debug$T plus 0x1000. Type indices less than 0x1000 are "simple" types, |
| /// composed of a SimpleTypeMode byte followed by a SimpleTypeKind byte. |
| class TypeIndex { |
| public: |
| static const uint32_t FirstNonSimpleIndex = 0x1000; |
| static const uint32_t SimpleKindMask = 0x000000ff; |
| static const uint32_t SimpleModeMask = 0x00000700; |
| static const uint32_t DecoratedItemIdMask = 0x80000000; |
| |
| public: |
| TypeIndex() : Index(static_cast<uint32_t>(SimpleTypeKind::None)) {} |
| explicit TypeIndex(uint32_t Index) : Index(Index) {} |
| explicit TypeIndex(SimpleTypeKind Kind) |
| : Index(static_cast<uint32_t>(Kind)) {} |
| TypeIndex(SimpleTypeKind Kind, SimpleTypeMode Mode) |
| : Index(static_cast<uint32_t>(Kind) | static_cast<uint32_t>(Mode)) {} |
| |
| uint32_t getIndex() const { return Index; } |
| void setIndex(uint32_t I) { Index = I; } |
| bool isSimple() const { return Index < FirstNonSimpleIndex; } |
| bool isDecoratedItemId() const { return !!(Index & DecoratedItemIdMask); } |
| |
| bool isNoneType() const { return *this == None(); } |
| |
| uint32_t toArrayIndex() const { |
| assert(!isSimple()); |
| return getIndex() - FirstNonSimpleIndex; |
| } |
| |
| static TypeIndex fromArrayIndex(uint32_t Index) { |
| return TypeIndex(Index + FirstNonSimpleIndex); |
| } |
| |
| SimpleTypeKind getSimpleKind() const { |
| assert(isSimple()); |
| return static_cast<SimpleTypeKind>(Index & SimpleKindMask); |
| } |
| |
| SimpleTypeMode getSimpleMode() const { |
| assert(isSimple()); |
| return static_cast<SimpleTypeMode>(Index & SimpleModeMask); |
| } |
| |
| TypeIndex makeDirect() const { return TypeIndex{getSimpleKind()}; } |
| |
| static TypeIndex None() { return TypeIndex(SimpleTypeKind::None); } |
| static TypeIndex Void() { return TypeIndex(SimpleTypeKind::Void); } |
| static TypeIndex VoidPointer32() { |
| return TypeIndex(SimpleTypeKind::Void, SimpleTypeMode::NearPointer32); |
| } |
| static TypeIndex VoidPointer64() { |
| return TypeIndex(SimpleTypeKind::Void, SimpleTypeMode::NearPointer64); |
| } |
| |
| static TypeIndex NullptrT() { |
| // std::nullptr_t uses the pointer mode that doesn't indicate bit-width, |
| // presumably because std::nullptr_t is intended to be compatible with any |
| // pointer type. |
| return TypeIndex(SimpleTypeKind::Void, SimpleTypeMode::NearPointer); |
| } |
| |
| static TypeIndex SignedCharacter() { |
| return TypeIndex(SimpleTypeKind::SignedCharacter); |
| } |
| static TypeIndex UnsignedCharacter() { |
| return TypeIndex(SimpleTypeKind::UnsignedCharacter); |
| } |
| static TypeIndex NarrowCharacter() { |
| return TypeIndex(SimpleTypeKind::NarrowCharacter); |
| } |
| static TypeIndex WideCharacter() { |
| return TypeIndex(SimpleTypeKind::WideCharacter); |
| } |
| static TypeIndex Int16Short() { |
| return TypeIndex(SimpleTypeKind::Int16Short); |
| } |
| static TypeIndex UInt16Short() { |
| return TypeIndex(SimpleTypeKind::UInt16Short); |
| } |
| static TypeIndex Int32() { return TypeIndex(SimpleTypeKind::Int32); } |
| static TypeIndex UInt32() { return TypeIndex(SimpleTypeKind::UInt32); } |
| static TypeIndex Int32Long() { return TypeIndex(SimpleTypeKind::Int32Long); } |
| static TypeIndex UInt32Long() { |
| return TypeIndex(SimpleTypeKind::UInt32Long); |
| } |
| static TypeIndex Int64() { return TypeIndex(SimpleTypeKind::Int64); } |
| static TypeIndex UInt64() { return TypeIndex(SimpleTypeKind::UInt64); } |
| static TypeIndex Int64Quad() { return TypeIndex(SimpleTypeKind::Int64Quad); } |
| static TypeIndex UInt64Quad() { |
| return TypeIndex(SimpleTypeKind::UInt64Quad); |
| } |
| |
| static TypeIndex Float32() { return TypeIndex(SimpleTypeKind::Float32); } |
| static TypeIndex Float64() { return TypeIndex(SimpleTypeKind::Float64); } |
| |
| TypeIndex &operator+=(unsigned N) { |
| Index += N; |
| return *this; |
| } |
| |
| TypeIndex &operator++() { |
| Index += 1; |
| return *this; |
| } |
| |
| TypeIndex operator++(int) { |
| TypeIndex Copy = *this; |
| operator++(); |
| return Copy; |
| } |
| |
| TypeIndex &operator-=(unsigned N) { |
| assert(Index >= N); |
| Index -= N; |
| return *this; |
| } |
| |
| TypeIndex &operator--() { |
| Index -= 1; |
| return *this; |
| } |
| |
| TypeIndex operator--(int) { |
| TypeIndex Copy = *this; |
| operator--(); |
| return Copy; |
| } |
| |
| friend inline bool operator==(const TypeIndex &A, const TypeIndex &B) { |
| return A.getIndex() == B.getIndex(); |
| } |
| |
| friend inline bool operator!=(const TypeIndex &A, const TypeIndex &B) { |
| return A.getIndex() != B.getIndex(); |
| } |
| |
| friend inline bool operator<(const TypeIndex &A, const TypeIndex &B) { |
| return A.getIndex() < B.getIndex(); |
| } |
| |
| friend inline bool operator<=(const TypeIndex &A, const TypeIndex &B) { |
| return A.getIndex() <= B.getIndex(); |
| } |
| |
| friend inline bool operator>(const TypeIndex &A, const TypeIndex &B) { |
| return A.getIndex() > B.getIndex(); |
| } |
| |
| friend inline bool operator>=(const TypeIndex &A, const TypeIndex &B) { |
| return A.getIndex() >= B.getIndex(); |
| } |
| |
| friend inline TypeIndex operator+(const TypeIndex &A, uint32_t N) { |
| TypeIndex Result(A); |
| Result += N; |
| return Result; |
| } |
| |
| friend inline TypeIndex operator-(const TypeIndex &A, uint32_t N) { |
| assert(A.getIndex() >= N); |
| TypeIndex Result(A); |
| Result -= N; |
| return Result; |
| } |
| |
| friend inline uint32_t operator-(const TypeIndex &A, const TypeIndex &B) { |
| assert(A >= B); |
| return A.toArrayIndex() - B.toArrayIndex(); |
| } |
| |
| static StringRef simpleTypeName(TypeIndex TI); |
| |
| private: |
| support::ulittle32_t Index; |
| }; |
| |
| // Used for pseudo-indexing an array of type records. An array of such records |
| // sorted by TypeIndex can allow log(N) lookups even though such a type record |
| // stream does not provide random access. |
| struct TypeIndexOffset { |
| TypeIndex Type; |
| support::ulittle32_t Offset; |
| }; |
| |
| void printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, TypeIndex TI, |
| TypeCollection &Types); |
| } |
| |
| template <> struct DenseMapInfo<codeview::TypeIndex> { |
| static inline codeview::TypeIndex getEmptyKey() { |
| return codeview::TypeIndex{DenseMapInfo<uint32_t>::getEmptyKey()}; |
| } |
| static inline codeview::TypeIndex getTombstoneKey() { |
| return codeview::TypeIndex{DenseMapInfo<uint32_t>::getTombstoneKey()}; |
| } |
| static unsigned getHashValue(const codeview::TypeIndex &TI) { |
| return DenseMapInfo<uint32_t>::getHashValue(TI.getIndex()); |
| } |
| static bool isEqual(const codeview::TypeIndex &LHS, |
| const codeview::TypeIndex &RHS) { |
| return LHS == RHS; |
| } |
| }; |
| |
| } // namespace llvm |
| |
| #endif |