This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
reorder bug in 3.0
- To: gcc-bugs at gcc dot gnu dot org, gcc-patches at gcc dot gnu dot org
- Subject: reorder bug in 3.0
- From: Andrew Macleod <amacleod at cygnus dot com>
- Date: Thu, 4 Oct 2001 06:42:46 -0700
This patch is required to get various IA64 OS packages to compile with 3.0.x
The problem is fixed in mainline 3.1, but it depends on all the dwarf2.1
work that rth did during the summer.
When reorder blocks moves things around, the dwarf debug
generation loses track of what moved block belongs where. It handles
this by calling abort and an internal compiler error ensues. It causes
something like 40 different packages to fail compilation
when -O and -g are used together.
I took rth's patch from July 29, and kept just the bare minimum required
to fix the problem. I have bootstrapped a 3.0 branch with this patch
on an ia64 machine.
rth has given it his blessing, but with a frozen branch, I need more
than that :-)
Can this be checked into the 3.0 branch?
Thanks
Andrew
* dwarf2.h (DW_AT_entry_pc, DW_AT_ranges): New.
* dwarf2out.c (dw_val_class_offset): New.
(val_offset): New field in struct dw_val_struct;
(arange_table): Change type to dw_die_ref *.
(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.
(DEBUG_RANGES_SECTION): New.
(dwarf_attr_name): Handle DW_AT_entry_pc, DW_AT_ranges.
(print_die, output_die): Handle dw_val_class_offset.
(attr_checksum, size_of_die, value_format): Handle dw_val_class_offset.
(add_arange): Change type to dw_die_ref *.
(gen_lexical_block_die): Handle non-contiguous blocks.
(gen_block_die): Handle non-contiguous blocks.
(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 reorder_fix_fragments.
* tree.h (BLOCK_FRAGMENT_ORIGIN, BLOCK_FRAGMENT_CHAIN): New.
* config/ia64/ia64.h (DEBUG_RANGES_SECTION): New.
* config/mips/iris6.h (DEBUG_RANGES_SECTION): New.
Index: dwarf2.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/dwarf2.h,v
retrieving revision 1.16.6.2
diff -c -p -r1.16.6.2 dwarf2.h
*** dwarf2.h 2001/06/05 21:07:46 1.16.6.2
--- dwarf2.h 2001/10/04 00:35:45
*************** enum dwarf_attribute
*** 192,197 ****
--- 192,200 ----
DW_AT_variable_parameter = 0x4b,
DW_AT_virtuality = 0x4c,
DW_AT_vtable_elem_location = 0x4d,
+ /* DWARF 2.1 */
+ DW_AT_entry_pc = 0x52,
+ DW_AT_ranges = 0x55,
/* SGI/MIPS Extensions */
DW_AT_MIPS_fde = 0x2001,
DW_AT_MIPS_loop_begin = 0x2002,
Index: dwarf2out.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/dwarf2out.c,v
retrieving revision 1.242.2.23
diff -c -p -r1.242.2.23 dwarf2out.c
*** dwarf2out.c 2001/09/10 18:29:37 1.242.2.23
--- dwarf2out.c 2001/10/04 00:36:33
*************** typedef struct dw_loc_descr_struct *dw_l
*** 2124,2129 ****
--- 2124,2130 ----
typedef enum
{
dw_val_class_addr,
+ dw_val_class_offset,
dw_val_class_loc,
dw_val_class_const,
dw_val_class_unsigned_const,
*************** typedef struct dw_val_struct
*** 2166,2171 ****
--- 2167,2173 ----
union
{
rtx val_addr;
+ long unsigned val_offset;
dw_loc_descr_ref val_loc;
long int val_int;
long unsigned val_unsigned;
*************** typedef struct dw_attr_struct *dw_attr_r
*** 3004,3010 ****
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;
/* Each entry in the line_info_table maintains the file and
line number associated with the label generated for that
--- 3006,3012 ----
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 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
*************** typedef struct pubname_struct
*** 3065,3070 ****
--- 3067,3078 ----
}
pubname_entry;
+ struct dw_ranges_struct
+ {
+ int block_num;
+ };
+
+
/* The limbo die list structure. */
typedef struct limbo_die_struct
{
*************** static unsigned pubname_table_in_use;
*** 3265,3273 ****
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;
/* Number of elements currently allocated for arange_table. */
static unsigned arange_table_allocated;
--- 3273,3280 ----
pubname_table. */
#define PUBNAME_TABLE_INCREMENT 64
! /* 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;
*************** static unsigned arange_table_in_use;
*** 3279,3284 ****
--- 3286,3304 ----
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
+
/* A pointer to the base of a list of incomplete types which might be
completed at some later time. incomplete_types_list needs to be a VARRAY
because we want to tell the garbage collector about it. If we don't tell
*************** static void add_AT_lbl_id PARAMS ((dw_d
*** 3349,3354 ****
--- 3369,3377 ----
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));
*************** static void add_pubname PARAMS ((tree,
*** 3412,3417 ****
--- 3435,3442 ----
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));
*************** static int file_info_cmp PARAMS ((const
*** 3529,3534 ****
--- 3554,3563 ----
#ifndef STR_SECTION
#define 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
*************** dwarf_attr_name (attr)
*** 3920,3925 ****
--- 3949,3959 ----
case DW_AT_vtable_elem_location:
return "DW_AT_vtable_elem_location";
+ case DW_AT_entry_pc:
+ return "DW_AT_entry_pc";
+ case DW_AT_ranges:
+ return "DW_AT_ranges";
+
case DW_AT_MIPS_fde:
return "DW_AT_MIPS_fde";
case DW_AT_MIPS_loop_begin:
*************** add_AT_lbl_offset (die, attr_kind, label
*** 4464,4469 ****
--- 4498,4520 ----
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)
*************** print_die (die, outfile)
*** 4876,4881 ****
--- 4927,4935 ----
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;
*************** attr_checksum (at, ctx)
*** 5121,5126 ****
--- 5175,5184 ----
}
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);
*************** attr_checksum (at, ctx)
*** 5134,5139 ****
--- 5192,5198 ----
case dw_val_class_fde_ref:
case dw_val_class_lbl_id:
case dw_val_class_lbl_offset:
+ break;
default:
break;
*************** size_of_die (die)
*** 5520,5525 ****
--- 5579,5587 ----
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));
*************** value_format (a)
*** 5664,5669 ****
--- 5726,5737 ----
{
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:
switch (constant_size (size_of_locs (AT_loc (a))))
{
*************** output_die (die)
*** 5811,5816 ****
--- 5879,5889 ----
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));
*************** add_arange (decl, die)
*** 6074,6082 ****
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[arange_table_in_use++] = die;
--- 6147,6154 ----
if (arange_table_in_use == arange_table_allocated)
{
arange_table_allocated += ARANGE_TABLE_INCREMENT;
! arange_table = (dw_die_ref *)
! xrealloc (arange_table, arange_table_allocated * sizeof (dw_die_ref));
}
arange_table[arange_table_in_use++] = die;
*************** output_aranges ()
*** 6162,6167 ****
--- 6234,6313 ----
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
*************** gen_variable_die (decl, context_die)
*** 9711,9716 ****
--- 9857,9863 ----
/* ??? 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)
{
*************** gen_lexical_block_die (stmt, context_die
*** 9822,9833 ****
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);
}
decls_for_scope (stmt, stmt_die, depth);
--- 9969,9998 ----
if (! BLOCK_ABSTRACT (stmt))
{
! 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);
*************** gen_block_die (stmt, context_die, depth)
*** 10464,10469 ****
--- 10629,10646 ----
|| (!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
*************** dwarf2out_finish ()
*** 11295,11300 ****
--- 11472,11484 ----
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 (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,
debug_line_section_label);
*************** dwarf2out_finish ()
*** 11328,11333 ****
--- 11512,11524 ----
/* Output the address range information. */
ASM_OUTPUT_SECTION (asm_out_file, ARANGES_SECTION);
output_aranges ();
+ }
+
+ /* Output ranges section if necessary. */
+ if (ranges_table_in_use)
+ {
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_RANGES_SECTION);
+ output_ranges ();
}
/* At this point, we've switched sections like mad, but we've done
Index: final.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/final.c,v
retrieving revision 1.158.2.6
diff -c -p -r1.158.2.6 final.c
*** final.c 2001/06/09 19:22:26 1.158.2.6
--- final.c 2001/10/04 00:36:42
*************** final_start_function (first, file, optim
*** 1646,1653 ****
function. */
if (write_symbols)
{
- number_blocks (current_function_decl);
remove_unnecessary_notes ();
/* We never actually put out begin/end notes for the top-level
block in the function. But, conceptually, that block is
always needed. */
--- 1646,1654 ----
function. */
if (write_symbols)
{
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. */
Index: function.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/function.c,v
retrieving revision 1.250.2.14
diff -c -p -r1.250.2.14 function.c
*** function.c 2001/09/12 20:55:20 1.250.2.14
--- function.c 2001/10/04 00:36:59
*************** static void pad_below PARAMS ((struct a
*** 275,282 ****
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_1 PARAMS ((rtx, tree, varray_type *));
static tree blocks_nreverse PARAMS ((tree));
static int all_blocks PARAMS ((tree, tree *));
static tree *get_block_vector PARAMS ((tree, int *));
--- 275,283 ----
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 ((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 *));
*************** identify_blocks_1 (insns, block_vector,
*** 5813,5820 ****
return block_vector;
}
! /* Identify BLOCKs referenced by more than one
! NOTE_INSN_BLOCK_{BEG,END}, and create duplicate blocks. */
void
reorder_blocks ()
--- 5814,5824 ----
return block_vector;
}
! /* 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 ()
*************** reorder_blocks ()
*** 5827,5873 ****
VARRAY_TREE_INIT (block_stack, 10, "block_stack");
/* 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 ());
reorder_blocks_1 (get_insns (), block, &block_stack);
-
BLOCK_SUBBLOCKS (block) = blocks_nreverse (BLOCK_SUBBLOCKS (block));
VARRAY_FREE (block_stack);
}
! /* Helper function for reorder_blocks. Process the insn chain beginning
! at INSNS. Recurse for CALL_PLACEHOLDER insns. */
static void
! reorder_blocks_0 (insns)
! rtx insns;
{
! rtx insn;
!
! for (insn = insns; insn; insn = NEXT_INSN (insn))
{
! 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));
! }
}
}
--- 5831,5864 ----
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;
! /* 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. Reset TREE_ASM_WRITTEN. */
static void
! reorder_blocks_0 (block)
! tree block;
{
! while (block)
{
! TREE_ASM_WRITTEN (block) = 0;
! reorder_blocks_0 (BLOCK_SUBBLOCKS (block));
! block = BLOCK_CHAIN (block);
}
}
*************** reorder_blocks_1 (insns, current_block,
*** 5886,5897 ****
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
{
tree block = NOTE_BLOCK (insn);
! /* If we have seen this block before, copy it. */
if (TREE_ASM_WRITTEN (block))
{
! block = copy_node (block);
! NOTE_BLOCK (insn) = block;
}
BLOCK_SUBBLOCKS (block) = 0;
TREE_ASM_WRITTEN (block) = 1;
BLOCK_SUPERCONTEXT (block) = current_block;
--- 5877,5902 ----
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG)
{
tree block = NOTE_BLOCK (insn);
!
! /* If we have seen this block before, that means it now
! spans multiple address regions. Create a new fragment. */
if (TREE_ASM_WRITTEN (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;
*************** reorder_blocks_1 (insns, current_block,
*** 5919,5924 ****
--- 5924,5985 ----
if (XEXP (cp, 2))
reorder_blocks_1 (XEXP (cp, 2), 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);
}
}
Index: tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tree.h,v
retrieving revision 1.223.2.13
diff -c -p -r1.223.2.13 tree.h
*** tree.h 2001/07/11 16:57:31 1.223.2.13
--- tree.h 2001/10/04 00:37:12
*************** struct tree_exp
*** 835,840 ****
--- 835,867 ----
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;
*************** struct tree_block
*** 847,852 ****
--- 874,881 ----
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. */
Index: config/ia64/ia64.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/ia64/ia64.h,v
retrieving revision 1.60.4.4
diff -c -p -r1.60.4.4 ia64.h
*** ia64.h 2001/07/25 13:24:46 1.60.4.4
--- ia64.h 2001/10/04 00:37:22
*************** do { \
*** 2556,2561 ****
--- 2556,2562 ----
#define ARANGES_SECTION ".debug_aranges, \"\", \"progbits\""
#define DEBUG_LINE_SECTION ".debug_line, \"\", \"progbits\""
#define PUBNAMES_SECTION ".debug_pubnames, \"\", \"progbits\""
+ #define DEBUG_RANGES_SECTION ".debug_ranges, \"\", \"progbits\""
/* C string constants giving the pseudo-op to use for a sequence of
2, 4, and 8 byte unaligned constants. dwarf2out.c needs these. */
Index: config/mips/iris6.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/mips/iris6.h,v
retrieving revision 1.28.2.6
diff -c -p -r1.28.2.6 iris6.h
*** iris6.h 2001/07/17 12:51:31 1.28.2.6
--- iris6.h 2001/10/04 00:37:25
*************** Boston, MA 02111-1307, USA. */
*** 226,231 ****
--- 226,232 ----
#define ARANGES_SECTION ".debug_aranges,0x7000001e,0,0,1"
#define FRAME_SECTION ".debug_frame,0x7000001e,0x08000000,0,1"
#define ABBREV_SECTION ".debug_abbrev,0x7000001e,0,0,1"
+ #define DEBUG_RANGES_SECTION ".debug_ranges,0x7000001e,0,0,1"
/* ??? If no mabi=X option give, but a mipsX option is, then should depend
on the mipsX option. */