This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
rtlopt-branch merge - variable tracking pass - part 2
- From: Josef Zlomek <zlomj9am at artax dot karlin dot mff dot cuni dot cz>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Daniel Berlin <dberlin at dberlin dot org>
- Date: Thu, 27 Feb 2003 18:59:26 +0100
- Subject: rtlopt-branch merge - variable tracking pass - part 2
Hi,
this patch adds emitting of DWARF2 variable location lists from
NOTE_INSN_VAR_LOCATION notes.
Bootstrapped/regtested i386 and x86-64.
Josef
2003-02-27 Daniel Berlin <dberlin at dberlin dot org>,
Josef Zlomek <zlomekj at suse dot cz>
2003-02-20 Josef Zlomek <zlomekj at suse dot cz>
* dwarf2out.c (struct var_loc_list_def): New structure.
(decl_loc_table): Changed to be an array of var_loc_list.
(lookup_decl_loc): Now returns var_loc_list *.
(add_var_loc_to_decl): Use direct pointer to the last node for adding
a node to the end of list.
(add_location_or_const_value_attribute): Do not add the empty
locations to loc list, finish the range of variable location instead.
(dwarf2out_var_location): Do not emit unnecessary labels.
2003-02-19 Daniel Berlin <dberlin at dberlin dot org>
* dwarf2out.c (output_die): Use dw2_asm_output_offset,
not dw2_asm_output_delta, for location list labels.
2003-02-02 Daniel Berlin <dberlin at dberlin dot org>
* dwarf2out.c (output_loc_list): Location list terminators
should be DWARF2_ADDR_SIZE long.
Add comments.
(add_var_loc_to_decl): Remove dead code, fix formatting.
(add_location_or_const_value_attribute): Add comments.
(dwarf2out_var_location): Remove dead code.
Daniel Berlin <dberlin at dberlin dot org>
* dwarf2out.c (struct gcc_debug_hooks): Call dwarf2out_begin_function
on the beginning of function, call dwarf2out_var_location for
NOTE_INSN_VAR_LOCATION note.
(dwarf2out_begin_function): New function.
(dwarf2out_var_location): New function.
(struct var_loc_node): New structure.
(loclabel_num): New variable.
(decl_loc_table): New variable.
(decl_loc_table_allocated): New variable.
(decl_loc_table_in_use): New variable.
(DECL_LOC_TABLE_INCREMENT): New macro.
(lookup_decl_loc): New function.
(add_var_loc_to_decl): New function.
(output_loc_list): Inverted compare of curr->section and ".text".
(output_loc_list): Output absolute addresses when
separate_line_info_table_in_use.
(mem_loc_descriptor): Added case LO_SUM and debug text for default.
(loc_descriptor): Return if rtl == NULL.
(loc_descriptor): Create loc descriptor.
(add_location_or_const_value_attribute): Add loc descriptor to location
list.
(dwarf2out_init): Create decl_loc_table.
*** var-tracking/gcc/dwarf2out.c Wed Feb 26 13:01:24 2003
--- dwarf2out/gcc/dwarf2out.c Thu Feb 27 18:46:12 2003
*************** static void dwarf2out_end_block PARAMS
*** 3241,3246 ****
--- 3241,3248 ----
static bool dwarf2out_ignore_block PARAMS ((tree));
static void dwarf2out_global_decl PARAMS ((tree));
static void dwarf2out_abstract_function PARAMS ((tree));
+ static void dwarf2out_var_location PARAMS ((rtx));
+ static void dwarf2out_begin_function PARAMS ((tree));
/* The debug hooks structure. */
*************** const struct gcc_debug_hooks dwarf2_debu
*** 3259,3265 ****
dwarf2out_begin_prologue,
debug_nothing_int_charstar, /* end_prologue */
dwarf2out_end_epilogue,
! debug_nothing_tree, /* begin_function */
debug_nothing_int, /* end_function */
dwarf2out_decl, /* function_decl */
dwarf2out_global_decl,
--- 3261,3267 ----
dwarf2out_begin_prologue,
debug_nothing_int_charstar, /* end_prologue */
dwarf2out_end_epilogue,
! dwarf2out_begin_function,
debug_nothing_int, /* end_function */
dwarf2out_decl, /* function_decl */
dwarf2out_global_decl,
*************** const struct gcc_debug_hooks dwarf2_debu
*** 3269,3275 ****
something tries to reference them. */
dwarf2out_abstract_function, /* outlining_inline_function */
debug_nothing_rtx, /* label */
! debug_nothing_rtx /* var location */
};
#endif
--- 3271,3277 ----
something tries to reference them. */
dwarf2out_abstract_function, /* outlining_inline_function */
debug_nothing_rtx, /* label */
! dwarf2out_var_location
};
#endif
*************** static unsigned decl_die_table_in_use;
*** 3478,3483 ****
--- 3480,3520 ----
decl_die_table. */
#define DECL_DIE_TABLE_INCREMENT 256
+ /* Node of the variable location list. */
+ struct var_loc_node GTY ((chain_next ("%h.next")))
+ {
+ rtx GTY (()) var_loc_note;
+ const char * GTY (()) label;
+ struct var_loc_node * GTY (()) next;
+ };
+
+ /* Variable location list. */
+ struct var_loc_list_def GTY (())
+ {
+ struct var_loc_node * GTY (()) first;
+
+ /* Do not mark the last element of the chained list because
+ it is marked through the chain. */
+ struct var_loc_node * GTY ((skip ("%h"))) last;
+ };
+ typedef struct var_loc_list_def var_loc_list;
+
+ /* Unique label counter. */
+ static unsigned int loclabel_num = 0;
+
+ /* Table of decl location linked lists. */
+ static GTY ((length ("decl_loc_table_allocated"))) var_loc_list *decl_loc_table;
+
+ /* Number of elements in the decl_loc_table that are allocated. */
+ static unsigned decl_loc_table_allocated;
+
+ /* Number of elements in the decl_loc_table that are in use. */
+ static unsigned decl_loc_table_in_use;
+
+ /* Size (in elements) of increments by which we may expand the
+ decl_die_table. */
+ #define DECL_LOC_TABLE_INCREMENT 256
+
/* 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 dw_die_ref new_die PARAMS ((enum
*** 3684,3690 ****
--- 3721,3729 ----
static dw_die_ref lookup_type_die PARAMS ((tree));
static void equate_type_number_to_die PARAMS ((tree, dw_die_ref));
static dw_die_ref lookup_decl_die PARAMS ((tree));
+ static var_loc_list *lookup_decl_loc PARAMS ((tree));
static void equate_decl_number_to_die PARAMS ((tree, dw_die_ref));
+ static void add_var_loc_to_decl PARAMS ((tree, struct var_loc_node *));
static void print_spaces PARAMS ((FILE *));
static void print_die PARAMS ((dw_die_ref, FILE *));
static void print_dwarf_line_table PARAMS ((FILE *));
*************** lookup_decl_die (decl)
*** 5280,5285 ****
--- 5319,5335 ----
return (decl_id < decl_die_table_in_use ? decl_die_table[decl_id] : NULL);
}
+ /* Return the var_loc list associated with a given declaration. */
+
+ static inline var_loc_list *
+ lookup_decl_loc (decl)
+ tree decl;
+ {
+ unsigned decl_id = DECL_UID (decl);
+
+ return (decl_id < decl_loc_table_in_use ? &decl_loc_table[decl_id] : NULL);
+ }
+
/* Equate a DIE to a particular declaration. */
static void
*************** equate_decl_number_to_die (decl, decl_di
*** 5310,5315 ****
--- 5360,5415 ----
decl_die_table[decl_id] = decl_die;
}
+
+ /* Add a variable location node to the linked list for DECL. */
+
+ static void
+ add_var_loc_to_decl (decl, loc)
+ tree decl;
+ struct var_loc_node *loc;
+ {
+ unsigned int decl_id = DECL_UID (decl);
+ unsigned int num_allocated;
+ var_loc_list *temp;
+
+ if (decl_id >= decl_loc_table_allocated)
+ {
+ num_allocated = ((decl_id + 1 + DECL_LOC_TABLE_INCREMENT - 1)
+ / DECL_LOC_TABLE_INCREMENT)
+ * DECL_LOC_TABLE_INCREMENT;
+
+ decl_loc_table = ggc_realloc (decl_loc_table,
+ sizeof (var_loc_list) * num_allocated);
+
+ memset (&decl_loc_table[decl_loc_table_allocated], 0,
+ (num_allocated - decl_loc_table_allocated)
+ * sizeof (var_loc_list));
+ decl_loc_table_allocated = num_allocated;
+ }
+
+ if (decl_id >= decl_loc_table_in_use)
+ decl_loc_table_in_use = decl_id + 1;
+
+ temp = &decl_loc_table[decl_id];
+ if (temp->last)
+ {
+ /* If the current location is the same as the end of the list,
+ we have nothing to do. */
+ if (!rtx_equal_p (NOTE_VAR_LOCATION_LOC (temp->last->var_loc_note),
+ NOTE_VAR_LOCATION_LOC (loc->var_loc_note)))
+ {
+ /* Add LOC to the end of list and update LAST. */
+ temp->last->next = loc;
+ temp->last = loc;
+ }
+ }
+ /* Do not add empty location to the beginning of the list. */
+ else if (NOTE_VAR_LOCATION_LOC (loc->var_loc_note) != NULL_RTX)
+ {
+ temp->first = loc;
+ temp->last = loc;
+ }
+ }
/* Keep track of the number of spaces used to indent the
output of the debugging routines that print the structure of
*************** output_loc_list (list_head)
*** 6678,6684 ****
/* ??? This shouldn't be needed now that we've forced the
compilation unit base address to zero when there is code
in more than one section. */
! if (strcmp (curr->section, ".text") == 0)
{
/* dw2_asm_output_data will mask off any extra bits in the ~0. */
dw2_asm_output_data (DWARF2_ADDR_SIZE, ~(unsigned HOST_WIDE_INT) 0,
--- 6778,6784 ----
/* ??? This shouldn't be needed now that we've forced the
compilation unit base address to zero when there is code
in more than one section. */
! if (strcmp (curr->section, ".text") != 0)
{
/* dw2_asm_output_data will mask off any extra bits in the ~0. */
dw2_asm_output_data (DWARF2_ADDR_SIZE, ~(unsigned HOST_WIDE_INT) 0,
*************** output_loc_list (list_head)
*** 6687,6702 ****
"Location list base address specifier base");
}
for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
{
unsigned long size;
!
! dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
! "Location list begin address (%s)",
! list_head->ll_symbol);
! dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->end, curr->section,
! "Location list end address (%s)",
! list_head->ll_symbol);
size = size_of_locs (curr->expr);
/* Output the block length for this list of location operations. */
--- 6787,6814 ----
"Location list base address specifier base");
}
+ /* Walk the location list, and output each range + expression. */
for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
{
unsigned long size;
! if (separate_line_info_table_in_use == 0)
! {
! dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
! "Location list begin address (%s)",
! list_head->ll_symbol);
! dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->end, curr->section,
! "Location list end address (%s)",
! list_head->ll_symbol);
! }
! else
! {
! dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->begin,
! "Location list begin address (%s)",
! list_head->ll_symbol);
! dw2_asm_output_addr (DWARF2_ADDR_SIZE, curr->end,
! "Location list end address (%s)",
! list_head->ll_symbol);
! }
size = size_of_locs (curr->expr);
/* Output the block length for this list of location operations. */
*************** output_loc_list (list_head)
*** 6707,6716 ****
output_loc_sequence (curr->expr);
}
! dw2_asm_output_data (DWARF_OFFSET_SIZE, 0,
"Location list terminator begin (%s)",
list_head->ll_symbol);
! dw2_asm_output_data (DWARF_OFFSET_SIZE, 0,
"Location list terminator end (%s)",
list_head->ll_symbol);
}
--- 6819,6828 ----
output_loc_sequence (curr->expr);
}
! dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
"Location list terminator begin (%s)",
list_head->ll_symbol);
! dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
"Location list terminator end (%s)",
list_head->ll_symbol);
}
*************** output_die (die)
*** 6830,6837 ****
if (sym == 0)
abort ();
! dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym,
! loc_section_label, "%s", name);
}
break;
--- 6942,6948 ----
if (sym == 0)
abort ();
! dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, "%s", name);
}
break;
*************** mem_loc_descriptor (rtl, mode)
*** 8424,8430 ****
--- 8535,8546 ----
else
return 0;
+ case LO_SUM:
+ return 0;
+
default:
+ fprintf (stderr, "\nInvalid mem_loc_descriptor RTL:\n");
+ print_rtl (stderr, rtl);
abort ();
}
*************** loc_descriptor (rtl)
*** 8472,8477 ****
--- 8588,8596 ----
{
dw_loc_descr_ref loc_result = NULL;
+ if (!rtl)
+ return 0;
+
switch (GET_CODE (rtl))
{
case SUBREG:
*************** loc_descriptor (rtl)
*** 8496,8503 ****
loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1));
break;
default:
! abort ();
}
return loc_result;
--- 8615,8655 ----
loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1));
break;
+ case VAR_LOCATION:
+ /* Single part. */
+ if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
+ {
+ loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0));
+ }
+ /* Multiple parts. */
+ else
+ {
+ rtvec par_elems = XVEC (XEXP (rtl, 1), 0);
+ int num_elem = GET_NUM_ELEM (par_elems);
+ enum machine_mode mode;
+ int i;
+
+ /* Create the first one, so we have something to add to. */
+ loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0));
+ mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
+ add_loc_descr (&loc_result,
+ new_loc_descr (DW_OP_piece, GET_MODE_SIZE (mode), 0));
+ for (i = 1; i < num_elem; i++)
+ {
+ dw_loc_descr_ref temp;
+
+ temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0));
+ add_loc_descr (&loc_result, temp);
+ mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
+ add_loc_descr (&loc_result,
+ new_loc_descr (DW_OP_piece,
+ GET_MODE_SIZE (mode), 0));
+ }
+ }
+ break;
+
default:
! return 0;
}
return loc_result;
*************** add_location_or_const_value_attribute (d
*** 9505,9516 ****
--- 9657,9758 ----
{
rtx rtl;
dw_loc_descr_ref descr;
+ var_loc_list *loc_list;
if (TREE_CODE (decl) == ERROR_MARK)
return;
else if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL)
abort ();
+ /* See if we possibly have multiple locations for this variable. */
+ loc_list = lookup_decl_loc (decl);
+
+ /* If it truly has multiple locations, the first and last node will
+ differ. */
+ if (loc_list && loc_list->first != loc_list->last)
+ {
+ const char *secname;
+ const char *endname;
+ dw_loc_list_ref list;
+ rtx varloc;
+ struct var_loc_node *node;
+
+ /* We need to figure out what section we should use as the base
+ for the address ranges where a given location is valid.
+ 1. If this particular DECL has a section associated with it,
+ use that.
+ 2. If this function has a section associated with it, use
+ that.
+ 3. Otherwise, use the text section.
+ XXX: If you split a variable across multiple sections, this
+ won't notice. */
+
+ if (DECL_SECTION_NAME (decl))
+ {
+ tree sectree = DECL_SECTION_NAME (decl);
+ secname = TREE_STRING_POINTER (sectree);
+ }
+ else if (current_function_decl
+ && DECL_SECTION_NAME (current_function_decl))
+ {
+ tree sectree = DECL_SECTION_NAME (current_function_decl);
+ secname = TREE_STRING_POINTER (sectree);
+ }
+ else
+ secname = TEXT_SECTION_NAME;
+
+ /* Now that we know what section we are using for a base,
+ actually construct the list of locations.
+ The first location information is what is passed to the
+ function that creates the location list, and the remaining
+ locations just get added on to that list.
+ Note that we only know the start address for a location
+ (IE location changes), so to build the range, we use
+ the range [current location start, next location start].
+ This means we have to special case the last node, and generate
+ a range of [last location start, end of function label]. */
+
+ node = loc_list->first;
+ varloc = NOTE_VAR_LOCATION (node->var_loc_note);
+ list = new_loc_list (loc_descriptor (varloc), node->label,
+ node->next->label, secname, 1);
+ node = node->next;
+
+ for (; node->next; node = node->next)
+ if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
+ {
+ /* The variable has a location between NODE->LABEL and
+ NODE->NEXT->LABEL. */
+ varloc = NOTE_VAR_LOCATION (node->var_loc_note);
+ add_loc_descr_to_loc_list (&list, loc_descriptor (varloc),
+ node->label, node->next->label,
+ secname);
+ }
+
+ /* If the variable has a location at the last label
+ it keeps its location until the end of function. */
+ if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
+ {
+ char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ varloc = NOTE_VAR_LOCATION (node->var_loc_note);
+ if (!current_function_decl)
+ endname = text_end_label;
+ else
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
+ current_function_funcdef_no);
+ endname = ggc_strdup (label_id);
+ }
+ add_loc_descr_to_loc_list (&list, loc_descriptor (varloc),
+ node->label, endname, secname);
+ }
+
+ /* Finally, add the location list to the DIE, and we are done. */
+ add_AT_loc_list (die, DW_AT_location, list);
+ return;
+ }
+
rtl = rtl_for_decl_location (decl);
if (rtl == NULL_RTX)
return;
*************** init_file_table ()
*** 12375,12380 ****
--- 12617,12679 ----
file_table_last_lookup_index = 0;
}
+ /* Called by the final INSN scan whenever we see a var location. We
+ use it to drop labels in the right places, and throw the location in
+ our lookup table. */
+
+ static void
+ dwarf2out_var_location (loc_note)
+ rtx loc_note;
+ {
+ char loclabel[MAX_ARTIFICIAL_LABEL_BYTES];
+ struct var_loc_node *newloc;
+ rtx prev_insn;
+ static rtx last_insn;
+ static const char *last_label;
+
+ if (!DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
+ return;
+ prev_insn = PREV_INSN (loc_note);
+
+ newloc = ggc_alloc_cleared (sizeof (struct var_loc_node));
+ /* If the insn we processed last time is the previous insn
+ and it is also a var location note, use the label we emitted
+ last time. */
+ if (last_insn != NULL_RTX
+ && last_insn == prev_insn
+ && GET_CODE (prev_insn) == NOTE
+ && NOTE_LINE_NUMBER (prev_insn) == NOTE_INSN_VAR_LOCATION)
+ {
+ newloc->label = last_label;
+ }
+ else
+ {
+ ASM_GENERATE_INTERNAL_LABEL (loclabel, "LVL", loclabel_num++);
+ ASM_OUTPUT_LABEL (asm_out_file, loclabel);
+ newloc->label = ggc_strdup (loclabel);
+ }
+ newloc->var_loc_note = loc_note;
+ newloc->next = NULL;
+
+ last_insn = loc_note;
+ last_label = newloc->label;
+
+ add_var_loc_to_decl (NOTE_VAR_LOCATION_DECL (loc_note), newloc);
+ }
+
+ /* We need to reset the locations at the beginning of each
+ function. We can't do this in the end_function hook, because the
+ declarations that use the locations won't have been outputted when
+ that hook is called. */
+
+ static void
+ dwarf2out_begin_function (unused)
+ tree unused ATTRIBUTE_UNUSED;
+ {
+ decl_loc_table_in_use = 0;
+ memset (decl_loc_table, 0,
+ sizeof (struct var_loc_node *) * decl_loc_table_allocated);
+ }
/* Output a label to mark the beginning of a source code line entry
and record information relating to this source line, in
'line_info_table' for later output of the .debug_line section. */
*************** dwarf2out_init (input_filename)
*** 12560,12565 ****
--- 12859,12870 ----
decl_die_table_allocated = DECL_DIE_TABLE_INCREMENT;
decl_die_table_in_use = 0;
+ /* Allocate the initial hunk of the decl_loc_table. */
+ decl_loc_table = ggc_alloc_cleared (DECL_LOC_TABLE_INCREMENT
+ * sizeof (var_loc_list));
+ decl_loc_table_allocated = DECL_LOC_TABLE_INCREMENT;
+ decl_loc_table_in_use = 0;
+
/* Allocate the initial hunk of the decl_scope_table. */
VARRAY_TREE_INIT (decl_scope_table, 256, "decl_scope_table");