struct vlr_context *);
static void add_bit_size_attribute (dw_die_ref, tree);
static void add_prototyped_attribute (dw_die_ref, tree);
-static dw_die_ref add_abstract_origin_attribute (dw_die_ref, tree);
+static void add_abstract_origin_attribute (dw_die_ref, tree);
static void add_pure_or_virtual_attribute (dw_die_ref, tree);
static void add_src_coords_attributes (dw_die_ref, tree);
static void add_name_and_src_coords_attributes (dw_die_ref, tree, bool = false);
TYPE_SYMTAB_DIE (type) = type_die;
}
+static dw_die_ref maybe_create_die_with_external_ref (tree);
+struct GTY(()) sym_off_pair
+{
+ const char * GTY((skip)) sym;
+ unsigned HOST_WIDE_INT off;
+};
+static GTY(()) hash_map<tree, sym_off_pair> *external_die_map;
+
/* Returns a hash value for X (which really is a die_struct). */
inline hashval_t
dw_die_ref *die = decl_die_table->find_slot_with_hash (decl, DECL_UID (decl),
NO_INSERT);
if (!die)
- return NULL;
+ {
+ if (in_lto_p)
+ return maybe_create_die_with_external_ref (decl);
+ return NULL;
+ }
if ((*die)->removed)
{
decl_die_table->clear_slot (die);
}
+/* Return the DIE associated with BLOCK. */
+
+static inline dw_die_ref
+lookup_block_die (tree block)
+{
+ dw_die_ref die = BLOCK_DIE (block);
+ if (!die && in_lto_p)
+ return maybe_create_die_with_external_ref (block);
+ return die;
+}
+
+/* Associate DIE with BLOCK. */
+
+static inline void
+equate_block_to_die (tree block, dw_die_ref die)
+{
+ BLOCK_DIE (block) = die;
+}
+#undef BLOCK_DIE
+
+
/* For DECL which might have early dwarf output query a SYMBOL + OFFSET
style reference. Return true if we found one refering to a DIE for
DECL, otherwise return false. */
{
dw_die_ref die;
- if (in_lto_p && !decl_die_table)
- return false;
+ if (in_lto_p)
+ {
+ /* During WPA stage and incremental linking we use a hash-map
+ to store the decl <-> label + offset map. */
+ if (!external_die_map)
+ return false;
+ sym_off_pair *desc = external_die_map->get (decl);
+ if (!desc)
+ return false;
+ *sym = desc->sym;
+ *off = desc->off;
+ return true;
+ }
if (TREE_CODE (decl) == BLOCK)
- die = BLOCK_DIE (decl);
+ die = lookup_block_die (decl);
else
die = lookup_decl_die (decl);
if (!die)
return false;
- /* During WPA stage and incremental linking we currently use DIEs
- to store the decl <-> label + offset map. That's quite inefficient
- but it works for now. */
- if (in_lto_p)
- {
- dw_die_ref ref = get_AT_ref (die, DW_AT_abstract_origin);
- if (!ref)
- {
- gcc_assert (die == comp_unit_die ());
- return false;
- }
- *off = ref->die_offset;
- *sym = ref->die_id.die_symbol;
- return true;
- }
-
/* Similar to get_ref_die_offset_label, but using the "correct"
label. */
*off = die->die_offset;
{
/* Create a fake DIE that contains the reference. Don't use
new_die because we don't want to end up in the limbo list. */
+ /* ??? We probably want to share these, thus put a ref to the DIE
+ we create here to the external_die_map entry. */
dw_die_ref ref = new_die_raw (die->die_tag);
ref->die_id.die_symbol = IDENTIFIER_POINTER (get_identifier (symbol));
ref->die_offset = offset;
if (debug_info_level == DINFO_LEVEL_NONE)
return;
- if ((flag_wpa
- || flag_incremental_link == INCREMENTAL_LINK_LTO) && !decl_die_table)
- decl_die_table = hash_table<decl_die_hasher>::create_ggc (1000);
+ if (!external_die_map)
+ external_die_map = hash_map<tree, sym_off_pair>::create_ggc (1000);
+ gcc_checking_assert (!external_die_map->get (decl));
+ sym_off_pair p = { IDENTIFIER_POINTER (get_identifier (sym)), off };
+ external_die_map->put (decl, p);
+}
+
+/* If we have a registered external DIE for DECL return a new DIE for
+ the concrete instance with an appropriate abstract origin. */
+
+static dw_die_ref
+maybe_create_die_with_external_ref (tree decl)
+{
+ if (!external_die_map)
+ return NULL;
+ sym_off_pair *desc = external_die_map->get (decl);
+ if (!desc)
+ return NULL;
+
+ const char *sym = desc->sym;
+ unsigned HOST_WIDE_INT off = desc->off;
- dw_die_ref die
- = TREE_CODE (decl) == BLOCK ? BLOCK_DIE (decl) : lookup_decl_die (decl);
+ in_lto_p = false;
+ dw_die_ref die = (TREE_CODE (decl) == BLOCK
+ ? lookup_block_die (decl) : lookup_decl_die (decl));
gcc_assert (!die);
+ in_lto_p = true;
tree ctx;
dw_die_ref parent = NULL;
/* ??? We do not output DIEs for all scopes thus skip as
many DIEs as needed. */
while (TREE_CODE (ctx) == BLOCK
- && !BLOCK_DIE (ctx))
+ && !lookup_block_die (ctx))
ctx = BLOCK_SUPERCONTEXT (ctx);
}
else
if (ctx)
{
if (TREE_CODE (ctx) == BLOCK)
- parent = BLOCK_DIE (ctx);
+ parent = lookup_block_die (ctx);
else if (TREE_CODE (ctx) == TRANSLATION_UNIT_DECL
/* Keep the 1:1 association during WPA. */
&& !flag_wpa
switch (TREE_CODE (decl))
{
case TRANSLATION_UNIT_DECL:
- if (! flag_wpa && flag_incremental_link != INCREMENTAL_LINK_LTO)
- {
- die = comp_unit_die ();
- dw_die_ref import = new_die (DW_TAG_imported_unit, die, NULL_TREE);
- add_AT_external_die_ref (import, DW_AT_import, sym, off);
- /* We re-target all CU decls to the LTRANS CU DIE, so no need
- to create a DIE for the original CUs. */
- return;
- }
- /* Keep the 1:1 association during WPA. */
- die = new_die (DW_TAG_compile_unit, NULL, decl);
- break;
+ {
+ die = comp_unit_die ();
+ dw_die_ref import = new_die (DW_TAG_imported_unit, die, NULL_TREE);
+ add_AT_external_die_ref (import, DW_AT_import, sym, off);
+ /* We re-target all CU decls to the LTRANS CU DIE, so no need
+ to create a DIE for the original CUs. */
+ return die;
+ }
case NAMESPACE_DECL:
if (is_fortran (decl))
die = new_die (DW_TAG_module, parent, decl);
gcc_unreachable ();
}
if (TREE_CODE (decl) == BLOCK)
- BLOCK_DIE (decl) = die;
+ equate_block_to_die (decl, die);
else
equate_decl_number_to_die (decl, die);
/* Add a reference to the DIE providing early debug at $sym + off. */
add_AT_external_die_ref (die, DW_AT_abstract_origin, sym, off);
+
+ return die;
}
/* Returns a hash value for X (which really is a var_loc_list). */
by looking in the type declaration, the object declaration equate table or
the block mapping. */
-static inline dw_die_ref
+static inline void
add_abstract_origin_attribute (dw_die_ref die, tree origin)
{
dw_die_ref origin_die = NULL;
if (DECL_P (origin))
{
- dw_die_ref c;
- origin_die = lookup_decl_die (origin);
- /* "Unwrap" the decls DIE which we put in the imported unit context.
- We are looking for the abstract copy here. */
+ sym_off_pair *desc;
if (in_lto_p
- && origin_die
- && (c = get_AT_ref (origin_die, DW_AT_abstract_origin))
- /* ??? Identify this better. */
- && c->with_offset)
- origin_die = c;
+ && external_die_map
+ && (desc = external_die_map->get (origin)))
+ {
+ add_AT_external_die_ref (die, DW_AT_abstract_origin,
+ desc->sym, desc->off);
+ return;
+ }
+ origin_die = lookup_decl_die (origin);
}
else if (TYPE_P (origin))
origin_die = lookup_type_die (origin);
else if (TREE_CODE (origin) == BLOCK)
- origin_die = BLOCK_DIE (origin);
+ origin_die = lookup_block_die (origin);
/* XXX: Functions that are never lowered don't always have correct block
trees (in the case of java, they simply have no block tree, in some other
if (origin_die)
add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
- return origin_die;
}
/* We do not currently support the pure_virtual attribute. */
if (DECL_IGNORED_P (decl))
return;
+ /* Do not lazily create a DIE for decl here just because we
+ got called via debug_hooks->outlining_inline_function. */
+ if (in_lto_p
+ && external_die_map
+ && external_die_map->get (decl))
+ return;
+
old_die = lookup_decl_die (decl);
/* With early debug we always have an old DIE unless we are in LTO
and the user did not compile but only link with debug. */
&& block != DECL_INITIAL (decl)
&& TREE_CODE (block) == BLOCK)
{
- stmt_die = BLOCK_DIE (block);
+ stmt_die = lookup_block_die (block);
if (stmt_die)
break;
block = BLOCK_SUPERCONTEXT (block);
static void
gen_lexical_block_die (tree stmt, dw_die_ref context_die)
{
- dw_die_ref old_die = BLOCK_DIE (stmt);
+ dw_die_ref old_die = lookup_block_die (stmt);
dw_die_ref stmt_die = NULL;
if (!old_die)
{
stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
- BLOCK_DIE (stmt) = stmt_die;
+ equate_block_to_die (stmt, stmt_die);
}
if (BLOCK_ABSTRACT (stmt))
if (old_die)
{
stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
- BLOCK_DIE (stmt) = stmt_die;
+ equate_block_to_die (stmt, stmt_die);
old_die = NULL;
}
= new_die (DW_TAG_inlined_subroutine, context_die, stmt);
if (call_arg_locations || debug_inline_points)
- BLOCK_DIE (stmt) = subr_die;
+ equate_block_to_die (stmt, subr_die);
add_abstract_origin_attribute (subr_die, decl);
if (TREE_ASM_WRITTEN (stmt))
add_high_low_attributes (stmt, subr_die);
/* The outer scopes for inlinings *must* always be represented. We
generate DW_TAG_inlined_subroutine DIEs for them. (See below.) */
must_output_die = 1;
- else if (BLOCK_DIE (stmt))
+ else if (lookup_block_die (stmt))
/* If we already have a DIE then it was filled early. Meanwhile
we might have pruned all BLOCK_VARS as optimized out but we
still want to generate high/low PC attributes so output it. */
true));
gcc_assert (inlined_function_outer_scope_p (block));
- gcc_assert (!BLOCK_DIE (block));
+ gcc_assert (!lookup_block_die (block));
if (BLOCK_FRAGMENT_ORIGIN (block))
block = BLOCK_FRAGMENT_ORIGIN (block);
sure to adjust the phase after annotating the LTRANS CU DIE. */
if (in_lto_p)
{
+ /* Force DW_TAG_imported_unit to be created now, otherwise
+ we might end up without it or ordered after DW_TAG_inlined_subroutine
+ referencing DIEs from it. */
+ if (! flag_wpa && flag_incremental_link != INCREMENTAL_LINK_LTO)
+ {
+ unsigned i;
+ tree tu;
+ FOR_EACH_VEC_SAFE_ELT (all_translation_units, i, tu)
+ maybe_create_die_with_external_ref (tu);
+ }
+
early_dwarf_finished = true;
if (dump_file)
{