Skip to content

Commit d91ed80

Browse files
committed
[codeview] Reference types in type parent scopes
Without this change, when a nested tag type of any kind (enum, class, struct, union) is used as a variable type, it is emitted without emitting the parent type. In CodeView, parent types point to their inner types, and inner types do not point back to their parents. We already walk over all of the parent scopes to build the fully qualified name. This change simply requests their type indices as we go along to enusre they are all emitted. Fixes PR43905 Reviewers: akhuang, amccarth Differential Revision: https://reviews.llvm.org/D69924
1 parent 01b10bc commit d91ed80

File tree

4 files changed

+170
-16
lines changed

4 files changed

+170
-16
lines changed

llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -303,12 +303,19 @@ static StringRef getPrettyScopeName(const DIScope *Scope) {
303303
return StringRef();
304304
}
305305

306-
static const DISubprogram *getQualifiedNameComponents(
306+
const DISubprogram *CodeViewDebug::collectParentScopeNames(
307307
const DIScope *Scope, SmallVectorImpl<StringRef> &QualifiedNameComponents) {
308308
const DISubprogram *ClosestSubprogram = nullptr;
309309
while (Scope != nullptr) {
310310
if (ClosestSubprogram == nullptr)
311311
ClosestSubprogram = dyn_cast<DISubprogram>(Scope);
312+
313+
// If a type appears in a scope chain, make sure it gets emitted. The
314+
// frontend will be responsible for deciding if this should be a forward
315+
// declaration or a complete type.
316+
if (const auto *Ty = dyn_cast<DIType>(Scope))
317+
(void)getTypeIndex(Ty);
318+
312319
StringRef ScopeName = getPrettyScopeName(Scope);
313320
if (!ScopeName.empty())
314321
QualifiedNameComponents.push_back(ScopeName);
@@ -317,8 +324,9 @@ static const DISubprogram *getQualifiedNameComponents(
317324
return ClosestSubprogram;
318325
}
319326

320-
static std::string getQualifiedName(ArrayRef<StringRef> QualifiedNameComponents,
321-
StringRef TypeName) {
327+
std::string
328+
CodeViewDebug::formatNestedName(ArrayRef<StringRef> QualifiedNameComponents,
329+
StringRef TypeName) {
322330
std::string FullyQualifiedName;
323331
for (StringRef QualifiedNameComponent :
324332
llvm::reverse(QualifiedNameComponents)) {
@@ -329,10 +337,15 @@ static std::string getQualifiedName(ArrayRef<StringRef> QualifiedNameComponents,
329337
return FullyQualifiedName;
330338
}
331339

332-
static std::string getFullyQualifiedName(const DIScope *Scope, StringRef Name) {
340+
std::string CodeViewDebug::getFullyQualifiedName(const DIScope *Scope, StringRef Name) {
333341
SmallVector<StringRef, 5> QualifiedNameComponents;
334-
getQualifiedNameComponents(Scope, QualifiedNameComponents);
335-
return getQualifiedName(QualifiedNameComponents, Name);
342+
collectParentScopeNames(Scope, QualifiedNameComponents);
343+
return formatNestedName(QualifiedNameComponents, Name);
344+
}
345+
346+
std::string CodeViewDebug::getFullyQualifiedName(const DIScope *Ty) {
347+
const DIScope *Scope = Ty->getScope();
348+
return getFullyQualifiedName(Scope, getPrettyScopeName(Ty));
336349
}
337350

338351
struct CodeViewDebug::TypeLoweringScope {
@@ -347,11 +360,6 @@ struct CodeViewDebug::TypeLoweringScope {
347360
CodeViewDebug &CVD;
348361
};
349362

350-
static std::string getFullyQualifiedName(const DIScope *Ty) {
351-
const DIScope *Scope = Ty->getScope();
352-
return getFullyQualifiedName(Scope, getPrettyScopeName(Ty));
353-
}
354-
355363
TypeIndex CodeViewDebug::getScopeIndex(const DIScope *Scope) {
356364
// No scope means global scope and that uses the zero index.
357365
if (!Scope || isa<DIFile>(Scope))
@@ -1468,12 +1476,12 @@ void CodeViewDebug::addToUDTs(const DIType *Ty) {
14681476
if (!shouldEmitUdt(Ty))
14691477
return;
14701478

1471-
SmallVector<StringRef, 5> QualifiedNameComponents;
1479+
SmallVector<StringRef, 5> ParentScopeNames;
14721480
const DISubprogram *ClosestSubprogram =
1473-
getQualifiedNameComponents(Ty->getScope(), QualifiedNameComponents);
1481+
collectParentScopeNames(Ty->getScope(), ParentScopeNames);
14741482

14751483
std::string FullyQualifiedName =
1476-
getQualifiedName(QualifiedNameComponents, getPrettyScopeName(Ty));
1484+
formatNestedName(ParentScopeNames, getPrettyScopeName(Ty));
14771485

14781486
if (ClosestSubprogram == nullptr) {
14791487
GlobalUDTs.emplace_back(std::move(FullyQualifiedName), Ty);

llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,19 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
443443
codeview::TypeIndex TI,
444444
const DIType *ClassTy = nullptr);
445445

446+
/// Collect the names of parent scopes, innermost to outermost. Return the
447+
/// innermost subprogram scope if present. Ensure that parent type scopes are
448+
/// inserted into the type table.
449+
const DISubprogram *
450+
collectParentScopeNames(const DIScope *Scope,
451+
SmallVectorImpl<StringRef> &ParentScopeNames);
452+
453+
std::string formatNestedName(ArrayRef<StringRef> ParentScopeNames,
454+
StringRef TypeName);
455+
456+
std::string getFullyQualifiedName(const DIScope *Scope, StringRef Name);
457+
std::string getFullyQualifiedName(const DIScope *Scope);
458+
446459
unsigned getPointerSizeInBytes();
447460

448461
protected:

llvm/test/DebugInfo/COFF/global-constants.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
; ASM-NEXT: .asciz "S::TestConst2" # Name
3737
; ASM: .short {{.*-.*}} # Record length
3838
; ASM: .short 4359 # Record kind: S_CONSTANT
39-
; ASM-NEXT: .long 4105 # Type
39+
; ASM-NEXT: .long 4113 # Type
4040
; ASM-NEXT: .byte 0x0a, 0x80, 0x40, 0x61 # Value
4141
; ASM-NEXT: .byte 0x07, 0x80, 0xff, 0xff
4242
; ASM-NEXT: .byte 0xff, 0xff
@@ -62,7 +62,7 @@
6262
; OBJ-NEXT: }
6363
; OBJ-NEXT: ConstantSym {
6464
; OBJ-NEXT: Kind: S_CONSTANT (0x1107)
65-
; OBJ-NEXT: Type: TestEnum (0x1009)
65+
; OBJ-NEXT: Type: TestEnum (0x1011)
6666
; OBJ-NEXT: Value: 18446744071562551616
6767
; OBJ-NEXT: Name: ENUM_B
6868
; OBJ-NEXT: }
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
; RUN: llc < %s -filetype=obj -o %t.o
2+
; RUN: llvm-pdbutil dump -types %t.o | FileCheck %s
3+
4+
; C++ source:
5+
; // Note that MSVC doesn't emit anything about WrapTypedef or WrapTypedef::Inner!
6+
; struct WrapTypedef {
7+
; typedef int Inner;
8+
; };
9+
; struct WrapStruct {
10+
; struct Inner { int x; };
11+
; };
12+
; struct WrapClass {
13+
; class Inner { public: int x; };
14+
; };
15+
; struct WrapEnum {
16+
; enum Inner { One, Two };
17+
; };
18+
; struct WrapUnion {
19+
; union Inner { int x; float y; };
20+
; };
21+
; void useInnerTypes() {
22+
; WrapTypedef::Inner v1;
23+
; WrapStruct::Inner v2;
24+
; WrapClass::Inner v3;
25+
; WrapEnum::Inner v4;
26+
; WrapUnion::Inner v5;
27+
; }
28+
29+
; There should be two LF_STRUCTURE records for each wrapped type, forward decl
30+
; and complete type. For every inner record type, there should be two. Enums
31+
; don't get forward decls.
32+
33+
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapStruct`
34+
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapStruct`
35+
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapStruct::Inner`
36+
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapStruct::Inner`
37+
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapClass`
38+
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapClass`
39+
; CHECK-DAG: | LF_CLASS {{.*}} `WrapClass::Inner`
40+
; CHECK-DAG: | LF_CLASS {{.*}} `WrapClass::Inner`
41+
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapEnum`
42+
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapEnum`
43+
; CHECK-DAG: | LF_ENUM {{.*}} `WrapEnum::Inner`
44+
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapUnion`
45+
; CHECK-DAG: | LF_STRUCTURE {{.*}} `WrapUnion`
46+
; CHECK-DAG: | LF_UNION {{.*}} `WrapUnion::Inner`
47+
; CHECK-DAG: | LF_UNION {{.*}} `WrapUnion::Inner`
48+
49+
; ModuleID = 't.cpp'
50+
source_filename = "t.cpp"
51+
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
52+
target triple = "x86_64-pc-windows-msvc19.23.28106"
53+
54+
%"struct.WrapStruct::Inner" = type { i32 }
55+
%"class.WrapClass::Inner" = type { i32 }
56+
%"union.WrapUnion::Inner" = type { i32 }
57+
58+
; Function Attrs: noinline nounwind optnone uwtable
59+
define dso_local void @"?useInnerTypes@@YAXXZ"() #0 !dbg !15 {
60+
entry:
61+
%v1 = alloca i32, align 4
62+
%v2 = alloca %"struct.WrapStruct::Inner", align 4
63+
%v3 = alloca %"class.WrapClass::Inner", align 4
64+
%v4 = alloca i32, align 4
65+
%v5 = alloca %"union.WrapUnion::Inner", align 4
66+
call void @llvm.dbg.declare(metadata i32* %v1, metadata !19, metadata !DIExpression()), !dbg !23
67+
call void @llvm.dbg.declare(metadata %"struct.WrapStruct::Inner"* %v2, metadata !24, metadata !DIExpression()), !dbg !30
68+
call void @llvm.dbg.declare(metadata %"class.WrapClass::Inner"* %v3, metadata !31, metadata !DIExpression()), !dbg !37
69+
call void @llvm.dbg.declare(metadata i32* %v4, metadata !38, metadata !DIExpression()), !dbg !39
70+
call void @llvm.dbg.declare(metadata %"union.WrapUnion::Inner"* %v5, metadata !40, metadata !DIExpression()), !dbg !48
71+
ret void, !dbg !49
72+
}
73+
74+
; Function Attrs: nounwind readnone speculatable willreturn
75+
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
76+
77+
attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
78+
attributes #1 = { nounwind readnone speculatable willreturn }
79+
80+
!llvm.dbg.cu = !{!0}
81+
!llvm.module.flags = !{!10, !11, !12, !13}
82+
!llvm.ident = !{!14}
83+
84+
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 10.0.0 ([email protected]:llvm/llvm-project.git a8ccb48f697d3fbe85c593248ff1053fdf522a6e)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
85+
!1 = !DIFile(filename: "t.cpp", directory: "C:\\src\\llvm-project\\build", checksumkind: CSK_MD5, checksum: "4228f12f516cd3d6dd76462be09ec111")
86+
!2 = !{!3, !3}
87+
!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Inner", scope: !4, file: !1, line: 11, baseType: !6, size: 32, elements: !7, identifier: ".?AW4Inner@WrapEnum@@")
88+
!4 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "WrapEnum", file: !1, line: 10, size: 8, flags: DIFlagTypePassByValue, elements: !5, identifier: ".?AUWrapEnum@@")
89+
!5 = !{!3}
90+
!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
91+
!7 = !{!8, !9}
92+
!8 = !DIEnumerator(name: "One", value: 0)
93+
!9 = !DIEnumerator(name: "Two", value: 1)
94+
!10 = !{i32 2, !"CodeView", i32 1}
95+
!11 = !{i32 2, !"Debug Info Version", i32 3}
96+
!12 = !{i32 1, !"wchar_size", i32 2}
97+
!13 = !{i32 7, !"PIC Level", i32 2}
98+
!14 = !{!"clang version 10.0.0 ([email protected]:llvm/llvm-project.git a8ccb48f697d3fbe85c593248ff1053fdf522a6e)"}
99+
!15 = distinct !DISubprogram(name: "useInnerTypes", linkageName: "?useInnerTypes@@YAXXZ", scope: !1, file: !1, line: 16, type: !16, scopeLine: 16, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !18)
100+
!16 = !DISubroutineType(types: !17)
101+
!17 = !{null}
102+
!18 = !{}
103+
!19 = !DILocalVariable(name: "v1", scope: !15, file: !1, line: 17, type: !20)
104+
!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "Inner", scope: !21, file: !1, line: 2, baseType: !6)
105+
!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "WrapTypedef", file: !1, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !22, identifier: ".?AUWrapTypedef@@")
106+
!22 = !{!20}
107+
!23 = !DILocation(line: 17, scope: !15)
108+
!24 = !DILocalVariable(name: "v2", scope: !15, file: !1, line: 18, type: !25)
109+
!25 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Inner", scope: !26, file: !1, line: 5, size: 32, flags: DIFlagTypePassByValue, elements: !28, identifier: ".?AUInner@WrapStruct@@")
110+
!26 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "WrapStruct", file: !1, line: 4, size: 8, flags: DIFlagTypePassByValue, elements: !27, identifier: ".?AUWrapStruct@@")
111+
!27 = !{!25}
112+
!28 = !{!29}
113+
!29 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !25, file: !1, line: 5, baseType: !6, size: 32)
114+
!30 = !DILocation(line: 18, scope: !15)
115+
!31 = !DILocalVariable(name: "v3", scope: !15, file: !1, line: 19, type: !32)
116+
!32 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "Inner", scope: !33, file: !1, line: 8, size: 32, flags: DIFlagTypePassByValue, elements: !35, identifier: ".?AVInner@WrapClass@@")
117+
!33 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "WrapClass", file: !1, line: 7, size: 8, flags: DIFlagTypePassByValue, elements: !34, identifier: ".?AUWrapClass@@")
118+
!34 = !{!32}
119+
!35 = !{!36}
120+
!36 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !32, file: !1, line: 8, baseType: !6, size: 32, flags: DIFlagPublic)
121+
!37 = !DILocation(line: 19, scope: !15)
122+
!38 = !DILocalVariable(name: "v4", scope: !15, file: !1, line: 20, type: !3)
123+
!39 = !DILocation(line: 20, scope: !15)
124+
!40 = !DILocalVariable(name: "v5", scope: !15, file: !1, line: 21, type: !41)
125+
!41 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "Inner", scope: !42, file: !1, line: 14, size: 32, flags: DIFlagTypePassByValue, elements: !44, identifier: ".?ATInner@WrapUnion@@")
126+
!42 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "WrapUnion", file: !1, line: 13, size: 8, flags: DIFlagTypePassByValue, elements: !43, identifier: ".?AUWrapUnion@@")
127+
!43 = !{!41}
128+
!44 = !{!45, !46}
129+
!45 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !41, file: !1, line: 14, baseType: !6, size: 32)
130+
!46 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !41, file: !1, line: 14, baseType: !47, size: 32)
131+
!47 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
132+
!48 = !DILocation(line: 21, scope: !15)
133+
!49 = !DILocation(line: 22, scope: !15)

0 commit comments

Comments
 (0)