[llvm] r312583 - [CodeView] Don't output S_UDTs for nested typedefs.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 5 15:06:39 PDT 2017


Author: zturner
Date: Tue Sep  5 15:06:39 2017
New Revision: 312583

URL: http://llvm.org/viewvc/llvm-project?rev=312583&view=rev
Log:
[CodeView] Don't output S_UDTs for nested typedefs.

S_UDT records are basically the "bridge" between the debugger's
expression evaluator and the type information. If you type
(Foo*)nullptr into the watch window, the debugger looks for an
S_UDT record named Foo. If it can find one, it displays your type.
Otherwise you get an error.

We have always understood this to mean that if you have code like
this:

  struct A {
    int X;
  };

  struct B {
    typedef A AT;
    AT Member;
  };

that you will get 3 S_UDT records. "A", "B", and "B::AT". Because
if you were to type (B::AT*)nullptr into the debugger, it would
need to find an S_UDT record named "B::AT".

But "B::AT" is actually the S_UDT record that would be generated
if B were a namespace, not a struct. So the debugger needs to be
able to distinguish this case. So what it does is:

  1. Look for an S_UDT named "B::AT". If it finds one, it knows
     that AT is in a namespace.
  2. If it doesn't find one, split at the scope resolution operator,
     and look for an S_UDT named B. If it finds one, look up the type
     for B, and then look for AT as one of its members.

With this algorithm, S_UDT records for nested typedefs are not just
unnecessary, but actually wrong!

The results of implementing this in clang are dramatic. It cuts
our /DEBUG:FASTLINK PDB sizes by more than 50%, and we go from
being ~20% larger than MSVC PDBs on average, to ~40% smaller.

It also slightly speeds up link time. We get about 10% faster
links than without this patch.

Differential Revision: https://reviews.llvm.org/D37410

Modified:
    llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
    llvm/trunk/test/DebugInfo/COFF/udts.ll

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp?rev=312583&r1=312582&r2=312583&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp Tue Sep  5 15:06:39 2017
@@ -1139,6 +1139,21 @@ void CodeViewDebug::beginFunctionImpl(co
 }
 
 static bool shouldEmitUdt(const DIType *T) {
+  if (!T)
+    return false;
+
+  // MSVC does not emit UDTs for typedefs that are scoped to classes.
+  if (T->getTag() == dwarf::DW_TAG_typedef) {
+    if (DIScope *Scope = T->getScope().resolve()) {
+      switch (Scope->getTag()) {
+      case dwarf::DW_TAG_structure_type:
+      case dwarf::DW_TAG_class_type:
+      case dwarf::DW_TAG_union_type:
+        return false;
+      }
+    }
+  }
+
   while (true) {
     if (!T || T->isForwardDecl())
       return false;

Modified: llvm/trunk/test/DebugInfo/COFF/udts.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/udts.ll?rev=312583&r1=312582&r2=312583&view=diff
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/udts.ll (original)
+++ llvm/trunk/test/DebugInfo/COFF/udts.ll Tue Sep  5 15:06:39 2017
@@ -1,11 +1,9 @@
 ; RUN: llc < %s -filetype=obj > %t.obj
 ; RUN: llvm-readobj -codeview %t.obj | FileCheck --check-prefix=READOBJ %s
-; RUN: llvm-pdbutil dump -udt-stats %t.obj | FileCheck --check-prefix=PDBUTIL %s
+; RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck --check-prefix=PDBUTIL %s
 
-source_filename = "test/DebugInfo/COFF/udts.ll"
-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.0"
-; C++ source to regenerate:
+; C++ to regenerate:
+; $ clang -g -gcodeview -m64 -S -emit-llvm t.cpp
 ; $ cat t.cpp
 ; void f() {
 ;   typedef int FOO;
@@ -18,9 +16,20 @@ target triple = "i686-pc-windows-msvc18.
 ;   p.x = s->x;
 ;   return p.f;
 ; }
+; struct A {
+;   // We should not output S_UDT for nested typedef.
+;   typedef S C;
+;   C c;
+;   // We should output S_UDT for typedef of nested unnamed struct
+;   typedef struct { long X; } D;
+;   D d;
+; };
+; A a;
+; 
 ; typedef struct { int x; } U;
 ; U u;
 
+; READOBJ-NOT:  UDTName: A::C
 ; READOBJ:      {{.*}}Proc{{.*}}Sym {
 ; READOBJ:        DisplayName: f
 ; READOBJ:        LinkageName: ?f@@YAXXZ
@@ -51,108 +60,134 @@ target triple = "i686-pc-windows-msvc18.
 ; READOBJ-NEXT: UDTName: S
 ; READOBJ:      UDTSym {
 ; READOBJ-NEXT:   Kind: S_UDT (0x1108)
-; READOBJ-NEXT: Type: <unnamed-tag> (0x{{[0-9A-F]+}})
+; READOBJ-NEXT: Type: A (0x{{[0-9A-F]+}})
+; READOBJ-NEXT: UDTName: A
+; READOBJ:      UDTSym {
+; READOBJ-NEXT:   Kind: S_UDT (0x1108)
+; READOBJ-NEXT: Type: A::D (0x{{[0-9A-F]+}})
+; READOBJ-NEXT: UDTName: A::D
+; READOBJ:      UDTSym {
+; READOBJ-NEXT:   Kind: S_UDT (0x1108)
+; READOBJ-NEXT: Type: U (0x{{[0-9A-F]+}})
 ; READOBJ-NEXT: UDTName: U
-; READOBJ-NOT:  UDTSym {
+; READOBJ:      UDTSym {
+; READOBJ-NEXT:   Kind: S_UDT (0x1108)
+; READOBJ-NEXT: Type: U (0x{{[0-9A-F]+}})
+; READOBJ-NEXT: UDTName: U
+; READOBJ-NOT: UDTSym
 
-; PDBUTIL:                           S_UDT Record Stats
+; PDBUTIL:                           Symbols
 ; PDBUTIL-NEXT: ============================================================
-; PDBUTIL:             Record Kind | Count  Size
-; PDBUTIL-NEXT:     -----------------------------
-; PDBUTIL-NEXT:           LF_UNION |     1    24
-; PDBUTIL-NEXT:      <simple type> |     1     0
-; PDBUTIL-NEXT:       LF_STRUCTURE |     2    76
-; PDBUTIL-NEXT:     -----------------------------
-; PDBUTIL-NEXT:      Total (S_UDT) |     4    50
-; PDBUTIL-NEXT:     -----------------------------
-; PDBUTIL-NEXT:      namespace 'f' |     1     0
-; PDBUTIL-NEXT:      namespace 'g' |     1    24
+; PDBUTIL-NOT:   S_UDT {{.*}} `A::C`
+; PDBUTIL:       S_UDT [size = 15] `f::FOO`
+; PDBUTIL:       S_UDT [size = 15] `g::pun`
+; PDBUTIL:       S_UDT [size = 10] `S`
+; PDBUTIL:       S_UDT [size = 10] `A`
+; PDBUTIL:       S_UDT [size = 13] `A::D`
+; PDBUTIL:       S_UDT [size = 10] `U`
+; PDBUTIL:       S_UDT [size = 10] `U`
 
-%struct.U = type { i32 }
+source_filename = "test/DebugInfo/COFF/udts.ll"
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.11.25506"
+
+%struct.A = type { %struct.S, %"struct.A::D" }
 %struct.S = type { i32 }
+%"struct.A::D" = type { i32 }
+%struct.U = type { i32 }
 %union.pun = type { i32 }
 
-@"\01?u@@3UU@@A" = global %struct.U zeroinitializer, align 4, !dbg !0
+@"\01?a@@3UA@@A" = global %struct.A zeroinitializer, align 4, !dbg !0
+@"\01?u@@3UU@@A" = global %struct.U zeroinitializer, align 4, !dbg !6
 
-; Function Attrs: nounwind uwtable
-define void @"\01?f@@YAXXZ"() #0 !dbg !15 {
-entry:
-  %f = alloca i32, align 4
-  call void @llvm.dbg.declare(metadata i32* %f, metadata !18, metadata !20), !dbg !21
-  ret void, !dbg !22
+; Function Attrs: noinline nounwind optnone uwtable
+define void @"\01?f@@YAXXZ"() #0 !dbg !31 {
+  %1 = alloca i32, align 4
+  call void @llvm.dbg.declare(metadata i32* %1, metadata !34, metadata !DIExpression()), !dbg !36
+  ret void, !dbg !37
 }
 
-; Function Attrs: nounwind readnone
+; Function Attrs: nounwind readnone speculatable
 declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
 
-; Function Attrs: nounwind uwtable
-define float @"\01?g@@YAMPEAUS@@@Z"(%struct.S* %s) #0 !dbg !23 {
-entry:
-  %s.addr = alloca %struct.S*, align 8
-  %p = alloca %union.pun, align 4
-  store %struct.S* %s, %struct.S** %s.addr, align 8
-  call void @llvm.dbg.declare(metadata %struct.S** %s.addr, metadata !31, metadata !20), !dbg !32
-  call void @llvm.dbg.declare(metadata %union.pun* %p, metadata !33, metadata !20), !dbg !38
-  %0 = load %struct.S*, %struct.S** %s.addr, align 8, !dbg !39
-  %x = getelementptr inbounds %struct.S, %struct.S* %0, i32 0, i32 0, !dbg !40
-  %1 = load i32, i32* %x, align 4, !dbg !40
-  %x1 = bitcast %union.pun* %p to i32*, !dbg !41
-  store i32 %1, i32* %x1, align 4, !dbg !42
-  %f = bitcast %union.pun* %p to float*, !dbg !43
-  %2 = load float, float* %f, align 4, !dbg !43
-  ret float %2, !dbg !44
+; Function Attrs: noinline nounwind optnone uwtable
+define float @"\01?g@@YAMPEAUS@@@Z"(%struct.S*) #0 !dbg !38 {
+  %2 = alloca %struct.S*, align 8
+  %3 = alloca %union.pun, align 4
+  store %struct.S* %0, %struct.S** %2, align 8
+  call void @llvm.dbg.declare(metadata %struct.S** %2, metadata !43, metadata !DIExpression()), !dbg !44
+  call void @llvm.dbg.declare(metadata %union.pun* %3, metadata !45, metadata !DIExpression()), !dbg !50
+  %4 = load %struct.S*, %struct.S** %2, align 8, !dbg !51
+  %5 = getelementptr inbounds %struct.S, %struct.S* %4, i32 0, i32 0, !dbg !52
+  %6 = load i32, i32* %5, align 4, !dbg !52
+  %7 = bitcast %union.pun* %3 to i32*, !dbg !53
+  store i32 %6, i32* %7, align 4, !dbg !54
+  %8 = bitcast %union.pun* %3 to float*, !dbg !55
+  %9 = load float, float* %8, align 4, !dbg !55
+  ret float %9, !dbg !56
 }
 
-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" }
-attributes #1 = { nounwind readnone }
+attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "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" "no-signed-zeros-fp-math"="false" "no-trapping-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" }
+attributes #1 = { nounwind readnone speculatable }
 
 !llvm.dbg.cu = !{!2}
-!llvm.module.flags = !{!11, !12, !13}
-!llvm.ident = !{!14}
+!llvm.module.flags = !{!26, !27, !28, !29}
+!llvm.ident = !{!30}
 
-!0 = distinct !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
-!1 = !DIGlobalVariable(name: "u", linkageName: "\01?u@@3UU@@A", scope: !2, file: !3, line: 13, type: !6, isLocal: false, isDefinition: true)
-!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 3.9.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5)
-!3 = !DIFile(filename: "t.cpp", directory: "D:\5Csrc\5Cllvm\5Cbuild")
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "a", linkageName: "\01?a@@3UA@@A", scope: !2, file: !3, line: 21, type: !13, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang version 6.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5)
+!3 = !DIFile(filename: "t.cpp", directory: "D:\5Csrc\5Cllvmbuild\5Cninja-release", checksumkind: CSK_MD5, checksum: "e894de94ed2e0d503ebb5dbcc550c544")
 !4 = !{}
-!5 = !{!0}
-!6 = !DIDerivedType(tag: DW_TAG_typedef, name: "U", file: !3, line: 12, baseType: !7)
-!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 12, size: 32, align: 32, elements: !8, identifier: ".?AUU@@")
-!8 = !{!9}
-!9 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !7, file: !3, line: 12, baseType: !10, size: 32, align: 32)
-!10 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
-!11 = !{i32 2, !"CodeView", i32 1}
-!12 = !{i32 2, !"Debug Info Version", i32 3}
-!13 = !{i32 1, !"PIC Level", i32 2}
-!14 = !{!"clang version 3.9.0 "}
-!15 = distinct !DISubprogram(name: "f", linkageName: "\01?f@@YAXXZ", scope: !3, file: !3, line: 1, type: !16, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !2, variables: !4)
-!16 = !DISubroutineType(types: !17)
-!17 = !{null}
-!18 = !DILocalVariable(name: "f", scope: !15, file: !3, line: 3, type: !19)
-!19 = !DIDerivedType(tag: DW_TAG_typedef, name: "FOO", scope: !15, file: !3, line: 2, baseType: !10)
-!20 = !DIExpression()
-!21 = !DILocation(line: 3, column: 7, scope: !15)
-!22 = !DILocation(line: 4, column: 1, scope: !15)
-!23 = distinct !DISubprogram(name: "g", linkageName: "\01?g@@YAMPEAUS@@@Z", scope: !3, file: !3, line: 7, type: !24, isLocal: false, isDefinition: true, scopeLine: 7, flags: DIFlagPrototyped, isOptimized: false, unit: !2, variables: !4)
-!24 = !DISubroutineType(types: !25)
-!25 = !{!26, !27}
-!26 = !DIBasicType(name: "float", size: 32, align: 32, encoding: DW_ATE_float)
-!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !28, size: 64, align: 64)
-!28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !3, line: 6, size: 32, align: 32, elements: !29, identifier: ".?AUS@@")
-!29 = !{!30}
-!30 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !28, file: !3, line: 6, baseType: !10, size: 32, align: 32)
-!31 = !DILocalVariable(name: "s", arg: 1, scope: !23, file: !3, line: 7, type: !27)
-!32 = !DILocation(line: 7, column: 12, scope: !23)
-!33 = !DILocalVariable(name: "p", scope: !23, file: !3, line: 8, type: !34)
-!34 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "pun", scope: !23, file: !3, line: 8, size: 32, align: 32, elements: !35)
-!35 = !{!36, !37}
-!36 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !34, file: !3, line: 8, baseType: !10, size: 32, align: 32)
-!37 = !DIDerivedType(tag: DW_TAG_member, name: "f", scope: !34, file: !3, line: 8, baseType: !26, size: 32, align: 32)
-!38 = !DILocation(line: 8, column: 33, scope: !23)
-!39 = !DILocation(line: 9, column: 9, scope: !23)
-!40 = !DILocation(line: 9, column: 12, scope: !23)
-!41 = !DILocation(line: 9, column: 5, scope: !23)
-!42 = !DILocation(line: 9, column: 7, scope: !23)
-!43 = !DILocation(line: 10, column: 12, scope: !23)
-!44 = !DILocation(line: 10, column: 3, scope: !23)
-
+!5 = !{!0, !6}
+!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression())
+!7 = distinct !DIGlobalVariable(name: "u", linkageName: "\01?u@@3UU@@A", scope: !2, file: !3, line: 24, type: !8, isLocal: false, isDefinition: true)
+!8 = !DIDerivedType(tag: DW_TAG_typedef, name: "U", file: !3, line: 23, baseType: !9)
+!9 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "U", file: !3, line: 23, size: 32, elements: !10, identifier: ".?AUU@@")
+!10 = !{!11}
+!11 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !9, file: !3, line: 23, baseType: !12, size: 32)
+!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !3, line: 13, size: 64, elements: !14, identifier: ".?AUA@@")
+!14 = !{!15, !19, !20, !24, !25}
+!15 = !DIDerivedType(tag: DW_TAG_typedef, name: "C", scope: !13, file: !3, line: 15, baseType: !16)
+!16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !3, line: 6, size: 32, elements: !17, identifier: ".?AUS@@")
+!17 = !{!18}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !16, file: !3, line: 6, baseType: !12, size: 32)
+!19 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !13, file: !3, line: 16, baseType: !15, size: 32)
+!20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "D", scope: !13, file: !3, line: 18, size: 32, elements: !21, identifier: ".?AUD at A@@")
+!21 = !{!22}
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "X", scope: !20, file: !3, line: 18, baseType: !23, size: 32)
+!23 = !DIBasicType(name: "long int", size: 32, encoding: DW_ATE_signed)
+!24 = !DIDerivedType(tag: DW_TAG_typedef, name: "D", scope: !13, file: !3, line: 18, baseType: !20)
+!25 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !13, file: !3, line: 19, baseType: !24, size: 32, offset: 32)
+!26 = !{i32 2, !"CodeView", i32 1}
+!27 = !{i32 2, !"Debug Info Version", i32 3}
+!28 = !{i32 1, !"wchar_size", i32 2}
+!29 = !{i32 7, !"PIC Level", i32 2}
+!30 = !{!"clang version 6.0.0 "}
+!31 = distinct !DISubprogram(name: "f", linkageName: "\01?f@@YAXXZ", scope: !3, file: !3, line: 1, type: !32, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !2, variables: !4)
+!32 = !DISubroutineType(types: !33)
+!33 = !{null}
+!34 = !DILocalVariable(name: "f", scope: !31, file: !3, line: 3, type: !35)
+!35 = !DIDerivedType(tag: DW_TAG_typedef, name: "FOO", scope: !31, file: !3, line: 2, baseType: !12)
+!36 = !DILocation(line: 3, column: 7, scope: !31)
+!37 = !DILocation(line: 4, column: 1, scope: !31)
+!38 = distinct !DISubprogram(name: "g", linkageName: "\01?g@@YAMPEAUS@@@Z", scope: !3, file: !3, line: 7, type: !39, isLocal: false, isDefinition: true, scopeLine: 7, flags: DIFlagPrototyped, isOptimized: false, unit: !2, variables: !4)
+!39 = !DISubroutineType(types: !40)
+!40 = !{!41, !42}
+!41 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
+!42 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64)
+!43 = !DILocalVariable(name: "s", arg: 1, scope: !38, file: !3, line: 7, type: !42)
+!44 = !DILocation(line: 7, column: 12, scope: !38)
+!45 = !DILocalVariable(name: "p", scope: !38, file: !3, line: 8, type: !46)
+!46 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "pun", scope: !38, file: !3, line: 8, size: 32, elements: !47)
+!47 = !{!48, !49}
+!48 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !46, file: !3, line: 8, baseType: !12, size: 32)
+!49 = !DIDerivedType(tag: DW_TAG_member, name: "f", scope: !46, file: !3, line: 8, baseType: !41, size: 32)
+!50 = !DILocation(line: 8, column: 33, scope: !38)
+!51 = !DILocation(line: 9, column: 9, scope: !38)
+!52 = !DILocation(line: 9, column: 12, scope: !38)
+!53 = !DILocation(line: 9, column: 5, scope: !38)
+!54 = !DILocation(line: 9, column: 7, scope: !38)
+!55 = !DILocation(line: 10, column: 12, scope: !38)
+!56 = !DILocation(line: 10, column: 3, scope: !38)
\ No newline at end of file




More information about the llvm-commits mailing list