Index: examples/Kaleidoscope/Chapter8/toy.cpp =================================================================== --- examples/Kaleidoscope/Chapter8/toy.cpp +++ examples/Kaleidoscope/Chapter8/toy.cpp @@ -1234,7 +1234,7 @@ unsigned ScopeLine = Line; DISubprogram *SP = DBuilder->createFunction( FContext, Name, StringRef(), Unit, LineNo, - CreateFunctionType(Args.size(), Unit), false /* internal linkage */, + CreateFunctionType(Args.size(), Unit), codeview::TypeIndex(), false /* internal linkage */, true /* definition */, ScopeLine, DINode::FlagPrototyped, false, F); KSDbgInfo.FnScopeMap[this] = SP; @@ -1255,7 +1255,7 @@ KSDbgInfo.TheCU->getDirectory()); DILocalVariable *D = DBuilder->createLocalVariable( dwarf::DW_TAG_arg_variable, Scope, Args[Idx], Unit, Line, - KSDbgInfo.getDoubleTy(), Idx); + KSDbgInfo.getDoubleTy(), codeview::TypeIndex(), Idx); DBuilder->insertDeclare(Alloca, D, DBuilder->createExpression(), DebugLoc::get(Line, 0, Scope), Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -167,7 +167,9 @@ METADATA_EXPRESSION = 29, // [distinct, n x element] METADATA_OBJC_PROPERTY = 30, // [distinct, name, file, line, ...] METADATA_IMPORTED_ENTITY=31, // [distinct, tag, scope, entity, line, name] - METADATA_MODULE=32, // [distinct, scope, name, ...] + METADATA_MODULE =32, // [distinct, scope, name, ...] + METADATA_CODEVIEW_TYPES =33, // [distinct, signature, typeRecords, udtSymbols] + METADATA_CODEVIEW_UDT =34, // [distinct, typeIndex, name] }; // The constants block (CONSTANTS_BLOCK_ID) describes emission for each Index: include/llvm/CodeView/CodeView.h =================================================================== --- /dev/null +++ include/llvm/CodeView/CodeView.h @@ -0,0 +1,381 @@ +#ifndef LLVM_CODEVIEW_CODEVIEW_H +#define LLVM_CODEVIEW_CODEVIEW_H + +#include + +namespace llvm +{ +namespace codeview +{ + +enum class CallingConvention : uint8_t +{ + NearC = 0x00, // near right to left push, caller pops stack + FarC = 0x01, // far right to left push, caller pops stack + NearPascal = 0x02, // near left to right push, callee pops stack + FarPascal = 0x03, // far left to right push, callee pops stack + NearFast = 0x04, // near left to right push with regs, callee pops stack + FarFast = 0x05, // far left to right push with regs, callee pops stack + NearStdCall = 0x07, // near standard call + FarStdCall = 0x08, // far standard call + NearSysCall = 0x09, // near sys call + FarSysCall = 0x0a, // far sys call + ThisCall = 0x0b, // this call (this passed in register) + MipsCall = 0x0c, // Mips call + Generic = 0x0d, // Generic call sequence + AlphaCall = 0x0e, // Alpha call + PpcCall = 0x0f, // PPC call + SHCall = 0x10, // Hitachi SuperH call + ArmCall = 0x11, // ARM call + AM33Call = 0x12, // AM33 call + TriCall = 0x13, // TriCore Call + SH5Call = 0x14, // Hitachi SuperH-5 call + M32RCall = 0x15, // M32R Call + ClrCall = 0x16, // clr call + Inline = 0x17, // Marker for routines always inlined and thus lacking a convention + NearVector = 0x18 // near left to right push with regs, callee pops stack +}; + +enum class ClassOptions : uint16_t +{ + None = 0x0000, + Packed = 0x0001, + HasConstructorOrDestructor = 0x0002, + HasOverloadedOperator = 0x0004, + Nested = 0x0008, + ContainsNestedClass = 0x0010, + HasOverloadedAssignmentOperator = 0x0020, + HasConversionOperator = 0x0040, + ForwardReference = 0x0080, + Scoped = 0x0100, + HasUniqueName = 0x0200, + Sealed = 0x0400, + Intrinsic = 0x2000 +}; + +inline ClassOptions operator|(ClassOptions a, ClassOptions b) throw() +{ + return static_cast(static_cast(a) | static_cast(b)); +} + +inline ClassOptions operator&(ClassOptions a, ClassOptions b) throw() +{ + return static_cast(static_cast(a)& static_cast(b)); +} + +inline ClassOptions operator~(ClassOptions a) throw() +{ + return static_cast(~static_cast(a)); +} + +enum class FrameProcedureOptions : uint32_t +{ + None = 0x00000000, + HasAlloca = 0x00000001, + HasSetJmp = 0x00000002, + HasLongJmp = 0x00000004, + HasInlineAssembly = 0x00000008, + HasExceptionHandling = 0x00000010, + MarkedInline = 0x00000020, + HasStructuredExceptionHandling = 0x00000040, + Naked = 0x00000080, + SecurityChecks = 0x00000100, + AsynchronousExceptionHandling = 0x00000200, + NoStackOrderingForSecurityChecks = 0x00000400, + Inlined = 0x00000800, + StrictSecurityChecks = 0x00001000, + SafeBuffers = 0x00002000, + ProfileGuidedOptimization = 0x00040000, + ValidProfileCounts = 0x00080000, + OptimizedForSpeed = 0x00100000, + GuardCfg = 0x00200000, + GuardCfw = 0x00400000 +}; + +inline FrameProcedureOptions operator|(FrameProcedureOptions a, FrameProcedureOptions b) throw() +{ + return static_cast(static_cast(a) | static_cast(b)); +} + +inline FrameProcedureOptions operator&(FrameProcedureOptions a, FrameProcedureOptions b) throw() +{ + return static_cast(static_cast(a)& static_cast(b)); +} + +inline FrameProcedureOptions operator~(FrameProcedureOptions a) throw() +{ + return static_cast(~static_cast(a)); +} + +enum class FunctionOptions : uint8_t +{ + None = 0x00, + CxxReturnUdt = 0x01, + Constructor = 0x02, + ConstructorWithVirtualBases = 0x04 +}; + +inline FunctionOptions operator|(FunctionOptions a, FunctionOptions b) throw() +{ + return static_cast(static_cast(a) | static_cast(b)); +} + +inline FunctionOptions operator&(FunctionOptions a, FunctionOptions b) throw() +{ + return static_cast(static_cast(a)& static_cast(b)); +} + +inline FunctionOptions operator~(FunctionOptions a) throw() +{ + return static_cast(~static_cast(a)); +} + +enum class HfaKind : uint8_t +{ + None = 0x00, + Float = 0x01, + Double = 0x02, + Other = 0x03 +}; + +enum class MemberAccess : uint8_t +{ + None = 0, + Private = 1, + Protected = 2, + Public = 3 +}; + +enum class MethodKind : uint8_t +{ + Vanilla = 0x00, + Virtual = 0x01, + Static = 0x02, + Friend = 0x03, + IntroducingVirtual = 0x04, + PureVirtual = 0x05, + PureIntroducingVirtual = 0x06 +}; + +enum class MethodOptions : uint16_t +{ + None = 0x0000, + Pseudo = 0x0020, + CompilerGenerated = 0x0100, + Sealed = 0x0200 +}; + +inline MethodOptions operator|(MethodOptions a, MethodOptions b) throw() +{ + return static_cast(static_cast(a) | static_cast(b)); +} + +inline MethodOptions operator&(MethodOptions a, MethodOptions b) throw() +{ + return static_cast(static_cast(a)& static_cast(b)); +} + +inline MethodOptions operator~(MethodOptions a) throw() +{ + return static_cast(~static_cast(a)); +} + +enum class ModifierOptions : uint16_t +{ + None = 0x0000, + Const = 0x0001, + Volatile = 0x0002, + Unaligned = 0x0004 +}; + +inline ModifierOptions operator|(ModifierOptions a, ModifierOptions b) throw() +{ + return static_cast(static_cast(a) | static_cast(b)); +} + +inline ModifierOptions operator&(ModifierOptions a, ModifierOptions b) throw() +{ + return static_cast(static_cast(a)& static_cast(b)); +} + +inline ModifierOptions operator~(ModifierOptions a) throw() +{ + return static_cast(~static_cast(a)); +} + +enum class ModuleSubstreamKind : uint32_t +{ + Symbols = 0xf1, + Lines = 0xf2, + StringTable = 0xf3, + FileChecksums = 0xf4, + FrameData = 0xf5, + InlineeLines = 0xf6, + CrossScopeImports = 0xf7, + CrossScopeExports = 0xf8 +}; + +enum class PointerKind : uint8_t +{ + Near16 = 0x00, // 16 bit pointer + Far16 = 0x01, // 16:16 far pointer + Huge16 = 0x02, // 16:16 huge pointer + BasedOnSegment = 0x03, // based on segment + BasedOnValue = 0x04, // based on value of base + BasedOnSegmentValue = 0x05, // based on segment value of base + BasedOnAddress = 0x06, // based on address of base + BasedOnSegmentAddress = 0x07, // based on segment address of base + BasedOnType = 0x08, // based on type + BasedOnSelf = 0x09, // based on self + Near32 = 0x0a, // 32 bit pointer + Far32 = 0x0b, // 16:32 pointer + Near64 = 0x0c // 64 bit pointer +}; + +enum class PointerMode : uint8_t +{ + Pointer = 0x00, // "normal" pointer + LValueReference = 0x01, // "old" reference + PointerToDataMember = 0x02, // pointer to data member + PointerToMemberFunction = 0x03, // pointer to member function + RValueReference = 0x04 // r-value reference +}; + +enum class PointerOptions : uint32_t +{ + None = 0x00000000, + Flat32 = 0x00000100, + Volatile = 0x00000200, + Const = 0x00000400, + Unaligned = 0x00000800, + Restrict = 0x00001000, + WinRTSmartPointer = 0x00080000 +}; + +inline PointerOptions operator|(PointerOptions a, PointerOptions b) throw() +{ + return static_cast(static_cast(a) | static_cast(b)); +} + +inline PointerOptions operator&(PointerOptions a, PointerOptions b) throw() +{ + return static_cast(static_cast(a)& static_cast(b)); +} + +inline PointerOptions operator~(PointerOptions a) throw() +{ + return static_cast(~static_cast(a)); +} + +enum class PointerToMemberRepresentation : uint16_t +{ + Unknown = 0x00, // not specified (pre VC8) + SingleInheritanceData = 0x01, // member data, single inheritance + MultipleInheritanceData = 0x02, // member data, multiple inheritance + VirtualInheritanceData = 0x03, // member data, virtual inheritance + GeneralData = 0x04, // member data, most general + SingleInheritanceFunction = 0x05, // member function, single inheritance + MultipleInheritanceFunction = 0x06, // member function, multiple inheritance + VirtualInheritanceFunction = 0x07, // member function, virtual inheritance + GeneralFunction = 0x08 // member function, most general +}; + +enum class TypeRecordKind : uint16_t +{ + None = 0, + + VirtualTableShape = 0x000a, + Label = 0x000e, + EndPrecompiledHeader = 0x0014, + + Modifier = 0x1001, + Pointer = 0x1002, + Procedure = 0x1008, + MemberFunction = 0x1009, + + Oem = 0x100f, + Oem2 = 0x1011, + + ArgumentList = 0x1201, + FieldList = 0x1203, + BitField = 0x1205, + MethodList = 0x1206, + + BaseClass = 0x1400, + VirtualBaseClass = 0x1401, + IndirectVirtualBaseClass = 0x1402, + Index = 0x1404, + VirtualFunctionTablePointer = 0x1409, + + Enumerate = 0x1502, + Array = 0x1503, + Class = 0x1504, + Structure = 0x1505, + Union = 0x1506, + Enum = 0x1507, + Alias = 0x150a, + Member = 0x150d, + StaticMember = 0x150e, + Method = 0x150f, + NestedType = 0x1510, + OneMethod = 0x1511, + VirtualFunctionTable = 0x151d, + + FunctionId = 0x1601, + MemberFunctionId = 0x1602, + BuildInfo = 0x1603, + SubstringList = 0x1604, + StringId = 0x1605, + UdtSourceLine = 0x1606, + + SByte = 0x8000, + Int16 = 0x8001, + UInt16 = 0x8002, + Int32 = 0x8003, + UInt32 = 0x8004, + Single = 0x8005, + Double = 0x8006, + Float80 = 0x8007, + Float128 = 0x8008, + Int64 = 0x8009, + UInt64 = 0x800a, + Float48 = 0x800b, + Complex32 = 0x800c, + Complex64 = 0x800d, + Complex80 = 0x800e, + Complex128 = 0x800f, + VarString = 0x8010, + + Int128 = 0x8017, + UInt128 = 0x8018, + + Decimal = 0x8019, + Date = 0x801a, + Utf8String = 0x801b, + + Float16 = 0x801c +}; + +enum class VirtualTableSlotKind : uint8_t +{ + Near16 = 0x00, + Far16 = 0x01, + This = 0x02, + Outer = 0x03, + Meta = 0x04, + Near = 0x05, + Far = 0x06 +}; + +enum class WindowsRTClassKind : uint8_t +{ + None = 0x00, + RefClass = 0x01, + ValueClass = 0x02, + Interface = 0x03 +}; + +} +} + +#endif Index: include/llvm/CodeView/CodeViewOStream.h =================================================================== --- /dev/null +++ include/llvm/CodeView/CodeViewOStream.h @@ -0,0 +1,33 @@ +#ifndef LLVM_CODEVIEW_CODEVIEWOSTREAM_H +#define LLVM_CODEVIEW_CODEVIEWOSTREAM_H + +#include "llvm/CodeView/TypeIndex.h" +#include "llvm/CodeView/CodeView.h" + +namespace llvm { +namespace codeview { + +template +class CodeViewOStream +{ +private: + CodeViewOStream(const CodeViewOStream&) = delete; + CodeViewOStream& operator=(const CodeViewOStream&) = delete; + +public: + typedef typename Writer::LabelType LabelType; + +public: + explicit CodeViewOStream(Writer& W); + +private: + uint64_t size() const { return W.tell(); } + +private: + Writer& W; +}; + +} +} + +#endif Index: include/llvm/CodeView/FieldListRecordBuilder.h =================================================================== --- /dev/null +++ include/llvm/CodeView/FieldListRecordBuilder.h @@ -0,0 +1,82 @@ +#ifndef LLVM_CODEVIEW_FIELDLISTRECORDBUILDER_H +#define LLVM_CODEVIEW_FIELDLISTRECORDBUILDER_H + +#include "llvm/CodeView/ListRecordBuilder.h" + +namespace llvm { +namespace codeview { + +class MethodInfo +{ +public: + MethodInfo() : + Access(), + Kind(), + Options(), + Type(), + VTableSlotOffset(-1) + { + } + + MethodInfo(MemberAccess Access, MethodKind Kind, MethodOptions Options, + TypeIndex Type, int32_t VTableSlotOffset) : + Access(Access), + Kind(Kind), + Options(Options), + Type(Type), + VTableSlotOffset(VTableSlotOffset) + { + } + + MemberAccess getAccess() const { return Access; } + MethodKind getKind() const { return Kind; } + MethodOptions getOptions() const { return Options; } + TypeIndex getType() const { return Type; } + int32_t getVTableSlotOffset() const { return VTableSlotOffset; } + +private: + MemberAccess Access; + MethodKind Kind; + MethodOptions Options; + TypeIndex Type; + int32_t VTableSlotOffset; +}; + +class FieldListRecordBuilder : public ListRecordBuilder +{ +private: + FieldListRecordBuilder(const FieldListRecordBuilder&) = delete; + void operator=(const FieldListRecordBuilder&) = delete; + +public: + FieldListRecordBuilder(); + + void writeBaseClass(MemberAccess Access, TypeIndex Type, uint64_t Offset); + void writeEnumerate(MemberAccess Access, uint64_t Value, StringRef Name); + void writeIndirectVirtualBaseClass(MemberAccess Access, TypeIndex Type, + TypeIndex VirtualBasePointerType, int64_t VirtualBasePointerOffset, + uint64_t SlotIndex); + void writeMember(MemberAccess Access, TypeIndex Type, uint64_t Offset, + StringRef Name); + void writeOneMethod(MemberAccess Access, MethodKind Kind, + MethodOptions Options, TypeIndex Type, int32_t VTableSlotOffset, + StringRef Name); + void writeOneMethod(const MethodInfo& Method, StringRef Name); + void writeMethod(uint16_t OverloadCount, TypeIndex MethodList, + StringRef Name); + void writeNestedType(TypeIndex Type, StringRef Name); + void writeStaticMember(MemberAccess Access, TypeIndex Type, + StringRef Name); + void writeVirtualBaseClass(MemberAccess Access, TypeIndex Type, + TypeIndex VirtualBasePointerType, int64_t VirtualBasePointerOffset, + uint64_t SlotIndex); + void writeVirtualBaseClass(TypeRecordKind Kind, MemberAccess Access, + TypeIndex Type, TypeIndex VirtualBasePointerType, + int64_t VirtualBasePointerOffset, uint64_t SlotIndex); + void writeVirtualFunctionTablePointer(TypeIndex Type); +}; + +} +} + +#endif Index: include/llvm/CodeView/FunctionId.h =================================================================== --- /dev/null +++ include/llvm/CodeView/FunctionId.h @@ -0,0 +1,62 @@ +#ifndef LLVM_CODEVIEW_FUNCTIONID_H +#define LLVM_CODEVIEW_FUNCTIONID_H + +#include + +namespace llvm { +namespace codeview { + +class FunctionId +{ +public: + FunctionId() : + Index(0) + { + } + + explicit FunctionId(uint32_t Index) : + Index(Index) + { + } + + uint32_t getIndex() const { return Index; } + +private: + uint32_t Index; +}; + +inline bool operator==(const FunctionId& A, const FunctionId& B) +{ + return A.getIndex() == B.getIndex(); +} + +inline bool operator!=(const FunctionId& A, const FunctionId& B) +{ + return A.getIndex() != B.getIndex(); +} + +inline bool operator<(const FunctionId& A, const FunctionId& B) +{ + return A.getIndex() < B.getIndex(); +} + +inline bool operator<=(const FunctionId& A, const FunctionId& B) +{ + return A.getIndex() <= B.getIndex(); +} + +inline bool operator>(const FunctionId& A, const FunctionId& B) +{ + return A.getIndex() > B.getIndex(); +} + +inline bool operator>=(const FunctionId& A, const FunctionId& B) +{ + return A.getIndex() >= B.getIndex(); +} + +} +} + +#endif + Index: include/llvm/CodeView/Line.h =================================================================== --- /dev/null +++ include/llvm/CodeView/Line.h @@ -0,0 +1,114 @@ +#ifndef LLVM_CODEVIEW_LINE_H +#define LLVM_CODEVIEW_LINE_H + +#include + +namespace llvm { +namespace codeview { + +class LineInfo +{ +public: + static const int32_t AlwaysStepIntoLineNumber = 0xfeefee; + static const int32_t NeverStepIntoLineNumber = 0xf00f00; + +private: + static const uint32_t StartLineMask = 0x00ffffff; + static const uint32_t EndLineDeltaMask = 0x7f000000; + static const int EndLineDeltaShift = 24; + static const uint32_t StatementFlag = 0x80000000u; + +public: + LineInfo(uint32_t StartLine, uint32_t EndLine, bool IsStatement); + + uint32_t getStartLine() const { return LineData & StartLineMask; } + + uint32_t getLineDelta() const { return (LineData & EndLineDeltaMask) >> EndLineDeltaShift; } + + uint32_t getEndLine() const { return getStartLine() + getLineDelta(); } + + bool isStatement() const { return (LineData & StatementFlag) != 0; } + + uint32_t getRawData() const { return LineData; } + + bool isAlwaysStepInto() const { return getStartLine() == AlwaysStepIntoLineNumber; } + + bool isNeverStepInto() const { return getStartLine() == NeverStepIntoLineNumber; } + +private: + uint32_t LineData; +}; + +class ColumnInfo +{ +private: + static const uint32_t StartColumnMask = 0x0000ffffu; + static const uint32_t EndColumnMask = 0xffff0000u; + static const int EndColumnShift = 16; + +public: + ColumnInfo(uint16_t StartColumn, uint16_t EndColumn) + { + ColumnData = (static_cast(StartColumn)& StartColumnMask) | + ((static_cast(EndColumn) << EndColumnShift) & EndColumnMask); + } + + uint16_t getStartColumn() const { return static_cast(ColumnData & StartColumnMask); } + + uint16_t getEndColumn() const { return static_cast((ColumnData & EndColumnMask) >> EndColumnShift); } + + uint32_t getRawData() const { return ColumnData; } + +private: + uint32_t ColumnData; +}; + +class Line +{ +private: + int32_t CodeOffset; + LineInfo LineInf; + ColumnInfo ColumnInf; + +public: + Line(int32_t CodeOffset, uint32_t StartLine, uint32_t EndLine, uint16_t StartColumn, uint16_t EndColumn, bool IsStatement) : + CodeOffset(CodeOffset), + LineInf(StartLine, EndLine, IsStatement), + ColumnInf(StartColumn, EndColumn) + { + } + + Line(int32_t CodeOffset, LineInfo LineInf, ColumnInfo ColumnInf) : + CodeOffset(CodeOffset), + LineInf(LineInf), + ColumnInf(ColumnInf) + { + } + + LineInfo getLineInfo() const { return LineInf; } + + ColumnInfo getColumnInfo() const { return ColumnInf; } + + int32_t getCodeOffset() const { return CodeOffset; } + + uint32_t getStartLine() const { return LineInf.getStartLine(); } + + uint32_t getLineDelta() const { return LineInf.getLineDelta(); } + + uint32_t getEndLine() const { return LineInf.getEndLine(); } + + uint16_t getStartColumn() const { return ColumnInf.getStartColumn(); } + + uint16_t getEndColumn() const { return ColumnInf.getEndColumn(); } + + bool isStatement() const { return LineInf.isStatement(); } + + bool isAlwaysStepInto() const { return LineInf.isAlwaysStepInto(); } + + bool isNeverStepInto() const { return LineInf.isNeverStepInto(); } +}; + +} +} + +#endif Index: include/llvm/CodeView/ListRecordBuilder.h =================================================================== --- /dev/null +++ include/llvm/CodeView/ListRecordBuilder.h @@ -0,0 +1,42 @@ +#ifndef LLVM_CODEVIEW_LISTRECORDBUILDER_H +#define LLVM_CODEVIEW_LISTRECORDBUILDER_H + +#include "llvm/CodeView/TypeRecordBuilder.h" + +namespace llvm { +namespace codeview { + +class ListRecordBuilder +{ +private: + ListRecordBuilder(const ListRecordBuilder&) = delete; + ListRecordBuilder& operator=(const ListRecordBuilder&) = delete; + +protected: + const int MethodKindShift = 2; + + explicit ListRecordBuilder(TypeRecordKind Kind); + +public: + llvm::StringRef str() + { + return Builder.str(); + } + +protected: + void finishSubRecord(); + + TypeRecordBuilder& getBuilder() + { + return Builder; + } + +private: + TypeRecordBuilder Builder; + SmallVector ContinuationOffsets; +}; + +} +} + +#endif Index: include/llvm/CodeView/MemoryTypeTableBuilder.h =================================================================== --- /dev/null +++ include/llvm/CodeView/MemoryTypeTableBuilder.h @@ -0,0 +1,67 @@ +#ifndef LLVM_CODEVIEW_MEMORYTYPETABLEBUILDER_H +#define LLVM_CODEVIEW_MEMORYTYPETABLEBUILDER_H + +#include "llvm/CodeView/TypeTableBuilder.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/StringRef.h" +#include +#include +#include +#include + +namespace llvm { +namespace codeview { + +class MemoryTypeTableBuilder : public TypeTableBuilder +{ +public: + class Record + { + public: + explicit Record(llvm::StringRef RData); + + const char* data() const { return Data.get(); } + uint16_t size() const { return Size; } + + private: + uint16_t Size; + std::unique_ptr Data; + }; + +private: + class RecordHash : std::unary_function + { + public: + size_t operator()(llvm::StringRef Val) const { + return static_cast(llvm::hash_value(Val)); + } + }; + +public: + MemoryTypeTableBuilder() + { + } + + template + void ForEachRecord(TFunc Func) + { + uint32_t Index = TypeIndex::FirstNonSimpleIndex; + + for (const std::unique_ptr& R : Records) { + Func(TypeIndex(Index), R.get()); + ++Index; + } + } + +private: + virtual TypeIndex writeRecord(llvm::StringRef Data) override; + +private: + std::vector> Records; + std::unordered_map HashedRecords; +}; + +} +} + +#endif Index: include/llvm/CodeView/MethodListRecordBuilder.h =================================================================== --- /dev/null +++ include/llvm/CodeView/MethodListRecordBuilder.h @@ -0,0 +1,29 @@ +#ifndef LLVM_CODEVIEW_METHODLISTRECORDBUILDER_H +#define LLVM_CODEVIEW_METHODLISTRECORDBUILDER_H + +#include "llvm/CodeView/ListRecordBuilder.h" + +namespace llvm { +namespace codeview { + +class MethodInfo; + +class MethodListRecordBuilder : public ListRecordBuilder +{ +private: + MethodListRecordBuilder(const MethodListRecordBuilder&) = delete; + MethodListRecordBuilder& operator=(const MethodListRecordBuilder&) = delete; + +public: + MethodListRecordBuilder(); + + void writeMethod(MemberAccess Access, + MethodKind Kind, MethodOptions Options, TypeIndex Type, + int32_t VTableSlotOffset); + void writeMethod(const MethodInfo& Method); +}; + +} +} + +#endif Index: include/llvm/CodeView/TypeIndex.h =================================================================== --- /dev/null +++ include/llvm/CodeView/TypeIndex.h @@ -0,0 +1,189 @@ +#ifndef LLVM_CODEVIEW_TYPEINDEX_H +#define LLVM_CODEVIEW_TYPEINDEX_H + +#include +#include + +namespace llvm { +namespace codeview { + +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 + + 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 + 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 + + Complex32 = 0x0050, // 32 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 +}; + +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 +}; + +class TypeIndex +{ +public: + static const uint32_t FirstNonSimpleIndex = 0x1000; + static const uint32_t SimpleKindMask = 0x000000ff; + static const uint32_t SimpleModeMask = 0x00000700; + +public: + TypeIndex() : + Index(0) + { + } + explicit TypeIndex(uint32_t Index) : + Index(Index) + { + } + explicit TypeIndex(SimpleTypeKind Kind) : + Index(static_cast(Kind)) + { + } + TypeIndex(SimpleTypeKind Kind, SimpleTypeMode Mode) : + Index(static_cast(Kind) | static_cast(Mode)) + { + } + + uint32_t getIndex() const { return Index; } + bool isSimple() const { return Index < FirstNonSimpleIndex; } + + SimpleTypeKind getSimpleKind() const { + assert(isSimple()); + return static_cast(Index & SimpleKindMask); + } + + SimpleTypeMode getSimpleMode() const { + assert(isSimple()); + return static_cast(Index & SimpleModeMask); + } + + 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 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); } + +private: + uint32_t Index; +}; + +inline bool operator==(const TypeIndex& A, const TypeIndex& B) +{ + return A.getIndex() == B.getIndex(); +} + +inline bool operator!=(const TypeIndex& A, const TypeIndex& B) +{ + return A.getIndex() != B.getIndex(); +} + +inline bool operator<(const TypeIndex& A, const TypeIndex& B) +{ + return A.getIndex() < B.getIndex(); +} + +inline bool operator<=(const TypeIndex& A, const TypeIndex& B) +{ + return A.getIndex() <= B.getIndex(); +} + +inline bool operator>(const TypeIndex& A, const TypeIndex& B) +{ + return A.getIndex() > B.getIndex(); +} + +inline bool operator>=(const TypeIndex& A, const TypeIndex& B) +{ + return A.getIndex() >= B.getIndex(); +} + +} +} + +#endif Index: include/llvm/CodeView/TypeRecord.h =================================================================== --- /dev/null +++ include/llvm/CodeView/TypeRecord.h @@ -0,0 +1,327 @@ +#ifndef LLVM_CODEVIEW_TYPERECORD_H +#define LLVM_CODEVIEW_TYPERECORD_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/CodeView/CodeView.h" +#include "llvm/CodeView/TypeIndex.h" +#include + +namespace llvm { +namespace codeview { + +class TypeRecord +{ +protected: + explicit TypeRecord(TypeRecordKind Kind) : + Kind(Kind) + { + } + +public: + TypeRecordKind getKind() const { return Kind; } + +private: + TypeRecordKind Kind; +}; + +class ModifierRecord : public TypeRecord +{ +public: + ModifierRecord(TypeIndex ModifiedType, ModifierOptions Options) : + TypeRecord(TypeRecordKind::Modifier), + ModifiedType(ModifiedType), + Options(Options) + { + } + + TypeIndex getModifiedType() const { return ModifiedType; } + ModifierOptions getOptions() const { return Options; } + +private: + TypeIndex ModifiedType; + ModifierOptions Options; +}; + +class ProcedureRecord : public TypeRecord +{ +public: + ProcedureRecord(TypeIndex ReturnType, CallingConvention CallConv, + FunctionOptions Options, uint16_t ParameterCount, + TypeIndex ArgumentList) : + TypeRecord(TypeRecordKind::Procedure), + ReturnType(ReturnType), + CallConv(CallConv), + Options(Options), + ParameterCount(ParameterCount), + ArgumentList(ArgumentList) + { + } + + TypeIndex getReturnType() const { return ReturnType; } + CallingConvention getCallConv() const { return CallConv; } + FunctionOptions getOptions() const { return Options; } + uint16_t getParameterCount() const { return ParameterCount; } + TypeIndex getArgumentList() const { return ArgumentList; } + +private: + TypeIndex ReturnType; + CallingConvention CallConv; + FunctionOptions Options; + uint16_t ParameterCount; + TypeIndex ArgumentList; +}; + +class MemberFunctionRecord : public TypeRecord +{ +public: + MemberFunctionRecord(TypeIndex ReturnType, TypeIndex ClassType, + TypeIndex ThisType, CallingConvention CallConv, FunctionOptions Options, + uint16_t ParameterCount, TypeIndex ArgumentList, + int32_t ThisPointerAdjustment) : + TypeRecord(TypeRecordKind::MemberFunction), + ReturnType(ReturnType), + ClassType(ClassType), + ThisType(ThisType), + CallConv(CallConv), + Options(Options), + ParameterCount(ParameterCount), + ArgumentList(ArgumentList), + ThisPointerAdjustment(ThisPointerAdjustment) + { + } + + TypeIndex getReturnType() const { return ReturnType; } + TypeIndex getClassType() const { return ClassType; } + TypeIndex getThisType() const { return ThisType; } + CallingConvention getCallConv() const { return CallConv; } + FunctionOptions getOptions() const { return Options; } + uint16_t getParameterCount() const { return ParameterCount; } + TypeIndex getArgumentList() const { return ArgumentList; } + int32_t getThisPointerAdjustment() const { return ThisPointerAdjustment; } + +private: + TypeIndex ReturnType; + TypeIndex ClassType; + TypeIndex ThisType; + CallingConvention CallConv; + FunctionOptions Options; + uint16_t ParameterCount; + TypeIndex ArgumentList; + int32_t ThisPointerAdjustment; +}; + +class ArgumentListRecord : public TypeRecord +{ +public: + explicit ArgumentListRecord(llvm::ArrayRef ArgumentTypes) : + TypeRecord(TypeRecordKind::ArgumentList), + ArgumentTypes(ArgumentTypes) + { + } + + llvm::ArrayRef getArgumentTypes() const { return ArgumentTypes; } + +private: + llvm::ArrayRef ArgumentTypes; +}; + +class PointerRecordBase : public TypeRecord +{ +public: + PointerRecordBase(TypeIndex ReferentType, PointerKind Kind, + PointerMode Mode, PointerOptions Options, uint8_t Size) : + TypeRecord(TypeRecordKind::Pointer), + ReferentType(ReferentType), + PtrKind(Kind), + Mode(Mode), + Options(Options), + Size(Size) + { + } + + TypeIndex getReferentType() const { return ReferentType; } + PointerKind getPointerKind() const { return PtrKind; } + PointerMode getMode() const { return Mode; } + PointerOptions getOptions() const { return Options; } + uint8_t getSize() const { return Size; } + +private: + TypeIndex ReferentType; + PointerKind PtrKind; + PointerMode Mode; + PointerOptions Options; + uint8_t Size; +}; + +class PointerRecord : public PointerRecordBase +{ +public: + PointerRecord(TypeIndex ReferentType, PointerKind Kind, + PointerMode Mode, PointerOptions Options, uint8_t Size) : + PointerRecordBase(ReferentType, Kind, Mode, Options, Size) + { + } +}; + +class PointerToMemberRecord : public PointerRecordBase +{ +public: + PointerToMemberRecord(TypeIndex ReferentType, PointerKind Kind, + PointerMode Mode, PointerOptions Options, uint8_t Size, + TypeIndex ContainingType, PointerToMemberRepresentation Representation) : + PointerRecordBase(ReferentType, Kind, Mode, Options, Size), + ContainingType(ContainingType), + Representation(Representation) + { + } + + TypeIndex getContainingType() const { return ContainingType; } + PointerToMemberRepresentation getRepresentation() const { return Representation; } + +private: + TypeIndex ContainingType; + PointerToMemberRepresentation Representation; +}; + +class ArrayRecord : public TypeRecord +{ +public: + ArrayRecord(TypeIndex ElementType, TypeIndex IndexType, + uint64_t Size, llvm::StringRef Name) : + TypeRecord(TypeRecordKind::Array), + ElementType(ElementType), + IndexType(IndexType), + Size(Size), + Name(Name) + { + } + + TypeIndex getElementType() const { return ElementType; } + TypeIndex getIndexType() const { return IndexType; } + uint64_t getSize() const { return Size; } + llvm::StringRef getName() const { return Name; } + +private: + TypeIndex ElementType; + TypeIndex IndexType; + uint64_t Size; + llvm::StringRef Name; +}; + +class TagRecord : public TypeRecord +{ +protected: + TagRecord(TypeRecordKind Kind, uint16_t MemberCount, ClassOptions Options, + TypeIndex FieldList, StringRef Name, StringRef UniqueName) : + TypeRecord(Kind), + MemberCount(MemberCount), + Options(Options), + FieldList(FieldList), + Name(Name), + UniqueName(UniqueName) + { + } + +public: + uint16_t getMemberCount() const { return MemberCount; } + ClassOptions getOptions() const { return Options; } + TypeIndex getFieldList() const { return FieldList; } + StringRef getName() const { return Name; } + StringRef getUniqueName() const { return UniqueName; } + +private: + uint16_t MemberCount; + ClassOptions Options; + TypeIndex FieldList; + StringRef Name; + StringRef UniqueName; +}; + +class AggregateRecord : public TagRecord +{ +public: + AggregateRecord(TypeRecordKind Kind, uint16_t MemberCount, + ClassOptions Options, HfaKind Hfa, WindowsRTClassKind WinRTKind, + TypeIndex FieldList, TypeIndex DerivationList, TypeIndex VTableShape, + uint64_t Size, StringRef Name, StringRef UniqueName) : + TagRecord(Kind, MemberCount, Options, FieldList, Name, UniqueName), + Hfa(Hfa), + WinRTKind(WinRTKind), + DerivationList(DerivationList), + VTableShape(VTableShape), + Size(Size) + { + } + + HfaKind getHfa() const { return Hfa; } + WindowsRTClassKind getWinRTKind() const { return WinRTKind; } + TypeIndex getDerivationList() const { return DerivationList; } + TypeIndex getVTableShape() const { return VTableShape; } + uint64_t getSize() const { return Size; } + +private: + HfaKind Hfa; + WindowsRTClassKind WinRTKind; + TypeIndex DerivationList; + TypeIndex VTableShape; + uint64_t Size; +}; + +class EnumRecord : public TagRecord +{ +public: + EnumRecord(uint16_t MemberCount, ClassOptions Options, + TypeIndex FieldList, StringRef Name, StringRef UniqueName, + TypeIndex UnderlyingType) : + TagRecord(TypeRecordKind::Enum, MemberCount, Options, FieldList, Name, UniqueName), + UnderlyingType(UnderlyingType) + { + } + + TypeIndex getUnderlyingType() const { return UnderlyingType; } + +private: + TypeIndex UnderlyingType; +}; + +class BitFieldRecord : TypeRecord +{ +public: + BitFieldRecord(TypeIndex Type, uint8_t BitSize, uint8_t BitOffset) : + TypeRecord(TypeRecordKind::BitField), + Type(Type), + BitOffset(BitOffset), + BitSize(BitSize) + { + } + + TypeIndex getType() const { return Type; } + uint8_t getBitOffset() const { return BitOffset; } + uint8_t getBitSize() const { return BitSize; } + +private: + TypeIndex Type; + uint8_t BitSize; + uint8_t BitOffset; +}; + +class VirtualTableShapeRecord : TypeRecord +{ +public: + explicit VirtualTableShapeRecord(ArrayRef Slots) : + TypeRecord(TypeRecordKind::VirtualTableShape), + Slots(Slots) + { + } + + ArrayRef getSlots() const { return Slots; } + +private: + ArrayRef Slots; +}; + +} +} + +#endif Index: include/llvm/CodeView/TypeRecordBuilder.h =================================================================== --- /dev/null +++ include/llvm/CodeView/TypeRecordBuilder.h @@ -0,0 +1,50 @@ +#ifndef LLVM_CODEVIEW_TYPERECORDBUILDER_H +#define LLVM_CODEVIEW_TYPERECORDBUILDER_H + +#include "llvm/CodeView/TypeIndex.h" +#include "llvm/CodeView/CodeView.h" +#include +#include + +namespace llvm { +namespace codeview { + +class TypeRecordBuilder +{ +private: + TypeRecordBuilder(const TypeRecordBuilder&) = delete; + TypeRecordBuilder& operator=(const TypeRecordBuilder&) = delete; + +public: + explicit TypeRecordBuilder(TypeRecordKind Kind); + + void writeUInt8(uint8_t Value); + void writeInt16(int16_t Value); + void writeUInt16(uint16_t Value); + void writeInt32(int32_t Value); + void writeUInt32(uint32_t Value); + void writeInt64(int64_t Value); + void writeUInt64(uint64_t Value); + void writeTypeIndex(TypeIndex TypeInd); + void writeTypeRecordKind(TypeRecordKind Kind); + void writeEncodedInteger(int64_t Value); + void writeEncodedSignedInteger(int64_t Value); + void writeEncodedUnsignedInteger(uint64_t Value); + void writeNullTerminatedString(const char* Value); + void writeNullTerminatedString(StringRef Value); + + llvm::StringRef str(); + + uint64_t size() const { + return Stream.tell(); + } + +private: + llvm::SmallVector Buffer; + llvm::raw_svector_ostream Stream; +}; + +} +} + +#endif Index: include/llvm/CodeView/TypeSymbolEmitter.h =================================================================== --- /dev/null +++ include/llvm/CodeView/TypeSymbolEmitter.h @@ -0,0 +1,34 @@ +#ifndef LLVM_CODEVIEW_TYPESYMBOLEMITTER_H +#define LLVM_CODEVIEW_TYPESYMBOLEMITTER_H + +#include "llvm/CodeView/CodeView.h" +#include "llvm/CodeView/TypeIndex.h" +#include "llvm/ADT/StringRef.h" + +namespace llvm { +namespace codeview { + +class TypeSymbolEmitter +{ +private: + TypeSymbolEmitter(const TypeSymbolEmitter&) = delete; + TypeSymbolEmitter& operator=(const TypeSymbolEmitter&) = delete; + +protected: + TypeSymbolEmitter() + { + } + +public: + virtual ~TypeSymbolEmitter() + { + } + +public: + virtual void writeUserDefinedType(TypeIndex TI, StringRef Name) = 0; +}; + +} +} + +#endif Index: include/llvm/CodeView/TypeTableBuilder.h =================================================================== --- /dev/null +++ include/llvm/CodeView/TypeTableBuilder.h @@ -0,0 +1,53 @@ +#ifndef LLVM_CODEVIEW_TYPETABLEBUILDER_H +#define LLVM_CODEVIEW_TYPETABLEBUILDER_H + +#include "llvm/CodeView/CodeView.h" +#include "llvm/CodeView/TypeIndex.h" +#include "llvm/CodeView/TypeRecord.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { +namespace codeview { + +class FieldListRecordBuilder; +class MethodListRecordBuilder; +class TypeRecordBuilder; + +class TypeTableBuilder +{ +private: + TypeTableBuilder(const TypeTableBuilder&) = delete; + TypeTableBuilder& operator=(const TypeTableBuilder&) = delete; + +protected: + TypeTableBuilder(); + +public: + virtual ~TypeTableBuilder(); + +public: + TypeIndex writeModifier(const ModifierRecord& Record); + TypeIndex writeProcedure(const ProcedureRecord& Record); + TypeIndex writeMemberFunction(const MemberFunctionRecord& Record); + TypeIndex writeArgumentList(const ArgumentListRecord& Record); + TypeIndex writeRecord(TypeRecordBuilder& builder); + TypeIndex writePointer(const PointerRecord& Record); + TypeIndex writePointerToMember(const PointerToMemberRecord& Record); + TypeIndex writeArray(const ArrayRecord& Record); + TypeIndex writeAggregate(const AggregateRecord& Record); + TypeIndex writeEnum(const EnumRecord& Record); + TypeIndex writeBitField(const BitFieldRecord& Record); + TypeIndex writeVirtualTableShape(const VirtualTableShapeRecord& Record); + + TypeIndex writeFieldList(FieldListRecordBuilder& FieldList); + TypeIndex writeMethodList(MethodListRecordBuilder& MethodList); + +private: + virtual TypeIndex writeRecord(llvm::StringRef record) = 0; +}; + +} +} + +#endif Index: include/llvm/IR/DIBuilder.h =================================================================== --- include/llvm/IR/DIBuilder.h +++ include/llvm/IR/DIBuilder.h @@ -17,7 +17,11 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "llvm/CodeView/TypeIndex.h" +#include "llvm/CodeView/TypeSymbolEmitter.h" +#include "llvm/CodeView/TypeTableBuilder.h" #include "llvm/IR/DebugInfo.h" +#include "llvm/IR/MDTypeTableBuilder.h" #include "llvm/IR/TrackingMDRef.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/DataTypes.h" @@ -33,6 +37,23 @@ class StringRef; class DIBuilder { + class MDTypeSymbolEmitter : public codeview::TypeSymbolEmitter { + public: + explicit MDTypeSymbolEmitter(LLVMContext &Context) : + Context(Context) { + } + + ArrayRef getUDTRecords() const { + return UDTRecords; + } + + void writeUserDefinedType(codeview::TypeIndex TI, StringRef Name) override; + + private: + LLVMContext &Context; + SmallVector UDTRecords; + }; + Module &M; LLVMContext &VMContext; @@ -46,6 +67,7 @@ SmallVector AllSubprograms; SmallVector AllGVs; SmallVector AllImportedModules; + SmallVector AllCodeViewTypes; /// Track nodes that may be unresolved. SmallVector UnresolvedNodes; @@ -54,6 +76,9 @@ /// Each subprogram's preserved local variables. DenseMap> PreservedVariables; + MDTypeTableBuilder CodeViewTypesBuilder; + MDTypeSymbolEmitter CodeViewTypeSymbolEmitter; + DIBuilder(const DIBuilder &) = delete; void operator=(const DIBuilder &) = delete; @@ -62,6 +87,8 @@ /// Create an \a temporary node and track it in \a UnresolvedNodes. void trackIfUnresolved(MDNode *N); + DICodeViewTypes *createCodeViewTypes(); + public: /// Construct a builder for a module. /// @@ -73,6 +100,14 @@ /// Construct any deferred debug info descriptors. void finalize(); + codeview::TypeTableBuilder &getCodeViewTypesBuilder() { + return CodeViewTypesBuilder; + } + + codeview::TypeSymbolEmitter &getCodeViewTypeSymbolEmitter() { + return CodeViewTypeSymbolEmitter; + } + /// A CompileUnit provides an anchor for all debugging /// information generated during this instance of compilation. /// \param Lang Source programming language, eg. dwarf::DW_LANG_C99 @@ -432,13 +467,15 @@ /// \param File File where this variable is defined. /// \param LineNo Line number. /// \param Ty Variable Type. + /// \param TI CodeView type index. /// \param isLocalToUnit Boolean flag indicate whether this variable is /// externally visible or not. /// \param Val llvm::Value of the variable. /// \param Decl Reference to the corresponding declaration. DIGlobalVariable *createGlobalVariable(DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, - unsigned LineNo, DIType *Ty, + unsigned LineNo, + DIType *Ty, codeview::TypeIndex TI, bool isLocalToUnit, llvm::Constant *Val, MDNode *Decl = nullptr); @@ -447,8 +484,8 @@ /// except that the resulting DbgNode is temporary and meant to be RAUWed. DIGlobalVariable *createTempGlobalVariableFwdDecl( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, - unsigned LineNo, DIType *Ty, bool isLocalToUnit, llvm::Constant *Val, - MDNode *Decl = nullptr); + unsigned LineNo, DIType *Ty, codeview::TypeIndex TI, bool isLocalToUnit, + llvm::Constant *Val, MDNode *Decl = nullptr); /// Create a new descriptor for the specified /// local variable. @@ -459,6 +496,7 @@ /// \param File File where this variable is defined. /// \param LineNo Line number. /// \param Ty Variable Type + /// \param TI CodeView type index. /// \param AlwaysPreserve Boolean. Set to true if debug info for this /// variable should be preserved in optimized build. /// \param Flags Flags, e.g. artificial variable. @@ -466,7 +504,8 @@ /// number. 1 indicates 1st argument. DILocalVariable *createLocalVariable(unsigned Tag, DIScope *Scope, StringRef Name, DIFile *File, - unsigned LineNo, DIType *Ty, + unsigned LineNo, + DIType *Ty, codeview::TypeIndex TI, bool AlwaysPreserve = false, unsigned Flags = 0, unsigned ArgNo = 0); @@ -493,6 +532,7 @@ /// \param File File where this variable is defined. /// \param LineNo Line number. /// \param Ty Function type. + /// \param TI CodeView type index. /// \param isLocalToUnit True if this function is not externally visible. /// \param isDefinition True if this is a function definition. /// \param ScopeLine Set to the beginning of the scope this starts @@ -504,6 +544,7 @@ DISubprogram * createFunction(DIScope *Scope, StringRef Name, StringRef LinkageName, DIFile *File, unsigned LineNo, DISubroutineType *Ty, + codeview::TypeIndex TI, bool isLocalToUnit, bool isDefinition, unsigned ScopeLine, unsigned Flags = 0, bool isOptimized = false, Function *Fn = nullptr, MDNode *TParam = nullptr, @@ -513,7 +554,8 @@ /// except that the resulting DbgNode is meant to be RAUWed. DISubprogram *createTempFunctionFwdDecl( DIScope *Scope, StringRef Name, StringRef LinkageName, DIFile *File, - unsigned LineNo, DISubroutineType *Ty, bool isLocalToUnit, + unsigned LineNo, DISubroutineType *Ty, codeview::TypeIndex TI, + bool isLocalToUnit, bool isDefinition, unsigned ScopeLine, unsigned Flags = 0, bool isOptimized = false, Function *Fn = nullptr, MDNode *TParam = nullptr, MDNode *Decl = nullptr); @@ -523,6 +565,7 @@ DISubprogram * createFunction(DIScopeRef Scope, StringRef Name, StringRef LinkageName, DIFile *File, unsigned LineNo, DISubroutineType *Ty, + codeview::TypeIndex TI, bool isLocalToUnit, bool isDefinition, unsigned ScopeLine, unsigned Flags = 0, bool isOptimized = false, Function *Fn = nullptr, MDNode *TParam = nullptr, @@ -536,6 +579,7 @@ /// \param File File where this variable is defined. /// \param LineNo Line number. /// \param Ty Function type. + /// \param TI CodeView type index. /// \param isLocalToUnit True if this function is not externally visible.. /// \param isDefinition True if this is a function definition. /// \param Virtuality Attributes describing virtualness. e.g. pure @@ -550,6 +594,7 @@ DISubprogram * createMethod(DIScope *Scope, StringRef Name, StringRef LinkageName, DIFile *File, unsigned LineNo, DISubroutineType *Ty, + codeview::TypeIndex TI, bool isLocalToUnit, bool isDefinition, unsigned Virtuality = 0, unsigned VTableIndex = 0, DIType *VTableHolder = nullptr, unsigned Flags = 0, bool isOptimized = false, Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -16,6 +16,7 @@ #include "llvm/IR/Metadata.h" #include "llvm/Support/Dwarf.h" +#include "llvm/CodeView/TypeIndex.h" // Helper macros for defining get() overrides. #define DEFINE_MDNODE_GET_UNPACK_IMPL(...) __VA_ARGS__ @@ -964,6 +965,77 @@ } }; +/// \brief CodeView type information for compile unit. +class DICodeViewTypes : public DINode { + friend class LLVMContextImpl; + friend class MDNode; + + unsigned Signature; + + DICodeViewTypes(LLVMContext &C, StorageType Storage, unsigned Signature, + ArrayRef Ops) + : DINode(C, DICodeViewTypesKind, Storage, dwarf::DW_TAG_hi_user, Ops), + Signature(Signature) { + } + ~DICodeViewTypes() = default; + + static DICodeViewTypes * + getImpl(LLVMContext &Context, unsigned Signature, Metadata *TypeRecords, + DICodeViewUDTArray UDTSymbols, StorageType Storage, + bool ShouldCreate = true) { + return getImpl(Context, Signature, TypeRecords, UDTSymbols.get(), + Storage, ShouldCreate); + } + static DICodeViewTypes * + getImpl(LLVMContext &Context, unsigned Signature, Metadata *TypeRecords, + Metadata *UDTSymbols, StorageType Storage, bool ShouldCreate = true); + + TempDICodeViewTypes cloneImpl() const { + return getTemporary( + getContext(), getSignature(), getTypeRecords(), getUDTSymbols()); + } + +public: + DEFINE_MDNODE_GET(DICodeViewTypes, + (unsigned Signature, Metadata *TypeRecords, + DICodeViewUDTArray UDTSymbols), + (Signature, TypeRecords, UDTSymbols)) + DEFINE_MDNODE_GET( + DICodeViewTypes, + (unsigned Signature, Metadata *TypeRecords, Metadata *UDTSymbols), + (Signature, TypeRecords, UDTSymbols)) + + TempDICodeViewTypes clone() const { return cloneImpl(); } + + unsigned getSignature() const { return Signature; } + MDTuple *getTypeRecords() const { + return cast_or_null(getRawTypeRecords()); + } + DICodeViewUDTArray getUDTSymbols() const { + return cast_or_null(getRawUDTSymbols()); + } + + Metadata *getRawTypeRecords() const { return getOperand(0); } + Metadata *getRawUDTSymbols() const { return getOperand(1); } + + /// \brief Replace arrays. + /// + /// If this \a isUniqued() and not \a isResolved(), it will be RAUW'ed and + /// deleted on a uniquing collision. In practice, uniquing collisions on \a + /// DICodeViewTypes should be fairly rare. + /// @{ + void replaceTypeRecords(MDNodeArray N) { + replaceOperandWith(1, N.get()); + } + void replaceUDTSymbols(DICodeViewUDTArray N) { + replaceOperandWith(2, N.get()); + } + + static bool classof(const Metadata *MD) { + return MD->getMetadataID() == DICodeViewTypesKind; + } +}; + /// \brief Compile unit. class DICompileUnit : public DIScope { friend class LLVMContextImpl; @@ -991,15 +1063,17 @@ unsigned EmissionKind, DICompositeTypeArray EnumTypes, DITypeArray RetainedTypes, DISubprogramArray Subprograms, DIGlobalVariableArray GlobalVariables, - DIImportedEntityArray ImportedEntities, uint64_t DWOId, - StorageType Storage, bool ShouldCreate = true) { + DIImportedEntityArray ImportedEntities, + DICodeViewTypes *CodeViewTypes, + uint64_t DWOId, StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, SourceLanguage, File, getCanonicalMDString(Context, Producer), IsOptimized, getCanonicalMDString(Context, Flags), RuntimeVersion, getCanonicalMDString(Context, SplitDebugFilename), EmissionKind, EnumTypes.get(), RetainedTypes.get(), Subprograms.get(), GlobalVariables.get(), - ImportedEntities.get(), DWOId, Storage, ShouldCreate); + ImportedEntities.get(), CodeViewTypes, DWOId, Storage, + ShouldCreate); } static DICompileUnit * getImpl(LLVMContext &Context, unsigned SourceLanguage, Metadata *File, @@ -1007,15 +1081,15 @@ unsigned RuntimeVersion, MDString *SplitDebugFilename, unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, Metadata *Subprograms, Metadata *GlobalVariables, - Metadata *ImportedEntities, uint64_t DWOId, StorageType Storage, - bool ShouldCreate = true); + Metadata *ImportedEntities, Metadata *CodeViewTypes, uint64_t DWOId, + StorageType Storage, bool ShouldCreate = true); TempDICompileUnit cloneImpl() const { return getTemporary( getContext(), getSourceLanguage(), getFile(), getProducer(), isOptimized(), getFlags(), getRuntimeVersion(), getSplitDebugFilename(), getEmissionKind(), getEnumTypes(), getRetainedTypes(), getSubprograms(), - getGlobalVariables(), getImportedEntities(), DWOId); + getGlobalVariables(), getImportedEntities(), getCodeViewTypes(), DWOId); } public: @@ -1026,21 +1100,23 @@ DICompositeTypeArray EnumTypes, DITypeArray RetainedTypes, DISubprogramArray Subprograms, DIGlobalVariableArray GlobalVariables, - DIImportedEntityArray ImportedEntities, uint64_t DWOId), + DIImportedEntityArray ImportedEntities, + DICodeViewTypes *CodeViewTypes, uint64_t DWOId), (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, GlobalVariables, - ImportedEntities, DWOId)) + ImportedEntities, CodeViewTypes, DWOId)) DEFINE_MDNODE_GET( DICompileUnit, (unsigned SourceLanguage, Metadata *File, MDString *Producer, bool IsOptimized, MDString *Flags, unsigned RuntimeVersion, MDString *SplitDebugFilename, unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, Metadata *Subprograms, - Metadata *GlobalVariables, Metadata *ImportedEntities, uint64_t DWOId), + Metadata *GlobalVariables, Metadata *ImportedEntities, + Metadata *CodeViewTypes, uint64_t DWOId), (SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, - GlobalVariables, ImportedEntities, DWOId)) + GlobalVariables, ImportedEntities, CodeViewTypes, DWOId)) TempDICompileUnit clone() const { return cloneImpl(); } @@ -1066,6 +1142,9 @@ DIImportedEntityArray getImportedEntities() const { return cast_or_null(getRawImportedEntities()); } + DICodeViewTypes *getCodeViewTypes() const { + return cast_or_null(getRawCodeViewTypes()); + } unsigned getDWOId() const { return DWOId; } MDString *getRawProducer() const { return getOperandAs(1); } @@ -1078,6 +1157,7 @@ Metadata *getRawSubprograms() const { return getOperand(6); } Metadata *getRawGlobalVariables() const { return getOperand(7); } Metadata *getRawImportedEntities() const { return getOperand(8); } + Metadata *getRawCodeViewTypes() const { return getOperand(9); } /// \brief Replace arrays. /// @@ -1100,6 +1180,9 @@ void replaceImportedEntities(DIImportedEntityArray N) { replaceOperandWith(8, N.get()); } + void replaceCodeViewTypes(DICodeViewTypes *N) { + replaceOperandWith(9, N); + } /// @} static bool classof(const Metadata *MD) { @@ -1258,30 +1341,33 @@ bool IsLocalToUnit; bool IsDefinition; bool IsOptimized; + codeview::TypeIndex TI; DISubprogram(LLVMContext &C, StorageType Storage, unsigned Line, unsigned ScopeLine, unsigned Virtuality, unsigned VirtualIndex, unsigned Flags, bool IsLocalToUnit, bool IsDefinition, - bool IsOptimized, ArrayRef Ops) + bool IsOptimized, codeview::TypeIndex TI, + ArrayRef Ops) : DILocalScope(C, DISubprogramKind, Storage, dwarf::DW_TAG_subprogram, Ops), Line(Line), ScopeLine(ScopeLine), Virtuality(Virtuality), VirtualIndex(VirtualIndex), Flags(Flags), IsLocalToUnit(IsLocalToUnit), - IsDefinition(IsDefinition), IsOptimized(IsOptimized) {} + IsDefinition(IsDefinition), IsOptimized(IsOptimized), TI(TI) {} ~DISubprogram() = default; static DISubprogram * getImpl(LLVMContext &Context, DIScopeRef Scope, StringRef Name, StringRef LinkageName, DIFile *File, unsigned Line, - DISubroutineType *Type, bool IsLocalToUnit, bool IsDefinition, - unsigned ScopeLine, DITypeRef ContainingType, unsigned Virtuality, - unsigned VirtualIndex, unsigned Flags, bool IsOptimized, - Constant *Function, DITemplateParameterArray TemplateParams, + DISubroutineType *Type, codeview::TypeIndex TI, bool IsLocalToUnit, + bool IsDefinition, unsigned ScopeLine, DITypeRef ContainingType, + unsigned Virtuality, unsigned VirtualIndex, unsigned Flags, + bool IsOptimized, Constant *Function, + DITemplateParameterArray TemplateParams, DISubprogram *Declaration, DILocalVariableArray Variables, StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Scope, getCanonicalMDString(Context, Name), getCanonicalMDString(Context, LinkageName), File, Line, Type, - IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, + TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function ? ConstantAsMetadata::get(Function) : nullptr, TemplateParams.get(), Declaration, Variables.get(), Storage, @@ -1290,15 +1376,17 @@ static DISubprogram * getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, + codeview::TypeIndex TI, bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine, Metadata *ContainingType, unsigned Virtuality, unsigned VirtualIndex, - unsigned Flags, bool IsOptimized, Metadata *Function, - Metadata *TemplateParams, Metadata *Declaration, Metadata *Variables, - StorageType Storage, bool ShouldCreate = true); + unsigned Flags, bool IsOptimized, + Metadata *Function, Metadata *TemplateParams, Metadata *Declaration, + Metadata *Variables, StorageType Storage, bool ShouldCreate = true); TempDISubprogram cloneImpl() const { return getTemporary(getContext(), getScope(), getName(), getLinkageName(), - getFile(), getLine(), getType(), isLocalToUnit(), + getFile(), getLine(), getType(), getTypeIndex(), + isLocalToUnit(), isDefinition(), getScopeLine(), getContainingType(), getVirtuality(), getVirtualIndex(), getFlags(), isOptimized(), getFunctionConstant(), @@ -1309,6 +1397,7 @@ DEFINE_MDNODE_GET(DISubprogram, (DIScopeRef Scope, StringRef Name, StringRef LinkageName, DIFile *File, unsigned Line, DISubroutineType *Type, + codeview::TypeIndex TI, bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine, DITypeRef ContainingType, unsigned Virtuality, unsigned VirtualIndex, unsigned Flags, bool IsOptimized, @@ -1316,21 +1405,24 @@ DITemplateParameterArray TemplateParams = nullptr, DISubprogram *Declaration = nullptr, DILocalVariableArray Variables = nullptr), - (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, + (Scope, Name, LinkageName, File, Line, Type, TI, + IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, - VirtualIndex, Flags, IsOptimized, Function, TemplateParams, - Declaration, Variables)) + VirtualIndex, Flags, IsOptimized, Function, + TemplateParams, Declaration, Variables)) DEFINE_MDNODE_GET( DISubprogram, (Metadata * Scope, MDString *Name, MDString *LinkageName, Metadata *File, - unsigned Line, Metadata *Type, bool IsLocalToUnit, bool IsDefinition, - unsigned ScopeLine, Metadata *ContainingType, unsigned Virtuality, - unsigned VirtualIndex, unsigned Flags, bool IsOptimized, - Metadata *Function = nullptr, Metadata *TemplateParams = nullptr, - Metadata *Declaration = nullptr, Metadata *Variables = nullptr), - (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, IsDefinition, - ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, - Function, TemplateParams, Declaration, Variables)) + unsigned Line, Metadata *Type, codeview::TypeIndex TI, + bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine, + Metadata *ContainingType, unsigned Virtuality, + unsigned VirtualIndex, unsigned Flags, bool IsOptimized, + Metadata *Function = nullptr, + Metadata *TemplateParams = nullptr, Metadata *Declaration = nullptr, + Metadata *Variables = nullptr), + (Scope, Name, LinkageName, File, Line, Type, TI, IsLocalToUnit, + IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, + IsOptimized, Function, TemplateParams, Declaration, Variables)) TempDISubprogram clone() const { return cloneImpl(); } @@ -1343,6 +1435,7 @@ bool isLocalToUnit() const { return IsLocalToUnit; } bool isDefinition() const { return IsDefinition; } bool isOptimized() const { return IsOptimized; } + codeview::TypeIndex getTypeIndex() const { return TI; } unsigned isArtificial() const { return getFlags() & FlagArtificial; } bool isPrivate() const { @@ -1801,15 +1894,17 @@ /// TODO: Hardcode to DW_TAG_variable. class DIVariable : public DINode { unsigned Line; + codeview::TypeIndex TI; protected: DIVariable(LLVMContext &C, unsigned ID, StorageType Storage, unsigned Tag, - unsigned Line, ArrayRef Ops) - : DINode(C, ID, Storage, Tag, Ops), Line(Line) {} + unsigned Line, codeview::TypeIndex TI, ArrayRef Ops) + : DINode(C, ID, Storage, Tag, Ops), Line(Line), TI(TI) {} ~DIVariable() = default; public: unsigned getLine() const { return Line; } + codeview::TypeIndex getTypeIndex() const { return TI; } DIScope *getScope() const { return cast_or_null(getRawScope()); } StringRef getName() const { return getStringOperand(1); } DIFile *getFile() const { return cast_or_null(getRawFile()); } @@ -1848,36 +1943,38 @@ bool IsDefinition; DIGlobalVariable(LLVMContext &C, StorageType Storage, unsigned Line, - bool IsLocalToUnit, bool IsDefinition, - ArrayRef Ops) + codeview::TypeIndex TI, bool IsLocalToUnit, + bool IsDefinition, ArrayRef Ops) : DIVariable(C, DIGlobalVariableKind, Storage, dwarf::DW_TAG_variable, - Line, Ops), + Line, TI, Ops), IsLocalToUnit(IsLocalToUnit), IsDefinition(IsDefinition) {} ~DIGlobalVariable() = default; static DIGlobalVariable * getImpl(LLVMContext &Context, DIScope *Scope, StringRef Name, - StringRef LinkageName, DIFile *File, unsigned Line, DITypeRef Type, + StringRef LinkageName, DIFile *File, unsigned Line, + DITypeRef Type, codeview::TypeIndex TI, bool IsLocalToUnit, bool IsDefinition, Constant *Variable, DIDerivedType *StaticDataMemberDeclaration, StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Scope, getCanonicalMDString(Context, Name), - getCanonicalMDString(Context, LinkageName), File, Line, Type, - IsLocalToUnit, IsDefinition, + getCanonicalMDString(Context, LinkageName), File, Line, + Type, TI, IsLocalToUnit, IsDefinition, Variable ? ConstantAsMetadata::get(Variable) : nullptr, StaticDataMemberDeclaration, Storage, ShouldCreate); } static DIGlobalVariable * getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, - MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, - bool IsLocalToUnit, bool IsDefinition, Metadata *Variable, + MDString *LinkageName, Metadata *File, unsigned Line, + Metadata *Type, codeview::TypeIndex TI, bool IsLocalToUnit, + bool IsDefinition, Metadata *Variable, Metadata *StaticDataMemberDeclaration, StorageType Storage, bool ShouldCreate = true); TempDIGlobalVariable cloneImpl() const { return getTemporary(getContext(), getScope(), getName(), getLinkageName(), - getFile(), getLine(), getType(), isLocalToUnit(), - isDefinition(), getVariable(), + getFile(), getLine(), getType(), getTypeIndex(), + isLocalToUnit(), isDefinition(), getVariable(), getStaticDataMemberDeclaration()); } @@ -1885,17 +1982,21 @@ DEFINE_MDNODE_GET(DIGlobalVariable, (DIScope * Scope, StringRef Name, StringRef LinkageName, DIFile *File, unsigned Line, DITypeRef Type, - bool IsLocalToUnit, bool IsDefinition, Constant *Variable, + codeview::TypeIndex TI, bool IsLocalToUnit, + bool IsDefinition, Constant *Variable, DIDerivedType *StaticDataMemberDeclaration), - (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, - IsDefinition, Variable, StaticDataMemberDeclaration)) + (Scope, Name, LinkageName, File, Line, Type, TI, + IsLocalToUnit, IsDefinition, Variable, + StaticDataMemberDeclaration)) DEFINE_MDNODE_GET(DIGlobalVariable, (Metadata * Scope, MDString *Name, MDString *LinkageName, - Metadata *File, unsigned Line, Metadata *Type, - bool IsLocalToUnit, bool IsDefinition, Metadata *Variable, + Metadata *File, unsigned Line, Metadata *Type, + codeview::TypeIndex TI, bool IsLocalToUnit, + bool IsDefinition, Metadata *Variable, Metadata *StaticDataMemberDeclaration), - (Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, - IsDefinition, Variable, StaticDataMemberDeclaration)) + (Scope, Name, LinkageName, File, Line, Type, TI, + IsLocalToUnit, IsDefinition, Variable, + StaticDataMemberDeclaration)) TempDIGlobalVariable clone() const { return cloneImpl(); } @@ -1934,41 +2035,44 @@ unsigned Flags; DILocalVariable(LLVMContext &C, StorageType Storage, unsigned Tag, - unsigned Line, unsigned Arg, unsigned Flags, - ArrayRef Ops) - : DIVariable(C, DILocalVariableKind, Storage, Tag, Line, Ops), Arg(Arg), - Flags(Flags) {} + unsigned Line, codeview::TypeIndex TI, unsigned Arg, + unsigned Flags, ArrayRef Ops) + : DIVariable(C, DILocalVariableKind, Storage, Tag, Line, TI, Ops), + Arg(Arg), Flags(Flags) {} ~DILocalVariable() = default; static DILocalVariable *getImpl(LLVMContext &Context, unsigned Tag, DIScope *Scope, StringRef Name, DIFile *File, - unsigned Line, DITypeRef Type, unsigned Arg, + unsigned Line, DITypeRef Type, + codeview::TypeIndex TI, unsigned Arg, unsigned Flags, StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Tag, Scope, getCanonicalMDString(Context, Name), - File, Line, Type, Arg, Flags, Storage, ShouldCreate); + File, Line, Type, TI, Arg, Flags, Storage, ShouldCreate); } static DILocalVariable * getImpl(LLVMContext &Context, unsigned Tag, Metadata *Scope, MDString *Name, - Metadata *File, unsigned Line, Metadata *Type, unsigned Arg, - unsigned Flags, StorageType Storage, bool ShouldCreate = true); + Metadata *File, unsigned Line, Metadata *Type, codeview::TypeIndex TI, + unsigned Arg, unsigned Flags, StorageType Storage, + bool ShouldCreate = true); TempDILocalVariable cloneImpl() const { return getTemporary(getContext(), getTag(), getScope(), getName(), - getFile(), getLine(), getType(), getArg(), getFlags()); + getFile(), getLine(), getType(), getTypeIndex(), + getArg(), getFlags()); } public: DEFINE_MDNODE_GET(DILocalVariable, (unsigned Tag, DILocalScope *Scope, StringRef Name, - DIFile *File, unsigned Line, DITypeRef Type, unsigned Arg, - unsigned Flags), - (Tag, Scope, Name, File, Line, Type, Arg, Flags)) + DIFile *File, unsigned Line, DITypeRef Type, + codeview::TypeIndex TI, unsigned Arg, unsigned Flags), + (Tag, Scope, Name, File, Line, Type, TI, Arg, Flags)) DEFINE_MDNODE_GET(DILocalVariable, (unsigned Tag, Metadata *Scope, MDString *Name, Metadata *File, unsigned Line, Metadata *Type, - unsigned Arg, unsigned Flags), - (Tag, Scope, Name, File, Line, Type, Arg, Flags)) + codeview::TypeIndex TI, unsigned Arg, unsigned Flags), + (Tag, Scope, Name, File, Line, Type, TI, Arg, Flags)) TempDILocalVariable clone() const { return cloneImpl(); } @@ -2284,6 +2388,53 @@ } }; +class DICodeViewUDT : public DINode { + friend class LLVMContextImpl; + friend class MDNode; + + codeview::TypeIndex TI; + + DICodeViewUDT(LLVMContext &C, StorageType Storage, codeview::TypeIndex TI, + ArrayRef Ops) + : DINode(C, DICodeViewUDTKind, Storage, dwarf::DW_TAG_hi_user, + Ops), + TI(TI) { + } + ~DICodeViewUDT() = default; + + static DICodeViewUDT * + getImpl(LLVMContext &Context, StringRef Name, codeview::TypeIndex TI, + StorageType Storage, bool ShouldCreate = true) { + return getImpl(Context, getCanonicalMDString(Context, Name), TI, Storage, + ShouldCreate); + } + static DICodeViewUDT *getImpl(LLVMContext &Context, MDString *Name, + codeview::TypeIndex TI, StorageType Storage, bool ShouldCreate = true); + + TempDICodeViewUDT cloneImpl() const { + return getTemporary(getContext(), getName(), getTypeIndex()); + } + +public: + DEFINE_MDNODE_GET(DICodeViewUDT, + (StringRef Name, codeview::TypeIndex TI), + (Name, TI)) + DEFINE_MDNODE_GET(DICodeViewUDT, + (MDString * Name, codeview::TypeIndex TI), + (Name, TI)) + + TempDICodeViewUDT clone() const { return cloneImpl(); } + + codeview::TypeIndex getTypeIndex() const { return TI; } + StringRef getName() const { return getStringOperand(0); } + + MDString *getRawName() const { return getOperandAs(0); } + + static bool classof(const Metadata *MD) { + return MD->getMetadataID() == DICodeViewUDTKind; + } +}; + } // end namespace llvm #undef DEFINE_MDNODE_GET_UNPACK_IMPL Index: include/llvm/IR/MDTypeTableBuilder.h =================================================================== --- /dev/null +++ include/llvm/IR/MDTypeTableBuilder.h @@ -0,0 +1,39 @@ +#ifndef LLVM_IR_MDTYPETABLEBUILDER_H +#define LLVM_IR_MDTYPETABLEBUILDER_H + +#include "llvm/CodeView/TypeTableBuilder.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Metadata.h" +#include +#include + +namespace llvm { + +class MDTypeTableBuilder : public codeview::TypeTableBuilder +{ +public: + explicit MDTypeTableBuilder(LLVMContext &Context) : + Context(Context) + { + } + + ArrayRef getRecords() const + { + return Records; + } + +private: + virtual codeview::TypeIndex writeRecord(StringRef record) + override; + +private: + LLVMContext &Context; + std::vector Records; + std::map TypeIndices; +}; + +} + +#endif Index: include/llvm/IR/Metadata.h =================================================================== --- include/llvm/IR/Metadata.h +++ include/llvm/IR/Metadata.h @@ -84,6 +84,8 @@ DIExpressionKind, DIObjCPropertyKind, DIImportedEntityKind, + DICodeViewTypesKind, + DICodeViewUDTKind, ConstantAsMetadataKind, LocalAsMetadataKind, MDStringKind Index: include/llvm/IR/Metadata.def =================================================================== --- include/llvm/IR/Metadata.def +++ include/llvm/IR/Metadata.def @@ -91,6 +91,8 @@ HANDLE_SPECIALIZED_MDNODE_LEAF(DILocalVariable) HANDLE_SPECIALIZED_MDNODE_LEAF(DIObjCProperty) HANDLE_SPECIALIZED_MDNODE_LEAF(DIImportedEntity) +HANDLE_SPECIALIZED_MDNODE_LEAF(DICodeViewTypes) +HANDLE_SPECIALIZED_MDNODE_LEAF(DICodeViewUDT) #undef HANDLE_METADATA #undef HANDLE_METADATA_LEAF Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -3564,12 +3564,42 @@ return false; } +/// ParseDICodeViewTypes: +/// ::= !DICodeViewTypes(signature: 4, typeRecords: !0, udtSymbols: !1) +bool LLParser::ParseDICodeViewTypes(MDNode *&Result, bool IsDistinct) { +#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ + REQUIRED(signature, MDUnsignedField, (0, UINT32_MAX)); \ + OPTIONAL(typeRecords, MDField, ); \ + OPTIONAL(udtSymbols, MDField, ); + PARSE_MD_FIELDS(); +#undef VISIT_MD_FIELDS + + Result = GET_OR_DISTINCT(DICodeViewTypes, + (Context, signature.Val, typeRecords.Val, udtSymbols.Val)); + return false; +} + +/// ParseDICodeViewUDT: +/// ::= !DICodeViewUDT(typeIndex: 0x74, name: "abc") +bool LLParser::ParseDICodeViewUDT(MDNode *&Result, bool IsDistinct) { +#define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ + REQUIRED(name, MDStringField, ); \ + REQUIRED(typeIndex, MDUnsignedField, (0, UINT32_MAX)); + PARSE_MD_FIELDS(); +#undef VISIT_MD_FIELDS + + Result = GET_OR_DISTINCT(DICodeViewUDT, + (Context, name.Val, codeview::TypeIndex(typeIndex.Val))); + return false; +} + /// ParseDICompileUnit: /// ::= !DICompileUnit(language: DW_LANG_C99, file: !0, producer: "clang", /// isOptimized: true, flags: "-O2", runtimeVersion: 1, /// splitDebugFilename: "abc.debug", emissionKind: 1, /// enums: !1, retainedTypes: !2, subprograms: !3, -/// globals: !4, imports: !5, dwoId: 0x0abcd) +/// globals: !4, imports: !5, codeViewTypes: !6, +/// dwoId: 0x0abcd) bool LLParser::ParseDICompileUnit(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ REQUIRED(language, DwarfLangField, ); \ @@ -3585,6 +3615,7 @@ OPTIONAL(subprograms, MDField, ); \ OPTIONAL(globals, MDField, ); \ OPTIONAL(imports, MDField, ); \ + OPTIONAL(codeViewTypes, MDField, ); \ OPTIONAL(dwoId, MDUnsignedField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS @@ -3594,7 +3625,7 @@ isOptimized.Val, flags.Val, runtimeVersion.Val, splitDebugFilename.Val, emissionKind.Val, enums.Val, retainedTypes.Val, subprograms.Val, globals.Val, - imports.Val, dwoId.Val)); + imports.Val, codeViewTypes.Val, dwoId.Val)); return false; } @@ -3614,6 +3645,7 @@ OPTIONAL(file, MDField, ); \ OPTIONAL(line, LineField, ); \ OPTIONAL(type, MDField, ); \ + OPTIONAL(typeIndex, MDUnsignedField, (0, UINT32_MAX)); \ OPTIONAL(isLocal, MDBoolField, ); \ OPTIONAL(isDefinition, MDBoolField, (true)); \ OPTIONAL(scopeLine, LineField, ); \ @@ -3631,7 +3663,8 @@ Result = GET_OR_DISTINCT( DISubprogram, (Context, scope.Val, name.Val, linkageName.Val, file.Val, - line.Val, type.Val, isLocal.Val, isDefinition.Val, + line.Val, type.Val, codeview::TypeIndex(typeIndex.Val), + isLocal.Val, isDefinition.Val, scopeLine.Val, containingType.Val, virtuality.Val, virtualIndex.Val, flags.Val, isOptimized.Val, function.Val, templateParams.Val, declaration.Val, variables.Val)); @@ -3747,6 +3780,7 @@ OPTIONAL(file, MDField, ); \ OPTIONAL(line, LineField, ); \ OPTIONAL(type, MDField, ); \ + OPTIONAL(typeIndex, MDUnsignedField, (0, UINT32_MAX)); \ OPTIONAL(isLocal, MDBoolField, ); \ OPTIONAL(isDefinition, MDBoolField, (true)); \ OPTIONAL(variable, MDConstant, ); \ @@ -3756,7 +3790,8 @@ Result = GET_OR_DISTINCT(DIGlobalVariable, (Context, scope.Val, name.Val, linkageName.Val, - file.Val, line.Val, type.Val, isLocal.Val, + file.Val, line.Val, type.Val, + codeview::TypeIndex(typeIndex.Val), isLocal.Val, isDefinition.Val, variable.Val, declaration.Val)); return false; } @@ -3772,6 +3807,7 @@ OPTIONAL(file, MDField, ); \ OPTIONAL(line, LineField, ); \ OPTIONAL(type, MDField, ); \ + OPTIONAL(typeIndex, MDUnsignedField, (0, UINT32_MAX)); \ OPTIONAL(arg, MDUnsignedField, (0, UINT16_MAX)); \ OPTIONAL(flags, DIFlagField, ); PARSE_MD_FIELDS(); @@ -3779,7 +3815,9 @@ Result = GET_OR_DISTINCT(DILocalVariable, (Context, tag.Val, scope.Val, name.Val, file.Val, - line.Val, type.Val, arg.Val, flags.Val)); + line.Val, type.Val, + codeview::TypeIndex(typeIndex.Val), arg.Val, + flags.Val)); return false; } Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -1869,7 +1869,7 @@ break; } case bitc::METADATA_COMPILE_UNIT: { - if (Record.size() < 14 || Record.size() > 15) + if (Record.size() < 15 || Record.size() > 16) return error("Invalid record"); MDValueList.assignValue( @@ -1880,12 +1880,13 @@ Record[6], getMDString(Record[7]), Record[8], getMDOrNull(Record[9]), getMDOrNull(Record[10]), getMDOrNull(Record[11]), getMDOrNull(Record[12]), - getMDOrNull(Record[13]), Record.size() == 14 ? 0 : Record[14])), + getMDOrNull(Record[13]), getMDOrNull(Record[14]), + Record.size() == 15 ? 0 : Record[15])), NextMDValueNo++); break; } case bitc::METADATA_SUBPROGRAM: { - if (Record.size() != 19) + if (Record.size() != 20) return error("Invalid record"); MDValueList.assignValue( @@ -1893,10 +1894,11 @@ DISubprogram, Record[0], (Context, getMDOrNull(Record[1]), getMDString(Record[2]), getMDString(Record[3]), getMDOrNull(Record[4]), Record[5], - getMDOrNull(Record[6]), Record[7], Record[8], Record[9], - getMDOrNull(Record[10]), Record[11], Record[12], Record[13], - Record[14], getMDOrNull(Record[15]), getMDOrNull(Record[16]), - getMDOrNull(Record[17]), getMDOrNull(Record[18]))), + getMDOrNull(Record[6]), codeview::TypeIndex(Record[7]), + Record[8], Record[9], Record[10], + getMDOrNull(Record[11]), Record[12], Record[13], Record[14], + Record[15], getMDOrNull(Record[16]), getMDOrNull(Record[17]), + getMDOrNull(Record[18]), getMDOrNull(Record[19]))), NextMDValueNo++); break; } @@ -1957,7 +1959,7 @@ break; } case bitc::METADATA_GLOBAL_VAR: { - if (Record.size() != 11) + if (Record.size() != 12) return error("Invalid record"); MDValueList.assignValue( @@ -1965,22 +1967,25 @@ (Context, getMDOrNull(Record[1]), getMDString(Record[2]), getMDString(Record[3]), getMDOrNull(Record[4]), Record[5], - getMDOrNull(Record[6]), Record[7], Record[8], - getMDOrNull(Record[9]), getMDOrNull(Record[10]))), + getMDOrNull(Record[6]), + codeview::TypeIndex(Record[7]), + Record[8], Record[9], + getMDOrNull(Record[10]), getMDOrNull(Record[11]))), NextMDValueNo++); break; } case bitc::METADATA_LOCAL_VAR: { // 10th field is for the obseleted 'inlinedAt:' field. - if (Record.size() != 9 && Record.size() != 10) + if (Record.size() != 10 && Record.size() != 11) return error("Invalid record"); MDValueList.assignValue( GET_OR_DISTINCT(DILocalVariable, Record[0], (Context, Record[1], getMDOrNull(Record[2]), getMDString(Record[3]), getMDOrNull(Record[4]), - Record[5], getMDOrNull(Record[6]), Record[7], - Record[8])), + Record[5], getMDOrNull(Record[6]), + codeview::TypeIndex(Record[7]), Record[8], + Record[9])), NextMDValueNo++); break; } Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -957,12 +957,40 @@ Record.push_back(VE.getMetadataOrNullID(N->getSubprograms().get())); Record.push_back(VE.getMetadataOrNullID(N->getGlobalVariables().get())); Record.push_back(VE.getMetadataOrNullID(N->getImportedEntities().get())); + Record.push_back(VE.getMetadataOrNullID(N->getRawCodeViewTypes())); Record.push_back(N->getDWOId()); Stream.EmitRecord(bitc::METADATA_COMPILE_UNIT, Record, Abbrev); Record.clear(); } +static void WriteDICodeViewTypes(const DICodeViewTypes *N, + const ValueEnumerator &VE, + BitstreamWriter &Stream, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(N->getSignature()); + Record.push_back(VE.getMetadataOrNullID(N->getRawTypeRecords())); + Record.push_back(VE.getMetadataOrNullID(N->getRawUDTSymbols())); + + Stream.EmitRecord(bitc::METADATA_CODEVIEW_TYPES, Record, Abbrev); + Record.clear(); +} + +static void WriteDICodeViewUDT(const DICodeViewUDT *N, + const ValueEnumerator &VE, + BitstreamWriter &Stream, + SmallVectorImpl &Record, + unsigned Abbrev) { + Record.push_back(N->isDistinct()); + Record.push_back(VE.getMetadataOrNullID(N->getRawName())); + Record.push_back(N->getTypeIndex().getIndex()); + + Stream.EmitRecord(bitc::METADATA_CODEVIEW_UDT, Record, Abbrev); + Record.clear(); +} + static void WriteDISubprogram(const DISubprogram *N, const ValueEnumerator &VE, BitstreamWriter &Stream, SmallVectorImpl &Record, Index: lib/CMakeLists.txt =================================================================== --- lib/CMakeLists.txt +++ lib/CMakeLists.txt @@ -20,3 +20,4 @@ add_subdirectory(Fuzzer) add_subdirectory(Passes) add_subdirectory(LibDriver) +add_subdirectory(CodeView) Index: lib/CodeView/CMakeLists.txt =================================================================== --- /dev/null +++ lib/CodeView/CMakeLists.txt @@ -0,0 +1,12 @@ +add_llvm_library(LLVMCodeView + CodeViewOStream.cpp + FieldListRecordBuilder.cpp + FunctionId.cpp + Line.cpp + ListRecordBuilder.cpp + MemoryTypeTableBuilder.cpp + MethodListRecordBuilder.cpp + TypeIndex.cpp + TypeRecordBuilder.cpp + TypeTableBuilder.cpp + ) Index: lib/CodeView/CodeViewOStream.cpp =================================================================== --- /dev/null +++ lib/CodeView/CodeViewOStream.cpp @@ -0,0 +1,4 @@ +#include "llvm/CodeView/CodeViewOStream.h" + +using namespace llvm; +using namespace codeview; Index: lib/CodeView/FieldListRecordBuilder.cpp =================================================================== --- /dev/null +++ lib/CodeView/FieldListRecordBuilder.cpp @@ -0,0 +1,167 @@ +#include "llvm/CodeView/FieldListRecordBuilder.h" + +using namespace llvm; +using namespace codeview; + +FieldListRecordBuilder::FieldListRecordBuilder() : + ListRecordBuilder(TypeRecordKind::FieldList) +{ +} + +void FieldListRecordBuilder::writeBaseClass(MemberAccess Access, + TypeIndex Type, uint64_t Offset) +{ + TypeRecordBuilder& Builder = getBuilder(); + + Builder.writeTypeRecordKind(TypeRecordKind::BaseClass); + Builder.writeUInt16(static_cast(Access)); + Builder.writeTypeIndex(Type); + Builder.writeEncodedUnsignedInteger(Offset); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeEnumerate(MemberAccess Access, + uint64_t Value, StringRef Name) +{ + TypeRecordBuilder& Builder = getBuilder(); + + Builder.writeTypeRecordKind(TypeRecordKind::Enumerate); + Builder.writeUInt16(static_cast(Access)); + Builder.writeEncodedUnsignedInteger(Value); + Builder.writeNullTerminatedString(Name); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeMember(MemberAccess Access, TypeIndex Type, + uint64_t Offset, StringRef Name) +{ + TypeRecordBuilder& Builder = getBuilder(); + + Builder.writeTypeRecordKind(TypeRecordKind::Member); + Builder.writeUInt16(static_cast(Access)); + Builder.writeTypeIndex(Type); + Builder.writeEncodedUnsignedInteger(Offset); + Builder.writeNullTerminatedString(Name); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeMethod(uint16_t OverloadCount, + TypeIndex MethodList, StringRef Name) +{ + TypeRecordBuilder& Builder = getBuilder(); + + Builder.writeTypeRecordKind(TypeRecordKind::Method); + Builder.writeUInt16(OverloadCount); + Builder.writeTypeIndex(MethodList); + Builder.writeNullTerminatedString(Name); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeOneMethod(MemberAccess Access, + MethodKind Kind, MethodOptions Options, TypeIndex Type, + int32_t VTableSlotOffset, StringRef Name) +{ + TypeRecordBuilder& Builder = getBuilder(); + + uint16_t Flags = static_cast(Access); + Flags |= static_cast(Kind) << MethodKindShift; + Flags |= static_cast(Options); + + Builder.writeTypeRecordKind(TypeRecordKind::OneMethod); + Builder.writeUInt16(Flags); + Builder.writeTypeIndex(Type); + switch (Kind) { + case MethodKind::IntroducingVirtual: + case MethodKind::PureIntroducingVirtual: + assert(VTableSlotOffset >= 0); + Builder.writeInt32(VTableSlotOffset); + break; + + default: + assert(VTableSlotOffset == -1); + break; + } + + Builder.writeNullTerminatedString(Name); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeOneMethod(const MethodInfo& Method, + StringRef Name) +{ + writeOneMethod(Method.getAccess(), Method.getKind(), Method.getOptions(), + Method.getType(), Method.getVTableSlotOffset(), Name); +} + +void FieldListRecordBuilder::writeNestedType(TypeIndex Type, StringRef Name) +{ + TypeRecordBuilder& Builder = getBuilder(); + + Builder.writeTypeRecordKind(TypeRecordKind::NestedType); + Builder.writeUInt16(0); + Builder.writeTypeIndex(Type); + Builder.writeNullTerminatedString(Name); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeStaticMember(MemberAccess Access, + TypeIndex Type, StringRef Name) +{ + TypeRecordBuilder& Builder = getBuilder(); + + Builder.writeTypeRecordKind(TypeRecordKind::StaticMember); + Builder.writeUInt16(static_cast(Access)); + Builder.writeTypeIndex(Type); + Builder.writeNullTerminatedString(Name); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeIndirectVirtualBaseClass(MemberAccess Access, + TypeIndex Type, TypeIndex VirtualBasePointerType, + int64_t VirtualBasePointerOffset, uint64_t SlotIndex) +{ + writeVirtualBaseClass(TypeRecordKind::IndirectVirtualBaseClass, Access, Type, + VirtualBasePointerType, VirtualBasePointerOffset, SlotIndex); +} + +void FieldListRecordBuilder::writeVirtualBaseClass(MemberAccess Access, + TypeIndex Type, TypeIndex VirtualBasePointerType, + int64_t VirtualBasePointerOffset, uint64_t SlotIndex) +{ + writeVirtualBaseClass(TypeRecordKind::VirtualBaseClass, Access, Type, + VirtualBasePointerType, VirtualBasePointerOffset, SlotIndex); +} + +void FieldListRecordBuilder::writeVirtualBaseClass(TypeRecordKind Kind, + MemberAccess Access, TypeIndex Type, TypeIndex VirtualBasePointerType, + int64_t VirtualBasePointerOffset, uint64_t SlotIndex) +{ + TypeRecordBuilder& Builder = getBuilder(); + + Builder.writeTypeRecordKind(Kind); + Builder.writeUInt16(static_cast(Access)); + Builder.writeTypeIndex(Type); + Builder.writeTypeIndex(VirtualBasePointerType); + Builder.writeEncodedInteger(VirtualBasePointerOffset); + Builder.writeEncodedUnsignedInteger(SlotIndex); + + finishSubRecord(); +} + +void FieldListRecordBuilder::writeVirtualFunctionTablePointer(TypeIndex Type) +{ + TypeRecordBuilder& Builder = getBuilder(); + + Builder.writeTypeRecordKind(TypeRecordKind::VirtualFunctionTablePointer); + Builder.writeUInt16(0); + Builder.writeTypeIndex(Type); + + finishSubRecord(); +} \ No newline at end of file Index: lib/CodeView/FunctionId.cpp =================================================================== --- /dev/null +++ lib/CodeView/FunctionId.cpp @@ -0,0 +1,7 @@ +#include "llvm/CodeView/FunctionId.h" + +namespace llvm { +namespace codeview { + +} +} \ No newline at end of file Index: lib/CodeView/LLVMBuild.txt =================================================================== --- /dev/null +++ lib/CodeView/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./lib/CodeView/LLVMBuild.txt -------------------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = CodeView +parent = Libraries +required_libraries = Support Index: lib/CodeView/Line.cpp =================================================================== --- /dev/null +++ lib/CodeView/Line.cpp @@ -0,0 +1,14 @@ +#include "llvm/CodeView/Line.h" + +using namespace llvm; +using namespace codeview; + +LineInfo::LineInfo(uint32_t StartLine, uint32_t EndLine, bool IsStatement) +{ + LineData = StartLine & StartLineMask; + uint32_t LineDelta = EndLine - StartLine; + LineData |= (LineDelta << EndLineDeltaShift) & EndLineDeltaMask; + if (IsStatement) { + LineData |= StatementFlag; + } +} Index: lib/CodeView/ListRecordBuilder.cpp =================================================================== --- /dev/null +++ lib/CodeView/ListRecordBuilder.cpp @@ -0,0 +1,24 @@ +#include "llvm/CodeView/ListRecordBuilder.h" + +using namespace llvm; +using namespace codeview; + +ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind) : + Builder(Kind) +{ +} + +void ListRecordBuilder::finishSubRecord() +{ + // The builder starts at offset 2 in the actual CodeView buffer, so add an additional + // offset of 2 before computing the alignment. + uint32_t Remainder = (Builder.size() + 2) % 4; + if (Remainder != 0) { + for (int32_t PaddingBytesLeft = 4 - Remainder; PaddingBytesLeft > 0; --PaddingBytesLeft) { + Builder.writeUInt8(0xf0 + PaddingBytesLeft); + } + } + + //TODO: Continuations + assert(Builder.size() < 65536); +} Index: lib/CodeView/MemoryTypeTableBuilder.cpp =================================================================== --- /dev/null +++ lib/CodeView/MemoryTypeTableBuilder.cpp @@ -0,0 +1,33 @@ +#include "llvm/CodeView/MemoryTypeTableBuilder.h" +#include "llvm/CodeView/TypeIndex.h" + +namespace llvm { +namespace codeview { + +MemoryTypeTableBuilder::Record::Record(StringRef RData) : + Size(RData.size()), + Data(new char[RData.size()]) +{ + memcpy(Data.get(), RData.data(), RData.size()); +} + +TypeIndex MemoryTypeTableBuilder::writeRecord(StringRef Data) +{ + auto I = HashedRecords.find(Data); + if (I != HashedRecords.end()) { + return I->second; + } + + std::unique_ptr R(new Record(Data)); + + TypeIndex TI(static_cast(Records.size()) + + TypeIndex::FirstNonSimpleIndex); + HashedRecords.insert(std::make_pair(StringRef(R->data(), R->size()), + TI)); + Records.push_back(std::move(R)); + + return TI; +} + +} +} \ No newline at end of file Index: lib/CodeView/MethodListRecordBuilder.cpp =================================================================== --- /dev/null +++ lib/CodeView/MethodListRecordBuilder.cpp @@ -0,0 +1,44 @@ +#include "llvm/CodeView/MethodListRecordBuilder.h" +#include "llvm/CodeView/FieldListRecordBuilder.h" + +using namespace llvm; +using namespace codeview; + +MethodListRecordBuilder::MethodListRecordBuilder() : + ListRecordBuilder(TypeRecordKind::MethodList) +{ +} + +void MethodListRecordBuilder::writeMethod(MemberAccess Access, + MethodKind Kind, MethodOptions Options, TypeIndex Type, + int32_t VTableSlotOffset) +{ + TypeRecordBuilder& Builder = getBuilder(); + + uint16_t Flags = static_cast(Access); + Flags |= static_cast(Kind) << MethodKindShift; + Flags |= static_cast(Options); + + Builder.writeUInt16(Flags); + Builder.writeUInt16(0); + Builder.writeTypeIndex(Type); + switch (Kind) { + case MethodKind::IntroducingVirtual: + case MethodKind::PureIntroducingVirtual: + assert(VTableSlotOffset >= 0); + Builder.writeInt32(VTableSlotOffset); + break; + + default: + assert(VTableSlotOffset == -1); + break; + } + + //TODO: Fail if too big? +} + +void MethodListRecordBuilder::writeMethod(const MethodInfo& Method) +{ + writeMethod(Method.getAccess(), Method.getKind(), Method.getOptions(), + Method.getType(), Method.getVTableSlotOffset()); +} Index: lib/CodeView/TypeIndex.cpp =================================================================== --- /dev/null +++ lib/CodeView/TypeIndex.cpp @@ -0,0 +1,4 @@ +#include "llvm/CodeView/TypeIndex.h" + +using namespace llvm; +using namespace codeview; Index: lib/CodeView/TypeRecordBuilder.cpp =================================================================== --- /dev/null +++ lib/CodeView/TypeRecordBuilder.cpp @@ -0,0 +1,128 @@ +#include "llvm/CodeView/TypeRecordBuilder.h" + +using namespace llvm; +using namespace codeview; + +TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind) : + Stream(Buffer) +{ + writeTypeRecordKind(Kind); +} + +StringRef TypeRecordBuilder::str() +{ + Stream.flush(); + return StringRef(Buffer.data(), Buffer.size()); +} + +void TypeRecordBuilder::writeUInt8(uint8_t Value) +{ + Stream.write(reinterpret_cast(&Value), sizeof(uint8_t)); +} + +void TypeRecordBuilder::writeInt16(int16_t Value) +{ + Stream.write(reinterpret_cast(&Value), sizeof(int16_t)); +} + +void TypeRecordBuilder::writeUInt16(uint16_t Value) +{ + Stream.write(reinterpret_cast(&Value), sizeof(uint16_t)); +} + +void TypeRecordBuilder::writeInt32(int32_t Value) +{ + Stream.write(reinterpret_cast(&Value), sizeof(int32_t)); +} + +void TypeRecordBuilder::writeUInt32(uint32_t Value) +{ + Stream.write(reinterpret_cast(&Value), sizeof(uint32_t)); +} + +void TypeRecordBuilder::writeInt64(int64_t Value) +{ + Stream.write(reinterpret_cast(&Value), sizeof(int64_t)); +} + +void TypeRecordBuilder::writeUInt64(uint64_t Value) +{ + Stream.write(reinterpret_cast(&Value), sizeof(uint64_t)); +} + +void TypeRecordBuilder::writeEncodedInteger(int64_t Value) +{ + if (Value >= 0) { + writeEncodedUnsignedInteger(static_cast(Value)); + } + else { + writeEncodedSignedInteger(Value); + } +} + +void TypeRecordBuilder::writeEncodedSignedInteger(int64_t Value) +{ + if (Value >= std::numeric_limits::min() && + Value <= std::numeric_limits::max()) { + writeUInt16(static_cast(TypeRecordKind::SByte)); + writeInt16(static_cast(Value)); + } + else if (Value >= std::numeric_limits::min() && + Value <= std::numeric_limits::max()) { + writeUInt16(static_cast(TypeRecordKind::Int16)); + writeInt16(static_cast(Value)); + } + else if (Value >= std::numeric_limits::min() && + Value <= std::numeric_limits::max()) { + writeUInt16(static_cast(TypeRecordKind::Int32)); + writeInt32(static_cast(Value)); + } + else { + writeUInt16(static_cast(TypeRecordKind::Int64)); + writeInt64(Value); + } +} + +void TypeRecordBuilder::writeEncodedUnsignedInteger(uint64_t Value) +{ + if (Value < static_cast(TypeRecordKind::SByte)) { + writeUInt16(static_cast(Value)); + } + else if (Value <= std::numeric_limits::max()) { + writeUInt16(static_cast(TypeRecordKind::UInt16)); + writeUInt16(static_cast(Value)); + } + else if (Value <= std::numeric_limits::max()) { + writeUInt16(static_cast(TypeRecordKind::UInt32)); + writeUInt32(static_cast(Value)); + } + else { + writeUInt16(static_cast(TypeRecordKind::UInt64)); + writeUInt64(Value); + } +} + +void TypeRecordBuilder::writeNullTerminatedString(const char* Value) +{ + assert(Value != nullptr); + + size_t Length = strlen(Value); + Stream.write(Value, Length); + writeUInt8(0); +} + +void TypeRecordBuilder::writeNullTerminatedString(StringRef Value) +{ + Stream.write(Value.data(), Value.size()); + writeUInt8(0); +} + +void TypeRecordBuilder::writeTypeIndex(TypeIndex TypeInd) +{ + writeUInt32(TypeInd.getIndex()); +} + +void TypeRecordBuilder::writeTypeRecordKind(TypeRecordKind Kind) +{ + writeUInt16(static_cast(Kind)); +} Index: lib/CodeView/TypeTableBuilder.cpp =================================================================== --- /dev/null +++ lib/CodeView/TypeTableBuilder.cpp @@ -0,0 +1,222 @@ +#include "llvm/CodeView/TypeTableBuilder.h" +#include "llvm/CodeView/FieldListRecordBuilder.h" +#include "llvm/CodeView/MethodListRecordBuilder.h" +#include "llvm/CodeView/TypeIndex.h" +#include "llvm/CodeView/TypeRecordBuilder.h" +#include "llvm/support/raw_ostream.h" +#include "llvm/ADT/SmallVector.h" + +using namespace llvm; +using namespace codeview; + +namespace { + +const uint32_t PointerKindMask = 0x0000001f; +const int PointerKindShift = 0; +const uint32_t PointerModeMask = 0x000000e0; +const int PointerModeShift = 5; +const uint32_t PointerSizeMask = 0x0007e000; +const int PointerSizeShift = 13; +const uint32_t PointerOptionsMask = 0x00081f00; + +const int ClassHfaKindShift = 11; +const int ClassWindowsRTClassKindShift = 14; + +void writePointerBase(TypeRecordBuilder& Builder, + const PointerRecordBase& Record) +{ + Builder.writeTypeIndex(Record.getReferentType()); + uint32_t flags = static_cast(Record.getOptions()) | + (Record.getSize() << PointerSizeShift) | + (static_cast(Record.getMode()) << PointerModeShift) | + (static_cast(Record.getPointerKind()) << PointerKindShift); + Builder.writeUInt32(flags); +} + +} + +TypeTableBuilder::TypeTableBuilder() +{ +} + +TypeTableBuilder::~TypeTableBuilder() +{ +} + +TypeIndex TypeTableBuilder::writeModifier(const ModifierRecord& Record) +{ + TypeRecordBuilder Builder(TypeRecordKind::Modifier); + + Builder.writeTypeIndex(Record.getModifiedType()); + Builder.writeUInt16(static_cast(Record.getOptions())); + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord& Record) +{ + TypeRecordBuilder Builder(TypeRecordKind::Procedure); + + Builder.writeTypeIndex(Record.getReturnType()); + Builder.writeUInt8(static_cast(Record.getCallConv())); + Builder.writeUInt8(static_cast(Record.getOptions())); + Builder.writeUInt16(Record.getParameterCount()); + Builder.writeTypeIndex(Record.getArgumentList()); + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeMemberFunction( + const MemberFunctionRecord& Record) +{ + TypeRecordBuilder Builder(TypeRecordKind::MemberFunction); + + Builder.writeTypeIndex(Record.getReturnType()); + Builder.writeTypeIndex(Record.getClassType()); + Builder.writeTypeIndex(Record.getThisType()); + Builder.writeUInt8(static_cast(Record.getCallConv())); + Builder.writeUInt8(static_cast(Record.getOptions())); + Builder.writeUInt16(Record.getParameterCount()); + Builder.writeTypeIndex(Record.getArgumentList()); + Builder.writeInt32(Record.getThisPointerAdjustment()); + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeArgumentList( + const ArgumentListRecord& Record) +{ + TypeRecordBuilder Builder(TypeRecordKind::ArgumentList); + + Builder.writeUInt32(Record.getArgumentTypes().size()); + for (TypeIndex TI : Record.getArgumentTypes()) { + Builder.writeTypeIndex(TI); + } + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writePointer(const PointerRecord& Record) +{ + TypeRecordBuilder Builder(TypeRecordKind::Pointer); + + writePointerBase(Builder, Record); + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writePointerToMember( + const PointerToMemberRecord& Record) +{ + TypeRecordBuilder Builder(TypeRecordKind::Pointer); + + writePointerBase(Builder, Record); + + Builder.writeTypeIndex(Record.getContainingType()); + Builder.writeUInt16(static_cast(Record.getRepresentation())); + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeArray(const ArrayRecord& Record) +{ + TypeRecordBuilder Builder(TypeRecordKind::Array); + + Builder.writeTypeIndex(Record.getElementType()); + Builder.writeTypeIndex(Record.getIndexType()); + Builder.writeEncodedUnsignedInteger(Record.getSize()); + Builder.writeNullTerminatedString(Record.getName()); + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeAggregate(const AggregateRecord& Record) +{ + assert((Record.getKind() == TypeRecordKind::Structure) || + (Record.getKind() == TypeRecordKind::Class) || (Record.getKind() == TypeRecordKind::Union)); + + TypeRecordBuilder Builder(Record.getKind()); + + Builder.writeUInt16(Record.getMemberCount()); + uint16_t Flags = static_cast(Record.getOptions()) | + (static_cast(Record.getHfa()) << ClassHfaKindShift) | + (static_cast(Record.getWinRTKind()) << ClassWindowsRTClassKindShift); + Builder.writeUInt16(Flags); + Builder.writeTypeIndex(Record.getFieldList()); + if (Record.getKind() != TypeRecordKind::Union) { + Builder.writeTypeIndex(Record.getDerivationList()); + Builder.writeTypeIndex(Record.getVTableShape()); + } + else { + assert(Record.getDerivationList() == TypeIndex()); + assert(Record.getVTableShape() == TypeIndex()); + } + Builder.writeEncodedUnsignedInteger(Record.getSize()); + Builder.writeNullTerminatedString(Record.getName()); + if ((Record.getOptions() & ClassOptions::HasUniqueName) != ClassOptions::None) { + Builder.writeNullTerminatedString(Record.getUniqueName()); + } + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeEnum(const EnumRecord& Record) +{ + TypeRecordBuilder Builder(TypeRecordKind::Enum); + + Builder.writeUInt16(Record.getMemberCount()); + Builder.writeUInt16(static_cast(Record.getOptions())); + Builder.writeTypeIndex(Record.getUnderlyingType()); + Builder.writeTypeIndex(Record.getFieldList()); + Builder.writeNullTerminatedString(Record.getName()); + if ((Record.getOptions() & ClassOptions::HasUniqueName) != ClassOptions::None) { + Builder.writeNullTerminatedString(Record.getUniqueName()); + } + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord& Record) +{ + TypeRecordBuilder Builder(TypeRecordKind::BitField); + + Builder.writeTypeIndex(Record.getType()); + Builder.writeUInt8(Record.getBitSize()); + Builder.writeUInt8(Record.getBitOffset()); + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeVirtualTableShape( + const VirtualTableShapeRecord& Record) +{ + TypeRecordBuilder Builder(TypeRecordKind::VirtualTableShape); + + Builder.writeUInt16(Record.getSlots().size()); + for (size_t SlotIndex = 0; SlotIndex < Record.getSlots().size(); SlotIndex += 2) { + uint8_t Byte = static_cast(Record.getSlots()[SlotIndex]) << 4; + if ((SlotIndex + 1) < Record.getSlots().size()) { + Byte |= static_cast(Record.getSlots()[SlotIndex + 1]); + } + Builder.writeUInt8(Byte); + } + + return writeRecord(Builder); +} + +TypeIndex TypeTableBuilder::writeRecord(TypeRecordBuilder& Builder) +{ + return writeRecord(Builder.str()); +} + +TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder& FieldList) +{ + //TODO: Continuations + return writeRecord(FieldList.str()); +} + +TypeIndex TypeTableBuilder::writeMethodList(MethodListRecordBuilder& MethodList) +{ + //TODO: Continuations + return writeRecord(MethodList.str()); +} Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -1633,6 +1633,27 @@ Out << ")"; } +static void writeDICodeViewTypes(raw_ostream &Out, const DICodeViewTypes *N, + TypePrinting *TypePrinter, + SlotTracker *Machine, const Module *Context) { + Out << "!DICodeViewTypes("; + MDFieldPrinter Printer(Out, TypePrinter, Machine, Context); + Printer.printInt("signature", N->getSignature(), false); + Printer.printMetadata("typeRecords", N->getRawTypeRecords()); + Printer.printMetadata("udtSymbols", N->getRawUDTSymbols()); + Out << ")"; +} + +static void writeDICodeViewUDT(raw_ostream &Out, const DICodeViewUDT *N, + TypePrinting *TypePrinter, + SlotTracker *Machine, const Module *Context) { + Out << "!DICodeViewUDT("; + MDFieldPrinter Printer(Out); + Printer.printInt("typeIndex", N->getTypeIndex().getIndex(), false); + Printer.printString("name", N->getName()); + Out << ")"; +} + static void writeDICompileUnit(raw_ostream &Out, const DICompileUnit *N, TypePrinting *TypePrinter, SlotTracker *Machine, const Module *Context) { @@ -1654,6 +1675,7 @@ Printer.printMetadata("subprograms", N->getRawSubprograms()); Printer.printMetadata("globals", N->getRawGlobalVariables()); Printer.printMetadata("imports", N->getRawImportedEntities()); + Printer.printMetadata("codeViewTypes", N->getRawCodeViewTypes()); Printer.printInt("dwoId", N->getDWOId()); Out << ")"; } Index: lib/IR/CMakeLists.txt =================================================================== --- lib/IR/CMakeLists.txt +++ lib/IR/CMakeLists.txt @@ -30,6 +30,7 @@ LLVMContextImpl.cpp LegacyPassManager.cpp MDBuilder.cpp + MDTypeTableBuilder.cpp Mangler.cpp Metadata.cpp MetadataTracking.cpp Index: lib/IR/DIBuilder.cpp =================================================================== --- lib/IR/DIBuilder.cpp +++ lib/IR/DIBuilder.cpp @@ -21,6 +21,7 @@ #include "llvm/Support/Dwarf.h" using namespace llvm; +using namespace llvm::codeview; using namespace llvm::dwarf; namespace { @@ -57,10 +58,17 @@ }; } +void DIBuilder::MDTypeSymbolEmitter::writeUserDefinedType(TypeIndex TI, + StringRef Name) { + UDTRecords.push_back(DICodeViewUDT::get(Context, Name , TI)); +} + DIBuilder::DIBuilder(Module &m, bool AllowUnresolvedNodes) : M(m), VMContext(M.getContext()), CUNode(nullptr), DeclareFn(nullptr), ValueFn(nullptr), - AllowUnresolvedNodes(AllowUnresolvedNodes) {} + AllowUnresolvedNodes(AllowUnresolvedNodes), + CodeViewTypesBuilder(m.getContext()), + CodeViewTypeSymbolEmitter(m.getContext()) {} void DIBuilder::trackIfUnresolved(MDNode *N) { if (!N) @@ -115,6 +123,9 @@ VMContext, SmallVector(AllImportedModules.begin(), AllImportedModules.end()))); + DICodeViewTypes *CodeViewTypes = createCodeViewTypes(); + CUNode->replaceCodeViewTypes(CodeViewTypes); + // Now that all temp nodes have been replaced or deleted, resolve remaining // cycles. for (const auto &N : UnresolvedNodes) @@ -148,7 +159,7 @@ CUNode = DICompileUnit::getDistinct( VMContext, Lang, DIFile::get(VMContext, Filename, Directory), Producer, isOptimized, Flags, RunTimeVer, SplitName, Kind, nullptr, - nullptr, nullptr, nullptr, nullptr, DWOId); + nullptr, nullptr, nullptr, nullptr, nullptr, DWOId); // Create a named metadata so that it is easier to find cu in a module. // Note that we only generate this when the caller wants to actually @@ -164,6 +175,12 @@ return CUNode; } +DICodeViewTypes *DIBuilder::createCodeViewTypes() { + MDTuple *TypeRecords = MDNode::get(VMContext, CodeViewTypesBuilder.getRecords()); + DICodeViewUDTArray UDTs(MDNode::get(VMContext, CodeViewTypeSymbolEmitter.getUDTRecords())); + return DICodeViewTypes::get(VMContext, 4, TypeRecords, UDTs); +} + static DIImportedEntity * createImportedModule(LLVMContext &C, dwarf::Tag Tag, DIScope *Context, Metadata *NS, unsigned Line, StringRef Name, @@ -565,34 +582,35 @@ DIGlobalVariable *DIBuilder::createGlobalVariable( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, - unsigned LineNumber, DIType *Ty, bool isLocalToUnit, Constant *Val, - MDNode *Decl) { + unsigned LineNumber, DIType *Ty, codeview::TypeIndex TI, bool isLocalToUnit, + Constant *Val, MDNode *Decl) { checkGlobalVariableScope(Context); auto *N = DIGlobalVariable::get(VMContext, cast_or_null(Context), - Name, LinkageName, F, LineNumber, - DITypeRef::get(Ty), isLocalToUnit, true, Val, - cast_or_null(Decl)); + Name, LinkageName, F, LineNumber, + DITypeRef::get(Ty), TI, isLocalToUnit, true, + Val, cast_or_null(Decl)); AllGVs.push_back(N); return N; } DIGlobalVariable *DIBuilder::createTempGlobalVariableFwdDecl( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, - unsigned LineNumber, DIType *Ty, bool isLocalToUnit, Constant *Val, - MDNode *Decl) { + unsigned LineNumber, DIType *Ty, codeview::TypeIndex TI, bool isLocalToUnit, + Constant *Val, MDNode *Decl) { checkGlobalVariableScope(Context); return DIGlobalVariable::getTemporary( VMContext, cast_or_null(Context), Name, LinkageName, F, - LineNumber, DITypeRef::get(Ty), isLocalToUnit, false, Val, + LineNumber, DITypeRef::get(Ty), TI, isLocalToUnit, false, Val, cast_or_null(Decl)) .release(); } DILocalVariable *DIBuilder::createLocalVariable( unsigned Tag, DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNo, - DIType *Ty, bool AlwaysPreserve, unsigned Flags, unsigned ArgNo) { + DIType *Ty, codeview::TypeIndex TI, bool AlwaysPreserve, unsigned Flags, + unsigned ArgNo) { // FIXME: Why getNonCompileUnitScope()? // FIXME: Why is "!Context" okay here? // FIXME: Why doesn't this check for a subprogram or lexical block (AFAICT @@ -601,7 +619,7 @@ auto *Node = DILocalVariable::get( VMContext, Tag, cast_or_null(Context), Name, File, LineNo, - DITypeRef::get(Ty), ArgNo, Flags); + DITypeRef::get(Ty), TI, ArgNo, Flags); if (AlwaysPreserve) { // The optimizer may remove local variables. If there is an interest // to preserve variable info in such situation then stash it in a @@ -632,6 +650,7 @@ DISubprogram *DIBuilder::createFunction(DIScopeRef Context, StringRef Name, StringRef LinkageName, DIFile *File, unsigned LineNo, DISubroutineType *Ty, + codeview::TypeIndex TI, bool isLocalToUnit, bool isDefinition, unsigned ScopeLine, unsigned Flags, bool isOptimized, Function *Fn, @@ -640,13 +659,14 @@ // to resolve the context should be fine. DITypeIdentifierMap EmptyMap; return createFunction(Context.resolve(EmptyMap), Name, LinkageName, File, - LineNo, Ty, isLocalToUnit, isDefinition, ScopeLine, + LineNo, Ty, TI, isLocalToUnit, isDefinition, ScopeLine, Flags, isOptimized, Fn, TParams, Decl); } DISubprogram *DIBuilder::createFunction(DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, unsigned LineNo, DISubroutineType *Ty, + codeview::TypeIndex TI, bool isLocalToUnit, bool isDefinition, unsigned ScopeLine, unsigned Flags, bool isOptimized, Function *Fn, @@ -655,7 +675,7 @@ "function types should be subroutines"); auto *Node = DISubprogram::get( VMContext, DIScopeRef::get(getNonCompileUnitScope(Context)), Name, - LinkageName, File, LineNo, Ty, isLocalToUnit, isDefinition, ScopeLine, + LinkageName, File, LineNo, Ty, TI, isLocalToUnit, isDefinition, ScopeLine, nullptr, 0, 0, Flags, isOptimized, Fn, cast_or_null(TParams), cast_or_null(Decl), MDTuple::getTemporary(VMContext, None).release()); @@ -668,12 +688,12 @@ DISubprogram *DIBuilder::createTempFunctionFwdDecl( DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File, - unsigned LineNo, DISubroutineType *Ty, bool isLocalToUnit, - bool isDefinition, unsigned ScopeLine, unsigned Flags, bool isOptimized, - Function *Fn, MDNode *TParams, MDNode *Decl) { + unsigned LineNo, DISubroutineType *Ty, codeview::TypeIndex TI, + bool isLocalToUnit, bool isDefinition, unsigned ScopeLine, unsigned Flags, + bool isOptimized, Function *Fn, MDNode *TParams, MDNode *Decl) { return DISubprogram::getTemporary( VMContext, DIScopeRef::get(getNonCompileUnitScope(Context)), Name, - LinkageName, File, LineNo, Ty, isLocalToUnit, isDefinition, + LinkageName, File, LineNo, Ty, TI, isLocalToUnit, isDefinition, ScopeLine, nullptr, 0, 0, Flags, isOptimized, Fn, cast_or_null(TParams), cast_or_null(Decl), nullptr) @@ -683,6 +703,7 @@ DISubprogram * DIBuilder::createMethod(DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F, unsigned LineNo, DISubroutineType *Ty, + codeview::TypeIndex TI, bool isLocalToUnit, bool isDefinition, unsigned VK, unsigned VIndex, DIType *VTableHolder, unsigned Flags, bool isOptimized, Function *Fn, MDNode *TParam) { @@ -694,7 +715,7 @@ // FIXME: Do we want to use different scope/lines? auto *SP = DISubprogram::get( VMContext, DIScopeRef::get(cast(Context)), Name, LinkageName, F, - LineNo, Ty, isLocalToUnit, isDefinition, LineNo, + LineNo, Ty, TI, isLocalToUnit, isDefinition, LineNo, DITypeRef::get(VTableHolder), VK, VIndex, Flags, isOptimized, Fn, cast_or_null(TParam), nullptr, nullptr); @@ -721,7 +742,11 @@ DILexicalBlockFile *DIBuilder::createLexicalBlockFile(DIScope *Scope, DIFile *File, unsigned Discriminator) { - return DILexicalBlockFile::get(VMContext, Scope, File, Discriminator); + // Defeat MDNode uniquing for lexical blocks. + // Note that Lexical block file must be unique (just as lexical block) otherwise + // everytime we transition between files, we will use the same lexical + // block file. + return DILexicalBlockFile::getDistinct(VMContext, Scope, File, Discriminator); } DILexicalBlock *DIBuilder::createLexicalBlock(DIScope *Scope, DIFile *File, Index: lib/IR/DebugInfoMetadata.cpp =================================================================== --- lib/IR/DebugInfoMetadata.cpp +++ lib/IR/DebugInfoMetadata.cpp @@ -310,13 +310,38 @@ DEFINE_GETIMPL_STORE_NO_CONSTRUCTOR_ARGS(DIFile, Ops); } +DICodeViewTypes *DICodeViewTypes::getImpl( + LLVMContext &Context, unsigned Signature, Metadata *TypeRecords, + Metadata *UDTSymbols, StorageType Storage, bool ShouldCreate) { + DEFINE_GETIMPL_LOOKUP( + DICodeViewTypes, + (Signature, TypeRecords, UDTSymbols)); + Metadata *Ops[] = { TypeRecords, UDTSymbols }; + DEFINE_GETIMPL_STORE( + DICodeViewTypes, + (Signature), Ops); +} + +DICodeViewUDT *DICodeViewUDT::getImpl( + LLVMContext &Context, MDString *Name, codeview::TypeIndex TI, + StorageType Storage, bool ShouldCreate) { + assert(isCanonical(Name) && "Expected canonical MDString"); + DEFINE_GETIMPL_LOOKUP( + DICodeViewUDT, + (getString(Name), TI)); + Metadata *Ops[] = { Name }; + DEFINE_GETIMPL_STORE( + DICodeViewUDT, + (TI), Ops); +} + DICompileUnit *DICompileUnit::getImpl( LLVMContext &Context, unsigned SourceLanguage, Metadata *File, MDString *Producer, bool IsOptimized, MDString *Flags, unsigned RuntimeVersion, MDString *SplitDebugFilename, unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, Metadata *Subprograms, Metadata *GlobalVariables, - Metadata *ImportedEntities, uint64_t DWOId, + Metadata *ImportedEntities, Metadata *CodeViewTypes, uint64_t DWOId, StorageType Storage, bool ShouldCreate) { assert(isCanonical(Producer) && "Expected canonical MDString"); assert(isCanonical(Flags) && "Expected canonical MDString"); @@ -325,13 +350,15 @@ DICompileUnit, (SourceLanguage, File, getString(Producer), IsOptimized, getString(Flags), RuntimeVersion, getString(SplitDebugFilename), EmissionKind, EnumTypes, - RetainedTypes, Subprograms, GlobalVariables, ImportedEntities, DWOId)); + RetainedTypes, Subprograms, GlobalVariables, ImportedEntities, + CodeViewTypes, DWOId)); Metadata *Ops[] = {File, Producer, Flags, SplitDebugFilename, EnumTypes, RetainedTypes, Subprograms, GlobalVariables, - ImportedEntities}; + ImportedEntities, CodeViewTypes}; DEFINE_GETIMPL_STORE( DICompileUnit, - (SourceLanguage, IsOptimized, RuntimeVersion, EmissionKind, DWOId), Ops); + (SourceLanguage, IsOptimized, RuntimeVersion, EmissionKind, + DWOId), Ops); } DISubprogram *DILocalScope::getSubprogram() const { @@ -343,16 +370,16 @@ DISubprogram *DISubprogram::getImpl( LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, - bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine, - Metadata *ContainingType, unsigned Virtuality, unsigned VirtualIndex, - unsigned Flags, bool IsOptimized, Metadata *Function, - Metadata *TemplateParams, Metadata *Declaration, Metadata *Variables, - StorageType Storage, bool ShouldCreate) { + codeview::TypeIndex TI, bool IsLocalToUnit, bool IsDefinition, + unsigned ScopeLine, Metadata *ContainingType, unsigned Virtuality, + unsigned VirtualIndex, unsigned Flags, bool IsOptimized, + Metadata *Function, Metadata *TemplateParams, Metadata *Declaration, + Metadata *Variables, StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); assert(isCanonical(LinkageName) && "Expected canonical MDString"); DEFINE_GETIMPL_LOOKUP(DISubprogram, (Scope, getString(Name), getString(LinkageName), File, - Line, Type, IsLocalToUnit, IsDefinition, ScopeLine, + Line, Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, Declaration, Variables)); @@ -361,7 +388,7 @@ TemplateParams, Declaration, Variables}; DEFINE_GETIMPL_STORE(DISubprogram, (Line, ScopeLine, Virtuality, VirtualIndex, Flags, - IsLocalToUnit, IsDefinition, IsOptimized), + IsLocalToUnit, IsDefinition, IsOptimized, TI), Ops); } @@ -451,7 +478,8 @@ DIGlobalVariable * DIGlobalVariable::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, - Metadata *Type, bool IsLocalToUnit, bool IsDefinition, + Metadata *Type, codeview::TypeIndex TI, + bool IsLocalToUnit, bool IsDefinition, Metadata *Variable, Metadata *StaticDataMemberDeclaration, StorageType Storage, bool ShouldCreate) { @@ -459,18 +487,19 @@ assert(isCanonical(LinkageName) && "Expected canonical MDString"); DEFINE_GETIMPL_LOOKUP(DIGlobalVariable, (Scope, getString(Name), getString(LinkageName), File, - Line, Type, IsLocalToUnit, IsDefinition, Variable, + Line, Type, TI, IsLocalToUnit, IsDefinition, Variable, StaticDataMemberDeclaration)); Metadata *Ops[] = {Scope, Name, File, Type, Name, LinkageName, Variable, StaticDataMemberDeclaration}; - DEFINE_GETIMPL_STORE(DIGlobalVariable, (Line, IsLocalToUnit, IsDefinition), + DEFINE_GETIMPL_STORE(DIGlobalVariable, (Line, TI, IsLocalToUnit, IsDefinition), Ops); } DILocalVariable *DILocalVariable::getImpl(LLVMContext &Context, unsigned Tag, Metadata *Scope, MDString *Name, Metadata *File, unsigned Line, - Metadata *Type, unsigned Arg, + Metadata *Type, + codeview::TypeIndex TI, unsigned Arg, unsigned Flags, StorageType Storage, bool ShouldCreate) { // 64K ought to be enough for any frontend. @@ -479,9 +508,9 @@ assert(Scope && "Expected scope"); assert(isCanonical(Name) && "Expected canonical MDString"); DEFINE_GETIMPL_LOOKUP(DILocalVariable, (Tag, Scope, getString(Name), File, - Line, Type, Arg, Flags)); + Line, Type, TI, Arg, Flags)); Metadata *Ops[] = {Scope, Name, File, Type}; - DEFINE_GETIMPL_STORE(DILocalVariable, (Tag, Line, Arg, Flags), Ops); + DEFINE_GETIMPL_STORE(DILocalVariable, (Tag, Line, TI, Arg, Flags), Ops); } DIExpression *DIExpression::getImpl(LLVMContext &Context, Index: lib/IR/LLVMBuild.txt =================================================================== --- lib/IR/LLVMBuild.txt +++ lib/IR/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Library name = Core parent = Libraries -required_libraries = Support +required_libraries = CodeView Support Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -472,6 +472,7 @@ Metadata *Subprograms; Metadata *GlobalVariables; Metadata *ImportedEntities; + Metadata *CodeViewTypes; uint64_t DWOId; MDNodeKeyImpl(unsigned SourceLanguage, Metadata *File, StringRef Producer, @@ -479,13 +480,15 @@ StringRef SplitDebugFilename, unsigned EmissionKind, Metadata *EnumTypes, Metadata *RetainedTypes, Metadata *Subprograms, Metadata *GlobalVariables, - Metadata *ImportedEntities, uint64_t DWOId) + Metadata *ImportedEntities, Metadata *CodeViewTypes, + uint64_t DWOId) : SourceLanguage(SourceLanguage), File(File), Producer(Producer), IsOptimized(IsOptimized), Flags(Flags), RuntimeVersion(RuntimeVersion), SplitDebugFilename(SplitDebugFilename), EmissionKind(EmissionKind), EnumTypes(EnumTypes), RetainedTypes(RetainedTypes), Subprograms(Subprograms), GlobalVariables(GlobalVariables), - ImportedEntities(ImportedEntities), DWOId(DWOId) {} + ImportedEntities(ImportedEntities), CodeViewTypes(CodeViewTypes), + DWOId(DWOId) {} MDNodeKeyImpl(const DICompileUnit *N) : SourceLanguage(N->getSourceLanguage()), File(N->getRawFile()), Producer(N->getProducer()), IsOptimized(N->isOptimized()), @@ -495,7 +498,9 @@ RetainedTypes(N->getRawRetainedTypes()), Subprograms(N->getRawSubprograms()), GlobalVariables(N->getRawGlobalVariables()), - ImportedEntities(N->getRawImportedEntities()), DWOId(N->getDWOId()) {} + ImportedEntities(N->getRawImportedEntities()), + CodeViewTypes(N->getRawCodeViewTypes()), + DWOId(N->getDWOId()) {} bool isKeyOf(const DICompileUnit *RHS) const { return SourceLanguage == RHS->getSourceLanguage() && @@ -509,13 +514,58 @@ Subprograms == RHS->getRawSubprograms() && GlobalVariables == RHS->getRawGlobalVariables() && ImportedEntities == RHS->getRawImportedEntities() && + CodeViewTypes == RHS->getRawCodeViewTypes() && DWOId == RHS->getDWOId(); } unsigned getHashValue() const { return hash_combine(SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, GlobalVariables, - ImportedEntities, DWOId); + ImportedEntities, CodeViewTypes, DWOId); + } +}; + +template <> struct MDNodeKeyImpl { + unsigned Signature; + Metadata *TypeRecords; + Metadata *UDTSymbols; + + MDNodeKeyImpl(unsigned Signature, Metadata *TypeRecords, + Metadata *UDTSymbols) + : Signature(Signature), TypeRecords(TypeRecords), UDTSymbols(UDTSymbols) { + } + MDNodeKeyImpl(const DICodeViewTypes *N) + : Signature(N->getSignature()), TypeRecords(N->getRawTypeRecords()), + UDTSymbols(N->getRawUDTSymbols()) { + } + + bool isKeyOf(const DICodeViewTypes *RHS) const { + return Signature == RHS->getSignature() && + TypeRecords == RHS->getRawTypeRecords() && + UDTSymbols == RHS->getRawUDTSymbols(); + } + unsigned getHashValue() const { + return hash_combine(Signature, TypeRecords, UDTSymbols); + } +}; + +template <> struct MDNodeKeyImpl { + StringRef Name; + codeview::TypeIndex TI; + + MDNodeKeyImpl(StringRef Name, codeview::TypeIndex TI) + : Name(Name), TI(TI) { + } + MDNodeKeyImpl(const DICodeViewUDT *N) + : Name(N->getName()), TI(N->getTypeIndex()) { + } + + bool isKeyOf(const DICodeViewUDT *RHS) const { + return Name == RHS->getName() && + TI == RHS->getTypeIndex(); + } + unsigned getHashValue() const { + return hash_combine(Name, TI.getIndex()); } }; @@ -526,6 +576,7 @@ Metadata *File; unsigned Line; Metadata *Type; + codeview::TypeIndex TI; bool IsLocalToUnit; bool IsDefinition; unsigned ScopeLine; @@ -541,13 +592,14 @@ MDNodeKeyImpl(Metadata *Scope, StringRef Name, StringRef LinkageName, Metadata *File, unsigned Line, Metadata *Type, + codeview::TypeIndex TI, bool IsLocalToUnit, bool IsDefinition, unsigned ScopeLine, Metadata *ContainingType, unsigned Virtuality, unsigned VirtualIndex, unsigned Flags, bool IsOptimized, Metadata *Function, Metadata *TemplateParams, Metadata *Declaration, Metadata *Variables) : Scope(Scope), Name(Name), LinkageName(LinkageName), File(File), - Line(Line), Type(Type), IsLocalToUnit(IsLocalToUnit), + Line(Line), Type(Type), TI(TI), IsLocalToUnit(IsLocalToUnit), IsDefinition(IsDefinition), ScopeLine(ScopeLine), ContainingType(ContainingType), Virtuality(Virtuality), VirtualIndex(VirtualIndex), Flags(Flags), IsOptimized(IsOptimized), @@ -556,11 +608,11 @@ MDNodeKeyImpl(const DISubprogram *N) : Scope(N->getRawScope()), Name(N->getName()), LinkageName(N->getLinkageName()), File(N->getRawFile()), - Line(N->getLine()), Type(N->getRawType()), + Line(N->getLine()), Type(N->getRawType()), TI(N->getTypeIndex()), IsLocalToUnit(N->isLocalToUnit()), IsDefinition(N->isDefinition()), ScopeLine(N->getScopeLine()), ContainingType(N->getRawContainingType()), Virtuality(N->getVirtuality()), VirtualIndex(N->getVirtualIndex()), - Flags(N->getFlags()), IsOptimized(N->isOptimized()), + Flags(N->getFlags()), IsOptimized(N->isOptimized()), Function(N->getRawFunction()), TemplateParams(N->getRawTemplateParams()), Declaration(N->getRawDeclaration()), Variables(N->getRawVariables()) {} @@ -569,6 +621,7 @@ return Scope == RHS->getRawScope() && Name == RHS->getName() && LinkageName == RHS->getLinkageName() && File == RHS->getRawFile() && Line == RHS->getLine() && Type == RHS->getRawType() && + TI == RHS->getTypeIndex() && IsLocalToUnit == RHS->isLocalToUnit() && IsDefinition == RHS->isDefinition() && ScopeLine == RHS->getScopeLine() && @@ -582,10 +635,10 @@ Variables == RHS->getRawVariables(); } unsigned getHashValue() const { - return hash_combine(Scope, Name, LinkageName, File, Line, Type, + return hash_combine(Scope, Name, LinkageName, File, Line, Type, TI.getIndex(), IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, - Virtuality, VirtualIndex, Flags, IsOptimized, Function, - TemplateParams, Declaration, Variables); + Virtuality, VirtualIndex, Flags, IsOptimized, + Function, TemplateParams, Declaration, Variables); } }; @@ -720,23 +773,24 @@ Metadata *File; unsigned Line; Metadata *Type; + codeview::TypeIndex TI; bool IsLocalToUnit; bool IsDefinition; Metadata *Variable; Metadata *StaticDataMemberDeclaration; MDNodeKeyImpl(Metadata *Scope, StringRef Name, StringRef LinkageName, - Metadata *File, unsigned Line, Metadata *Type, - bool IsLocalToUnit, bool IsDefinition, Metadata *Variable, - Metadata *StaticDataMemberDeclaration) + Metadata *File, unsigned Line, Metadata *Type, + codeview::TypeIndex TI, bool IsLocalToUnit, bool IsDefinition, + Metadata *Variable, Metadata *StaticDataMemberDeclaration) : Scope(Scope), Name(Name), LinkageName(LinkageName), File(File), - Line(Line), Type(Type), IsLocalToUnit(IsLocalToUnit), + Line(Line), Type(Type), TI(TI), IsLocalToUnit(IsLocalToUnit), IsDefinition(IsDefinition), Variable(Variable), StaticDataMemberDeclaration(StaticDataMemberDeclaration) {} MDNodeKeyImpl(const DIGlobalVariable *N) : Scope(N->getRawScope()), Name(N->getName()), LinkageName(N->getLinkageName()), File(N->getRawFile()), - Line(N->getLine()), Type(N->getRawType()), + Line(N->getLine()), Type(N->getRawType()), TI(N->getTypeIndex()), IsLocalToUnit(N->isLocalToUnit()), IsDefinition(N->isDefinition()), Variable(N->getRawVariable()), StaticDataMemberDeclaration(N->getRawStaticDataMemberDeclaration()) {} @@ -744,7 +798,9 @@ bool isKeyOf(const DIGlobalVariable *RHS) const { return Scope == RHS->getRawScope() && Name == RHS->getName() && LinkageName == RHS->getLinkageName() && File == RHS->getRawFile() && - Line == RHS->getLine() && Type == RHS->getRawType() && + Line == RHS->getLine() && + Type == RHS->getRawType() && + TI == RHS->getTypeIndex() && IsLocalToUnit == RHS->isLocalToUnit() && IsDefinition == RHS->isDefinition() && Variable == RHS->getRawVariable() && @@ -752,8 +808,8 @@ RHS->getRawStaticDataMemberDeclaration(); } unsigned getHashValue() const { - return hash_combine(Scope, Name, LinkageName, File, Line, Type, - IsLocalToUnit, IsDefinition, Variable, + return hash_combine(Scope, Name, LinkageName, File, Line, Type, + TI.getIndex(), IsLocalToUnit, IsDefinition, Variable, StaticDataMemberDeclaration); } }; @@ -765,26 +821,30 @@ Metadata *File; unsigned Line; Metadata *Type; + codeview::TypeIndex TI; unsigned Arg; unsigned Flags; MDNodeKeyImpl(unsigned Tag, Metadata *Scope, StringRef Name, Metadata *File, - unsigned Line, Metadata *Type, unsigned Arg, unsigned Flags) + unsigned Line, Metadata *Type, codeview::TypeIndex TI, + unsigned Arg, unsigned Flags) : Tag(Tag), Scope(Scope), Name(Name), File(File), Line(Line), Type(Type), - Arg(Arg), Flags(Flags) {} + TI(TI), Arg(Arg), Flags(Flags) {} MDNodeKeyImpl(const DILocalVariable *N) : Tag(N->getTag()), Scope(N->getRawScope()), Name(N->getName()), File(N->getRawFile()), Line(N->getLine()), Type(N->getRawType()), - Arg(N->getArg()), Flags(N->getFlags()) {} + TI(N->getTypeIndex()), Arg(N->getArg()), Flags(N->getFlags()) {} bool isKeyOf(const DILocalVariable *RHS) const { return Tag == RHS->getTag() && Scope == RHS->getRawScope() && Name == RHS->getName() && File == RHS->getRawFile() && Line == RHS->getLine() && Type == RHS->getRawType() && + TI == RHS->getTypeIndex() && Arg == RHS->getArg() && Flags == RHS->getFlags(); } unsigned getHashValue() const { - return hash_combine(Tag, Scope, Name, File, Line, Type, Arg, Flags); + return hash_combine(Tag, Scope, Name, File, Line, Type, TI.getIndex(), Arg, + Flags); } }; Index: lib/IR/MDTypeTableBuilder.cpp =================================================================== --- /dev/null +++ lib/IR/MDTypeTableBuilder.cpp @@ -0,0 +1,16 @@ +#include "llvm/IR/MDTypeTableBuilder.h" + +using namespace llvm; +using namespace codeview; + +TypeIndex MDTypeTableBuilder::writeRecord(StringRef Record) +{ + MDString *RecordValue = MDString::get(Context, Record); + TypeIndex TI(TypeIndices.size() + TypeIndex::FirstNonSimpleIndex); + auto Result = TypeIndices.insert(std::make_pair(RecordValue, TI)); + if (Result.second) { + Records.push_back(RecordValue); + } + + return Result.first->second; +} Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -884,6 +884,20 @@ Assert(N.getTag() == dwarf::DW_TAG_file_type, "invalid tag", &N); } +void Verifier::visitDICodeViewTypes(const DICodeViewTypes &N) { + Assert(N.getTag() == dwarf::DW_TAG_hi_user, "invalid tag", &N); + if (auto *TypeRecords = N.getRawTypeRecords()) { + Assert(isa(TypeRecords), "invalid type records", &N, TypeRecords); + for (Metadata *Ty : N.getTypeRecords()->operands()) { + Assert(isa(Ty), "invalid type record type", &N, TypeRecords, Ty); + } + } +} + +void Verifier::visitDICodeViewUDT(const DICodeViewUDT &N) { + Assert(N.getTag() == dwarf::DW_TAG_hi_user, "invalid tag", &N); +} + void Verifier::visitDICompileUnit(const DICompileUnit &N) { Assert(N.getTag() == dwarf::DW_TAG_compile_unit, "invalid tag", &N); Index: lib/LLVMBuild.txt =================================================================== --- lib/LLVMBuild.txt +++ lib/LLVMBuild.txt @@ -21,6 +21,7 @@ AsmParser Bitcode CodeGen + CodeView DebugInfo ExecutionEngine LibDriver Index: unittests/IR/IRBuilderTest.cpp =================================================================== --- unittests/IR/IRBuilderTest.cpp +++ unittests/IR/IRBuilderTest.cpp @@ -313,9 +313,11 @@ auto CU = DIB.createCompileUnit(dwarf::DW_LANG_Cobol74, "F.CBL", "/", "llvm-cobol74", true, "", 0); auto Type = DIB.createSubroutineType(File, DIB.getOrCreateTypeArray(None)); - DIB.createFunction(CU, "foo", "", File, 1, Type, false, true, 1, 0, true, F); + DIB.createFunction(CU, "foo", "", File, 1, Type, codeview::TypeIndex(), false, + true, 1, 0, true, F); AllocaInst *I = Builder.CreateAlloca(Builder.getInt8Ty()); - auto BarSP = DIB.createFunction(CU, "bar", "", File, 1, Type, false, true, 1, + auto BarSP = DIB.createFunction(CU, "bar", "", File, 1, Type, + codeview::TypeIndex(), false, true, 1, 0, true, nullptr); auto BadScope = DIB.createLexicalBlockFile(BarSP, File, 0); I->setDebugLoc(DebugLoc::get(2, 0, BadScope)); @@ -364,7 +366,8 @@ "", true, "", 0); auto SPType = DIB.createSubroutineType(File, DIB.getOrCreateTypeArray(None)); auto SP = - DIB.createFunction(CU, "foo", "foo", File, 1, SPType, false, true, 1); + DIB.createFunction(CU, "foo", "foo", File, 1, SPType, + codeview::TypeIndex(), false, true, 1); DebugLoc DL1 = DILocation::get(Ctx, 2, 0, SP); DebugLoc DL2 = DILocation::get(Ctx, 3, 0, SP); Index: unittests/IR/MetadataTest.cpp =================================================================== --- unittests/IR/MetadataTest.cpp +++ unittests/IR/MetadataTest.cpp @@ -84,13 +84,16 @@ } DISubprogram *getSubprogram() { return DISubprogram::getDistinct(Context, nullptr, "", "", nullptr, 0, - nullptr, false, false, 0, nullptr, 0, 0, 0, - 0); + nullptr, codeview::TypeIndex(), false, + false, 0, nullptr, 0, 0, 0, 0); } DIScopeRef getSubprogramRef() { return getSubprogram()->getRef(); } DIFile *getFile() { return DIFile::getDistinct(Context, "file.c", "/path/to/dir"); } + DICodeViewTypes *getCodeViewTypes() { + return DICodeViewTypes::getDistinct(Context, 4, nullptr, nullptr); + } DITypeRef getBasicType(StringRef Name) { return DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, Name) ->getRef(); @@ -1307,11 +1310,13 @@ MDTuple *Subprograms = getTuple(); MDTuple *GlobalVariables = getTuple(); MDTuple *ImportedEntities = getTuple(); + DICodeViewTypes *CodeViewTypes = getCodeViewTypes(); uint64_t DWOId = 0xc0ffee; auto *N = DICompileUnit::get( Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, - RetainedTypes, Subprograms, GlobalVariables, ImportedEntities, DWOId); + RetainedTypes, Subprograms, GlobalVariables, ImportedEntities, + CodeViewTypes, DWOId); EXPECT_EQ(dwarf::DW_TAG_compile_unit, N->getTag()); EXPECT_EQ(SourceLanguage, N->getSourceLanguage()); @@ -1327,83 +1332,85 @@ EXPECT_EQ(Subprograms, N->getSubprograms().get()); EXPECT_EQ(GlobalVariables, N->getGlobalVariables().get()); EXPECT_EQ(ImportedEntities, N->getImportedEntities().get()); + EXPECT_EQ(CodeViewTypes, N->getCodeViewTypes()); EXPECT_EQ(DWOId, N->getDWOId()); EXPECT_EQ(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, GlobalVariables, - ImportedEntities, DWOId)); + ImportedEntities, CodeViewTypes, DWOId)); EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage + 1, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, GlobalVariables, - ImportedEntities, DWOId)); + ImportedEntities, CodeViewTypes, DWOId)); EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, getFile(), Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, GlobalVariables, - ImportedEntities, DWOId)); + ImportedEntities, CodeViewTypes, DWOId)); EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, "other", IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, GlobalVariables, - ImportedEntities, DWOId)); + ImportedEntities, CodeViewTypes, DWOId)); EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, !IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, GlobalVariables, - ImportedEntities, DWOId)); + ImportedEntities, CodeViewTypes, DWOId)); EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, IsOptimized, "other", RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, GlobalVariables, - ImportedEntities, DWOId)); + ImportedEntities, CodeViewTypes, DWOId)); EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion + 1, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, GlobalVariables, - ImportedEntities, DWOId)); + ImportedEntities, CodeViewTypes, DWOId)); EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, "other", EmissionKind, EnumTypes, RetainedTypes, Subprograms, GlobalVariables, - ImportedEntities, DWOId)); + ImportedEntities, CodeViewTypes, DWOId)); EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind + 1, EnumTypes, RetainedTypes, Subprograms, - GlobalVariables, ImportedEntities, DWOId)); + GlobalVariables, ImportedEntities, + CodeViewTypes, DWOId)); EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, getTuple(), RetainedTypes, Subprograms, GlobalVariables, - ImportedEntities, DWOId)); + ImportedEntities, CodeViewTypes, DWOId)); EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, getTuple(), Subprograms, GlobalVariables, - ImportedEntities, DWOId)); + ImportedEntities, CodeViewTypes, DWOId)); EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, getTuple(), GlobalVariables, - ImportedEntities, DWOId)); + ImportedEntities, CodeViewTypes, DWOId)); EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, getTuple(), - ImportedEntities, DWOId)); + ImportedEntities, CodeViewTypes, DWOId)); EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, GlobalVariables, - getTuple(), DWOId)); + getTuple(), CodeViewTypes, DWOId)); EXPECT_NE(N, DICompileUnit::get(Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, RetainedTypes, Subprograms, GlobalVariables, - ImportedEntities, DWOId + 1)); + ImportedEntities, CodeViewTypes, DWOId + 1)); TempDICompileUnit Temp = N->clone(); EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); @@ -1425,7 +1432,7 @@ auto *N = DICompileUnit::get( Context, SourceLanguage, File, Producer, IsOptimized, Flags, RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, - RetainedTypes, nullptr, nullptr, ImportedEntities, DWOId); + RetainedTypes, nullptr, nullptr, ImportedEntities, nullptr, DWOId); auto *Subprograms = MDTuple::getDistinct(Context, None); EXPECT_EQ(nullptr, N->getSubprograms().get()); @@ -1451,6 +1458,7 @@ DIFile *File = getFile(); unsigned Line = 2; DISubroutineType *Type = getSubroutineType(); + codeview::TypeIndex TI = codeview::TypeIndex(codeview::SimpleTypeKind::Int32); bool IsLocalToUnit = false; bool IsDefinition = true; unsigned ScopeLine = 3; @@ -1465,7 +1473,8 @@ MDTuple *Variables = getTuple(); auto *N = DISubprogram::get( - Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, + Context, Scope, Name, LinkageName, File, Line, Type, TI, + IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, Declaration, Variables); @@ -1489,98 +1498,98 @@ EXPECT_EQ(Declaration, N->getDeclaration()); EXPECT_EQ(Variables, N->getVariables().get()); EXPECT_EQ(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, ScopeLine, + Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, getCompositeType(), Name, LinkageName, - File, Line, Type, IsLocalToUnit, IsDefinition, + File, Line, Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, "other", LinkageName, File, - Line, Type, IsLocalToUnit, IsDefinition, + Line, Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, "other", File, Line, - Type, IsLocalToUnit, IsDefinition, ScopeLine, + Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, getFile(), - Line, Type, IsLocalToUnit, IsDefinition, + Line, Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, - Line + 1, Type, IsLocalToUnit, IsDefinition, + Line + 1, Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get( Context, Scope, Name, LinkageName, File, Line, - getSubroutineType(), IsLocalToUnit, IsDefinition, ScopeLine, + getSubroutineType(), TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, !IsLocalToUnit, IsDefinition, ScopeLine, + Type, TI, !IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, !IsDefinition, ScopeLine, + Type, TI, IsLocalToUnit, !IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, + Type, TI, IsLocalToUnit, IsDefinition, ScopeLine + 1, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, ScopeLine, + Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, getCompositeType(), Virtuality, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, ScopeLine, + Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality + 1, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, ScopeLine, + Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex + 1, Flags, IsOptimized, Function, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, ScopeLine, + Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, ~Flags, IsOptimized, Function, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, ScopeLine, + Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, !IsOptimized, Function, TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, ScopeLine, + Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, getFunction("bar"), TemplateParams, Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, ScopeLine, + Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function, getTuple(), Declaration, Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, ScopeLine, + Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, getSubprogram(), Variables)); EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, ScopeLine, + Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, Function, TemplateParams, Declaration, getTuple())); @@ -1596,6 +1605,7 @@ DIFile *File = getFile(); unsigned Line = 2; DISubroutineType *Type = getSubroutineType(); + codeview::TypeIndex TI(codeview::SimpleTypeKind::Int64); bool IsLocalToUnit = false; bool IsDefinition = true; unsigned ScopeLine = 3; @@ -1609,7 +1619,7 @@ MDTuple *Variables = getTuple(); auto *N = DISubprogram::get( - Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, + Context, Scope, Name, LinkageName, File, Line, Type, TI, IsLocalToUnit, IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, IsOptimized, nullptr, TemplateParams, Declaration, Variables); @@ -1797,6 +1807,7 @@ DIFile *File = getFile(); unsigned Line = 5; DITypeRef Type = getDerivedType(); + codeview::TypeIndex TI(codeview::SimpleTypeKind::Float32); bool IsLocalToUnit = false; bool IsDefinition = true; Constant *Variable = getConstant(); @@ -1804,7 +1815,7 @@ cast(getDerivedType()); auto *N = DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, Variable, + Type, TI, IsLocalToUnit, IsDefinition, Variable, StaticDataMemberDeclaration); EXPECT_EQ(dwarf::DW_TAG_variable, N->getTag()); EXPECT_EQ(Scope, N->getScope()); @@ -1818,44 +1829,44 @@ EXPECT_EQ(Variable, N->getVariable()); EXPECT_EQ(StaticDataMemberDeclaration, N->getStaticDataMemberDeclaration()); EXPECT_EQ(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, - Line, Type, IsLocalToUnit, IsDefinition, + Line, Type, TI, IsLocalToUnit, IsDefinition, Variable, StaticDataMemberDeclaration)); EXPECT_NE(N, DIGlobalVariable::get(Context, getSubprogram(), Name, LinkageName, - File, Line, Type, IsLocalToUnit, IsDefinition, + File, Line, Type, TI, IsLocalToUnit, IsDefinition, Variable, StaticDataMemberDeclaration)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, "other", LinkageName, File, - Line, Type, IsLocalToUnit, IsDefinition, + Line, Type, TI, IsLocalToUnit, IsDefinition, Variable, StaticDataMemberDeclaration)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, "other", File, Line, - Type, IsLocalToUnit, IsDefinition, + Type, TI, IsLocalToUnit, IsDefinition, Variable, StaticDataMemberDeclaration)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, getFile(), - Line, Type, IsLocalToUnit, IsDefinition, + Line, Type, TI, IsLocalToUnit, IsDefinition, Variable, StaticDataMemberDeclaration)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, - Line + 1, Type, IsLocalToUnit, IsDefinition, + Line + 1, Type, TI, IsLocalToUnit, IsDefinition, Variable, StaticDataMemberDeclaration)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, - getDerivedType(), IsLocalToUnit, IsDefinition, + getDerivedType(), TI, IsLocalToUnit, IsDefinition, Variable, StaticDataMemberDeclaration)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, - Line, Type, !IsLocalToUnit, IsDefinition, + Line, Type, TI, !IsLocalToUnit, IsDefinition, Variable, StaticDataMemberDeclaration)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, - Line, Type, IsLocalToUnit, !IsDefinition, + Line, Type, TI, IsLocalToUnit, !IsDefinition, Variable, StaticDataMemberDeclaration)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, + Type, TI, IsLocalToUnit, IsDefinition, getConstant(), StaticDataMemberDeclaration)); EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, - Type, IsLocalToUnit, IsDefinition, Variable, + Type, TI, IsLocalToUnit, IsDefinition, Variable, cast(getDerivedType()))); TempDIGlobalVariable Temp = N->clone(); @@ -1871,10 +1882,11 @@ DIFile *File = getFile(); unsigned Line = 5; DITypeRef Type = getDerivedType(); + codeview::TypeIndex TI(codeview::SimpleTypeKind::Float64); unsigned Arg = 6; unsigned Flags = 7; - auto *N = DILocalVariable::get(Context, Tag, Scope, Name, File, Line, Type, + auto *N = DILocalVariable::get(Context, Tag, Scope, Name, File, Line, Type, TI, Arg, Flags); EXPECT_EQ(Tag, N->getTag()); EXPECT_EQ(Scope, N->getScope()); @@ -1884,24 +1896,24 @@ EXPECT_EQ(Type, N->getType()); EXPECT_EQ(Arg, N->getArg()); EXPECT_EQ(Flags, N->getFlags()); - EXPECT_EQ(N, DILocalVariable::get(Context, Tag, Scope, Name, File, Line, Type, + EXPECT_EQ(N, DILocalVariable::get(Context, Tag, Scope, Name, File, Line, Type, TI, Arg, Flags)); EXPECT_NE(N, DILocalVariable::get(Context, dwarf::DW_TAG_auto_variable, Scope, - Name, File, Line, Type, Arg, Flags)); + Name, File, Line, Type, TI, Arg, Flags)); EXPECT_NE(N, DILocalVariable::get(Context, Tag, getSubprogram(), Name, File, - Line, Type, Arg, Flags)); + Line, Type, TI, Arg, Flags)); EXPECT_NE(N, DILocalVariable::get(Context, Tag, Scope, "other", File, Line, - Type, Arg, Flags)); + Type, TI, Arg, Flags)); EXPECT_NE(N, DILocalVariable::get(Context, Tag, Scope, Name, getFile(), Line, - Type, Arg, Flags)); + Type, TI, Arg, Flags)); EXPECT_NE(N, DILocalVariable::get(Context, Tag, Scope, Name, File, Line + 1, - Type, Arg, Flags)); + Type, TI, Arg, Flags)); EXPECT_NE(N, DILocalVariable::get(Context, Tag, Scope, Name, File, Line, - getDerivedType(), Arg, Flags)); - EXPECT_NE(N, DILocalVariable::get(Context, Tag, Scope, Name, File, Line, Type, + getDerivedType(), TI, Arg, Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Tag, Scope, Name, File, Line, Type, TI, Arg + 1, Flags)); - EXPECT_NE(N, DILocalVariable::get(Context, Tag, Scope, Name, File, Line, Type, + EXPECT_NE(N, DILocalVariable::get(Context, Tag, Scope, Name, File, Line, Type, TI, Arg, ~Flags)); TempDILocalVariable Temp = N->clone(); @@ -1911,20 +1923,20 @@ TEST_F(DILocalVariableTest, getArg256) { EXPECT_EQ(255u, DILocalVariable::get(Context, dwarf::DW_TAG_arg_variable, getSubprogram(), "", getFile(), 0, - nullptr, 255, 0) + nullptr, codeview::TypeIndex(), 255, 0) ->getArg()); EXPECT_EQ(256u, DILocalVariable::get(Context, dwarf::DW_TAG_arg_variable, getSubprogram(), "", getFile(), 0, - nullptr, 256, 0) + nullptr, codeview::TypeIndex(), 256, 0) ->getArg()); EXPECT_EQ(257u, DILocalVariable::get(Context, dwarf::DW_TAG_arg_variable, getSubprogram(), "", getFile(), 0, - nullptr, 257, 0) + nullptr, codeview::TypeIndex(), 257, 0) ->getArg()); unsigned Max = UINT16_MAX; EXPECT_EQ(Max, DILocalVariable::get(Context, dwarf::DW_TAG_arg_variable, getSubprogram(), "", getFile(), 0, - nullptr, Max, 0) + nullptr, codeview::TypeIndex(), Max, 0) ->getArg()); } Index: unittests/Transforms/Utils/Cloning.cpp =================================================================== --- unittests/Transforms/Utils/Cloning.cpp +++ unittests/Transforms/Utils/Cloning.cpp @@ -232,12 +232,13 @@ DITypeRefArray ParamTypes = DBuilder.getOrCreateTypeArray(None); DISubroutineType *FuncType = DBuilder.createSubroutineType(File, ParamTypes); + codeview::TypeIndex TI(codeview::SimpleTypeKind::Int32); auto *CU = DBuilder.createCompileUnit(dwarf::DW_LANG_C99, "filename.c", "/file/dir", "CloneFunc", false, "", 0); auto *Subprogram = DBuilder.createFunction( - CU, "f", "f", File, 4, FuncType, true, true, 3, 0, false, OldFunc); + CU, "f", "f", File, 4, FuncType, TI, true, true, 3, 0, false, OldFunc); // Function body BasicBlock* Entry = BasicBlock::Create(C, "", OldFunc); @@ -256,7 +257,7 @@ DBuilder.createBasicType("int", 32, 0, dwarf::DW_ATE_signed); auto *E = DBuilder.createExpression(); auto *Variable = DBuilder.createLocalVariable( - dwarf::DW_TAG_auto_variable, Subprogram, "x", File, 5, IntType, true); + dwarf::DW_TAG_auto_variable, Subprogram, "x", File, 5, IntType, codeview::TypeIndex(), true); auto *DL = DILocation::get(Subprogram->getContext(), 5, 0, Subprogram); DBuilder.insertDeclare(Alloca, Variable, E, DL, Store); DBuilder.insertDbgValueIntrinsic(AllocaContent, 0, Variable, E, DL,