[llvm] r311904 - [CodeView] Don't output S_UDT symbols for forward decls.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 28 11:49:04 PDT 2017


Author: zturner
Date: Mon Aug 28 11:49:04 2017
New Revision: 311904

URL: http://llvm.org/viewvc/llvm-project?rev=311904&view=rev
Log:
[CodeView] Don't output S_UDT symbols for forward decls.

S_UDT symbols are the debugger's "index" for all the structs,
typedefs, classes, and enums in a program.  If any of those
structs/classes don't have a complete declaration, or if there
is a typedef to something that doesn't have a complete definition,
then emitting the S_UDT is unhelpful because it doesn't give
the debugger enough information to do anything useful.  On the
other hand, it results in a huge size blow-up in the resulting
PDB, which is exacerbated by an order of magnitude when linking
with /DEBUG:FASTLINK.

With this patch, we drop S_UDT records for types that refer either
directly or indirectly (e.g. through a typedef, pointer, etc) to
a class/struct/union/enum without a complete definition.  This
brings us about 50% of the way towards parity with /DEBUG:FASTLINK
PDBs generated from cl-compiled object files.

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

Added:
    llvm/trunk/test/DebugInfo/COFF/purge-typedef-udts.ll
Modified:
    llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h
    llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
    llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h

Modified: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h?rev=311904&r1=311903&r2=311904&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h Mon Aug 28 11:49:04 2017
@@ -416,6 +416,10 @@ public:
     return (Options & ClassOptions::Nested) != ClassOptions::None;
   }
 
+  bool isForwardRef() const {
+    return (Options & ClassOptions::ForwardReference) != ClassOptions::None;
+  }
+
   uint16_t getMemberCount() const { return MemberCount; }
   ClassOptions getOptions() const { return Options; }
   TypeIndex getFieldList() const { return FieldList; }

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp?rev=311904&r1=311903&r2=311904&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp Mon Aug 28 11:49:04 2017
@@ -1099,10 +1099,25 @@ void CodeViewDebug::beginFunctionImpl(co
   }
 }
 
-void CodeViewDebug::addToUDTs(const DIType *Ty, TypeIndex TI) {
+static bool shouldEmitUdt(const DIType *T) {
+  while (true) {
+    if (!T || T->isForwardDecl())
+      return false;
+
+    const DIDerivedType *DT = dyn_cast<DIDerivedType>(T);
+    if (!DT)
+      return true;
+    T = DT->getBaseType().resolve();
+  }
+  return true;
+}
+
+void CodeViewDebug::addToUDTs(const DIType *Ty) {
   // Don't record empty UDTs.
   if (Ty->getName().empty())
     return;
+  if (!shouldEmitUdt(Ty))
+    return;
 
   SmallVector<StringRef, 5> QualifiedNameComponents;
   const DISubprogram *ClosestSubprogram = getQualifiedNameComponents(
@@ -1111,10 +1126,11 @@ void CodeViewDebug::addToUDTs(const DITy
   std::string FullyQualifiedName =
       getQualifiedName(QualifiedNameComponents, getPrettyScopeName(Ty));
 
-  if (ClosestSubprogram == nullptr)
-    GlobalUDTs.emplace_back(std::move(FullyQualifiedName), TI);
-  else if (ClosestSubprogram == CurrentSubprogram)
-    LocalUDTs.emplace_back(std::move(FullyQualifiedName), TI);
+  if (ClosestSubprogram == nullptr) {
+    GlobalUDTs.emplace_back(std::move(FullyQualifiedName), Ty);
+  } else if (ClosestSubprogram == CurrentSubprogram) {
+    LocalUDTs.emplace_back(std::move(FullyQualifiedName), Ty);
+  }
 
   // TODO: What if the ClosestSubprogram is neither null or the current
   // subprogram?  Currently, the UDT just gets dropped on the floor.
@@ -1172,7 +1188,7 @@ TypeIndex CodeViewDebug::lowerTypeAlias(
   TypeIndex UnderlyingTypeIndex = getTypeIndex(UnderlyingTypeRef);
   StringRef TypeName = Ty->getName();
 
-  addToUDTs(Ty, UnderlyingTypeIndex);
+  addToUDTs(Ty);
 
   if (UnderlyingTypeIndex == TypeIndex(SimpleTypeKind::Int32Long) &&
       TypeName == "HRESULT")
@@ -1764,7 +1780,7 @@ TypeIndex CodeViewDebug::lowerCompleteTy
     TypeTable.writeKnownType(USLR);
   }
 
-  addToUDTs(Ty, ClassTI);
+  addToUDTs(Ty);
 
   return ClassTI;
 }
@@ -1803,7 +1819,7 @@ TypeIndex CodeViewDebug::lowerCompleteTy
   UdtSourceLineRecord USLR(UnionTI, SIRI, Ty->getLine());
   TypeTable.writeKnownType(USLR);
 
-  addToUDTs(Ty, UnionTI);
+  addToUDTs(Ty);
 
   return UnionTI;
 }
@@ -2203,8 +2219,11 @@ void CodeViewDebug::endCVSubsection(MCSy
 }
 
 void CodeViewDebug::emitDebugInfoForUDTs(
-    ArrayRef<std::pair<std::string, TypeIndex>> UDTs) {
-  for (const std::pair<std::string, codeview::TypeIndex> &UDT : UDTs) {
+    ArrayRef<std::pair<std::string, const DIType *>> UDTs) {
+  for (const auto &UDT : UDTs) {
+    const DIType *T = UDT.second;
+    assert(shouldEmitUdt(T));
+
     MCSymbol *UDTRecordBegin = MMI->getContext().createTempSymbol(),
              *UDTRecordEnd = MMI->getContext().createTempSymbol();
     OS.AddComment("Record length");
@@ -2215,7 +2234,7 @@ void CodeViewDebug::emitDebugInfoForUDTs
     OS.EmitIntValue(unsigned(SymbolKind::S_UDT), 2);
 
     OS.AddComment("Type");
-    OS.EmitIntValue(UDT.second.getIndex(), 4);
+    OS.EmitIntValue(getCompleteTypeIndex(T).getIndex(), 4);
 
     emitNullTerminatedSymbolName(OS, UDT.first);
     OS.EmitLabel(UDTRecordEnd);

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h?rev=311904&r1=311903&r2=311904&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h Mon Aug 28 11:49:04 2017
@@ -187,8 +187,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDe
 
   // The UDTs we have seen while processing types; each entry is a pair of type
   // index and type name.
-  std::vector<std::pair<std::string, codeview::TypeIndex>> LocalUDTs,
-      GlobalUDTs;
+  std::vector<std::pair<std::string, const DIType *>> LocalUDTs;
+  std::vector<std::pair<std::string, const DIType *>> GlobalUDTs;
 
   using FileToFilepathMapTy = std::map<const DIFile *, std::string>;
   FileToFilepathMapTy FileToFilepathMap;
@@ -222,8 +222,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDe
 
   void emitDebugInfoForRetainedTypes();
 
-  void emitDebugInfoForUDTs(
-      ArrayRef<std::pair<std::string, codeview::TypeIndex>> UDTs);
+  void
+  emitDebugInfoForUDTs(ArrayRef<std::pair<std::string, const DIType *>> UDTs);
 
   void emitDebugInfoForGlobal(const DIGlobalVariable *DIGV,
                               const GlobalVariable *GV, MCSymbol *GVSym);
@@ -266,7 +266,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDe
 
   codeview::TypeIndex getVBPTypeIndex();
 
-  void addToUDTs(const DIType *Ty, codeview::TypeIndex TI);
+  void addToUDTs(const DIType *Ty);
 
   codeview::TypeIndex lowerType(const DIType *Ty, const DIType *ClassTy);
   codeview::TypeIndex lowerTypeAlias(const DIDerivedType *Ty);

Added: llvm/trunk/test/DebugInfo/COFF/purge-typedef-udts.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/COFF/purge-typedef-udts.ll?rev=311904&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/COFF/purge-typedef-udts.ll (added)
+++ llvm/trunk/test/DebugInfo/COFF/purge-typedef-udts.ll Mon Aug 28 11:49:04 2017
@@ -0,0 +1,120 @@
+; RUN: llc < %s -filetype=obj | llvm-readobj - -codeview | FileCheck %s
+source_filename = "test/DebugInfo/COFF/purge-typedef-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-msvc19.11.25506"
+
+; C++ source to regenerate:
+; $ cat t.cpp
+; struct Foo;
+; struct Bar {
+;   Bar() {}
+;   int X;
+; };
+;
+; typedef Foo FooTypedef;
+; typedef Bar BarTypedef;
+;
+; int func(void *F) { return 7; }
+; int func(const FooTypedef *F) { return func((void*)F); }
+; int func(const BarTypedef *B) { return func((void*)B->X); }
+
+; CHECK-NOT: UDTName: FooTypedef
+; CHECK: UDTName: BarTypedef
+
+%struct.Foo = type opaque
+%struct.Bar = type { i32 }
+
+; Function Attrs: noinline nounwind optnone
+define i32 @"\01?func@@YAHPAX at Z"(i8* %F) #0 !dbg !10 {
+entry:
+  %F.addr = alloca i8*, align 4
+  store i8* %F, i8** %F.addr, align 4
+  call void @llvm.dbg.declare(metadata i8** %F.addr, metadata !14, metadata !DIExpression()), !dbg !15
+  ret i32 7, !dbg !16
+}
+
+; Function Attrs: nounwind readnone speculatable
+declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
+
+; Function Attrs: noinline nounwind optnone
+define i32 @"\01?func@@YAHPBUFoo@@@Z"(%struct.Foo* %F) #0 !dbg !17 {
+entry:
+  %F.addr = alloca %struct.Foo*, align 4
+  store %struct.Foo* %F, %struct.Foo** %F.addr, align 4
+  call void @llvm.dbg.declare(metadata %struct.Foo** %F.addr, metadata !24, metadata !DIExpression()), !dbg !25
+  %0 = load %struct.Foo*, %struct.Foo** %F.addr, align 4, !dbg !26
+  %1 = bitcast %struct.Foo* %0 to i8*, !dbg !26
+  %call = call i32 @"\01?func@@YAHPAX at Z"(i8* %1), !dbg !27
+  ret i32 %call, !dbg !28
+}
+
+; Function Attrs: noinline nounwind optnone
+define i32 @"\01?func@@YAHPBUBar@@@Z"(%struct.Bar* %B) #0 !dbg !29 {
+entry:
+  %B.addr = alloca %struct.Bar*, align 4
+  store %struct.Bar* %B, %struct.Bar** %B.addr, align 4
+  call void @llvm.dbg.declare(metadata %struct.Bar** %B.addr, metadata !42, metadata !DIExpression()), !dbg !43
+  %0 = load %struct.Bar*, %struct.Bar** %B.addr, align 4, !dbg !44
+  %X = getelementptr inbounds %struct.Bar, %struct.Bar* %0, i32 0, i32 0, !dbg !45
+  %1 = load i32, i32* %X, align 4, !dbg !45
+  %2 = inttoptr i32 %1 to i8*, !dbg !46
+  %call = call i32 @"\01?func@@YAHPAX at Z"(i8* %2), !dbg !47
+  ret i32 %call, !dbg !48
+}
+
+attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone speculatable }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 6.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3)
+!1 = !DIFile(filename: "t.cpp", directory: "D:\5Csrc\5Cllvmbuild\5Cninja", checksumkind: CSK_MD5, checksum: "27c44c8a5531845f61f582a24ef5c151")
+!2 = !{}
+!3 = !{!4}
+!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 32)
+!5 = !{i32 1, !"NumRegisterParameters", i32 0}
+!6 = !{i32 2, !"CodeView", i32 1}
+!7 = !{i32 2, !"Debug Info Version", i32 3}
+!8 = !{i32 1, !"wchar_size", i32 2}
+!9 = !{!"clang version 6.0.0 "}
+!10 = distinct !DISubprogram(name: "func", linkageName: "\01?func@@YAHPAX at Z", scope: !1, file: !1, line: 10, type: !11, isLocal: false, isDefinition: true, scopeLine: 10, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13, !4}
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !DILocalVariable(name: "F", arg: 1, scope: !10, file: !1, line: 10, type: !4)
+!15 = !DILocation(line: 10, column: 16, scope: !10)
+!16 = !DILocation(line: 10, column: 21, scope: !10)
+!17 = distinct !DISubprogram(name: "func", linkageName: "\01?func@@YAHPBUFoo@@@Z", scope: !1, file: !1, line: 11, type: !18, isLocal: false, isDefinition: true, scopeLine: 11, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!18 = !DISubroutineType(types: !19)
+!19 = !{!13, !20}
+!20 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !21, size: 32)
+!21 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !22)
+!22 = !DIDerivedType(tag: DW_TAG_typedef, name: "FooTypedef", file: !1, line: 7, baseType: !23)
+!23 = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !1, line: 1, flags: DIFlagFwdDecl, identifier: ".?AUFoo@@")
+!24 = !DILocalVariable(name: "F", arg: 1, scope: !17, file: !1, line: 11, type: !20)
+!25 = !DILocation(line: 11, column: 28, scope: !17)
+!26 = !DILocation(line: 11, column: 52, scope: !17)
+!27 = !DILocation(line: 11, column: 40, scope: !17)
+!28 = !DILocation(line: 11, column: 33, scope: !17)
+!29 = distinct !DISubprogram(name: "func", linkageName: "\01?func@@YAHPBUBar@@@Z", scope: !1, file: !1, line: 12, type: !30, isLocal: false, isDefinition: true, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
+!30 = !DISubroutineType(types: !31)
+!31 = !{!13, !32}
+!32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 32)
+!33 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !34)
+!34 = !DIDerivedType(tag: DW_TAG_typedef, name: "BarTypedef", file: !1, line: 8, baseType: !35)
+!35 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Bar", file: !1, line: 2, size: 32, elements: !36, identifier: ".?AUBar@@")
+!36 = !{!37, !38}
+!37 = !DIDerivedType(tag: DW_TAG_member, name: "X", scope: !35, file: !1, line: 4, baseType: !13, size: 32)
+!38 = !DISubprogram(name: "Bar", scope: !35, file: !1, line: 3, type: !39, isLocal: false, isDefinition: false, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false)
+!39 = !DISubroutineType(cc: DW_CC_BORLAND_thiscall, types: !40)
+!40 = !{null, !41}
+!41 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !35, size: 32, flags: DIFlagArtificial | DIFlagObjectPointer)
+!42 = !DILocalVariable(name: "B", arg: 1, scope: !29, file: !1, line: 12, type: !32)
+!43 = !DILocation(line: 12, column: 28, scope: !29)
+!44 = !DILocation(line: 12, column: 52, scope: !29)
+!45 = !DILocation(line: 12, column: 55, scope: !29)
+!46 = !DILocation(line: 12, column: 45, scope: !29)
+!47 = !DILocation(line: 12, column: 40, scope: !29)
+!48 = !DILocation(line: 12, column: 33, scope: !29)




More information about the llvm-commits mailing list