[DebugInfo][CodeView] Change in line tables only mode to emit type information
authorAmy Huang <akhuang@google.com>
Tue, 12 Jan 2021 00:37:29 +0000 (16:37 -0800)
committerAmy Huang <akhuang@google.com>
Fri, 15 Jan 2021 17:28:27 +0000 (09:28 -0800)
for function scopes, rather than using the qualified name.

In line-tables-only mode, we used to emit qualified names as the display name for functions when using CodeView.
This patch changes to emitting the parent scopes instead, with forward declarations for class types.
The total object file size ends up being slightly smaller than if we use the full qualified names.

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

clang/lib/CodeGen/CGDebugInfo.cpp
clang/test/CodeGenCXX/debug-info-codeview-display-name.cpp
clang/test/CodeGenCXX/debug-info-codeview-scopes.cpp [new file with mode: 0644]

index 881ee24..00606d3 100644 (file)
@@ -254,24 +254,12 @@ StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
   FunctionTemplateSpecializationInfo *Info =
       FD->getTemplateSpecializationInfo();
 
-  // Emit the unqualified name in normal operation. LLVM and the debugger can
-  // compute the fully qualified name from the scope chain. If we're only
-  // emitting line table info, there won't be any scope chains, so emit the
-  // fully qualified name here so that stack traces are more accurate.
-  // FIXME: Do this when emitting DWARF as well as when emitting CodeView after
-  // evaluating the size impact.
-  bool UseQualifiedName = DebugKind == codegenoptions::DebugLineTablesOnly &&
-                          CGM.getCodeGenOpts().EmitCodeView;
-
-  if (!Info && FII && !UseQualifiedName)
+  if (!Info && FII)
     return FII->getName();
 
   SmallString<128> NS;
   llvm::raw_svector_ostream OS(NS);
-  if (!UseQualifiedName)
-    FD->printName(OS);
-  else
-    FD->printQualifiedName(OS, getPrintingPolicy());
+  FD->printName(OS);
 
   // Add any template specialization args.
   if (Info) {
@@ -1058,7 +1046,10 @@ CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty,
       Flags |= llvm::DINode::FlagNonTrivial;
 
   // Create the type.
-  SmallString<256> Identifier = getTypeIdentifier(Ty, CGM, TheCU);
+  SmallString<256> Identifier;
+  // Don't include a linkage name in line tables only.
+  if (CGM.getCodeGenOpts().hasReducedDebugInfo())
+    Identifier = getTypeIdentifier(Ty, CGM, TheCU);
   llvm::DICompositeType *RetTy = DBuilder.createReplaceableCompositeType(
       getTagForRecord(RD), RDName, Ctx, DefUnit, Line, 0, Size, Align, Flags,
       Identifier);
@@ -2326,6 +2317,9 @@ static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind,
     if (ES->hasExternalDefinitions(RD) == ExternalASTSource::EK_Always)
       return true;
 
+  if (DebugKind == codegenoptions::DebugLineTablesOnly)
+    return true;
+
   if (DebugKind > codegenoptions::LimitedDebugInfo)
     return false;
 
@@ -3473,7 +3467,11 @@ void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit,
                               DebugKind <= codegenoptions::DebugLineTablesOnly))
     LinkageName = StringRef();
 
-  if (CGM.getCodeGenOpts().hasReducedDebugInfo()) {
+  // Emit the function scope in line tables only mode (if CodeView) to
+  // differentiate between function names.
+  if (CGM.getCodeGenOpts().hasReducedDebugInfo() ||
+      (DebugKind == codegenoptions::DebugLineTablesOnly &&
+       CGM.getCodeGenOpts().EmitCodeView)) {
     if (const NamespaceDecl *NSDecl =
             dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext()))
       FDContext = getOrCreateNamespace(NSDecl);
@@ -3482,6 +3480,8 @@ void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit,
       llvm::DIScope *Mod = getParentModuleOrNull(RDecl);
       FDContext = getContextDescriptor(RDecl, Mod ? Mod : TheCU);
     }
+  }
+  if (CGM.getCodeGenOpts().hasReducedDebugInfo()) {
     // Check if it is a noreturn-marked function
     if (FD->isNoReturn())
       Flags |= llvm::DINode::FlagNoReturn;
index 15f625d..935fded 100644 (file)
@@ -20,11 +20,9 @@ void freefunc() { }
 
 namespace N {
   int b() { return 0; }
-// UNQUAL-DAG: "b"
-// QUAL-DAG: "N::b"
+// CHECK-DAG: "b"
   namespace { void func() { } }
-// UNQUAL-DAG: "func"
-// QUAL-DAG: "N::`anonymous namespace'::func"
+// CHECK-DAG: "func"
 }
 
 void _c(void) {
@@ -35,24 +33,19 @@ void _c(void) {
 struct foo {
   int operator+(int);
   foo(){}
-// UNQUAL-DAG: "foo"
-// QUAL-DAG: "foo::foo"
+// CHECK-DAG: "foo"
 
   ~foo(){}
-// UNQUAL-DAG: "~foo"
-// QUAL-DAG: "foo::~foo"
+// CHECK-DAG: "~foo"
 
   foo(int i){}
-// UNQUAL-DAG: "foo"
-// QUAL-DAG: "foo::foo"
+// CHECK-DAG: "foo"
 
   foo(char *q){}
-// UNQUAL-DAG: "foo"
-// QUAL-DAG: "foo::foo"
+// CHECK-DAG: "foo"
 
   static foo* static_method() { return 0; }
-// UNQUAL-DAG: "static_method"
-// QUAL-DAG: "foo::static_method"
+// CHECK-DAG: "static_method"
 
 };
 
@@ -61,8 +54,7 @@ void use_foo() {
   foo::static_method();
 }
 
-// UNQUAL-DAG: "operator+"
-// QUAL-DAG: "foo::operator+"
+// CHECK-DAG: "operator+"
 int foo::operator+(int a) { return a; }
 
 // PR17371
@@ -82,17 +74,11 @@ void OverloadedNewDelete::operator delete(void *) { }
 void OverloadedNewDelete::operator delete[](void *) { }
 int OverloadedNewDelete::operator+(int x) { return x; };
 
-// UNQUAL-DAG: "operator new"
-// UNQUAL-DAG: "operator new[]"
-// UNQUAL-DAG: "operator delete"
-// UNQUAL-DAG: "operator delete[]"
-// UNQUAL-DAG: "operator+"
-// QUAL-DAG: "OverloadedNewDelete::operator new"
-// QUAL-DAG: "OverloadedNewDelete::operator new[]"
-// QUAL-DAG: "OverloadedNewDelete::operator delete"
-// QUAL-DAG: "OverloadedNewDelete::operator delete[]"
-// QUAL-DAG: "OverloadedNewDelete::operator+"
-
+// CHECK-DAG: "operator new"
+// CHECK-DAG: "operator new[]"
+// CHECK-DAG: "operator delete"
+// CHECK-DAG: "operator delete[]"
+// CHECK-DAG: "operator+"
 
 template <typename T, void (*)(void)>
 void fn_tmpl() {}
diff --git a/clang/test/CodeGenCXX/debug-info-codeview-scopes.cpp b/clang/test/CodeGenCXX/debug-info-codeview-scopes.cpp
new file mode 100644 (file)
index 0000000..f096e33
--- /dev/null
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -debug-info-kind=line-tables-only -S -emit-llvm -std=c++11 -o - %s | FileCheck --check-prefix LINUX %s
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -debug-info-kind=line-tables-only -gcodeview -S -emit-llvm -std=c++11 -o - %s | FileCheck --check-prefix MSVC %s
+
+// Check that we emit type information for function scopes in line tables for
+// CodeView.
+
+namespace A {
+void f() {}
+
+struct S {
+  static void m() {}
+};
+}
+
+int main() {
+  A::f();
+  A::S::m();
+  return 0;
+  // MSVC:       !{{[0-9]+}} = distinct !DISubprogram(name: "f"
+  // MSVC-SAME:     scope: [[SCOPE1:![0-9]+]]
+  // MSVC-SAME:     )
+  // MSVC:       [[SCOPE1]] = !DINamespace(name: "A", {{.*}})
+  // MSVC:       !{{[0-9]+}} = distinct !DISubprogram(name: "m"
+  // MSVC-SAME:     scope: [[SCOPE2:![0-9]+]]
+  // MSVC-SAME:     )
+  // MSVC:       [[SCOPE2]] = !DICompositeType(tag: DW_TAG_structure_type,
+  // MSVC-SAME:     name: "S",
+  // MSVC-SAME:     scope: [[SCOPE1]]
+  // MSVC-SAME:     )
+
+  // LINUX-NOT: !DINamespace
+  // LINUX-NOT: !DICompositeType
+  return 0;
+}