aprantl created this revision.
aprantl added reviewers: dblaikie, dexonsmith.
aprantl added a subscriber: cfe-commits.
aprantl set the repository for this revision to rL LLVM.

As noted in the review thread for http://reviews.llvm.org/D18477 on 
llvm-commits, DWARF consumers such as dtrace's ctfconvert expect debug info for 
types to survive even if the underlying code that references those types has 
been optimized away.
This patch moves this logic from the backend, where it used to be 
unconditionally executed, into clang. For more info on this functionality check 
out DwarfDebug::collectDeadVariables(), added in r107027.

This code in this patch listens to the driver option -gfull, and lowers it to 
the new cc1 option -debug-retain-types (1).
When -debug-retain-types is present, CGDebugInfo will retain every(2) type it 
creates.

Implementation notes:
  1. I decided not use -fno-eliminate-unused-debug-symbols for consistency with 
our other cc1 debug options.
  2. I’m minimizing the set of retained types by only retaining top-level types.


Repository:
  rL LLVM

http://reviews.llvm.org/D18565

Files:
  include/clang/Driver/CC1Options.td
  include/clang/Frontend/CodeGenOptions.def
  lib/CodeGen/CGDebugInfo.cpp
  lib/CodeGen/CGDebugInfo.h
  lib/Driver/Tools.cpp
  lib/Frontend/CompilerInvocation.cpp
  test/CodeGen/debug-info-retain-types.c
  test/Driver/debug-options.c

Index: test/Driver/debug-options.c
===================================================================
--- test/Driver/debug-options.c
+++ test/Driver/debug-options.c
@@ -109,6 +109,12 @@
 // RUN: %clang -### -gmodules %s 2>&1 \
 // RUN:        | FileCheck -check-prefix=GEXTREFS %s
 //
+// RUN: %clang -### -S %s -gfull 2>&1 \
+// RUN:             | FileCheck --check-prefix=RETAIN %s
+//
+// RUN: %clang -### -S %s -g 2>&1 \
+// RUN:             | FileCheck --check-prefix=NO_RETAIN %s
+//
 // G: "-cc1"
 // G: "-debug-info-kind=limited"
 //
@@ -169,7 +175,8 @@
 // NOCI-NOT: "-dwarf-column-info"
 //
 // GEXTREFS: "-dwarf-ext-refs" "-fmodule-format=obj" "-debug-info-kind={{standalone|limited}}"
-
+// RETAIN: "-debug-info-retain-types"
+// NO_RETAIN-NOT: "-debug-info-retain-types"
 // RUN: not %clang -cc1 -debug-info-kind=watkind 2>&1 | FileCheck -check-prefix=BADSTRING1 %s
 // BADSTRING1: error: invalid value 'watkind' in '-debug-info-kind=watkind'
 // RUN: not %clang -cc1 -debugger-tuning=gmodal 2>&1 | FileCheck -check-prefix=BADSTRING2 %s
Index: test/CodeGen/debug-info-retain-types.c
===================================================================
--- /dev/null
+++ test/CodeGen/debug-info-retain-types.c
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -fblocks -emit-llvm -o - %s \
+// RUN:   -debug-info-kind=standalone -debug-info-retain-types | FileCheck %s
+// RUN: %clang_cc1 -fblocks -emit-llvm -o - %s \
+// RUN:   -debug-info-kind=standalone -debug-info-retain-types \
+// RUN:     | FileCheck %s --check-prefix=CHECK-MIN
+// RUN: %clang_cc1 -fblocks -emit-llvm -o - %s \
+// RUN:   -debug-info-kind=standalone | FileCheck %s --check-prefix=NORETAIN
+// NORETAIN-NOT: !DICompileUnit{{.*}}retainedTypes
+
+// CHECK-DAG: !DICompileUnit({{.*}}retainedTypes: ![[RETAINED:[0-9]+]]
+
+// Function type.
+// CHECK-DAG: !DISubprogram(name: "foo", {{.*}}type: ![[FNTY:[0-9]+]]
+static int foo(int i) { return i; }
+
+// Global variable.
+// CHECK-DAG: !DIGlobalVariable(name: "g", {{.*}}type: ![[GLOBTY:[0-9]+]]
+
+// Block capture.
+// CHECK-DAG: !DILocalVariable(name: "d", {{.*}}type: ![[BLOCKTY:[0-9]+]]
+
+// Local variable.
+// CHECK-DAG: !DILocalVariable(name: "xyz", {{.*}}type: ![[VARTY:[0-9]+]]
+static void bar() {
+  struct X { int a; int b; } xyz;
+}
+
+float g;
+int g1;
+
+void baz() {
+  double d;
+  void (^blockptr)(void) = ^(void) {
+    foo(0);
+    bar();
+  };
+}
+
+// CHECK-DAG: ![[RETAINED]] = {{.*}}![[FNTY]],{{.*}}![[BLOCKTY]],{{.*}}![[GLOBTY]],{{.*}}![[VARTY]]
+
+
+// CHECK-MIN: !DICompileUnit({{.*}}retainedTypes: ![[RETAINED:[0-9]+]]
+// CHECK-MIN: ![[RETAINED]] = !{![[A:.*]], ![[B:.*]], ![[C:.*]], ![[D:.*]], ![[E:.*]],
+// CHECK-MIN-NOT: ![[A]] = !DIBasicType(name: "int"
+// CHECK-MIN-NOT: ![[B]] = !DIBasicType(name: "int"
+// CHECK-MIN-NOT: ![[C]] = !DIBasicType(name: "int"
+// CHECK-MIN-NOT: ![[D]] = !DIBasicType(name: "int"
+// CHECK-MIN-NOT: ![[E]] = !DIBasicType(name: "int"
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -486,6 +486,7 @@
       Args.getAllArgValues(OPT_fwhole_program_vtables_blacklist_EQ);
   Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
   Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs);
+  Opts.RetainAllDebugTypes = Args.hasArg(OPT_debug_info_retain_types);
   Opts.DebugExplicitImport = Triple.isPS4CPU(); 
 
   for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ))
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -2600,7 +2600,8 @@
 static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs,
                                     codegenoptions::DebugInfoKind DebugInfoKind,
                                     unsigned DwarfVersion,
-                                    llvm::DebuggerKind DebuggerTuning) {
+                                    llvm::DebuggerKind DebuggerTuning,
+                                    bool RetainAllDebugTypes) {
   switch (DebugInfoKind) {
   case codegenoptions::DebugLineTablesOnly:
     CmdArgs.push_back("-debug-info-kind=line-tables-only");
@@ -2630,6 +2631,8 @@
   default:
     break;
   }
+  if (RetainAllDebugTypes)
+    CmdArgs.push_back(Args.MakeArgString("-debug-info-retain-types"));
 }
 
 static void CollectArgsForIntegratedAssembler(Compilation &C,
@@ -2747,7 +2750,8 @@
         } else {
           RenderDebugEnablingArgs(Args, CmdArgs,
                                   codegenoptions::LimitedDebugInfo,
-                                  DwarfVersion, llvm::DebuggerKind::Default);
+                                  DwarfVersion, llvm::DebuggerKind::Default,
+                                  /*retain types*/ false);
         }
       } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") ||
                  Value.startswith("-mhwdiv") || Value.startswith("-march")) {
@@ -4311,6 +4315,10 @@
     CmdArgs.push_back("-split-dwarf=Enable");
   }
 
+  bool RetainTypes =
+      !Args.hasFlag(options::OPT_feliminate_unused_debug_symbols,
+                    options::OPT_fno_eliminate_unused_debug_symbols, true);
+
   // After we've dealt with all combinations of things that could
   // make DebugInfoKind be other than None or DebugLineTablesOnly,
   // figure out if we need to "upgrade" it to standalone debug info.
@@ -4322,7 +4330,7 @@
   if (DebugInfoKind == codegenoptions::LimitedDebugInfo && NeedFullDebug)
     DebugInfoKind = codegenoptions::FullDebugInfo;
   RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion,
-                          DebuggerTuning);
+                          DebuggerTuning, RetainTypes);
 
   // -ggnu-pubnames turns on gnu style pubnames in the backend.
   if (Args.hasArg(options::OPT_ggnu_pubnames)) {
@@ -6183,7 +6191,8 @@
     RenderDebugEnablingArgs(Args, CmdArgs,
                             (WantDebug ? codegenoptions::LimitedDebugInfo
                                        : codegenoptions::NoDebugInfo),
-                            DwarfVersion, llvm::DebuggerKind::Default);
+                            DwarfVersion, llvm::DebuggerKind::Default,
+                            /*retain types*/ false);
 
     // Add the -fdebug-compilation-dir flag if needed.
     addDebugCompDirArg(Args, CmdArgs);
Index: lib/CodeGen/CGDebugInfo.h
===================================================================
--- lib/CodeGen/CGDebugInfo.h
+++ lib/CodeGen/CGDebugInfo.h
@@ -55,6 +55,7 @@
   CodeGenModule &CGM;
   const codegenoptions::DebugInfoKind DebugKind;
   bool DebugTypeExtRefs;
+  bool RetainAllDebugTypes;
   llvm::DIBuilder DBuilder;
   llvm::DICompileUnit *TheCU = nullptr;
   ModuleMap *ClangModuleMap = nullptr;
@@ -425,7 +426,10 @@
   llvm::DIFile *getOrCreateMainFile();
 
   /// Get the type from the cache or create a new type if necessary.
-  llvm::DIType *getOrCreateType(QualType Ty, llvm::DIFile *Fg);
+  /// If Retain is true, the type will be added to the list of
+  /// retained types if it isn't already cached.
+  llvm::DIType *getOrCreateType(QualType Ty, llvm::DIFile *Fg,
+                                bool Retain = false);
 
   /// Get a reference to a clang module.  If \p CreateSkeletonCU is true,
   /// this also creates a split dwarf skeleton compile unit.
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp
+++ lib/CodeGen/CGDebugInfo.cpp
@@ -46,6 +46,7 @@
 CGDebugInfo::CGDebugInfo(CodeGenModule &CGM)
     : CGM(CGM), DebugKind(CGM.getCodeGenOpts().getDebugInfo()),
       DebugTypeExtRefs(CGM.getCodeGenOpts().DebugTypeExtRefs),
+      RetainAllDebugTypes(CGM.getCodeGenOpts().RetainAllDebugTypes),
       DBuilder(CGM.getModule()) {
   for (const auto &KV : CGM.getCodeGenOpts().DebugPrefixMap)
     DebugPrefixMap[KV.first] = KV.second;
@@ -1447,8 +1448,7 @@
 llvm::DIType *CGDebugInfo::getOrCreateRecordType(QualType RTy,
                                                  SourceLocation Loc) {
   assert(DebugKind >= codegenoptions::LimitedDebugInfo);
-  llvm::DIType *T = getOrCreateType(RTy, getOrCreateFile(Loc));
-  return T;
+  return getOrCreateType(RTy, getOrCreateFile(Loc));
 }
 
 llvm::DIType *CGDebugInfo::getOrCreateInterfaceType(QualType D,
@@ -2190,7 +2190,8 @@
   RetainedTypes.push_back(CGM.getContext().getRecordType(&SD).getAsOpaquePtr());
 }
 
-llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) {
+llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit,
+                                           bool Retain) {
   if (Ty.isNull())
     return nullptr;
 
@@ -2206,6 +2207,9 @@
   // And update the type cache.
   TypeCache[TyPtr].reset(Res);
 
+  if (Retain)
+    RetainedTypes.push_back(TyPtr);
+
   return Res;
 }
 
@@ -2739,17 +2743,20 @@
   }
   unsigned LineNo = getLineNumber(Loc);
   unsigned ScopeLine = getLineNumber(ScopeLoc);
+  auto *FnTy = getOrCreateFunctionType(D, FnType, Unit);
+  if (RetainAllDebugTypes)
+    DBuilder.retainType(FnTy);
 
   // FIXME: The function declaration we're constructing here is mostly reusing
   // declarations from CXXMethodDecl and not constructing new ones for arbitrary
   // FunctionDecls. When/if we fix this we can have FDContext be TheCU/null for
   // all subprograms instead of the actual context since subprogram definitions
   // are emitted as CU level entities by the backend.
-  llvm::DISubprogram *SP = DBuilder.createFunction(
-      FDContext, Name, LinkageName, Unit, LineNo,
-      getOrCreateFunctionType(D, FnType, Unit), Fn->hasInternalLinkage(),
-      true /*definition*/, ScopeLine, Flags, CGM.getLangOpts().Optimize,
-      TParamsArray.get(), getFunctionDeclaration(D));
+  llvm::DISubprogram *SP =
+      DBuilder.createFunction(FDContext, Name, LinkageName, Unit, LineNo, FnTy,
+                              Fn->hasInternalLinkage(), true /*definition*/,
+                              ScopeLine, Flags, CGM.getLangOpts().Optimize,
+                              TParamsArray.get(), getFunctionDeclaration(D));
   Fn->setSubprogram(SP);
   // We might get here with a VarDecl in the case we're generating
   // code for the initialization of globals. Do not record these decls
@@ -2959,7 +2966,7 @@
   if (VD->hasAttr<BlocksAttr>())
     Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset);
   else
-    Ty = getOrCreateType(VD->getType(), Unit);
+    Ty = getOrCreateType(VD->getType(), Unit, RetainAllDebugTypes);
 
   // If there is no debug info for this type then do not emit debug info
   // for this variable.
@@ -3100,7 +3107,7 @@
   if (isByRef)
     Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset);
   else
-    Ty = getOrCreateType(VD->getType(), Unit);
+    Ty = getOrCreateType(VD->getType(), Unit, RetainAllDebugTypes);
 
   // Self is passed along as an implicit non-arg variable in a
   // block. Mark it as the object pointer.
@@ -3382,7 +3389,8 @@
     GV = CollectAnonRecordDecls(RD, Unit, LineNo, LinkageName, Var, DContext);
   } else {
     GV = DBuilder.createGlobalVariable(
-        DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit),
+        DContext, DeclName, LinkageName, Unit, LineNo,
+        getOrCreateType(T, Unit, RetainAllDebugTypes),
         Var->hasInternalLinkage(), Var,
         getOrCreateStaticDataMemberDeclarationOrNull(D));
   }
Index: include/clang/Frontend/CodeGenOptions.def
===================================================================
--- include/clang/Frontend/CodeGenOptions.def
+++ include/clang/Frontend/CodeGenOptions.def
@@ -180,6 +180,9 @@
                                        ///< contain explicit imports for 
                                        ///< anonymous namespaces
 
+CODEGENOPT(RetainAllDebugTypes, 1, 0) ///< Whether to keep debug types for
+                                      ///< code that is optimized away.
+
 CODEGENOPT(EmitLLVMUseLists, 1, 0) ///< Control whether to serialize use-lists.
 
 CODEGENOPT(WholeProgramVTables, 1, 0) ///< Whether to apply whole-program
Index: include/clang/Driver/CC1Options.td
===================================================================
--- include/clang/Driver/CC1Options.td
+++ include/clang/Driver/CC1Options.td
@@ -135,6 +135,8 @@
 def debug_info_kind_EQ : Joined<["-"], "debug-info-kind=">;
 def dwarf_version_EQ : Joined<["-"], "dwarf-version=">;
 def debugger_tuning_EQ : Joined<["-"], "debugger-tuning=">;
+def debug_info_retain_types : Flag<["-"], "debug-info-retain-types">,
+  HelpText<"Retain debug info for types that were optimized away">;
 def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">,
   HelpText<"The compilation directory to embed in the debug info.">;
 def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to