Index: lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -1343,16 +1343,21 @@ Info.Members.push_back({DDTy, 0}); return; } - // An unnamed member must represent a nested struct or union. Add all the + // If an unnamed member represents a nested struct or union, add all the // indirect fields to the current record. - assert((DDTy->getOffsetInBits() % 8) == 0 && "Unnamed bitfield member!"); - unsigned Offset = DDTy->getOffsetInBits() / 8; const DIType *Ty = DDTy->getBaseType().resolve(); - const DICompositeType *DCTy = cast(Ty); - ClassInfo NestedInfo = collectClassInfo(DCTy); - for (const ClassInfo::MemberInfo &IndirectField : NestedInfo.Members) - Info.Members.push_back( - {IndirectField.MemberTypeNode, IndirectField.BaseOffset + Offset}); + if (isa(Ty)) { + unsigned Offset = DDTy->getOffsetInBits() / 8; + const DICompositeType *DCTy = cast(Ty); + ClassInfo NestedInfo = collectClassInfo(DCTy); + for (const ClassInfo::MemberInfo &IndirectField : NestedInfo.Members) + Info.Members.push_back( + {IndirectField.MemberTypeNode, IndirectField.BaseOffset + Offset}); + } + + // At this point an unnamed member must be a bitfield member, add it to + // Members list for later handling. + Info.Members.push_back({ DDTy, 0 }); } ClassInfo CodeViewDebug::collectClassInfo(const DICompositeType *Ty) { @@ -1465,6 +1470,35 @@ return UnionTI; } +/// If this type is derived from a base type then return base type size. +static uint64_t getBaseTypeSize(const DIDerivedType *Ty) { + unsigned Tag = Ty->getTag(); + + if (Tag != dwarf::DW_TAG_member && Tag != dwarf::DW_TAG_typedef && + Tag != dwarf::DW_TAG_const_type && Tag != dwarf::DW_TAG_volatile_type && + Tag != dwarf::DW_TAG_restrict_type) + return Ty->getSizeInBits(); + + DIType *BaseType = Ty->getBaseType().resolve(); + + // If this type is not derived from any type or the type is a declaration then + // take conservative approach. + if (!BaseType || BaseType->isForwardDecl()) + return Ty->getSizeInBits(); + + // If this is a derived type, go ahead and get the base type, unless it's a + // reference then it's just the size of the field. Pointer types have no need + // of this since they're a different type of qualification on the type. + if (BaseType->getTag() == dwarf::DW_TAG_reference_type || + BaseType->getTag() == dwarf::DW_TAG_rvalue_reference_type) + return Ty->getSizeInBits(); + + if (DIDerivedType *DT = dyn_cast(BaseType)) + return getBaseTypeSize(DT); + + return BaseType->getSizeInBits(); +} + std::tuple CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) { // Manually count members. MSVC appears to count everything that generates a @@ -1497,6 +1531,9 @@ } // Create members. + uint64_t PrevAlignment = 0; + uint64_t PrevFieldSize = 0; + uint64_t BaseOffset = 0; for (ClassInfo::MemberInfo &MemberInfo : Info.Members) { const DIDerivedType *Member = MemberInfo.MemberTypeNode; TypeIndex MemberBaseType = getTypeIndex(Member->getBaseType()); @@ -1509,10 +1546,47 @@ continue; } + // Do not emit unnamed members. + // We need them only to calculate the offsets of other members. + bool ToEmitMember = !Member->getName().empty(); + + uint64_t Alignment = Member->getAlignInBits(); + uint64_t Offset = Member->getOffsetInBits(); + uint64_t Size = Member->getSizeInBits(); + uint64_t FieldSize = getBaseTypeSize(Member); uint64_t OffsetInBytes = MemberInfo.BaseOffset; - // FIXME: Handle bitfield type memeber. - OffsetInBytes += Member->getOffsetInBits() / 8; + + if (Size != FieldSize) { + // If alignment was changed, increase BaseOffset with PrevFieldSize. + if (PrevAlignment != Alignment) + BaseOffset += PrevFieldSize; + + Offset -= BaseOffset; + + // If Offset equals or exceeds Alignment, adjust BaseOffset and Offset. + if (Offset >= Alignment) { + uint64_t RealOffset = Offset % Alignment; + BaseOffset += (Offset - RealOffset); + Offset = RealOffset; + } + + if (ToEmitMember) + MemberBaseType = TypeTable.writeBitField( + BitFieldRecord(MemberBaseType, (uint8_t)Size, (uint8_t)Offset)); + OffsetInBytes += BaseOffset / 8; + } else { + // This is not a bitfield. + OffsetInBytes += Offset / 8; + BaseOffset += PrevFieldSize; + } + + // Update previous field size and alignment. + PrevAlignment = Alignment; + PrevFieldSize = FieldSize; + + if (!ToEmitMember) + continue; Fields.writeDataMember( DataMemberRecord(translateAccessFlags(Ty->getTag(), Member->getFlags()), Index: test/DebugInfo/COFF/types-bitfield.ll =================================================================== --- test/DebugInfo/COFF/types-bitfield.ll +++ test/DebugInfo/COFF/types-bitfield.ll @@ -0,0 +1,285 @@ +; RUN: llc < %s -filetype=obj | llvm-readobj - -codeview | FileCheck %s + +; C++ source to regenerate: +; $ cat t.cpp +; #pragma pack(1) +; struct S1 { +; char x1[2]; +; char x2; +; int y : 23; +; int z : 23; +; int w : 2; +; struct { char c; short s; } v; +; short u : 3; +; } s1; +; +; #pragma pack(1) +; struct S2 { +; char : 0; +; int y : 1; +; } s2; +; +; #pragma pack(1) +; struct S3 { +; char : 8; +; short : 8; +; short x : 8; +; } s3; +; $ clang t.cpp -S -emit-llvm -g -gcodeview -o t.ll + +; CHECK: CodeViewTypes [ +; CHECK: Section: .debug$T (5) +; CHECK: Magic: 0x4 +; CHECK: Struct (0x1000) { +; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505) +; CHECK: MemberCount: 0 +; CHECK: Properties [ (0x280) +; CHECK: ForwardReference (0x80) +; CHECK: HasUniqueName (0x200) +; CHECK: ] +; CHECK: FieldList: 0x0 +; CHECK: DerivedFrom: 0x0 +; CHECK: VShape: 0x0 +; CHECK: SizeOf: 0 +; CHECK: Name: S +; CHECK: LinkageName: .?AUS1@@ +; CHECK: } +; CHECK: Array (0x1001) { +; CHECK: TypeLeafKind: LF_ARRAY (0x1503) +; CHECK: ElementType: char (0x70) +; CHECK: IndexType: unsigned long (0x22) +; CHECK: SizeOf: 2 +; CHECK: Name: +; CHECK: } +; CHECK: BitField (0x1002) { +; CHECK: TypeLeafKind: LF_BITFIELD (0x1205) +; CHECK: Type: int (0x74) +; CHECK: BitSize: 23 +; CHECK: BitOffset: 0 +; CHECK: } +; CHECK: BitField (0x1003) { +; CHECK: TypeLeafKind: LF_BITFIELD (0x1205) +; CHECK: Type: int (0x74) +; CHECK: BitSize: 2 +; CHECK: BitOffset: 23 +; CHECK: } +; CHECK: Struct (0x1004) { +; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505) +; CHECK: MemberCount: 0 +; CHECK: Properties [ (0x280) +; CHECK: ForwardReference (0x80) +; CHECK: HasUniqueName (0x200) +; CHECK: ] +; CHECK: FieldList: 0x0 +; CHECK: DerivedFrom: 0x0 +; CHECK: VShape: 0x0 +; CHECK: SizeOf: 0 +; CHECK: Name: +; CHECK: LinkageName: .?AU@S1@@ +; CHECK: } +; CHECK: BitField (0x1005) { +; CHECK: TypeLeafKind: LF_BITFIELD (0x1205) +; CHECK: Type: short (0x11) +; CHECK: BitSize: 3 +; CHECK: BitOffset: 0 +; CHECK: } +; CHECK: FieldList (0x1006) { +; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203) +; CHECK: DataMember { +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: 0x1001 +; CHECK: FieldOffset: 0x0 +; CHECK: Name: x1 +; CHECK: } +; CHECK: DataMember { +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: char (0x70) +; CHECK: FieldOffset: 0x2 +; CHECK: Name: x2 +; CHECK: } +; CHECK: DataMember { +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: 0x1002 +; CHECK: FieldOffset: 0x3 +; CHECK: Name: y +; CHECK: } +; CHECK: DataMember { +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: 0x1002 +; CHECK: FieldOffset: 0x7 +; CHECK: Name: z +; CHECK: } +; CHECK: DataMember { +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: 0x1003 +; CHECK: FieldOffset: 0x7 +; CHECK: Name: w +; CHECK: } +; CHECK: DataMember { +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: S1:: (0x1004) +; CHECK: FieldOffset: 0xB +; CHECK: Name: v +; CHECK: } +; CHECK: DataMember { +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: 0x1005 +; CHECK: FieldOffset: 0xE +; CHECK: Name: u +; CHECK: } +; CHECK: } +; CHECK: Struct (0x1007) { +; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505) +; CHECK: MemberCount: 7 +; CHECK: Properties [ (0x200) +; CHECK: HasUniqueName (0x200) +; CHECK: ] +; CHECK: FieldList: (0x1006) +; CHECK: DerivedFrom: 0x0 +; CHECK: VShape: 0x0 +; CHECK: SizeOf: 16 +; CHECK: Name: S +; CHECK: LinkageName: .?AUS1@@ +; CHECK: } +; +; CHECK: FieldList (0x100A) { +; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203) +; CHECK: DataMember { +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: char (0x70) +; CHECK: FieldOffset: 0x0 +; CHECK: Name: c +; CHECK: } +; CHECK: DataMember { +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: short (0x11) +; CHECK: FieldOffset: 0x1 +; CHECK: Name: s +; CHECK: } +; CHECK: } +; CHECK: Struct (0x100B) { +; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505) +; CHECK: MemberCount: 2 +; CHECK: Properties [ (0x200) +; CHECK: HasUniqueName (0x200) +; CHECK: ] +; CHECK: FieldList: (0x100A) +; CHECK: DerivedFrom: 0x0 +; CHECK: VShape: 0x0 +; CHECK: SizeOf: 3 +; CHECK: Name: S1:: +; CHECK: LinkageName: .?AU@S1@@ +; CHECK: } +; +; CHECK: BitField (0x100E) { +; CHECK: TypeLeafKind: LF_BITFIELD (0x1205) +; CHECK: Type: int (0x74) +; CHECK: BitSize: 1 +; CHECK: BitOffset: 0 +; CHECK: } +; CHECK: FieldList (0x100F) { +; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203) +; CHECK: DataMember { +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: 0x100E +; CHECK: FieldOffset: 0x0 +; CHECK: Name: y +; CHECK: } +; CHECK: } +; CHECK: Struct (0x1010) { +; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505) +; CHECK: MemberCount: 1 +; CHECK: Properties [ (0x200) +; CHECK: HasUniqueName (0x200) +; CHECK: ] +; CHECK: FieldList: (0x100F) +; CHECK: DerivedFrom: 0x0 +; CHECK: VShape: 0x0 +; CHECK: SizeOf: 4 +; CHECK: Name: S2 +; CHECK: LinkageName: .?AUS2@@ +; CHECK: } +; +; CHECK: BitField (0x1013) { +; CHECK: TypeLeafKind: LF_BITFIELD (0x1205) +; CHECK: Type: short (0x11) +; CHECK: BitSize: 8 +; CHECK: BitOffset: 8 +; CHECK: } +; CHECK: FieldList (0x1014) { +; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203) +; CHECK: DataMember { +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: 0x1013 +; CHECK: FieldOffset: 0x1 +; CHECK: Name: x +; CHECK: } +; CHECK: } +; CHECK: Struct (0x1015) { +; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505) +; CHECK: MemberCount: 1 +; CHECK: Properties [ (0x200) +; CHECK: HasUniqueName (0x200) +; CHECK: ] +; CHECK: FieldList: (0x1014) +; CHECK: DerivedFrom: 0x0 +; CHECK: VShape: 0x0 +; CHECK: SizeOf: 3 +; CHECK: Name: S3 +; CHECK: LinkageName: .?AUS3@@ +; CHECK: } +; CHECK: ] + +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-pc-windows-msvc18.0.31101" + +%struct.S1 = type <{ [2 x i8], i8, i32, i32, %struct.anon, i16 }> +%struct.anon = type <{ i8, i16 }> +%struct.S2 = type { i32 } +%struct.S3 = type <{ i8, i16 }> + +@"\01?s1@@3US1@@A" = global %struct.S1 zeroinitializer, align 1 +@"\01?s2@@3US2@@A" = global %struct.S2 zeroinitializer, align 1 +@"\01?s3@@3US3@@A" = global %struct.S3 zeroinitializer, align 1 + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!34, !35} +!llvm.ident = !{!36} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 (trunk 273874)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3) +!1 = !DIFile(filename: "t.cpp", directory: "/") +!2 = !{} +!3 = !{!4, !24, !28} +!4 = distinct !DIGlobalVariable(name: "s1", linkageName: "\01?s1@@3US1@@A", scope: !0, file: !1, line: 10, type: !5, isLocal: false, isDefinition: true, variable: %struct.S1* @"\01?s1@@3US1@@A") +!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S1", file: !1, line: 2, size: 128, align: 8, elements: !6, identifier: ".?AUS1@@") +!6 = !{!7, !12, !13, !15, !16, !17, !23} +!7 = !DIDerivedType(tag: DW_TAG_member, name: "x1", scope: !5, file: !1, line: 3, baseType: !8, size: 16, align: 8) +!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 16, align: 8, elements: !10) +!9 = !DIBasicType(name: "char", size: 8, align: 8, encoding: DW_ATE_signed_char) +!10 = !{!11} +!11 = !DISubrange(count: 2) +!12 = !DIDerivedType(tag: DW_TAG_member, name: "x2", scope: !5, file: !1, line: 4, baseType: !9, size: 8, align: 8, offset: 16) +!13 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !5, file: !1, line: 5, baseType: !14, size: 23, align: 32, offset: 24) +!14 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!15 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !5, file: !1, line: 6, baseType: !14, size: 23, align: 32, offset: 56) +!16 = !DIDerivedType(tag: DW_TAG_member, name: "w", scope: !5, file: !1, line: 7, baseType: !14, size: 2, align: 32, offset: 79) +!17 = !DIDerivedType(tag: DW_TAG_member, name: "v", scope: !5, file: !1, line: 8, baseType: !18, size: 24, align: 8, offset: 88) +!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !5, file: !1, line: 8, size: 24, align: 8, elements: !19, identifier: ".?AU@S1@@") +!19 = !{!20, !21} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !18, file: !1, line: 8, baseType: !9, size: 8, align: 8) +!21 = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: !18, file: !1, line: 8, baseType: !22, size: 16, align: 16, offset: 8) +!22 = !DIBasicType(name: "short", size: 16, align: 16, encoding: DW_ATE_signed) +!23 = !DIDerivedType(tag: DW_TAG_member, name: "u", scope: !5, file: !1, line: 9, baseType: !22, size: 3, align: 16, offset: 112) +!24 = distinct !DIGlobalVariable(name: "s2", linkageName: "\01?s2@@3US2@@A", scope: !0, file: !1, line: 16, type: !25, isLocal: false, isDefinition: true, variable: %struct.S2* @"\01?s2@@3US2@@A") +!25 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S2", file: !1, line: 13, size: 32, align: 8, elements: !26, identifier: ".?AUS2@@") +!26 = !{!27} +!27 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !25, file: !1, line: 15, baseType: !14, size: 1, align: 32) +!28 = distinct !DIGlobalVariable(name: "s3", linkageName: "\01?s3@@3US3@@A", scope: !0, file: !1, line: 23, type: !29, isLocal: false, isDefinition: true, variable: %struct.S3* @"\01?s3@@3US3@@A") +!29 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S3", file: !1, line: 19, size: 24, align: 8, elements: !30, identifier: ".?AUS3@@") +!30 = !{!31, !32, !33} +!31 = !DIDerivedType(tag: DW_TAG_member, scope: !29, file: !1, line: 20, baseType: !9, size: 8, align: 8) +!32 = !DIDerivedType(tag: DW_TAG_member, scope: !29, file: !1, line: 21, baseType: !22, size: 8, align: 16, offset: 8) +!33 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !29, file: !1, line: 22, baseType: !22, size: 8, align: 16, offset: 16) +!34 = !{i32 2, !"CodeView", i32 1} +!35 = !{i32 2, !"Debug Info Version", i32 3} +!36 = !{!"clang version 3.9.0 (trunk 273874)"}