[llvm] r356692 - [llvm-pdbutil] Add -type-ref-stats to help find unused type info

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 21 11:02:35 PDT 2019


Author: rnk
Date: Thu Mar 21 11:02:34 2019
New Revision: 356692

URL: http://llvm.org/viewvc/llvm-project?rev=356692&view=rev
Log:
[llvm-pdbutil] Add -type-ref-stats to help find unused type info

Summary:
This considers module symbol streams and the global symbol stream to be
roots. Most types that this considers "unreferenced" are referenced by
LF_UDT_MOD_SRC_LINE id records, which VC seems to always include.
Essentially, they are types that the user can only find in the debugger
if they call them by name, they cannot be found by traversing a symbol.

In practice, around 80% of type information in a PDB is referenced by a
symbol. That seems like a reasonable number.

I don't really plan to do anything with this tool. It mostly just exists
for informational purposes, and to confirm that we probably don't need
to implement type reference tracking in LLD. We can continue to merge
all types as we do today without wasting space.

Reviewers: zturner, aganea

Subscribers: mgorny, hiraditya, arphaman, jdoerfert, llvm-commits

Tags: #llvm

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

Added:
    llvm/trunk/test/DebugInfo/PDB/pdb-type-ref-stats.test
    llvm/trunk/tools/llvm-pdbutil/TypeReferenceTracker.cpp
    llvm/trunk/tools/llvm-pdbutil/TypeReferenceTracker.h
Modified:
    llvm/trunk/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
    llvm/trunk/tools/llvm-pdbutil/CMakeLists.txt
    llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp
    llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.h
    llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp
    llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h
    llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp
    llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h

Modified: llvm/trunk/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp?rev=356692&r1=356691&r2=356692&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp Thu Mar 21 11:02:34 2019
@@ -363,14 +363,16 @@ static bool discoverTypeIndices(ArrayRef
   // values.  One idea is to define some structures representing these types
   // that would allow the use of offsetof().
   switch (Kind) {
-  case SymbolKind::S_GPROC32:
-  case SymbolKind::S_LPROC32:
   case SymbolKind::S_GPROC32_ID:
   case SymbolKind::S_LPROC32_ID:
   case SymbolKind::S_LPROC32_DPC:
   case SymbolKind::S_LPROC32_DPC_ID:
     Refs.push_back({TiRefKind::IndexRef, 24, 1}); // LF_FUNC_ID
     break;
+  case SymbolKind::S_GPROC32:
+  case SymbolKind::S_LPROC32:
+    Refs.push_back({TiRefKind::TypeRef, 24, 1}); // Type
+    break;
   case SymbolKind::S_UDT:
     Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UDT
     break;

Added: llvm/trunk/test/DebugInfo/PDB/pdb-type-ref-stats.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/pdb-type-ref-stats.test?rev=356692&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/PDB/pdb-type-ref-stats.test (added)
+++ llvm/trunk/test/DebugInfo/PDB/pdb-type-ref-stats.test Thu Mar 21 11:02:34 2019
@@ -0,0 +1,577 @@
+RUN: llvm-pdbutil dump -types -type-ref-stats %p/Inputs/every-class.pdb \
+RUN:   | FileCheck %s
+
+CHECK:                      Types (TPI Stream)                     
+CHECK: ============================================================
+CHECK:   Showing 157 records
+CHECK:   0x1000 | LF_ARGLIST [size = 16, referenced]
+CHECK:            0x0603 (void*): `void*`
+CHECK:            0x0023 (unsigned __int64): `unsigned __int64`
+CHECK:   0x1001 | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 2, param list = 0x1000
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x1002 | LF_ARGLIST [size = 16, referenced]
+CHECK:            0x0603 (void*): `void*`
+CHECK:            0x0075 (unsigned): `unsigned`
+CHECK:   0x1003 | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 2, param list = 0x1002
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x1004 | LF_POINTER [size = 12, referenced]
+CHECK:            referent = 0x0670 (char*), mode = pointer, opts = None, kind = ptr64
+CHECK:   0x1005 | LF_ARGLIST [size = 16, referenced]
+CHECK:            0x0074 (int): `int`
+CHECK:            0x1004: `char**`
+CHECK:   0x1006 | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0074 (int), # args = 2, param list = 0x1005
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x1007 | LF_FIELDLIST [size = 4, referenced]
+CHECK:   0x1008 | LF_STRUCTURE [size = 124, referenced] `main::__l2::<unnamed-type-Anonymous>`
+CHECK:            unique name: `.?AU<unnamed-type-Anonymous>@?1??main@@YAHHPEAPEAD at Z@`aa6523bc`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1007
+CHECK:            options: has unique name | scoped, sizeof 1
+CHECK:   0x1009 | LF_STRUCTURE [size = 88, referenced] `main::__l2::Scoped`
+CHECK:            unique name: `.?AUScoped@?1??main@@YAHHPEAPEAD at Z@`aa6523bc`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1007
+CHECK:            options: has unique name | scoped, sizeof 1
+CHECK:   0x100A | LF_FIELDLIST [size = 48, unreferenced]
+CHECK:            - LF_ENUMERATE [native = 0]
+CHECK:            - LF_ENUMERATE [com = 1]
+CHECK:            - LF_ENUMERATE [managed = 2]
+CHECK:   0x100B | LF_ENUM [size = 116, unreferenced] `__vc_attributes::event_sourceAttribute::type_e`
+CHECK:            unique name: `.?AW4type_e at event_sourceAttribute@__vc_attributes@@`
+CHECK:            field list: 0x100A, underlying type: 0x0074 (int)
+CHECK:            options: has unique name | is nested
+CHECK:   0x100C | LF_FIELDLIST [size = 28, unreferenced]
+CHECK:            - LF_ENUMERATE [speed = 0]
+CHECK:            - LF_ENUMERATE [size = 1]
+CHECK:   0x100D | LF_ENUM [size = 124, unreferenced] `__vc_attributes::event_sourceAttribute::optimize_e`
+CHECK:            unique name: `.?AW4optimize_e at event_sourceAttribute@__vc_attributes@@`
+CHECK:            field list: 0x100C, underlying type: 0x0074 (int)
+CHECK:            options: has unique name | is nested
+CHECK:   0x100E | LF_STRUCTURE [size = 108, unreferenced] `__vc_attributes::event_sourceAttribute`
+CHECK:            unique name: `.?AUevent_sourceAttribute at __vc_attributes@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (-> 0x1016) | has unique name, sizeof 0
+CHECK:   0x100F | LF_POINTER [size = 12, unreferenced]
+CHECK:            referent = 0x100E, mode = pointer, opts = const, kind = ptr64
+CHECK:   0x1010 | LF_ARGLIST [size = 12, unreferenced]
+CHECK:            0x100B: `__vc_attributes::event_sourceAttribute::type_e`
+CHECK:   0x1011 | LF_MFUNCTION [size = 28, unreferenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x1010
+CHECK:            class type = 0x100E, this type = 0x100F, this adjust = 0
+CHECK:            calling conv = cdecl, options = constructor
+CHECK:   0x1012 | LF_ARGLIST [size = 8, referenced]
+CHECK:   0x1013 | LF_MFUNCTION [size = 28, unreferenced]
+CHECK:            return type = 0x0003 (void), # args = 0, param list = 0x1012
+CHECK:            class type = 0x100E, this type = 0x100F, this adjust = 0
+CHECK:            calling conv = cdecl, options = constructor
+CHECK:   0x1014 | LF_METHODLIST [size = 20, unreferenced]
+CHECK:            - Method [type = 0x1011, vftable offset = -1, attrs = public]
+CHECK:            - Method [type = 0x1013, vftable offset = -1, attrs = public]
+CHECK:   0x1015 | LF_FIELDLIST [size = 128, unreferenced]
+CHECK:            - LF_NESTTYPE [name = `type_e`, parent = 0x100B]
+CHECK:            - LF_NESTTYPE [name = `optimize_e`, parent = 0x100D]
+CHECK:            - LF_METHOD [name = `event_sourceAttribute`, # overloads = 2, overload list = 0x1014]
+CHECK:            - LF_MEMBER [name = `type`, Type = 0x100B, offset = 0, attrs = public]
+CHECK:            - LF_MEMBER [name = `optimize`, Type = 0x100D, offset = 4, attrs = public]
+CHECK:            - LF_MEMBER [name = `decorate`, Type = 0x0030 (bool), offset = 8, attrs = public]
+CHECK:   0x1016 | LF_STRUCTURE [size = 108, unreferenced] `__vc_attributes::event_sourceAttribute`
+CHECK:            unique name: `.?AUevent_sourceAttribute at __vc_attributes@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1015
+CHECK:            options: has ctor / dtor | contains nested class | has unique name, sizeof 12
+CHECK:   0x1017 | LF_FIELDLIST [size = 68, unreferenced]
+CHECK:            - LF_ENUMERATE [eBoolean = 0]
+CHECK:            - LF_ENUMERATE [eInteger = 1]
+CHECK:            - LF_ENUMERATE [eFloat = 2]
+CHECK:            - LF_ENUMERATE [eDouble = 3]
+CHECK:   0x1018 | LF_ENUM [size = 148, unreferenced] `__vc_attributes::helper_attributes::v1_alttypeAttribute::type_e`
+CHECK:            unique name: `.?AW4type_e at v1_alttypeAttribute@helper_attributes at __vc_attributes@@`
+CHECK:            field list: 0x1017, underlying type: 0x0074 (int)
+CHECK:            options: has unique name | is nested
+CHECK:   0x1019 | LF_STRUCTURE [size = 140, unreferenced] `__vc_attributes::helper_attributes::v1_alttypeAttribute`
+CHECK:            unique name: `.?AUv1_alttypeAttribute at helper_attributes@__vc_attributes@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (-> 0x101E) | has unique name, sizeof 0
+CHECK:   0x101A | LF_POINTER [size = 12, unreferenced]
+CHECK:            referent = 0x1019, mode = pointer, opts = const, kind = ptr64
+CHECK:   0x101B | LF_ARGLIST [size = 12, unreferenced]
+CHECK:            0x1018: `__vc_attributes::helper_attributes::v1_alttypeAttribute::type_e`
+CHECK:   0x101C | LF_MFUNCTION [size = 28, unreferenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x101B
+CHECK:            class type = 0x1019, this type = 0x101A, this adjust = 0
+CHECK:            calling conv = cdecl, options = constructor
+CHECK:   0x101D | LF_FIELDLIST [size = 64, unreferenced]
+CHECK:            - LF_NESTTYPE [name = `type_e`, parent = 0x1018]
+CHECK:            - LF_ONEMETHOD [name = `v1_alttypeAttribute`]
+CHECK:              type = 0x101C, vftable offset = -1, attrs = public
+CHECK:            - LF_MEMBER [name = `type`, Type = 0x1018, offset = 0, attrs = public]
+CHECK:   0x101E | LF_STRUCTURE [size = 140, unreferenced] `__vc_attributes::helper_attributes::v1_alttypeAttribute`
+CHECK:            unique name: `.?AUv1_alttypeAttribute at helper_attributes@__vc_attributes@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x101D
+CHECK:            options: has ctor / dtor | contains nested class | has unique name, sizeof 4
+CHECK:   0x101F | LF_FIELDLIST [size = 756, unreferenced]
+CHECK:            - LF_ENUMERATE [eAnyUsage = 0]
+CHECK:            - LF_ENUMERATE [eCoClassUsage = 1]
+CHECK:            - LF_ENUMERATE [eCOMInterfaceUsage = 2]
+CHECK:            - LF_ENUMERATE [eInterfaceUsage = 6]
+CHECK:            - LF_ENUMERATE [eMemberUsage = 8]
+CHECK:            - LF_ENUMERATE [eMethodUsage = 16]
+CHECK:            - LF_ENUMERATE [eInterfaceMethodUsage = 32]
+CHECK:            - LF_ENUMERATE [eInterfaceMemberUsage = 64]
+CHECK:            - LF_ENUMERATE [eCoClassMemberUsage = 128]
+CHECK:            - LF_ENUMERATE [eCoClassMethodUsage = 256]
+CHECK:            - LF_ENUMERATE [eGlobalMethodUsage = 768]
+CHECK:            - LF_ENUMERATE [eGlobalDataUsage = 1024]
+CHECK:            - LF_ENUMERATE [eClassUsage = 2048]
+CHECK:            - LF_ENUMERATE [eInterfaceParameterUsage = 4096]
+CHECK:            - LF_ENUMERATE [eMethodParameterUsage = 12288]
+CHECK:            - LF_ENUMERATE [eIDLModuleUsage = 16384]
+CHECK:            - LF_ENUMERATE [eAnonymousUsage = 32768]
+CHECK:            - LF_ENUMERATE [eTypedefUsage = 65536]
+CHECK:            - LF_ENUMERATE [eUnionUsage = 131072]
+CHECK:            - LF_ENUMERATE [eEnumUsage = 262144]
+CHECK:            - LF_ENUMERATE [eDefineTagUsage = 524288]
+CHECK:            - LF_ENUMERATE [eStructUsage = 1048576]
+CHECK:            - LF_ENUMERATE [eLocalUsage = 2097152]
+CHECK:            - LF_ENUMERATE [ePropertyUsage = 4194304]
+CHECK:            - LF_ENUMERATE [eEventUsage = 8388608]
+CHECK:            - LF_ENUMERATE [eTemplateUsage = 16777216]
+CHECK:            - LF_ENUMERATE [eModuleUsage = 16777216]
+CHECK:            - LF_ENUMERATE [eIllegalUsage = 33554432]
+CHECK:            - LF_ENUMERATE [eAsynchronousUsage = 67108864]
+CHECK:            - LF_ENUMERATE [eAnyIDLUsage = 4161535]
+CHECK:   0x1020 | LF_ENUM [size = 140, unreferenced] `__vc_attributes::helper_attributes::usageAttribute::usage_e`
+CHECK:            unique name: `.?AW4usage_e at usageAttribute@helper_attributes at __vc_attributes@@`
+CHECK:            field list: 0x101F, underlying type: 0x0074 (int)
+CHECK:            options: has unique name | is nested
+CHECK:   0x1021 | LF_STRUCTURE [size = 128, unreferenced] `__vc_attributes::helper_attributes::usageAttribute`
+CHECK:            unique name: `.?AUusageAttribute at helper_attributes@__vc_attributes@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (-> 0x1026) | has unique name, sizeof 0
+CHECK:   0x1022 | LF_POINTER [size = 12, unreferenced]
+CHECK:            referent = 0x1021, mode = pointer, opts = const, kind = ptr64
+CHECK:   0x1023 | LF_ARGLIST [size = 12, unreferenced]
+CHECK:            0x0075 (unsigned): `unsigned`
+CHECK:   0x1024 | LF_MFUNCTION [size = 28, unreferenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x1023
+CHECK:            class type = 0x1021, this type = 0x1022, this adjust = 0
+CHECK:            calling conv = cdecl, options = constructor
+CHECK:   0x1025 | LF_FIELDLIST [size = 60, unreferenced]
+CHECK:            - LF_NESTTYPE [name = `usage_e`, parent = 0x1020]
+CHECK:            - LF_ONEMETHOD [name = `usageAttribute`]
+CHECK:              type = 0x1024, vftable offset = -1, attrs = public
+CHECK:            - LF_MEMBER [name = `value`, Type = 0x0075 (unsigned), offset = 0, attrs = public]
+CHECK:   0x1026 | LF_STRUCTURE [size = 128, unreferenced] `__vc_attributes::helper_attributes::usageAttribute`
+CHECK:            unique name: `.?AUusageAttribute at helper_attributes@__vc_attributes@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1025
+CHECK:            options: has ctor / dtor | contains nested class | has unique name, sizeof 4
+CHECK:   0x1027 | LF_FIELDLIST [size = 76, unreferenced]
+CHECK:            - LF_ENUMERATE [apartment = 1]
+CHECK:            - LF_ENUMERATE [single = 2]
+CHECK:            - LF_ENUMERATE [free = 3]
+CHECK:            - LF_ENUMERATE [neutral = 4]
+CHECK:            - LF_ENUMERATE [both = 5]
+CHECK:   0x1028 | LF_ENUM [size = 120, unreferenced] `__vc_attributes::threadingAttribute::threading_e`
+CHECK:            unique name: `.?AW4threading_e at threadingAttribute@__vc_attributes@@`
+CHECK:            field list: 0x1027, underlying type: 0x0074 (int)
+CHECK:            options: has unique name | is nested
+CHECK:   0x1029 | LF_STRUCTURE [size = 100, unreferenced] `__vc_attributes::threadingAttribute`
+CHECK:            unique name: `.?AUthreadingAttribute at __vc_attributes@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (-> 0x1030) | has unique name, sizeof 0
+CHECK:   0x102A | LF_POINTER [size = 12, unreferenced]
+CHECK:            referent = 0x1029, mode = pointer, opts = const, kind = ptr64
+CHECK:   0x102B | LF_ARGLIST [size = 12, unreferenced]
+CHECK:            0x1028: `__vc_attributes::threadingAttribute::threading_e`
+CHECK:   0x102C | LF_MFUNCTION [size = 28, unreferenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x102B
+CHECK:            class type = 0x1029, this type = 0x102A, this adjust = 0
+CHECK:            calling conv = cdecl, options = constructor
+CHECK:   0x102D | LF_MFUNCTION [size = 28, unreferenced]
+CHECK:            return type = 0x0003 (void), # args = 0, param list = 0x1012
+CHECK:            class type = 0x1029, this type = 0x102A, this adjust = 0
+CHECK:            calling conv = cdecl, options = constructor
+CHECK:   0x102E | LF_METHODLIST [size = 20, unreferenced]
+CHECK:            - Method [type = 0x102C, vftable offset = -1, attrs = public]
+CHECK:            - Method [type = 0x102D, vftable offset = -1, attrs = public]
+CHECK:   0x102F | LF_FIELDLIST [size = 68, unreferenced]
+CHECK:            - LF_NESTTYPE [name = `threading_e`, parent = 0x1028]
+CHECK:            - LF_METHOD [name = `threadingAttribute`, # overloads = 2, overload list = 0x102E]
+CHECK:            - LF_MEMBER [name = `value`, Type = 0x1028, offset = 0, attrs = public]
+CHECK:   0x1030 | LF_STRUCTURE [size = 100, unreferenced] `__vc_attributes::threadingAttribute`
+CHECK:            unique name: `.?AUthreadingAttribute at __vc_attributes@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x102F
+CHECK:            options: has ctor / dtor | contains nested class | has unique name, sizeof 4
+CHECK:   0x1031 | LF_FIELDLIST [size = 48, unreferenced]
+CHECK:            - LF_ENUMERATE [never = 0]
+CHECK:            - LF_ENUMERATE [allowed = 1]
+CHECK:            - LF_ENUMERATE [always = 2]
+CHECK:   0x1032 | LF_ENUM [size = 116, unreferenced] `__vc_attributes::aggregatableAttribute::type_e`
+CHECK:            unique name: `.?AW4type_e at aggregatableAttribute@__vc_attributes@@`
+CHECK:            field list: 0x1031, underlying type: 0x0074 (int)
+CHECK:            options: has unique name | is nested
+CHECK:   0x1033 | LF_STRUCTURE [size = 108, unreferenced] `__vc_attributes::aggregatableAttribute`
+CHECK:            unique name: `.?AUaggregatableAttribute at __vc_attributes@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (-> 0x103A) | has unique name, sizeof 0
+CHECK:   0x1034 | LF_POINTER [size = 12, unreferenced]
+CHECK:            referent = 0x1033, mode = pointer, opts = const, kind = ptr64
+CHECK:   0x1035 | LF_ARGLIST [size = 12, unreferenced]
+CHECK:            0x1032: `__vc_attributes::aggregatableAttribute::type_e`
+CHECK:   0x1036 | LF_MFUNCTION [size = 28, unreferenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x1035
+CHECK:            class type = 0x1033, this type = 0x1034, this adjust = 0
+CHECK:            calling conv = cdecl, options = constructor
+CHECK:   0x1037 | LF_MFUNCTION [size = 28, unreferenced]
+CHECK:            return type = 0x0003 (void), # args = 0, param list = 0x1012
+CHECK:            class type = 0x1033, this type = 0x1034, this adjust = 0
+CHECK:            calling conv = cdecl, options = constructor
+CHECK:   0x1038 | LF_METHODLIST [size = 20, unreferenced]
+CHECK:            - Method [type = 0x1036, vftable offset = -1, attrs = public]
+CHECK:            - Method [type = 0x1037, vftable offset = -1, attrs = public]
+CHECK:   0x1039 | LF_FIELDLIST [size = 68, unreferenced]
+CHECK:            - LF_NESTTYPE [name = `type_e`, parent = 0x1032]
+CHECK:            - LF_METHOD [name = `aggregatableAttribute`, # overloads = 2, overload list = 0x1038]
+CHECK:            - LF_MEMBER [name = `type`, Type = 0x1032, offset = 0, attrs = public]
+CHECK:   0x103A | LF_STRUCTURE [size = 108, unreferenced] `__vc_attributes::aggregatableAttribute`
+CHECK:            unique name: `.?AUaggregatableAttribute at __vc_attributes@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1039
+CHECK:            options: has ctor / dtor | contains nested class | has unique name, sizeof 4
+CHECK:   0x103B | LF_ENUM [size = 120, unreferenced] `__vc_attributes::event_receiverAttribute::type_e`
+CHECK:            unique name: `.?AW4type_e at event_receiverAttribute@__vc_attributes@@`
+CHECK:            field list: 0x100A, underlying type: 0x0074 (int)
+CHECK:            options: has unique name | is nested
+CHECK:   0x103C | LF_STRUCTURE [size = 112, unreferenced] `__vc_attributes::event_receiverAttribute`
+CHECK:            unique name: `.?AUevent_receiverAttribute at __vc_attributes@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (-> 0x1045) | has unique name, sizeof 0
+CHECK:   0x103D | LF_POINTER [size = 12, unreferenced]
+CHECK:            referent = 0x103C, mode = pointer, opts = const, kind = ptr64
+CHECK:   0x103E | LF_ARGLIST [size = 16, unreferenced]
+CHECK:            0x103B: `__vc_attributes::event_receiverAttribute::type_e`
+CHECK:            0x0030 (bool): `bool`
+CHECK:   0x103F | LF_MFUNCTION [size = 28, unreferenced]
+CHECK:            return type = 0x0003 (void), # args = 2, param list = 0x103E
+CHECK:            class type = 0x103C, this type = 0x103D, this adjust = 0
+CHECK:            calling conv = cdecl, options = constructor
+CHECK:   0x1040 | LF_ARGLIST [size = 12, unreferenced]
+CHECK:            0x103B: `__vc_attributes::event_receiverAttribute::type_e`
+CHECK:   0x1041 | LF_MFUNCTION [size = 28, unreferenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x1040
+CHECK:            class type = 0x103C, this type = 0x103D, this adjust = 0
+CHECK:            calling conv = cdecl, options = constructor
+CHECK:   0x1042 | LF_MFUNCTION [size = 28, unreferenced]
+CHECK:            return type = 0x0003 (void), # args = 0, param list = 0x1012
+CHECK:            class type = 0x103C, this type = 0x103D, this adjust = 0
+CHECK:            calling conv = cdecl, options = constructor
+CHECK:   0x1043 | LF_METHODLIST [size = 28, unreferenced]
+CHECK:            - Method [type = 0x103F, vftable offset = -1, attrs = public]
+CHECK:            - Method [type = 0x1041, vftable offset = -1, attrs = public]
+CHECK:            - Method [type = 0x1042, vftable offset = -1, attrs = public]
+CHECK:   0x1044 | LF_FIELDLIST [size = 96, unreferenced]
+CHECK:            - LF_NESTTYPE [name = `type_e`, parent = 0x103B]
+CHECK:            - LF_METHOD [name = `event_receiverAttribute`, # overloads = 3, overload list = 0x1043]
+CHECK:            - LF_MEMBER [name = `type`, Type = 0x103B, offset = 0, attrs = public]
+CHECK:            - LF_MEMBER [name = `layout_dependent`, Type = 0x0030 (bool), offset = 4, attrs = public]
+CHECK:   0x1045 | LF_STRUCTURE [size = 112, unreferenced] `__vc_attributes::event_receiverAttribute`
+CHECK:            unique name: `.?AUevent_receiverAttribute at __vc_attributes@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1044
+CHECK:            options: has ctor / dtor | contains nested class | has unique name, sizeof 8
+CHECK:   0x1046 | LF_FIELDLIST [size = 92, unreferenced]
+CHECK:            - LF_ENUMERATE [dll = 1]
+CHECK:            - LF_ENUMERATE [exe = 2]
+CHECK:            - LF_ENUMERATE [service = 3]
+CHECK:            - LF_ENUMERATE [unspecified = 4]
+CHECK:            - LF_ENUMERATE [EXE = 2]
+CHECK:            - LF_ENUMERATE [SERVICE = 3]
+CHECK:   0x1047 | LF_ENUM [size = 104, unreferenced] `__vc_attributes::moduleAttribute::type_e`
+CHECK:            unique name: `.?AW4type_e at moduleAttribute@__vc_attributes@@`
+CHECK:            field list: 0x1046, underlying type: 0x0074 (int)
+CHECK:            options: has unique name | is nested
+CHECK:   0x1048 | LF_STRUCTURE [size = 96, unreferenced] `__vc_attributes::moduleAttribute`
+CHECK:            unique name: `.?AUmoduleAttribute at __vc_attributes@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (-> 0x1053) | has unique name, sizeof 0
+CHECK:   0x1049 | LF_POINTER [size = 12, unreferenced]
+CHECK:            referent = 0x1048, mode = pointer, opts = const, kind = ptr64
+CHECK:   0x104A | LF_MODIFIER [size = 12, unreferenced]
+CHECK:            referent = 0x0070 (char), modifiers = const
+CHECK:   0x104B | LF_POINTER [size = 12, unreferenced]
+CHECK:            referent = 0x104A, mode = pointer, opts = None, kind = ptr64
+CHECK:   0x104C | LF_ARGLIST [size = 68, unreferenced]
+CHECK:            0x1047: `__vc_attributes::moduleAttribute::type_e`
+CHECK:            0x104B: `const char*`
+CHECK:            0x104B: `const char*`
+CHECK:            0x104B: `const char*`
+CHECK:            0x0074 (int): `int`
+CHECK:            0x0030 (bool): `bool`
+CHECK:            0x104B: `const char*`
+CHECK:            0x0074 (int): `int`
+CHECK:            0x104B: `const char*`
+CHECK:            0x104B: `const char*`
+CHECK:            0x0074 (int): `int`
+CHECK:            0x0030 (bool): `bool`
+CHECK:            0x0030 (bool): `bool`
+CHECK:            0x104B: `const char*`
+CHECK:            0x104B: `const char*`
+CHECK:   0x104D | LF_MFUNCTION [size = 28, unreferenced]
+CHECK:            return type = 0x0003 (void), # args = 15, param list = 0x104C
+CHECK:            class type = 0x1048, this type = 0x1049, this adjust = 0
+CHECK:            calling conv = cdecl, options = constructor
+CHECK:   0x104E | LF_ARGLIST [size = 12, unreferenced]
+CHECK:            0x1047: `__vc_attributes::moduleAttribute::type_e`
+CHECK:   0x104F | LF_MFUNCTION [size = 28, unreferenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x104E
+CHECK:            class type = 0x1048, this type = 0x1049, this adjust = 0
+CHECK:            calling conv = cdecl, options = constructor
+CHECK:   0x1050 | LF_MFUNCTION [size = 28, unreferenced]
+CHECK:            return type = 0x0003 (void), # args = 0, param list = 0x1012
+CHECK:            class type = 0x1048, this type = 0x1049, this adjust = 0
+CHECK:            calling conv = cdecl, options = constructor
+CHECK:   0x1051 | LF_METHODLIST [size = 28, unreferenced]
+CHECK:            - Method [type = 0x104D, vftable offset = -1, attrs = public]
+CHECK:            - Method [type = 0x104F, vftable offset = -1, attrs = public]
+CHECK:            - Method [type = 0x1050, vftable offset = -1, attrs = public]
+CHECK:   0x1052 | LF_FIELDLIST [size = 356, unreferenced]
+CHECK:            - LF_NESTTYPE [name = `type_e`, parent = 0x1047]
+CHECK:            - LF_METHOD [name = `moduleAttribute`, # overloads = 3, overload list = 0x1051]
+CHECK:            - LF_MEMBER [name = `type`, Type = 0x1047, offset = 0, attrs = public]
+CHECK:            - LF_MEMBER [name = `name`, Type = 0x104B, offset = 8, attrs = public]
+CHECK:            - LF_MEMBER [name = `version`, Type = 0x104B, offset = 16, attrs = public]
+CHECK:            - LF_MEMBER [name = `uuid`, Type = 0x104B, offset = 24, attrs = public]
+CHECK:            - LF_MEMBER [name = `lcid`, Type = 0x0074 (int), offset = 32, attrs = public]
+CHECK:            - LF_MEMBER [name = `control`, Type = 0x0030 (bool), offset = 36, attrs = public]
+CHECK:            - LF_MEMBER [name = `helpstring`, Type = 0x104B, offset = 40, attrs = public]
+CHECK:            - LF_MEMBER [name = `helpstringcontext`, Type = 0x0074 (int), offset = 48, attrs = public]
+CHECK:            - LF_MEMBER [name = `helpstringdll`, Type = 0x104B, offset = 56, attrs = public]
+CHECK:            - LF_MEMBER [name = `helpfile`, Type = 0x104B, offset = 64, attrs = public]
+CHECK:            - LF_MEMBER [name = `helpcontext`, Type = 0x0074 (int), offset = 72, attrs = public]
+CHECK:            - LF_MEMBER [name = `hidden`, Type = 0x0030 (bool), offset = 76, attrs = public]
+CHECK:            - LF_MEMBER [name = `restricted`, Type = 0x0030 (bool), offset = 77, attrs = public]
+CHECK:            - LF_MEMBER [name = `custom`, Type = 0x104B, offset = 80, attrs = public]
+CHECK:            - LF_MEMBER [name = `resource_name`, Type = 0x104B, offset = 88, attrs = public]
+CHECK:   0x1053 | LF_STRUCTURE [size = 96, unreferenced] `__vc_attributes::moduleAttribute`
+CHECK:            unique name: `.?AUmoduleAttribute at __vc_attributes@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1052
+CHECK:            options: has ctor / dtor | contains nested class | has unique name, sizeof 96
+CHECK:   0x1054 | LF_STRUCTURE [size = 48, referenced] `Nested::F`
+CHECK:            unique name: `.?AUF at Nested@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (-> 0x1057) | has unique name | is nested, sizeof 0
+CHECK:   0x1055 | LF_FIELDLIST [size = 16, referenced]
+CHECK:            - LF_NESTTYPE [name = `F`, parent = 0x1054]
+CHECK:   0x1056 | LF_STRUCTURE [size = 44, referenced] `Nested`
+CHECK:            unique name: `.?AUNested@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1055
+CHECK:            options: contains nested class | has unique name, sizeof 1
+CHECK:   0x1057 | LF_STRUCTURE [size = 48, referenced] `Nested::F`
+CHECK:            unique name: `.?AUF at Nested@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1007
+CHECK:            options: has unique name | is nested, sizeof 1
+CHECK:   0x1058 | LF_STRUCTURE [size = 52, referenced] `Constructor`
+CHECK:            unique name: `.?AUConstructor@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (-> 0x105C) | has unique name, sizeof 0
+CHECK:   0x1059 | LF_POINTER [size = 12, referenced]
+CHECK:            referent = 0x1058, mode = pointer, opts = const, kind = ptr64
+CHECK:   0x105A | LF_MFUNCTION [size = 28, referenced]
+CHECK:            return type = 0x0003 (void), # args = 0, param list = 0x1012
+CHECK:            class type = 0x1058, this type = 0x1059, this adjust = 0
+CHECK:            calling conv = cdecl, options = constructor
+CHECK:   0x105B | LF_FIELDLIST [size = 24, referenced]
+CHECK:            - LF_ONEMETHOD [name = `Constructor`]
+CHECK:              type = 0x105A, vftable offset = -1, attrs = public
+CHECK:   0x105C | LF_STRUCTURE [size = 52, referenced] `Constructor`
+CHECK:            unique name: `.?AUConstructor@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x105B
+CHECK:            options: has ctor / dtor | has unique name, sizeof 1
+CHECK:   0x105D | LF_CLASS [size = 40, referenced] `Class`
+CHECK:            unique name: `.?AVClass@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1007
+CHECK:            options: has unique name, sizeof 1
+CHECK:   0x105E | LF_UNION [size = 32, referenced] `Union`
+CHECK:            unique name: `.?ATUnion@@`
+CHECK:            field list: 0x1007
+CHECK:            options: has unique name | sealed, sizeof 1
+CHECK:   0x105F | LF_STRUCTURE [size = 48, referenced] `Operator`
+CHECK:            unique name: `.?AUOperator@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (-> 0x1064) | has unique name, sizeof 0
+CHECK:   0x1060 | LF_POINTER [size = 12, referenced]
+CHECK:            referent = 0x105F, mode = pointer, opts = const, kind = ptr64
+CHECK:   0x1061 | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x0074 (int): `int`
+CHECK:   0x1062 | LF_MFUNCTION [size = 28, referenced]
+CHECK:            return type = 0x0074 (int), # args = 1, param list = 0x1061
+CHECK:            class type = 0x105F, this type = 0x1060, this adjust = 0
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x1063 | LF_FIELDLIST [size = 24, referenced]
+CHECK:            - LF_ONEMETHOD [name = `operator+`]
+CHECK:              type = 0x1062, vftable offset = -1, attrs = public
+CHECK:   0x1064 | LF_STRUCTURE [size = 48, referenced] `Operator`
+CHECK:            unique name: `.?AUOperator@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1063
+CHECK:            options: has unique name | overloaded operator, sizeof 1
+CHECK:   0x1065 | LF_FIELDLIST [size = 12, referenced]
+CHECK:            - LF_ENUMERATE [A = 0]
+CHECK:   0x1066 | LF_ENUM [size = 36, referenced] `Enum`
+CHECK:            unique name: `.?AW4Enum@@`
+CHECK:            field list: 0x1065, underlying type: 0x0074 (int)
+CHECK:            options: has unique name
+CHECK:   0x1067 | LF_STRUCTURE [size = 40, referenced] `Cast`
+CHECK:            unique name: `.?AUCast@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (-> 0x106B) | has unique name, sizeof 0
+CHECK:   0x1068 | LF_POINTER [size = 12, referenced]
+CHECK:            referent = 0x1067, mode = pointer, opts = const, kind = ptr64
+CHECK:   0x1069 | LF_MFUNCTION [size = 28, referenced]
+CHECK:            return type = 0x0074 (int), # args = 0, param list = 0x1012
+CHECK:            class type = 0x1067, this type = 0x1068, this adjust = 0
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x106A | LF_FIELDLIST [size = 28, referenced]
+CHECK:            - LF_ONEMETHOD [name = `operator int`]
+CHECK:              type = 0x1069, vftable offset = -1, attrs = public
+CHECK:   0x106B | LF_STRUCTURE [size = 40, referenced] `Cast`
+CHECK:            unique name: `.?AUCast@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x106A
+CHECK:            options: conversion operator | has unique name | overloaded operator, sizeof 1
+CHECK:   0x106C | LF_STRUCTURE [size = 44, referenced] `Nothing`
+CHECK:            unique name: `.?AUNothing@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1007
+CHECK:            options: has unique name, sizeof 1
+CHECK:   0x106D | LF_STRUCTURE [size = 52, referenced] `Assignment`
+CHECK:            unique name: `.?AUAssignment@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (-> 0x1073) | has unique name, sizeof 0
+CHECK:   0x106E | LF_POINTER [size = 12, referenced]
+CHECK:            referent = 0x106D, mode = ref, opts = None, kind = ptr64
+CHECK:   0x106F | LF_POINTER [size = 12, referenced]
+CHECK:            referent = 0x106D, mode = pointer, opts = const, kind = ptr64
+CHECK:   0x1070 | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x106D: `Assignment`
+CHECK:   0x1071 | LF_MFUNCTION [size = 28, referenced]
+CHECK:            return type = 0x106E, # args = 1, param list = 0x1070
+CHECK:            class type = 0x106D, this type = 0x106F, this adjust = 0
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x1072 | LF_FIELDLIST [size = 24, referenced]
+CHECK:            - LF_ONEMETHOD [name = `operator=`]
+CHECK:              type = 0x1071, vftable offset = -1, attrs = public
+CHECK:   0x1073 | LF_STRUCTURE [size = 52, referenced] `Assignment`
+CHECK:            unique name: `.?AUAssignment@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: 0x1072
+CHECK:            options: has unique name | overloaded operator | overloaded operator=, sizeof 1
+CHECK:   0x1074 | LF_STRUCTURE [size = 44, referenced] `Nothing`
+CHECK:            unique name: `.?AUNothing@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (<- 0x106C) | has unique name, sizeof 0
+CHECK:   0x1075 | LF_MODIFIER [size = 12, referenced]
+CHECK:            referent = 0x1074, modifiers = const
+CHECK:   0x1076 | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x1075: `const Nothing`
+CHECK:   0x1077 | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x1076
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x1078 | LF_MODIFIER [size = 12, referenced]
+CHECK:            referent = 0x1074, modifiers = volatile
+CHECK:   0x1079 | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x1078: `volatile Nothing`
+CHECK:   0x107A | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x1079
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x107B | LF_MODIFIER [size = 12, referenced]
+CHECK:            referent = 0x1074, modifiers = const | volatile
+CHECK:   0x107C | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x107B: `const volatile Nothing`
+CHECK:   0x107D | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x107C
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x107E | LF_MODIFIER [size = 12, referenced]
+CHECK:            referent = 0x1074, modifiers = unaligned
+CHECK:   0x107F | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x107E: `__unaligned Nothing`
+CHECK:   0x1080 | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x107F
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x1081 | LF_UNION [size = 32, referenced] `Union`
+CHECK:            unique name: `.?ATUnion@@`
+CHECK:            field list: <no type>
+CHECK:            options: forward ref (<- 0x105E) | has unique name, sizeof 0
+CHECK:   0x1082 | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x1081: `Union`
+CHECK:   0x1083 | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x1082
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x1084 | LF_STRUCTURE [size = 124, referenced] `main::__l2::<unnamed-type-Anonymous>`
+CHECK:            unique name: `.?AU<unnamed-type-Anonymous>@?1??main@@YAHHPEAPEAD at Z@`aa6523bc`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (<- 0x1008) | has unique name | scoped, sizeof 0
+CHECK:   0x1085 | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x1084: `main::__l2::<unnamed-type-Anonymous>`
+CHECK:   0x1086 | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x1085
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x1087 | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x1070
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x1088 | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x1067: `Cast`
+CHECK:   0x1089 | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x1088
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x108A | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x1058: `Constructor`
+CHECK:   0x108B | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x108A
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x108C | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x1054: `Nested::F`
+CHECK:   0x108D | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x108C
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x108E | LF_STRUCTURE [size = 44, referenced] `Nested`
+CHECK:            unique name: `.?AUNested@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (<- 0x1056) | has unique name, sizeof 0
+CHECK:   0x108F | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x108E: `Nested`
+CHECK:   0x1090 | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x108F
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x1091 | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x1074: `Nothing`
+CHECK:   0x1092 | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x1091
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x1093 | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x105F: `Operator`
+CHECK:   0x1094 | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x1093
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x1095 | LF_STRUCTURE [size = 88, referenced] `main::__l2::Scoped`
+CHECK:            unique name: `.?AUScoped@?1??main@@YAHHPEAPEAD at Z@`aa6523bc`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (<- 0x1009) | has unique name | scoped, sizeof 0
+CHECK:   0x1096 | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x1095: `main::__l2::Scoped`
+CHECK:   0x1097 | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x1096
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x1098 | LF_CLASS [size = 40, referenced] `Class`
+CHECK:            unique name: `.?AVClass@@`
+CHECK:            vtable: <no type>, base list: <no type>, field list: <no type>
+CHECK:            options: forward ref (<- 0x105D) | has unique name, sizeof 0
+CHECK:   0x1099 | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x1098: `Class`
+CHECK:   0x109A | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x1099
+CHECK:            calling conv = cdecl, options = None
+CHECK:   0x109B | LF_ARGLIST [size = 12, referenced]
+CHECK:            0x1066: `Enum`
+CHECK:   0x109C | LF_PROCEDURE [size = 16, referenced]
+CHECK:            return type = 0x0003 (void), # args = 1, param list = 0x109B
+CHECK:            calling conv = cdecl, options = None
+
+CHECK:                  Type Reference Statistics                  
+CHECK: ============================================================
+CHECK:   Records referenced: 84 / 157 53.50%
+CHECK:   Bytes referenced: 2,188 / 7,500 29.17%

Modified: llvm/trunk/tools/llvm-pdbutil/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/CMakeLists.txt?rev=356692&r1=356691&r2=356692&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbutil/CMakeLists.txt (original)
+++ llvm/trunk/tools/llvm-pdbutil/CMakeLists.txt Thu Mar 21 11:02:34 2019
@@ -30,5 +30,6 @@ add_llvm_tool(llvm-pdbutil
   PrettyTypedefDumper.cpp
   PrettyVariableDumper.cpp
   StreamUtil.cpp
+  TypeReferenceTracker.cpp
   YAMLOutputStyle.cpp
   )

Modified: llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp?rev=356692&r1=356691&r2=356692&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp (original)
+++ llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.cpp Thu Mar 21 11:02:34 2019
@@ -13,6 +13,7 @@
 #include "MinimalSymbolDumper.h"
 #include "MinimalTypeDumper.h"
 #include "StreamUtil.h"
+#include "TypeReferenceTracker.h"
 #include "llvm-pdbutil.h"
 
 #include "llvm/ADT/STLExtras.h"
@@ -60,7 +61,12 @@ using namespace llvm::msf;
 using namespace llvm::pdb;
 
 DumpOutputStyle::DumpOutputStyle(InputFile &File)
-    : File(File), P(2, false, outs()) {}
+    : File(File), P(2, false, outs()) {
+  if (opts::dump::DumpTypeRefStats)
+    RefTracker.reset(new TypeReferenceTracker(File));
+}
+
+DumpOutputStyle::~DumpOutputStyle() {}
 
 PDBFile &DumpOutputStyle::getPdb() { return File.pdb(); }
 object::COFFObjectFile &DumpOutputStyle::getObj() { return File.obj(); }
@@ -76,6 +82,10 @@ void DumpOutputStyle::printStreamNotPres
 }
 
 Error DumpOutputStyle::dump() {
+  // Walk symbols & globals if we are supposed to mark types referenced.
+  if (opts::dump::DumpTypeRefStats)
+    RefTracker->mark();
+
   if (opts::dump::DumpSummary) {
     if (auto EC = dumpFileSummary())
       return EC;
@@ -187,6 +197,11 @@ Error DumpOutputStyle::dump() {
       return EC;
   }
 
+  if (opts::dump::DumpTypeRefStats) {
+    if (auto EC = dumpTypeRefStats())
+      return EC;
+  }
+
   if (opts::dump::DumpSectionHeaders) {
     if (auto EC = dumpSectionHeaders())
       return EC;
@@ -1227,14 +1242,15 @@ static void buildDepSet(LazyRandomTypeCo
 
 static void
 dumpFullTypeStream(LinePrinter &Printer, LazyRandomTypeCollection &Types,
-                   uint32_t NumTypeRecords, uint32_t NumHashBuckets,
+                   TypeReferenceTracker *RefTracker, uint32_t NumTypeRecords,
+                   uint32_t NumHashBuckets,
                    FixedStreamArray<support::ulittle32_t> HashValues,
                    TpiStream *Stream, bool Bytes, bool Extras) {
 
   Printer.formatLine("Showing {0:N} records", NumTypeRecords);
   uint32_t Width = NumDigits(TypeIndex::FirstNonSimpleIndex + NumTypeRecords);
 
-  MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
+  MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker,
                            NumHashBuckets, HashValues, Stream);
 
   if (auto EC = codeview::visitTypeStream(Types, V)) {
@@ -1245,12 +1261,13 @@ dumpFullTypeStream(LinePrinter &Printer,
 
 static void dumpPartialTypeStream(LinePrinter &Printer,
                                   LazyRandomTypeCollection &Types,
+                                  TypeReferenceTracker *RefTracker,
                                   TpiStream &Stream, ArrayRef<TypeIndex> TiList,
                                   bool Bytes, bool Extras, bool Deps) {
   uint32_t Width =
       NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
 
-  MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types,
+  MinimalTypeDumpVisitor V(Printer, Width + 2, Bytes, Extras, Types, RefTracker,
                            Stream.getNumHashBuckets(), Stream.getHashValues(),
                            &Stream);
 
@@ -1314,8 +1331,8 @@ Error DumpOutputStyle::dumpTypesFromObje
     Types.reset(Reader, 100);
 
     if (opts::dump::DumpTypes) {
-      dumpFullTypeStream(P, Types, 0, 0, {}, nullptr, opts::dump::DumpTypeData,
-                         false);
+      dumpFullTypeStream(P, Types, RefTracker.get(), 0, 0, {}, nullptr,
+                         opts::dump::DumpTypeData, false);
     } else if (opts::dump::DumpTypeExtras) {
       auto LocalHashes = LocallyHashedType::hashTypeCollection(Types);
       auto GlobalHashes = GloballyHashedType::hashTypeCollection(Types);
@@ -1384,18 +1401,22 @@ Error DumpOutputStyle::dumpTpiStream(uin
 
   auto &Types = (StreamIdx == StreamTPI) ? File.types() : File.ids();
 
+  // Only emit notes about referenced/unreferenced for types.
+  TypeReferenceTracker *MaybeTracker =
+      (StreamIdx == StreamTPI) ? RefTracker.get() : nullptr;
+
   // Enable resolving forward decls.
   Stream.buildHashMap();
 
   if (DumpTypes || !Indices.empty()) {
     if (Indices.empty())
-      dumpFullTypeStream(P, Types, Stream.getNumTypeRecords(),
+      dumpFullTypeStream(P, Types, MaybeTracker, Stream.getNumTypeRecords(),
                          Stream.getNumHashBuckets(), Stream.getHashValues(),
                          &Stream, DumpBytes, DumpExtras);
     else {
       std::vector<TypeIndex> TiList(Indices.begin(), Indices.end());
-      dumpPartialTypeStream(P, Types, Stream, TiList, DumpBytes, DumpExtras,
-                            opts::dump::DumpTypeDependents);
+      dumpPartialTypeStream(P, Types, MaybeTracker, Stream, TiList, DumpBytes,
+                            DumpExtras, opts::dump::DumpTypeDependents);
     }
   }
 
@@ -1520,6 +1541,34 @@ Error DumpOutputStyle::dumpModuleSymsFor
   return Error::success();
 }
 
+Error DumpOutputStyle::dumpTypeRefStats() {
+  printHeader(P, "Type Reference Statistics");
+  AutoIndent Indent(P);
+
+  // Sum the byte size of all type records, and the size and count of all
+  // referenced records.
+  size_t TotalRecs = File.types().size();
+  size_t RefRecs = 0;
+  size_t TotalBytes = 0;
+  size_t RefBytes = 0;
+  auto &Types = File.types();
+  for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI)) {
+    CVType Type = File.types().getType(*TI);
+    TotalBytes += Type.length();
+    if (RefTracker->isTypeReferenced(*TI)) {
+      ++RefRecs;
+      RefBytes += Type.length();
+    }
+  }
+
+  P.formatLine("Records referenced: {0:N} / {1:N} {2:P}", RefRecs, TotalRecs,
+               (double)RefRecs / TotalRecs);
+  P.formatLine("Bytes referenced: {0:N} / {1:N} {2:P}", RefBytes, TotalBytes,
+               (double)RefBytes / TotalBytes);
+
+  return Error::success();
+}
+
 Error DumpOutputStyle::dumpGSIRecords() {
   printHeader(P, "GSI Records");
 

Modified: llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.h?rev=356692&r1=356691&r2=356692&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.h (original)
+++ llvm/trunk/tools/llvm-pdbutil/DumpOutputStyle.h Thu Mar 21 11:02:34 2019
@@ -34,6 +34,7 @@ class COFFObjectFile;
 namespace pdb {
 class GSIHashTable;
 class InputFile;
+class TypeReferenceTracker;
 
 struct StatCollection {
   struct Stat {
@@ -62,6 +63,7 @@ class DumpOutputStyle : public OutputSty
 
 public:
   DumpOutputStyle(InputFile &File);
+  ~DumpOutputStyle() override;
 
   Error dump() override;
 
@@ -89,6 +91,7 @@ private:
   Error dumpNewFpo(PDBFile &File);
   Error dumpTpiStream(uint32_t StreamIdx);
   Error dumpTypesFromObjectFile();
+  Error dumpTypeRefStats();
   Error dumpModules();
   Error dumpModuleFiles();
   Error dumpModuleSymsForPdb();
@@ -104,6 +107,7 @@ private:
   void dumpSectionHeaders(StringRef Label, DbgHeaderType Type);
 
   InputFile &File;
+  std::unique_ptr<TypeReferenceTracker> RefTracker;
   LinePrinter P;
   SmallVector<StreamInfo, 32> StreamPurposes;
 };

Modified: llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp?rev=356692&r1=356691&r2=356692&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp (original)
+++ llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.cpp Thu Mar 21 11:02:34 2019
@@ -10,6 +10,7 @@
 
 #include "FormatUtil.h"
 #include "LinePrinter.h"
+#include "TypeReferenceTracker.h"
 
 #include "llvm-pdbutil.h"
 #include "llvm/DebugInfo/CodeView/CVRecord.h"
@@ -221,11 +222,10 @@ Error MinimalTypeDumpVisitor::visitTypeB
   // formatLine puts the newline at the beginning, so we use formatLine here
   // to start a new line, and then individual visit methods use format to
   // append to the existing line.
-  if (!Hashes) {
-    P.formatLine("{0} | {1} [size = {2}]",
-                 fmt_align(Index, AlignStyle::Right, Width),
-                 formatTypeLeafKind(Record.Type), Record.length());
-  } else {
+  P.formatLine("{0} | {1} [size = {2}",
+               fmt_align(Index, AlignStyle::Right, Width),
+               formatTypeLeafKind(Record.Type), Record.length());
+  if (Hashes) {
     std::string H;
     if (Index.toArrayIndex() >= HashValues.size()) {
       H = "(not present)";
@@ -241,13 +241,19 @@ Error MinimalTypeDumpVisitor::visitTypeB
       else
         H = "0x" + utohexstr(Hash) + ", our hash = 0x" + utohexstr(OurHash);
     }
-    P.formatLine("{0} | {1} [size = {2}, hash = {3}]",
-                 fmt_align(Index, AlignStyle::Right, Width),
-                 formatTypeLeafKind(Record.Type), Record.length(), H);
+    P.format(", hash = {0}", H);
+  }
+  if (RefTracker) {
+    if (RefTracker->isTypeReferenced(Index))
+      P.format(", referenced");
+    else
+      P.format(", unreferenced");
   }
+  P.format("]");
   P.Indent(Width + 3);
   return Error::success();
 }
+
 Error MinimalTypeDumpVisitor::visitTypeEnd(CVType &Record) {
   P.Unindent(Width + 3);
   if (RecordBytes) {

Modified: llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h?rev=356692&r1=356691&r2=356692&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h (original)
+++ llvm/trunk/tools/llvm-pdbutil/MinimalTypeDumper.h Thu Mar 21 11:02:34 2019
@@ -20,17 +20,19 @@ class LazyRandomTypeCollection;
 namespace pdb {
 class LinePrinter;
 class TpiStream;
+class TypeReferenceTracker;
 
 class MinimalTypeDumpVisitor : public codeview::TypeVisitorCallbacks {
 public:
   MinimalTypeDumpVisitor(LinePrinter &P, uint32_t Width, bool RecordBytes,
                          bool Hashes, codeview::LazyRandomTypeCollection &Types,
+                         TypeReferenceTracker *RefTracker,
                          uint32_t NumHashBuckets,
                          FixedStreamArray<support::ulittle32_t> HashValues,
                          pdb::TpiStream *Stream)
       : P(P), Width(Width), RecordBytes(RecordBytes), Hashes(Hashes),
-        Types(Types), NumHashBuckets(NumHashBuckets), HashValues(HashValues),
-        Stream(Stream) {}
+        Types(Types), RefTracker(RefTracker), NumHashBuckets(NumHashBuckets),
+        HashValues(HashValues), Stream(Stream) {}
 
   Error visitTypeBegin(codeview::CVType &Record,
                        codeview::TypeIndex Index) override;
@@ -56,6 +58,7 @@ private:
   bool RecordBytes = false;
   bool Hashes = false;
   codeview::LazyRandomTypeCollection &Types;
+  pdb::TypeReferenceTracker *RefTracker = nullptr;
   uint32_t NumHashBuckets;
   codeview::TypeIndex CurrentTypeIndex;
   FixedStreamArray<support::ulittle32_t> HashValues;

Added: llvm/trunk/tools/llvm-pdbutil/TypeReferenceTracker.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/TypeReferenceTracker.cpp?rev=356692&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-pdbutil/TypeReferenceTracker.cpp (added)
+++ llvm/trunk/tools/llvm-pdbutil/TypeReferenceTracker.cpp Thu Mar 21 11:02:34 2019
@@ -0,0 +1,160 @@
+//===- TypeReferenceTracker.cpp ------------------------------- *- C++ --*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "TypeReferenceTracker.h"
+
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+using namespace llvm::codeview;
+
+// LazyRandomTypeCollection doesn't appear to expose the number of records, so
+// just iterate up front to find out.
+static uint32_t getNumRecordsInCollection(LazyRandomTypeCollection &Types) {
+  uint32_t NumTypes = 0;
+  for (Optional<TypeIndex> TI = Types.getFirst(); TI; TI = Types.getNext(*TI))
+    ++NumTypes;
+  return NumTypes;
+}
+
+TypeReferenceTracker::TypeReferenceTracker(InputFile &File)
+    : File(File), Types(File.types()),
+      Ids(File.isPdb() ? &File.ids() : nullptr) {
+  NumTypeRecords = getNumRecordsInCollection(Types);
+  TypeReferenced.resize(NumTypeRecords, false);
+
+  // If this is a PDB, ids are stored separately, so make a separate bit vector.
+  if (Ids) {
+    NumIdRecords = getNumRecordsInCollection(*Ids);
+    IdReferenced.resize(NumIdRecords, false);
+  }
+
+  // Get the TpiStream pointer for forward decl resolution if this is a pdb.
+  // Build the hash map to enable resolving forward decls.
+  if (File.isPdb()) {
+    Tpi = &cantFail(File.pdb().getPDBTpiStream());
+    Tpi->buildHashMap();
+  }
+}
+
+void TypeReferenceTracker::mark() {
+  // Walk type roots:
+  // - globals
+  // - modi symbols
+  // - LF_UDT_MOD_SRC_LINE? VC always links these in.
+  for (SymbolGroup SG : File.symbol_groups()) {
+    if (File.isObj()) {
+      for (const auto &SS : SG.getDebugSubsections()) {
+        // FIXME: Are there other type-referencing subsections? Inlinees?
+        // Probably for IDs.
+        if (SS.kind() != DebugSubsectionKind::Symbols)
+          continue;
+
+        CVSymbolArray Symbols;
+        BinaryStreamReader Reader(SS.getRecordData());
+        cantFail(Reader.readArray(Symbols, Reader.getLength()));
+        for (const CVSymbol &S : Symbols)
+          addTypeRefsFromSymbol(S);
+      }
+    } else if (SG.hasDebugStream()) {
+      for (const CVSymbol &S : SG.getPdbModuleStream().getSymbolArray())
+        addTypeRefsFromSymbol(S);
+    }
+  }
+
+  // Walk globals and mark types referenced from globals.
+  if (File.isPdb() && File.pdb().hasPDBGlobalsStream()) {
+    SymbolStream &SymStream = cantFail(File.pdb().getPDBSymbolStream());
+    GlobalsStream &GS = cantFail(File.pdb().getPDBGlobalsStream());
+    for (uint32_t PubSymOff : GS.getGlobalsTable()) {
+      CVSymbol Sym = SymStream.readRecord(PubSymOff);
+      addTypeRefsFromSymbol(Sym);
+    }
+  }
+
+  // FIXME: Should we walk Ids?
+}
+
+void TypeReferenceTracker::addOneTypeRef(TiRefKind RefKind, TypeIndex RefTI) {
+  // If it's simple or already seen, no need to add to work list.
+  BitVector &TypeOrIdReferenced =
+      (Ids && RefKind == TiRefKind::IndexRef) ? IdReferenced : TypeReferenced;
+  if (RefTI.isSimple() || TypeOrIdReferenced.test(RefTI.toArrayIndex()))
+    return;
+
+  // Otherwise, mark it seen and add it to the work list.
+  TypeOrIdReferenced.set(RefTI.toArrayIndex());
+  RefWorklist.push_back({RefKind, RefTI});
+}
+
+void TypeReferenceTracker::addTypeRefsFromSymbol(const CVSymbol &Sym) {
+  SmallVector<TiReference, 4> DepList;
+  // FIXME: Check for failure.
+  discoverTypeIndicesInSymbol(Sym, DepList);
+  addReferencedTypes(Sym.content(), DepList);
+  markReferencedTypes();
+}
+
+void TypeReferenceTracker::addReferencedTypes(ArrayRef<uint8_t> RecData,
+                                              ArrayRef<TiReference> DepList) {
+  for (const auto &Ref : DepList) {
+    // FIXME: Report OOB slice instead of truncating.
+    ArrayRef<uint8_t> ByteSlice =
+        RecData.drop_front(Ref.Offset).take_front(4 * Ref.Count);
+    ArrayRef<TypeIndex> TIs(
+        reinterpret_cast<const TypeIndex *>(ByteSlice.data()),
+        ByteSlice.size() / 4);
+
+    // If this is a PDB and this is an item reference, track it in the IPI
+    // bitvector. Otherwise, it's a type ref, or there is only one stream.
+    for (TypeIndex RefTI : TIs)
+      addOneTypeRef(Ref.Kind, RefTI);
+  }
+}
+
+void TypeReferenceTracker::markReferencedTypes() {
+  while (!RefWorklist.empty()) {
+    TiRefKind RefKind;
+    TypeIndex RefTI;
+    std::tie(RefKind, RefTI) = RefWorklist.pop_back_val();
+    Optional<CVType> Rec = (Ids && RefKind == TiRefKind::IndexRef)
+                               ? Ids->tryGetType(RefTI)
+                               : Types.tryGetType(RefTI);
+    if (!Rec)
+      continue; // FIXME: Report a reference to a non-existant type.
+
+    SmallVector<TiReference, 4> DepList;
+    // FIXME: Check for failure.
+    discoverTypeIndices(*Rec, DepList);
+    addReferencedTypes(Rec->content(), DepList);
+
+    // If this is a tag kind and this is a PDB input, mark the complete type as
+    // referenced.
+    // FIXME: This limitation makes this feature somewhat useless on object file
+    // inputs.
+    if (Tpi) {
+      switch (Rec->kind()) {
+      default:
+        break;
+      case LF_CLASS:
+      case LF_INTERFACE:
+      case LF_STRUCTURE:
+      case LF_UNION:
+      case LF_ENUM:
+        addOneTypeRef(TiRefKind::TypeRef,
+                      cantFail(Tpi->findFullDeclForForwardRef(RefTI)));
+        break;
+      }
+    }
+  }
+}

Added: llvm/trunk/tools/llvm-pdbutil/TypeReferenceTracker.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/TypeReferenceTracker.h?rev=356692&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-pdbutil/TypeReferenceTracker.h (added)
+++ llvm/trunk/tools/llvm-pdbutil/TypeReferenceTracker.h Thu Mar 21 11:02:34 2019
@@ -0,0 +1,69 @@
+//===- TypeReferenceTracker.h --------------------------------- *- C++ --*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_TYPEREFERENCETRACKER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_TYPEREFERENCETRACKER_H
+
+#include "InputFile.h"
+
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace pdb {
+
+class TpiStream;
+
+/// Maintains bitvector to track whether a type was referenced by a symbol
+/// record.
+class TypeReferenceTracker {
+public:
+  TypeReferenceTracker(InputFile &File);
+
+  // Do the work of marking referenced types.
+  void mark();
+
+  // Return true if a symbol record transitively references this type.
+  bool isTypeReferenced(codeview::TypeIndex TI) {
+    return TI.toArrayIndex() <= NumTypeRecords &&
+           TypeReferenced.test(TI.toArrayIndex());
+  }
+
+private:
+  void addTypeRefsFromSymbol(const codeview::CVSymbol &Sym);
+
+  // Mark types on this list as referenced.
+  void addReferencedTypes(ArrayRef<uint8_t> RecData,
+                          ArrayRef<codeview::TiReference> Refs);
+
+  // Consume all types on the worklist.
+  void markReferencedTypes();
+
+  void addOneTypeRef(codeview::TiRefKind RefKind, codeview::TypeIndex RefTI);
+
+  InputFile &File;
+  codeview::LazyRandomTypeCollection &Types;
+  codeview::LazyRandomTypeCollection *Ids = nullptr;
+  TpiStream *Tpi = nullptr;
+  BitVector TypeReferenced;
+  BitVector IdReferenced;
+  SmallVector<std::pair<codeview::TiRefKind, codeview::TypeIndex>, 10>
+      RefWorklist;
+  uint32_t NumTypeRecords = 0;
+  uint32_t NumIdRecords = 0;
+};
+
+} // namespace pdb
+} // namespace llvm
+
+#endif // LLVM_TOOLS_LLVMPDBDUMP_TYPEREFERENCETRACKER_H

Modified: llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp?rev=356692&r1=356691&r2=356692&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp (original)
+++ llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.cpp Thu Mar 21 11:02:34 2019
@@ -476,6 +476,11 @@ cl::opt<bool> DumpTypeData(
     "type-data",
     cl::desc("dump CodeView type record raw bytes from TPI stream"),
     cl::cat(TypeOptions), cl::sub(DumpSubcommand));
+cl::opt<bool>
+    DumpTypeRefStats("type-ref-stats",
+                     cl::desc("dump statistics on the number and size of types "
+                              "transitively referenced by symbol records"),
+                     cl::cat(TypeOptions), cl::sub(DumpSubcommand));
 
 cl::opt<bool> DumpTypeExtras("type-extras",
                              cl::desc("dump type hashes and index offsets"),

Modified: llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h?rev=356692&r1=356691&r2=356692&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h (original)
+++ llvm/trunk/tools/llvm-pdbutil/llvm-pdbutil.h Thu Mar 21 11:02:34 2019
@@ -155,6 +155,7 @@ extern llvm::cl::opt<bool> DumpTypeData;
 extern llvm::cl::opt<bool> DumpTypeExtras;
 extern llvm::cl::list<uint32_t> DumpTypeIndex;
 extern llvm::cl::opt<bool> DumpTypeDependents;
+extern llvm::cl::opt<bool> DumpTypeRefStats;
 extern llvm::cl::opt<bool> DumpSectionHeaders;
 
 extern llvm::cl::opt<bool> DumpIds;




More information about the llvm-commits mailing list