Implement a new -fstandalone-debug option. rdar://problem/15685848

It controls everything that -flimit-debug-info used to, plus the
vtable type optimization. The old -fno-limit-debug-info option is now an
alias to -fstandalone-debug and vice versa.

Standalone is the default on Darwin until dtrace is updated to work with
non-standalone debug info (rdar://problem/15758808).

Note: I kept the LimitedDebugInfo name in CodeGenOptions::DebugInfoKind
because NoStandaloneDebugInfo sounded even more confusing.

llvm-svn: 198655
This commit is contained in:
Adrian Prantl 2014-01-07 01:19:08 +00:00
parent 0b8e3b2cb4
commit a763447124
15 changed files with 87 additions and 41 deletions

View File

@ -312,12 +312,19 @@ Currently equivalent to B<-O3>
Generate debug information. Note that Clang debug information works best at Generate debug information. Note that Clang debug information works best at
B<-O0>. B<-O0>.
=item B<-flimit-debug-info> B<-fno-limit-debug-info> =item B<-fstandalone-debug> B<-fno-standalone-debug>
By default Clang does not emit type definitions for types that are not Clang supports a number of optimizations to reduce the size of debug
needed by the module and could be replaced with a forward information in the binary. They work based on the assumption that the
declaration. By specifying B<-fno-limit-debug-info> this optimization debug type information can be spread out over multiple compilation
can be turned off. Note that Clang will never emit type information units. For instance, Clang will not emit type definitions for types
that are not needed by a module and could be replaced with a forward
declaration. Further, Clang will only emit type info for a dynamic
C++ class in the module that contains the vtable for the class.
The B<-fstandalone-debug> option turns off these optimizations. This
is useful when working with 3rd-party libraries that don't come with
debug information. Note that Clang will never emit type information
for types that are not referenced at all by the program. for types that are not referenced at all by the program.
=item B<-fexceptions> =item B<-fexceptions>

View File

@ -559,8 +559,6 @@ def finstrument_functions : Flag<["-"], "finstrument-functions">, Group<f_Group>
def fkeep_inline_functions : Flag<["-"], "fkeep-inline-functions">, Group<clang_ignored_f_Group>; def fkeep_inline_functions : Flag<["-"], "fkeep-inline-functions">, Group<clang_ignored_f_Group>;
def flat__namespace : Flag<["-"], "flat_namespace">; def flat__namespace : Flag<["-"], "flat_namespace">;
def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>; def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>;
def flimit_debug_info : Flag<["-"], "flimit-debug-info">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Limit debug information produced to reduce size of debug binary">;
def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>; def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>;
def flto : Flag<["-"], "flto">, Group<f_Group>; def flto : Flag<["-"], "flto">, Group<f_Group>;
def fno_lto : Flag<["-"], "fno-lto">, Group<f_Group>; def fno_lto : Flag<["-"], "fno-lto">, Group<f_Group>;
@ -654,8 +652,6 @@ def fno_inline : Flag<["-"], "fno-inline">, Group<f_clang_Group>, Flags<[CC1Opti
def fno_keep_inline_functions : Flag<["-"], "fno-keep-inline-functions">, Group<clang_ignored_f_Group>; def fno_keep_inline_functions : Flag<["-"], "fno-keep-inline-functions">, Group<clang_ignored_f_Group>;
def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group<f_Group>, def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group<f_Group>,
HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">, Flags<[CC1Option]>; HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">, Flags<[CC1Option]>;
def fno_limit_debug_info : Flag<["-"], "fno-limit-debug-info">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Do not limit debug information produced to reduce size of debug binary">;
def fno_merge_all_constants : Flag<["-"], "fno-merge-all-constants">, Group<f_Group>, def fno_merge_all_constants : Flag<["-"], "fno-merge-all-constants">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Disallow merging of constants">; Flags<[CC1Option]>, HelpText<"Disallow merging of constants">;
def fno_modules : Flag <["-"], "fno-modules">, Group<f_Group>, def fno_modules : Flag <["-"], "fno-modules">, Group<f_Group>,
@ -783,6 +779,12 @@ def fno_signed_char : Flag<["-"], "fno-signed-char">, Flags<[CC1Option]>,
def fsplit_stack : Flag<["-"], "fsplit-stack">, Group<f_Group>; def fsplit_stack : Flag<["-"], "fsplit-stack">, Group<f_Group>;
def fstack_protector_all : Flag<["-"], "fstack-protector-all">, Group<f_Group>; def fstack_protector_all : Flag<["-"], "fstack-protector-all">, Group<f_Group>;
def fstack_protector : Flag<["-"], "fstack-protector">, Group<f_Group>; def fstack_protector : Flag<["-"], "fstack-protector">, Group<f_Group>;
def fstandalone_debug : Flag<["-"], "fstandalone-debug">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Emit full debug info for all types used by the program">;
def fno_standalone_debug : Flag<["-"], "fno-standalone-debug">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Limit debug information produced to reduce size of debug binary">;
def flimit_debug_info : Flag<["-"], "flimit-debug-info">, Alias<fno_standalone_debug>;
def fno_limit_debug_info : Flag<["-"], "fno-limit-debug-info">, Alias<fstandalone_debug>;
def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group<f_Group>; def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group<f_Group>;
def fstrict_enums : Flag<["-"], "fstrict-enums">, Group<f_Group>, Flags<[CC1Option]>, def fstrict_enums : Flag<["-"], "fstrict-enums">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable optimizations based on the strict definition of an enum's " HelpText<"Enable optimizations based on the strict definition of an enum's "

View File

@ -50,12 +50,20 @@ public:
}; };
enum DebugInfoKind { enum DebugInfoKind {
NoDebugInfo, // Don't generate debug info. NoDebugInfo, /// Don't generate debug info.
DebugLineTablesOnly, // Emit only debug info necessary for generating
// line number tables (-gline-tables-only). DebugLineTablesOnly, /// Emit only debug info necessary for generating
LimitedDebugInfo, // Limit generated debug info to reduce size /// line number tables (-gline-tables-only).
// (-flimit-debug-info).
FullDebugInfo // Generate complete debug info. LimitedDebugInfo, /// Limit generated debug info to reduce size
/// (-fno-standalone-debug). This emits
/// forward decls for types that could be
/// replaced with forward decls in the source
/// code. For dynamic C++ classes type info
/// is only emitted int the module that
/// contains the classe's vtable.
FullDebugInfo /// Generate complete debug info.
}; };
enum TLSModel { enum TLSModel {

View File

@ -1464,13 +1464,13 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
// declaration. The completeType, completeRequiredType, and completeClassData // declaration. The completeType, completeRequiredType, and completeClassData
// callbacks will handle promoting the declaration to a definition. // callbacks will handle promoting the declaration to a definition.
if (T || if (T ||
// Under -flimit-debug-info:
(DebugKind <= CodeGenOptions::LimitedDebugInfo && (DebugKind <= CodeGenOptions::LimitedDebugInfo &&
// Under -flimit-debug-info, emit only a declaration unless the type is // Emit only a forward declaration unless the type is required.
// required to be complete. ((!RD->isCompleteDefinitionRequired() && CGM.getLangOpts().CPlusPlus) ||
!RD->isCompleteDefinitionRequired() && CGM.getLangOpts().CPlusPlus) ||
// If the class is dynamic, only emit a declaration. A definition will be // If the class is dynamic, only emit a declaration. A definition will be
// emitted whenever the vtable is emitted. // emitted whenever the vtable is emitted.
(CXXDecl && CXXDecl->hasDefinition() && CXXDecl->isDynamicClass())) { (CXXDecl && CXXDecl->hasDefinition() && CXXDecl->isDynamicClass())))) {
llvm::DIDescriptor FDContext = llvm::DIDescriptor FDContext =
getContextDescriptor(cast<Decl>(RD->getDeclContext())); getContextDescriptor(cast<Decl>(RD->getDeclContext()));
if (!T) if (!T)

View File

@ -2945,8 +2945,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Forward -f (flag) options which we can pass directly. // Forward -f (flag) options which we can pass directly.
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info); Args.AddLastArg(CmdArgs, options::OPT_fstandalone_debug);
Args.AddLastArg(CmdArgs, options::OPT_fno_limit_debug_info); Args.AddLastArg(CmdArgs, options::OPT_fno_standalone_debug);
Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names); Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names);
// AltiVec language extensions aren't relevant for assembling. // AltiVec language extensions aren't relevant for assembling.
if (!isa<PreprocessJobAction>(JA) || if (!isa<PreprocessJobAction>(JA) ||

View File

@ -296,7 +296,8 @@ static void ParseCommentArgs(CommentOptions &Opts, ArgList &Args) {
} }
static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags) { DiagnosticsEngine &Diags,
const TargetOptions &TargetOpts) {
using namespace options; using namespace options;
bool Success = true; bool Success = true;
@ -323,10 +324,16 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.setDebugInfo(CodeGenOptions::DebugLineTablesOnly); Opts.setDebugInfo(CodeGenOptions::DebugLineTablesOnly);
} else if (Args.hasArg(OPT_g_Flag) || Args.hasArg(OPT_gdwarf_2) || } else if (Args.hasArg(OPT_g_Flag) || Args.hasArg(OPT_gdwarf_2) ||
Args.hasArg(OPT_gdwarf_3) || Args.hasArg(OPT_gdwarf_4)) { Args.hasArg(OPT_gdwarf_3) || Args.hasArg(OPT_gdwarf_4)) {
if (Args.hasFlag(OPT_flimit_debug_info, OPT_fno_limit_debug_info, true)) bool Default = false;
Opts.setDebugInfo(CodeGenOptions::LimitedDebugInfo); // Until dtrace (via CTF) can deal with distributed debug info,
else // Darwin defaults to standalone/full debug info.
if (llvm::Triple(TargetOpts.Triple).isOSDarwin())
Default = true;
if (Args.hasFlag(OPT_fstandalone_debug, OPT_fno_standalone_debug, Default))
Opts.setDebugInfo(CodeGenOptions::FullDebugInfo); Opts.setDebugInfo(CodeGenOptions::FullDebugInfo);
else
Opts.setDebugInfo(CodeGenOptions::LimitedDebugInfo);
} }
Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info); Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info);
Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file); Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
@ -1662,8 +1669,9 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParseFileSystemArgs(Res.getFileSystemOpts(), *Args); ParseFileSystemArgs(Res.getFileSystemOpts(), *Args);
// FIXME: We shouldn't have to pass the DashX option around here // FIXME: We shouldn't have to pass the DashX option around here
InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags); InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags);
Success = ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags) ParseTargetArgs(Res.getTargetOpts(), *Args);
&& Success; Success = ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, DashX, Diags,
Res.getTargetOpts()) && Success;
ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args); ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args);
if (DashX != IK_AST && DashX != IK_LLVM_IR) { if (DashX != IK_AST && DashX != IK_LLVM_IR) {
ParseLangArgs(*Res.getLangOpts(), *Args, DashX, Diags); ParseLangArgs(*Res.getLangOpts(), *Args, DashX, Diags);
@ -1678,8 +1686,6 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, FileMgr, Diags); ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, FileMgr, Diags);
ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args, ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args,
Res.getFrontendOpts().ProgramAction); Res.getFrontendOpts().ProgramAction);
ParseTargetArgs(Res.getTargetOpts(), *Args);
return Success; return Success;
} }

View File

@ -1,4 +1,4 @@
// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s // RUN: %clang -emit-llvm -fno-standalone-debug -g -S %s -o - | FileCheck %s
namespace PR16214_1 { namespace PR16214_1 {
// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [def] // CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [def]

View File

@ -1,4 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-unk-unk -fno-limit-debug-info -o - -emit-llvm -g %s | FileCheck %s // RUN: %clang_cc1 -triple x86_64-unk-unk -fstandalone-debug -o - -emit-llvm -g %s | FileCheck %s
// On Darwin, this should be the default:
// RUN: %clang_cc1 -triple x86_64-apple-darwin -o - -emit-llvm -g %s | FileCheck %s
namespace rdar14101097_1 { // see also PR16214 namespace rdar14101097_1 { // see also PR16214
// Check that we emit debug info for the definition of a struct if the // Check that we emit debug info for the definition of a struct if the

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin -fno-limit-debug-info %s -o - | FileCheck %s // RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin -fstandalone-debug %s -o - | FileCheck %s
class Test class Test
{ {

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -flimit-debug-info -x c++ -g -S -emit-llvm < %s | FileCheck %s // RUN: %clang_cc1 -fno-standalone-debug -x c++ -g -S -emit-llvm < %s | FileCheck %s
// rdar://10336845 // rdar://10336845
// Preserve type qualifiers in -flimit-debug-info mode. // Preserve type qualifiers in -flimit-debug-info mode.

View File

@ -1,6 +1,6 @@
// RUN: %clang -g -S -emit-llvm %s -o - | FileCheck %s // RUN: %clang -g -fno-standalone-debug -S -emit-llvm %s -o - | FileCheck %s
// RUN: %clang -g -gline-tables-only -S -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-GMLT %s // RUN: %clang -g -gline-tables-only -S -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-GMLT %s
// RUN: %clang -g -fno-limit-debug-info -S -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-NOLIMIT %s // RUN: %clang -g -fstandalone-debug -S -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-NOLIMIT %s
namespace A { namespace A {
#line 1 "foo.cpp" #line 1 "foo.cpp"

View File

@ -1,5 +1,5 @@
// REQUIRES: x86-registered-target // REQUIRES: x86-registered-target
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -g -fno-limit-debug-info -S -mllvm -generate-dwarf-pub-sections=Enable %s -o - | FileCheck %s // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -g -fstandalone-debug -S -mllvm -generate-dwarf-pub-sections=Enable %s -o - | FileCheck %s
// FIXME: This testcase shouldn't rely on assembly emission. // FIXME: This testcase shouldn't rely on assembly emission.
//CHECK: Lpubtypes_begin[[SECNUM:[0-9]:]] //CHECK: Lpubtypes_begin[[SECNUM:[0-9]:]]

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -emit-llvm -flimit-debug-info -cxx-abi itanium -g %s -o - | FileCheck %s // RUN: %clang_cc1 -emit-llvm -fno-standalone-debug -cxx-abi itanium -g %s -o - | FileCheck %s
// Check that this pointer type is TC<int> // Check that this pointer type is TC<int>
// CHECK: ![[LINE:[0-9]+]] = {{.*}}"TC<int>", {{.*}} metadata !"_ZTS2TCIiE"} ; [ DW_TAG_class_type ] // CHECK: ![[LINE:[0-9]+]] = {{.*}}"TC<int>", {{.*}} metadata !"_ZTS2TCIiE"} ; [ DW_TAG_class_type ]

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s // RUN: %clang_cc1 -emit-llvm -g -fno-standalone-debug -triple x86_64-apple-darwin %s -o - | FileCheck %s
struct MyClass { struct MyClass {
template <int i> int add(int j) { template <int i> int add(int j) {

View File

@ -0,0 +1,21 @@
// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s
//
// This tests that the "emit debug info for a C++ class only in the
// module that has its vtable" optimization is disabled by default on
// Darwin.
//
// CHECK: [ DW_TAG_member ] [lost]
class A
{
virtual bool f() = 0;
int lost;
};
class B : public A
{
B *g();
};
B *B::g() {
return this;
}