dwarf2out.c (struct gcc_debug_hooks): Call dwarf2out_begin_function at the beginning...
authorDaniel Berlin <dberlin@dberlin.org>
Fri, 6 Feb 2004 20:17:00 +0000 (20:17 +0000)
committerJosef Zlomek <zlomek@gcc.gnu.org>
Fri, 6 Feb 2004 20:17:00 +0000 (20:17 +0000)
* dwarf2out.c (struct gcc_debug_hooks): Call dwarf2out_begin_function
at the beginning of function, call dwarf2out_var_location for
NOTE_INSN_VAR_LOCATION note.
(struct var_loc_node, struct var_loc_list_def, loclabel_num,
decl_loc_table): New.
(lookup_decl_loc): New function.
(add_var_loc_to_decl): New function.
(based_loc_descr): Added parameter can_use_fbreg, DW_OP_fbreg is used
only if can_use_fbreg.
(mem_loc_descriptor): Added parameter can_use_fbreg, pass it to other
functions.
(loc_descriptor): Likewise. Process VAR_LOCATION.
(concat_loc_descriptor): Call loc_descriptor with can_use_fbreg == true.
(loc_descriptor_from_tree): Call mem_loc_descriptor with
can_use_fbreg == true.
(add_location_or_const_value_attribute): Added parameter enum
dwarf_attribute attr, generate attribute ATTR.  Create the location list.
(add_bound_info): Call loc_descriptor with can_use_fbreg == true.
(gen_formal_parameter_die): Call add_location_or_const_value_attribute
with attr == DW_AT_location.
(gen_subprogram_die): Generate the location list for DW_AT_frame_base
if frame_base_decl is defined and has a location list.
(gen_variable_die): Call add_location_or_const_value_attribute with
attr == DW_AT_location.
(dwarf2out_var_location): New function.
(dwarf2out_begin_function): New function.
(dwarf2out_init): Create decl_loc_table.

Co-Authored-By: Josef Zlomek <zlomekj@suse.cz>
From-SVN: r77421

gcc/ChangeLog
gcc/dwarf2out.c

index 6853041..b44197f 100644 (file)
@@ -1,3 +1,34 @@
+2004-02-06  Daniel Berlin <dberlin@dberlin.org>
+            Josef Zlomek  <zlomekj@suse.cz>
+
+       * dwarf2out.c (struct gcc_debug_hooks): Call dwarf2out_begin_function
+       at the beginning of function, call dwarf2out_var_location for
+       NOTE_INSN_VAR_LOCATION note.
+       (struct var_loc_node, struct var_loc_list_def, loclabel_num,
+       decl_loc_table): New.
+       (lookup_decl_loc): New function.
+       (add_var_loc_to_decl): New function.
+       (based_loc_descr): Added parameter can_use_fbreg, DW_OP_fbreg is used
+       only if can_use_fbreg.
+       (mem_loc_descriptor): Added parameter can_use_fbreg, pass it to other
+       functions.
+       (loc_descriptor): Likewise. Process VAR_LOCATION.
+       (concat_loc_descriptor): Call loc_descriptor with can_use_fbreg == true.
+       (loc_descriptor_from_tree): Call mem_loc_descriptor with
+       can_use_fbreg == true.
+       (add_location_or_const_value_attribute): Added parameter enum
+       dwarf_attribute attr, generate attribute ATTR.  Create the location list.
+       (add_bound_info): Call loc_descriptor with can_use_fbreg == true.
+       (gen_formal_parameter_die): Call add_location_or_const_value_attribute
+       with attr == DW_AT_location.
+       (gen_subprogram_die): Generate the location list for DW_AT_frame_base
+       if frame_base_decl is defined and has a location list.
+       (gen_variable_die): Call add_location_or_const_value_attribute with
+       attr == DW_AT_location.
+       (dwarf2out_var_location): New function.
+       (dwarf2out_begin_function): New function.
+       (dwarf2out_init): Create decl_loc_table.
+
 2004-02-06  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * loop.c (force_movables): Transitively increase the priorities of
index e407a0b..b35b5ea 100644 (file)
@@ -3251,6 +3251,8 @@ static bool dwarf2out_ignore_block (tree);
 static void dwarf2out_global_decl (tree);
 static void dwarf2out_imported_module_or_decl (tree, tree);
 static void dwarf2out_abstract_function (tree);
+static void dwarf2out_var_location (rtx);
+static void dwarf2out_begin_function (tree);
 
 /* The debug hooks structure.  */
 
@@ -3269,7 +3271,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   dwarf2out_begin_prologue,
   debug_nothing_int_charstar,  /* end_prologue */
   dwarf2out_end_epilogue,
-  debug_nothing_tree,          /* begin_function */
+  dwarf2out_begin_function,
   debug_nothing_int,           /* end_function */
   dwarf2out_decl,              /* function_decl */
   dwarf2out_global_decl,
@@ -3281,7 +3283,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   dwarf2out_abstract_function, /* outlining_inline_function */
   debug_nothing_rtx,           /* label */
   debug_nothing_int,           /* handle_pch */
-  debug_nothing_rtx            /* var_location */
+  dwarf2out_var_location
 };
 #endif
 \f
@@ -3477,6 +3479,34 @@ static GTY(()) size_t file_table_last_lookup_index;
    The key is a DECL_UID() which is a unique number identifying each decl.  */
 static GTY ((param_is (struct die_struct))) htab_t decl_die_table;
 
+/* 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;
+
+  /* DECL_UID of the variable decl.  */
+  unsigned int decl_id;
+};
+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 ((param_is (var_loc_list))) htab_t decl_loc_table;
+
 /* 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.  */
@@ -3651,7 +3681,11 @@ static void equate_type_number_to_die (tree, dw_die_ref);
 static hashval_t decl_die_table_hash (const void *);
 static int decl_die_table_eq (const void *, const void *);
 static dw_die_ref lookup_decl_die (tree);
+static hashval_t decl_loc_table_hash (const void *);
+static int decl_loc_table_eq (const void *, const void *);
+static var_loc_list *lookup_decl_loc (tree);
 static void equate_decl_number_to_die (tree, dw_die_ref);
+static void add_var_loc_to_decl (tree, struct var_loc_node *);
 static void print_spaces (FILE *);
 static void print_die (dw_die_ref, FILE *);
 static void print_dwarf_line_table (FILE *);
@@ -3717,11 +3751,11 @@ static dw_loc_descr_ref reg_loc_descriptor (rtx);
 static dw_loc_descr_ref one_reg_loc_descriptor (unsigned int);
 static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx);
 static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT);
-static dw_loc_descr_ref based_loc_descr (unsigned, HOST_WIDE_INT);
+static dw_loc_descr_ref based_loc_descr (unsigned, HOST_WIDE_INT, bool);
 static int is_based_loc (rtx);
-static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode);
+static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode, bool);
 static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx);
-static dw_loc_descr_ref loc_descriptor (rtx);
+static dw_loc_descr_ref loc_descriptor (rtx, bool);
 static dw_loc_descr_ref loc_descriptor_from_tree (tree, int);
 static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
 static tree field_type (tree);
@@ -3734,7 +3768,8 @@ static void add_AT_location_description   (dw_die_ref, enum dwarf_attribute,
 static void add_data_member_location_attribute (dw_die_ref, tree);
 static void add_const_value_attribute (dw_die_ref, rtx);
 static rtx rtl_for_decl_location (tree);
-static void add_location_or_const_value_attribute (dw_die_ref, tree);
+static void add_location_or_const_value_attribute (dw_die_ref, tree,
+                                                  enum dwarf_attribute);
 static void tree_add_const_value_attribute (dw_die_ref, tree);
 static void add_name_attribute (dw_die_ref, const char *);
 static void add_comp_dir_attribute (dw_die_ref);
@@ -5229,6 +5264,31 @@ lookup_decl_die (tree decl)
   return htab_find_with_hash (decl_die_table, decl, DECL_UID (decl));
 }
 
+/* Returns a hash value for X (which really is a var_loc_list).  */
+
+static hashval_t
+decl_loc_table_hash (const void *x)
+{
+  return (hashval_t) ((const var_loc_list *) x)->decl_id;
+}
+
+/* Return nonzero if decl_id of var_loc_list X is the same as
+   UID of decl *Y.  */
+
+static int
+decl_loc_table_eq (const void *x, const void *y)
+{
+  return (((const var_loc_list *) x)->decl_id == DECL_UID ((const tree) y));
+}
+
+/* Return the var_loc list associated with a given declaration.  */
+
+static inline var_loc_list *
+lookup_decl_loc (tree decl)
+{
+  return htab_find_with_hash (decl_loc_table, decl, DECL_UID (decl));
+}
+
 /* Equate a DIE to a particular declaration.  */
 
 static void
@@ -5241,6 +5301,45 @@ equate_decl_number_to_die (tree decl, dw_die_ref decl_die)
   *slot = decl_die;
   decl_die->decl_id = decl_id;
 }
+
+/* Add a variable location node to the linked list for DECL.  */
+
+static void
+add_var_loc_to_decl (tree decl, struct var_loc_node *loc)
+{
+  unsigned int decl_id = DECL_UID (decl);
+  var_loc_list *temp;
+  void **slot;
+
+  slot = htab_find_slot_with_hash (decl_loc_table, decl, decl_id, INSERT);
+  if (*slot == NULL)
+    {
+      temp = ggc_alloc_cleared (sizeof (var_loc_list));
+      temp->decl_id = decl_id;
+      *slot = temp;
+    }
+  else
+    temp = *slot;
+
+  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;
+    }
+}
 \f
 /* Keep track of the number of spaces used to indent the
    output of the debugging routines that print the structure of
@@ -8204,7 +8303,7 @@ int_loc_descriptor (HOST_WIDE_INT i)
 /* Return a location descriptor that designates a base+offset location.  */
 
 static dw_loc_descr_ref
-based_loc_descr (unsigned int reg, HOST_WIDE_INT offset)
+based_loc_descr (unsigned int reg, HOST_WIDE_INT offset, bool can_use_fbreg)
 {
   dw_loc_descr_ref loc_result;
   /* For the "frame base", we use the frame pointer or stack pointer
@@ -8214,7 +8313,7 @@ based_loc_descr (unsigned int reg, HOST_WIDE_INT offset)
                                         ? HARD_FRAME_POINTER_REGNUM
                                         : STACK_POINTER_REGNUM);
 
-  if (reg == fp_reg)
+  if (reg == fp_reg && can_use_fbreg)
     loc_result = new_loc_descr (DW_OP_fbreg, offset, 0);
   else if (reg <= 31)
     loc_result = new_loc_descr (DW_OP_breg0 + reg, offset, 0);
@@ -8248,10 +8347,15 @@ is_based_loc (rtx rtl)
    MODE is the mode of the memory reference, needed to handle some
    autoincrement addressing modes.
 
+   CAN_USE_FBREG is a flag whether we can use DW_AT_frame_base in the location
+   list for RTL. We can't use it when we are emitting location list for
+   virtual variable frame_base_decl (i.e. a location list for DW_AT_frame_base)
+   which describes how frame base changes when !frame_pointer_needed.
+
    Return 0 if we can't represent the location.  */
 
 static dw_loc_descr_ref
-mem_loc_descriptor (rtx rtl, enum machine_mode mode)
+mem_loc_descriptor (rtx rtl, enum machine_mode mode, bool can_use_fbreg)
 {
   dw_loc_descr_ref mem_loc_result = NULL;
 
@@ -8297,11 +8401,12 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode)
         memory) so DWARF consumers need to be aware of the subtle
         distinction between OP_REG and OP_BASEREG.  */
       if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
-       mem_loc_result = based_loc_descr (reg_number (rtl), 0);
+       mem_loc_result = based_loc_descr (reg_number (rtl), 0, can_use_fbreg);
       break;
 
     case MEM:
-      mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
+      mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
+                                          can_use_fbreg);
       if (mem_loc_result != 0)
        add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
       break;
@@ -8368,10 +8473,12 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode)
     plus:
       if (is_based_loc (rtl))
        mem_loc_result = based_loc_descr (reg_number (XEXP (rtl, 0)),
-                                         INTVAL (XEXP (rtl, 1)));
+                                         INTVAL (XEXP (rtl, 1)),
+                                         can_use_fbreg);
       else
        {
-         mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode);
+         mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                                              can_use_fbreg);
          if (mem_loc_result == 0)
            break;
 
@@ -8383,7 +8490,8 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode)
          else
            {
              add_loc_descr (&mem_loc_result,
-                            mem_loc_descriptor (XEXP (rtl, 1), mode));
+                            mem_loc_descriptor (XEXP (rtl, 1), mode,
+                                                can_use_fbreg));
              add_loc_descr (&mem_loc_result,
                             new_loc_descr (DW_OP_plus, 0, 0));
            }
@@ -8394,8 +8502,10 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode)
       {
        /* If a pseudo-reg is optimized away, it is possible for it to
           be replaced with a MEM containing a multiply.  */
-       dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode);
-       dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode);
+       dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                                                  can_use_fbreg);
+       dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                                                  can_use_fbreg);
 
        if (op0 == 0 || op1 == 0)
          break;
@@ -8414,7 +8524,8 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode)
       /* If this is a MEM, return its address.  Otherwise, we can't
         represent this.  */
       if (GET_CODE (XEXP (rtl, 0)) == MEM)
-       return mem_loc_descriptor (XEXP (XEXP (rtl, 0), 0), mode);
+       return mem_loc_descriptor (XEXP (XEXP (rtl, 0), 0), mode,
+                                  can_use_fbreg);
       else
        return 0;
 
@@ -8432,8 +8543,8 @@ static dw_loc_descr_ref
 concat_loc_descriptor (rtx x0, rtx x1)
 {
   dw_loc_descr_ref cc_loc_result = NULL;
-  dw_loc_descr_ref x0_ref = loc_descriptor (x0);
-  dw_loc_descr_ref x1_ref = loc_descriptor (x1);
+  dw_loc_descr_ref x0_ref = loc_descriptor (x0, true);
+  dw_loc_descr_ref x1_ref = loc_descriptor (x1, true);
 
   if (x0_ref == 0 || x1_ref == 0)
     return 0;
@@ -8460,7 +8571,7 @@ concat_loc_descriptor (rtx x0, rtx x1)
    If we don't know how to describe it, return 0.  */
 
 static dw_loc_descr_ref
-loc_descriptor (rtx rtl)
+loc_descriptor (rtx rtl, bool can_use_fbreg)
 {
   dw_loc_descr_ref loc_result = NULL;
 
@@ -8481,13 +8592,49 @@ loc_descriptor (rtx rtl)
       break;
 
     case MEM:
-      loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
+      loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
+                                      can_use_fbreg);
       break;
 
     case CONCAT:
       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), can_use_fbreg);
+       }
+      /* 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),
+                                      can_use_fbreg);
+         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),
+                                    can_use_fbreg);
+             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:
       abort ();
     }
@@ -8603,7 +8750,7 @@ loc_descriptor_from_tree (tree loc, int addressp)
                rtl = XEXP (rtl, 0);
              }
 
-           ret = mem_loc_descriptor (rtl, mode);
+           ret = mem_loc_descriptor (rtl, mode, true);
          }
       }
       break;
@@ -8687,7 +8834,7 @@ loc_descriptor_from_tree (tree loc, int addressp)
        rtl = (*targetm.delegitimize_address) (rtl);
 
        indirect_p = 1;
-       ret = mem_loc_descriptor (rtl, mode);
+       ret = mem_loc_descriptor (rtl, mode, true);
        break;
       }
 
@@ -9481,16 +9628,110 @@ rtl_for_decl_location (tree decl)
    function call evaluates to a compile-time constant address.  */
 
 static void
-add_location_or_const_value_attribute (dw_die_ref die, tree decl)
+add_location_or_const_value_attribute (dw_die_ref die, tree decl,
+                                      enum dwarf_attribute attr)
 {
   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, attr != DW_AT_frame_base),
+                          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,
+                                                      attr != DW_AT_frame_base),
+                                      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,
+                                                    attr != DW_AT_frame_base),
+                                    node->label, endname, secname);
+       }
+
+      /* Finally, add the location list to the DIE, and we are done.  */
+      add_AT_loc_list (die, attr, list);
+      return;
+    }
+
   rtl = rtl_for_decl_location (decl);
   if (rtl == NULL_RTX)
     return;
@@ -9527,9 +9768,9 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl)
        case REG:
        case SUBREG:
        case CONCAT:
-         descr = loc_descriptor (rtl);
+         descr = loc_descriptor (rtl, true);
        }
-      add_AT_location_description (die, DW_AT_location, descr);
+      add_AT_location_description (die, attr, descr);
       break;
 
     case PARALLEL:
@@ -9540,7 +9781,7 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl)
        int i;
 
        /* Create the first one, so we have something to add to.  */
-       descr = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0));
+       descr = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0), true);
        mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
        add_loc_descr (&descr,
                       new_loc_descr (DW_OP_piece, GET_MODE_SIZE (mode), 0));
@@ -9548,7 +9789,7 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl)
          {
            dw_loc_descr_ref temp;
 
-           temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0));
+           temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0), true);
            add_loc_descr (&descr, temp);
            mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
            add_loc_descr (&descr,
@@ -9694,7 +9935,7 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
          add_AT_flag (decl_die, DW_AT_artificial, 1);
          add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
          add_AT_location_description (decl_die, DW_AT_location,
-                                      loc_descriptor (loc));
+                                      loc_descriptor (loc, true));
          add_AT_die_ref (subrange_die, bound_attr, decl_die);
        }
 
@@ -10517,7 +10758,7 @@ gen_formal_parameter_die (tree node, dw_die_ref context_die)
 
       equate_decl_number_to_die (node, parm_die);
       if (! DECL_ABSTRACT (node))
-       add_location_or_const_value_attribute (parm_die, node);
+       add_location_or_const_value_attribute (parm_die, node, DW_AT_location);
 
       break;
 
@@ -10851,9 +11092,17 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
       /* Define the "frame base" location for this routine.  We use the
         frame pointer or stack pointer registers, since the RTL for local
         variables is relative to one of them.  */
-      fp_reg
-       = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
-      add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg));
+      if (frame_base_decl && lookup_decl_loc (frame_base_decl) != NULL)
+       {
+         add_location_or_const_value_attribute (subr_die, frame_base_decl,
+                                                DW_AT_frame_base);
+       }
+      else
+       {
+         fp_reg
+           = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
+         add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg));
+       }
 
 #if 0
       /* ??? This fails for nested inline functions, because context_display
@@ -11022,7 +11271,7 @@ gen_variable_die (tree decl, dw_die_ref context_die)
 
   if (! declaration && ! DECL_ABSTRACT (decl))
     {
-      add_location_or_const_value_attribute (var_die, decl);
+      add_location_or_const_value_attribute (var_die, decl, DW_AT_location);
       add_pubname (decl, var_die);
     }
   else
@@ -12542,6 +12791,61 @@ init_file_table (void)
   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 (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_DEBUG_LABEL (asm_out_file, "LVL", loclabel_num);
+      loclabel_num++;
+      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 (tree unused ATTRIBUTE_UNUSED)
+{
+  htab_empty (decl_loc_table);
+}
+
 /* 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.  */
@@ -12714,10 +13018,14 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
 {
   init_file_table ();
 
-  /* Allocate the initial hunk of the decl_die_table.  */
+  /* Allocate the decl_die_table.  */
   decl_die_table = htab_create_ggc (10, decl_die_table_hash,
                                    decl_die_table_eq, NULL);
 
+  /* Allocate the decl_loc_table.  */
+  decl_loc_table = htab_create_ggc (10, decl_loc_table_hash,
+                                   decl_loc_table_eq, NULL);
+
   /* Allocate the initial hunk of the decl_scope_table.  */
   VARRAY_TREE_INIT (decl_scope_table, 256, "decl_scope_table");