This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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");
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]