dwarf2out.c (dw_val_class_offset): New.
* dwarf2out.c (dw_val_class_offset): New. (struct dw_ranges_struct, dw_ranges_ref): New. (ranges_table, ranges_table_allocated): New. (ranges_table_in_use, RANGES_TABLE_INCREMENT): New. (add_AT_offset, add_ranges, output_ranges): New. (print_die, output_die): Handle dw_val_class_offset. (attr_checksum, size_of_die, value_format): Likewise. (gen_lexical_block_die): Handle non-contiguous blocks. (gen_block_die): Likewise. (dwarf2out_finish): Add a DW_AT_entry_pc to the compilation unit if needed. Dump the ranges table. * final.c (final_start_function): Remove unnecessary notes and rebuild the block tree before numbering the blocks. * function.c (reorder_blocks_0): Walk the existing block tree to unmark all blocks. (reorder_blocks_1): Create block fragments when duplicate block notes are seen. (reorder_fix_fragments): New. (reorder_blocks): Call it. * tree.h (BLOCK_FRAGMENT_ORIGIN, BLOCK_FRAGMENT_CHAIN): New. From-SVN: r44444
This commit is contained in:
parent
594280a396
commit
a20612aa8b
@ -1,3 +1,26 @@
|
||||
2001-07-28 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* dwarf2out.c (dw_val_class_offset): New.
|
||||
(struct dw_ranges_struct, dw_ranges_ref): New.
|
||||
(ranges_table, ranges_table_allocated): New.
|
||||
(ranges_table_in_use, RANGES_TABLE_INCREMENT): New.
|
||||
(add_AT_offset, add_ranges, output_ranges): New.
|
||||
(print_die, output_die): Handle dw_val_class_offset.
|
||||
(attr_checksum, size_of_die, value_format): Likewise.
|
||||
(gen_lexical_block_die): Handle non-contiguous blocks.
|
||||
(gen_block_die): Likewise.
|
||||
(dwarf2out_finish): Add a DW_AT_entry_pc to the compilation unit
|
||||
if needed. Dump the ranges table.
|
||||
* final.c (final_start_function): Remove unnecessary notes and
|
||||
rebuild the block tree before numbering the blocks.
|
||||
* function.c (reorder_blocks_0): Walk the existing block tree
|
||||
to unmark all blocks.
|
||||
(reorder_blocks_1): Create block fragments when duplicate block
|
||||
notes are seen.
|
||||
(reorder_fix_fragments): New.
|
||||
(reorder_blocks): Call it.
|
||||
* tree.h (BLOCK_FRAGMENT_ORIGIN, BLOCK_FRAGMENT_CHAIN): New.
|
||||
|
||||
2001-07-28 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* emit-rtl.c (adjust_address): Make a copy of the memory address.
|
||||
|
255
gcc/dwarf2out.c
255
gcc/dwarf2out.c
@ -2138,6 +2138,7 @@ typedef struct dw_loc_list_struct *dw_loc_list_ref;
|
||||
typedef enum
|
||||
{
|
||||
dw_val_class_addr,
|
||||
dw_val_class_offset,
|
||||
dw_val_class_loc,
|
||||
dw_val_class_loc_list,
|
||||
dw_val_class_const,
|
||||
@ -2181,6 +2182,7 @@ typedef struct dw_val_struct
|
||||
union
|
||||
{
|
||||
rtx val_addr;
|
||||
long unsigned val_offset;
|
||||
dw_loc_list_ref val_loc_list;
|
||||
dw_loc_descr_ref val_loc;
|
||||
long int val_int;
|
||||
@ -3075,7 +3077,7 @@ typedef struct dw_attr_struct *dw_attr_ref;
|
||||
typedef struct dw_line_info_struct *dw_line_info_ref;
|
||||
typedef struct dw_separate_line_info_struct *dw_separate_line_info_ref;
|
||||
typedef struct pubname_struct *pubname_ref;
|
||||
typedef dw_die_ref *arange_ref;
|
||||
typedef struct dw_ranges_struct *dw_ranges_ref;
|
||||
|
||||
/* Each entry in the line_info_table maintains the file and
|
||||
line number associated with the label generated for that
|
||||
@ -3136,6 +3138,11 @@ typedef struct pubname_struct
|
||||
}
|
||||
pubname_entry;
|
||||
|
||||
struct dw_ranges_struct
|
||||
{
|
||||
int block_num;
|
||||
};
|
||||
|
||||
/* The limbo die list structure. */
|
||||
typedef struct limbo_die_struct
|
||||
{
|
||||
@ -3346,9 +3353,8 @@ static unsigned pubname_table_in_use;
|
||||
pubname_table. */
|
||||
#define PUBNAME_TABLE_INCREMENT 64
|
||||
|
||||
/* A pointer to the base of a table that contains a list of publicly
|
||||
accessible names. */
|
||||
static arange_ref arange_table;
|
||||
/* Array of dies for which we should generate .debug_arange info. */
|
||||
static dw_die_ref *arange_table;
|
||||
|
||||
/* Number of elements currently allocated for arange_table. */
|
||||
static unsigned arange_table_allocated;
|
||||
@ -3360,6 +3366,19 @@ static unsigned arange_table_in_use;
|
||||
arange_table. */
|
||||
#define ARANGE_TABLE_INCREMENT 64
|
||||
|
||||
/* Array of dies for which we should generate .debug_ranges info. */
|
||||
static dw_ranges_ref ranges_table;
|
||||
|
||||
/* Number of elements currently allocated for ranges_table. */
|
||||
static unsigned ranges_table_allocated;
|
||||
|
||||
/* Number of elements in ranges_table currently in use. */
|
||||
static unsigned ranges_table_in_use;
|
||||
|
||||
/* Size (in elements) of increments by which we may expand the
|
||||
ranges_table. */
|
||||
#define RANGES_TABLE_INCREMENT 64
|
||||
|
||||
/* Whether we have location lists that need outputting */
|
||||
static unsigned have_location_lists;
|
||||
|
||||
@ -3445,6 +3464,9 @@ static void add_AT_lbl_id PARAMS ((dw_die_ref,
|
||||
static void add_AT_lbl_offset PARAMS ((dw_die_ref,
|
||||
enum dwarf_attribute,
|
||||
const char *));
|
||||
static void add_AT_offset PARAMS ((dw_die_ref,
|
||||
enum dwarf_attribute,
|
||||
unsigned long));
|
||||
static dw_attr_ref get_AT PARAMS ((dw_die_ref,
|
||||
enum dwarf_attribute));
|
||||
static const char *get_AT_low_pc PARAMS ((dw_die_ref));
|
||||
@ -3508,6 +3530,8 @@ static void add_pubname PARAMS ((tree, dw_die_ref));
|
||||
static void output_pubnames PARAMS ((void));
|
||||
static void add_arange PARAMS ((tree, dw_die_ref));
|
||||
static void output_aranges PARAMS ((void));
|
||||
static unsigned int add_ranges PARAMS ((tree));
|
||||
static void output_ranges PARAMS ((void));
|
||||
static void output_line_info PARAMS ((void));
|
||||
static void output_file_names PARAMS ((void));
|
||||
static dw_die_ref base_type_die PARAMS ((tree));
|
||||
@ -3633,6 +3657,9 @@ static char *gen_internal_sym PARAMS ((const char *));
|
||||
#ifndef DEBUG_STR_SECTION
|
||||
#define DEBUG_STR_SECTION ".debug_str"
|
||||
#endif
|
||||
#ifndef DEBUG_RANGES_SECTION
|
||||
#define DEBUG_RANGES_SECTION ".debug_ranges"
|
||||
#endif
|
||||
|
||||
/* Standard ELF section names for compiled code and data. */
|
||||
#ifndef TEXT_SECTION
|
||||
@ -3666,6 +3693,7 @@ static char *gen_internal_sym PARAMS ((const char *));
|
||||
#ifndef DEBUG_MACINFO_SECTION_LABEL
|
||||
#define DEBUG_MACINFO_SECTION_LABEL "Ldebug_macinfo"
|
||||
#endif
|
||||
|
||||
/* Definitions of defaults for formats and names of various special
|
||||
(artificial) labels which may be generated within this file (when the -g
|
||||
options is used and DWARF_DEBUGGING_INFO is in effect.
|
||||
@ -4030,6 +4058,31 @@ dwarf_attr_name (attr)
|
||||
case DW_AT_vtable_elem_location:
|
||||
return "DW_AT_vtable_elem_location";
|
||||
|
||||
case DW_AT_allocated:
|
||||
return "DW_AT_allocated";
|
||||
case DW_AT_associated:
|
||||
return "DW_AT_associated";
|
||||
case DW_AT_data_location:
|
||||
return "DW_AT_data_location";
|
||||
case DW_AT_stride:
|
||||
return "DW_AT_stride";
|
||||
case DW_AT_entry_pc:
|
||||
return "DW_AT_entry_pc";
|
||||
case DW_AT_use_UTF8:
|
||||
return "DW_AT_use_UTF8";
|
||||
case DW_AT_extension:
|
||||
return "DW_AT_extension";
|
||||
case DW_AT_ranges:
|
||||
return "DW_AT_ranges";
|
||||
case DW_AT_trampoline:
|
||||
return "DW_AT_trampoline";
|
||||
case DW_AT_call_column:
|
||||
return "DW_AT_call_column";
|
||||
case DW_AT_call_file:
|
||||
return "DW_AT_call_file";
|
||||
case DW_AT_call_line:
|
||||
return "DW_AT_call_line";
|
||||
|
||||
case DW_AT_MIPS_fde:
|
||||
return "DW_AT_MIPS_fde";
|
||||
case DW_AT_MIPS_loop_begin:
|
||||
@ -4602,6 +4655,23 @@ add_AT_lbl_offset (die, attr_kind, label)
|
||||
add_dwarf_attr (die, attr);
|
||||
}
|
||||
|
||||
/* Add an offset attribute value to a DIE. */
|
||||
|
||||
static void
|
||||
add_AT_offset (die, attr_kind, offset)
|
||||
register dw_die_ref die;
|
||||
register enum dwarf_attribute attr_kind;
|
||||
register unsigned long offset;
|
||||
{
|
||||
register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
|
||||
|
||||
attr->dw_attr_next = NULL;
|
||||
attr->dw_attr = attr_kind;
|
||||
attr->dw_attr_val.val_class = dw_val_class_offset;
|
||||
attr->dw_attr_val.v.val_offset = offset;
|
||||
add_dwarf_attr (die, attr);
|
||||
}
|
||||
|
||||
static inline const char *AT_lbl PARAMS ((dw_attr_ref));
|
||||
static inline const char *
|
||||
AT_lbl (a)
|
||||
@ -5014,11 +5084,15 @@ print_die (die, outfile)
|
||||
case dw_val_class_addr:
|
||||
fprintf (outfile, "address");
|
||||
break;
|
||||
case dw_val_class_offset:
|
||||
fprintf (outfile, "offset");
|
||||
break;
|
||||
case dw_val_class_loc:
|
||||
fprintf (outfile, "location descriptor");
|
||||
break;
|
||||
case dw_val_class_loc_list:
|
||||
fprintf (outfile, "location list -> label:%s", AT_loc_list (a)->ll_symbol);
|
||||
fprintf (outfile, "location list -> label:%s",
|
||||
AT_loc_list (a)->ll_symbol);
|
||||
break;
|
||||
case dw_val_class_const:
|
||||
fprintf (outfile, "%ld", AT_int (a));
|
||||
@ -5249,6 +5323,7 @@ attr_checksum (at, ctx)
|
||||
case dw_val_class_str:
|
||||
PROCESS_STRING (AT_string (at));
|
||||
break;
|
||||
|
||||
case dw_val_class_addr:
|
||||
r = AT_addr (at);
|
||||
switch (GET_CODE (r))
|
||||
@ -5262,6 +5337,10 @@ attr_checksum (at, ctx)
|
||||
}
|
||||
break;
|
||||
|
||||
case dw_val_class_offset:
|
||||
PROCESS (at->dw_attr_val.v.val_offset);
|
||||
break;
|
||||
|
||||
case dw_val_class_loc:
|
||||
for (loc = AT_loc (at); loc; loc = loc->dw_loc_next)
|
||||
loc_checksum (loc, ctx);
|
||||
@ -5275,6 +5354,7 @@ attr_checksum (at, ctx)
|
||||
case dw_val_class_fde_ref:
|
||||
case dw_val_class_lbl_id:
|
||||
case dw_val_class_lbl_offset:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
@ -5680,6 +5760,9 @@ size_of_die (die)
|
||||
case dw_val_class_addr:
|
||||
size += DWARF2_ADDR_SIZE;
|
||||
break;
|
||||
case dw_val_class_offset:
|
||||
size += DWARF_OFFSET_SIZE;
|
||||
break;
|
||||
case dw_val_class_loc:
|
||||
{
|
||||
register unsigned long lsize = size_of_locs (AT_loc (a));
|
||||
@ -5827,6 +5910,12 @@ value_format (a)
|
||||
{
|
||||
case dw_val_class_addr:
|
||||
return DW_FORM_addr;
|
||||
case dw_val_class_offset:
|
||||
if (DWARF_OFFSET_SIZE == 4)
|
||||
return DW_FORM_data4;
|
||||
if (DWARF_OFFSET_SIZE == 8)
|
||||
return DW_FORM_data8;
|
||||
abort ();
|
||||
case dw_val_class_loc_list:
|
||||
/* FIXME: Could be DW_FORM_data8, with a > 32 bit size
|
||||
.debug_loc section */
|
||||
@ -5876,6 +5965,7 @@ value_format (a)
|
||||
return DW_FORM_data;
|
||||
case dw_val_class_str:
|
||||
return DW_FORM_string;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
@ -5990,8 +6080,6 @@ add_loc_descr_to_loc_list (list_head, descr, begin, end, section)
|
||||
*d = new_loc_list (descr, begin, end, section, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Output the location list given to us */
|
||||
static void
|
||||
output_loc_list (list_head)
|
||||
@ -5999,6 +6087,10 @@ output_loc_list (list_head)
|
||||
{
|
||||
register dw_loc_list_ref curr=list_head;
|
||||
ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
|
||||
|
||||
/* ??? This shouldn't be needed now that we've forced the
|
||||
compilation unit base address to zero when there is code
|
||||
in more than one section. */
|
||||
if (strcmp (curr->section, ".text") == 0)
|
||||
{
|
||||
/* dw2_asm_output_data will mask off any extra bits in the ~0. */
|
||||
@ -6060,6 +6152,11 @@ output_die (die)
|
||||
dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
|
||||
break;
|
||||
|
||||
case dw_val_class_offset:
|
||||
dw2_asm_output_data (DWARF_OFFSET_SIZE, a->dw_attr_val.v.val_offset,
|
||||
"%s", name);
|
||||
break;
|
||||
|
||||
case dw_val_class_loc:
|
||||
size = size_of_locs (AT_loc (a));
|
||||
|
||||
@ -6121,14 +6218,17 @@ output_die (die)
|
||||
case dw_val_class_flag:
|
||||
dw2_asm_output_data (1, AT_flag (a), "%s", name);
|
||||
break;
|
||||
|
||||
case dw_val_class_loc_list:
|
||||
{
|
||||
char *sym = AT_loc_list (a)->ll_symbol;
|
||||
if (sym == 0)
|
||||
abort();
|
||||
dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label, name);
|
||||
dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym,
|
||||
loc_section_label, "%s", name);
|
||||
}
|
||||
break;
|
||||
|
||||
case dw_val_class_die_ref:
|
||||
if (AT_ref_external (a))
|
||||
{
|
||||
@ -6330,9 +6430,8 @@ add_arange (decl, die)
|
||||
if (arange_table_in_use == arange_table_allocated)
|
||||
{
|
||||
arange_table_allocated += ARANGE_TABLE_INCREMENT;
|
||||
arange_table
|
||||
= (arange_ref) xrealloc (arange_table,
|
||||
arange_table_allocated * sizeof (dw_die_ref));
|
||||
arange_table = (dw_die_ref *)
|
||||
xrealloc (arange_table, arange_table_allocated * sizeof (dw_die_ref));
|
||||
}
|
||||
|
||||
arange_table[arange_table_in_use++] = die;
|
||||
@ -6418,6 +6517,80 @@ output_aranges ()
|
||||
dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
|
||||
}
|
||||
|
||||
/* Add a new entry to .debug_ranges. Return the offset at which it
|
||||
was placed. */
|
||||
|
||||
static unsigned int
|
||||
add_ranges (block)
|
||||
tree block;
|
||||
{
|
||||
unsigned int in_use = ranges_table_in_use;
|
||||
|
||||
if (in_use == ranges_table_allocated)
|
||||
{
|
||||
ranges_table_allocated += RANGES_TABLE_INCREMENT;
|
||||
ranges_table = (dw_ranges_ref)
|
||||
xrealloc (ranges_table, (ranges_table_allocated
|
||||
* sizeof (struct dw_ranges_struct)));
|
||||
}
|
||||
|
||||
ranges_table[in_use].block_num = (block ? BLOCK_NUMBER (block) : 0);
|
||||
ranges_table_in_use = in_use + 1;
|
||||
|
||||
return in_use * 2 * DWARF2_ADDR_SIZE;
|
||||
}
|
||||
|
||||
static void
|
||||
output_ranges ()
|
||||
{
|
||||
register unsigned i;
|
||||
const char *start_fmt = "Offset 0x%x";
|
||||
const char *fmt = start_fmt;
|
||||
|
||||
for (i = 0; i < ranges_table_in_use; ++i)
|
||||
{
|
||||
int block_num = ranges_table[i].block_num;
|
||||
|
||||
if (block_num)
|
||||
{
|
||||
char blabel[MAX_ARTIFICIAL_LABEL_BYTES];
|
||||
char elabel[MAX_ARTIFICIAL_LABEL_BYTES];
|
||||
|
||||
ASM_GENERATE_INTERNAL_LABEL (blabel, BLOCK_BEGIN_LABEL, block_num);
|
||||
ASM_GENERATE_INTERNAL_LABEL (elabel, BLOCK_END_LABEL, block_num);
|
||||
|
||||
/* If all code is in the text section, then the compilation
|
||||
unit base address defaults to DW_AT_low_pc, which is the
|
||||
base of the text section. */
|
||||
if (separate_line_info_table_in_use == 0)
|
||||
{
|
||||
dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
|
||||
text_section_label,
|
||||
fmt, i * 2 * DWARF2_ADDR_SIZE);
|
||||
dw2_asm_output_delta (DWARF2_ADDR_SIZE, elabel,
|
||||
text_section_label, NULL);
|
||||
}
|
||||
/* Otherwise, we add a DW_AT_entry_pc attribute to force the
|
||||
compilation unit base address to zero, which allows us to
|
||||
use absolute addresses, and not worry about whether the
|
||||
target supports cross-section arithmetic. */
|
||||
else
|
||||
{
|
||||
dw2_asm_output_addr (DWARF2_ADDR_SIZE, blabel,
|
||||
fmt, i * 2 * DWARF2_ADDR_SIZE);
|
||||
dw2_asm_output_addr (DWARF2_ADDR_SIZE, elabel, NULL);
|
||||
}
|
||||
|
||||
fmt = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
|
||||
dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
|
||||
fmt = start_fmt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Data structure containing information about input files. */
|
||||
struct file_info
|
||||
@ -9973,6 +10146,7 @@ gen_variable_die (decl, context_die)
|
||||
/* ??? Loop unrolling/reorder_blocks should perhaps be rewritten to
|
||||
copy decls and set the DECL_ABSTRACT flag on them instead of
|
||||
sharing them. */
|
||||
/* ??? Duplicated blocks have been rewritten to use .debug_ranges. */
|
||||
else if (old_die && TREE_STATIC (decl)
|
||||
&& get_AT_flag (old_die, DW_AT_declaration) == 1)
|
||||
{
|
||||
@ -10084,12 +10258,30 @@ gen_lexical_block_die (stmt, context_die, depth)
|
||||
|
||||
if (! BLOCK_ABSTRACT (stmt))
|
||||
{
|
||||
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
|
||||
BLOCK_NUMBER (stmt));
|
||||
add_AT_lbl_id (stmt_die, DW_AT_low_pc, label);
|
||||
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL,
|
||||
BLOCK_NUMBER (stmt));
|
||||
add_AT_lbl_id (stmt_die, DW_AT_high_pc, label);
|
||||
if (BLOCK_FRAGMENT_CHAIN (stmt))
|
||||
{
|
||||
tree chain;
|
||||
|
||||
add_AT_offset (stmt_die, DW_AT_ranges, add_ranges (stmt));
|
||||
|
||||
chain = BLOCK_FRAGMENT_CHAIN (stmt);
|
||||
do
|
||||
{
|
||||
add_ranges (chain);
|
||||
chain = BLOCK_FRAGMENT_CHAIN (chain);
|
||||
}
|
||||
while (chain);
|
||||
add_ranges (NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
|
||||
BLOCK_NUMBER (stmt));
|
||||
add_AT_lbl_id (stmt_die, DW_AT_low_pc, label);
|
||||
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL,
|
||||
BLOCK_NUMBER (stmt));
|
||||
add_AT_lbl_id (stmt_die, DW_AT_high_pc, label);
|
||||
}
|
||||
}
|
||||
|
||||
decls_for_scope (stmt, stmt_die, depth);
|
||||
@ -10721,11 +10913,22 @@ gen_block_die (stmt, context_die, depth)
|
||||
register enum tree_code origin_code;
|
||||
|
||||
/* Ignore blocks never really used to make RTL. */
|
||||
|
||||
if (stmt == NULL_TREE || !TREE_USED (stmt)
|
||||
|| (!TREE_ASM_WRITTEN (stmt) && !BLOCK_ABSTRACT (stmt)))
|
||||
return;
|
||||
|
||||
/* If the block is one fragment of a non-contiguous block, do not
|
||||
process the variables, since they will have been done by the
|
||||
origin block. Do process subblocks. */
|
||||
if (BLOCK_FRAGMENT_ORIGIN (stmt))
|
||||
{
|
||||
tree sub;
|
||||
|
||||
for (sub= BLOCK_SUBBLOCKS (stmt); sub; sub = BLOCK_CHAIN (sub))
|
||||
gen_block_die (sub, context_die, depth + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Determine the "ultimate origin" of this block. This block may be an
|
||||
inlined instance of an inlined instance of inline function, so we have
|
||||
to trace all of the way back through the origin chain to find out what
|
||||
@ -11607,6 +11810,11 @@ dwarf2out_finish (input_filename)
|
||||
add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, text_section_label);
|
||||
add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label);
|
||||
}
|
||||
/* And if it wasn't, we need to give .debug_loc and .debug_ranges
|
||||
an appropriate "base address". Use zero so that these addresses
|
||||
become absolute. */
|
||||
else if (have_location_lists || ranges_table_in_use)
|
||||
add_AT_addr (comp_unit_die, DW_AT_entry_pc, const0_rtx);
|
||||
|
||||
if (debug_info_level >= DINFO_LEVEL_NORMAL)
|
||||
add_AT_lbl_offset (comp_unit_die, DW_AT_stmt_list,
|
||||
@ -11640,7 +11848,8 @@ dwarf2out_finish (input_filename)
|
||||
ASM_OUTPUT_SECTION (asm_out_file, DEBUG_ARANGES_SECTION);
|
||||
output_aranges ();
|
||||
}
|
||||
/* Output location list section if necessary */
|
||||
|
||||
/* Output location list section if necessary. */
|
||||
if (have_location_lists)
|
||||
{
|
||||
/* Output the location lists info. */
|
||||
@ -11649,12 +11858,18 @@ dwarf2out_finish (input_filename)
|
||||
have_location_lists = 0;
|
||||
}
|
||||
|
||||
/* Output ranges section if necessary. */
|
||||
if (ranges_table_in_use)
|
||||
{
|
||||
ASM_OUTPUT_SECTION (asm_out_file, DEBUG_RANGES_SECTION);
|
||||
output_ranges ();
|
||||
}
|
||||
|
||||
/* Have to end the primary source file. */
|
||||
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
|
||||
{
|
||||
ASM_OUTPUT_SECTION (asm_out_file, DEBUG_MACINFO_SECTION);
|
||||
dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
|
||||
}
|
||||
|
||||
}
|
||||
#endif /* DWARF2_DEBUGGING_INFO */
|
||||
|
@ -1597,8 +1597,9 @@ final_start_function (first, file, optimize)
|
||||
function. */
|
||||
if (write_symbols)
|
||||
{
|
||||
number_blocks (current_function_decl);
|
||||
remove_unnecessary_notes ();
|
||||
reorder_blocks ();
|
||||
number_blocks (current_function_decl);
|
||||
/* We never actually put out begin/end notes for the top-level
|
||||
block in the function. But, conceptually, that block is
|
||||
always needed. */
|
||||
|
127
gcc/function.c
127
gcc/function.c
@ -278,8 +278,9 @@ static void pad_below PARAMS ((struct args_size *, enum machine_mode,
|
||||
static rtx round_trampoline_addr PARAMS ((rtx));
|
||||
static rtx adjust_trampoline_addr PARAMS ((rtx));
|
||||
static tree *identify_blocks_1 PARAMS ((rtx, tree *, tree *, tree *));
|
||||
static void reorder_blocks_0 PARAMS ((rtx));
|
||||
static void reorder_blocks_0 PARAMS ((tree));
|
||||
static void reorder_blocks_1 PARAMS ((rtx, tree, varray_type *));
|
||||
static void reorder_fix_fragments PARAMS ((tree));
|
||||
static tree blocks_nreverse PARAMS ((tree));
|
||||
static int all_blocks PARAMS ((tree, tree *));
|
||||
static tree *get_block_vector PARAMS ((tree, int *));
|
||||
@ -5819,8 +5820,11 @@ identify_blocks_1 (insns, block_vector, end_block_vector, orig_block_stack)
|
||||
return block_vector;
|
||||
}
|
||||
|
||||
/* Identify BLOCKs referenced by more than one
|
||||
NOTE_INSN_BLOCK_{BEG,END}, and create duplicate blocks. */
|
||||
/* Identify BLOCKs referenced by more than one NOTE_INSN_BLOCK_{BEG,END},
|
||||
and create duplicate blocks. */
|
||||
/* ??? Need an option to either create block fragments or to create
|
||||
abstract origin duplicates of a source block. It really depends
|
||||
on what optimization has been performed. */
|
||||
|
||||
void
|
||||
reorder_blocks ()
|
||||
@ -5833,47 +5837,34 @@ reorder_blocks ()
|
||||
|
||||
VARRAY_TREE_INIT (block_stack, 10, "block_stack");
|
||||
|
||||
/* Reset the TREE_ASM_WRITTEN bit for all blocks. */
|
||||
reorder_blocks_0 (block);
|
||||
|
||||
/* Prune the old trees away, so that they don't get in the way. */
|
||||
BLOCK_SUBBLOCKS (block) = NULL_TREE;
|
||||
BLOCK_CHAIN (block) = NULL_TREE;
|
||||
|
||||
reorder_blocks_0 (get_insns ());
|
||||
/* Recreate the block tree from the note nesting. */
|
||||
reorder_blocks_1 (get_insns (), block, &block_stack);
|
||||
|
||||
BLOCK_SUBBLOCKS (block) = blocks_nreverse (BLOCK_SUBBLOCKS (block));
|
||||
|
||||
/* Remove deleted blocks from the block fragment chains. */
|
||||
reorder_fix_fragments (block);
|
||||
|
||||
VARRAY_FREE (block_stack);
|
||||
}
|
||||
|
||||
/* Helper function for reorder_blocks. Process the insn chain beginning
|
||||
at INSNS. Recurse for CALL_PLACEHOLDER insns. */
|
||||
/* Helper function for reorder_blocks. Reset TREE_ASM_WRITTEN. */
|
||||
|
||||
static void
|
||||
reorder_blocks_0 (insns)
|
||||
rtx insns;
|
||||
reorder_blocks_0 (block)
|
||||
tree block;
|
||||
{
|
||||
rtx insn;
|
||||
|
||||
for (insn = insns; insn; insn = NEXT_INSN (insn))
|
||||
while (block)
|
||||
{
|
||||
if (GET_CODE (insn) == NOTE)
|
||||
{
|
||||
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
|
||||
{
|
||||
tree block = NOTE_BLOCK (insn);
|
||||
TREE_ASM_WRITTEN (block) = 0;
|
||||
}
|
||||
}
|
||||
else if (GET_CODE (insn) == CALL_INSN
|
||||
&& GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
|
||||
{
|
||||
rtx cp = PATTERN (insn);
|
||||
reorder_blocks_0 (XEXP (cp, 0));
|
||||
if (XEXP (cp, 1))
|
||||
reorder_blocks_0 (XEXP (cp, 1));
|
||||
if (XEXP (cp, 2))
|
||||
reorder_blocks_0 (XEXP (cp, 2));
|
||||
}
|
||||
TREE_ASM_WRITTEN (block) = 0;
|
||||
reorder_blocks_0 (BLOCK_SUBBLOCKS (block));
|
||||
block = BLOCK_CHAIN (block);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5892,12 +5883,26 @@ reorder_blocks_1 (insns, current_block, p_block_stack)
|
||||
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
|
||||
{
|
||||
tree block = NOTE_BLOCK (insn);
|
||||
/* If we have seen this block before, copy it. */
|
||||
|
||||
/* If we have seen this block before, that means it now
|
||||
spans multiple address regions. Create a new fragment. */
|
||||
if (TREE_ASM_WRITTEN (block))
|
||||
{
|
||||
block = copy_node (block);
|
||||
NOTE_BLOCK (insn) = block;
|
||||
tree new_block = copy_node (block);
|
||||
tree origin;
|
||||
|
||||
origin = (BLOCK_FRAGMENT_ORIGIN (block)
|
||||
? BLOCK_FRAGMENT_ORIGIN (block)
|
||||
: block);
|
||||
BLOCK_FRAGMENT_ORIGIN (new_block) = origin;
|
||||
BLOCK_FRAGMENT_CHAIN (new_block)
|
||||
= BLOCK_FRAGMENT_CHAIN (origin);
|
||||
BLOCK_FRAGMENT_CHAIN (origin) = new_block;
|
||||
|
||||
NOTE_BLOCK (insn) = new_block;
|
||||
block = new_block;
|
||||
}
|
||||
|
||||
BLOCK_SUBBLOCKS (block) = 0;
|
||||
TREE_ASM_WRITTEN (block) = 1;
|
||||
BLOCK_SUPERCONTEXT (block) = current_block;
|
||||
@ -5928,6 +5933,62 @@ reorder_blocks_1 (insns, current_block, p_block_stack)
|
||||
}
|
||||
}
|
||||
|
||||
/* Rationalize BLOCK_FRAGMENT_ORIGIN. If an origin block no longer
|
||||
appears in the block tree, select one of the fragments to become
|
||||
the new origin block. */
|
||||
|
||||
static void
|
||||
reorder_fix_fragments (block)
|
||||
tree block;
|
||||
{
|
||||
while (block)
|
||||
{
|
||||
tree dup_origin = BLOCK_FRAGMENT_ORIGIN (block);
|
||||
tree new_origin = NULL_TREE;
|
||||
|
||||
if (dup_origin)
|
||||
{
|
||||
if (! TREE_ASM_WRITTEN (dup_origin))
|
||||
{
|
||||
new_origin = BLOCK_FRAGMENT_CHAIN (dup_origin);
|
||||
|
||||
/* Find the first of the remaining fragments. There must
|
||||
be at least one -- the current block. */
|
||||
while (! TREE_ASM_WRITTEN (new_origin))
|
||||
new_origin = BLOCK_FRAGMENT_CHAIN (new_origin);
|
||||
BLOCK_FRAGMENT_ORIGIN (new_origin) = NULL_TREE;
|
||||
}
|
||||
}
|
||||
else if (! dup_origin)
|
||||
new_origin = block;
|
||||
|
||||
/* Re-root the rest of the fragments to the new origin. In the
|
||||
case that DUP_ORIGIN was null, that means BLOCK was the origin
|
||||
of a chain of fragments and we want to remove those fragments
|
||||
that didn't make it to the output. */
|
||||
if (new_origin)
|
||||
{
|
||||
tree *pp = &BLOCK_FRAGMENT_CHAIN (new_origin);
|
||||
tree chain = *pp;
|
||||
|
||||
while (chain)
|
||||
{
|
||||
if (TREE_ASM_WRITTEN (chain))
|
||||
{
|
||||
BLOCK_FRAGMENT_ORIGIN (chain) = new_origin;
|
||||
*pp = chain;
|
||||
pp = &BLOCK_FRAGMENT_CHAIN (chain);
|
||||
}
|
||||
chain = BLOCK_FRAGMENT_CHAIN (chain);
|
||||
}
|
||||
*pp = NULL_TREE;
|
||||
}
|
||||
|
||||
reorder_fix_fragments (BLOCK_SUBBLOCKS (block));
|
||||
block = BLOCK_CHAIN (block);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reverse the order of elements in the chain T of blocks,
|
||||
and return the new head of the chain (old last element). */
|
||||
|
||||
|
29
gcc/tree.h
29
gcc/tree.h
@ -848,6 +848,33 @@ struct tree_exp
|
||||
the debugging output format in use. */
|
||||
#define BLOCK_NUMBER(NODE) (BLOCK_CHECK (NODE)->block.block_num)
|
||||
|
||||
/* If block reordering splits a lexical block into discontiguous
|
||||
address ranges, we'll make a copy of the original block.
|
||||
|
||||
Note that this is logically distinct from BLOCK_ABSTRACT_ORIGIN.
|
||||
In that case, we have one source block that has been replicated
|
||||
(through inlining or unrolling) into many logical blocks, and that
|
||||
these logical blocks have different physical variables in them.
|
||||
|
||||
In this case, we have one logical block split into several
|
||||
non-contiguous address ranges. Most debug formats can't actually
|
||||
represent this idea directly, so we fake it by creating multiple
|
||||
logical blocks with the same variables in them. However, for those
|
||||
that do support non-contiguous regions, these allow the original
|
||||
logical block to be reconstructed, along with the set of address
|
||||
ranges.
|
||||
|
||||
One of the logical block fragments is arbitrarily chosen to be
|
||||
the ORIGIN. The other fragments will point to the origin via
|
||||
BLOCK_FRAGMENT_ORIGIN; the origin itself will have this pointer
|
||||
be null. The list of fragments will be chained through
|
||||
BLOCK_FRAGMENT_CHAIN from the origin. */
|
||||
|
||||
#define BLOCK_FRAGMENT_ORIGIN(NODE) \
|
||||
(BLOCK_CHECK (NODE)->block.fragment_origin)
|
||||
#define BLOCK_FRAGMENT_CHAIN(NODE) \
|
||||
(BLOCK_CHECK (NODE)->block.fragment_chain)
|
||||
|
||||
struct tree_block
|
||||
{
|
||||
struct tree_common common;
|
||||
@ -860,6 +887,8 @@ struct tree_block
|
||||
union tree_node *subblocks;
|
||||
union tree_node *supercontext;
|
||||
union tree_node *abstract_origin;
|
||||
union tree_node *fragment_origin;
|
||||
union tree_node *fragment_chain;
|
||||
};
|
||||
|
||||
/* Define fields and accessors for nodes representing data types. */
|
||||
|
Loading…
Reference in New Issue
Block a user