@@ -153,7 +153,10 @@ enum dw_val_class
dw_val_class_vms_delta,
dw_val_class_high_pc,
dw_val_class_discr_value,
- dw_val_class_discr_list
+ dw_val_class_discr_list,
+ dw_val_class_const_implicit,
+ dw_val_class_unsigned_const_implicit,
+ dw_val_class_file_implicit
};
/* Describe a floating point constant value, or a vector constant value. */
@@ -198,7 +201,8 @@ struct GTY(()) dw_val_node {
dw_loc_list_ref GTY ((tag ("dw_val_class_loc_list"))) val_loc_list;
dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc;
HOST_WIDE_INT GTY ((default)) val_int;
- unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
+ unsigned HOST_WIDE_INT
+ GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
double_int GTY ((tag ("dw_val_class_const_double"))) val_double;
wide_int_ptr GTY ((tag ("dw_val_class_wide_int"))) val_wide;
dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
@@ -212,6 +216,8 @@ struct GTY(()) dw_val_node {
char * GTY ((tag ("dw_val_class_lbl_id"))) val_lbl_id;
unsigned char GTY ((tag ("dw_val_class_flag"))) val_flag;
struct dwarf_file_data * GTY ((tag ("dw_val_class_file"))) val_file;
+ struct dwarf_file_data *
+ GTY ((tag ("dw_val_class_file_implicit"))) val_file_implicit;
unsigned char GTY ((tag ("dw_val_class_data8"))) val_data8[8];
tree GTY ((tag ("dw_val_class_decl_ref"))) val_decl_ref;
struct dw_val_vms_delta_union
@@ -1363,6 +1363,8 @@ dw_val_equal_p (dw_val_node *a, dw_val_n
case dw_val_class_offset:
case dw_val_class_unsigned_const:
case dw_val_class_const:
+ case dw_val_class_unsigned_const_implicit:
+ case dw_val_class_const_implicit:
case dw_val_class_range_list:
case dw_val_class_lineptr:
case dw_val_class_macptr:
@@ -1385,6 +1387,7 @@ dw_val_equal_p (dw_val_node *a, dw_val_n
case dw_val_class_flag:
return a->v.val_flag == b->v.val_flag;
case dw_val_class_file:
+ case dw_val_class_file_implicit:
return a->v.val_file == b->v.val_file;
case dw_val_class_decl_ref:
return a->v.val_decl_ref == b->v.val_decl_ref;
@@ -3006,17 +3009,9 @@ struct dw_loc_list_hasher : ggc_ptr_hash
/* Table of cached location lists. */
static GTY (()) hash_table<dw_loc_list_hasher> *cached_dw_loc_list_table;
-/* A pointer to the base of a list of references to DIE's that
- are uniquely identified by their tag, presence/absence of
- children DIE's, and list of attribute/value pairs. */
-static GTY((length ("abbrev_die_table_allocated")))
- dw_die_ref *abbrev_die_table;
-
-/* Number of elements currently allocated for abbrev_die_table. */
-static GTY(()) unsigned abbrev_die_table_allocated;
-
-/* Number of elements in abbrev_die_table currently in use. */
-static GTY(()) unsigned abbrev_die_table_in_use;
+/* A vector of references to DIE's that are uniquely identified by their tag,
+ presence/absence of children DIE's, and list of attribute/value pairs. */
+static GTY(()) vec<dw_die_ref, va_gc> *abbrev_die_table;
/* A hash map to remember the stack usage for DWARF procedures. The value
stored is the stack size difference between before the DWARF procedure
@@ -3024,10 +3019,6 @@ static GTY(()) unsigned abbrev_die_table
that consumes N stack slots and that pushes M ones, this stores M - N. */
static hash_map<dw_die_ref, int> *dwarf_proc_stack_usage_map;
-/* Size (in elements) of increments by which we may expand the
- abbrev_die_table. */
-#define ABBREV_DIE_TABLE_INCREMENT 256
-
/* A global counter for generating labels for line number data. */
static unsigned int line_info_label_num;
@@ -3922,7 +3913,8 @@ add_AT_int (dw_die_ref die, enum dwarf_a
static inline HOST_WIDE_INT
AT_int (dw_attr_node *a)
{
- gcc_assert (a && AT_class (a) == dw_val_class_const);
+ gcc_assert (a && (AT_class (a) == dw_val_class_const
+ || AT_class (a) == dw_val_class_const_implicit));
return a->dw_attr_val.v.val_int;
}
@@ -3944,7 +3936,8 @@ add_AT_unsigned (dw_die_ref die, enum dw
static inline unsigned HOST_WIDE_INT
AT_unsigned (dw_attr_node *a)
{
- gcc_assert (a && AT_class (a) == dw_val_class_unsigned_const);
+ gcc_assert (a && (AT_class (a) == dw_val_class_unsigned_const
+ || AT_class (a) == dw_val_class_unsigned_const_implicit));
return a->dw_attr_val.v.val_unsigned;
}
@@ -4523,7 +4516,8 @@ add_AT_file (dw_die_ref die, enum dwarf_
static inline struct dwarf_file_data *
AT_file (dw_attr_node *a)
{
- gcc_assert (a && AT_class (a) == dw_val_class_file);
+ gcc_assert (a && (AT_class (a) == dw_val_class_file
+ || AT_class (a) == dw_val_class_file_implicit));
return a->dw_attr_val.v.val_file;
}
@@ -5598,9 +5592,11 @@ print_dw_val (dw_val_node *val, bool rec
fprintf (outfile, "range list");
break;
case dw_val_class_const:
+ case dw_val_class_const_implicit:
fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, val->v.val_int);
break;
case dw_val_class_unsigned_const:
+ case dw_val_class_unsigned_const_implicit:
fprintf (outfile, HOST_WIDE_INT_PRINT_UNSIGNED, val->v.val_unsigned);
break;
case dw_val_class_const_double:
@@ -5667,6 +5663,7 @@ print_dw_val (dw_val_node *val, bool rec
fprintf (outfile, "<null>");
break;
case dw_val_class_file:
+ case dw_val_class_file_implicit:
fprintf (outfile, "\"%s\" (%d)", val->v.val_file->filename,
val->v.val_file->emitted_number);
break;
@@ -5996,9 +5993,11 @@ attr_checksum (dw_attr_node *at, struct
switch (AT_class (at))
{
case dw_val_class_const:
+ case dw_val_class_const_implicit:
CHECKSUM (at->dw_attr_val.v.val_int);
break;
case dw_val_class_unsigned_const:
+ case dw_val_class_unsigned_const_implicit:
CHECKSUM (at->dw_attr_val.v.val_unsigned);
break;
case dw_val_class_const_double:
@@ -6049,6 +6048,7 @@ attr_checksum (dw_attr_node *at, struct
break;
case dw_val_class_file:
+ case dw_val_class_file_implicit:
CHECKSUM_STRING (AT_file (at)->filename);
break;
@@ -6273,11 +6273,13 @@ attr_checksum_ordered (enum dwarf_tag ta
switch (AT_class (at))
{
case dw_val_class_const:
+ case dw_val_class_const_implicit:
CHECKSUM_ULEB128 (DW_FORM_sdata);
CHECKSUM_SLEB128 (at->dw_attr_val.v.val_int);
break;
case dw_val_class_unsigned_const:
+ case dw_val_class_unsigned_const_implicit:
CHECKSUM_ULEB128 (DW_FORM_sdata);
CHECKSUM_SLEB128 ((int) at->dw_attr_val.v.val_unsigned);
break;
@@ -6341,6 +6343,7 @@ attr_checksum_ordered (enum dwarf_tag ta
break;
case dw_val_class_file:
+ case dw_val_class_file_implicit:
CHECKSUM_ULEB128 (DW_FORM_string);
CHECKSUM_STRING (AT_file (at)->filename);
break;
@@ -6783,8 +6786,10 @@ same_dw_val_p (const dw_val_node *v1, co
switch (v1->val_class)
{
case dw_val_class_const:
+ case dw_val_class_const_implicit:
return v1->v.val_int == v2->v.val_int;
case dw_val_class_unsigned_const:
+ case dw_val_class_unsigned_const_implicit:
return v1->v.val_unsigned == v2->v.val_unsigned;
case dw_val_class_const_double:
return v1->v.val_double.high == v2->v.val_double.high
@@ -6834,6 +6839,7 @@ same_dw_val_p (const dw_val_node *v1, co
return 1;
case dw_val_class_file:
+ case dw_val_class_file_implicit:
return v1->v.val_file == v2->v.val_file;
case dw_val_class_data8:
@@ -8269,6 +8275,16 @@ optimize_external_refs (dw_die_ref die)
return map;
}
+/* First abbrev_id that can be optimized based on usage. */
+static unsigned int abbrev_opt_start;
+
+/* Vector of usage counts during build_abbrev_table. Indexed by
+ abbrev_id - abbrev_opt_start. */
+static vec<unsigned int> abbrev_usage_count;
+
+/* Vector of all DIEs added with die_abbrev >= abbrev_opt_start. */
+static vec<dw_die_ref> abbrev_dies;
+
/* The format of each DIE (and its attribute value pairs) is encoded in an
abbreviation table. This routine builds the abbreviation table and assigns
a unique abbreviation id for each abbreviation entry. The children of each
@@ -8277,11 +8293,11 @@ optimize_external_refs (dw_die_ref die)
static void
build_abbrev_table (dw_die_ref die, external_ref_hash_type *extern_map)
{
- unsigned long abbrev_id;
- unsigned int n_alloc;
+ unsigned int abbrev_id = 0;
dw_die_ref c;
dw_attr_node *a;
unsigned ix;
+ dw_die_ref abbrev;
/* Scan the DIE references, and replace any that refer to
DIEs from other CUs (i.e. those which are not marked) with
@@ -8301,13 +8317,14 @@ build_abbrev_table (dw_die_ref die, exte
set_AT_ref_external (a, 1);
}
- for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
+ FOR_EACH_VEC_SAFE_ELT (abbrev_die_table, abbrev_id, abbrev)
{
- dw_die_ref abbrev = abbrev_die_table[abbrev_id];
dw_attr_node *die_a, *abbrev_a;
unsigned ix;
bool ok = true;
+ if (abbrev_id == 0)
+ continue;
if (abbrev->die_tag != die->die_tag)
continue;
if ((abbrev->die_child != NULL) != (die->die_child != NULL))
@@ -8330,26 +8347,178 @@ build_abbrev_table (dw_die_ref die, exte
break;
}
- if (abbrev_id >= abbrev_die_table_in_use)
+ if (abbrev_id >= vec_safe_length (abbrev_die_table))
{
- if (abbrev_die_table_in_use >= abbrev_die_table_allocated)
- {
- n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT;
- abbrev_die_table = GGC_RESIZEVEC (dw_die_ref, abbrev_die_table,
- n_alloc);
-
- memset (&abbrev_die_table[abbrev_die_table_allocated], 0,
- (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref));
- abbrev_die_table_allocated = n_alloc;
- }
-
- ++abbrev_die_table_in_use;
- abbrev_die_table[abbrev_id] = die;
+ vec_safe_push (abbrev_die_table, die);
+ if (abbrev_opt_start)
+ abbrev_usage_count.safe_push (0);
+ }
+ if (abbrev_opt_start && abbrev_id >= abbrev_opt_start)
+ {
+ abbrev_usage_count[abbrev_id - abbrev_opt_start]++;
+ abbrev_dies.safe_push (die);
}
die->die_abbrev = abbrev_id;
FOR_EACH_CHILD (die, c, build_abbrev_table (c, extern_map));
}
+
+/* Callback function for abbrev_dies vector sorting. We sort
+ by die_abbrev's usage count, from the most commonly used
+ abbreviation to the least. */
+
+static int
+die_abbrev_cmp (const void *p1, const void *p2)
+{
+ dw_die_ref die1 = *(const dw_die_ref *) p1;
+ dw_die_ref die2 = *(const dw_die_ref *) p2;
+
+ gcc_checking_assert (die1->die_abbrev >= abbrev_opt_start);
+ gcc_checking_assert (die2->die_abbrev >= abbrev_opt_start);
+
+ if (abbrev_usage_count[die1->die_abbrev - abbrev_opt_start]
+ > abbrev_usage_count[die2->die_abbrev - abbrev_opt_start])
+ return -1;
+ if (abbrev_usage_count[die1->die_abbrev - abbrev_opt_start]
+ < abbrev_usage_count[die2->die_abbrev - abbrev_opt_start])
+ return 1;
+
+ /* Stabilize the sort. */
+ if (die1->die_abbrev < die2->die_abbrev)
+ return -1;
+ if (die1->die_abbrev > die2->die_abbrev)
+ return 1;
+
+ return 0;
+}
+
+/* Convert dw_val_class_const and dw_val_class_unsigned_const class attributes
+ of DIEs in between abbrev_dies[first_id] and abbrev_dies[end_id - 1] into
+ dw_val_class_const_implicit or dw_val_class_unsigned_const_implicit. */
+
+static void
+optimize_implicit_const (unsigned int first_id, unsigned int end,
+ vec<bool> &implicit_consts)
+{
+ /* It never makes sense if there is just one DIE using the abbreviation. */
+ if (end < first_id + 2)
+ return;
+
+ dw_attr_node *a;
+ unsigned ix, i;
+ dw_die_ref die = abbrev_dies[first_id];
+ FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+ if (implicit_consts[ix])
+ {
+ enum dw_val_class new_class = dw_val_class_none;
+ switch (AT_class (a))
+ {
+ case dw_val_class_unsigned_const:
+ if ((HOST_WIDE_INT) AT_unsigned (a) < 0)
+ continue;
+
+ /* The .debug_abbrev section will grow by
+ size_of_sleb128 (AT_unsigned (a)) and we avoid the constants
+ in all the DIEs using that abbreviation. */
+ if (constant_size (AT_unsigned (a)) * (end - first_id)
+ <= (unsigned) size_of_sleb128 (AT_unsigned (a)))
+ continue;
+
+ new_class = dw_val_class_unsigned_const_implicit;
+ break;
+
+ case dw_val_class_const:
+ new_class = dw_val_class_const_implicit;
+ break;
+
+ case dw_val_class_file:
+ new_class = dw_val_class_file_implicit;
+ break;
+
+ default:
+ continue;
+ }
+ for (i = first_id; i < end; i++)
+ (*abbrev_dies[i]->die_attr)[ix].dw_attr_val.val_class = new_class;
+ }
+}
+
+/* Attempt to optimize abbreviation table from abbrev_opt_start
+ abbreviation above. */
+
+static void
+optimize_abbrev_table (void)
+{
+ if (abbrev_opt_start
+ && vec_safe_length (abbrev_die_table) > abbrev_opt_start
+ && (dwarf_version >= 5 || vec_safe_length (abbrev_die_table) > 127))
+ {
+ auto_vec<bool, 32> implicit_consts;
+ abbrev_dies.qsort (die_abbrev_cmp);
+
+ unsigned int abbrev_id = abbrev_opt_start - 1;
+ unsigned int first_id = 0;
+ unsigned int last_abbrev_id = 0;
+ unsigned int i;
+ dw_die_ref die;
+ /* Reassign abbreviation ids from abbrev_opt_start above, so that
+ most commonly used abbreviations come first. */
+ FOR_EACH_VEC_ELT (abbrev_dies, i, die)
+ {
+ dw_attr_node *a;
+ unsigned ix;
+
+ if (die->die_abbrev != last_abbrev_id)
+ {
+ last_abbrev_id = die->die_abbrev;
+ if (dwarf_version >= 5 && i)
+ optimize_implicit_const (first_id, i, implicit_consts);
+ abbrev_id++;
+ (*abbrev_die_table)[abbrev_id] = die;
+ if (dwarf_version >= 5)
+ {
+ first_id = i;
+ implicit_consts.truncate (0);
+
+ FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+ switch (AT_class (a))
+ {
+ case dw_val_class_const:
+ case dw_val_class_unsigned_const:
+ case dw_val_class_file:
+ implicit_consts.safe_push (true);
+ break;
+ default:
+ implicit_consts.safe_push (false);
+ break;
+ }
+ }
+ }
+ else if (dwarf_version >= 5)
+ {
+ FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+ if (!implicit_consts[ix])
+ continue;
+ else
+ {
+ dw_attr_node *other_a
+ = &(*(*abbrev_die_table)[abbrev_id]->die_attr)[ix];
+ if (!dw_val_equal_p (&a->dw_attr_val,
+ &other_a->dw_attr_val))
+ implicit_consts[ix] = false;
+ }
+ }
+ die->die_abbrev = abbrev_id;
+ }
+ gcc_assert (abbrev_id == vec_safe_length (abbrev_die_table) - 1);
+ if (dwarf_version >= 5)
+ optimize_implicit_const (first_id, i, implicit_consts);
+ }
+
+ abbrev_opt_start = 0;
+ abbrev_usage_count.release ();
+ abbrev_dies.release ();
+}
/* Return the power-of-two number of bytes necessary to represent VALUE. */
@@ -8435,6 +8604,12 @@ size_of_die (dw_die_ref die)
size += csize;
}
break;
+ case dw_val_class_const_implicit:
+ case dw_val_class_unsigned_const_implicit:
+ case dw_val_class_file_implicit:
+ /* These occupy no size in the DIE, just an extra sleb128 in
+ .debug_abbrev. */
+ break;
case dw_val_class_const_double:
size += HOST_BITS_PER_DOUBLE_INT / HOST_BITS_PER_CHAR;
if (HOST_BITS_PER_WIDE_INT >= 64)
@@ -8815,6 +8990,10 @@ value_format (dw_attr_node *a)
default:
gcc_unreachable ();
}
+ case dw_val_class_const_implicit:
+ case dw_val_class_unsigned_const_implicit:
+ case dw_val_class_file_implicit:
+ return DW_FORM_implicit_const;
case dw_val_class_const_double:
switch (HOST_BITS_PER_WIDE_INT)
{
@@ -8968,6 +9147,17 @@ output_die_abbrevs (unsigned long abbrev
dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
dwarf_attr_name (a_attr->dw_attr));
output_value_format (a_attr);
+ if (value_format (a_attr) == DW_FORM_implicit_const)
+ {
+ if (AT_class (a_attr) == dw_val_class_file_implicit)
+ {
+ int f = maybe_emit_file (a_attr->dw_attr_val.v.val_file);
+ const char *filename = a_attr->dw_attr_val.v.val_file->filename;
+ dw2_asm_output_data_sleb128 (f, "(%s)", filename);
+ }
+ else
+ dw2_asm_output_data_sleb128 (a_attr->dw_attr_val.v.val_int, NULL);
+ }
}
dw2_asm_output_data (1, 0, NULL);
@@ -8981,10 +9171,12 @@ output_die_abbrevs (unsigned long abbrev
static void
output_abbrev_section (void)
{
- unsigned long abbrev_id;
+ unsigned int abbrev_id;
+ dw_die_ref abbrev;
- for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
- output_die_abbrevs (abbrev_id, abbrev_die_table[abbrev_id]);
+ FOR_EACH_VEC_SAFE_ELT (abbrev_die_table, abbrev_id, abbrev)
+ if (abbrev_id != 0)
+ output_die_abbrevs (abbrev_id, abbrev);
/* Terminate the table. */
dw2_asm_output_data (1, 0, NULL);
@@ -9281,6 +9473,20 @@ output_die (dw_die_ref die)
}
break;
+ case dw_val_class_const_implicit:
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t\t\t%s %s ("
+ HOST_WIDE_INT_PRINT_DEC ")\n",
+ ASM_COMMENT_START, name, AT_int (a));
+ break;
+
+ case dw_val_class_unsigned_const_implicit:
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t\t\t%s %s ("
+ HOST_WIDE_INT_PRINT_HEX ")\n",
+ ASM_COMMENT_START, name, AT_unsigned (a));
+ break;
+
case dw_val_class_const_double:
{
unsigned HOST_WIDE_INT first, second;
@@ -9474,6 +9680,14 @@ output_die (dw_die_ref die)
break;
}
+ case dw_val_class_file_implicit:
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t\t\t%s %s (%d, %s)\n",
+ ASM_COMMENT_START, name,
+ maybe_emit_file (a->dw_attr_val.v.val_file),
+ a->dw_attr_val.v.val_file->filename);
+ break;
+
case dw_val_class_data8:
{
int i;
@@ -9581,8 +9795,16 @@ output_comp_unit (dw_die_ref die, int ou
external_ref_hash_type *extern_map = optimize_external_refs (die);
+ /* For now, optimize only the main CU, in order to optimize the rest
+ we'd need to see all of them earlier. Leave the rest for post-linking
+ tools like DWZ. */
+ if (die == comp_unit_die ())
+ abbrev_opt_start = vec_safe_length (abbrev_die_table);
+
build_abbrev_table (die, extern_map);
+ optimize_abbrev_table ();
+
delete extern_map;
/* Initialize the beginning DIE offset - and calculate sizes/offsets. */
@@ -25738,11 +25960,9 @@ dwarf2out_init (const char *filename ATT
vec_alloc (decl_scope_table, 256);
/* Allocate the initial hunk of the abbrev_die_table. */
- abbrev_die_table = ggc_cleared_vec_alloc<dw_die_ref>
- (ABBREV_DIE_TABLE_INCREMENT);
- abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
+ vec_alloc (abbrev_die_table, 256);
/* Zero-th entry is allocated, but unused. */
- abbrev_die_table_in_use = 1;
+ abbrev_die_table->quick_push (NULL);
/* Allocate the dwarf_proc_stack_usage_map. */
dwarf_proc_stack_usage_map = new hash_map<dw_die_ref, int>;
@@ -28142,7 +28362,7 @@ dwarf2out_finish (const char *)
output_skeleton_debug_sections (main_comp_unit_die);
/* Output the abbreviation table. */
- if (abbrev_die_table_in_use != 1)
+ if (vec_safe_length (abbrev_die_table) != 1)
{
switch_to_section (debug_abbrev_section);
ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
@@ -28373,8 +28593,6 @@ dwarf2out_c_finalize (void)
tail_call_site_count = -1;
cached_dw_loc_list_table = NULL;
abbrev_die_table = NULL;
- abbrev_die_table_allocated = 0;
- abbrev_die_table_in_use = 0;
delete dwarf_proc_stack_usage_map;
dwarf_proc_stack_usage_map = NULL;
line_info_label_num = 0;