summaryrefslogtreecommitdiff
path: root/gcc/dwarf2out.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/dwarf2out.c')
-rw-r--r--gcc/dwarf2out.c199
1 files changed, 196 insertions, 3 deletions
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index a88b4cdf6e2..df2f6d92c6f 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -2731,6 +2731,7 @@ static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree,
dw_die_ref);
static void dwarf2out_abstract_function (tree);
static void dwarf2out_var_location (rtx_insn *);
+static void dwarf2out_inline_entry (tree);
static void dwarf2out_size_function (tree);
static void dwarf2out_begin_function (tree);
static void dwarf2out_end_function (unsigned int);
@@ -2784,7 +2785,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
debug_nothing_rtx_code_label, /* label */
debug_nothing_int, /* handle_pch */
dwarf2out_var_location,
- debug_nothing_tree, /* inline_entry */
+ dwarf2out_inline_entry, /* inline_entry */
dwarf2out_size_function, /* size_function */
dwarf2out_switch_text_section,
dwarf2out_set_name,
@@ -4025,6 +4026,9 @@ static char ranges_base_label[2 * MAX_ARTIFICIAL_LABEL_BYTES];
#ifndef BLOCK_BEGIN_LABEL
#define BLOCK_BEGIN_LABEL "LBB"
#endif
+#ifndef BLOCK_INLINE_ENTRY_LABEL
+#define BLOCK_INLINE_ENTRY_LABEL "LBI"
+#endif
#ifndef BLOCK_END_LABEL
#define BLOCK_END_LABEL "LBE"
#endif
@@ -23079,6 +23083,48 @@ block_die_hasher::equal (die_struct *x, die_struct *y)
return x->decl_id == y->decl_id && x->die_parent == y->die_parent;
}
+/* Hold information about markers for inlined entry points. */
+struct GTY ((for_user)) inline_entry_data
+{
+ /* The block that's the inlined_function_outer_scope for an inlined
+ function. */
+ tree block;
+
+ /* The label at the inlined entry point. */
+ const char *label_pfx;
+ unsigned int label_num;
+
+ /* The view number to be used as the inlined entry point. */
+ var_loc_view view;
+};
+
+struct inline_entry_data_hasher : ggc_ptr_hash <inline_entry_data>
+{
+ typedef tree compare_type;
+ static inline hashval_t hash (const inline_entry_data *);
+ static inline bool equal (const inline_entry_data *, const_tree);
+};
+
+/* Hash table routines for inline_entry_data. */
+
+inline hashval_t
+inline_entry_data_hasher::hash (const inline_entry_data *data)
+{
+ return htab_hash_pointer (data->block);
+}
+
+inline bool
+inline_entry_data_hasher::equal (const inline_entry_data *data,
+ const_tree block)
+{
+ return data->block == block;
+}
+
+/* Inlined entry points pending DIE creation in this compilation unit. */
+
+static GTY(()) hash_table<inline_entry_data_hasher> *inline_entry_data_table;
+
+
/* Return TRUE if DECL, which may have been previously generated as
OLD_DIE, is a candidate for a DW_AT_specification. DECLARATION is
true if decl (or its origin) is either an extern declaration or a
@@ -23533,6 +23579,42 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ if (inline_entry_data **iedp
+ = !inline_entry_data_table ? NULL
+ : inline_entry_data_table->find_slot_with_hash (stmt,
+ htab_hash_pointer (stmt),
+ NO_INSERT))
+ {
+ inline_entry_data *ied = *iedp;
+ gcc_assert (MAY_HAVE_DEBUG_MARKER_INSNS);
+ gcc_assert (inlined_function_outer_scope_p (stmt));
+ ASM_GENERATE_INTERNAL_LABEL (label, ied->label_pfx, ied->label_num);
+ add_AT_lbl_id (die, DW_AT_entry_pc, label);
+
+ if (debug_variable_location_views && !ZERO_VIEW_P (ied->view))
+ {
+ if (!output_asm_line_debug_info ())
+ add_AT_unsigned (die, DW_AT_GNU_entry_view, ied->view);
+ else
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", ied->view);
+ /* FIXME: this will resolve to a small number. Could we
+ possibly emit smaller data? Ideally we'd emit a
+ uleb128, but that would make the size of DIEs
+ impossible for the compiler to compute, since it's
+ the assembler that computes the value of the view
+ label in this case. Ideally, we'd have a single form
+ encompassing both the address and the view, and
+ indirecting them through a table might make things
+ easier, but even that would be more wasteful,
+ space-wise, than what we have now. */
+ add_AT_lbl_id (die, DW_AT_GNU_entry_view, label);
+ }
+ }
+
+ inline_entry_data_table->clear_slot (iedp);
+ }
+
if (BLOCK_FRAGMENT_CHAIN (stmt)
&& (dwarf_version >= 3 || !dwarf_strict))
{
@@ -23540,7 +23622,7 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
dw_die_ref pdie;
dw_attr_node *attr = NULL;
- if (inlined_function_outer_scope_p (stmt))
+ if (!MAY_HAVE_DEBUG_MARKER_INSNS && inlined_function_outer_scope_p (stmt))
{
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
BLOCK_NUMBER (stmt));
@@ -23705,7 +23787,7 @@ gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die)
dw_die_ref subr_die
= new_die (DW_TAG_inlined_subroutine, context_die, stmt);
- if (call_arg_locations)
+ if (call_arg_locations || MAY_HAVE_DEBUG_MARKER_INSNS)
BLOCK_DIE (stmt) = subr_die;
add_abstract_origin_attribute (subr_die, decl);
if (TREE_ASM_WRITTEN (stmt))
@@ -26735,6 +26817,7 @@ dwarf2out_var_location (rtx_insn *loc_note)
|| ! NOTE_P (next_note)
|| (NOTE_KIND (next_note) != NOTE_INSN_VAR_LOCATION
&& NOTE_KIND (next_note) != NOTE_INSN_BEGIN_STMT
+ && NOTE_KIND (next_note) != NOTE_INSN_INLINE_ENTRY
&& NOTE_KIND (next_note) != NOTE_INSN_CALL_ARG_LOCATION))
next_note = NULL;
@@ -26923,6 +27006,113 @@ create_label:
last_in_cold_section_p = in_cold_section_p;
}
+/* Check whether BLOCK, a lexical block, is nested within OUTER, or is
+ OUTER itself. If BOTHWAYS, check not only that BLOCK can reach
+ OUTER through BLOCK_SUPERCONTEXT links, but also that there is a
+ path from OUTER to BLOCK through BLOCK_SUBBLOCKs and
+ BLOCK_FRAGMENT_ORIGIN links. */
+static bool
+block_within_block_p (tree block, tree outer, bool bothways)
+{
+ if (block == outer)
+ return true;
+
+ /* Quickly check that OUTER is up BLOCK's supercontext chain. */
+ for (tree context = BLOCK_SUPERCONTEXT (block);
+ context != outer;
+ context = BLOCK_SUPERCONTEXT (context))
+ if (!context || TREE_CODE (context) != BLOCK)
+ return false;
+
+ if (!bothways)
+ return true;
+
+ /* Now check that each block is actually referenced by its
+ parent. */
+ for (tree context = BLOCK_SUPERCONTEXT (block); ;
+ context = BLOCK_SUPERCONTEXT (context))
+ {
+ if (BLOCK_FRAGMENT_ORIGIN (context))
+ {
+ gcc_assert (!BLOCK_SUBBLOCKS (context));
+ context = BLOCK_FRAGMENT_ORIGIN (context);
+ }
+ for (tree sub = BLOCK_SUBBLOCKS (context);
+ sub != block;
+ sub = BLOCK_CHAIN (sub))
+ if (!sub)
+ return false;
+ if (context == outer)
+ return true;
+ else
+ block = context;
+ }
+}
+
+/* Called during final while assembling the marker of the entry point
+ for an inlined function. */
+
+static void
+dwarf2out_inline_entry (tree block)
+{
+ gcc_assert (DECL_P (block_ultimate_origin (block)));
+
+ /* Sanity check the block tree. This would catch a case in which
+ BLOCK got removed from the tree reachable from the outermost
+ lexical block, but got retained in markers. It would still link
+ back to its parents, but some ancestor would be missing a link
+ down the path to the sub BLOCK. If the block got removed, its
+ BLOCK_NUMBER will not be a usable value. */
+ gcc_checking_assert (block_within_block_p (block,
+ DECL_INITIAL
+ (current_function_decl),
+ true));
+
+ gcc_assert (inlined_function_outer_scope_p (block));
+ gcc_assert (!BLOCK_DIE (block));
+
+ /* If we can't represent it, don't bother. */
+ if (!(dwarf_version >= 3 || !dwarf_strict))
+ return;
+
+ if (BLOCK_FRAGMENT_ORIGIN (block))
+ block = BLOCK_FRAGMENT_ORIGIN (block);
+ /* Can the entry point ever not be at the beginning of an
+ unfragmented lexical block? */
+ else if (!(BLOCK_FRAGMENT_CHAIN (block)
+ || (cur_line_info_table
+ && !ZERO_VIEW_P (cur_line_info_table->view))))
+ return;
+
+ if (!inline_entry_data_table)
+ inline_entry_data_table
+ = hash_table<inline_entry_data_hasher>::create_ggc (10);
+
+
+ inline_entry_data **iedp
+ = inline_entry_data_table->find_slot_with_hash (block,
+ htab_hash_pointer (block),
+ INSERT);
+ if (*iedp)
+ /* ??? Ideally, we'd record all entry points for the same inlined
+ function (some may have been duplicated by e.g. unrolling), but
+ we have no way to represent that ATM. */
+ return;
+
+ inline_entry_data *ied = *iedp = ggc_cleared_alloc<inline_entry_data> ();
+ ied->block = block;
+ ied->label_pfx = BLOCK_INLINE_ENTRY_LABEL;
+ ied->label_num = BLOCK_NUMBER (block);
+ if (cur_line_info_table)
+ ied->view = cur_line_info_table->view;
+
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_INLINE_ENTRY_LABEL,
+ BLOCK_NUMBER (block));
+ ASM_OUTPUT_LABEL (asm_out_file, label);
+}
+
/* Called from finalize_size_functions for size functions so that their body
can be encoded in the debug info to describe the layout of variable-length
structures. */
@@ -30401,6 +30591,9 @@ dwarf2out_finish (const char *)
/* Flush out any latecomers to the limbo party. */
flush_limbo_die_list ();
+ if (inline_entry_data_table)
+ gcc_assert (inline_entry_data_table->elements () == 0);
+
if (flag_checking)
{
verify_die (comp_unit_die ());