Index: lib/CodeGen/AsmPrinter/CodeViewDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -185,6 +185,16 @@ void emitLocalVariable(const LocalVariable &Var); + /// Translates the DIType to codeview if necessary and returns a type index + /// for it. + codeview::TypeIndex getTypeIndex(DITypeRef Ty); + + codeview::TypeIndex lowerType(const DIType *Ty); + codeview::TypeIndex lowerTypeBasic(const DIBasicType *Ty); + codeview::TypeIndex lowerTypePointer(const DIDerivedType *Ty); + codeview::TypeIndex lowerTypeMemberPointer(const DIDerivedType *Ty); + codeview::TypeIndex lowerTypeModifier(const DIDerivedType *Ty); + public: CodeViewDebug(AsmPrinter *Asm); Index: lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -230,8 +230,6 @@ if (FnDebugInfo.empty()) return; - emitTypeInformation(); - assert(Asm != nullptr); // The COFF .debug$S section consists of several subsections, each starting @@ -258,6 +256,10 @@ OS.AddComment("String table"); OS.EmitCVStringTableDirective(); + // Emit type information last, so that any types we translate while emitting + // function info are included. + emitTypeInformation(); + clear(); } @@ -726,6 +728,201 @@ } } +TypeIndex CodeViewDebug::lowerType(const DIType *Ty) { + // Generic dispatch for lowering an unknown type. + switch (Ty->getTag()) { + case dwarf::DW_TAG_base_type: + return lowerTypeBasic(cast(Ty)); + case dwarf::DW_TAG_pointer_type: + case dwarf::DW_TAG_reference_type: + case dwarf::DW_TAG_rvalue_reference_type: + return lowerTypePointer(cast(Ty)); + case dwarf::DW_TAG_ptr_to_member_type: + return lowerTypeMemberPointer(cast(Ty)); + case dwarf::DW_TAG_const_type: + case dwarf::DW_TAG_volatile_type: + return lowerTypeModifier(cast(Ty)); + default: + // Use the null type index. + return TypeIndex(); + } +} + +TypeIndex CodeViewDebug::lowerTypeBasic(const DIBasicType *Ty) { + TypeIndex Index; + dwarf::TypeKind Kind; + uint32_t ByteSize; + + Kind = static_cast(Ty->getEncoding()); + ByteSize = Ty->getSizeInBits() >> 3; + + SimpleTypeKind STK = SimpleTypeKind::None; + switch (Kind) { + case dwarf::DW_ATE_address: + // FIXME: Translate + break; + case dwarf::DW_ATE_boolean: + switch (ByteSize) { + case 1: STK = SimpleTypeKind::Boolean8; break; + case 2: STK = SimpleTypeKind::Boolean16; break; + case 4: STK = SimpleTypeKind::Boolean32; break; + case 8: STK = SimpleTypeKind::Boolean64; break; + } + break; + case dwarf::DW_ATE_complex_float: + switch (ByteSize) { + case 4: STK = SimpleTypeKind::Complex32; break; + case 8: STK = SimpleTypeKind::Complex64; break; + case 10: STK = SimpleTypeKind::Complex80; break; + case 16: STK = SimpleTypeKind::Complex128; break; + } + break; + case dwarf::DW_ATE_decimal_float: + case dwarf::DW_ATE_float: + switch (ByteSize) { + case 4: STK = SimpleTypeKind::Float32; break; + case 6: STK = SimpleTypeKind::Float48; break; + case 8: STK = SimpleTypeKind::Float64; break; + case 10: STK = SimpleTypeKind::Float80; break; + case 16: STK = SimpleTypeKind::Float128; break; + } + break; + case dwarf::DW_ATE_signed: + switch (ByteSize) { + case 1: STK = SimpleTypeKind::SignedCharacter; break; + case 2: STK = SimpleTypeKind::Int16Short; break; + case 4: STK = SimpleTypeKind::Int32; break; + case 8: STK = SimpleTypeKind::Int64; break; + } + break; + case dwarf::DW_ATE_unsigned: + switch (ByteSize) { + case 1: STK = SimpleTypeKind::UnsignedCharacter; break; + case 2: STK = SimpleTypeKind::UInt16; break; + case 4: STK = SimpleTypeKind::UInt32; break; + case 8: STK = SimpleTypeKind::UInt64; break; + } + break; + case dwarf::DW_ATE_signed_char: + if (ByteSize == 1) + STK = SimpleTypeKind::SignedCharacter; + break; + case dwarf::DW_ATE_unsigned_char: + if (ByteSize == 1) + STK = SimpleTypeKind::UnsignedCharacter; + break; + default: + break; + } + + // Look at the DIType name to figure out which types were really "long" at the + // source level. + if (STK == SimpleTypeKind::Int32 && Ty->getName() == "long") + STK = SimpleTypeKind::Int32Long; + if (STK == SimpleTypeKind::UInt32 && Ty->getName() == "unsigned long") + STK = SimpleTypeKind::UInt32Long; + + return TypeIndex(STK); +} + +TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty) { + TypeIndex PointeeTI = getTypeIndex(Ty->getBaseType()); + + // Pointers to simple types can use SimpleTypeMode, rather than having a + // dedicated pointer type record. + if (PointeeTI.isSimple() && + PointeeTI.getSimpleMode() == SimpleTypeMode::Direct && + Ty->getTag() == dwarf::DW_TAG_pointer_type) { + SimpleTypeMode Mode = Ty->getSizeInBits() == 64 + ? SimpleTypeMode::NearPointer64 + : SimpleTypeMode::NearPointer32; + return TypeIndex(PointeeTI.getSimpleKind(), Mode); + } + + PointerKind PK = + Ty->getSizeInBits() == 64 ? PointerKind::Near64 : PointerKind::Near32; + PointerMode PM = PointerMode::Pointer; + switch (Ty->getTag()) { + default: llvm_unreachable("not a pointer tag type"); + case dwarf::DW_TAG_pointer_type: + PM = PointerMode::Pointer; + break; + case dwarf::DW_TAG_reference_type: + PM = PointerMode::LValueReference; + break; + case dwarf::DW_TAG_rvalue_reference_type: + PM = PointerMode::RValueReference; + break; + } + // FIXME: MSVC folds qualifiers into PointerOptions in the context of a method + // 'this' pointer, but not normal contexts. Figure out what we're supposed to + // do. + PointerOptions PO = PointerOptions::None; + PointerRecord PR(PointeeTI, PK, PM, PO, Ty->getSizeInBits() / 8); + return TypeTable.writePointer(PR); +} + +TypeIndex CodeViewDebug::lowerTypeMemberPointer(const DIDerivedType *Ty) { + assert(Ty->getTag() == dwarf::DW_TAG_ptr_to_member_type); + TypeIndex ClassTI = getTypeIndex(Ty->getClassType()); + TypeIndex PointeeTI = getTypeIndex(Ty->getBaseType()); + PointerKind PK = Asm->MAI->getPointerSize() == 8 ? PointerKind::Near64 + : PointerKind::Near32; + PointerMode PM = isa(Ty->getBaseType()) + ? PointerMode::PointerToMemberFunction + : PointerMode::PointerToDataMember; + PointerOptions PO = PointerOptions::None; // FIXME + // FIXME: Thread this ABI info through metadata. + PointerToMemberRepresentation PMR = PointerToMemberRepresentation::Unknown; + MemberPointerInfo MPI(ClassTI, PMR); + PointerRecord PR(PointeeTI, PK, PM, PO, Ty->getSizeInBits() / 8, MPI); + return TypeTable.writePointer(PR); +} + +TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) { + ModifierOptions Mods = ModifierOptions::None; + bool IsModifier = true; + const DIType *BaseTy = Ty; + while (IsModifier) { + assert(BaseTy); + switch (BaseTy->getTag()) { + case dwarf::DW_TAG_const_type: + Mods |= ModifierOptions::Const; + break; + case dwarf::DW_TAG_volatile_type: + Mods |= ModifierOptions::Volatile; + break; + default: + IsModifier = false; + break; + } + if (IsModifier) + BaseTy = cast(BaseTy)->getBaseType().resolve(); + } + TypeIndex ModifiedTI = getTypeIndex(BaseTy); + ModifierRecord MR(ModifiedTI, Mods); + return TypeTable.writeModifier(MR); +} + +TypeIndex CodeViewDebug::getTypeIndex(DITypeRef TypeRef) { + const DIType *Ty = TypeRef.resolve(); + + // The null DIType is the void type. Don't try to hash it. + if (!Ty) + return TypeIndex::Void(); + + // Check if we've already translated this type. + auto I = TypeIndices.find(Ty); + if (I != TypeIndices.end()) + return I->second; + + TypeIndex TI = lowerType(Ty); + + auto InsertResult = TypeIndices.insert({Ty, TI}); + assert(InsertResult.second && "DIType lowered twice"); + return TI; +} + void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) { // LocalSym record, see SymbolRecord.h for more info. MCSymbol *LocalBegin = MMI->getContext().createTempSymbol(), @@ -744,7 +941,8 @@ Flags |= LocalSymFlags::IsOptimizedOut; OS.AddComment("TypeIndex"); - OS.EmitIntValue(TypeIndex::Int32().getIndex(), 4); + TypeIndex TI = getTypeIndex(Var.DIVar->getType()); + OS.EmitIntValue(TI.getIndex(), 4); OS.AddComment("Flags"); OS.EmitIntValue(static_cast(Flags), 2); // Truncate the name so we won't overflow the record length field. Index: test/DebugInfo/COFF/inlining.ll =================================================================== --- test/DebugInfo/COFF/inlining.ll +++ test/DebugInfo/COFF/inlining.ll @@ -39,6 +39,36 @@ ; ASM: addl $7, "?x@@3HC" ; ASM: .cv_loc 0 1 17 1 # t.cpp:17:1 +; ASM: .section .debug$S,"dr" +; ASM: .long 246 # Inlinee lines subsection +; ASM: .long [[inline_end:.*]]-[[inline_beg:.*]] # +; ASM: [[inline_beg]]: +; ASM: .long 0 +; ASM: # Inlined function bar starts at t.cpp:8 +; ASM: .long 4098 # Type index of inlined function +; ASM: .long 0 # Offset into filechecksum table +; ASM: .long 8 # Starting line number +; ASM: # Inlined function foo starts at t.cpp:2 +; ASM: .long 4099 +; ASM: .long 0 +; ASM: .long 2 +; ASM: [[inline_end]]: + +; ASM: .long 241 # Symbol subsection for baz +; ASM: .long {{.*}} # Subsection size +; ASM: .short 4429 +; ASM: .long +; ASM: .long +; ASM: .long +; ASM: .cv_inline_linetable 1 1 8 Lfunc_begin0 Lfunc_end0 contains 2 +; ASM: .short 4429 +; ASM: .long +; ASM: .long +; ASM: .long +; ASM: .cv_inline_linetable 2 1 2 Lfunc_begin0 Lfunc_end0 +; ASM: .short 4430 +; ASM: .short 4430 + ; ASM: .section .debug$T,"dr" ; ASM: .long 4 # Debug section magic ; ASM: # ArgList (0x1000) { @@ -83,39 +113,9 @@ ; ASM: .byte 0x01, 0x10, 0x00, 0x00 ; ASM: .byte 0x66, 0x6f, 0x6f, 0x00 -; ASM: .section .debug$S,"dr" -; ASM: .long 246 # Inlinee lines subsection -; ASM: .long [[inline_end:.*]]-[[inline_beg:.*]] # -; ASM: [[inline_beg]]: -; ASM: .long 0 -; ASM: # Inlined function bar starts at t.cpp:8 -; ASM: .long 4098 # Type index of inlined function -; ASM: .long 0 # Offset into filechecksum table -; ASM: .long 8 # Starting line number -; ASM: # Inlined function foo starts at t.cpp:2 -; ASM: .long 4099 -; ASM: .long 0 -; ASM: .long 2 -; ASM: [[inline_end]]: - -; ASM: .long 241 # Symbol subsection for baz -; ASM: .long {{.*}} # Subsection size -; ASM: .short 4429 -; ASM: .long -; ASM: .long -; ASM: .long -; ASM: .cv_inline_linetable 1 1 8 Lfunc_begin0 Lfunc_end0 contains 2 -; ASM: .short 4429 -; ASM: .long -; ASM: .long -; ASM: .long -; ASM: .cv_inline_linetable 2 1 2 Lfunc_begin0 Lfunc_end0 -; ASM: .short 4430 -; ASM: .short 4430 - ; We should only the LF_FUNC_ID records that we needed to reference. ; OBJ: CodeViewTypes [ -; OBJ: Section: .debug$T (4) +; OBJ: Section: .debug$T ; OBJ: ArgList (0x1000) { ; OBJ: TypeLeafKind: LF_ARGLIST (0x1201) ; OBJ: NumArgs: 0