This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
(C++) patch to debug info optimization
- To: gcc-patches at gcc dot gnu dot org
- Subject: (C++) patch to debug info optimization
- From: Jason Merrill <jason at cygnus dot com>
- Date: Mon, 15 Nov 1999 17:27:23 -0800
In the past, we've tried to limit where we emitted debug info for classes,
since it can get pretty big. It had problems with the info never being
emitted for some classes, and was largely disabled. This patch updates the
optimization so that polymorphic classes have their info emitted with the
vtable.
This is not very interesting on stabs targets that support the BINCL
optimization (such as Linux), but it's a slight win there, too.
1999-11-15 Jason Merrill <jason@casey.cygnus.com>
* search.c (maybe_suppress_debug_info): New function...
* class.c (finish_struct_1): ...split out from here.
* cp-tree.h: Declare it.
* decl2.c (finish_vtable_vardecl): Override TYPE_DECL_SUPPRESS_DEBUG
if we're writing out the vtable.
* decl.c, search.c (dfs_debug_mark, dfs_debug_unmarked_p,
note_debug_info_needed): #if 0 out.
Index: search.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/search.c,v
retrieving revision 1.129
diff -c -p -r1.129 search.c
*** search.c 1999/10/06 19:01:43 1.129
--- search.c 1999/11/16 00:53:09
*************** static tree marked_new_vtablep PROTO((tr
*** 103,110 ****
--- 103,112 ----
static tree unmarked_new_vtablep PROTO((tree, void *));
static tree marked_pushdecls_p PROTO((tree, void *));
static tree unmarked_pushdecls_p PROTO((tree, void *));
+ #if 0
static tree dfs_debug_unmarkedp PROTO((tree, void *));
static tree dfs_debug_mark PROTO((tree, void *));
+ #endif
static tree dfs_find_vbases PROTO((tree, void *));
static tree dfs_clear_vbase_slots PROTO((tree, void *));
static tree dfs_init_vbase_pointers PROTO((tree, void *));
*************** unmarked_pushdecls_p (binfo, data)
*** 2301,2307 ****
#if 0
static int dfs_search_slot_nonempty_p (binfo) tree binfo;
{ return CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) != 0; }
- #endif
static tree
dfs_debug_unmarkedp (binfo, data)
--- 2303,2308 ----
*************** dfs_debug_unmarkedp (binfo, data)
*** 2311,2316 ****
--- 2312,2318 ----
return (!CLASSTYPE_DEBUG_REQUESTED (BINFO_TYPE (binfo))
? binfo : NULL_TREE);
}
+ #endif
/* The worker functions for `dfs_walk'. These do not need to
test anything (vis a vis marking) if they are paired with
*************** dfs_unmark_new_vtable (binfo) tree binfo
*** 2351,2358 ****
static void
dfs_clear_search_slot (binfo) tree binfo;
{ CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) = 0; }
- #endif
static tree
dfs_debug_mark (binfo, data)
tree binfo;
--- 2353,2362 ----
static void
dfs_clear_search_slot (binfo) tree binfo;
{ CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) = 0; }
+ /* Keep this code around in case we later want to control debug info
+ based on whether a type is "used". Currently, we only suppress debug
+ info if we can emit it with the vtable. jason 1999-11-11) */
static tree
dfs_debug_mark (binfo, data)
tree binfo;
*************** dfs_debug_mark (binfo, data)
*** 2360,2406 ****
{
tree t = BINFO_TYPE (binfo);
- /* Use heuristic that if there are virtual functions,
- ignore until we see a non-inline virtual function. */
- tree methods = CLASSTYPE_METHOD_VEC (t);
-
CLASSTYPE_DEBUG_REQUESTED (t) = 1;
- if (methods == 0)
- return NULL_TREE;
-
/* If interface info is known, either we've already emitted the debug
info or we don't need to. */
if (CLASSTYPE_INTERFACE_KNOWN (t))
return NULL_TREE;
! /* If debug info is requested from this context for this type, supply it.
! If debug info is requested from another context for this type,
! see if some third context can supply it. */
! if (current_function_decl == NULL_TREE
! || DECL_CLASS_CONTEXT (current_function_decl) != t)
! {
! if (TREE_VEC_ELT (methods, 1))
! methods = TREE_VEC_ELT (methods, 1);
! else if (TREE_VEC_ELT (methods, 0))
! methods = TREE_VEC_ELT (methods, 0);
! else
! methods = TREE_VEC_ELT (methods, 2);
! methods = OVL_CURRENT (methods);
! while (methods)
! {
! if (DECL_VINDEX (methods)
! && DECL_THIS_INLINE (methods) == 0
! && DECL_ABSTRACT_VIRTUAL_P (methods) == 0)
! {
! /* Somebody, somewhere is going to have to define this
! virtual function. When they do, they will provide
! the debugging info. */
! return NULL_TREE;
! }
! methods = TREE_CHAIN (methods);
! }
! }
/* We cannot rely on some alien method to solve our problems,
so we must write out the debug info ourselves. */
TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = 0;
--- 2364,2381 ----
{
tree t = BINFO_TYPE (binfo);
CLASSTYPE_DEBUG_REQUESTED (t) = 1;
/* If interface info is known, either we've already emitted the debug
info or we don't need to. */
if (CLASSTYPE_INTERFACE_KNOWN (t))
return NULL_TREE;
! /* If the class has virtual functions, we'll emit the debug info
! with the vtable. */
! if (TYPE_VIRTUAL_P (t))
! return NULL_TREE;
!
/* We cannot rely on some alien method to solve our problems,
so we must write out the debug info ourselves. */
TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = 0;
*************** dfs_debug_mark (binfo, data)
*** 2408,2413 ****
--- 2383,2389 ----
return NULL_TREE;
}
+ #endif
struct vbase_info
{
*************** get_vbase_types (type)
*** 2933,2938 ****
--- 2909,2949 ----
return vbase_types;
}
+ /* Debug info for C++ classes can get very large; try to avoid
+ emitting it everywhere.
+
+ As it happens, this optimization wins even when the target supports
+ BINCL (though only slightly), so we always do it. */
+
+ void
+ maybe_suppress_debug_info (t)
+ tree t;
+ {
+ /* We don't bother with this for dwarf1, which shouldn't be used for C++
+ anyway. */
+ if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG
+ || write_symbols == NO_DEBUG)
+ return;
+
+ /* If we already know how we're handling this class, handle debug info
+ the same way. */
+ if (CLASSTYPE_INTERFACE_ONLY (t))
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
+ else if (CLASSTYPE_INTERFACE_KNOWN (t))
+ /* Don't set it. */;
+ /* If the class has virtual functions, write out the debug info
+ along with the vtable. */
+ else if (TYPE_VIRTUAL_P (t))
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
+
+ /* Otherwise, just emit the debug info normally. */
+ }
+
+ #if 0
+ /* Keep this code around in case we later want to control debug info
+ based on whether a type is "used". Currently, we only suppress debug
+ info if we can emit it with the vtable. jason 1999-11-11) */
+
/* If we want debug info for a type TYPE, make sure all its base types
are also marked as being potentially interesting. This avoids
the problem of not writing any debug info for intermediate basetypes
*************** note_debug_info_needed (type)
*** 2952,2961 ****
return;
/* We can't do the TYPE_DECL_SUPPRESS_DEBUG thing with DWARF, which
! does not support name references between translation units. Well, we
! could, but that would mean putting global labels in the debug output
! before each exported type and each of its functions and static data
! members. */
if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG
|| write_symbols == NO_DEBUG)
return;
--- 2963,2971 ----
return;
/* We can't do the TYPE_DECL_SUPPRESS_DEBUG thing with DWARF, which
! does not support name references between translation units. It supports
! symbolic references between translation units, but only within a single
! executable or shared library. */
if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG
|| write_symbols == NO_DEBUG)
return;
*************** note_debug_info_needed (type)
*** 2970,2975 ****
--- 2980,2986 ----
note_debug_info_needed (ttype);
}
}
+ #endif
/* Subroutines of push_class_decls (). */
*************** types_overlap_p (empty_type, next_type)
*** 3332,3339 ****
dfs_no_overlap_yet, &oi);
return oi.found_overlap;
}
! /* Given a vtable VAR, determine which binfo it comes from. */
tree
binfo_for_vtable (var)
--- 3343,3352 ----
dfs_no_overlap_yet, &oi);
return oi.found_overlap;
}
+
+ /* Given a vtable VAR, determine which binfo it comes from.
! FIXME What about secondary vtables? */
tree
binfo_for_vtable (var)
Index: class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.198
diff -c -p -r1.198 class.c
*** class.c 1999/11/07 22:21:28 1.198
--- class.c 1999/11/16 00:53:19
*************** finish_struct_1 (t)
*** 4183,4228 ****
if (warn_overloaded_virtual)
warn_hidden (t);
! #if 0
! /* This has to be done after we have sorted out what to do with
! the enclosing type. */
! if (write_symbols != DWARF_DEBUG)
! {
! /* Be smarter about nested classes here. If a type is nested,
! only output it if we would output the enclosing type. */
! if (DECL_CLASS_SCOPE_P (TYPE_MAIN_DECL (t)))
! DECL_IGNORED_P (TYPE_MAIN_DECL (t)) = TREE_ASM_WRITTEN (TYPE_MAIN_DECL (t));
! }
! #endif
!
! if (write_symbols != DWARF_DEBUG && write_symbols != DWARF2_DEBUG)
! {
! /* If the type has methods, we want to think about cutting down
! the amount of symbol table stuff we output. The value stored in
! the TYPE_DECL's DECL_IGNORED_P slot is a first approximation.
! For example, if a member function is seen and we decide to
! write out that member function, then we can change the value
! of the DECL_IGNORED_P slot, and the type will be output when
! that member function's debug info is written out.
!
! We can't do this with DWARF, which does not support name
! references between translation units. */
! if (CLASSTYPE_METHOD_VEC (t))
! {
! /* Don't output full info about any type
! which does not have its implementation defined here. */
! if (CLASSTYPE_INTERFACE_ONLY (t))
! TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
! #if 0
! /* XXX do something about this. */
! else if (CLASSTYPE_INTERFACE_UNKNOWN (t))
! /* Only a first approximation! */
! TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
! #endif
! }
! else if (CLASSTYPE_INTERFACE_ONLY (t))
! TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
! }
/* Finish debugging output for this type. */
rest_of_type_compilation (t, toplevel_bindings_p ());
--- 4183,4189 ----
if (warn_overloaded_virtual)
warn_hidden (t);
! maybe_suppress_debug_info (t);
/* Finish debugging output for this type. */
rest_of_type_compilation (t, toplevel_bindings_p ());
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.343
diff -c -p -r1.343 cp-tree.h
*** cp-tree.h 1999/11/09 08:15:07 1.343
--- cp-tree.h 1999/11/16 00:53:25
*************** cp-tree.h PROTO(
*** 3815,3820 ****
--- 3815,3821 ----
extern void expand_indirect_vtbls_init PROTO((tree, tree, tree));
extern void clear_search_slots PROTO((tree));
extern tree get_vbase_types PROTO((tree));
+ extern void maybe_suppress_debug_info PROTO((tree));
extern void note_debug_info_needed PROTO((tree));
extern void push_class_decls PROTO((tree));
extern void pop_class_decls PROTO((void));
Index: decl2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl2.c,v
retrieving revision 1.277
diff -c -p -r1.277 decl2.c
*** decl2.c 1999/11/05 23:11:57 1.277
--- decl2.c 1999/11/16 00:53:35
*************** finish_vtable_vardecl (t, data)
*** 2602,2607 ****
--- 2602,2615 ----
if (flag_syntax_only)
TREE_ASM_WRITTEN (vars) = 1;
+ /* Since we're writing out the vtable here, also write the debug
+ info. */
+ if (TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (ctype)))
+ {
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (ctype)) = 0;
+ rest_of_type_compilation (ctype, toplevel_bindings_p ());
+ }
+
return 1;
}
else if (!DECL_NEEDED_P (vars))
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.497
diff -c -p -r1.497 decl.c
*** decl.c 1999/11/09 08:15:07 1.497
--- decl.c 1999/11/16 00:53:53
*************** layout_var_decl (decl)
*** 7094,7105 ****
--- 7094,7110 ----
cp_error ("storage size of `%D' isn't known", decl);
TREE_TYPE (decl) = error_mark_node;
}
+ #if 0
+ /* Keep this code around in case we later want to control debug info
+ based on whether a type is "used". (jason 1999-11-11) */
+
else if (!DECL_EXTERNAL (decl) && IS_AGGR_TYPE (ttype))
/* Let debugger know it should output info for this type. */
note_debug_info_needed (ttype);
if (TREE_STATIC (decl) && DECL_CLASS_SCOPE_P (decl))
note_debug_info_needed (DECL_CONTEXT (decl));
+ #endif
if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl))
&& DECL_SIZE (decl) != NULL_TREE
*************** finish_function (lineno, flags)
*** 13511,13516 ****
--- 13516,13525 ----
tree ttype = target_type (fntype);
tree parmdecl;
+ #if 0
+ /* Keep this code around in case we later want to control debug info
+ based on whether a type is "used". (jason 1999-11-11) */
+
if (IS_AGGR_TYPE (ttype))
/* Let debugger know it should output info for this type. */
note_debug_info_needed (ttype);
*************** finish_function (lineno, flags)
*** 13522,13527 ****
--- 13531,13537 ----
/* Let debugger know it should output info for this type. */
note_debug_info_needed (ttype);
}
+ #endif
}
/* Clean house because we will need to reorder insns here. */
*************** finish_function (lineno, flags)
*** 13711,13718 ****
--- 13721,13733 ----
mark_inline_for_output (fndecl);
}
+ #if 0
+ /* Keep this code around in case we later want to control debug info
+ based on whether a type is "used". (jason 1999-11-11) */
+
if (ctype && TREE_ASM_WRITTEN (fndecl))
note_debug_info_needed (ctype);
+ #endif
returns_null |= can_reach_end;