GTY ((desc ("%1.kind"))) addr;
};
+typedef unsigned int var_loc_view;
+
/* Location lists are ranges + location descriptions for that range,
so you can track variables that are in different places over
their entire life. */
addr_table_entry *begin_entry;
const char *end; /* Label for end of range */
char *ll_symbol; /* Label for beginning of location list.
- Only on head of list */
+ Only on head of list. */
+ char *vl_symbol; /* Label for beginning of view list. Ditto. */
const char *section; /* Section this loclist is relative to */
dw_loc_descr_ref expr;
+ var_loc_view vbegin, vend;
hashval_t hash;
/* True if all addresses in this and subsequent lists are known to be
resolved. */
return "OP_<unknown>";
}
+/* Return TRUE iff we're to output location view lists as a separate
+ attribute next to the location lists, as an extension compatible
+ with DWARF 2 and above. */
+
+static inline bool
+dwarf2out_locviews_in_attribute ()
+{
+ return debug_variable_location_views == 1;
+}
+
+/* Return TRUE iff we're to output location view lists as part of the
+ location lists, as proposed for standardization after DWARF 5. */
+
+static inline bool
+dwarf2out_locviews_in_loclist ()
+{
+#ifndef DW_LLE_view_pair
+ return false;
+#else
+ return debug_variable_location_views == -1;
+#endif
+}
+
/* Return a pointer to a newly allocated location description. Location
descriptions are simple expression terms that can be strung
together to form more complicated location (address) descriptions. */
return a->v.val_loc == b->v.val_loc;
case dw_val_class_loc_list:
return a->v.val_loc_list == b->v.val_loc_list;
+ case dw_val_class_view_list:
+ return a->v.val_view_list == b->v.val_view_list;
case dw_val_class_die_ref:
return a->v.val_die_ref.die == b->v.val_die_ref.die;
case dw_val_class_fde_ref:
LI_set_epilogue_begin,
/* Emit a DW_LNE_set_discriminator. */
- LI_set_discriminator
+ LI_set_discriminator,
+
+ /* Output a Fixed Advance PC; the target PC is the label index; the
+ base PC is the previous LI_adv_address or LI_set_address entry.
+ We only use this when emitting debug views without assembler
+ support, at explicit user request. Ideally, we should only use
+ it when the offset might be zero but we can't tell: it's the only
+ way to maybe change the PC without resetting the view number. */
+ LI_adv_address
};
typedef struct GTY(()) dw_line_info_struct {
bool is_stmt;
bool in_use;
+ /* This denotes the NEXT view number.
+
+ If it is 0, it is known that the NEXT view will be the first view
+ at the given PC.
+
+ If it is -1, we've advanced PC but we haven't emitted a line location yet,
+ so we shouldn't use this view number.
+
+ The meaning of other nonzero values depends on whether we're
+ computing views internally or leaving it for the assembler to do
+ so. If we're emitting them internally, view denotes the view
+ number since the last known advance of PC. If we're leaving it
+ for the assembler, it denotes the LVU label number that we're
+ going to ask the assembler to assign. */
+ var_loc_view view;
+
+#define RESET_NEXT_VIEW(x) ((x) = (var_loc_view)0)
+#define RESETTING_VIEW_P(x) ((x) == (var_loc_view)0)
+
vec<dw_line_info_entry, va_gc> *entries;
};
#endif
#endif
+/* Use assembler views in line directives if available. */
+#ifndef DWARF2_ASM_VIEW_DEBUG_INFO
+#ifdef HAVE_AS_DWARF2_DEBUG_VIEW
+#define DWARF2_ASM_VIEW_DEBUG_INFO 1
+#else
+#define DWARF2_ASM_VIEW_DEBUG_INFO 0
+#endif
+#endif
+
+/* A bit is set in ZERO_VIEW_P if we are using the assembler-supported
+ view computation, and it refers to a view identifier for which we
+ will not emit a label because it is known to map to a view number
+ zero. We won't allocate the bitmap if we're not using assembler
+ support for location views, but we have to make the variable
+ visible for GGC and for code that will be optimized out for lack of
+ support but that's still parsed and compiled. We could abstract it
+ out with macros, but it's not worth it. */
+static GTY(()) bitmap zero_view_p;
+
+/* Evaluate to TRUE iff N is known to identify the first location view
+ at its PC. When not using assembler location view computation,
+ that must be view number zero. Otherwise, ZERO_VIEW_P is allocated
+ and views label numbers recorded in it are the ones known to be
+ zero. */
+#define ZERO_VIEW_P(N) (zero_view_p \
+ ? bitmap_bit_p (zero_view_p, (N)) \
+ : (N) == 0)
+
+/* Return true iff we're to emit .loc directives for the assembler to
+ generate line number sections.
+
+ When we're not emitting views, all we need from the assembler is
+ support for .loc directives.
+
+ If we are emitting views, we can only use the assembler's .loc
+ support if it also supports views.
+
+ When the compiler is emitting the line number programs and
+ computing view numbers itself, it resets view numbers at known PC
+ changes and counts from that, and then it emits view numbers as
+ literal constants in locviewlists. There are cases in which the
+ compiler is not sure about PC changes, e.g. when extra alignment is
+ requested for a label. In these cases, the compiler may not reset
+ the view counter, and the potential PC advance in the line number
+ program will use an opcode that does not reset the view counter
+ even if the PC actually changes, so that compiler and debug info
+ consumer can keep view numbers in sync.
+
+ When the compiler defers view computation to the assembler, it
+ emits symbolic view numbers in locviewlists, with the exception of
+ views known to be zero (forced resets, or reset after
+ compiler-visible PC changes): instead of emitting symbols for
+ these, we emit literal zero and assert the assembler agrees with
+ the compiler's assessment. We could use symbolic views everywhere,
+ instead of special-casing zero views, but then we'd be unable to
+ optimize out locviewlists that contain only zeros. */
+
+static bool
+output_asm_line_debug_info (void)
+{
+ return (DWARF2_ASM_VIEW_DEBUG_INFO
+ || (DWARF2_ASM_LINE_DEBUG_INFO
+ && !debug_variable_location_views));
+}
+
/* Minimum line offset in a special line info. opcode.
This value was chosen to give a reasonable range of values. */
#define DWARF_LINE_BASE -10
rtx GTY (()) loc;
const char * GTY (()) label;
struct var_loc_node * GTY (()) next;
+ var_loc_view view;
};
/* Variable location list. */
static void add_AT_loc_list (dw_die_ref, enum dwarf_attribute,
dw_loc_list_ref);
static inline dw_loc_list_ref AT_loc_list (dw_attr_node *);
+static void add_AT_view_list (dw_die_ref, enum dwarf_attribute);
+static inline dw_loc_list_ref AT_loc_list (dw_attr_node *);
static addr_table_entry *add_addr_table_entry (void *, enum ate_kind);
static void remove_addr_table_entry (addr_table_entry *);
static void add_AT_addr (dw_die_ref, enum dwarf_attribute, rtx, bool);
static dw_die_ref lookup_decl_die (tree);
static var_loc_list *lookup_decl_loc (const_tree);
static void equate_decl_number_to_die (tree, dw_die_ref);
-static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *);
+static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *, var_loc_view);
static void print_spaces (FILE *);
static void print_die (dw_die_ref, FILE *);
static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *);
static void gen_type_die_with_usage (tree, dw_die_ref, enum debug_info_usage);
static void splice_child_die (dw_die_ref, dw_die_ref);
static int file_info_cmp (const void *, const void *);
-static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *,
- const char *, const char *);
+static dw_loc_list_ref new_loc_list (dw_loc_descr_ref, const char *, var_loc_view,
+ const char *, var_loc_view, const char *);
static void output_loc_list (dw_loc_list_ref);
static char *gen_internal_sym (const char *);
static bool want_pubnames (void);
return a->dw_attr_val.v.val_loc_list;
}
+/* Add a view list attribute to DIE. It must have a DW_AT_location
+ attribute, because the view list complements the location list. */
+
+static inline void
+add_AT_view_list (dw_die_ref die, enum dwarf_attribute attr_kind)
+{
+ dw_attr_node attr;
+
+ if (XCOFF_DEBUGGING_INFO && !HAVE_XCOFF_DWARF_EXTRAS)
+ return;
+
+ attr.dw_attr = attr_kind;
+ attr.dw_attr_val.val_class = dw_val_class_view_list;
+ attr.dw_attr_val.val_entry = NULL;
+ attr.dw_attr_val.v.val_view_list = die;
+ add_dwarf_attr (die, &attr);
+ gcc_checking_assert (get_AT (die, DW_AT_location));
+ gcc_assert (have_location_lists);
+}
+
+/* Return a pointer to the location list referenced by the attribute.
+ If the named attribute is a view list, look up the corresponding
+ DW_AT_location attribute and return its location list. */
+
static inline dw_loc_list_ref *
AT_loc_list_ptr (dw_attr_node *a)
{
- gcc_assert (a && AT_class (a) == dw_val_class_loc_list);
- return &a->dw_attr_val.v.val_loc_list;
+ gcc_assert (a);
+ switch (AT_class (a))
+ {
+ case dw_val_class_loc_list:
+ return &a->dw_attr_val.v.val_loc_list;
+ case dw_val_class_view_list:
+ {
+ dw_attr_node *l;
+ l = get_AT (a->dw_attr_val.v.val_view_list, DW_AT_location);
+ if (!l)
+ return NULL;
+ gcc_checking_assert (l + 1 == a);
+ return AT_loc_list_ptr (l);
+ }
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Return the location attribute value associated with a view list
+ attribute value. */
+
+static inline dw_val_node *
+view_list_to_loc_list_val_node (dw_val_node *val)
+{
+ gcc_assert (val->val_class == dw_val_class_view_list);
+ dw_attr_node *loc = get_AT (val->v.val_view_list, DW_AT_location);
+ if (!loc)
+ return NULL;
+ gcc_checking_assert (&(loc + 1)->dw_attr_val == val);
+ gcc_assert (AT_class (loc) == dw_val_class_loc_list);
+ return &loc->dw_attr_val;
}
struct addr_hasher : ggc_ptr_hash<addr_table_entry>
/* Add a variable location node to the linked list for DECL. */
static struct var_loc_node *
-add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
+add_var_loc_to_decl (tree decl, rtx loc_note, const char *label, var_loc_view view)
{
unsigned int decl_id;
var_loc_list *temp;
/* TEMP->LAST here is either pointer to the last but one or
last element in the chained list, LAST is pointer to the
last element. */
- if (label && strcmp (last->label, label) == 0)
+ if (label && strcmp (last->label, label) == 0 && last->view == view)
{
/* For SRA optimized variables if there weren't any real
insns since last note, just modify the last node. */
temp->last->next = NULL;
unused = last;
last = temp->last;
- gcc_assert (strcmp (last->label, label) != 0);
+ gcc_assert (strcmp (last->label, label) != 0 || last->view != view);
}
else
{
fprintf (outfile, "location list -> label:%s",
val->v.val_loc_list->ll_symbol);
break;
+ case dw_val_class_view_list:
+ val = view_list_to_loc_list_val_node (val);
+ fprintf (outfile, "location list with views -> labels:%s and %s",
+ val->v.val_loc_list->ll_symbol,
+ val->v.val_loc_list->vl_symbol);
+ break;
case dw_val_class_range_list:
fprintf (outfile, "range list");
break;
}
break;
case dw_val_class_loc_list:
+ case dw_val_class_view_list:
if (dwarf_split_debug_info && dwarf_version >= 5)
{
gcc_assert (AT_loc_list (a)->num_assigned);
gcc_unreachable ();
}
case dw_val_class_loc_list:
+ case dw_val_class_view_list:
if (dwarf_split_debug_info
&& dwarf_version >= 5
&& AT_loc_list (a)->num_assigned)
expression. */
static inline dw_loc_list_ref
-new_loc_list (dw_loc_descr_ref expr, const char *begin, const char *end,
+new_loc_list (dw_loc_descr_ref expr, const char *begin, var_loc_view vbegin,
+ const char *end, var_loc_view vend,
const char *section)
{
dw_loc_list_ref retlist = ggc_cleared_alloc<dw_loc_list_node> ();
retlist->end = end;
retlist->expr = expr;
retlist->section = section;
+ retlist->vbegin = vbegin;
+ retlist->vend = vend;
return retlist;
}
+/* Return true iff there's any nonzero view number in the loc list. */
+
+static bool
+loc_list_has_views (dw_loc_list_ref list)
+{
+ if (!debug_variable_location_views)
+ return false;
+
+ for (dw_loc_list_ref loc = list;
+ loc != NULL; loc = loc->dw_loc_next)
+ if (!ZERO_VIEW_P (loc->vbegin) || !ZERO_VIEW_P (loc->vend))
+ return true;
+
+ return false;
+}
+
/* Generate a new internal symbol for this location list node, if it
hasn't got one yet. */
{
gcc_assert (!list->ll_symbol);
list->ll_symbol = gen_internal_sym ("LLST");
+
+ if (!loc_list_has_views (list))
+ return;
+
+ if (dwarf2out_locviews_in_attribute ())
+ {
+ /* Use the same label_num for the view list. */
+ label_num--;
+ list->vl_symbol = gen_internal_sym ("LVUS");
+ }
+ else
+ list->vl_symbol = list->ll_symbol;
+}
+
+/* Generate a symbol for the list, but only if we really want to emit
+ it as a list. */
+
+static inline void
+maybe_gen_llsym (dw_loc_list_ref list)
+{
+ if (!list || (!list->dw_loc_next && !loc_list_has_views (list)))
+ return;
+
+ gen_llsym (list);
+}
+
+/* Determine whether or not to skip loc_list entry CURR. If we're not
+ to skip it, and SIZEP is non-null, store the size of CURR->expr's
+ representation in *SIZEP. */
+
+static bool
+skip_loc_list_entry (dw_loc_list_ref curr, unsigned long *sizep = 0)
+{
+ /* Don't output an entry that starts and ends at the same address. */
+ if (strcmp (curr->begin, curr->end) == 0
+ && curr->vbegin == curr->vend && !curr->force)
+ return true;
+
+ unsigned long size = size_of_locs (curr->expr);
+
+ /* If the expression is too large, drop it on the floor. We could
+ perhaps put it into DW_TAG_dwarf_procedure and refer to that
+ in the expression, but >= 64KB expressions for a single value
+ in a single range are unlikely very useful. */
+ if (dwarf_version < 5 && size > 0xffff)
+ return true;
+
+ if (sizep)
+ *sizep = size;
+
+ return false;
+}
+
+/* Output a view pair loclist entry for CURR, if it requires one. */
+
+static void
+dwarf2out_maybe_output_loclist_view_pair (dw_loc_list_ref curr)
+{
+ if (!dwarf2out_locviews_in_loclist ())
+ return;
+
+ if (ZERO_VIEW_P (curr->vbegin) && ZERO_VIEW_P (curr->vend))
+ return;
+
+#ifdef DW_LLE_view_pair
+ dw2_asm_output_data (1, DW_LLE_view_pair, "DW_LLE_view_pair");
+
+# if DWARF2_ASM_VIEW_DEBUG_INFO
+ if (ZERO_VIEW_P (curr->vbegin))
+ dw2_asm_output_data_uleb128 (0, "Location view begin");
+ else
+ {
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin);
+ dw2_asm_output_symname_uleb128 (label, "Location view begin");
+ }
+
+ if (ZERO_VIEW_P (curr->vend))
+ dw2_asm_output_data_uleb128 (0, "Location view end");
+ else
+ {
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend);
+ dw2_asm_output_symname_uleb128 (label, "Location view end");
+ }
+# else /* !DWARF2_ASM_VIEW_DEBUG_INFO */
+ dw2_asm_output_data_uleb128 (curr->vbegin, "Location view begin");
+ dw2_asm_output_data_uleb128 (curr->vend, "Location view end");
+# endif /* DWARF2_ASM_VIEW_DEBUG_INFO */
+#endif /* DW_LLE_view_pair */
+
+ return;
}
/* Output the location list given to us. */
static void
output_loc_list (dw_loc_list_ref list_head)
{
+ int vcount = 0, lcount = 0;
+
if (list_head->emitted)
return;
list_head->emitted = true;
+ if (list_head->vl_symbol && dwarf2out_locviews_in_attribute ())
+ {
+ ASM_OUTPUT_LABEL (asm_out_file, list_head->vl_symbol);
+
+ for (dw_loc_list_ref curr = list_head; curr != NULL;
+ curr = curr->dw_loc_next)
+ {
+ if (skip_loc_list_entry (curr))
+ continue;
+
+ vcount++;
+
+ /* ?? dwarf_split_debug_info? */
+#if DWARF2_ASM_VIEW_DEBUG_INFO
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ if (!ZERO_VIEW_P (curr->vbegin))
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vbegin);
+ dw2_asm_output_symname_uleb128 (label,
+ "View list begin (%s)",
+ list_head->vl_symbol);
+ }
+ else
+ dw2_asm_output_data_uleb128 (0,
+ "View list begin (%s)",
+ list_head->vl_symbol);
+
+ if (!ZERO_VIEW_P (curr->vend))
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", curr->vend);
+ dw2_asm_output_symname_uleb128 (label,
+ "View list end (%s)",
+ list_head->vl_symbol);
+ }
+ else
+ dw2_asm_output_data_uleb128 (0,
+ "View list end (%s)",
+ list_head->vl_symbol);
+#else /* !DWARF2_ASM_VIEW_DEBUG_INFO */
+ dw2_asm_output_data_uleb128 (curr->vbegin,
+ "View list begin (%s)",
+ list_head->vl_symbol);
+ dw2_asm_output_data_uleb128 (curr->vend,
+ "View list end (%s)",
+ list_head->vl_symbol);
+#endif
+ }
+ }
+
ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
- dw_loc_list_ref curr = list_head;
const char *last_section = NULL;
const char *base_label = NULL;
/* Walk the location list, and output each range + expression. */
- for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
+ for (dw_loc_list_ref curr = list_head; curr != NULL;
+ curr = curr->dw_loc_next)
{
unsigned long size;
- /* Don't output an entry that starts and ends at the same address. */
- if (strcmp (curr->begin, curr->end) == 0 && !curr->force)
- continue;
- size = size_of_locs (curr->expr);
- /* If the expression is too large, drop it on the floor. We could
- perhaps put it into DW_TAG_dwarf_procedure and refer to that
- in the expression, but >= 64KB expressions for a single value
- in a single range are unlikely very useful. */
- if (dwarf_version < 5 && size > 0xffff)
+
+ /* Skip this entry? If we skip it here, we must skip it in the
+ view list above as well. */
+ if (skip_loc_list_entry (curr, &size))
continue;
+
+ lcount++;
+
if (dwarf_version >= 5)
{
if (dwarf_split_debug_info)
{
+ dwarf2out_maybe_output_loclist_view_pair (curr);
/* For -gsplit-dwarf, emit DW_LLE_starx_length, which has
uleb128 index into .debug_addr and uleb128 length. */
dw2_asm_output_data (1, DW_LLE_startx_length,
}
else if (!have_multiple_function_sections && HAVE_AS_LEB128)
{
+ dwarf2out_maybe_output_loclist_view_pair (curr);
/* If all code is in .text section, the base address is
already provided by the CU attributes. Use
DW_LLE_offset_pair where both addresses are uleb128 encoded
length. */
if (last_section == NULL)
{
+ dwarf2out_maybe_output_loclist_view_pair (curr);
dw2_asm_output_data (1, DW_LLE_start_length,
"DW_LLE_start_length (%s)",
list_head->ll_symbol);
DW_LLE_base_address. */
else
{
+ dwarf2out_maybe_output_loclist_view_pair (curr);
dw2_asm_output_data (1, DW_LLE_offset_pair,
"DW_LLE_offset_pair (%s)",
list_head->ll_symbol);
DW_LLE_start_end with a pair of absolute addresses. */
else
{
+ dwarf2out_maybe_output_loclist_view_pair (curr);
dw2_asm_output_data (1, DW_LLE_start_end,
"DW_LLE_start_end (%s)",
list_head->ll_symbol);
"Location list terminator end (%s)",
list_head->ll_symbol);
}
+
+ gcc_assert (!list_head->vl_symbol
+ || vcount == lcount * (dwarf2out_locviews_in_attribute () ? 1 : 0));
}
/* Output a range_list offset into the .debug_ranges or .debug_rnglists
"%s", dwarf_attr_name (a->dw_attr));
}
+/* Output the offset into the debug_loc section. */
+
+static void
+output_view_list_offset (dw_attr_node *a)
+{
+ char *sym = (*AT_loc_list_ptr (a))->vl_symbol;
+
+ gcc_assert (sym);
+ if (dwarf_split_debug_info)
+ dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label,
+ "%s", dwarf_attr_name (a->dw_attr));
+ else
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, debug_loc_section,
+ "%s", dwarf_attr_name (a->dw_attr));
+}
+
/* Output an attribute's index or value appropriately. */
static void
output_loc_list_offset (a);
break;
+ case dw_val_class_view_list:
+ output_view_list_offset (a);
+ break;
+
case dw_val_class_die_ref:
if (AT_ref_external (a))
{
(unsigned long) die->die_offset);
}
+/* Output the dwarf version number. */
+
+static void
+output_dwarf_version ()
+{
+ /* ??? For now, if -gdwarf-6 is specified, we output version 5 with
+ views in loclist. That will change eventually. */
+ if (dwarf_version == 6)
+ {
+ static bool once;
+ if (!once)
+ {
+ warning (0,
+ "-gdwarf-6 is output as version 5 with incompatibilities");
+ once = true;
+ }
+ dw2_asm_output_data (2, 5, "DWARF version number");
+ }
+ else
+ dw2_asm_output_data (2, dwarf_version, "DWARF version number");
+}
+
/* Output the compilation unit that appears at the beginning of the
.debug_info section, and precedes the DIE descriptions. */
"Length of Compilation Unit Info");
}
- dw2_asm_output_data (2, dwarf_version, "DWARF version number");
+ output_dwarf_version ();
if (dwarf_version >= 5)
{
const char *name;
- DWARF_INITIAL_LENGTH_SIZE
+ size_of_die (comp_unit),
"Length of Compilation Unit Info");
- dw2_asm_output_data (2, dwarf_version, "DWARF version number");
+ output_dwarf_version ();
if (dwarf_version >= 5)
{
dw2_asm_output_data (1, DW_UT_skeleton, "DW_UT_skeleton");
}
/* Version number for pubnames/pubtypes is independent of dwarf version. */
- dw2_asm_output_data (2, 2, "DWARF Version");
+ dw2_asm_output_data (2, 2, "DWARF pubnames/pubtypes version");
if (dwarf_split_debug_info)
dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
}
/* Version number for aranges is still 2, even up to DWARF5. */
- dw2_asm_output_data (2, 2, "DWARF Version");
+ dw2_asm_output_data (2, 2, "DWARF aranges version");
if (dwarf_split_debug_info)
dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_skeleton_info_section_label,
debug_skeleton_info_section,
dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1,
"Length of Range Lists");
ASM_OUTPUT_LABEL (asm_out_file, l1);
- dw2_asm_output_data (2, dwarf_version, "DWARF Version");
+ output_dwarf_version ();
dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size");
dw2_asm_output_data (1, 0, "Segment Size");
/* Emit the offset table only for -gsplit-dwarf. If we don't care
char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
unsigned int current_line = 1;
bool current_is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
- dw_line_info_entry *ent;
+ dw_line_info_entry *ent, *prev_addr;
size_t i;
+ unsigned int view;
+
+ view = 0;
FOR_EACH_VEC_SAFE_ELT (table->entries, i, ent)
{
to determine when it is safe to use DW_LNS_fixed_advance_pc. */
ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val);
+ view = 0;
+
/* This can handle any delta. This takes
4+DWARF2_ADDR_SIZE bytes. */
- dw2_asm_output_data (1, 0, "set address %s", line_label);
+ dw2_asm_output_data (1, 0, "set address %s%s", line_label,
+ debug_variable_location_views
+ ? ", reset view to 0" : "");
dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
dw2_asm_output_data (1, DW_LNE_set_address, NULL);
dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
+
+ prev_addr = ent;
break;
+ case LI_adv_address:
+ {
+ ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val);
+ char prev_label[MAX_ARTIFICIAL_LABEL_BYTES];
+ ASM_GENERATE_INTERNAL_LABEL (prev_label, LINE_CODE_LABEL, prev_addr->val);
+
+ view++;
+
+ dw2_asm_output_data (1, DW_LNS_fixed_advance_pc, "fixed advance PC, increment view to %i", view);
+ dw2_asm_output_delta (2, line_label, prev_label,
+ "from %s to %s", prev_label, line_label);
+
+ prev_addr = ent;
+ break;
+ }
+
case LI_set_line:
if (ent->val == current_line)
{
ASM_OUTPUT_LABEL (asm_out_file, l1);
- dw2_asm_output_data (2, dwarf_version, "DWARF Version");
+ output_dwarf_version ();
if (dwarf_version >= 5)
{
dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size");
dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
{
const char *endname, *secname;
+ var_loc_view endview;
rtx varloc;
enum var_init_status initialized;
struct var_loc_node *node;
&& current_function_decl)
{
endname = cfun->fde->dw_fde_end;
+ endview = 0;
range_across_switch = true;
}
/* The variable has a location between NODE->LABEL and
NODE->NEXT->LABEL. */
else if (node->next)
- endname = node->next->label;
+ endname = node->next->label, endview = node->next->view;
/* If the variable has a location at the last label
it keeps its location until the end of function. */
else if (!current_function_decl)
- endname = text_end_label;
+ endname = text_end_label, endview = 0;
else
{
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
current_function_funcdef_no);
endname = ggc_strdup (label_id);
+ endview = 0;
}
- *listp = new_loc_list (descr, node->label, endname, secname);
+ *listp = new_loc_list (descr, node->label, node->view,
+ endname, endview, secname);
if (TREE_CODE (decl) == PARM_DECL
&& node == loc_list->first
&& NOTE_P (node->loc)
/* The variable has a location between NODE->LABEL and
NODE->NEXT->LABEL. */
if (node->next)
- endname = node->next->label;
+ endname = node->next->label, endview = node->next->view;
else
- endname = cfun->fde->dw_fde_second_end;
- *listp = new_loc_list (descr, cfun->fde->dw_fde_second_begin,
- endname, secname);
+ endname = cfun->fde->dw_fde_second_end, endview = 0;
+ *listp = new_loc_list (descr, cfun->fde->dw_fde_second_begin, 0,
+ endname, endview, secname);
listp = &(*listp)->dw_loc_next;
}
}
representable, we don't want to pretend a single entry that was
applies to the entire scope in which the variable is
available. */
- if (list && loc_list->first->next)
- gen_llsym (list);
+ maybe_gen_llsym (list);
return list;
}
{
if (dwarf_version >= 3 || !dwarf_strict)
return new_loc_list (new_loc_descr (DW_OP_push_object_address, 0, 0),
- NULL, NULL, NULL);
+ NULL, 0, NULL, 0, NULL);
else
return NULL;
}
add_loc_descr_to_each (list_ret, new_loc_descr (op, size, 0));
}
if (ret)
- list_ret = new_loc_list (ret, NULL, NULL, NULL);
+ list_ret = new_loc_list (ret, NULL, 0, NULL, 0, NULL);
return list_ret;
}
add_AT_location_description (dw_die_ref die, enum dwarf_attribute attr_kind,
dw_loc_list_ref descr)
{
+ bool check_no_locviews = true;
if (descr == 0)
return;
if (single_element_loc_list_p (descr))
add_AT_loc (die, attr_kind, descr->expr);
else
- add_AT_loc_list (die, attr_kind, descr);
+ {
+ add_AT_loc_list (die, attr_kind, descr);
+ gcc_assert (descr->ll_symbol);
+ if (attr_kind == DW_AT_location && descr->vl_symbol
+ && dwarf2out_locviews_in_attribute ())
+ {
+ add_AT_view_list (die, DW_AT_GNU_locviews);
+ check_no_locviews = false;
+ }
+ }
+
+ if (check_no_locviews)
+ gcc_assert (!get_AT (die, DW_AT_GNU_locviews));
}
/* Add DW_AT_accessibility attribute to DIE if needed. */
/* If the first partition contained no CFI adjustments, the
CIE opcodes apply to the whole first partition. */
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- fde->dw_fde_begin, fde->dw_fde_end, section);
+ fde->dw_fde_begin, 0, fde->dw_fde_end, 0, section);
list_tail =&(*list_tail)->dw_loc_next;
start_label = last_label = fde->dw_fde_second_begin;
}
if (!cfa_equal_p (&last_cfa, &next_cfa))
{
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, last_label, section);
+ start_label, 0, last_label, 0, section);
list_tail = &(*list_tail)->dw_loc_next;
last_cfa = next_cfa;
if (!cfa_equal_p (&last_cfa, &next_cfa))
{
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, last_label, section);
+ start_label, 0, last_label, 0, section);
list_tail = &(*list_tail)->dw_loc_next;
last_cfa = next_cfa;
start_label = last_label;
}
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, fde->dw_fde_end, section);
+ start_label, 0, fde->dw_fde_end, 0, section);
list_tail = &(*list_tail)->dw_loc_next;
start_label = last_label = fde->dw_fde_second_begin;
}
if (!cfa_equal_p (&last_cfa, &next_cfa))
{
*list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset),
- start_label, last_label, section);
+ start_label, 0, last_label, 0, section);
list_tail = &(*list_tail)->dw_loc_next;
start_label = last_label;
}
*list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset),
- start_label,
+ start_label, 0,
fde->dw_fde_second_begin
- ? fde->dw_fde_second_end : fde->dw_fde_end,
+ ? fde->dw_fde_second_end : fde->dw_fde_end, 0,
section);
- if (list && list->dw_loc_next)
- gen_llsym (list);
+ maybe_gen_llsym (list);
return list;
}
fd->emitted_number = 1;
last_emitted_file = fd;
- if (DWARF2_ASM_LINE_DEBUG_INFO)
+ if (output_asm_line_debug_info ())
{
fprintf (asm_out_file, "\t.file %u ", fd->emitted_number);
output_quoted_string (asm_out_file,
static rtx_insn *expected_next_loc_note;
tree decl;
bool var_loc_p;
+ var_loc_view view = 0;
if (!NOTE_P (loc_note))
{
if (CALL_P (loc_note))
{
+ RESET_NEXT_VIEW (cur_line_info_table->view);
call_site_count++;
if (SIBLING_CALL_P (loc_note))
tail_call_site_count++;
}
}
}
+ else if (!debug_variable_location_views)
+ gcc_unreachable ();
+ else if (JUMP_TABLE_DATA_P (loc_note))
+ RESET_NEXT_VIEW (cur_line_info_table->view);
+ else if (GET_CODE (loc_note) == USE
+ || GET_CODE (loc_note) == CLOBBER
+ || GET_CODE (loc_note) == ASM_INPUT
+ || asm_noperands (loc_note) >= 0)
+ ;
+ else if (get_attr_min_length (loc_note) > 0)
+ RESET_NEXT_VIEW (cur_line_info_table->view);
+
return;
}
if (var_loc_p)
{
+ const char *label
+ = NOTE_DURING_CALL_P (loc_note) ? last_postcall_label : last_label;
+ view = cur_line_info_table->view;
decl = NOTE_VAR_LOCATION_DECL (loc_note);
- newloc = add_var_loc_to_decl (decl, loc_note,
- NOTE_DURING_CALL_P (loc_note)
- ? last_postcall_label : last_label);
+ newloc = add_var_loc_to_decl (decl, loc_note, label, view);
if (newloc == NULL)
return;
}
else if (GET_CODE (body) == ASM_INPUT
|| asm_noperands (body) >= 0)
continue;
-#ifdef HAVE_attr_length
- else if (get_attr_min_length (insn) == 0)
+#ifdef HAVE_ATTR_length /* ??? We don't include insn-attr.h. */
+ else if (HAVE_ATTR_length && get_attr_min_length (insn) == 0)
continue;
#endif
else
call_arg_loc_last = ca_loc;
}
else if (loc_note != NULL_RTX && !NOTE_DURING_CALL_P (loc_note))
- newloc->label = last_label;
+ {
+ newloc->label = last_label;
+ newloc->view = view;
+ }
else
{
if (!last_postcall_label)
last_postcall_label = ggc_strdup (loclabel);
}
newloc->label = last_postcall_label;
+ newloc->view = view;
}
if (var_loc_p && flag_debug_asm)
table->file_num = 1;
table->line_num = 1;
table->is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START;
+ RESET_NEXT_VIEW (table->view);
return table;
}
vec_safe_push (separate_line_info, table);
}
- if (DWARF2_ASM_LINE_DEBUG_INFO)
+ if (output_asm_line_debug_info ())
table->is_stmt = (cur_line_info_table
? cur_line_info_table->is_stmt
: DWARF_LINE_DEFAULT_IS_STMT_START);
filename, line);
}
- if (DWARF2_ASM_LINE_DEBUG_INFO)
+ if (output_asm_line_debug_info ())
{
/* Emit the .loc directive understood by GNU as. */
/* "\t.loc %u %u 0 is_stmt %u discriminator %u",
fputs (" discriminator ", asm_out_file);
fprint_ul (asm_out_file, (unsigned long) discriminator);
}
+ if (debug_variable_location_views)
+ {
+ static var_loc_view lvugid;
+ if (!lvugid)
+ {
+ gcc_assert (!zero_view_p);
+ zero_view_p = BITMAP_GGC_ALLOC ();
+ bitmap_set_bit (zero_view_p, 0);
+ }
+ if (!RESETTING_VIEW_P (table->view))
+ {
+ /* When we're using the assembler to compute view
+ numbers, we output symbolic labels after "view" in
+ .loc directives, and the assembler will set them for
+ us, so that we can refer to the view numbers in
+ location lists. The only exceptions are when we know
+ a view will be zero: "-0" is a forced reset, used
+ e.g. in the beginning of functions, whereas "0" tells
+ the assembler to check that there was a PC change
+ since the previous view, in a way that implicitly
+ resets the next view. */
+ fputs (" view ", asm_out_file);
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ ASM_GENERATE_INTERNAL_LABEL (label, "LVU", table->view);
+ assemble_name (asm_out_file, label);
+ table->view = ++lvugid;
+ }
+ else
+ {
+ if (!table->in_use)
+ fputs (" view -0", asm_out_file);
+ else
+ fputs (" view 0", asm_out_file);
+ /* Mark the present view as a zero view. Earlier debug
+ binds may have already added its id to loclists to be
+ emitted later, so we can't reuse the id for something
+ else. However, it's good to know whether a view is
+ known to be zero, because then we may be able to
+ optimize out locviews that are all zeros, so take
+ note of it in zero_view_p. */
+ bitmap_set_bit (zero_view_p, lvugid);
+ table->view = ++lvugid;
+ }
+ }
putc ('\n', asm_out_file);
}
else
targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, label_num);
- push_dw_line_info_entry (table, LI_set_address, label_num);
+ if (debug_variable_location_views && table->view)
+ push_dw_line_info_entry (table, LI_adv_address, label_num);
+ else
+ push_dw_line_info_entry (table, LI_set_address, label_num);
+ if (debug_variable_location_views)
+ {
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s view %s%d\n",
+ ASM_COMMENT_START,
+ table->in_use ? "" : "-",
+ table->view);
+ table->view++;
+ }
if (file_num != table->file_num)
push_dw_line_info_entry (table, LI_set_file, file_num);
if (discriminator != table->discrim_num)
SECTION_DEBUG, NULL);
debug_str_section = get_section (DEBUG_STR_SECTION,
DEBUG_STR_SECTION_FLAGS, NULL);
- if (!dwarf_split_debug_info && !DWARF2_ASM_LINE_DEBUG_INFO)
+ if (!dwarf_split_debug_info && !output_asm_line_debug_info ())
debug_line_str_section = get_section (DEBUG_LINE_STR_SECTION,
DEBUG_STR_SECTION_FLAGS, NULL);
+
debug_ranges_section = get_section (dwarf_version >= 5
? DEBUG_RNGLISTS_SECTION
: DEBUG_RANGES_SECTION,
prune_unused_types_walk_loc_descr (list->expr);
break;
+ case dw_val_class_view_list:
+ /* This points to a loc_list in another attribute, so it's
+ already covered. */
+ break;
+
case dw_val_class_die_ref:
/* A reference to another DIE.
Make sure that it will get emitted.
if (d->expr && non_dwarf_expression (d->expr))
non_dwarf_expr = true;
break;
+ case dw_val_class_view_list:
+ gcc_unreachable ();
case dw_val_class_loc:
lv = AT_loc (av);
if (lv == NULL)
lv = copy_deref_exprloc (d->expr);
if (lv)
{
- *p = new_loc_list (lv, d->begin, d->end, d->section);
+ *p = new_loc_list (lv, d->begin, d->vbegin, d->end, d->vend, d->section);
p = &(*p)->dw_loc_next;
}
else if (!dwarf_strict && d->expr)
{
gcc_assert (!next->ll_symbol);
next->ll_symbol = (*curr)->ll_symbol;
+ next->vl_symbol = (*curr)->vl_symbol;
}
if (dwarf_split_debug_info)
remove_loc_list_addr_table_entries (l);
ix--;
}
break;
+ case dw_val_class_view_list:
+ {
+ gcc_checking_assert (a->dw_attr == DW_AT_GNU_locviews);
+ gcc_checking_assert (dwarf2out_locviews_in_attribute ());
+ dw_val_node *llnode
+ = view_list_to_loc_list_val_node (&a->dw_attr_val);
+ /* If we no longer have a loclist, or it no longer needs
+ views, drop this attribute. */
+ if (!llnode || !llnode->v.val_loc_list->vl_symbol)
+ {
+ remove_AT (die, a->dw_attr);
+ ix--;
+ }
+ break;
+ }
case dw_val_class_loc:
{
dw_loc_descr_ref l = AT_loc (a);
{
hstate.add (curr->begin, strlen (curr->begin) + 1);
hstate.add (curr->end, strlen (curr->end) + 1);
+ hstate.add_object (curr->vbegin);
+ hstate.add_object (curr->vend);
if (curr->section)
hstate.add (curr->section, strlen (curr->section) + 1);
hash_locs (curr->expr, hstate);
|| strcmp (a->end, b->end) != 0
|| (a->section == NULL) != (b->section == NULL)
|| (a->section && strcmp (a->section, b->section) != 0)
+ || a->vbegin != b->vbegin || a->vend != b->vend
|| !compare_locs (a->expr, b->expr))
break;
return a == NULL && b == NULL;
dw_attr_node *a;
unsigned ix;
dw_loc_list_struct **slot;
+ bool drop_locviews = false;
+ bool has_locviews = false;
FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
if (AT_class (a) == dw_val_class_loc_list)
hash_loc_list (list);
slot = htab->find_slot_with_hash (list, list->hash, INSERT);
if (*slot == NULL)
- *slot = list;
+ {
+ *slot = list;
+ if (loc_list_has_views (list))
+ gcc_assert (list->vl_symbol);
+ else if (list->vl_symbol)
+ {
+ drop_locviews = true;
+ list->vl_symbol = NULL;
+ }
+ }
else
- a->dw_attr_val.v.val_loc_list = *slot;
+ {
+ if (list->vl_symbol && !(*slot)->vl_symbol)
+ drop_locviews = true;
+ a->dw_attr_val.v.val_loc_list = *slot;
+ }
+ }
+ else if (AT_class (a) == dw_val_class_view_list)
+ {
+ gcc_checking_assert (a->dw_attr == DW_AT_GNU_locviews);
+ has_locviews = true;
}
+
+ if (drop_locviews && has_locviews)
+ remove_AT (die, DW_AT_GNU_locviews);
+
FOR_EACH_CHILD (die, c, optimize_location_lists_1 (c, htab));
}
/* Don't index an entry that has already been indexed
or won't be output. */
if (curr->begin_entry != NULL
- || (strcmp (curr->begin, curr->end) == 0 && !curr->force))
+ || skip_loc_list_entry (curr))
continue;
curr->begin_entry
dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1,
"Length of Location Lists");
ASM_OUTPUT_LABEL (asm_out_file, l1);
- dw2_asm_output_data (2, dwarf_version, "DWARF Version");
+ output_dwarf_version ();
dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Address Size");
dw2_asm_output_data (1, 0, "Segment Size");
dw2_asm_output_data (4, dwarf_split_debug_info ? loc_list_idx : 0,
used by the debug_info section are marked as 'used'. */
switch_to_section (debug_line_section);
ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
- if (! DWARF2_ASM_LINE_DEBUG_INFO)
+ if (! output_asm_line_debug_info ())
output_line_info (false);
if (dwarf_split_debug_info && info_section_emitted)
/* Bitflags used by final_scan_insn. */
#define SEEN_NOTE 1
#define SEEN_EMITTED 2
+#define SEEN_NEXT_VIEW 4
/* Last insn processed by final_scan_insn. */
static rtx_insn *debug_insn;
return 0;
}
+/* Arrange for us to emit a source location note before any further
+ real insns or section changes, by setting the SEEN_NEXT_VIEW bit in
+ *SEEN, as long as we are keeping track of location views. The bit
+ indicates we have referenced the next view at the current PC, so we
+ have to emit it. This should be called next to the var_location
+ debug hook. */
+
+static inline void
+set_next_view_needed (int *seen)
+{
+ if (debug_variable_location_views)
+ *seen |= SEEN_NEXT_VIEW;
+}
+
+/* Clear the flag in *SEEN indicating we need to emit the next view.
+ This should be called next to the source_line debug hook. */
+
+static inline void
+clear_next_view_needed (int *seen)
+{
+ *seen &= ~SEEN_NEXT_VIEW;
+}
+
+/* Test whether we have a pending request to emit the next view in
+ *SEEN, and emit it if needed, clearing the request bit. */
+
+static inline void
+maybe_output_next_view (int *seen)
+{
+ if ((*seen & SEEN_NEXT_VIEW) != 0)
+ {
+ clear_next_view_needed (seen);
+ (*debug_hooks->source_line) (last_linenum, last_columnnum,
+ last_filename, last_discriminator,
+ false);
+ }
+}
+
+/* We want to emit param bindings (before the first begin_stmt) in the
+ initial view, if we are emitting views. To that end, we may
+ consume initial notes in the function, processing them in
+ final_start_function, before signaling the beginning of the
+ prologue, rather than in final.
+
+ We don't test whether the DECLs are PARM_DECLs: the assumption is
+ that there will be a NOTE_INSN_BEGIN_STMT marker before any
+ non-parameter NOTE_INSN_VAR_LOCATION. It's ok if the marker is not
+ there, we'll just have more variable locations bound in the initial
+ view, which is consistent with their being bound without any code
+ that would give them a value. */
+
+static inline bool
+in_initial_view_p (rtx_insn *insn)
+{
+ return (!DECL_IGNORED_P (current_function_decl)
+ && debug_variable_location_views
+ && insn && GET_CODE (insn) == NOTE
+ && (NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION
+ || NOTE_KIND (insn) == NOTE_INSN_DELETED));
+}
+
/* Output assembler code for the start of a function,
and initialize some of the variables in this file
for the new function. The label for the function and associated
FIRST is the first insn of the rtl for the function being compiled.
FILE is the file to write assembler code to.
+ SEEN should be initially set to zero, and it may be updated to
+ indicate we have references to the next location view, that would
+ require us to emit it at the current PC.
OPTIMIZE_P is nonzero if we should eliminate redundant
test and compare insns. */
-void
-final_start_function (rtx_insn *first, FILE *file,
- int optimize_p ATTRIBUTE_UNUSED)
+static void
+final_start_function_1 (rtx_insn **firstp, FILE *file, int *seen,
+ int optimize_p ATTRIBUTE_UNUSED)
{
block_depth = 0;
if (flag_sanitize & SANITIZE_ADDRESS)
asan_function_start ();
+ rtx_insn *first = *firstp;
+ if (in_initial_view_p (first))
+ {
+ do
+ {
+ final_scan_insn (first, file, 0, 0, seen);
+ first = NEXT_INSN (first);
+ }
+ while (in_initial_view_p (first));
+ *firstp = first;
+ }
+
if (!DECL_IGNORED_P (current_function_decl))
- debug_hooks->begin_prologue (last_linenum, last_columnnum, last_filename);
+ debug_hooks->begin_prologue (last_linenum, last_columnnum,
+ last_filename);
if (!dwarf2_debug_info_emitted_p (current_function_decl))
dwarf2out_begin_prologue (0, 0, NULL);
profile_after_prologue (file);
}
+/* This is an exported final_start_function_1, callable without SEEN. */
+
+void
+final_start_function (rtx_insn *first, FILE *file,
+ int optimize_p ATTRIBUTE_UNUSED)
+{
+ int seen = 0;
+ final_start_function_1 (&first, file, &seen, optimize_p);
+ gcc_assert (seen == 0);
+}
+
static void
profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
{
/* Output assembler code for some insns: all or part of a function.
For description of args, see `final_start_function', above. */
-void
-final (rtx_insn *first, FILE *file, int optimize_p)
+static void
+final_1 (rtx_insn *first, FILE *file, int seen, int optimize_p)
{
rtx_insn *insn, *next;
- int seen = 0;
/* Used for -dA dump. */
basic_block *start_to_bb = NULL;
insn = final_scan_insn (insn, file, optimize_p, 0, &seen);
}
+ maybe_output_next_view (&seen);
+
if (flag_debug_asm)
{
free (start_to_bb);
delete_insn (insn);
}
}
+
+/* This is an exported final_1, callable without SEEN. */
+
+void
+final (rtx_insn *first, FILE *file, int optimize_p)
+{
+ /* Those that use the internal final_start_function_1/final_1 API
+ skip initial debug bind notes in final_start_function_1, and pass
+ the modified FIRST to final_1. But those that use the public
+ final_start_function/final APIs, final_start_function can't move
+ FIRST because it's not passed by reference, so if they were
+ skipped there, skip them again here. */
+ while (in_initial_view_p (first))
+ first = NEXT_INSN (first);
+
+ final_1 (first, file, 0, optimize_p);
+}
\f
const char *
get_insn_template (int code, rtx insn)
break;
case NOTE_INSN_SWITCH_TEXT_SECTIONS:
+ maybe_output_next_view (seen);
+
in_cold_section_p = !in_cold_section_p;
if (in_cold_section_p)
break;
case NOTE_INSN_BLOCK_END:
+ maybe_output_next_view (seen);
+
if (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE
|| write_symbols == DWARF2_DEBUG
case NOTE_INSN_VAR_LOCATION:
case NOTE_INSN_CALL_ARG_LOCATION:
if (!DECL_IGNORED_P (current_function_decl))
- debug_hooks->var_location (insn);
+ {
+ debug_hooks->var_location (insn);
+ set_next_view_needed (seen);
+ }
break;
case NOTE_INSN_BEGIN_STMT:
(*debug_hooks->source_line) (last_linenum, last_columnnum,
last_filename, last_discriminator,
true);
+ clear_next_view_needed (seen);
}
break;
switch_to_section (current_function_section ());
+ if (debug_variable_location_views
+ && !DECL_IGNORED_P (current_function_decl))
+ debug_hooks->var_location (insn);
+
break;
}
/* Output this line note if it is the first or the last line
(*debug_hooks->source_line) (last_linenum, last_columnnum,
last_filename, last_discriminator,
is_stmt);
+ clear_next_view_needed (seen);
}
+ else
+ maybe_output_next_view (seen);
+
+ gcc_checking_assert (!DEBUG_INSN_P (insn));
if (GET_CODE (body) == PARALLEL
&& GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
/* Let the debug info back-end know about this call. We do this only
after the instruction has been emitted because labels that may be
created to reference the call instruction must appear after it. */
- if (call_insn != NULL && !DECL_IGNORED_P (current_function_decl))
+ if ((debug_variable_location_views || call_insn != NULL)
+ && !DECL_IGNORED_P (current_function_decl))
debug_hooks->var_location (insn);
current_output_insn = debug_insn = 0;
delete_vta_debug_insns (false);
assemble_start_function (current_function_decl, fnname);
- final_start_function (get_insns (), asm_out_file, optimize);
- final (get_insns (), asm_out_file, optimize);
+ rtx_insn *first = get_insns ();
+ int seen = 0;
+ final_start_function_1 (&first, asm_out_file, &seen, optimize);
+ final_1 (first, asm_out_file, seen, optimize);
if (flag_ipa_ra
&& !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
collect_fn_hard_reg_usage ();