+2012-03-05 Jakub Jelinek <jakub@redhat.com>
+
+ PR debug/51902
+ * tree.h (BLOCK_SAME_RANGE): Define.
+ * function.c (block_fragments_nreverse): Clear BLOCK_SAME_RANGE
+ if BLOCK_FRAGMENT_CHAIN is non-NULL, but has it cleared.
+ Also clear BLOCK_SAME_RANGE if fragment chain's supercontext fragment
+ isn't equal to supercontext fragment's fragment chain.
+ Adjust BLOCK_SUPERCONTEXT to point to supercontext fragment's
+ fragment origin.
+ (blocks_nreverse_all): Likewise.
+ (reorder_blocks_1): Compute BLOCK_SAME_RANGE bits. Set
+ BLOCK_SUPERCONTEXT to supercontext fragment instead of
+ supercontext fragment's fragment origin.
+ * dwarf2out.c (add_high_low_attributes): If stmt has the same
+ range as its parent (or parents thereof etc.), use the parent's
+ DW_AT_ranges value instead of creating a new .debug_ranges range.
+
2012-03-05 Richard Henderson <rth@redhat.com>
PR tree-opt/52242
if (BLOCK_FRAGMENT_CHAIN (stmt)
&& (dwarf_version >= 3 || !dwarf_strict))
{
- tree chain;
+ tree chain, superblock = NULL_TREE;
+ dw_die_ref pdie;
+ dw_attr_ref attr = NULL;
if (inlined_function_outer_scope_p (stmt))
{
add_AT_lbl_id (die, DW_AT_entry_pc, label);
}
+ /* Optimize duplicate .debug_ranges lists or even tails of
+ lists. If this BLOCK has same ranges as its supercontext,
+ lookup DW_AT_ranges attribute in the supercontext (and
+ recursively so), verify that the ranges_table contains the
+ right values and use it instead of adding a new .debug_range. */
+ for (chain = stmt, pdie = die;
+ BLOCK_SAME_RANGE (chain);
+ chain = BLOCK_SUPERCONTEXT (chain))
+ {
+ dw_attr_ref new_attr;
+
+ pdie = pdie->die_parent;
+ if (pdie == NULL)
+ break;
+ if (BLOCK_SUPERCONTEXT (chain) == NULL_TREE)
+ break;
+ new_attr = get_AT (pdie, DW_AT_ranges);
+ if (new_attr == NULL
+ || new_attr->dw_attr_val.val_class != dw_val_class_range_list)
+ break;
+ attr = new_attr;
+ superblock = BLOCK_SUPERCONTEXT (chain);
+ }
+ if (attr != NULL
+ && (ranges_table[attr->dw_attr_val.v.val_offset
+ / 2 / DWARF2_ADDR_SIZE].num
+ == BLOCK_NUMBER (superblock))
+ && BLOCK_FRAGMENT_CHAIN (superblock))
+ {
+ unsigned long off = attr->dw_attr_val.v.val_offset
+ / 2 / DWARF2_ADDR_SIZE;
+ unsigned long supercnt = 0, thiscnt = 0;
+ for (chain = BLOCK_FRAGMENT_CHAIN (superblock);
+ chain; chain = BLOCK_FRAGMENT_CHAIN (chain))
+ {
+ ++supercnt;
+ gcc_checking_assert (ranges_table[off + supercnt].num
+ == BLOCK_NUMBER (chain));
+ }
+ gcc_checking_assert (ranges_table[off + supercnt + 1].num == 0);
+ for (chain = BLOCK_FRAGMENT_CHAIN (stmt);
+ chain; chain = BLOCK_FRAGMENT_CHAIN (chain))
+ ++thiscnt;
+ gcc_assert (supercnt >= thiscnt);
+ add_AT_range_list (die, DW_AT_ranges,
+ (off + supercnt - thiscnt)
+ * 2 * DWARF2_ADDR_SIZE);
+ return;
+ }
+
add_AT_range_list (die, DW_AT_ranges, add_ranges (stmt));
chain = BLOCK_FRAGMENT_CHAIN (stmt);
\f
/* Reverse the order of elements in the fragment chain T of blocks,
- and return the new head of the chain (old last element). */
+ and return the new head of the chain (old last element).
+ In addition to that clear BLOCK_SAME_RANGE flags when needed
+ and adjust BLOCK_SUPERCONTEXT from the super fragment to
+ its super fragment origin. */
static tree
block_fragments_nreverse (tree t)
{
- tree prev = 0, block, next;
+ tree prev = 0, block, next, prev_super = 0;
+ tree super = BLOCK_SUPERCONTEXT (t);
+ if (BLOCK_FRAGMENT_ORIGIN (super))
+ super = BLOCK_FRAGMENT_ORIGIN (super);
for (block = t; block; block = next)
{
next = BLOCK_FRAGMENT_CHAIN (block);
BLOCK_FRAGMENT_CHAIN (block) = prev;
+ if ((prev && !BLOCK_SAME_RANGE (prev))
+ || (BLOCK_FRAGMENT_CHAIN (BLOCK_SUPERCONTEXT (block))
+ != prev_super))
+ BLOCK_SAME_RANGE (block) = 0;
+ prev_super = BLOCK_SUPERCONTEXT (block);
+ BLOCK_SUPERCONTEXT (block) = super;
prev = block;
}
+ t = BLOCK_FRAGMENT_ORIGIN (t);
+ if (BLOCK_FRAGMENT_CHAIN (BLOCK_SUPERCONTEXT (t))
+ != prev_super)
+ BLOCK_SAME_RANGE (t) = 0;
+ BLOCK_SUPERCONTEXT (t) = super;
return prev;
}
{
next = BLOCK_CHAIN (block);
BLOCK_CHAIN (block) = prev;
- BLOCK_SUBBLOCKS (block) = blocks_nreverse_all (BLOCK_SUBBLOCKS (block));
if (BLOCK_FRAGMENT_CHAIN (block)
&& BLOCK_FRAGMENT_ORIGIN (block) == NULL_TREE)
- BLOCK_FRAGMENT_CHAIN (block)
- = block_fragments_nreverse (BLOCK_FRAGMENT_CHAIN (block));
+ {
+ BLOCK_FRAGMENT_CHAIN (block)
+ = block_fragments_nreverse (BLOCK_FRAGMENT_CHAIN (block));
+ if (!BLOCK_SAME_RANGE (BLOCK_FRAGMENT_CHAIN (block)))
+ BLOCK_SAME_RANGE (block) = 0;
+ }
+ BLOCK_SUBBLOCKS (block) = blocks_nreverse_all (BLOCK_SUBBLOCKS (block));
prev = block;
}
return prev;
reorder_blocks_1 (rtx insns, tree current_block, VEC(tree,heap) **p_block_stack)
{
rtx insn;
+ tree prev_beg = NULL_TREE, prev_end = NULL_TREE;
for (insn = insns; insn; insn = NEXT_INSN (insn))
{
gcc_assert (BLOCK_FRAGMENT_ORIGIN (block) == NULL_TREE);
origin = block;
+ if (prev_end)
+ BLOCK_SAME_RANGE (prev_end) = 0;
+ prev_end = NULL_TREE;
+
/* 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);
+ BLOCK_SAME_RANGE (new_block) = 0;
BLOCK_FRAGMENT_ORIGIN (new_block) = origin;
BLOCK_FRAGMENT_CHAIN (new_block)
= BLOCK_FRAGMENT_CHAIN (origin);
block = new_block;
}
+ if (prev_beg == current_block && prev_beg)
+ BLOCK_SAME_RANGE (block) = 1;
+
+ prev_beg = origin;
+
BLOCK_SUBBLOCKS (block) = 0;
TREE_ASM_WRITTEN (block) = 1;
/* When there's only one block for the entire function,
will cause infinite recursion. */
if (block != current_block)
{
+ tree super;
if (block != origin)
- gcc_assert (BLOCK_SUPERCONTEXT (origin) == current_block);
-
- BLOCK_SUPERCONTEXT (block) = current_block;
+ gcc_assert (BLOCK_SUPERCONTEXT (origin) == current_block
+ || BLOCK_FRAGMENT_ORIGIN (BLOCK_SUPERCONTEXT
+ (origin))
+ == current_block);
+ if (VEC_empty (tree, *p_block_stack))
+ super = current_block;
+ else
+ {
+ super = VEC_last (tree, *p_block_stack);
+ gcc_assert (super == current_block
+ || BLOCK_FRAGMENT_ORIGIN (super)
+ == current_block);
+ }
+ BLOCK_SUPERCONTEXT (block) = super;
BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (current_block);
BLOCK_SUBBLOCKS (current_block) = block;
current_block = origin;
{
NOTE_BLOCK (insn) = VEC_pop (tree, *p_block_stack);
current_block = BLOCK_SUPERCONTEXT (current_block);
+ if (BLOCK_FRAGMENT_ORIGIN (current_block))
+ current_block = BLOCK_FRAGMENT_ORIGIN (current_block);
+ prev_beg = NULL_TREE;
+ prev_end = BLOCK_SAME_RANGE (NOTE_BLOCK (insn))
+ ? NOTE_BLOCK (insn) : NULL_TREE;
}
}
+ else
+ {
+ prev_beg = NULL_TREE;
+ if (prev_end)
+ BLOCK_SAME_RANGE (prev_end) = 0;
+ prev_end = NULL_TREE;
+ }
}
}