Skip to content

Commit a8d5740

Browse files
committedJun 3, 2016
[codeview] Add basic record type translation
This only translates data members for now. Translating overloaded methods is complicated, so I stopped short of doing that. Reviewers: aaboud Differential Revision: http://reviews.llvm.org/D20924 llvm-svn: 271680
1 parent 9bc93f6 commit a8d5740

File tree

7 files changed

+945
-25
lines changed

7 files changed

+945
-25
lines changed
 

‎llvm/include/llvm/DebugInfo/CodeView/ListRecordBuilder.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,13 @@ class ListRecordBuilder {
2828
public:
2929
llvm::StringRef str() { return Builder.str(); }
3030

31-
void reset(TypeRecordKind K) { Builder.reset(K); }
31+
void reset(TypeRecordKind K) {
32+
Builder.reset(K);
33+
ContinuationOffsets.clear();
34+
SubrecordCount = 0;
35+
}
36+
37+
unsigned getSubrecordCount() { return SubrecordCount; }
3238

3339
protected:
3440
void finishSubRecord();
@@ -38,6 +44,7 @@ class ListRecordBuilder {
3844
private:
3945
TypeRecordBuilder Builder;
4046
SmallVector<size_t, 4> ContinuationOffsets;
47+
unsigned SubrecordCount = 0;
4148
};
4249
}
4350
}

‎llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp

+201-8
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include "CodeViewDebug.h"
1515
#include "llvm/DebugInfo/CodeView/CodeView.h"
16+
#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
1617
#include "llvm/DebugInfo/CodeView/Line.h"
1718
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
1819
#include "llvm/DebugInfo/CodeView/TypeDumper.h"
@@ -138,12 +139,16 @@ TypeIndex CodeViewDebug::getFuncIdForSubprogram(const DISubprogram *SP) {
138139
FuncIdRecord FuncId(ParentScope, getTypeIndex(SP->getType()), DisplayName);
139140
TypeIndex TI = TypeTable.writeFuncId(FuncId);
140141

141-
auto InsertResult = TypeIndices.insert({SP, TI});
142-
(void)InsertResult;
143-
assert(InsertResult.second && "DISubprogram lowered twice");
142+
recordTypeIndexForDINode(SP, TI);
144143
return TI;
145144
}
146145

146+
void CodeViewDebug::recordTypeIndexForDINode(const DINode *Node, TypeIndex TI) {
147+
auto InsertResult = TypeIndices.insert({Node, TI});
148+
(void)InsertResult;
149+
assert(InsertResult.second && "DINode was already assigned a type index");
150+
}
151+
147152
void CodeViewDebug::recordLocalVariable(LocalVariable &&Var,
148153
const DILocation *InlinedAt) {
149154
if (InlinedAt) {
@@ -746,6 +751,11 @@ TypeIndex CodeViewDebug::lowerType(const DIType *Ty) {
746751
return lowerTypeModifier(cast<DIDerivedType>(Ty));
747752
case dwarf::DW_TAG_subroutine_type:
748753
return lowerTypeFunction(cast<DISubroutineType>(Ty));
754+
case dwarf::DW_TAG_class_type:
755+
case dwarf::DW_TAG_structure_type:
756+
return lowerTypeClass(cast<DICompositeType>(Ty));
757+
case dwarf::DW_TAG_union_type:
758+
return lowerTypeUnion(cast<DICompositeType>(Ty));
749759
default:
750760
// Use the null type index.
751761
return TypeIndex();
@@ -961,23 +971,206 @@ TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) {
961971
return TypeTable.writeProcedure(Procedure);
962972
}
963973

974+
static MemberAccess translateAccessFlags(unsigned RecordTag,
975+
const DIType *Member) {
976+
switch (Member->getFlags() & DINode::FlagAccessibility) {
977+
case DINode::FlagPrivate: return MemberAccess::Private;
978+
case DINode::FlagPublic: return MemberAccess::Public;
979+
case DINode::FlagProtected: return MemberAccess::Protected;
980+
case 0:
981+
// If there was no explicit access control, provide the default for the tag.
982+
return RecordTag == dwarf::DW_TAG_class_type ? MemberAccess::Private
983+
: MemberAccess::Public;
984+
}
985+
llvm_unreachable("access flags are exclusive");
986+
}
987+
988+
static TypeRecordKind getRecordKind(const DICompositeType *Ty) {
989+
switch (Ty->getTag()) {
990+
case dwarf::DW_TAG_class_type: return TypeRecordKind::Class;
991+
case dwarf::DW_TAG_structure_type: return TypeRecordKind::Struct;
992+
}
993+
llvm_unreachable("unexpected tag");
994+
}
995+
996+
/// Return the HasUniqueName option if it should be present in ClassOptions, or
997+
/// None otherwise.
998+
static ClassOptions getRecordUniqueNameOption(const DICompositeType *Ty) {
999+
// MSVC always sets this flag now, even for local types. Clang doesn't always
1000+
// appear to give every type a linkage name, which may be problematic for us.
1001+
// FIXME: Investigate the consequences of not following them here.
1002+
return !Ty->getIdentifier().empty() ? ClassOptions::HasUniqueName
1003+
: ClassOptions::None;
1004+
}
1005+
1006+
TypeIndex CodeViewDebug::lowerTypeClass(const DICompositeType *Ty) {
1007+
// First, construct the forward decl. Don't look into Ty to compute the
1008+
// forward decl options, since it might not be available in all TUs.
1009+
TypeRecordKind Kind = getRecordKind(Ty);
1010+
ClassOptions CO =
1011+
ClassOptions::ForwardReference | getRecordUniqueNameOption(Ty);
1012+
TypeIndex FwdDeclTI = TypeTable.writeClass(ClassRecord(
1013+
Kind, 0, CO, HfaKind::None, WindowsRTClassKind::None, TypeIndex(),
1014+
TypeIndex(), TypeIndex(), 0, Ty->getName(), Ty->getIdentifier()));
1015+
return FwdDeclTI;
1016+
}
1017+
1018+
TypeIndex CodeViewDebug::lowerCompleteTypeClass(const DICompositeType *Ty) {
1019+
// Construct the field list and complete type record.
1020+
TypeRecordKind Kind = getRecordKind(Ty);
1021+
// FIXME: Other ClassOptions, like ContainsNestedClass and NestedClass.
1022+
ClassOptions CO = ClassOptions::None | getRecordUniqueNameOption(Ty);
1023+
TypeIndex FTI;
1024+
unsigned FieldCount;
1025+
std::tie(FTI, FieldCount) = lowerRecordFieldList(Ty);
1026+
1027+
uint64_t SizeInBytes = Ty->getSizeInBits() / 8;
1028+
return TypeTable.writeClass(ClassRecord(Kind, FieldCount, CO, HfaKind::None,
1029+
WindowsRTClassKind::None, FTI,
1030+
TypeIndex(), TypeIndex(), SizeInBytes,
1031+
Ty->getName(), Ty->getIdentifier()));
1032+
// FIXME: Make an LF_UDT_SRC_LINE record.
1033+
}
1034+
1035+
TypeIndex CodeViewDebug::lowerTypeUnion(const DICompositeType *Ty) {
1036+
ClassOptions CO =
1037+
ClassOptions::ForwardReference | getRecordUniqueNameOption(Ty);
1038+
TypeIndex FwdDeclTI =
1039+
TypeTable.writeUnion(UnionRecord(0, CO, HfaKind::None, TypeIndex(), 0,
1040+
Ty->getName(), Ty->getIdentifier()));
1041+
return FwdDeclTI;
1042+
}
1043+
1044+
TypeIndex CodeViewDebug::lowerCompleteTypeUnion(const DICompositeType *Ty) {
1045+
ClassOptions CO = ClassOptions::None | getRecordUniqueNameOption(Ty);
1046+
TypeIndex FTI;
1047+
unsigned FieldCount;
1048+
std::tie(FTI, FieldCount) = lowerRecordFieldList(Ty);
1049+
uint64_t SizeInBytes = Ty->getSizeInBits() / 8;
1050+
return TypeTable.writeUnion(UnionRecord(FieldCount, CO, HfaKind::None, FTI,
1051+
SizeInBytes, Ty->getName(),
1052+
Ty->getIdentifier()));
1053+
// FIXME: Make an LF_UDT_SRC_LINE record.
1054+
}
1055+
1056+
std::pair<TypeIndex, unsigned>
1057+
CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
1058+
// Manually count members. MSVC appears to count everything that generates a
1059+
// field list record. Each individual overload in a method overload group
1060+
// contributes to this count, even though the overload group is a single field
1061+
// list record.
1062+
unsigned MemberCount = 0;
1063+
FieldListRecordBuilder Fields;
1064+
for (const DINode *Element : Ty->getElements()) {
1065+
// We assume that the frontend provides all members in source declaration
1066+
// order, which is what MSVC does.
1067+
if (!Element)
1068+
continue;
1069+
if (auto *SP = dyn_cast<DISubprogram>(Element)) {
1070+
// C++ method.
1071+
// FIXME: Overloaded methods are grouped together, so we'll need two
1072+
// passes to group them.
1073+
(void)SP;
1074+
} else if (auto *Member = dyn_cast<DIDerivedType>(Element)) {
1075+
if (Member->getTag() == dwarf::DW_TAG_member) {
1076+
if (Member->isStaticMember()) {
1077+
// Static data member.
1078+
Fields.writeStaticDataMember(StaticDataMemberRecord(
1079+
translateAccessFlags(Ty->getTag(), Member),
1080+
getTypeIndex(Member->getBaseType()), Member->getName()));
1081+
MemberCount++;
1082+
} else {
1083+
// Data member.
1084+
// FIXME: Make a BitFieldRecord for bitfields.
1085+
Fields.writeDataMember(DataMemberRecord(
1086+
translateAccessFlags(Ty->getTag(), Member),
1087+
getTypeIndex(Member->getBaseType()),
1088+
Member->getOffsetInBits() / 8, Member->getName()));
1089+
MemberCount++;
1090+
}
1091+
} else if (Member->getTag() == dwarf::DW_TAG_friend) {
1092+
// Ignore friend members. It appears that MSVC emitted info about
1093+
// friends in the past, but modern versions do not.
1094+
}
1095+
// FIXME: Get clang to emit nested types here and do something with
1096+
// them.
1097+
}
1098+
// Skip other unrecognized kinds of elements.
1099+
}
1100+
return {TypeTable.writeFieldList(Fields), MemberCount};
1101+
}
1102+
9641103
TypeIndex CodeViewDebug::getTypeIndex(DITypeRef TypeRef) {
9651104
const DIType *Ty = TypeRef.resolve();
9661105

9671106
// The null DIType is the void type. Don't try to hash it.
9681107
if (!Ty)
9691108
return TypeIndex::Void();
9701109

971-
// Check if we've already translated this type.
1110+
// Check if we've already translated this type. Don't try to do a
1111+
// get-or-create style insertion that caches the hash lookup across the
1112+
// lowerType call. It will update the TypeIndices map.
9721113
auto I = TypeIndices.find(Ty);
9731114
if (I != TypeIndices.end())
9741115
return I->second;
9751116

9761117
TypeIndex TI = lowerType(Ty);
9771118

978-
auto InsertResult = TypeIndices.insert({Ty, TI});
979-
(void)InsertResult;
980-
assert(InsertResult.second && "DIType lowered twice");
1119+
recordTypeIndexForDINode(Ty, TI);
1120+
return TI;
1121+
}
1122+
1123+
TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) {
1124+
const DIType *Ty = TypeRef.resolve();
1125+
1126+
// The null DIType is the void type. Don't try to hash it.
1127+
if (!Ty)
1128+
return TypeIndex::Void();
1129+
1130+
// If this is a non-record type, the complete type index is the same as the
1131+
// normal type index. Just call getTypeIndex.
1132+
switch (Ty->getTag()) {
1133+
case dwarf::DW_TAG_class_type:
1134+
case dwarf::DW_TAG_structure_type:
1135+
case dwarf::DW_TAG_union_type:
1136+
break;
1137+
default:
1138+
return getTypeIndex(Ty);
1139+
}
1140+
1141+
// Check if we've already translated the complete record type. Lowering a
1142+
// complete type should never trigger lowering another complete type, so we
1143+
// can reuse the hash table lookup result.
1144+
const auto *CTy = cast<DICompositeType>(Ty);
1145+
auto InsertResult = CompleteTypeIndices.insert({CTy, TypeIndex()});
1146+
if (!InsertResult.second)
1147+
return InsertResult.first->second;
1148+
1149+
// Make sure the forward declaration is emitted first. It's unclear if this
1150+
// is necessary, but MSVC does it, and we should follow suit until we can show
1151+
// otherwise.
1152+
TypeIndex FwdDeclTI = getTypeIndex(CTy);
1153+
1154+
// Just use the forward decl if we don't have complete type info. This might
1155+
// happen if the frontend is using modules and expects the complete definition
1156+
// to be emitted elsewhere.
1157+
if (CTy->isForwardDecl())
1158+
return FwdDeclTI;
1159+
1160+
TypeIndex TI;
1161+
switch (CTy->getTag()) {
1162+
case dwarf::DW_TAG_class_type:
1163+
case dwarf::DW_TAG_structure_type:
1164+
TI = lowerCompleteTypeClass(CTy);
1165+
break;
1166+
case dwarf::DW_TAG_union_type:
1167+
TI = lowerCompleteTypeUnion(CTy);
1168+
break;
1169+
default:
1170+
llvm_unreachable("not a record");
1171+
}
1172+
1173+
InsertResult.first->second = TI;
9811174
return TI;
9821175
}
9831176

@@ -999,7 +1192,7 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) {
9991192
Flags |= LocalSymFlags::IsOptimizedOut;
10001193

10011194
OS.AddComment("TypeIndex");
1002-
TypeIndex TI = getTypeIndex(Var.DIVar->getType());
1195+
TypeIndex TI = getCompleteTypeIndex(Var.DIVar->getType());
10031196
OS.EmitIntValue(TI.getIndex(), 4);
10041197
OS.AddComment("Flags");
10051198
OS.EmitIntValue(static_cast<uint16_t>(Flags), 2);

‎llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h

+26-1
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
140140
/// DIType* and DISubprogram*.
141141
DenseMap<const DINode *, codeview::TypeIndex> TypeIndices;
142142

143+
/// Map from DICompositeType* to complete type index. Non-record types are
144+
/// always looked up in the normal TypeIndices map.
145+
DenseMap<const DICompositeType *, codeview::TypeIndex> CompleteTypeIndices;
146+
143147
typedef std::map<const DIFile *, std::string> FileToFilepathMapTy;
144148
FileToFilepathMapTy FileToFilepathMap;
145149
StringRef getFullFilepath(const DIFile *S);
@@ -182,7 +186,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
182186

183187
/// Translates the DIType to codeview if necessary and returns a type index
184188
/// for it.
185-
codeview::TypeIndex getTypeIndex(DITypeRef Ty);
189+
codeview::TypeIndex getTypeIndex(DITypeRef TypeRef);
186190

187191
codeview::TypeIndex lowerType(const DIType *Ty);
188192
codeview::TypeIndex lowerTypeAlias(const DIDerivedType *Ty);
@@ -191,6 +195,27 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
191195
codeview::TypeIndex lowerTypeMemberPointer(const DIDerivedType *Ty);
192196
codeview::TypeIndex lowerTypeModifier(const DIDerivedType *Ty);
193197
codeview::TypeIndex lowerTypeFunction(const DISubroutineType *Ty);
198+
codeview::TypeIndex lowerTypeClass(const DICompositeType *Ty);
199+
codeview::TypeIndex lowerTypeUnion(const DICompositeType *Ty);
200+
201+
/// Symbol records should point to complete types, but type records should
202+
/// always point to incomplete types to avoid cycles in the type graph. Only
203+
/// use this entry point when generating symbol records. The complete and
204+
/// incomplete type indices only differ for record types. All other types use
205+
/// the same index.
206+
codeview::TypeIndex getCompleteTypeIndex(DITypeRef TypeRef);
207+
208+
codeview::TypeIndex lowerCompleteTypeClass(const DICompositeType *Ty);
209+
codeview::TypeIndex lowerCompleteTypeUnion(const DICompositeType *Ty);
210+
211+
/// Common record member lowering functionality for record types, which are
212+
/// structs, classes, and unions. Returns the field list index and the member
213+
/// count.
214+
std::pair<codeview::TypeIndex, unsigned>
215+
lowerRecordFieldList(const DICompositeType *Ty);
216+
217+
/// Inserts {Node, TI} into TypeIndices and checks for duplicates.
218+
void recordTypeIndexForDINode(const DINode *Node, codeview::TypeIndex TI);
194219

195220
public:
196221
CodeViewDebug(AsmPrinter *Asm);

‎llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ using namespace codeview;
1515
ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind) : Builder(Kind) {}
1616

1717
void ListRecordBuilder::finishSubRecord() {
18+
SubrecordCount++;
19+
1820
// The builder starts at offset 2 in the actual CodeView buffer, so add an
1921
// additional offset of 2 before computing the alignment.
2022
uint32_t Remainder = (Builder.size() + 2) % 4;

‎llvm/test/DebugInfo/COFF/types-basic.ll

+63-15
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
; $ clang t.cpp -S -emit-llvm -g -gcodeview -o t.ll
3434

3535
; CHECK: CodeViewTypes [
36+
; CHECK: Section: .debug$T (6)
37+
; CHECK: Magic: 0x4
3638
; CHECK: ArgList (0x1000) {
3739
; CHECK: TypeLeafKind: LF_ARGLIST (0x1201)
3840
; CHECK: NumArgs: 3
@@ -75,7 +77,19 @@
7577
; CHECK: IsVolatile: 0
7678
; CHECK: IsUnaligned: 0
7779
; CHECK: }
78-
; CHECK: Pointer (0x1005) {
80+
; CHECK: Struct (0x1005) {
81+
; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505)
82+
; CHECK: MemberCount: 0
83+
; CHECK: Properties [ (0x80)
84+
; CHECK: ForwardReference (0x80)
85+
; CHECK: ]
86+
; CHECK: FieldList: 0x0
87+
; CHECK: DerivedFrom: 0x0
88+
; CHECK: VShape: 0x0
89+
; CHECK: SizeOf: 0
90+
; CHECK: Name: A
91+
; CHECK: }
92+
; CHECK: Pointer (0x1006) {
7993
; CHECK: TypeLeafKind: LF_POINTER (0x1002)
8094
; CHECK: PointeeType: int (0x74)
8195
; CHECK: PointerAttributes: 0x804C
@@ -85,48 +99,59 @@
8599
; CHECK: IsConst: 0
86100
; CHECK: IsVolatile: 0
87101
; CHECK: IsUnaligned: 0
88-
; CHECK: ClassType: 0x0
102+
; CHECK: ClassType: A (0x1005)
89103
; CHECK: Representation: Unknown (0x0)
90104
; CHECK: }
91-
; CHECK: ArgList (0x1006) {
105+
; CHECK: Pointer (0x1007) {
106+
; CHECK: TypeLeafKind: LF_POINTER (0x1002)
107+
; CHECK: PointeeType: A (0x1005)
108+
; CHECK: PointerAttributes: 0x1000C
109+
; CHECK: PtrType: Near64 (0xC)
110+
; CHECK: PtrMode: Pointer (0x0)
111+
; CHECK: IsFlat: 0
112+
; CHECK: IsConst: 0
113+
; CHECK: IsVolatile: 0
114+
; CHECK: IsUnaligned: 0
115+
; CHECK: }
116+
; CHECK: ArgList (0x1008) {
92117
; CHECK: TypeLeafKind: LF_ARGLIST (0x1201)
93118
; CHECK: NumArgs: 1
94119
; CHECK: Arguments [
95-
; CHECK: ArgType: <unknown simple type> (0x600)
120+
; CHECK: ArgType: A* (0x1007)
96121
; CHECK: ]
97122
; CHECK: }
98-
; CHECK: Procedure (0x1007) {
123+
; CHECK: Procedure (0x1009) {
99124
; CHECK: TypeLeafKind: LF_PROCEDURE (0x1008)
100125
; CHECK: ReturnType: void (0x3)
101126
; CHECK: CallingConvention: NearC (0x0)
102127
; CHECK: FunctionOptions [ (0x0)
103128
; CHECK: ]
104129
; CHECK: NumParameters: 1
105-
; CHECK: ArgListType: (<unknown simple type>) (0x1006)
130+
; CHECK: ArgListType: (A*) (0x1008)
106131
; CHECK: }
107-
; CHECK: Pointer (0x1008) {
132+
; CHECK: Pointer (0x100A) {
108133
; CHECK: TypeLeafKind: LF_POINTER (0x1002)
109-
; CHECK: PointeeType: void (<unknown simple type>) (0x1007)
134+
; CHECK: PointeeType: void (A*) (0x1009)
110135
; CHECK: PointerAttributes: 0x1006C
111136
; CHECK: PtrType: Near64 (0xC)
112137
; CHECK: PtrMode: PointerToMemberFunction (0x3)
113138
; CHECK: IsFlat: 0
114139
; CHECK: IsConst: 0
115140
; CHECK: IsVolatile: 0
116141
; CHECK: IsUnaligned: 0
117-
; CHECK: ClassType: 0x0
142+
; CHECK: ClassType: A (0x1005)
118143
; CHECK: Representation: Unknown (0x0)
119144
; CHECK: }
120-
; CHECK: Modifier (0x1009) {
145+
; CHECK: Modifier (0x100B) {
121146
; CHECK: TypeLeafKind: LF_MODIFIER (0x1001)
122147
; CHECK: ModifiedType: void (0x3)
123148
; CHECK: Modifiers [ (0x1)
124149
; CHECK: Const (0x1)
125150
; CHECK: ]
126151
; CHECK: }
127-
; CHECK: Pointer (0x100A) {
152+
; CHECK: Pointer (0x100C) {
128153
; CHECK: TypeLeafKind: LF_POINTER (0x1002)
129-
; CHECK: PointeeType: const void (0x1009)
154+
; CHECK: PointeeType: const void (0x100B)
130155
; CHECK: PointerAttributes: 0x1000C
131156
; CHECK: PtrType: Near64 (0xC)
132157
; CHECK: PtrMode: Pointer (0x0)
@@ -135,7 +160,29 @@
135160
; CHECK: IsVolatile: 0
136161
; CHECK: IsUnaligned: 0
137162
; CHECK: }
163+
; CHECK: ArgList (0x100D) {
164+
; CHECK: TypeLeafKind: LF_ARGLIST (0x1201)
165+
; CHECK: NumArgs: 0
166+
; CHECK: Arguments [
167+
; CHECK: ]
168+
; CHECK: }
169+
; CHECK: Procedure (0x100E) {
170+
; CHECK: TypeLeafKind: LF_PROCEDURE (0x1008)
171+
; CHECK: ReturnType: void (0x3)
172+
; CHECK: CallingConvention: NearC (0x0)
173+
; CHECK: FunctionOptions [ (0x0)
174+
; CHECK: ]
175+
; CHECK: NumParameters: 0
176+
; CHECK: ArgListType: () (0x100D)
177+
; CHECK: }
178+
; CHECK: FuncId (0x100F) {
179+
; CHECK: TypeLeafKind: LF_FUNC_ID (0x1601)
180+
; CHECK: ParentScope: 0x0
181+
; CHECK: FunctionType: void () (0x100E)
182+
; CHECK: Name: CharTypes
183+
; CHECK: }
138184
; CHECK: ]
185+
139186
; CHECK: CodeViewDebugInfo [
140187
; CHECK: Subsection [
141188
; CHECK: SubSectionType: Symbols (0xF1)
@@ -188,11 +235,11 @@
188235
; CHECK: VarName: v3
189236
; CHECK: }
190237
; CHECK: Local {
191-
; CHECK: Type: int <no type>::* (0x1005)
238+
; CHECK: Type: int A::* (0x1006)
192239
; CHECK: VarName: v4
193240
; CHECK: }
194241
; CHECK: Local {
195-
; CHECK: Type: void (<unknown simple type>) <no type>::* (0x1008)
242+
; CHECK: Type: void (A*) A::* (0x100A)
196243
; CHECK: VarName: v5
197244
; CHECK: }
198245
; CHECK: Local {
@@ -212,14 +259,15 @@
212259
; CHECK: VarName: l4
213260
; CHECK: }
214261
; CHECK: Local {
215-
; CHECK: Type: const void* (0x100A)
262+
; CHECK: Type: const void* (0x100C)
216263
; CHECK: VarName: v6
217264
; CHECK: }
218265
; CHECK: ProcEnd {
219266
; CHECK: }
220267
; CHECK: ]
221268
; CHECK: Subsection [
222269
; CHECK: ProcStart {
270+
; CHECK: Type: CharTypes (0x100F)
223271
; CHECK: DisplayName: CharTypes
224272
; CHECK: LinkageName: ?CharTypes@@YAXXZ
225273
; CHECK: }

‎llvm/test/DebugInfo/COFF/types-data-members.ll

+473
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
; RUN: llc < %s -filetype=obj | llvm-readobj - -codeview | FileCheck %s
2+
3+
; This test ensures that circular type references through pointer types don't
4+
; cause infinite recursion. It also tests that we always refer to the forward
5+
; declaration type index in field lists and pointer types, which is consistent
6+
; with what MSVC does. It ensures that these records get merged when merging
7+
; streams even if the complete record types differ slightly due to ODR
8+
; violations, i.e. methods that only exist ifndef NDEBUG.
9+
10+
; C++ source to regenerate:
11+
; $ cat t.cpp
12+
; struct B;
13+
; struct A { B *b; };
14+
; struct B { A a; };
15+
; void f() {
16+
; A a;
17+
; B b;
18+
; }
19+
; $ clang t.cpp -S -emit-llvm -g -gcodeview -o t.ll
20+
21+
; CHECK: CodeViewTypes [
22+
; CHECK: Section: .debug$T (6)
23+
; CHECK: Magic: 0x4
24+
; CHECK: ArgList (0x1000) {
25+
; CHECK: TypeLeafKind: LF_ARGLIST (0x1201)
26+
; CHECK: NumArgs: 0
27+
; CHECK: Arguments [
28+
; CHECK: ]
29+
; CHECK: }
30+
; CHECK: Procedure (0x1001) {
31+
; CHECK: TypeLeafKind: LF_PROCEDURE (0x1008)
32+
; CHECK: ReturnType: void (0x3)
33+
; CHECK: CallingConvention: NearC (0x0)
34+
; CHECK: FunctionOptions [ (0x0)
35+
; CHECK: ]
36+
; CHECK: NumParameters: 0
37+
; CHECK: ArgListType: () (0x1000)
38+
; CHECK: }
39+
; CHECK: FuncId (0x1002) {
40+
; CHECK: TypeLeafKind: LF_FUNC_ID (0x1601)
41+
; CHECK: ParentScope: 0x0
42+
; CHECK: FunctionType: void () (0x1001)
43+
; CHECK: Name: f
44+
; CHECK: }
45+
; CHECK: Struct (0x1003) {
46+
; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505)
47+
; CHECK: MemberCount: 0
48+
; CHECK: Properties [ (0x80)
49+
; CHECK: ForwardReference (0x80)
50+
; CHECK: ]
51+
; CHECK: FieldList: 0x0
52+
; CHECK: DerivedFrom: 0x0
53+
; CHECK: VShape: 0x0
54+
; CHECK: SizeOf: 0
55+
; CHECK: Name: A
56+
; CHECK: }
57+
; CHECK: Struct (0x1004) {
58+
; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505)
59+
; CHECK: MemberCount: 0
60+
; CHECK: Properties [ (0x80)
61+
; CHECK: ForwardReference (0x80)
62+
; CHECK: ]
63+
; CHECK: FieldList: 0x0
64+
; CHECK: DerivedFrom: 0x0
65+
; CHECK: VShape: 0x0
66+
; CHECK: SizeOf: 0
67+
; CHECK: Name: B
68+
; CHECK: }
69+
; CHECK: Pointer (0x1005) {
70+
; CHECK: TypeLeafKind: LF_POINTER (0x1002)
71+
; CHECK: PointeeType: B (0x1004)
72+
; CHECK: PointerAttributes: 0x1000C
73+
; CHECK: PtrType: Near64 (0xC)
74+
; CHECK: PtrMode: Pointer (0x0)
75+
; CHECK: IsFlat: 0
76+
; CHECK: IsConst: 0
77+
; CHECK: IsVolatile: 0
78+
; CHECK: IsUnaligned: 0
79+
; CHECK: }
80+
; CHECK: UnknownLeaf (0x1006) {
81+
; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203)
82+
; CHECK: DataMember {
83+
; CHECK: AccessSpecifier: Public (0x3)
84+
; CHECK: Type: B* (0x1005)
85+
; CHECK: FieldOffset: 0x0
86+
; CHECK: Name: b
87+
; CHECK: }
88+
; CHECK: }
89+
; CHECK: Struct (0x1007) {
90+
; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505)
91+
; CHECK: MemberCount: 1
92+
; CHECK: Properties [ (0x0)
93+
; CHECK: ]
94+
; CHECK: FieldList: b (0x1006)
95+
; CHECK: DerivedFrom: 0x0
96+
; CHECK: VShape: 0x0
97+
; CHECK: SizeOf: 8
98+
; CHECK: Name: A
99+
; CHECK: }
100+
; CHECK: UnknownLeaf (0x1008) {
101+
; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203)
102+
; CHECK: DataMember {
103+
; CHECK: AccessSpecifier: Public (0x3)
104+
; CHECK: Type: A (0x1003)
105+
; CHECK: FieldOffset: 0x0
106+
; CHECK: Name: a
107+
; CHECK: }
108+
; CHECK: }
109+
; CHECK: Struct (0x1009) {
110+
; CHECK: TypeLeafKind: LF_STRUCTURE (0x1505)
111+
; CHECK: MemberCount: 1
112+
; CHECK: Properties [ (0x0)
113+
; CHECK: ]
114+
; CHECK: FieldList: a (0x1008)
115+
; CHECK: DerivedFrom: 0x0
116+
; CHECK: VShape: 0x0
117+
; CHECK: SizeOf: 8
118+
; CHECK: Name: B
119+
; CHECK: }
120+
; CHECK: ]
121+
122+
; ModuleID = 't.cpp'
123+
source_filename = "t.cpp"
124+
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
125+
target triple = "x86_64-pc-windows-msvc19.0.23918"
126+
127+
%struct.A = type { %struct.B* }
128+
%struct.B = type { %struct.A }
129+
130+
; Function Attrs: nounwind uwtable
131+
define void @"\01?f@@YAXXZ"() #0 !dbg !7 {
132+
entry:
133+
%a = alloca %struct.A, align 8
134+
%b = alloca %struct.B, align 8
135+
call void @llvm.dbg.declare(metadata %struct.A* %a, metadata !10, metadata !18), !dbg !19
136+
call void @llvm.dbg.declare(metadata %struct.B* %b, metadata !20, metadata !18), !dbg !21
137+
ret void, !dbg !22
138+
}
139+
140+
; Function Attrs: nounwind readnone
141+
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
142+
143+
attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
144+
attributes #1 = { nounwind readnone }
145+
146+
!llvm.dbg.cu = !{!0}
147+
!llvm.module.flags = !{!3, !4, !5}
148+
!llvm.ident = !{!6}
149+
150+
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
151+
!1 = !DIFile(filename: "t.cpp", directory: "D:\5Csrc\5Cllvm\5Cbuild")
152+
!2 = !{}
153+
!3 = !{i32 2, !"CodeView", i32 1}
154+
!4 = !{i32 2, !"Debug Info Version", i32 3}
155+
!5 = !{i32 1, !"PIC Level", i32 2}
156+
!6 = !{!"clang version 3.9.0 "}
157+
!7 = distinct !DISubprogram(name: "f", linkageName: "\01?f@@YAXXZ", scope: !1, file: !1, line: 4, type: !8, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
158+
!8 = !DISubroutineType(types: !9)
159+
!9 = !{null}
160+
!10 = !DILocalVariable(name: "a", scope: !7, file: !1, line: 5, type: !11)
161+
!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !1, line: 2, size: 64, align: 64, elements: !12)
162+
!12 = !{!13}
163+
!13 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !11, file: !1, line: 2, baseType: !14, size: 64, align: 64)
164+
!14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64, align: 64)
165+
!15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "B", file: !1, line: 3, size: 64, align: 64, elements: !16)
166+
!16 = !{!17}
167+
!17 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !15, file: !1, line: 3, baseType: !11, size: 64, align: 64)
168+
!18 = !DIExpression()
169+
!19 = !DILocation(line: 5, column: 5, scope: !7)
170+
!20 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 6, type: !15)
171+
!21 = !DILocation(line: 6, column: 5, scope: !7)
172+
!22 = !DILocation(line: 7, column: 1, scope: !7)

0 commit comments

Comments
 (0)
Please sign in to comment.