diff options
author | Cary Coutant <ccoutant@google.com> | 2009-10-08 21:00:04 +0000 |
---|---|---|
committer | Cary Coutant <ccoutant@gcc.gnu.org> | 2009-10-08 14:00:04 -0700 |
commit | 77831620cf45a82c54a85091dcdc9e0affea47a9 (patch) | |
tree | d4e268cc74aaa313626c0a3a838960f89e919d48 /gcc | |
parent | 968e57283eda9b6f9eb513b0e8572c8a9efaa79f (diff) | |
download | gcc-77831620cf45a82c54a85091dcdc9e0affea47a9.zip gcc-77831620cf45a82c54a85091dcdc9e0affea47a9.tar.gz gcc-77831620cf45a82c54a85091dcdc9e0affea47a9.tar.bz2 |
Add support for debugging with ICF (Identical Code Folding).
gcc/ChangeLog:
Add support for debugging with ICF (Identical Code Folding).
* calls.c (debug.h): New #include.
(emit_call_1): Call virtual_call_token debug hook.
* common.opt (-fenable-icf-debug): New option.
* dwarf2out.c (dwarf2_debug_hooks): Add entries for new hooks (two
locations in the source).
(poc_label_num): New variable.
(dcall_entry, vcall_entry): New typedefs.
(dcall_table, vcall_table): New variables.
(struct vcall_insn): New type.
(vcall_insn_table): New variable.
(DEBUG_DCALL_SECTION, DEBUG_VCALL_SECTION): New macros.
(size_of_dcall_table): New function.
(output_dcall_table): New function.
(size_of_vcall_table): New function.
(output_vcall_table): New function.
(dwarf2out_direct_call): New function.
(vcall_insn_table_hash): New function.
(vcall_insn_table_eq): New function.
(dwarf2out_virtual_call_token): New function.
(dwarf2out_virtual_call): New function.
(dwarf2out_init): Allocate new tables and sections.
(prune_unused_types): Mark DIEs referenced from direct call table.
(dwarf2out_finish): Output direct and virtual call tables.
* final.c (final_scan_insn): Call direct_call and virtual_call
debug hooks.
* debug.h (struct gcc_debug_hooks): Add direct_call,
virtual_call_token, virtual_call hooks.
(debug_nothing_uid): New function.
* debug.c (do_nothing_debug_hooks): Add dummy entries for new hooks.
(debug_nothing_uid): New function.
* dbxout.c (dbx_debug_hooks): Add dummy entries for new hooks.
* sdbout.c (sdb_debug_hooks): Likewise.
* vmsdbgout.c (vmsdbg_debug_hooks): Likewise.
* doc/invoke.texi (-fenable-icf-debug): New option.
gcc/testsuite/ChangeLog:
Add support for debugging with ICF (Identical Code Folding).
* g++.dg/debug/dwarf2/icf.C: New test.
From-SVN: r152577
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 38 | ||||
-rw-r--r-- | gcc/calls.c | 6 | ||||
-rw-r--r-- | gcc/common.opt | 4 | ||||
-rw-r--r-- | gcc/dbxout.c | 6 | ||||
-rw-r--r-- | gcc/debug.c | 8 | ||||
-rw-r--r-- | gcc/debug.h | 20 | ||||
-rw-r--r-- | gcc/doc/invoke.texi | 6 | ||||
-rw-r--r-- | gcc/dwarf2out.c | 301 | ||||
-rw-r--r-- | gcc/final.c | 20 | ||||
-rw-r--r-- | gcc/sdbout.c | 6 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/debug/dwarf2/icf.C | 50 | ||||
-rw-r--r-- | gcc/vmsdbgout.c | 3 |
13 files changed, 473 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a7e2290..370fcac 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,41 @@ +2009-10-08 Cary Coutant <ccoutant@google.com> + + Add support for debugging with ICF (Identical Code Folding). + * calls.c (debug.h): New #include. + (emit_call_1): Call virtual_call_token debug hook. + * common.opt (-fenable-icf-debug): New option. + * dwarf2out.c (dwarf2_debug_hooks): Add entries for new hooks (two + locations in the source). + (poc_label_num): New variable. + (dcall_entry, vcall_entry): New typedefs. + (dcall_table, vcall_table): New variables. + (struct vcall_insn): New type. + (vcall_insn_table): New variable. + (DEBUG_DCALL_SECTION, DEBUG_VCALL_SECTION): New macros. + (size_of_dcall_table): New function. + (output_dcall_table): New function. + (size_of_vcall_table): New function. + (output_vcall_table): New function. + (dwarf2out_direct_call): New function. + (vcall_insn_table_hash): New function. + (vcall_insn_table_eq): New function. + (dwarf2out_virtual_call_token): New function. + (dwarf2out_virtual_call): New function. + (dwarf2out_init): Allocate new tables and sections. + (prune_unused_types): Mark DIEs referenced from direct call table. + (dwarf2out_finish): Output direct and virtual call tables. + * final.c (final_scan_insn): Call direct_call and virtual_call + debug hooks. + * debug.h (struct gcc_debug_hooks): Add direct_call, + virtual_call_token, virtual_call hooks. + (debug_nothing_uid): New function. + * debug.c (do_nothing_debug_hooks): Add dummy entries for new hooks. + (debug_nothing_uid): New function. + * dbxout.c (dbx_debug_hooks): Add dummy entries for new hooks. + * sdbout.c (sdb_debug_hooks): Likewise. + * vmsdbgout.c (vmsdbg_debug_hooks): Likewise. + * doc/invoke.texi (-fenable-icf-debug): New option. + 2009-10-08 Alexandre Oliva <aoliva@redhat.com> PR debug/41353 diff --git a/gcc/calls.c b/gcc/calls.c index f28fb51..49e576e 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see #include "sbitmap.h" #include "langhooks.h" #include "target.h" +#include "debug.h" #include "cgraph.h" #include "except.h" #include "dbgcnt.h" @@ -394,6 +395,11 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU SIBLING_CALL_P (call_insn) = ((ecf_flags & ECF_SIBCALL) != 0); + /* Record debug information for virtual calls. */ + if (flag_enable_icf_debug && fndecl == NULL) + (*debug_hooks->virtual_call_token) (CALL_EXPR_FN (fntree), + INSN_UID (call_insn)); + /* Restore this now, so that we do defer pops for this call's args if the context of the call as a whole permits. */ inhibit_defer_pop = old_inhibit_defer_pop; diff --git a/gcc/common.opt b/gcc/common.opt index de43201..dd2d815 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -502,6 +502,10 @@ femit-class-debug-always Common Report Var(flag_emit_class_debug_always) Init(0) Do not suppress C++ class debug information. +fenable-icf-debug +Common Report Var(flag_enable_icf_debug) +Generate debug information to support Identical Code Folding (ICF) + fexceptions Common Report Var(flag_exceptions) Optimization Enable exception handling diff --git a/gcc/dbxout.c b/gcc/dbxout.c index 097b20b..d09087a 100644 --- a/gcc/dbxout.c +++ b/gcc/dbxout.c @@ -373,6 +373,9 @@ const struct gcc_debug_hooks dbx_debug_hooks = dbxout_handle_pch, /* handle_pch */ debug_nothing_rtx, /* var_location */ debug_nothing_void, /* switch_text_section */ + debug_nothing_tree, /* direct_call */ + debug_nothing_tree_int, /* virtual_call_token */ + debug_nothing_uid, /* virtual_call */ debug_nothing_tree_tree, /* set_name */ 0 /* start_end_main_source_file */ }; @@ -406,6 +409,9 @@ const struct gcc_debug_hooks xcoff_debug_hooks = dbxout_handle_pch, /* handle_pch */ debug_nothing_rtx, /* var_location */ debug_nothing_void, /* switch_text_section */ + debug_nothing_tree, /* direct_call */ + debug_nothing_tree_int, /* virtual_call_token */ + debug_nothing_uid, /* virtual_call */ debug_nothing_tree_tree, /* set_name */ 0 /* start_end_main_source_file */ }; diff --git a/gcc/debug.c b/gcc/debug.c index df69fd5..8035c43 100644 --- a/gcc/debug.c +++ b/gcc/debug.c @@ -50,6 +50,9 @@ const struct gcc_debug_hooks do_nothing_debug_hooks = debug_nothing_int, /* handle_pch */ debug_nothing_rtx, /* var_location */ debug_nothing_void, /* switch_text_section */ + debug_nothing_tree, /* direct_call */ + debug_nothing_tree_int, /* virtual_call_token */ + debug_nothing_uid, /* virtual_call */ debug_nothing_tree_tree, /* set_name */ 0 /* start_end_main_source_file */ }; @@ -127,3 +130,8 @@ debug_nothing_tree_int (tree decl ATTRIBUTE_UNUSED, int local ATTRIBUTE_UNUSED) { } + +void +debug_nothing_uid (int uid ATTRIBUTE_UNUSED) +{ +} diff --git a/gcc/debug.h b/gcc/debug.h index de525fe..4009cd6 100644 --- a/gcc/debug.h +++ b/gcc/debug.h @@ -126,6 +126,25 @@ struct gcc_debug_hooks text sections. */ void (* switch_text_section) (void); + /* Records a direct call to the function DECL, noting the point of call + and the debug info for the function. Called from final_scan_insn + when ICF debugging is enabled. */ + void (* direct_call) (tree decl); + + /* Records the OBJ_TYPE_REF_TOKEN for a virtual call through ADDR, which + for C++ is the vtable slot index, noting the INSN_UID for the call + instruction. Called from calls.c:emit_call_1 when ICF debugging is + enabled. It's necessary to do this during lowering because the + call instruction and the OBJ_TYPE_REF become separated after that + point. */ + void (* virtual_call_token) (tree addr, int insn_uid); + + /* Records a virtual call given INSN_UID, which is the UID of the call + instruction. The UID is then mapped to the vtable slot index noted + during the lowering phase. Called from final_scan_insn when ICF + debugging is enabled. */ + void (* virtual_call) (int insn_uid); + /* Called from grokdeclarator. Replaces the anonymous name with the type name. */ void (* set_name) (tree, tree); @@ -151,6 +170,7 @@ extern void debug_nothing_tree_int (tree, int); extern void debug_nothing_tree_tree_tree_bool (tree, tree, tree, bool); extern bool debug_true_const_tree (const_tree); extern void debug_nothing_rtx (rtx); +extern void debug_nothing_uid (int); /* Hooks for various debug formats. */ extern const struct gcc_debug_hooks do_nothing_debug_hooks; diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 6d0d4c4..da7afea 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -307,6 +307,7 @@ Objective-C and Objective-C++ Dialects}. -fcompare-debug@r{[}=@var{opts}@r{]} -fcompare-debug-second @gol -feliminate-dwarf2-dups -feliminate-unused-debug-types @gol -feliminate-unused-debug-symbols -femit-class-debug-always @gol +-fenable-icf-debug @gol -fmem-report -fpre-ipa-mem-report -fpost-ipa-mem-report -fprofile-arcs @gol -frandom-seed=@var{string} -fsched-verbose=@var{n} @gol -fsel-sched-verbose -fsel-sched-dump-cfg -fsel-sched-pipelining-verbose @gol @@ -4609,6 +4610,11 @@ The default is @samp{-femit-struct-debug-detailed=all}. This option works only with DWARF 2. +@item -fenable-icf-debug +@opindex fenable-icf-debug +Generate additional debug information to support identical code folding (ICF). +This option only works with DWARF version 2 or higher. + @item -fno-merge-debug-strings @opindex fmerge-debug-strings @opindex fno-merge-debug-strings diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 7e0d466..27f2c45 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -224,6 +224,8 @@ static GTY(()) section *debug_line_section; static GTY(()) section *debug_loc_section; static GTY(()) section *debug_pubnames_section; static GTY(()) section *debug_pubtypes_section; +static GTY(()) section *debug_dcall_section; +static GTY(()) section *debug_vcall_section; static GTY(()) section *debug_str_section; static GTY(()) section *debug_ranges_section; static GTY(()) section *debug_frame_section; @@ -5413,6 +5415,9 @@ static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree, dw_die_ref); static void dwarf2out_abstract_function (tree); static void dwarf2out_var_location (rtx); +static void dwarf2out_direct_call (tree); +static void dwarf2out_virtual_call_token (tree, int); +static void dwarf2out_virtual_call (int); static void dwarf2out_begin_function (tree); static void dwarf2out_set_name (tree, tree); @@ -5448,6 +5453,9 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = debug_nothing_int, /* handle_pch */ dwarf2out_var_location, dwarf2out_switch_text_section, + dwarf2out_direct_call, + dwarf2out_virtual_call_token, + dwarf2out_virtual_call, dwarf2out_set_name, 1 /* start_end_main_source_file */ }; @@ -5828,6 +5836,45 @@ static GTY(()) bool have_location_lists; /* Unique label counter. */ static GTY(()) unsigned int loclabel_num; +/* Unique label counter for point-of-call tables. */ +static GTY(()) unsigned int poc_label_num; + +/* The direct call table structure. */ + +typedef struct GTY(()) dcall_struct { + unsigned int poc_label_num; + tree poc_decl; + dw_die_ref targ_die; +} +dcall_entry; + +DEF_VEC_O(dcall_entry); +DEF_VEC_ALLOC_O(dcall_entry, gc); + +/* The virtual call table structure. */ + +typedef struct GTY(()) vcall_struct { + unsigned int poc_label_num; + unsigned int vtable_slot; +} +vcall_entry; + +DEF_VEC_O(vcall_entry); +DEF_VEC_ALLOC_O(vcall_entry, gc); + +/* Pointers to the direct and virtual call tables. */ +static GTY (()) VEC (dcall_entry, gc) * dcall_table = NULL; +static GTY (()) VEC (vcall_entry, gc) * vcall_table = NULL; + +/* A hash table to map INSN_UIDs to vtable slot indexes. */ + +struct GTY (()) vcall_insn { + int insn_uid; + unsigned int vtable_slot; +}; + +static GTY ((param_is (struct vcall_insn))) htab_t vcall_insn_table; + #ifdef DWARF2_DEBUGGING_INFO /* Record whether the function being analyzed contains inlined functions. */ static int current_function_has_inlines; @@ -6165,6 +6212,12 @@ static void gen_remaining_tmpl_value_param_die_attribute (void); #ifndef DEBUG_PUBTYPES_SECTION #define DEBUG_PUBTYPES_SECTION ".debug_pubtypes" #endif +#ifndef DEBUG_DCALL_SECTION +#define DEBUG_DCALL_SECTION ".debug_dcall" +#endif +#ifndef DEBUG_VCALL_SECTION +#define DEBUG_VCALL_SECTION ".debug_vcall" +#endif #ifndef DEBUG_STR_SECTION #define DEBUG_STR_SECTION ".debug_str" #endif @@ -11684,6 +11737,129 @@ output_line_info (void) /* Output the marker for the end of the line number info. */ ASM_OUTPUT_LABEL (asm_out_file, l2); } + +/* Return the size of the .debug_dcall table for the compilation unit. */ + +static unsigned long +size_of_dcall_table (void) +{ + unsigned long size; + unsigned int i; + dcall_entry *p; + tree last_poc_decl = NULL; + + /* Header: version + debug info section pointer + pointer size. */ + size = 2 + DWARF_OFFSET_SIZE + 1; + + /* Each entry: code label + DIE offset. */ + for (i = 0; VEC_iterate (dcall_entry, dcall_table, i, p); i++) + { + gcc_assert (p->targ_die != NULL); + /* Insert a "from" entry when the point-of-call DIE offset changes. */ + if (p->poc_decl != last_poc_decl) + { + dw_die_ref poc_die = lookup_decl_die (p->poc_decl); + gcc_assert (poc_die); + last_poc_decl = p->poc_decl; + if (poc_die) + size += (DWARF_OFFSET_SIZE + + size_of_uleb128 (poc_die->die_offset)); + } + size += DWARF_OFFSET_SIZE + size_of_uleb128 (p->targ_die->die_offset); + } + + return size; +} + +/* Output the direct call table used to disambiguate PC values when + identical function have been merged. */ + +static void +output_dcall_table (void) +{ + unsigned i; + unsigned long dcall_length = size_of_dcall_table (); + dcall_entry *p; + char poc_label[MAX_ARTIFICIAL_LABEL_BYTES]; + tree last_poc_decl = NULL; + + if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + dw2_asm_output_data (4, 0xffffffff, + "Initial length escape value indicating 64-bit DWARF extension"); + dw2_asm_output_data (DWARF_OFFSET_SIZE, dcall_length, + "Length of Direct Call Table"); + dw2_asm_output_data (2, 4, "Version number"); + dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, + debug_info_section, + "Offset of Compilation Unit Info"); + dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)"); + + for (i = 0; VEC_iterate (dcall_entry, dcall_table, i, p); i++) + { + /* Insert a "from" entry when the point-of-call DIE offset changes. */ + if (p->poc_decl != last_poc_decl) + { + dw_die_ref poc_die = lookup_decl_die (p->poc_decl); + last_poc_decl = p->poc_decl; + if (poc_die) + { + dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, "New caller"); + dw2_asm_output_data_uleb128 (poc_die->die_offset, + "Caller DIE offset"); + } + } + ASM_GENERATE_INTERNAL_LABEL (poc_label, "LPOC", p->poc_label_num); + dw2_asm_output_addr (DWARF_OFFSET_SIZE, poc_label, "Point of call"); + dw2_asm_output_data_uleb128 (p->targ_die->die_offset, + "Callee DIE offset"); + } +} + +/* Return the size of the .debug_vcall table for the compilation unit. */ + +static unsigned long +size_of_vcall_table (void) +{ + unsigned long size; + unsigned int i; + vcall_entry *p; + + /* Header: version + pointer size. */ + size = 2 + 1; + + /* Each entry: code label + vtable slot index. */ + for (i = 0; VEC_iterate (vcall_entry, vcall_table, i, p); i++) + size += DWARF_OFFSET_SIZE + size_of_uleb128 (p->vtable_slot); + + return size; +} + +/* Output the virtual call table used to disambiguate PC values when + identical function have been merged. */ + +static void +output_vcall_table (void) +{ + unsigned i; + unsigned long vcall_length = size_of_vcall_table (); + vcall_entry *p; + char poc_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + dw2_asm_output_data (4, 0xffffffff, + "Initial length escape value indicating 64-bit DWARF extension"); + dw2_asm_output_data (DWARF_OFFSET_SIZE, vcall_length, + "Length of Virtual Call Table"); + dw2_asm_output_data (2, 4, "Version number"); + dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)"); + + for (i = 0; VEC_iterate (vcall_entry, vcall_table, i, p); i++) + { + ASM_GENERATE_INTERNAL_LABEL (poc_label, "LPOC", p->poc_label_num); + dw2_asm_output_addr (DWARF_OFFSET_SIZE, poc_label, "Point of call"); + dw2_asm_output_data_uleb128 (p->vtable_slot, "Vtable slot"); + } +} /* Given a pointer to a tree node for some base type, return a pointer to a DIE that describes the given type. @@ -19709,6 +19885,103 @@ dwarf2out_set_name (tree decl, tree name) add_name_attribute (die, dwarf2_name (name, 0)); } +/* Called by the final INSN scan whenever we see a direct function call. + Make an entry into the direct call table, recording the point of call + and a reference to the target function's debug entry. */ + +static void +dwarf2out_direct_call (tree targ) +{ + dcall_entry e; + tree origin = decl_ultimate_origin (targ); + + /* If this is a clone, use the abstract origin as the target. */ + if (origin) + targ = origin; + + e.poc_label_num = poc_label_num++; + e.poc_decl = current_function_decl; + e.targ_die = force_decl_die (targ); + VEC_safe_push (dcall_entry, gc, dcall_table, &e); + + /* Drop a label at the return point to mark the point of call. */ + ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LPOC", e.poc_label_num); +} + +/* Returns a hash value for X (which really is a struct vcall_insn). */ + +static hashval_t +vcall_insn_table_hash (const void *x) +{ + return (hashval_t) ((const struct vcall_insn *) x)->insn_uid; +} + +/* Return nonzero if insn_uid of struct vcall_insn *X is the same as + insnd_uid of *Y. */ + +static int +vcall_insn_table_eq (const void *x, const void *y) +{ + return (((const struct vcall_insn *) x)->insn_uid + == ((const struct vcall_insn *) y)->insn_uid); +} + +/* Called when lowering indirect calls to RTL. We make a note of INSN_UID + and the OBJ_TYPE_REF_TOKEN from ADDR. For C++ virtual calls, the token + is the vtable slot index that we will need to put in the virtual call + table later. */ + +static void +dwarf2out_virtual_call_token (tree addr, int insn_uid) +{ + if (is_cxx() && TREE_CODE (addr) == OBJ_TYPE_REF) + { + tree token = OBJ_TYPE_REF_TOKEN (addr); + if (TREE_CODE (token) == INTEGER_CST) + { + struct vcall_insn *item = GGC_NEW (struct vcall_insn); + struct vcall_insn **slot; + + gcc_assert (item); + item->insn_uid = insn_uid; + item->vtable_slot = TREE_INT_CST_LOW (token); + slot = (struct vcall_insn **) + htab_find_slot_with_hash (vcall_insn_table, &item, + (hashval_t) insn_uid, INSERT); + *slot = item; + } + } +} + +/* Called by the final INSN scan whenever we see a virtual function call. + Make an entry into the virtual call table, recording the point of call + and the slot index of the vtable entry used to call the virtual member + function. The slot index was associated with the INSN_UID during the + lowering to RTL. */ + +static void +dwarf2out_virtual_call (int insn_uid) +{ + vcall_entry e; + struct vcall_insn item; + struct vcall_insn *p; + + item.insn_uid = insn_uid; + item.vtable_slot = 0; + p = (struct vcall_insn *) htab_find_with_hash (vcall_insn_table, + (void *) &item, + (hashval_t) insn_uid); + if (p == NULL) + return; + + e.poc_label_num = poc_label_num++; + e.vtable_slot = p->vtable_slot; + VEC_safe_push (vcall_entry, gc, vcall_table, &e); + + /* Drop a label at the return point to mark the point of call. */ + ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LPOC", e.poc_label_num); +} + /* Called by the final INSN scan whenever we see a var location. We use it to drop labels in the right places, and throw the location in our lookup table. */ @@ -19997,6 +20270,10 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) pubname_table = VEC_alloc (pubname_entry, gc, 32); pubtype_table = VEC_alloc (pubname_entry, gc, 32); + /* Allocate the table that maps insn UIDs to vtable slot indexes. */ + vcall_insn_table = htab_create_ggc (10, vcall_insn_table_hash, + vcall_insn_table_eq, NULL); + /* Generate the initial DIE for the .debug section. Note that the (string) value given in the DW_AT_name attribute of the DW_TAG_compile_unit DIE will (typically) be a relative pathname and that this pathname should be @@ -20025,6 +20302,10 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) SECTION_DEBUG, NULL); debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION, SECTION_DEBUG, NULL); + debug_dcall_section = get_section (DEBUG_DCALL_SECTION, + SECTION_DEBUG, NULL); + debug_vcall_section = get_section (DEBUG_VCALL_SECTION, + SECTION_DEBUG, NULL); debug_str_section = get_section (DEBUG_STR_SECTION, DEBUG_STR_SECTION_FLAGS, NULL); debug_ranges_section = get_section (DEBUG_RANGES_SECTION, @@ -20399,6 +20680,7 @@ prune_unused_types (void) limbo_die_node *node; comdat_type_node *ctnode; pubname_ref pub; + dcall_entry *dcall; #if ENABLE_ASSERT_CHECKING /* All the marks should already be clear. */ @@ -20429,6 +20711,10 @@ prune_unused_types (void) for (i = 0; i < arange_table_in_use; i++) prune_unused_types_mark (arange_table[i], 1); + /* Mark nodes referenced from the direct call table. */ + for (i = 0; VEC_iterate (dcall_entry, dcall_table, i, dcall); i++) + prune_unused_types_mark (dcall->targ_die, 1); + /* Get rid of nodes that aren't marked; and update the string counts. */ if (debug_str_hash && debug_str_hash_forced) htab_traverse (debug_str_hash, prune_indirect_string, NULL); @@ -20890,6 +21176,18 @@ dwarf2out_finish (const char *filename) output_pubnames (pubtype_table); } + /* Output direct and virtual call tables if necessary. */ + if (!VEC_empty (dcall_entry, dcall_table)) + { + switch_to_section (debug_dcall_section); + output_dcall_table (); + } + if (!VEC_empty (vcall_entry, vcall_table)) + { + switch_to_section (debug_vcall_section); + output_vcall_table (); + } + /* Output the address range information. We only put functions in the arange table, so don't write it out if we don't have any. */ if (fde_table_in_use) @@ -20960,6 +21258,9 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = 0, /* handle_pch */ 0, /* var_location */ 0, /* switch_text_section */ + 0, /* direct_call */ + 0, /* virtual_call_token */ + 0, /* virtual_call */ 0, /* set_name */ 0 /* start_end_main_source_file */ }; diff --git a/gcc/final.c b/gcc/final.c index f121da1..b8f5e51 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -2684,6 +2684,26 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* Output assembler code from the template. */ output_asm_insn (templ, recog_data.operand); + /* Record point-of-call information for ICF debugging. */ + if (flag_enable_icf_debug && CALL_P (insn)) + { + rtx x = call_from_call_insn (insn); + x = XEXP (x, 0); + if (x && MEM_P (x)) + { + if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF) + { + tree t; + x = XEXP (x, 0); + t = SYMBOL_REF_DECL (x); + if (t) + (*debug_hooks->direct_call) (t); + } + else + (*debug_hooks->virtual_call) (INSN_UID (insn)); + } + } + /* Some target machines need to postscan each insn after it is output. */ if (targetm.asm_out.final_postscan_insn) diff --git a/gcc/sdbout.c b/gcc/sdbout.c index 1c4ddfa..0553740 100644 --- a/gcc/sdbout.c +++ b/gcc/sdbout.c @@ -337,6 +337,9 @@ const struct gcc_debug_hooks sdb_debug_hooks = debug_nothing_int, /* handle_pch */ debug_nothing_rtx, /* var_location */ debug_nothing_void, /* switch_text_section */ + debug_nothing_tree, /* direct_call */ + debug_nothing_tree_int, /* virtual_call_token */ + debug_nothing_uid, /* virtual_call */ debug_nothing_tree_tree, /* set_name */ 0 /* start_end_main_source_file */ }; @@ -1725,6 +1728,9 @@ const struct gcc_debug_hooks sdb_debug_hooks = 0, /* handle_pch */ 0, /* var_location */ 0, /* switch_text_section */ + 0, /* direct_call */ + 0, /* virtual_call_token */ + 0, /* virtual_call */ 0, /* set_name */ 0 /* start_end_main_source_file */ }; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4212a36..65e739f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2009-10-08 Cary Coutant <ccoutant@google.com> + + Add support for debugging with ICF (Identical Code Folding). + * g++.dg/debug/dwarf2/icf.C: New test. + 2009-10-08 Adam Nemet <anemet@caviumnetworks.com> * gcc.target/mips/truncate-6.c: New test. diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/icf.C b/gcc/testsuite/g++.dg/debug/dwarf2/icf.C new file mode 100644 index 0000000..627b834 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/icf.C @@ -0,0 +1,50 @@ +// Test support for ICF debugging. +// { dg-do compile } +// { dg-options "-O0 -gdwarf-2 -fenable-icf-debug -dA" } + +class A +{ + public: + A(); + virtual void work(); + virtual int p(); + private: + int i; +}; + +class B +{ + public: + B(); + ~B(); + void work(const A* a); + private: + int j; +}; + +int +test1(A* a) +{ + a->work(); +} + +int +test2(A* a) +{ + if (a->p()) + { + B b; + b.work(a); + } +} + +// Verify that we get .debug_dcall and .debug_vcall tables generated +// and that we see entries for both virtual calls. +// { dg-final { scan-assembler "\\.section.*\.debug_dcall" } } +// { dg-final { scan-assembler "\\.section.*\.debug_vcall" } } +// { dg-final { scan-assembler "New caller" } } +// { dg-final { scan-assembler "Caller DIE offset" } } +// { dg-final { scan-assembler "Point of call" } } +// { dg-final { scan-assembler "Callee DIE offset" } } +// { dg-final { scan-assembler "0x0.*Vtable slot" } } +// { dg-final { scan-assembler "0x1.*Vtable slot" } } diff --git a/gcc/vmsdbgout.c b/gcc/vmsdbgout.c index f7cca03..0fab5e7 100644 --- a/gcc/vmsdbgout.c +++ b/gcc/vmsdbgout.c @@ -213,6 +213,9 @@ const struct gcc_debug_hooks vmsdbg_debug_hooks debug_nothing_int, /* handle_pch */ debug_nothing_rtx, /* var_location */ debug_nothing_void, /* switch_text_section */ + debug_nothing_tree, /* direct_call */ + debug_nothing_tree_int, /* virtual_call_token */ + debug_nothing_uid, /* virtual_call */ debug_nothing_tree_tree, /* set_name */ 0 /* start_end_main_source_file */ }; |