flags.h: Add flag_eliminate_unused_debug_types.
* flags.h: Add flag_eliminate_unused_debug_types. * toplev.c: Add flag_eliminate_unused_debug_types. (f_options): Add -feliminate-unused-debug-types. * dwarf2out.c (struct file_table): Add emitted member. (splice_child_die): Fix the parent pointer for the child being spliced. (lookup_filename): Maintain file_table.emitted array. Don't output .file directive here. (maybe_emit_file): (new) (init_file_table): Set up file_table.emitted. (dwarf2out_source_line): Use maybe_emit_file. (dwarf2out_start_source_file): Use maybe_emit_file. (dwarf2out_init): Use maybe_emit_file. (prune_unused_types_walk_attribs): (new) (prune_unused_types_mark): (new) (prune_unused_types_walk): (new) (prune_unused_types_prune): (new) (prune_unused_types): (new) (dwarf2out_finish): Call prune_unused_types if flag_eliminate_unused_debug_types is set. * doc/invoke.texi (Option Summary): Add -feliminate-unused-debug-types. (Debugging Options): Likewise. From-SVN: r63588
This commit is contained in:
parent
d8fad4ea49
commit
73c68f614d
@ -1,3 +1,29 @@
|
|||||||
|
2003-02-28 scott snyder <snyder@fnal.gov>
|
||||||
|
|
||||||
|
* flags.h: Add flag_eliminate_unused_debug_types.
|
||||||
|
* toplev.c: Add flag_eliminate_unused_debug_types.
|
||||||
|
(f_options): Add -feliminate-unused-debug-types.
|
||||||
|
* dwarf2out.c (struct file_table): Add emitted member.
|
||||||
|
(splice_child_die): Fix the parent pointer for the child being
|
||||||
|
spliced.
|
||||||
|
(lookup_filename): Maintain file_table.emitted array. Don't
|
||||||
|
output .file directive here.
|
||||||
|
(maybe_emit_file): (new)
|
||||||
|
(init_file_table): Set up file_table.emitted.
|
||||||
|
(dwarf2out_source_line): Use maybe_emit_file.
|
||||||
|
(dwarf2out_start_source_file): Use maybe_emit_file.
|
||||||
|
(dwarf2out_init): Use maybe_emit_file.
|
||||||
|
(prune_unused_types_walk_attribs): (new)
|
||||||
|
(prune_unused_types_mark): (new)
|
||||||
|
(prune_unused_types_walk): (new)
|
||||||
|
(prune_unused_types_prune): (new)
|
||||||
|
(prune_unused_types): (new)
|
||||||
|
(dwarf2out_finish): Call prune_unused_types if
|
||||||
|
flag_eliminate_unused_debug_types is set.
|
||||||
|
* doc/invoke.texi (Option Summary): Add
|
||||||
|
-feliminate-unused-debug-types.
|
||||||
|
(Debugging Options): Likewise.
|
||||||
|
|
||||||
2003-02-28 Geoffrey Keating <geoffk@apple.com>
|
2003-02-28 Geoffrey Keating <geoffk@apple.com>
|
||||||
|
|
||||||
* doc/invoke.texi: Change .pch to .gch.
|
* doc/invoke.texi: Change .pch to .gch.
|
||||||
|
@ -258,6 +258,7 @@ in the following sections.
|
|||||||
-p -pg -print-file-name=@var{library} -print-libgcc-file-name @gol
|
-p -pg -print-file-name=@var{library} -print-libgcc-file-name @gol
|
||||||
-print-multi-directory -print-multi-lib @gol
|
-print-multi-directory -print-multi-lib @gol
|
||||||
-print-prog-name=@var{program} -print-search-dirs -Q @gol
|
-print-prog-name=@var{program} -print-search-dirs -Q @gol
|
||||||
|
-feliminate-unused-debug-types @gol
|
||||||
-save-temps -time}
|
-save-temps -time}
|
||||||
|
|
||||||
@item Optimization Options
|
@item Optimization Options
|
||||||
@ -3412,6 +3413,18 @@ anything else.
|
|||||||
@opindex dumpspecs
|
@opindex dumpspecs
|
||||||
Print the compiler's built-in specs---and don't do anything else. (This
|
Print the compiler's built-in specs---and don't do anything else. (This
|
||||||
is used when GCC itself is being built.) @xref{Spec Files}.
|
is used when GCC itself is being built.) @xref{Spec Files}.
|
||||||
|
|
||||||
|
@item -feliminate-unused-debug-types
|
||||||
|
@opindex feliminate-unused-debug-types
|
||||||
|
Normally, when producing DWARF2 output, GCC will emit debugging
|
||||||
|
information for all types declared in a compilation
|
||||||
|
unit, regardless of whether or not they are actually used
|
||||||
|
in that compilation unit. Sometimes this is useful, such as
|
||||||
|
if, in the debugger, you want to cast a value to a type that is
|
||||||
|
not actually used in your program (but is declared). More often,
|
||||||
|
however, this results in a significant amount of wasted space.
|
||||||
|
With this option, GCC will avoid producing debug symbol output
|
||||||
|
for types that are nowhere used in the source file being compiled.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@node Optimize Options
|
@node Optimize Options
|
||||||
|
549
gcc/dwarf2out.c
549
gcc/dwarf2out.c
@ -337,7 +337,7 @@ static void dwarf2out_frame_debug_expr PARAMS ((rtx, const char *));
|
|||||||
/* Support for complex CFA locations. */
|
/* Support for complex CFA locations. */
|
||||||
static void output_cfa_loc PARAMS ((dw_cfi_ref));
|
static void output_cfa_loc PARAMS ((dw_cfi_ref));
|
||||||
static void get_cfa_from_loc_descr PARAMS ((dw_cfa_location *,
|
static void get_cfa_from_loc_descr PARAMS ((dw_cfa_location *,
|
||||||
struct dw_loc_descr_struct *));
|
struct dw_loc_descr_struct *));
|
||||||
static struct dw_loc_descr_struct *build_cfa_loc
|
static struct dw_loc_descr_struct *build_cfa_loc
|
||||||
PARAMS ((dw_cfa_location *));
|
PARAMS ((dw_cfa_location *));
|
||||||
static void def_cfa_1 PARAMS ((const char *,
|
static void def_cfa_1 PARAMS ((const char *,
|
||||||
@ -1236,7 +1236,7 @@ static dw_cfa_location cfa_temp;
|
|||||||
Rule 1:
|
Rule 1:
|
||||||
(set <reg1> <reg2>:cfa.reg)
|
(set <reg1> <reg2>:cfa.reg)
|
||||||
effects: cfa.reg = <reg1>
|
effects: cfa.reg = <reg1>
|
||||||
cfa.offset unchanged
|
cfa.offset unchanged
|
||||||
cfa_temp.reg = <reg1>
|
cfa_temp.reg = <reg1>
|
||||||
cfa_temp.offset = cfa.offset
|
cfa_temp.offset = cfa.offset
|
||||||
|
|
||||||
@ -1357,7 +1357,7 @@ dwarf2out_frame_debug_expr (expr, label)
|
|||||||
case REG:
|
case REG:
|
||||||
/* Rule 1 */
|
/* Rule 1 */
|
||||||
/* Update the CFA rule wrt SP or FP. Make sure src is
|
/* Update the CFA rule wrt SP or FP. Make sure src is
|
||||||
relative to the current CFA register. */
|
relative to the current CFA register. */
|
||||||
switch (GET_CODE (src))
|
switch (GET_CODE (src))
|
||||||
{
|
{
|
||||||
/* Setting FP from SP. */
|
/* Setting FP from SP. */
|
||||||
@ -1620,7 +1620,7 @@ dwarf2out_frame_debug_expr (expr, label)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Otherwise, we'll need to look in the stack to
|
/* Otherwise, we'll need to look in the stack to
|
||||||
calculate the CFA. */
|
calculate the CFA. */
|
||||||
rtx x = XEXP (dest, 0);
|
rtx x = XEXP (dest, 0);
|
||||||
|
|
||||||
if (GET_CODE (x) != REG)
|
if (GET_CODE (x) != REG)
|
||||||
@ -2123,13 +2123,13 @@ output_call_frame_info (for_eh)
|
|||||||
dw2_asm_output_data_uleb128 (size, "Augmentation size");
|
dw2_asm_output_data_uleb128 (size, "Augmentation size");
|
||||||
|
|
||||||
if (fde->uses_eh_lsda)
|
if (fde->uses_eh_lsda)
|
||||||
{
|
{
|
||||||
ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA",
|
ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA",
|
||||||
fde->funcdef_number);
|
fde->funcdef_number);
|
||||||
dw2_asm_output_encoded_addr_rtx (
|
dw2_asm_output_encoded_addr_rtx (
|
||||||
lsda_encoding, gen_rtx_SYMBOL_REF (Pmode, l1),
|
lsda_encoding, gen_rtx_SYMBOL_REF (Pmode, l1),
|
||||||
"Language Specific Data Area");
|
"Language Specific Data Area");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (lsda_encoding == DW_EH_PE_aligned)
|
if (lsda_encoding == DW_EH_PE_aligned)
|
||||||
@ -2151,7 +2151,7 @@ output_call_frame_info (for_eh)
|
|||||||
|
|
||||||
/* Pad the FDE out to an address sized boundary. */
|
/* Pad the FDE out to an address sized boundary. */
|
||||||
ASM_OUTPUT_ALIGN (asm_out_file,
|
ASM_OUTPUT_ALIGN (asm_out_file,
|
||||||
floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
|
floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
|
||||||
ASM_OUTPUT_LABEL (asm_out_file, l2);
|
ASM_OUTPUT_LABEL (asm_out_file, l2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2953,9 +2953,9 @@ output_loc_operands (loc)
|
|||||||
case DW_OP_skip:
|
case DW_OP_skip:
|
||||||
case DW_OP_bra:
|
case DW_OP_bra:
|
||||||
/* We currently don't make any attempt to make sure these are
|
/* We currently don't make any attempt to make sure these are
|
||||||
aligned properly like we do for the main unwind info, so
|
aligned properly like we do for the main unwind info, so
|
||||||
don't support emitting things larger than a byte if we're
|
don't support emitting things larger than a byte if we're
|
||||||
only doing unwinding. */
|
only doing unwinding. */
|
||||||
abort ();
|
abort ();
|
||||||
#endif
|
#endif
|
||||||
case DW_OP_const1u:
|
case DW_OP_const1u:
|
||||||
@ -3458,6 +3458,7 @@ static GTY(()) limbo_die_node *limbo_die_list;
|
|||||||
|
|
||||||
/* Filenames referenced by this compilation unit. */
|
/* Filenames referenced by this compilation unit. */
|
||||||
static GTY(()) varray_type file_table;
|
static GTY(()) varray_type file_table;
|
||||||
|
static GTY(()) varray_type file_table_emitted;
|
||||||
static GTY(()) size_t file_table_last_lookup_index;
|
static GTY(()) size_t file_table_last_lookup_index;
|
||||||
|
|
||||||
/* A pointer to the base of a table of references to DIE's that describe
|
/* A pointer to the base of a table of references to DIE's that describe
|
||||||
@ -3844,6 +3845,14 @@ static void add_loc_descr_to_loc_list PARAMS ((dw_loc_list_ref *,
|
|||||||
static void output_loc_list PARAMS ((dw_loc_list_ref));
|
static void output_loc_list PARAMS ((dw_loc_list_ref));
|
||||||
static char *gen_internal_sym PARAMS ((const char *));
|
static char *gen_internal_sym PARAMS ((const char *));
|
||||||
|
|
||||||
|
static void prune_unmark_dies PARAMS ((dw_die_ref));
|
||||||
|
static void prune_unused_types_mark PARAMS ((dw_die_ref, int));
|
||||||
|
static void prune_unused_types_walk PARAMS ((dw_die_ref));
|
||||||
|
static void prune_unused_types_walk_attribs PARAMS ((dw_die_ref));
|
||||||
|
static void prune_unused_types_prune PARAMS ((dw_die_ref));
|
||||||
|
static void prune_unused_types PARAMS ((void));
|
||||||
|
static int maybe_emit_file PARAMS ((int));
|
||||||
|
|
||||||
/* Section names used to hold DWARF debugging information. */
|
/* Section names used to hold DWARF debugging information. */
|
||||||
#ifndef DEBUG_INFO_SECTION
|
#ifndef DEBUG_INFO_SECTION
|
||||||
#define DEBUG_INFO_SECTION ".debug_info"
|
#define DEBUG_INFO_SECTION ".debug_info"
|
||||||
@ -5217,6 +5226,7 @@ splice_child_die (parent, child)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
child->die_parent = parent;
|
||||||
child->die_sib = parent->die_child;
|
child->die_sib = parent->die_child;
|
||||||
parent->die_child = child;
|
parent->die_child = child;
|
||||||
}
|
}
|
||||||
@ -5699,12 +5709,12 @@ same_dw_val_p (v1, v2, mark)
|
|||||||
return v1->v.val_unsigned == v2->v.val_unsigned;
|
return v1->v.val_unsigned == v2->v.val_unsigned;
|
||||||
case dw_val_class_long_long:
|
case dw_val_class_long_long:
|
||||||
return v1->v.val_long_long.hi == v2->v.val_long_long.hi
|
return v1->v.val_long_long.hi == v2->v.val_long_long.hi
|
||||||
&& v1->v.val_long_long.low == v2->v.val_long_long.low;
|
&& v1->v.val_long_long.low == v2->v.val_long_long.low;
|
||||||
case dw_val_class_float:
|
case dw_val_class_float:
|
||||||
if (v1->v.val_float.length != v2->v.val_float.length)
|
if (v1->v.val_float.length != v2->v.val_float.length)
|
||||||
return 0;
|
return 0;
|
||||||
for (i = 0; i < v1->v.val_float.length; i++)
|
for (i = 0; i < v1->v.val_float.length; i++)
|
||||||
if (v1->v.val_float.array[i] != v2->v.val_float.array[i])
|
if (v1->v.val_float.array[i] != v2->v.val_float.array[i])
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
case dw_val_class_flag:
|
case dw_val_class_flag:
|
||||||
@ -6145,7 +6155,7 @@ break_out_includes (die)
|
|||||||
if (is_dupl)
|
if (is_dupl)
|
||||||
*pnode = node->next;
|
*pnode = node->next;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pnode = &node->next;
|
pnode = &node->next;
|
||||||
record_comdat_symbol_number (node->die, cu_hash_table,
|
record_comdat_symbol_number (node->die, cu_hash_table,
|
||||||
comdat_symbol_number);
|
comdat_symbol_number);
|
||||||
@ -7078,7 +7088,7 @@ output_aranges ()
|
|||||||
if (DWARF_ARANGES_PAD_SIZE)
|
if (DWARF_ARANGES_PAD_SIZE)
|
||||||
{
|
{
|
||||||
/* Pad using a 2 byte words so that padding is correct for any
|
/* Pad using a 2 byte words so that padding is correct for any
|
||||||
pointer size. */
|
pointer size. */
|
||||||
dw2_asm_output_data (2, 0, "Pad to %d byte boundary",
|
dw2_asm_output_data (2, 0, "Pad to %d byte boundary",
|
||||||
2 * DWARF2_ADDR_SIZE);
|
2 * DWARF2_ADDR_SIZE);
|
||||||
for (i = 2; i < (unsigned) DWARF_ARANGES_PAD_SIZE; i += 2)
|
for (i = 2; i < (unsigned) DWARF_ARANGES_PAD_SIZE; i += 2)
|
||||||
@ -7582,8 +7592,8 @@ output_line_info ()
|
|||||||
prologue. */
|
prologue. */
|
||||||
|
|
||||||
/* Don't emit anything for redundant notes. Just updating the
|
/* Don't emit anything for redundant notes. Just updating the
|
||||||
address doesn't accomplish anything, because we already assume
|
address doesn't accomplish anything, because we already assume
|
||||||
that anything after the last address is this line. */
|
that anything after the last address is this line. */
|
||||||
if (line_info->dw_line_num == current_line
|
if (line_info->dw_line_num == current_line
|
||||||
&& line_info->dw_file_num == current_file)
|
&& line_info->dw_file_num == current_file)
|
||||||
continue;
|
continue;
|
||||||
@ -7609,7 +7619,7 @@ output_line_info ()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* This can handle any delta. This takes
|
/* This can handle any delta. This takes
|
||||||
4+DWARF2_ADDR_SIZE bytes. */
|
4+DWARF2_ADDR_SIZE bytes. */
|
||||||
dw2_asm_output_data (1, 0, "DW_LNE_set_address");
|
dw2_asm_output_data (1, 0, "DW_LNE_set_address");
|
||||||
dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
|
dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
|
||||||
dw2_asm_output_data (1, DW_LNE_set_address, NULL);
|
dw2_asm_output_data (1, DW_LNE_set_address, NULL);
|
||||||
@ -7831,9 +7841,9 @@ base_type_die (type)
|
|||||||
{
|
{
|
||||||
case INTEGER_TYPE:
|
case INTEGER_TYPE:
|
||||||
/* Carefully distinguish the C character types, without messing
|
/* Carefully distinguish the C character types, without messing
|
||||||
up if the language is not C. Note that we check only for the names
|
up if the language is not C. Note that we check only for the names
|
||||||
that contain spaces; other names might occur by coincidence in other
|
that contain spaces; other names might occur by coincidence in other
|
||||||
languages. */
|
languages. */
|
||||||
if (! (TYPE_PRECISION (type) == CHAR_TYPE_SIZE
|
if (! (TYPE_PRECISION (type) == CHAR_TYPE_SIZE
|
||||||
&& (type == char_type_node
|
&& (type == char_type_node
|
||||||
|| ! strcmp (type_name, "signed char")
|
|| ! strcmp (type_name, "signed char")
|
||||||
@ -8284,28 +8294,28 @@ mem_loc_descriptor (rtl, mode)
|
|||||||
|
|
||||||
case SUBREG:
|
case SUBREG:
|
||||||
/* The case of a subreg may arise when we have a local (register)
|
/* The case of a subreg may arise when we have a local (register)
|
||||||
variable or a formal (register) parameter which doesn't quite fill
|
variable or a formal (register) parameter which doesn't quite fill
|
||||||
up an entire register. For now, just assume that it is
|
up an entire register. For now, just assume that it is
|
||||||
legitimate to make the Dwarf info refer to the whole register which
|
legitimate to make the Dwarf info refer to the whole register which
|
||||||
contains the given subreg. */
|
contains the given subreg. */
|
||||||
rtl = SUBREG_REG (rtl);
|
rtl = SUBREG_REG (rtl);
|
||||||
|
|
||||||
/* ... fall through ... */
|
/* ... fall through ... */
|
||||||
|
|
||||||
case REG:
|
case REG:
|
||||||
/* Whenever a register number forms a part of the description of the
|
/* Whenever a register number forms a part of the description of the
|
||||||
method for calculating the (dynamic) address of a memory resident
|
method for calculating the (dynamic) address of a memory resident
|
||||||
object, DWARF rules require the register number be referred to as
|
object, DWARF rules require the register number be referred to as
|
||||||
a "base register". This distinction is not based in any way upon
|
a "base register". This distinction is not based in any way upon
|
||||||
what category of register the hardware believes the given register
|
what category of register the hardware believes the given register
|
||||||
belongs to. This is strictly DWARF terminology we're dealing with
|
belongs to. This is strictly DWARF terminology we're dealing with
|
||||||
here. Note that in cases where the location of a memory-resident
|
here. Note that in cases where the location of a memory-resident
|
||||||
data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
|
data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
|
||||||
OP_CONST (0)) the actual DWARF location descriptor that we generate
|
OP_CONST (0)) the actual DWARF location descriptor that we generate
|
||||||
may just be OP_BASEREG (basereg). This may look deceptively like
|
may just be OP_BASEREG (basereg). This may look deceptively like
|
||||||
the object in question was allocated to a register (rather than in
|
the object in question was allocated to a register (rather than in
|
||||||
memory) so DWARF consumers need to be aware of the subtle
|
memory) so DWARF consumers need to be aware of the subtle
|
||||||
distinction between OP_REG and OP_BASEREG. */
|
distinction between OP_REG and OP_BASEREG. */
|
||||||
if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
|
if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
|
||||||
mem_loc_result = based_loc_descr (reg_number (rtl), 0);
|
mem_loc_result = based_loc_descr (reg_number (rtl), 0);
|
||||||
break;
|
break;
|
||||||
@ -8354,7 +8364,7 @@ mem_loc_descriptor (rtl, mode)
|
|||||||
|
|
||||||
case PRE_MODIFY:
|
case PRE_MODIFY:
|
||||||
/* Extract the PLUS expression nested inside and fall into
|
/* Extract the PLUS expression nested inside and fall into
|
||||||
PLUS code below. */
|
PLUS code below. */
|
||||||
rtl = XEXP (rtl, 1);
|
rtl = XEXP (rtl, 1);
|
||||||
goto plus;
|
goto plus;
|
||||||
|
|
||||||
@ -8475,10 +8485,10 @@ loc_descriptor (rtl)
|
|||||||
{
|
{
|
||||||
case SUBREG:
|
case SUBREG:
|
||||||
/* The case of a subreg may arise when we have a local (register)
|
/* The case of a subreg may arise when we have a local (register)
|
||||||
variable or a formal (register) parameter which doesn't quite fill
|
variable or a formal (register) parameter which doesn't quite fill
|
||||||
up an entire register. For now, just assume that it is
|
up an entire register. For now, just assume that it is
|
||||||
legitimate to make the Dwarf info refer to the whole register which
|
legitimate to make the Dwarf info refer to the whole register which
|
||||||
contains the given subreg. */
|
contains the given subreg. */
|
||||||
rtl = SUBREG_REG (rtl);
|
rtl = SUBREG_REG (rtl);
|
||||||
|
|
||||||
/* ... fall through ... */
|
/* ... fall through ... */
|
||||||
@ -9199,9 +9209,9 @@ add_const_value_attribute (die, rtl)
|
|||||||
|
|
||||||
case CONST_DOUBLE:
|
case CONST_DOUBLE:
|
||||||
/* Note that a CONST_DOUBLE rtx could represent either an integer or a
|
/* Note that a CONST_DOUBLE rtx could represent either an integer or a
|
||||||
floating-point constant. A CONST_DOUBLE is used whenever the
|
floating-point constant. A CONST_DOUBLE is used whenever the
|
||||||
constant requires more than one word in order to be adequately
|
constant requires more than one word in order to be adequately
|
||||||
represented. We output CONST_DOUBLEs as blocks. */
|
represented. We output CONST_DOUBLEs as blocks. */
|
||||||
{
|
{
|
||||||
enum machine_mode mode = GET_MODE (rtl);
|
enum machine_mode mode = GET_MODE (rtl);
|
||||||
|
|
||||||
@ -9258,16 +9268,16 @@ add_const_value_attribute (die, rtl)
|
|||||||
|
|
||||||
case PLUS:
|
case PLUS:
|
||||||
/* In cases where an inlined instance of an inline function is passed
|
/* In cases where an inlined instance of an inline function is passed
|
||||||
the address of an `auto' variable (which is local to the caller) we
|
the address of an `auto' variable (which is local to the caller) we
|
||||||
can get a situation where the DECL_RTL of the artificial local
|
can get a situation where the DECL_RTL of the artificial local
|
||||||
variable (for the inlining) which acts as a stand-in for the
|
variable (for the inlining) which acts as a stand-in for the
|
||||||
corresponding formal parameter (of the inline function) will look
|
corresponding formal parameter (of the inline function) will look
|
||||||
like (plus:SI (reg:SI FRAME_PTR) (const_int ...)). This is not
|
like (plus:SI (reg:SI FRAME_PTR) (const_int ...)). This is not
|
||||||
exactly a compile-time constant expression, but it isn't the address
|
exactly a compile-time constant expression, but it isn't the address
|
||||||
of the (artificial) local variable either. Rather, it represents the
|
of the (artificial) local variable either. Rather, it represents the
|
||||||
*value* which the artificial local variable always has during its
|
*value* which the artificial local variable always has during its
|
||||||
lifetime. We currently have no way to represent such quasi-constant
|
lifetime. We currently have no way to represent such quasi-constant
|
||||||
values in Dwarf, so for now we just punt and generate nothing. */
|
values in Dwarf, so for now we just punt and generate nothing. */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -9366,7 +9376,7 @@ rtl_for_decl_location (decl)
|
|||||||
if (rtl
|
if (rtl
|
||||||
&& (CONSTANT_P (rtl)
|
&& (CONSTANT_P (rtl)
|
||||||
|| (GET_CODE (rtl) == MEM
|
|| (GET_CODE (rtl) == MEM
|
||||||
&& CONSTANT_P (XEXP (rtl, 0)))))
|
&& CONSTANT_P (XEXP (rtl, 0)))))
|
||||||
{
|
{
|
||||||
rtl = (*targetm.delegitimize_address) (rtl);
|
rtl = (*targetm.delegitimize_address) (rtl);
|
||||||
return rtl;
|
return rtl;
|
||||||
@ -9653,23 +9663,23 @@ add_bound_info (subrange_die, bound_attr, bound)
|
|||||||
|
|
||||||
case SAVE_EXPR:
|
case SAVE_EXPR:
|
||||||
/* If optimization is turned on, the SAVE_EXPRs that describe how to
|
/* If optimization is turned on, the SAVE_EXPRs that describe how to
|
||||||
access the upper bound values may be bogus. If they refer to a
|
access the upper bound values may be bogus. If they refer to a
|
||||||
register, they may only describe how to get at these values at the
|
register, they may only describe how to get at these values at the
|
||||||
points in the generated code right after they have just been
|
points in the generated code right after they have just been
|
||||||
computed. Worse yet, in the typical case, the upper bound values
|
computed. Worse yet, in the typical case, the upper bound values
|
||||||
will not even *be* computed in the optimized code (though the
|
will not even *be* computed in the optimized code (though the
|
||||||
number of elements will), so these SAVE_EXPRs are entirely
|
number of elements will), so these SAVE_EXPRs are entirely
|
||||||
bogus. In order to compensate for this fact, we check here to see
|
bogus. In order to compensate for this fact, we check here to see
|
||||||
if optimization is enabled, and if so, we don't add an attribute
|
if optimization is enabled, and if so, we don't add an attribute
|
||||||
for the (unknown and unknowable) upper bound. This should not
|
for the (unknown and unknowable) upper bound. This should not
|
||||||
cause too much trouble for existing (stupid?) debuggers because
|
cause too much trouble for existing (stupid?) debuggers because
|
||||||
they have to deal with empty upper bounds location descriptions
|
they have to deal with empty upper bounds location descriptions
|
||||||
anyway in order to be able to deal with incomplete array types.
|
anyway in order to be able to deal with incomplete array types.
|
||||||
Of course an intelligent debugger (GDB?) should be able to
|
Of course an intelligent debugger (GDB?) should be able to
|
||||||
comprehend that a missing upper bound specification in an array
|
comprehend that a missing upper bound specification in an array
|
||||||
type used for a storage class `auto' local array variable
|
type used for a storage class `auto' local array variable
|
||||||
indicates that the upper bound is both unknown (at compile- time)
|
indicates that the upper bound is both unknown (at compile- time)
|
||||||
and unknowable (at run-time) due to optimization.
|
and unknowable (at run-time) due to optimization.
|
||||||
|
|
||||||
We assume that a MEM rtx is safe because gcc wouldn't put the
|
We assume that a MEM rtx is safe because gcc wouldn't put the
|
||||||
value there unless it was going to be used repeatedly in the
|
value there unless it was going to be used repeatedly in the
|
||||||
@ -9790,7 +9800,7 @@ add_subscript_info (type_die, type)
|
|||||||
|
|
||||||
/* Arrays come in three flavors: Unspecified bounds, fixed bounds,
|
/* Arrays come in three flavors: Unspecified bounds, fixed bounds,
|
||||||
and (in GNU C only) variable bounds. Handle all three forms
|
and (in GNU C only) variable bounds. Handle all three forms
|
||||||
here. */
|
here. */
|
||||||
subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
|
subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
|
||||||
if (domain)
|
if (domain)
|
||||||
{
|
{
|
||||||
@ -9852,9 +9862,9 @@ add_byte_size_attribute (die, tree_node)
|
|||||||
break;
|
break;
|
||||||
case FIELD_DECL:
|
case FIELD_DECL:
|
||||||
/* For a data member of a struct or union, the DW_AT_byte_size is
|
/* For a data member of a struct or union, the DW_AT_byte_size is
|
||||||
generally given as the number of bytes normally allocated for an
|
generally given as the number of bytes normally allocated for an
|
||||||
object of the *declared* type of the member itself. This is true
|
object of the *declared* type of the member itself. This is true
|
||||||
even for bit-fields. */
|
even for bit-fields. */
|
||||||
size = simple_type_size_in_bits (field_type (tree_node)) / BITS_PER_UNIT;
|
size = simple_type_size_in_bits (field_type (tree_node)) / BITS_PER_UNIT;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -9979,7 +9989,7 @@ add_abstract_origin_attribute (die, origin)
|
|||||||
function, if we're in an exception handler or some such; make
|
function, if we're in an exception handler or some such; make
|
||||||
sure that the abstract function has been written out.
|
sure that the abstract function has been written out.
|
||||||
|
|
||||||
Doing this for nested functions is wrong, however; functions are
|
Doing this for nested functions is wrong, however; functions are
|
||||||
distinct units, and our context might not even be inline. */
|
distinct units, and our context might not even be inline. */
|
||||||
tree fn = origin;
|
tree fn = origin;
|
||||||
|
|
||||||
@ -10239,8 +10249,8 @@ type_tag (type)
|
|||||||
t = TYPE_NAME (type);
|
t = TYPE_NAME (type);
|
||||||
|
|
||||||
/* The g++ front end makes the TYPE_NAME of *each* tagged type point to
|
/* The g++ front end makes the TYPE_NAME of *each* tagged type point to
|
||||||
a TYPE_DECL node, regardless of whether or not a `typedef' was
|
a TYPE_DECL node, regardless of whether or not a `typedef' was
|
||||||
involved. */
|
involved. */
|
||||||
else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
|
else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
|
||||||
&& ! DECL_IGNORED_P (TYPE_NAME (type)))
|
&& ! DECL_IGNORED_P (TYPE_NAME (type)))
|
||||||
t = DECL_NAME (TYPE_NAME (type));
|
t = DECL_NAME (TYPE_NAME (type));
|
||||||
@ -10888,8 +10898,8 @@ gen_subprogram_die (decl, context_die)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Define the "frame base" location for this routine. We use the
|
/* Define the "frame base" location for this routine. We use the
|
||||||
frame pointer or stack pointer registers, since the RTL for local
|
frame pointer or stack pointer registers, since the RTL for local
|
||||||
variables is relative to one of them. */
|
variables is relative to one of them. */
|
||||||
fp_reg
|
fp_reg
|
||||||
= frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
|
= frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
|
||||||
add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg));
|
add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg));
|
||||||
@ -10927,7 +10937,7 @@ gen_subprogram_die (decl, context_die)
|
|||||||
tree parm;
|
tree parm;
|
||||||
|
|
||||||
/* When generating DIEs, generate the unspecified_parameters DIE
|
/* When generating DIEs, generate the unspecified_parameters DIE
|
||||||
instead if we come across the arg "__builtin_va_alist" */
|
instead if we come across the arg "__builtin_va_alist" */
|
||||||
for (parm = arg_decls; parm; parm = TREE_CHAIN (parm))
|
for (parm = arg_decls; parm; parm = TREE_CHAIN (parm))
|
||||||
if (TREE_CODE (parm) == PARM_DECL)
|
if (TREE_CODE (parm) == PARM_DECL)
|
||||||
{
|
{
|
||||||
@ -10940,11 +10950,11 @@ gen_subprogram_die (decl, context_die)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Decide whether we need an unspecified_parameters DIE at the end.
|
/* Decide whether we need an unspecified_parameters DIE at the end.
|
||||||
There are 2 more cases to do this for: 1) the ansi ... declaration -
|
There are 2 more cases to do this for: 1) the ansi ... declaration -
|
||||||
this is detectable when the end of the arg list is not a
|
this is detectable when the end of the arg list is not a
|
||||||
void_type_node 2) an unprototyped function declaration (not a
|
void_type_node 2) an unprototyped function declaration (not a
|
||||||
definition). This just means that we have no info about the
|
definition). This just means that we have no info about the
|
||||||
parameters at all. */
|
parameters at all. */
|
||||||
fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
|
fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
|
||||||
if (fn_arg_types != NULL)
|
if (fn_arg_types != NULL)
|
||||||
{
|
{
|
||||||
@ -11495,7 +11505,7 @@ gen_struct_or_union_type_die (type, context_die)
|
|||||||
if (complete)
|
if (complete)
|
||||||
{
|
{
|
||||||
/* Prevent infinite recursion in cases where the type of some member of
|
/* Prevent infinite recursion in cases where the type of some member of
|
||||||
this type is expressed in terms of this type itself. */
|
this type is expressed in terms of this type itself. */
|
||||||
TREE_ASM_WRITTEN (type) = 1;
|
TREE_ASM_WRITTEN (type) = 1;
|
||||||
add_byte_size_attribute (type_die, type);
|
add_byte_size_attribute (type_die, type);
|
||||||
if (TYPE_STUB_DECL (type) != NULL_TREE)
|
if (TYPE_STUB_DECL (type) != NULL_TREE)
|
||||||
@ -11645,7 +11655,7 @@ gen_type_die (type, context_die)
|
|||||||
TREE_ASM_WRITTEN (type) = 1;
|
TREE_ASM_WRITTEN (type) = 1;
|
||||||
|
|
||||||
/* For these types, all that is required is that we output a DIE (or a
|
/* For these types, all that is required is that we output a DIE (or a
|
||||||
set of DIEs) to represent the "basis" type. */
|
set of DIEs) to represent the "basis" type. */
|
||||||
gen_type_die (TREE_TYPE (type), context_die);
|
gen_type_die (TREE_TYPE (type), context_die);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -11658,7 +11668,7 @@ gen_type_die (type, context_die)
|
|||||||
gen_type_die (TREE_TYPE (type), context_die);
|
gen_type_die (TREE_TYPE (type), context_die);
|
||||||
|
|
||||||
/* Now output a DIE to represent this pointer-to-data-member type
|
/* Now output a DIE to represent this pointer-to-data-member type
|
||||||
itself. */
|
itself. */
|
||||||
gen_ptr_to_mbr_type_die (type, context_die);
|
gen_ptr_to_mbr_type_die (type, context_die);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -11703,11 +11713,11 @@ gen_type_die (type, context_die)
|
|||||||
case UNION_TYPE:
|
case UNION_TYPE:
|
||||||
case QUAL_UNION_TYPE:
|
case QUAL_UNION_TYPE:
|
||||||
/* If this is a nested type whose containing class hasn't been written
|
/* If this is a nested type whose containing class hasn't been written
|
||||||
out yet, writing it out will cover this one, too. This does not apply
|
out yet, writing it out will cover this one, too. This does not apply
|
||||||
to instantiations of member class templates; they need to be added to
|
to instantiations of member class templates; they need to be added to
|
||||||
the containing class as they are generated. FIXME: This hurts the
|
the containing class as they are generated. FIXME: This hurts the
|
||||||
idea of combining type decls from multiple TUs, since we can't predict
|
idea of combining type decls from multiple TUs, since we can't predict
|
||||||
what set of template instantiations we'll get. */
|
what set of template instantiations we'll get. */
|
||||||
if (TYPE_CONTEXT (type)
|
if (TYPE_CONTEXT (type)
|
||||||
&& AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
|
&& AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
|
||||||
&& ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
|
&& ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
|
||||||
@ -11850,12 +11860,12 @@ gen_block_die (stmt, context_die, depth)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* In the case where the current block represents an inlining of the
|
/* In the case where the current block represents an inlining of the
|
||||||
"body block" of an inline function, we must *NOT* output any DIE for
|
"body block" of an inline function, we must *NOT* output any DIE for
|
||||||
this block because we have already output a DIE to represent the whole
|
this block because we have already output a DIE to represent the whole
|
||||||
inlined function scope and the "body block" of any function doesn't
|
inlined function scope and the "body block" of any function doesn't
|
||||||
really represent a different scope according to ANSI C rules. So we
|
really represent a different scope according to ANSI C rules. So we
|
||||||
check here to make sure that this block does not represent a "body
|
check here to make sure that this block does not represent a "body
|
||||||
block inlining" before trying to set the MUST_OUTPUT_DIE flag. */
|
block inlining" before trying to set the MUST_OUTPUT_DIE flag. */
|
||||||
if (! is_body_block (origin ? origin : stmt))
|
if (! is_body_block (origin ? origin : stmt))
|
||||||
{
|
{
|
||||||
/* Determine if this block directly contains any "significant"
|
/* Determine if this block directly contains any "significant"
|
||||||
@ -11980,7 +11990,7 @@ gen_decl_die (decl, context_die)
|
|||||||
|
|
||||||
case CONST_DECL:
|
case CONST_DECL:
|
||||||
/* The individual enumerators of an enum type get output when we output
|
/* The individual enumerators of an enum type get output when we output
|
||||||
the Dwarf representation of the relevant enum type itself. */
|
the Dwarf representation of the relevant enum type itself. */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FUNCTION_DECL:
|
case FUNCTION_DECL:
|
||||||
@ -12030,16 +12040,16 @@ gen_decl_die (decl, context_die)
|
|||||||
|
|
||||||
case TYPE_DECL:
|
case TYPE_DECL:
|
||||||
/* If we are in terse mode, don't generate any DIEs to represent any
|
/* If we are in terse mode, don't generate any DIEs to represent any
|
||||||
actual typedefs. */
|
actual typedefs. */
|
||||||
if (debug_info_level <= DINFO_LEVEL_TERSE)
|
if (debug_info_level <= DINFO_LEVEL_TERSE)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* In the special case of a TYPE_DECL node representing the declaration
|
/* In the special case of a TYPE_DECL node representing the declaration
|
||||||
of some type tag, if the given TYPE_DECL is marked as having been
|
of some type tag, if the given TYPE_DECL is marked as having been
|
||||||
instantiated from some other (original) TYPE_DECL node (e.g. one which
|
instantiated from some other (original) TYPE_DECL node (e.g. one which
|
||||||
was generated within the original definition of an inline function) we
|
was generated within the original definition of an inline function) we
|
||||||
have to generate a special (abbreviated) DW_TAG_structure_type,
|
have to generate a special (abbreviated) DW_TAG_structure_type,
|
||||||
DW_TAG_union_type, or DW_TAG_enumeration_type DIE here. */
|
DW_TAG_union_type, or DW_TAG_enumeration_type DIE here. */
|
||||||
if (TYPE_DECL_IS_STUB (decl) && decl_ultimate_origin (decl) != NULL_TREE)
|
if (TYPE_DECL_IS_STUB (decl) && decl_ultimate_origin (decl) != NULL_TREE)
|
||||||
{
|
{
|
||||||
gen_tagged_type_instantiation_die (TREE_TYPE (decl), context_die);
|
gen_tagged_type_instantiation_die (TREE_TYPE (decl), context_die);
|
||||||
@ -12060,12 +12070,12 @@ gen_decl_die (decl, context_die)
|
|||||||
|
|
||||||
case VAR_DECL:
|
case VAR_DECL:
|
||||||
/* If we are in terse mode, don't generate any DIEs to represent any
|
/* If we are in terse mode, don't generate any DIEs to represent any
|
||||||
variable declarations or definitions. */
|
variable declarations or definitions. */
|
||||||
if (debug_info_level <= DINFO_LEVEL_TERSE)
|
if (debug_info_level <= DINFO_LEVEL_TERSE)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Output any DIEs that are needed to specify the type of this data
|
/* Output any DIEs that are needed to specify the type of this data
|
||||||
object. */
|
object. */
|
||||||
gen_type_die (TREE_TYPE (decl), context_die);
|
gen_type_die (TREE_TYPE (decl), context_die);
|
||||||
|
|
||||||
/* And its containing type. */
|
/* And its containing type. */
|
||||||
@ -12074,9 +12084,9 @@ gen_decl_die (decl, context_die)
|
|||||||
gen_type_die_for_member (origin, decl, context_die);
|
gen_type_die_for_member (origin, decl, context_die);
|
||||||
|
|
||||||
/* Now output the DIE to represent the data object itself. This gets
|
/* Now output the DIE to represent the data object itself. This gets
|
||||||
complicated because of the possibility that the VAR_DECL really
|
complicated because of the possibility that the VAR_DECL really
|
||||||
represents an inlined instance of a formal parameter for an inline
|
represents an inlined instance of a formal parameter for an inline
|
||||||
function. */
|
function. */
|
||||||
origin = decl_ultimate_origin (decl);
|
origin = decl_ultimate_origin (decl);
|
||||||
if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL)
|
if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL)
|
||||||
gen_formal_parameter_die (decl, context_die);
|
gen_formal_parameter_die (decl, context_die);
|
||||||
@ -12163,32 +12173,32 @@ dwarf2out_decl (decl)
|
|||||||
|
|
||||||
case FUNCTION_DECL:
|
case FUNCTION_DECL:
|
||||||
/* Ignore this FUNCTION_DECL if it refers to a builtin declaration of a
|
/* Ignore this FUNCTION_DECL if it refers to a builtin declaration of a
|
||||||
builtin function. Explicit programmer-supplied declarations of
|
builtin function. Explicit programmer-supplied declarations of
|
||||||
these same functions should NOT be ignored however. */
|
these same functions should NOT be ignored however. */
|
||||||
if (DECL_EXTERNAL (decl) && DECL_BUILT_IN (decl))
|
if (DECL_EXTERNAL (decl) && DECL_BUILT_IN (decl))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* What we would really like to do here is to filter out all mere
|
/* What we would really like to do here is to filter out all mere
|
||||||
file-scope declarations of file-scope functions which are never
|
file-scope declarations of file-scope functions which are never
|
||||||
referenced later within this translation unit (and keep all of ones
|
referenced later within this translation unit (and keep all of ones
|
||||||
that *are* referenced later on) but we aren't clairvoyant, so we have
|
that *are* referenced later on) but we aren't clairvoyant, so we have
|
||||||
no idea which functions will be referenced in the future (i.e. later
|
no idea which functions will be referenced in the future (i.e. later
|
||||||
on within the current translation unit). So here we just ignore all
|
on within the current translation unit). So here we just ignore all
|
||||||
file-scope function declarations which are not also definitions. If
|
file-scope function declarations which are not also definitions. If
|
||||||
and when the debugger needs to know something about these functions,
|
and when the debugger needs to know something about these functions,
|
||||||
it will have to hunt around and find the DWARF information associated
|
it will have to hunt around and find the DWARF information associated
|
||||||
with the definition of the function.
|
with the definition of the function.
|
||||||
|
|
||||||
We can't just check DECL_EXTERNAL to find out which FUNCTION_DECL
|
We can't just check DECL_EXTERNAL to find out which FUNCTION_DECL
|
||||||
nodes represent definitions and which ones represent mere
|
nodes represent definitions and which ones represent mere
|
||||||
declarations. We have to check DECL_INITIAL instead. That's because
|
declarations. We have to check DECL_INITIAL instead. That's because
|
||||||
the C front-end supports some weird semantics for "extern inline"
|
the C front-end supports some weird semantics for "extern inline"
|
||||||
function definitions. These can get inlined within the current
|
function definitions. These can get inlined within the current
|
||||||
translation unit (an thus, we need to generate Dwarf info for their
|
translation unit (an thus, we need to generate Dwarf info for their
|
||||||
abstract instances so that the Dwarf info for the concrete inlined
|
abstract instances so that the Dwarf info for the concrete inlined
|
||||||
instances can have something to refer to) but the compiler never
|
instances can have something to refer to) but the compiler never
|
||||||
generates any out-of-lines instances of such things (despite the fact
|
generates any out-of-lines instances of such things (despite the fact
|
||||||
that they *are* definitions).
|
that they *are* definitions).
|
||||||
|
|
||||||
The important point is that the C front-end marks these "extern
|
The important point is that the C front-end marks these "extern
|
||||||
inline" functions as DECL_EXTERNAL, but we need to generate DWARF for
|
inline" functions as DECL_EXTERNAL, but we need to generate DWARF for
|
||||||
@ -12207,18 +12217,18 @@ dwarf2out_decl (decl)
|
|||||||
|
|
||||||
case VAR_DECL:
|
case VAR_DECL:
|
||||||
/* Ignore this VAR_DECL if it refers to a file-scope extern data object
|
/* Ignore this VAR_DECL if it refers to a file-scope extern data object
|
||||||
declaration and if the declaration was never even referenced from
|
declaration and if the declaration was never even referenced from
|
||||||
within this entire compilation unit. We suppress these DIEs in
|
within this entire compilation unit. We suppress these DIEs in
|
||||||
order to save space in the .debug section (by eliminating entries
|
order to save space in the .debug section (by eliminating entries
|
||||||
which are probably useless). Note that we must not suppress
|
which are probably useless). Note that we must not suppress
|
||||||
block-local extern declarations (whether used or not) because that
|
block-local extern declarations (whether used or not) because that
|
||||||
would screw-up the debugger's name lookup mechanism and cause it to
|
would screw-up the debugger's name lookup mechanism and cause it to
|
||||||
miss things which really ought to be in scope at a given point. */
|
miss things which really ought to be in scope at a given point. */
|
||||||
if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
|
if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* If we are in terse mode, don't generate any DIEs to represent any
|
/* If we are in terse mode, don't generate any DIEs to represent any
|
||||||
variable declarations or definitions. */
|
variable declarations or definitions. */
|
||||||
if (debug_info_level <= DINFO_LEVEL_TERSE)
|
if (debug_info_level <= DINFO_LEVEL_TERSE)
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
@ -12229,11 +12239,11 @@ dwarf2out_decl (decl)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* Don't bother trying to generate any DIEs to represent any of the
|
/* Don't bother trying to generate any DIEs to represent any of the
|
||||||
normal built-in types for the language we are compiling. */
|
normal built-in types for the language we are compiling. */
|
||||||
if (DECL_SOURCE_LINE (decl) == 0)
|
if (DECL_SOURCE_LINE (decl) == 0)
|
||||||
{
|
{
|
||||||
/* OK, we need to generate one for `bool' so GDB knows what type
|
/* OK, we need to generate one for `bool' so GDB knows what type
|
||||||
comparisons have. */
|
comparisons have. */
|
||||||
if ((get_AT_unsigned (comp_unit_die, DW_AT_language)
|
if ((get_AT_unsigned (comp_unit_die, DW_AT_language)
|
||||||
== DW_LANG_C_plus_plus)
|
== DW_LANG_C_plus_plus)
|
||||||
&& TREE_CODE (TREE_TYPE (decl)) == BOOLEAN_TYPE
|
&& TREE_CODE (TREE_TYPE (decl)) == BOOLEAN_TYPE
|
||||||
@ -12336,7 +12346,7 @@ lookup_filename (file_name)
|
|||||||
const char *last
|
const char *last
|
||||||
= VARRAY_CHAR_PTR (file_table, file_table_last_lookup_index);
|
= VARRAY_CHAR_PTR (file_table, file_table_last_lookup_index);
|
||||||
if (strcmp (file_name, last) == 0)
|
if (strcmp (file_name, last) == 0)
|
||||||
return file_table_last_lookup_index;
|
return file_table_last_lookup_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Didn't match the previous lookup, search the table */
|
/* Didn't match the previous lookup, search the table */
|
||||||
@ -12352,25 +12362,43 @@ lookup_filename (file_name)
|
|||||||
file_table_last_lookup_index = n;
|
file_table_last_lookup_index = n;
|
||||||
save_file_name = (char *) ggc_strdup (file_name);
|
save_file_name = (char *) ggc_strdup (file_name);
|
||||||
VARRAY_PUSH_CHAR_PTR (file_table, save_file_name);
|
VARRAY_PUSH_CHAR_PTR (file_table, save_file_name);
|
||||||
|
VARRAY_PUSH_UINT (file_table_emitted, 0);
|
||||||
if (DWARF2_ASM_LINE_DEBUG_INFO)
|
|
||||||
{
|
|
||||||
fprintf (asm_out_file, "\t.file %lu ", (unsigned long) i);
|
|
||||||
output_quoted_string (asm_out_file, file_name);
|
|
||||||
fputc ('\n', asm_out_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
maybe_emit_file (fileno)
|
||||||
|
int fileno;
|
||||||
|
{
|
||||||
|
static int emitcount = 0;
|
||||||
|
if (DWARF2_ASM_LINE_DEBUG_INFO && fileno > 0)
|
||||||
|
{
|
||||||
|
if (!VARRAY_UINT (file_table_emitted, fileno))
|
||||||
|
{
|
||||||
|
VARRAY_UINT (file_table_emitted, fileno) = ++emitcount;
|
||||||
|
fprintf (asm_out_file, "\t.file %u ",
|
||||||
|
VARRAY_UINT (file_table_emitted, fileno));
|
||||||
|
output_quoted_string (asm_out_file,
|
||||||
|
VARRAY_CHAR_PTR (file_table, fileno));
|
||||||
|
fputc ('\n', asm_out_file);
|
||||||
|
}
|
||||||
|
return VARRAY_UINT (file_table_emitted, fileno);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return fileno;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_file_table ()
|
init_file_table ()
|
||||||
{
|
{
|
||||||
/* Allocate the initial hunk of the file_table. */
|
/* Allocate the initial hunk of the file_table. */
|
||||||
VARRAY_CHAR_PTR_INIT (file_table, 64, "file_table");
|
VARRAY_CHAR_PTR_INIT (file_table, 64, "file_table");
|
||||||
|
VARRAY_UINT_INIT (file_table_emitted, 64, "file_table_emitted");
|
||||||
|
|
||||||
/* Skip the first entry - file numbers begin at 1. */
|
/* Skip the first entry - file numbers begin at 1. */
|
||||||
VARRAY_PUSH_CHAR_PTR (file_table, NULL);
|
VARRAY_PUSH_CHAR_PTR (file_table, NULL);
|
||||||
|
VARRAY_PUSH_UINT (file_table_emitted, 0);
|
||||||
file_table_last_lookup_index = 0;
|
file_table_last_lookup_index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12396,6 +12424,8 @@ dwarf2out_source_line (line, filename)
|
|||||||
{
|
{
|
||||||
unsigned file_num = lookup_filename (filename);
|
unsigned file_num = lookup_filename (filename);
|
||||||
|
|
||||||
|
file_num = maybe_emit_file (file_num);
|
||||||
|
|
||||||
/* Emit the .loc directive understood by GNU as. */
|
/* Emit the .loc directive understood by GNU as. */
|
||||||
fprintf (asm_out_file, "\t.loc %d %d 0\n", file_num, line);
|
fprintf (asm_out_file, "\t.loc %d %d 0\n", file_num, line);
|
||||||
|
|
||||||
@ -12487,6 +12517,7 @@ dwarf2out_start_source_file (lineno, filename)
|
|||||||
dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
|
dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
|
||||||
dw2_asm_output_data_uleb128 (lineno, "Included from line number %d",
|
dw2_asm_output_data_uleb128 (lineno, "Included from line number %d",
|
||||||
lineno);
|
lineno);
|
||||||
|
maybe_emit_file (lookup_filename (filename));
|
||||||
dw2_asm_output_data_uleb128 (lookup_filename (filename),
|
dw2_asm_output_data_uleb128 (lookup_filename (filename),
|
||||||
"Filename we just started");
|
"Filename we just started");
|
||||||
}
|
}
|
||||||
@ -12646,6 +12677,215 @@ output_indirect_string (h, v)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Clear the marks for a die and its children.
|
||||||
|
Be cool if the mark isn't set. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
prune_unmark_dies (die)
|
||||||
|
dw_die_ref die;
|
||||||
|
{
|
||||||
|
dw_die_ref c;
|
||||||
|
die->die_mark = 0;
|
||||||
|
for (c = die->die_child; c; c = c->die_sib)
|
||||||
|
prune_unmark_dies (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Given DIE that we're marking as used, find any other dies
|
||||||
|
it references as attributes and mark them as used. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
prune_unused_types_walk_attribs (die)
|
||||||
|
dw_die_ref die;
|
||||||
|
{
|
||||||
|
dw_attr_ref a;
|
||||||
|
|
||||||
|
for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
|
||||||
|
{
|
||||||
|
if (a->dw_attr_val.val_class == dw_val_class_die_ref)
|
||||||
|
{
|
||||||
|
/* A reference to another DIE.
|
||||||
|
Make sure that it will get emitted. */
|
||||||
|
prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1);
|
||||||
|
}
|
||||||
|
else if (a->dw_attr == DW_AT_decl_file)
|
||||||
|
{
|
||||||
|
/* A reference to a file. Make sure the file name is emitted. */
|
||||||
|
a->dw_attr_val.v.val_unsigned =
|
||||||
|
maybe_emit_file (a->dw_attr_val.v.val_unsigned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Mark DIE as being used. If DOKIDS is true, then walk down
|
||||||
|
to DIE's children. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
prune_unused_types_mark (die, dokids)
|
||||||
|
dw_die_ref die;
|
||||||
|
int dokids;
|
||||||
|
{
|
||||||
|
dw_die_ref c;
|
||||||
|
|
||||||
|
if (die->die_mark == 0)
|
||||||
|
{
|
||||||
|
/* We haven't done this node yet. Mark it as used. */
|
||||||
|
die->die_mark = 1;
|
||||||
|
|
||||||
|
/* We also have to mark its parents as used.
|
||||||
|
(But we don't want to mark our parents' kids due to this.) */
|
||||||
|
if (die->die_parent)
|
||||||
|
prune_unused_types_mark (die->die_parent, 0);
|
||||||
|
|
||||||
|
/* Mark any referenced nodes. */
|
||||||
|
prune_unused_types_walk_attribs (die);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dokids && die->die_mark != 2)
|
||||||
|
{
|
||||||
|
/* We need to walk the children, but haven't done so yet.
|
||||||
|
Remember that we've walked the kids. */
|
||||||
|
die->die_mark = 2;
|
||||||
|
|
||||||
|
/* Walk them. */
|
||||||
|
for (c = die->die_child; c; c = c->die_sib)
|
||||||
|
{
|
||||||
|
/* If this is an array type, we need to make sure our
|
||||||
|
kids get marked, even if they're types. */
|
||||||
|
if (die->die_tag == DW_TAG_array_type)
|
||||||
|
prune_unused_types_mark (c, 1);
|
||||||
|
else
|
||||||
|
prune_unused_types_walk (c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Walk the tree DIE and mark types that we actually use. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
prune_unused_types_walk (die)
|
||||||
|
dw_die_ref die;
|
||||||
|
{
|
||||||
|
dw_die_ref c;
|
||||||
|
|
||||||
|
/* Don't do anything if this node is already marked. */
|
||||||
|
if (die->die_mark)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (die->die_tag) {
|
||||||
|
case DW_TAG_const_type:
|
||||||
|
case DW_TAG_packed_type:
|
||||||
|
case DW_TAG_pointer_type:
|
||||||
|
case DW_TAG_reference_type:
|
||||||
|
case DW_TAG_volatile_type:
|
||||||
|
case DW_TAG_typedef:
|
||||||
|
case DW_TAG_array_type:
|
||||||
|
case DW_TAG_structure_type:
|
||||||
|
case DW_TAG_union_type:
|
||||||
|
case DW_TAG_class_type:
|
||||||
|
case DW_TAG_friend:
|
||||||
|
case DW_TAG_variant_part:
|
||||||
|
case DW_TAG_enumeration_type:
|
||||||
|
case DW_TAG_subroutine_type:
|
||||||
|
case DW_TAG_string_type:
|
||||||
|
case DW_TAG_set_type:
|
||||||
|
case DW_TAG_subrange_type:
|
||||||
|
case DW_TAG_ptr_to_member_type:
|
||||||
|
case DW_TAG_file_type:
|
||||||
|
/* It's a type node --- don't mark it. */
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Mark everything else. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
die->die_mark = 1;
|
||||||
|
|
||||||
|
/* Now, mark any dies referenced from here. */
|
||||||
|
prune_unused_types_walk_attribs (die);
|
||||||
|
|
||||||
|
/* Mark children. */
|
||||||
|
for (c = die->die_child; c; c = c->die_sib)
|
||||||
|
prune_unused_types_walk (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Remove from the tree DIE any dies that aren't marked. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
prune_unused_types_prune (die)
|
||||||
|
dw_die_ref die;
|
||||||
|
{
|
||||||
|
dw_die_ref c, p, n;
|
||||||
|
if (!die->die_mark)
|
||||||
|
abort();
|
||||||
|
|
||||||
|
p = NULL;
|
||||||
|
for (c = die->die_child; c; c = n)
|
||||||
|
{
|
||||||
|
n = c->die_sib;
|
||||||
|
if (c->die_mark)
|
||||||
|
{
|
||||||
|
prune_unused_types_prune (c);
|
||||||
|
p = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (p)
|
||||||
|
p->die_sib = n;
|
||||||
|
else
|
||||||
|
die->die_child = n;
|
||||||
|
free_die (c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Remove dies representing declarations that we never use. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
prune_unused_types ()
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
limbo_die_node *node;
|
||||||
|
|
||||||
|
/* Clear all the marks. */
|
||||||
|
prune_unmark_dies (comp_unit_die);
|
||||||
|
for (node = limbo_die_list; node; node = node->next)
|
||||||
|
prune_unmark_dies (node->die);
|
||||||
|
|
||||||
|
/* Set the mark on nodes that are actually used. */
|
||||||
|
prune_unused_types_walk (comp_unit_die);
|
||||||
|
for (node = limbo_die_list; node; node = node->next)
|
||||||
|
prune_unused_types_walk (node->die);
|
||||||
|
|
||||||
|
/* Also set the mark on nodes referenced from the
|
||||||
|
pubname_table or arange_table. */
|
||||||
|
for (i=0; i < pubname_table_in_use; i++)
|
||||||
|
{
|
||||||
|
prune_unused_types_mark (pubname_table[i].die, 1);
|
||||||
|
}
|
||||||
|
for (i=0; i < arange_table_in_use; i++)
|
||||||
|
{
|
||||||
|
prune_unused_types_mark (arange_table[i], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get rid of nodes that aren't marked. */
|
||||||
|
prune_unused_types_prune (comp_unit_die);
|
||||||
|
for (node = limbo_die_list; node; node = node->next)
|
||||||
|
prune_unused_types_prune (node->die);
|
||||||
|
|
||||||
|
/* Leave the marks clear. */
|
||||||
|
prune_unmark_dies (comp_unit_die);
|
||||||
|
for (node = limbo_die_list; node; node = node->next)
|
||||||
|
prune_unmark_dies (node->die);
|
||||||
|
}
|
||||||
|
|
||||||
/* Output stuff that dwarf requires at the end of every file,
|
/* Output stuff that dwarf requires at the end of every file,
|
||||||
and generate the DWARF-2 debugging info. */
|
and generate the DWARF-2 debugging info. */
|
||||||
|
|
||||||
@ -12740,6 +12980,9 @@ dwarf2out_finish (input_filename)
|
|||||||
if (flag_eliminate_dwarf2_dups)
|
if (flag_eliminate_dwarf2_dups)
|
||||||
break_out_includes (comp_unit_die);
|
break_out_includes (comp_unit_die);
|
||||||
|
|
||||||
|
if (flag_eliminate_unused_debug_types)
|
||||||
|
prune_unused_types ();
|
||||||
|
|
||||||
/* Traverse the DIE's and add add sibling attributes to those DIE's
|
/* Traverse the DIE's and add add sibling attributes to those DIE's
|
||||||
that have children. */
|
that have children. */
|
||||||
add_sibling_attributes (comp_unit_die);
|
add_sibling_attributes (comp_unit_die);
|
||||||
|
@ -641,6 +641,10 @@ extern int flag_gcse_sm;
|
|||||||
|
|
||||||
extern int flag_eliminate_dwarf2_dups;
|
extern int flag_eliminate_dwarf2_dups;
|
||||||
|
|
||||||
|
/* Nonzero means we should do unused type elimination. */
|
||||||
|
|
||||||
|
extern int flag_eliminate_unused_debug_types;
|
||||||
|
|
||||||
/* Nonzero means to collect statistics which might be expensive
|
/* Nonzero means to collect statistics which might be expensive
|
||||||
and to print them when we are done. */
|
and to print them when we are done. */
|
||||||
extern int flag_detailed_statistics;
|
extern int flag_detailed_statistics;
|
||||||
|
@ -378,6 +378,10 @@ tree current_function_func_begin_label;
|
|||||||
|
|
||||||
int flag_eliminate_dwarf2_dups = 0;
|
int flag_eliminate_dwarf2_dups = 0;
|
||||||
|
|
||||||
|
/* Nonzero if doing unused type elimination. */
|
||||||
|
|
||||||
|
int flag_eliminate_unused_debug_types = 0;
|
||||||
|
|
||||||
/* Nonzero if generating code to do profiling. */
|
/* Nonzero if generating code to do profiling. */
|
||||||
|
|
||||||
int profile_flag = 0;
|
int profile_flag = 0;
|
||||||
@ -999,6 +1003,8 @@ static const lang_independent_options f_options[] =
|
|||||||
{
|
{
|
||||||
{"eliminate-dwarf2-dups", &flag_eliminate_dwarf2_dups, 1,
|
{"eliminate-dwarf2-dups", &flag_eliminate_dwarf2_dups, 1,
|
||||||
N_("Perform DWARF2 duplicate elimination") },
|
N_("Perform DWARF2 duplicate elimination") },
|
||||||
|
{"eliminate-unused-debug-types", &flag_eliminate_unused_debug_types, 1,
|
||||||
|
N_("Perform unused type elimination in debug info") },
|
||||||
{"float-store", &flag_float_store, 1,
|
{"float-store", &flag_float_store, 1,
|
||||||
N_("Do not store floats in registers") },
|
N_("Do not store floats in registers") },
|
||||||
{"defer-pop", &flag_defer_pop, 1,
|
{"defer-pop", &flag_defer_pop, 1,
|
||||||
|
Loading…
Reference in New Issue
Block a user