+/* Helper function for resolve_addr, mark DW_TAG_base_type nodes
+ referenced from typed stack ops and count how often they are used. */
+
+static void
+mark_base_types (dw_loc_descr_ref loc)
+{
+ dw_die_ref base_type = NULL;
+
+ for (; loc; loc = loc->dw_loc_next)
+ {
+ switch (loc->dw_loc_opc)
+ {
+ case DW_OP_GNU_regval_type:
+ case DW_OP_GNU_deref_type:
+ base_type = loc->dw_loc_oprnd2.v.val_die_ref.die;
+ break;
+ case DW_OP_GNU_const_type:
+ case DW_OP_GNU_convert:
+ case DW_OP_GNU_reinterpret:
+ base_type = loc->dw_loc_oprnd1.v.val_die_ref.die;
+ break;
+ case DW_OP_GNU_entry_value:
+ mark_base_types (loc->dw_loc_oprnd1.v.val_loc);
+ continue;
+ default:
+ continue;
+ }
+ gcc_assert (base_type->die_parent == comp_unit_die ());
+ if (base_type->die_mark)
+ base_type->die_mark++;
+ else
+ {
+ VEC_safe_push (dw_die_ref, heap, base_types, base_type);
+ base_type->die_mark = 1;
+ }
+ }
+}
+
+/* Comparison function for sorting marked base types. */
+
+static int
+base_type_cmp (const void *x, const void *y)
+{
+ dw_die_ref dx = *(const dw_die_ref *) x;
+ dw_die_ref dy = *(const dw_die_ref *) y;
+ unsigned int byte_size1, byte_size2;
+ unsigned int encoding1, encoding2;
+ if (dx->die_mark > dy->die_mark)
+ return -1;
+ if (dx->die_mark < dy->die_mark)
+ return 1;
+ byte_size1 = get_AT_unsigned (dx, DW_AT_byte_size);
+ byte_size2 = get_AT_unsigned (dy, DW_AT_byte_size);
+ if (byte_size1 < byte_size2)
+ return 1;
+ if (byte_size1 > byte_size2)
+ return -1;
+ encoding1 = get_AT_unsigned (dx, DW_AT_encoding);
+ encoding2 = get_AT_unsigned (dy, DW_AT_encoding);
+ if (encoding1 < encoding2)
+ return 1;
+ if (encoding1 > encoding2)
+ return -1;
+ return 0;
+}
+
+/* Move base types marked by mark_base_types as early as possible
+ in the CU, sorted by decreasing usage count both to make the
+ uleb128 references as small as possible and to make sure they
+ will have die_offset already computed by calc_die_sizes when
+ sizes of typed stack loc ops is computed. */
+
+static void
+move_marked_base_types (void)
+{
+ unsigned int i;
+ dw_die_ref base_type, die, c;
+
+ if (VEC_empty (dw_die_ref, base_types))
+ return;
+
+ /* Sort by decreasing usage count, they will be added again in that
+ order later on. */
+ VEC_qsort (dw_die_ref, base_types, base_type_cmp);
+ die = comp_unit_die ();
+ c = die->die_child;
+ do
+ {
+ dw_die_ref prev = c;
+ c = c->die_sib;
+ while (c->die_mark)
+ {
+ remove_child_with_prev (c, prev);
+ /* As base types got marked, there must be at least
+ one node other than DW_TAG_base_type. */
+ gcc_assert (c != c->die_sib);
+ c = c->die_sib;
+ }
+ }
+ while (c != die->die_child);
+ gcc_assert (die->die_child);
+ c = die->die_child;
+ for (i = 0; VEC_iterate (dw_die_ref, base_types, i, base_type); i++)
+ {
+ base_type->die_mark = 0;
+ base_type->die_sib = c->die_sib;
+ c->die_sib = base_type;
+ c = base_type;
+ }
+}
+