Index: lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -1511,6 +1511,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 @@ -1543,6 +1572,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()); @@ -1555,10 +1587,39 @@ continue; } + 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; + } + + 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; 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,243 @@ +; 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 c1; short s2; } v; +; short u : 3; +; }; +; S1 s1; +; +; #pragma pack(1) +; struct S2 { +; char : 0; +; int y : 1; +; }; +; S2 s2; +; $ 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: c1 +; CHECK: } +; CHECK: DataMember { +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: short (0x11) +; CHECK: FieldOffset: 0x1 +; CHECK: Name: s2 +; 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: ] + +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 } + +@"\01?s1@@3US1@@A" = global %struct.S1 zeroinitializer, align 1 +@"\01?s2@@3US2@@A" = global %struct.S2 zeroinitializer, align 1 + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!28, !29} +!llvm.ident = !{!30} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 (trunk 273806)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3) +!1 = !DIFile(filename: "t.cpp", directory: "/") +!2 = !{} +!3 = !{!4, !24} +!4 = distinct !DIGlobalVariable(name: "s1", linkageName: "\01?s1@@3US1@@A", scope: !0, file: !1, line: 11, 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: "c1", scope: !18, file: !1, line: 8, baseType: !9, size: 8, align: 8) +!21 = !DIDerivedType(tag: DW_TAG_member, name: "s2", 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: 18, 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: 14, size: 32, align: 8, elements: !26, identifier: ".?AUS2@@") +!26 = !{!27} +!27 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !25, file: !1, line: 16, baseType: !14, size: 1, align: 32) +!28 = !{i32 2, !"CodeView", i32 1} +!29 = !{i32 2, !"Debug Info Version", i32 3} +!30 = !{!"clang version 3.9.0 (trunk 273806)"}