#endif
#endif
+/* CIE identifier. */
+#if HOST_BITS_PER_WIDE_INT >= 64
+#define DWARF_CIE_ID \
+ (unsigned HOST_WIDE_INT) (DWARF_OFFSET_SIZE == 4 ? DW_CIE_ID : DW64_CIE_ID)
+#else
+#define DWARF_CIE_ID DW_CIE_ID
+#endif
+
/* A pointer to the base of a table that contains frame description
information for each routine. */
static GTY((length ("fde_table_allocated"))) dw_fde_ref fde_table;
if (for_eh)
switch_to_eh_frame_section ();
else
- switch_to_section (debug_frame_section);
+ {
+ if (!debug_frame_section)
+ debug_frame_section = get_section (DEBUG_FRAME_SECTION,
+ SECTION_DEBUG, NULL);
+ switch_to_section (debug_frame_section);
+ }
ASM_GENERATE_INTERNAL_LABEL (section_start_label, FRAME_BEGIN_LABEL, for_eh);
ASM_OUTPUT_LABEL (asm_out_file, section_start_label);
/* Output the CIE. */
ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh);
ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh);
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
"Length of Common Information Entry");
ASM_OUTPUT_LABEL (asm_out_file, l1);
/* Now that the CIE pointer is PC-relative for EH,
use 0 to identify the CIE. */
dw2_asm_output_data ((for_eh ? 4 : DWARF_OFFSET_SIZE),
- (for_eh ? 0 : DW_CIE_ID),
+ (for_eh ? 0 : DWARF_CIE_ID),
"CIE Identifier Tag");
dw2_asm_output_data (1, DW_CIE_VERSION, "CIE Version");
targetm.asm_out.internal_label (asm_out_file, FDE_LABEL, for_eh + i * 2);
ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i * 2);
ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i * 2);
+ if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4 && !for_eh)
+ dw2_asm_output_data (4, 0xffffffff,
+ "Initial length escape value indicating 64-bit DWARF extension");
dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
"FDE Length");
ASM_OUTPUT_LABEL (asm_out_file, l1);
static unsigned long
size_of_locs (dw_loc_descr_ref loc)
{
+ dw_loc_descr_ref l;
unsigned long size;
- for (size = 0; loc != NULL; loc = loc->dw_loc_next)
+ /* If there are no skip or bra opcodes, don't fill in the dw_loc_addr
+ field, to avoid writing to a PCH file. */
+ for (size = 0, l = loc; l != NULL; l = l->dw_loc_next)
{
- loc->dw_loc_addr = size;
- size += size_of_loc_descr (loc);
+ if (l->dw_loc_opc == DW_OP_skip || l->dw_loc_opc == DW_OP_bra)
+ break;
+ size += size_of_loc_descr (l);
+ }
+ if (! l)
+ return size;
+
+ for (size = 0, l = loc; l != NULL; l = l->dw_loc_next)
+ {
+ l->dw_loc_addr = size;
+ size += size_of_loc_descr (l);
}
return size;
typedef struct dw_attr_struct GTY(())
{
enum dwarf_attribute dw_attr;
- dw_attr_ref dw_attr_next;
dw_val_node dw_attr_val;
}
dw_attr_node;
-/* The Debugging Information Entry (DIE) structure */
+DEF_VEC_O(dw_attr_node);
+DEF_VEC_ALLOC_O(dw_attr_node,gc);
+
+/* The Debugging Information Entry (DIE) structure. DIEs form a tree.
+ The children of each node form a circular list linked by
+ die_sib. die_child points to the node *before* the "first" child node. */
typedef struct die_struct GTY(())
{
enum dwarf_tag die_tag;
char *die_symbol;
- dw_attr_ref die_attr;
+ VEC(dw_attr_node,gc) * die_attr;
dw_die_ref die_parent;
dw_die_ref die_child;
dw_die_ref die_sib;
dw_offset die_offset;
unsigned long die_abbrev;
int die_mark;
+ /* Die is used and must not be pruned as unused. */
+ int die_perennial_p;
unsigned int decl_id;
}
die_node;
+/* Evaluate 'expr' while 'c' is set to each child of DIE in order. */
+#define FOR_EACH_CHILD(die, c, expr) do { \
+ c = die->die_child; \
+ if (c) do { \
+ c = c->die_sib; \
+ expr; \
+ } while (c != die->die_child); \
+} while (0)
+
/* The pubname structure */
typedef struct pubname_struct GTY(())
static bool is_ada (void);
static void remove_AT (dw_die_ref, enum dwarf_attribute);
static void remove_child_TAG (dw_die_ref, enum dwarf_tag);
-static inline void free_die (dw_die_ref);
-static void remove_children (dw_die_ref);
static void add_child_die (dw_die_ref, dw_die_ref);
static dw_die_ref new_die (enum dwarf_tag, dw_die_ref, tree);
static dw_die_ref lookup_type_die (tree);
static void print_spaces (FILE *);
static void print_die (dw_die_ref, FILE *);
static void print_dwarf_line_table (FILE *);
-static void reverse_die_lists (dw_die_ref);
-static void reverse_all_dies (dw_die_ref);
static dw_die_ref push_new_compile_unit (dw_die_ref, dw_die_ref);
static dw_die_ref pop_compile_unit (dw_die_ref);
static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
return context;
}
\f
-/* Add an attribute/value pair to a DIE. We build the lists up in reverse
- addition order, and correct that in reverse_all_dies. */
+/* Add an attribute/value pair to a DIE. */
static inline void
add_dwarf_attr (dw_die_ref die, dw_attr_ref attr)
{
- if (die != NULL && attr != NULL)
- {
- attr->dw_attr_next = die->die_attr;
- die->die_attr = attr;
- }
+ /* Maybe this should be an assert? */
+ if (die == NULL)
+ return;
+
+ if (die->die_attr == NULL)
+ die->die_attr = VEC_alloc (dw_attr_node, gc, 1);
+ VEC_safe_push (dw_attr_node, gc, die->die_attr, attr);
}
static inline enum dw_val_class
static inline void
add_AT_flag (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int flag)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_flag;
- attr->dw_attr_val.v.val_flag = flag;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_flag;
+ attr.dw_attr_val.v.val_flag = flag;
+ add_dwarf_attr (die, &attr);
}
static inline unsigned
static inline void
add_AT_int (dw_die_ref die, enum dwarf_attribute attr_kind, HOST_WIDE_INT int_val)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_const;
- attr->dw_attr_val.v.val_int = int_val;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_const;
+ attr.dw_attr_val.v.val_int = int_val;
+ add_dwarf_attr (die, &attr);
}
static inline HOST_WIDE_INT
add_AT_unsigned (dw_die_ref die, enum dwarf_attribute attr_kind,
unsigned HOST_WIDE_INT unsigned_val)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_unsigned_const;
- attr->dw_attr_val.v.val_unsigned = unsigned_val;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_unsigned_const;
+ attr.dw_attr_val.v.val_unsigned = unsigned_val;
+ add_dwarf_attr (die, &attr);
}
static inline unsigned HOST_WIDE_INT
add_AT_long_long (dw_die_ref die, enum dwarf_attribute attr_kind,
long unsigned int val_hi, long unsigned int val_low)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_long_long;
- attr->dw_attr_val.v.val_long_long.hi = val_hi;
- attr->dw_attr_val.v.val_long_long.low = val_low;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_long_long;
+ attr.dw_attr_val.v.val_long_long.hi = val_hi;
+ attr.dw_attr_val.v.val_long_long.low = val_low;
+ add_dwarf_attr (die, &attr);
}
/* Add a floating point attribute value to a DIE and return it. */
add_AT_vec (dw_die_ref die, enum dwarf_attribute attr_kind,
unsigned int length, unsigned int elt_size, unsigned char *array)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_vec;
- attr->dw_attr_val.v.val_vec.length = length;
- attr->dw_attr_val.v.val_vec.elt_size = elt_size;
- attr->dw_attr_val.v.val_vec.array = array;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_vec;
+ attr.dw_attr_val.v.val_vec.length = length;
+ attr.dw_attr_val.v.val_vec.elt_size = elt_size;
+ attr.dw_attr_val.v.val_vec.array = array;
+ add_dwarf_attr (die, &attr);
}
/* Hash and equality functions for debug_str_hash. */
static inline void
add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
struct indirect_string_node *node;
void **slot;
node->str = ggc_strdup (str);
node->refcount++;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_str;
- attr->dw_attr_val.v.val_str = node;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_str;
+ attr.dw_attr_val.v.val_str = node;
+ add_dwarf_attr (die, &attr);
}
static inline const char *
static inline void
add_AT_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind, dw_die_ref targ_die)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_die_ref;
- attr->dw_attr_val.v.val_die_ref.die = targ_die;
- attr->dw_attr_val.v.val_die_ref.external = 0;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_die_ref;
+ attr.dw_attr_val.v.val_die_ref.die = targ_die;
+ attr.dw_attr_val.v.val_die_ref.external = 0;
+ add_dwarf_attr (die, &attr);
}
/* Add an AT_specification attribute to a DIE, and also make the back
static inline void
add_AT_fde_ref (dw_die_ref die, enum dwarf_attribute attr_kind, unsigned int targ_fde)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_fde_ref;
- attr->dw_attr_val.v.val_fde_index = targ_fde;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_fde_ref;
+ attr.dw_attr_val.v.val_fde_index = targ_fde;
+ add_dwarf_attr (die, &attr);
}
/* Add a location description attribute value to a DIE. */
static inline void
add_AT_loc (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_descr_ref loc)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_loc;
- attr->dw_attr_val.v.val_loc = loc;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_loc;
+ attr.dw_attr_val.v.val_loc = loc;
+ add_dwarf_attr (die, &attr);
}
static inline dw_loc_descr_ref
static inline void
add_AT_loc_list (dw_die_ref die, enum dwarf_attribute attr_kind, dw_loc_list_ref loc_list)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_loc_list;
- attr->dw_attr_val.v.val_loc_list = loc_list;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_loc_list;
+ attr.dw_attr_val.v.val_loc_list = loc_list;
+ add_dwarf_attr (die, &attr);
have_location_lists = true;
}
static inline void
add_AT_addr (dw_die_ref die, enum dwarf_attribute attr_kind, rtx addr)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_addr;
- attr->dw_attr_val.v.val_addr = addr;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_addr;
+ attr.dw_attr_val.v.val_addr = addr;
+ add_dwarf_attr (die, &attr);
}
static inline rtx
static inline void
add_AT_lbl_id (dw_die_ref die, enum dwarf_attribute attr_kind, const char *lbl_id)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_lbl_id;
- attr->dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_lbl_id;
+ attr.dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
+ add_dwarf_attr (die, &attr);
}
/* Add a section offset attribute value to a DIE, an offset into the
add_AT_lineptr (dw_die_ref die, enum dwarf_attribute attr_kind,
const char *label)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_lineptr;
- attr->dw_attr_val.v.val_lbl_id = xstrdup (label);
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_lineptr;
+ attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
+ add_dwarf_attr (die, &attr);
}
/* Add a section offset attribute value to a DIE, an offset into the
add_AT_macptr (dw_die_ref die, enum dwarf_attribute attr_kind,
const char *label)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_macptr;
- attr->dw_attr_val.v.val_lbl_id = xstrdup (label);
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_macptr;
+ attr.dw_attr_val.v.val_lbl_id = xstrdup (label);
+ add_dwarf_attr (die, &attr);
}
/* Add an offset attribute value to a DIE. */
add_AT_offset (dw_die_ref die, enum dwarf_attribute attr_kind,
unsigned HOST_WIDE_INT offset)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- 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);
+ 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);
}
/* Add an range_list attribute value to a DIE. */
add_AT_range_list (dw_die_ref die, enum dwarf_attribute attr_kind,
long unsigned int offset)
{
- dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
+ dw_attr_node attr;
- attr->dw_attr_next = NULL;
- attr->dw_attr = attr_kind;
- attr->dw_attr_val.val_class = dw_val_class_range_list;
- attr->dw_attr_val.v.val_offset = offset;
- add_dwarf_attr (die, attr);
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_range_list;
+ attr.dw_attr_val.v.val_offset = offset;
+ add_dwarf_attr (die, &attr);
}
static inline const char *
get_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a;
+ unsigned ix;
dw_die_ref spec = NULL;
- if (die != NULL)
- {
- for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
- if (a->dw_attr == attr_kind)
- return a;
- else if (a->dw_attr == DW_AT_specification
- || a->dw_attr == DW_AT_abstract_origin)
- spec = AT_ref (a);
+ if (! die)
+ return NULL;
- if (spec)
- return get_AT (spec, attr_kind);
- }
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (a->dw_attr == attr_kind)
+ return a;
+ else if (a->dw_attr == DW_AT_specification
+ || a->dw_attr == DW_AT_abstract_origin)
+ spec = AT_ref (a);
+
+ if (spec)
+ return get_AT (spec, attr_kind);
return NULL;
}
return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83;
}
-/* Free up the memory used by A. */
-
-static inline void free_AT (dw_attr_ref);
-static inline void
-free_AT (dw_attr_ref a)
-{
- if (AT_class (a) == dw_val_class_str)
- if (a->dw_attr_val.v.val_str->refcount)
- a->dw_attr_val.v.val_str->refcount--;
-}
-
/* Remove the specified attribute if present. */
static void
remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
{
- dw_attr_ref *p;
- dw_attr_ref removed = NULL;
+ dw_attr_ref a;
+ unsigned ix;
- if (die != NULL)
- {
- for (p = &(die->die_attr); *p; p = &((*p)->dw_attr_next))
- if ((*p)->dw_attr == attr_kind)
- {
- removed = *p;
- *p = (*p)->dw_attr_next;
- break;
- }
+ if (! die)
+ return;
- if (removed != 0)
- free_AT (removed);
- }
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (a->dw_attr == attr_kind)
+ {
+ if (AT_class (a) == dw_val_class_str)
+ if (a->dw_attr_val.v.val_str->refcount)
+ a->dw_attr_val.v.val_str->refcount--;
+
+ /* VEC_ordered_remove should help reduce the number of abbrevs
+ that are needed. */
+ VEC_ordered_remove (dw_attr_node, die->die_attr, ix);
+ return;
+ }
}
-/* Remove child die whose die_tag is specified tag. */
+/* Remove CHILD from its parent. PREV must have the property that
+ PREV->DIE_SIB == CHILD. Does not alter CHILD. */
static void
-remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
+remove_child_with_prev (dw_die_ref child, dw_die_ref prev)
{
- dw_die_ref current, prev, next;
- current = die->die_child;
- prev = NULL;
- while (current != NULL)
+ gcc_assert (child->die_parent == prev->die_parent);
+ gcc_assert (prev->die_sib == child);
+ if (prev == child)
{
- if (current->die_tag == tag)
- {
- next = current->die_sib;
- if (prev == NULL)
- die->die_child = next;
- else
- prev->die_sib = next;
- free_die (current);
- current = next;
- }
- else
- {
- prev = current;
- current = current->die_sib;
- }
+ gcc_assert (child->die_parent->die_child == child);
+ prev = NULL;
}
+ else
+ prev->die_sib = child->die_sib;
+ if (child->die_parent->die_child == child)
+ child->die_parent->die_child = prev;
}
-/* Free up the memory used by DIE. */
-
-static inline void
-free_die (dw_die_ref die)
-{
- remove_children (die);
-}
-
-/* Discard the children of this DIE. */
+/* Remove child DIE whose die_tag is TAG. Do nothing if no child
+ matches TAG. */
static void
-remove_children (dw_die_ref die)
+remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
{
- dw_die_ref child_die = die->die_child;
-
- die->die_child = NULL;
-
- while (child_die != NULL)
- {
- dw_die_ref tmp_die = child_die;
- dw_attr_ref a;
-
- child_die = child_die->die_sib;
-
- for (a = tmp_die->die_attr; a != NULL;)
- {
- dw_attr_ref tmp_a = a;
-
- a = a->dw_attr_next;
- free_AT (tmp_a);
- }
-
- free_die (tmp_die);
- }
+ dw_die_ref c;
+
+ c = die->die_child;
+ if (c) do {
+ dw_die_ref prev = c;
+ c = c->die_sib;
+ while (c->die_tag == tag)
+ {
+ remove_child_with_prev (c, prev);
+ /* Might have removed every child. */
+ if (c == c->die_sib)
+ return;
+ c = c->die_sib;
+ }
+ } while (c != die->die_child);
}
-/* Add a child DIE below its parent. We build the lists up in reverse
- addition order, and correct that in reverse_all_dies. */
+/* Add a CHILD_DIE as the last child of DIE. */
-static inline void
+static void
add_child_die (dw_die_ref die, dw_die_ref child_die)
{
- if (die != NULL && child_die != NULL)
- {
- gcc_assert (die != child_die);
+ /* FIXME this should probably be an assert. */
+ if (! die || ! child_die)
+ return;
+ gcc_assert (die != child_die);
- child_die->die_parent = die;
- child_die->die_sib = die->die_child;
- die->die_child = child_die;
+ child_die->die_parent = die;
+ if (die->die_child)
+ {
+ child_die->die_sib = die->die_child->die_sib;
+ die->die_child->die_sib = child_die;
}
+ else
+ child_die->die_sib = child_die;
+ die->die_child = child_die;
}
/* Move CHILD, which must be a child of PARENT or the DIE for which PARENT
- is the specification, to the front of PARENT's list of children. */
+ is the specification, to the end of PARENT's list of children.
+ This is done by removing and re-adding it. */
static void
splice_child_die (dw_die_ref parent, dw_die_ref child)
{
- dw_die_ref *p;
+ dw_die_ref p;
/* We want the declaration DIE from inside the class, not the
specification DIE at toplevel. */
gcc_assert (child->die_parent == parent
|| (child->die_parent
== get_AT_ref (parent, DW_AT_specification)));
-
- for (p = &(child->die_parent->die_child); *p; p = &((*p)->die_sib))
- if (*p == child)
+
+ for (p = child->die_parent->die_child; ; p = p->die_sib)
+ if (p->die_sib == child)
{
- *p = child->die_sib;
+ remove_child_with_prev (child, p);
break;
}
- child->die_parent = parent;
- child->die_sib = parent->die_child;
- parent->die_child = child;
+ add_child_die (parent, child);
}
/* Return a pointer to a newly created DIE node. */
{
dw_attr_ref a;
dw_die_ref c;
+ unsigned ix;
print_spaces (outfile);
fprintf (outfile, "DIE %4lu: %s\n",
fprintf (outfile, " abbrev id: %lu", die->die_abbrev);
fprintf (outfile, " offset: %lu\n", die->die_offset);
- for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
{
print_spaces (outfile);
fprintf (outfile, " %s: ", dwarf_attr_name (a->dw_attr));
if (die->die_child != NULL)
{
print_indent += 4;
- for (c = die->die_child; c != NULL; c = c->die_sib)
- print_die (c, outfile);
-
+ FOR_EACH_CHILD (die, c, print_die (c, outfile));
print_indent -= 4;
}
if (print_indent == 0)
print_dwarf_line_table (stderr);
}
\f
-/* We build up the lists of children and attributes by pushing new ones
- onto the beginning of the list. Reverse the lists for DIE so that
- they are in order of addition. */
-
-static void
-reverse_die_lists (dw_die_ref die)
-{
- dw_die_ref c, cp, cn;
- dw_attr_ref a, ap, an;
-
- for (a = die->die_attr, ap = 0; a; a = an)
- {
- an = a->dw_attr_next;
- a->dw_attr_next = ap;
- ap = a;
- }
-
- die->die_attr = ap;
-
- for (c = die->die_child, cp = 0; c; c = cn)
- {
- cn = c->die_sib;
- c->die_sib = cp;
- cp = c;
- }
-
- die->die_child = cp;
-}
-
-/* reverse_die_lists only reverses the single die you pass it. Since we used to
- reverse all dies in add_sibling_attributes, which runs through all the dies,
- it would reverse all the dies. Now, however, since we don't call
- reverse_die_lists in add_sibling_attributes, we need a routine to
- recursively reverse all the dies. This is that routine. */
-
-static void
-reverse_all_dies (dw_die_ref die)
-{
- dw_die_ref c;
-
- reverse_die_lists (die);
-
- for (c = die->die_child; c; c = c->die_sib)
- reverse_all_dies (c);
-}
-
/* Start a new compilation unit DIE for an include file. OLD_UNIT is the CU
for the enclosing include file, if any. BINCL_DIE is the DW_TAG_GNU_BINCL
DIE that marks the start of the DIEs for this include file. */
{
dw_die_ref c;
dw_attr_ref a;
+ unsigned ix;
/* To avoid infinite recursion. */
if (die->die_mark)
CHECKSUM (die->die_tag);
- for (a = die->die_attr; a; a = a->dw_attr_next)
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
attr_checksum (a, ctx, mark);
- for (c = die->die_child; c; c = c->die_sib)
- die_checksum (c, ctx, mark);
+ FOR_EACH_CHILD (die, c, die_checksum (c, ctx, mark));
}
#undef CHECKSUM
same_die_p (dw_die_ref die1, dw_die_ref die2, int *mark)
{
dw_die_ref c1, c2;
- dw_attr_ref a1, a2;
+ dw_attr_ref a1;
+ unsigned ix;
/* To avoid infinite recursion. */
if (die1->die_mark)
if (die1->die_tag != die2->die_tag)
return 0;
- for (a1 = die1->die_attr, a2 = die2->die_attr;
- a1 && a2;
- a1 = a1->dw_attr_next, a2 = a2->dw_attr_next)
- if (!same_attr_p (a1, a2, mark))
- return 0;
- if (a1 || a2)
+ if (VEC_length (dw_attr_node, die1->die_attr)
+ != VEC_length (dw_attr_node, die2->die_attr))
return 0;
-
- for (c1 = die1->die_child, c2 = die2->die_child;
- c1 && c2;
- c1 = c1->die_sib, c2 = c2->die_sib)
- if (!same_die_p (c1, c2, mark))
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die1->die_attr, ix, a1); ix++)
+ if (!same_attr_p (a1, VEC_index (dw_attr_node, die2->die_attr, ix), mark))
return 0;
- if (c1 || c2)
- return 0;
+
+ c1 = die1->die_child;
+ c2 = die2->die_child;
+ if (! c1)
+ {
+ if (c2)
+ return 0;
+ }
+ else
+ for (;;)
+ {
+ if (!same_die_p (c1, c2, mark))
+ return 0;
+ c1 = c1->die_sib;
+ c2 = c2->die_sib;
+ if (c1 == die1->die_child)
+ {
+ if (c2 == die2->die_child)
+ break;
+ else
+ return 0;
+ }
+ }
return 1;
}
{
return (is_type_die (c)
|| (get_AT (c, DW_AT_declaration)
- && !get_AT (c, DW_AT_specification)));
+ && !get_AT (c, DW_AT_specification))
+ || c->die_tag == DW_TAG_namespace);
}
static char *
die->die_symbol = gen_internal_sym ("LDIE");
}
- for (c = die->die_child; c != NULL; c = c->die_sib)
- assign_symbol_names (c);
+ FOR_EACH_CHILD (die, c, assign_symbol_names (c));
}
struct cu_hash_table_entry
static void
break_out_includes (dw_die_ref die)
{
- dw_die_ref *ptr;
+ dw_die_ref c;
dw_die_ref unit = NULL;
limbo_die_node *node, **pnode;
htab_t cu_hash_table;
- for (ptr = &(die->die_child); *ptr;)
- {
- dw_die_ref c = *ptr;
-
- if (c->die_tag == DW_TAG_GNU_BINCL || c->die_tag == DW_TAG_GNU_EINCL
- || (unit && is_comdat_die (c)))
- {
- /* This DIE is for a secondary CU; remove it from the main one. */
- *ptr = c->die_sib;
-
- if (c->die_tag == DW_TAG_GNU_BINCL)
- {
- unit = push_new_compile_unit (unit, c);
- free_die (c);
- }
- else if (c->die_tag == DW_TAG_GNU_EINCL)
- {
- unit = pop_compile_unit (unit);
- free_die (c);
- }
- else
- add_child_die (unit, c);
- }
- else
- {
- /* Leave this DIE in the main CU. */
- ptr = &(c->die_sib);
- continue;
- }
- }
+ c = die->die_child;
+ if (c) do {
+ dw_die_ref prev = c;
+ c = c->die_sib;
+ while (c->die_tag == DW_TAG_GNU_BINCL || c->die_tag == DW_TAG_GNU_EINCL
+ || (unit && is_comdat_die (c)))
+ {
+ dw_die_ref next = c->die_sib;
+
+ /* This DIE is for a secondary CU; remove it from the main one. */
+ remove_child_with_prev (c, prev);
+
+ if (c->die_tag == DW_TAG_GNU_BINCL)
+ unit = push_new_compile_unit (unit, c);
+ else if (c->die_tag == DW_TAG_GNU_EINCL)
+ unit = pop_compile_unit (unit);
+ else
+ add_child_die (unit, c);
+ c = next;
+ if (c == die->die_child)
+ break;
+ }
+ } while (c != die->die_child);
#if 0
/* We can only use this in debugging, since the frontend doesn't check
{
dw_die_ref c;
- if (die->die_tag != DW_TAG_compile_unit
- && die->die_sib && die->die_child != NULL)
- /* Add the sibling link to the front of the attribute list. */
+ if (! die->die_child)
+ return;
+
+ if (die->die_parent && die != die->die_parent->die_child)
add_AT_die_ref (die, DW_AT_sibling, die->die_sib);
- for (c = die->die_child; c != NULL; c = c->die_sib)
- add_sibling_attributes (c);
+ FOR_EACH_CHILD (die, c, add_sibling_attributes (c));
}
/* Output all location lists for the DIE and its children. */
output_location_lists (dw_die_ref die)
{
dw_die_ref c;
- dw_attr_ref d_attr;
-
- for (d_attr = die->die_attr; d_attr; d_attr = d_attr->dw_attr_next)
- if (AT_class (d_attr) == dw_val_class_loc_list)
- output_loc_list (AT_loc_list (d_attr));
+ dw_attr_ref a;
+ unsigned ix;
- for (c = die->die_child; c != NULL; c = c->die_sib)
- output_location_lists (c);
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (AT_class (a) == dw_val_class_loc_list)
+ output_loc_list (AT_loc_list (a));
+ FOR_EACH_CHILD (die, c, output_location_lists (c));
}
/* The format of each DIE (and its attribute value pairs) is encoded in an
unsigned long abbrev_id;
unsigned int n_alloc;
dw_die_ref c;
- dw_attr_ref d_attr, a_attr;
+ dw_attr_ref a;
+ unsigned ix;
/* Scan the DIE references, and mark as external any that refer to
DIEs from other CUs (i.e. those which are not marked). */
- for (d_attr = die->die_attr; d_attr; d_attr = d_attr->dw_attr_next)
- if (AT_class (d_attr) == dw_val_class_die_ref
- && AT_ref (d_attr)->die_mark == 0)
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (AT_class (a) == dw_val_class_die_ref
+ && AT_ref (a)->die_mark == 0)
{
- gcc_assert (AT_ref (d_attr)->die_symbol);
+ gcc_assert (AT_ref (a)->die_symbol);
- set_AT_ref_external (d_attr, 1);
+ set_AT_ref_external (a, 1);
}
for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
{
dw_die_ref abbrev = abbrev_die_table[abbrev_id];
-
- if (abbrev->die_tag == die->die_tag)
+ dw_attr_ref die_a, abbrev_a;
+ unsigned ix;
+ bool ok = true;
+
+ if (abbrev->die_tag != die->die_tag)
+ continue;
+ if ((abbrev->die_child != NULL) != (die->die_child != NULL))
+ continue;
+
+ if (VEC_length (dw_attr_node, abbrev->die_attr)
+ != VEC_length (dw_attr_node, die->die_attr))
+ continue;
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, die_a); ix++)
{
- if ((abbrev->die_child != NULL) == (die->die_child != NULL))
+ abbrev_a = VEC_index (dw_attr_node, abbrev->die_attr, ix);
+ if ((abbrev_a->dw_attr != die_a->dw_attr)
+ || (value_format (abbrev_a) != value_format (die_a)))
{
- a_attr = abbrev->die_attr;
- d_attr = die->die_attr;
-
- while (a_attr != NULL && d_attr != NULL)
- {
- if ((a_attr->dw_attr != d_attr->dw_attr)
- || (value_format (a_attr) != value_format (d_attr)))
- break;
-
- a_attr = a_attr->dw_attr_next;
- d_attr = d_attr->dw_attr_next;
- }
-
- if (a_attr == NULL && d_attr == NULL)
- break;
+ ok = false;
+ break;
}
}
+ if (ok)
+ break;
}
if (abbrev_id >= abbrev_die_table_in_use)
}
die->die_abbrev = abbrev_id;
- for (c = die->die_child; c != NULL; c = c->die_sib)
- build_abbrev_table (c);
+ FOR_EACH_CHILD (die, c, build_abbrev_table (c));
}
\f
/* Return the power-of-two number of bytes necessary to represent VALUE. */
{
unsigned long size = 0;
dw_attr_ref a;
+ unsigned ix;
size += size_of_uleb128 (die->die_abbrev);
- for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
{
switch (AT_class (a))
{
die->die_offset = next_die_offset;
next_die_offset += size_of_die (die);
- for (c = die->die_child; c != NULL; c = c->die_sib)
- calc_die_sizes (c);
+ FOR_EACH_CHILD (die, c, calc_die_sizes (c));
if (die->die_child != NULL)
/* Count the null byte used to terminate sibling lists. */
gcc_assert (!die->die_mark);
die->die_mark = 1;
- for (c = die->die_child; c; c = c->die_sib)
- mark_dies (c);
+ FOR_EACH_CHILD (die, c, mark_dies (c));
}
/* Clear the marks for a die and its children. */
gcc_assert (die->die_mark);
die->die_mark = 0;
- for (c = die->die_child; c; c = c->die_sib)
- unmark_dies (c);
+ FOR_EACH_CHILD (die, c, unmark_dies (c));
}
/* Clear the marks for a die, its children and referred dies. */
{
dw_die_ref c;
dw_attr_ref a;
+ unsigned ix;
if (!die->die_mark)
return;
die->die_mark = 0;
- for (c = die->die_child; c; c = c->die_sib)
- unmark_all_dies (c);
+ FOR_EACH_CHILD (die, c, unmark_all_dies (c));
- for (a = die->die_attr; a; a = a->dw_attr_next)
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
if (AT_class (a) == dw_val_class_die_ref)
unmark_all_dies (AT_ref (a));
}
return DW_FORM_addr;
case dw_val_class_range_list:
case dw_val_class_offset:
+ case dw_val_class_loc_list:
switch (DWARF_OFFSET_SIZE)
{
case 4:
default:
gcc_unreachable ();
}
- case dw_val_class_loc_list:
- /* FIXME: Could be DW_FORM_data8, with a > 32 bit size
- .debug_loc section */
- return DW_FORM_data4;
case dw_val_class_loc:
switch (constant_size (size_of_locs (AT_loc (a))))
{
{
unsigned long abbrev_id;
- dw_attr_ref a_attr;
-
for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
{
dw_die_ref abbrev = abbrev_die_table[abbrev_id];
+ unsigned ix;
+ dw_attr_ref a_attr;
dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
else
dw2_asm_output_data (1, DW_children_no, "DW_children_no");
- for (a_attr = abbrev->die_attr; a_attr != NULL;
- a_attr = a_attr->dw_attr_next)
+ for (ix = 0; VEC_iterate (dw_attr_node, abbrev->die_attr, ix, a_attr);
+ ix++)
{
dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
dwarf_attr_name (a_attr->dw_attr));
dw_attr_ref a;
dw_die_ref c;
unsigned long size;
+ unsigned ix;
/* If someone in another CU might refer to us, set up a symbol for
them to point to. */
dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (0x%lx) %s)",
die->die_offset, dwarf_tag_name (die->die_tag));
- for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
{
const char *name = dwarf_attr_name (a->dw_attr);
}
}
- for (c = die->die_child; c != NULL; c = c->die_sib)
- output_die (c);
+ FOR_EACH_CHILD (die, c, output_die (c));
/* Add null byte to terminate sibling list. */
if (die->die_child != NULL)
}
}
-/* The DWARF2 pubname for a nested thingy looks like "A::f". The
- output of lang_hooks.decl_printable_name for C++ looks like
- "A::f(int)". Let's drop the argument list, and maybe the scope. */
+/* Return the DWARF2/3 pubname associated with a decl. */
static const char *
dwarf2_name (tree decl, int scope)
{
- return lang_hooks.decl_printable_name (decl, scope ? 1 : 0);
+ return lang_hooks.dwarf_name (decl, scope ? 1 : 0);
}
/* Add a new entry to .debug_pubnames if appropriate. */
gcc_assert (regno < FIRST_PSEUDO_REGISTER);
#ifdef LEAF_REG_REMAP
- regno = LEAF_REG_REMAP (regno);
+ {
+ int leaf_reg;
+
+ leaf_reg = LEAF_REG_REMAP (regno);
+ if (leaf_reg != -1)
+ regno = (unsigned) leaf_reg;
+ }
#endif
return DBX_REGISTER_NUMBER (regno);
reg = REGNO (rtl);
#ifdef LEAF_REG_REMAP
- reg = LEAF_REG_REMAP (reg);
+ {
+ int leaf_reg;
+
+ leaf_reg = LEAF_REG_REMAP (reg);
+ if (leaf_reg != -1)
+ reg = (unsigned) leaf_reg;
+ }
#endif
gcc_assert ((unsigned) DBX_REGISTER_NUMBER (reg) == dbx_reg_number (rtl));
nregs = hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)];
current_function_decl = save_fn;
}
+/* Helper function of premark_used_types() which gets called through
+ htab_traverse_resize().
+
+ Marks the DIE of a given type in *SLOT as perennial, so it never gets
+ marked as unused by prune_unused_types. */
+static int
+premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED)
+{
+ tree type;
+ dw_die_ref die;
+
+ type = *slot;
+ die = lookup_type_die (type);
+ if (die != NULL)
+ die->die_perennial_p = 1;
+ return 1;
+}
+
+/* Mark all members of used_types_hash as perennial. */
+static void
+premark_used_types (void)
+{
+ if (cfun && cfun->used_types_hash)
+ htab_traverse (cfun->used_types_hash, premark_used_types_helper, NULL);
+}
+
/* Generate a DIE to represent a declared function (either file-scope or
block-local). */
int declaration = (current_function_decl != decl
|| class_or_namespace_scope_p (context_die));
+ premark_used_types();
+
/* It is possible to have both DECL_ABSTRACT and DECLARATION be true if we
started to generate the abstract instance of an inline, decided to output
its containing class, and proceeded to emit the declaration of the inline
return 1;
}
+#if ENABLE_ASSERT_CHECKING
+/* Verify that all marks are clear. */
+static void
+verify_marks_clear (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ gcc_assert (! die->die_mark);
+ FOR_EACH_CHILD (die, c, verify_marks_clear (c));
+}
+#endif /* ENABLE_ASSERT_CHECKING */
/* Clear the marks for a die and its children.
Be cool if the mark isn't set. */
prune_unmark_dies (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);
+
+ if (die->die_mark)
+ die->die_mark = 0;
+ FOR_EACH_CHILD (die, c, 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. */
prune_unused_types_walk_attribs (dw_die_ref die)
{
dw_attr_ref a;
+ unsigned ix;
- for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
{
if (a->dw_attr_val.val_class == dw_val_class_die_ref)
{
a->dw_attr_val.v.val_unsigned =
maybe_emit_file (a->dw_attr_val.v.val_unsigned);
}
+ /* Set the string's refcount to 0 so that prune_unused_types_mark
+ accounts properly for it. */
+ if (AT_class (a) == dw_val_class_str)
+ a->dw_attr_val.v.val_str->refcount = 0;
}
}
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);
- }
+ /* 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)
+ FOR_EACH_CHILD (die, c, prune_unused_types_mark (c, 1));
+ else
+ FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
}
}
case DW_TAG_subrange_type:
case DW_TAG_ptr_to_member_type:
case DW_TAG_file_type:
+ if (die->die_perennial_p)
+ break;
+
/* It's a type node --- don't mark it. */
return;
prune_unused_types_walk_attribs (die);
/* Mark children. */
- for (c = die->die_child; c; c = c->die_sib)
- prune_unused_types_walk (c);
+ FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
}
+/* Increment the string counts on strings referred to from DIE's
+ attributes. */
+
+static void
+prune_unused_types_update_strings (dw_die_ref die)
+{
+ dw_attr_ref a;
+ unsigned ix;
+
+ for (ix = 0; VEC_iterate (dw_attr_node, die->die_attr, ix, a); ix++)
+ if (AT_class (a) == dw_val_class_str)
+ {
+ struct indirect_string_node *s = a->dw_attr_val.v.val_str;
+ s->refcount++;
+ /* Avoid unnecessarily putting strings that are used less than
+ twice in the hash table. */
+ if (s->refcount
+ == ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) ? 1 : 2))
+ {
+ void ** slot;
+ slot = htab_find_slot_with_hash (debug_str_hash, s->str,
+ htab_hash_string (s->str),
+ INSERT);
+ gcc_assert (*slot == NULL);
+ *slot = s;
+ }
+ }
+}
/* Remove from the tree DIE any dies that aren't marked. */
static void
prune_unused_types_prune (dw_die_ref die)
{
- dw_die_ref c, p, n;
+ dw_die_ref c;
gcc_assert (die->die_mark);
- 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 (! die->die_child)
+ return;
+
+ c = die->die_child;
+ do {
+ dw_die_ref prev = c;
+ for (c = c->die_sib; ! c->die_mark; c = c->die_sib)
+ if (c == die->die_child)
{
- if (p)
- p->die_sib = n;
+ /* No marked children between 'prev' and the end of the list. */
+ if (prev == c)
+ /* No marked children at all. */
+ die->die_child = NULL;
else
- die->die_child = n;
- free_die (c);
+ {
+ prev->die_sib = c->die_sib;
+ die->die_child = prev;
+ }
+ return;
}
- }
+
+ if (c != prev->die_sib)
+ prev->die_sib = c;
+ prune_unused_types_update_strings (c);
+ prune_unused_types_prune (c);
+ } while (c != die->die_child);
}
unsigned int i;
limbo_die_node *node;
- /* Clear all the marks. */
- prune_unmark_dies (comp_unit_die);
+#if ENABLE_ASSERT_CHECKING
+ /* All the marks should already be clear. */
+ verify_marks_clear (comp_unit_die);
for (node = limbo_die_list; node; node = node->next)
- prune_unmark_dies (node->die);
+ verify_marks_clear (node->die);
+#endif /* ENABLE_ASSERT_CHECKING */
/* Set the mark on nodes that are actually used. */
prune_unused_types_walk (comp_unit_die);
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. */
+ /* Get rid of nodes that aren't marked; and update the string counts. */
+ if (debug_str_hash)
+ htab_empty (debug_str_hash);
prune_unused_types_prune (comp_unit_die);
for (node = limbo_die_list; node; node = node->next)
prune_unused_types_prune (node->die);
emit full debugging info for them. */
retry_incomplete_types ();
- /* We need to reverse all the dies before break_out_includes, or
- we'll see the end of an include file before the beginning. */
- reverse_all_dies (comp_unit_die);
-
if (flag_eliminate_unused_debug_types)
prune_unused_types ();