OSDN Git Service

PR optimization/13424 (hppa), bootstrap/14462, c/14828
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index acd79c4..86512a4 100644 (file)
@@ -149,7 +149,7 @@ collect2_eh_frame_section (void)
 
   data_section ();
   ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
 
   data_section ();
   ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
-  (*targetm.asm_out.globalize_label) (asm_out_file, IDENTIFIER_POINTER (label));
+  targetm.asm_out.globalize_label (asm_out_file, IDENTIFIER_POINTER (label));
   ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
 }
 
   ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
 }
 
@@ -243,6 +243,7 @@ typedef struct cfa_loc GTY(())
 
 typedef struct dw_fde_struct GTY(())
 {
 
 typedef struct dw_fde_struct GTY(())
 {
+  tree decl;
   const char *dw_fde_begin;
   const char *dw_fde_current_label;
   const char *dw_fde_end;
   const char *dw_fde_begin;
   const char *dw_fde_current_label;
   const char *dw_fde_end;
@@ -391,7 +392,9 @@ static void def_cfa_1 (const char *, dw_cfa_location *);
 #define FUNC_END_LABEL         "LFE"
 #endif
 
 #define FUNC_END_LABEL         "LFE"
 #endif
 
+#ifndef FRAME_BEGIN_LABEL
 #define FRAME_BEGIN_LABEL      "Lframe"
 #define FRAME_BEGIN_LABEL      "Lframe"
+#endif
 #define CIE_AFTER_SIZE_LABEL   "LSCIE"
 #define CIE_END_LABEL          "LECIE"
 #define FDE_LABEL              "LSFDE"
 #define CIE_AFTER_SIZE_LABEL   "LSCIE"
 #define CIE_END_LABEL          "LECIE"
 #define FDE_LABEL              "LSFDE"
@@ -1942,6 +1945,22 @@ output_call_frame_info (int for_eh)
   if (fde_table_in_use == 0)
     return;
 
   if (fde_table_in_use == 0)
     return;
 
+  /* If we make FDEs linkonce, we may have to emit an empty label for
+     an FDE that wouldn't otherwise be emitted.  We want to avoid
+     having an FDE kept around when the function it refers to is
+     discarded. (Example where this matters: a primary function
+     template in C++ requires EH information, but an explicit
+     specialization doesn't. */
+  if (TARGET_USES_WEAK_UNWIND_INFO
+      && ! flag_asynchronous_unwind_tables
+      && for_eh)
+    for (i = 0; i < fde_table_in_use; i++)
+      if ((fde_table[i].nothrow || fde_table[i].all_throwers_are_sibcalls)
+          && !fde_table[i].uses_eh_lsda
+         && ! DECL_ONE_ONLY (fde_table[i].decl))
+       targetm.asm_out.unwind_label (asm_out_file, fde_table[i].decl,
+                                        /* empty */ 1);
+
   /* If we don't have any functions we'll want to unwind out of, don't
      emit any EH unwind information.  Note that if exceptions aren't
      enabled, we won't have collected nothrow information, and if we
   /* If we don't have any functions we'll want to unwind out of, don't
      emit any EH unwind information.  Note that if exceptions aren't
      enabled, we won't have collected nothrow information, and if we
@@ -1953,6 +1972,9 @@ output_call_frame_info (int for_eh)
       for (i = 0; i < fde_table_in_use; i++)
        if (fde_table[i].uses_eh_lsda)
          any_eh_needed = any_lsda_needed = true;
       for (i = 0; i < fde_table_in_use; i++)
        if (fde_table[i].uses_eh_lsda)
          any_eh_needed = any_lsda_needed = true;
+        else if (TARGET_USES_WEAK_UNWIND_INFO
+                && DECL_ONE_ONLY (fde_table[i].decl))
+         any_eh_needed = 1;
        else if (! fde_table[i].nothrow
                 && ! fde_table[i].all_throwers_are_sibcalls)
          any_eh_needed = true;
        else if (! fde_table[i].nothrow
                 && ! fde_table[i].all_throwers_are_sibcalls)
          any_eh_needed = true;
@@ -1966,7 +1988,7 @@ output_call_frame_info (int for_eh)
     app_enable ();
 
   if (for_eh)
     app_enable ();
 
   if (for_eh)
-    (*targetm.asm_out.eh_frame_section) ();
+    targetm.asm_out.eh_frame_section ();
   else
     named_section_flags (DEBUG_FRAME_SECTION, SECTION_DEBUG);
 
   else
     named_section_flags (DEBUG_FRAME_SECTION, SECTION_DEBUG);
 
@@ -2004,7 +2026,9 @@ output_call_frame_info (int for_eh)
         P      Indicates the presence of an encoding + language
                personality routine in the CIE augmentation.  */
 
         P      Indicates the presence of an encoding + language
                personality routine in the CIE augmentation.  */
 
-      fde_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0);
+      fde_encoding = TARGET_USES_WEAK_UNWIND_INFO
+       ? ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1)
+       : ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0);
       per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
       lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
 
       per_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/2, /*global=*/1);
       lsda_encoding = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/0);
 
@@ -2095,10 +2119,12 @@ output_call_frame_info (int for_eh)
       /* Don't emit EH unwind info for leaf functions that don't need it.  */
       if (for_eh && !flag_asynchronous_unwind_tables && flag_exceptions
          && (fde->nothrow || fde->all_throwers_are_sibcalls)
       /* Don't emit EH unwind info for leaf functions that don't need it.  */
       if (for_eh && !flag_asynchronous_unwind_tables && flag_exceptions
          && (fde->nothrow || fde->all_throwers_are_sibcalls)
+         && (! TARGET_USES_WEAK_UNWIND_INFO || ! DECL_ONE_ONLY (fde->decl))
          && !fde->uses_eh_lsda)
        continue;
 
          && !fde->uses_eh_lsda)
        continue;
 
-      (*targetm.asm_out.internal_label) (asm_out_file, FDE_LABEL, for_eh + i * 2);
+      targetm.asm_out.unwind_label (asm_out_file, fde->decl, /* empty */ 0);
+      targetm.asm_out.internal_label (asm_out_file, FDE_LABEL, for_eh + i * 2);
       ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i * 2);
       ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i * 2);
       dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
       ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i * 2);
       ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i * 2);
       dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
@@ -2113,9 +2139,16 @@ output_call_frame_info (int for_eh)
 
       if (for_eh)
        {
 
       if (for_eh)
        {
-         dw2_asm_output_encoded_addr_rtx (fde_encoding,
-                  gen_rtx_SYMBOL_REF (Pmode, fde->dw_fde_begin),
-                  "FDE initial location");
+         if (TARGET_USES_WEAK_UNWIND_INFO
+             && DECL_ONE_ONLY (fde->decl))
+           dw2_asm_output_encoded_addr_rtx (fde_encoding,
+                    gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER
+                                                 (DECL_ASSEMBLER_NAME (fde->decl))),
+                    "FDE initial location");
+         else
+           dw2_asm_output_encoded_addr_rtx (fde_encoding,
+                    gen_rtx_SYMBOL_REF (Pmode, fde->dw_fde_begin),
+                    "FDE initial location");
          dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
                                fde->dw_fde_end, fde->dw_fde_begin,
                                "FDE address range");
          dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
                                fde->dw_fde_end, fde->dw_fde_begin,
                                "FDE address range");
@@ -2248,6 +2281,7 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
 
   /* Add the new FDE at the end of the fde_table.  */
   fde = &fde_table[fde_table_in_use++];
 
   /* Add the new FDE at the end of the fde_table.  */
   fde = &fde_table[fde_table_in_use++];
+  fde->decl = current_function_decl;
   fde->dw_fde_begin = xstrdup (label);
   fde->dw_fde_current_label = NULL;
   fde->dw_fde_end = NULL;
   fde->dw_fde_begin = xstrdup (label);
   fde->dw_fde_current_label = NULL;
   fde->dw_fde_end = NULL;
@@ -2344,7 +2378,7 @@ enum dw_val_class
   dw_val_class_const,
   dw_val_class_unsigned_const,
   dw_val_class_long_long,
   dw_val_class_const,
   dw_val_class_unsigned_const,
   dw_val_class_long_long,
-  dw_val_class_float,
+  dw_val_class_vec,
   dw_val_class_flag,
   dw_val_class_die_ref,
   dw_val_class_fde_ref,
   dw_val_class_flag,
   dw_val_class_die_ref,
   dw_val_class_fde_ref,
@@ -2363,14 +2397,15 @@ typedef struct dw_long_long_struct GTY(())
 }
 dw_long_long_const;
 
 }
 dw_long_long_const;
 
-/* Describe a floating point constant value.  */
+/* Describe a floating point constant value, or a vector constant value.  */
 
 
-typedef struct dw_fp_struct GTY(())
+typedef struct dw_vec_struct GTY(())
 {
 {
-  long * GTY((length ("%h.length"))) array;
+  unsigned char * GTY((length ("%h.length"))) array;
   unsigned length;
   unsigned length;
+  unsigned elt_size;
 }
 }
-dw_float_const;
+dw_vec_const;
 
 /* The dw_val_node describes an attribute's value, as it is
    represented internally.  */
 
 /* The dw_val_node describes an attribute's value, as it is
    represented internally.  */
@@ -2384,10 +2419,10 @@ typedef struct dw_val_struct GTY(())
       unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_offset"))) val_offset;
       dw_loc_list_ref GTY ((tag ("dw_val_class_loc_list"))) val_loc_list;
       dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc;
       unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_offset"))) val_offset;
       dw_loc_list_ref GTY ((tag ("dw_val_class_loc_list"))) val_loc_list;
       dw_loc_descr_ref GTY ((tag ("dw_val_class_loc"))) val_loc;
-      HOST_WIDE_INT GTY ((default (""))) val_int;
+      HOST_WIDE_INT GTY ((default)) val_int;
       unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
       dw_long_long_const GTY ((tag ("dw_val_class_long_long"))) val_long_long;
       unsigned HOST_WIDE_INT GTY ((tag ("dw_val_class_unsigned_const"))) val_unsigned;
       dw_long_long_const GTY ((tag ("dw_val_class_long_long"))) val_long_long;
-      dw_float_const GTY ((tag ("dw_val_class_float"))) val_float;
+      dw_vec_const GTY ((tag ("dw_val_class_vec"))) val_vec;
       struct dw_val_die_union
        {
          dw_die_ref die;
       struct dw_val_die_union
        {
          dw_die_ref die;
@@ -3249,8 +3284,11 @@ static void dwarf2out_begin_block (unsigned, unsigned);
 static void dwarf2out_end_block (unsigned, unsigned);
 static bool dwarf2out_ignore_block (tree);
 static void dwarf2out_global_decl (tree);
 static void dwarf2out_end_block (unsigned, unsigned);
 static bool dwarf2out_ignore_block (tree);
 static void dwarf2out_global_decl (tree);
+static void dwarf2out_type_decl (tree, int);
 static void dwarf2out_imported_module_or_decl (tree, tree);
 static void dwarf2out_abstract_function (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.  */
 
 
 /* The debug hooks structure.  */
 
@@ -3269,10 +3307,11 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
   dwarf2out_begin_prologue,
   debug_nothing_int_charstar,  /* end_prologue */
   dwarf2out_end_epilogue,
   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,
   debug_nothing_int,           /* end_function */
   dwarf2out_decl,              /* function_decl */
   dwarf2out_global_decl,
+  dwarf2out_type_decl,         /* type_decl */
   dwarf2out_imported_module_or_decl,
   debug_nothing_tree,          /* deferred_inline_function */
   /* The DWARF 2 backend tries to reduce debugging bloat by not
   dwarf2out_imported_module_or_decl,
   debug_nothing_tree,          /* deferred_inline_function */
   /* The DWARF 2 backend tries to reduce debugging bloat by not
@@ -3280,7 +3319,8 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
      something tries to reference them.  */
   dwarf2out_abstract_function, /* outlining_inline_function */
   debug_nothing_rtx,           /* label */
      something tries to reference them.  */
   dwarf2out_abstract_function, /* outlining_inline_function */
   debug_nothing_rtx,           /* label */
-  debug_nothing_int            /* handle_pch */
+  debug_nothing_int,           /* handle_pch */
+  dwarf2out_var_location
 };
 #endif
 \f
 };
 #endif
 \f
@@ -3476,6 +3516,32 @@ 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;
 
    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;
+
+
+/* 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.  */
 /* 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.  */
@@ -3561,6 +3627,9 @@ static GTY(()) unsigned ranges_table_in_use;
 /* Whether we have location lists that need outputting */
 static GTY(()) unsigned have_location_lists;
 
 /* Whether we have location lists that need outputting */
 static GTY(()) unsigned have_location_lists;
 
+/* Unique label counter.  */
+static GTY(()) unsigned int loclabel_num;
+
 #ifdef DWARF2_DEBUGGING_INFO
 /* Record whether the function being analyzed contains inlined functions.  */
 static int current_function_has_inlines;
 #ifdef DWARF2_DEBUGGING_INFO
 /* Record whether the function being analyzed contains inlined functions.  */
 static int current_function_has_inlines;
@@ -3601,7 +3670,8 @@ static void add_AT_unsigned (dw_die_ref, enum dwarf_attribute, unsigned HOST_WID
 static inline unsigned HOST_WIDE_INT AT_unsigned (dw_attr_ref);
 static void add_AT_long_long (dw_die_ref, enum dwarf_attribute, unsigned long,
                              unsigned long);
 static inline unsigned HOST_WIDE_INT AT_unsigned (dw_attr_ref);
 static void add_AT_long_long (dw_die_ref, enum dwarf_attribute, unsigned long,
                              unsigned long);
-static void add_AT_float (dw_die_ref, enum dwarf_attribute, unsigned, long *);
+static inline void add_AT_vec (dw_die_ref, enum dwarf_attribute, unsigned int,
+                              unsigned int, unsigned char *);
 static hashval_t debug_str_do_hash (const void *);
 static int debug_str_eq (const void *, const void *);
 static void add_AT_string (dw_die_ref, enum dwarf_attribute, const char *);
 static hashval_t debug_str_do_hash (const void *);
 static int debug_str_eq (const void *, const void *);
 static void add_AT_string (dw_die_ref, enum dwarf_attribute, const char *);
@@ -3650,7 +3720,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_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 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 *);
 static void print_spaces (FILE *);
 static void print_die (dw_die_ref, FILE *);
 static void print_dwarf_line_table (FILE *);
@@ -3716,11 +3790,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 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 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 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);
 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);
@@ -3732,8 +3806,12 @@ static void add_AT_location_description  (dw_die_ref, enum dwarf_attribute,
                                         dw_loc_descr_ref);
 static void add_data_member_location_attribute (dw_die_ref, tree);
 static void add_const_value_attribute (dw_die_ref, rtx);
                                         dw_loc_descr_ref);
 static void add_data_member_location_attribute (dw_die_ref, tree);
 static void add_const_value_attribute (dw_die_ref, rtx);
+static void insert_int (HOST_WIDE_INT, unsigned, unsigned char *);
+static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
+static void insert_float (rtx, unsigned char *);
 static rtx rtl_for_decl_location (tree);
 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);
 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);
@@ -4566,16 +4644,17 @@ add_AT_long_long (dw_die_ref die, enum dwarf_attribute attr_kind,
 /* Add a floating point attribute value to a DIE and return it.  */
 
 static inline void
 /* Add a floating point attribute value to a DIE and return it.  */
 
 static inline void
-add_AT_float (dw_die_ref die, enum dwarf_attribute attr_kind,
-             unsigned int length, long int *array)
+add_AT_vec (dw_die_ref die, enum dwarf_attribute attr_kind,
+           unsigned int length, unsigned int elt_size, unsigned char *array)
 {
   dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
 
   attr->dw_attr_next = NULL;
   attr->dw_attr = attr_kind;
 {
   dw_attr_ref attr = ggc_alloc (sizeof (dw_attr_node));
 
   attr->dw_attr_next = NULL;
   attr->dw_attr = attr_kind;
-  attr->dw_attr_val.val_class = dw_val_class_float;
-  attr->dw_attr_val.v.val_float.length = length;
-  attr->dw_attr_val.v.val_float.array = array;
+  attr->dw_attr_val.val_class = dw_val_class_vec;
+  attr->dw_attr_val.v.val_vec.length = length;
+  attr->dw_attr_val.v.val_vec.elt_size = elt_size;
+  attr->dw_attr_val.v.val_vec.array = array;
   add_dwarf_attr (die, attr);
 }
 
   add_dwarf_attr (die, attr);
 }
 
@@ -5228,6 +5307,31 @@ lookup_decl_die (tree decl)
   return htab_find_with_hash (decl_die_table, decl, DECL_UID (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
 /* Equate a DIE to a particular declaration.  */
 
 static void
@@ -5240,6 +5344,45 @@ equate_decl_number_to_die (tree decl, dw_die_ref decl_die)
   *slot = decl_die;
   decl_die->decl_id = decl_id;
 }
   *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
 \f
 /* Keep track of the number of spaces used to indent the
    output of the debugging routines that print the structure of
@@ -5304,8 +5447,8 @@ print_die (dw_die_ref die, FILE *outfile)
                   a->dw_attr_val.v.val_long_long.hi,
                   a->dw_attr_val.v.val_long_long.low);
          break;
                   a->dw_attr_val.v.val_long_long.hi,
                   a->dw_attr_val.v.val_long_long.low);
          break;
-       case dw_val_class_float:
-         fprintf (outfile, "floating-point constant");
+       case dw_val_class_vec:
+         fprintf (outfile, "floating-point or vector constant");
          break;
        case dw_val_class_flag:
          fprintf (outfile, "%u", AT_flag (a));
          break;
        case dw_val_class_flag:
          fprintf (outfile, "%u", AT_flag (a));
@@ -5505,8 +5648,8 @@ attr_checksum (dw_attr_ref at, struct md5_ctx *ctx, int *mark)
     case dw_val_class_long_long:
       CHECKSUM (at->dw_attr_val.v.val_long_long);
       break;
     case dw_val_class_long_long:
       CHECKSUM (at->dw_attr_val.v.val_long_long);
       break;
-    case dw_val_class_float:
-      CHECKSUM (at->dw_attr_val.v.val_float);
+    case dw_val_class_vec:
+      CHECKSUM (at->dw_attr_val.v.val_vec);
       break;
     case dw_val_class_flag:
       CHECKSUM (at->dw_attr_val.v.val_flag);
       break;
     case dw_val_class_flag:
       CHECKSUM (at->dw_attr_val.v.val_flag);
@@ -5594,7 +5737,6 @@ same_dw_val_p (dw_val_node *v1, dw_val_node *v2, int *mark)
 {
   dw_loc_descr_ref loc1, loc2;
   rtx r1, r2;
 {
   dw_loc_descr_ref loc1, loc2;
   rtx r1, r2;
-  unsigned i;
 
   if (v1->val_class != v2->val_class)
     return 0;
 
   if (v1->val_class != v2->val_class)
     return 0;
@@ -5608,12 +5750,13 @@ same_dw_val_p (dw_val_node *v1, dw_val_node *v2, int *mark)
     case dw_val_class_long_long:
       return v1->v.val_long_long.hi == v2->v.val_long_long.hi
             && v1->v.val_long_long.low == v2->v.val_long_long.low;
     case dw_val_class_long_long:
       return v1->v.val_long_long.hi == v2->v.val_long_long.hi
             && v1->v.val_long_long.low == v2->v.val_long_long.low;
-    case dw_val_class_float:
-      if (v1->v.val_float.length != v2->v.val_float.length)
+    case dw_val_class_vec:
+      if (v1->v.val_vec.length != v2->v.val_vec.length
+         || v1->v.val_vec.elt_size != v2->v.val_vec.elt_size)
+       return 0;
+      if (memcmp (v1->v.val_vec.array, v2->v.val_vec.array,
+                 v1->v.val_vec.length * v1->v.val_vec.elt_size))
        return 0;
        return 0;
-      for (i = 0; i < v1->v.val_float.length; i++)
-       if (v1->v.val_float.array[i] != v2->v.val_float.array[i])
-         return 0;
       return 1;
     case dw_val_class_flag:
       return v1->v.val_flag == v2->v.val_flag;
       return 1;
     case dw_val_class_flag:
       return v1->v.val_flag == v2->v.val_flag;
@@ -6207,8 +6350,9 @@ size_of_die (dw_die_ref die)
        case dw_val_class_long_long:
          size += 1 + 2*HOST_BITS_PER_LONG/HOST_BITS_PER_CHAR; /* block */
          break;
        case dw_val_class_long_long:
          size += 1 + 2*HOST_BITS_PER_LONG/HOST_BITS_PER_CHAR; /* block */
          break;
-       case dw_val_class_float:
-         size += 1 + a->dw_attr_val.v.val_float.length * 4; /* block */
+       case dw_val_class_vec:
+         size += 1 + (a->dw_attr_val.v.val_vec.length
+                      * a->dw_attr_val.v.val_vec.elt_size); /* block */
          break;
        case dw_val_class_flag:
          size += 1;
          break;
        case dw_val_class_flag:
          size += 1;
@@ -6402,7 +6546,7 @@ value_format (dw_attr_ref a)
        }
     case dw_val_class_long_long:
       return DW_FORM_block1;
        }
     case dw_val_class_long_long:
       return DW_FORM_block1;
-    case dw_val_class_float:
+    case dw_val_class_vec:
       return DW_FORM_block1;
     case dw_val_class_flag:
       return DW_FORM_flag;
       return DW_FORM_block1;
     case dw_val_class_flag:
       return DW_FORM_flag;
@@ -6488,7 +6632,7 @@ output_die_symbol (dw_die_ref die)
     /* We make these global, not weak; if the target doesn't support
        .linkonce, it doesn't support combining the sections, so debugging
        will break.  */
     /* We make these global, not weak; if the target doesn't support
        .linkonce, it doesn't support combining the sections, so debugging
        will break.  */
-    (*targetm.asm_out.globalize_label) (asm_out_file, sym);
+    targetm.asm_out.globalize_label (asm_out_file, sym);
 
   ASM_OUTPUT_LABEL (asm_out_file, sym);
 }
 
   ASM_OUTPUT_LABEL (asm_out_file, sym);
 }
@@ -6539,28 +6683,28 @@ output_loc_list (dw_loc_list_ref list_head)
 
   ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
 
 
   ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
 
-  /* ??? 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,
-                          "Location list base address specifier fake entry");
-      dw2_asm_output_offset (DWARF2_ADDR_SIZE, curr->section,
-                            "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;
   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);
+      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.  */
       size = size_of_locs (curr->expr);
 
       /* Output the block length for this list of location operations.  */
@@ -6571,10 +6715,10 @@ output_loc_list (dw_loc_list_ref list_head)
       output_loc_sequence (curr->expr);
     }
 
       output_loc_sequence (curr->expr);
     }
 
-  dw2_asm_output_data (DWARF_OFFSET_SIZE, 0,
+  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
                       "Location list terminator begin (%s)",
                       list_head->ll_symbol);
                       "Location list terminator begin (%s)",
                       list_head->ll_symbol);
-  dw2_asm_output_data (DWARF_OFFSET_SIZE, 0,
+  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0,
                       "Location list terminator end (%s)",
                       list_head->ll_symbol);
 }
                       "Location list terminator end (%s)",
                       list_head->ll_symbol);
 }
@@ -6671,16 +6815,24 @@ output_die (dw_die_ref die)
          }
          break;
 
          }
          break;
 
-       case dw_val_class_float:
+       case dw_val_class_vec:
          {
          {
+           unsigned int elt_size = a->dw_attr_val.v.val_vec.elt_size;
+           unsigned int len = a->dw_attr_val.v.val_vec.length;
            unsigned int i;
            unsigned int i;
+           unsigned char *p;
 
 
-           dw2_asm_output_data (1, a->dw_attr_val.v.val_float.length * 4,
-                                "%s", name);
-
-           for (i = 0; i < a->dw_attr_val.v.val_float.length; i++)
-             dw2_asm_output_data (4, a->dw_attr_val.v.val_float.array[i],
-                                  "fp constant word %u", i);
+           dw2_asm_output_data (1, len * elt_size, "%s", name);
+           if (elt_size > sizeof (HOST_WIDE_INT))
+             {
+               elt_size /= 2;
+               len *= 2;
+             }
+           for (i = 0, p = a->dw_attr_val.v.val_vec.array;
+                i < len;
+                i++, p += elt_size)
+             dw2_asm_output_data (elt_size, extract_int (p, elt_size),
+                                  "fp or vector constant word %u", i);
            break;
          }
 
            break;
          }
 
@@ -6694,8 +6846,7 @@ output_die (dw_die_ref die)
 
            if (sym == 0)
              abort ();
 
            if (sym == 0)
              abort ();
-           dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym,
-                                 loc_section_label, "%s", name);
+           dw2_asm_output_offset (DWARF_OFFSET_SIZE, sym, "%s", name);
          }
          break;
 
          }
          break;
 
@@ -6832,7 +6983,7 @@ output_comp_unit (dw_die_ref die, int output_if_empty)
 static const char *
 dwarf2_name (tree decl, int scope)
 {
 static const char *
 dwarf2_name (tree decl, int scope)
 {
-  return (*lang_hooks.decl_printable_name) (decl, scope ? 1 : 0);
+  return lang_hooks.decl_printable_name (decl, scope ? 1 : 0);
 }
 
 /* Add a new entry to .debug_pubnames if appropriate.  */
 }
 
 /* Add a new entry to .debug_pubnames if appropriate.  */
@@ -7702,7 +7853,7 @@ base_type_die (tree type)
                 || ! strcmp (type_name, "signed char")
                 || ! strcmp (type_name, "unsigned char"))))
        {
                 || ! strcmp (type_name, "signed char")
                 || ! strcmp (type_name, "unsigned char"))))
        {
-         if (TREE_UNSIGNED (type))
+         if (TYPE_UNSIGNED (type))
            encoding = DW_ATE_unsigned;
          else
            encoding = DW_ATE_signed;
            encoding = DW_ATE_unsigned;
          else
            encoding = DW_ATE_signed;
@@ -7712,7 +7863,7 @@ base_type_die (tree type)
 
     case CHAR_TYPE:
       /* GNU Pascal/Ada CHAR type.  Not used in C.  */
 
     case CHAR_TYPE:
       /* GNU Pascal/Ada CHAR type.  Not used in C.  */
-      if (TREE_UNSIGNED (type))
+      if (TYPE_UNSIGNED (type))
        encoding = DW_ATE_unsigned_char;
       else
        encoding = DW_ATE_signed_char;
        encoding = DW_ATE_unsigned_char;
       else
        encoding = DW_ATE_signed_char;
@@ -7849,15 +8000,51 @@ is_subrange_type (tree type)
 {
   tree subtype = TREE_TYPE (type);
 
 {
   tree subtype = TREE_TYPE (type);
 
-  if (TREE_CODE (type) == INTEGER_TYPE
-      && subtype != NULL_TREE)
+  /* Subrange types are identified by the fact that they are integer
+     types, and that they have a subtype which is either an integer type
+     or an enumeral type.  */
+
+  if (TREE_CODE (type) != INTEGER_TYPE
+      || subtype == NULL_TREE)
+    return false;
+
+  if (TREE_CODE (subtype) != INTEGER_TYPE
+      && TREE_CODE (subtype) != ENUMERAL_TYPE)
+    return false;
+
+  if (TREE_CODE (type) == TREE_CODE (subtype)
+      && int_size_in_bytes (type) == int_size_in_bytes (subtype)
+      && TYPE_MIN_VALUE (type) != NULL
+      && TYPE_MIN_VALUE (subtype) != NULL
+      && tree_int_cst_equal (TYPE_MIN_VALUE (type), TYPE_MIN_VALUE (subtype))
+      && TYPE_MAX_VALUE (type) != NULL
+      && TYPE_MAX_VALUE (subtype) != NULL
+      && tree_int_cst_equal (TYPE_MAX_VALUE (type), TYPE_MAX_VALUE (subtype)))
     {
     {
-      if (TREE_CODE (subtype) == INTEGER_TYPE)
-        return true;
-      if (TREE_CODE (subtype) == ENUMERAL_TYPE)
-        return true;
+      /* The type and its subtype have the same representation.  If in
+         addition the two types also have the same name, then the given
+         type is not a subrange type, but rather a plain base type.  */
+      /* FIXME: brobecker/2004-03-22:
+         Sizetype INTEGER_CSTs nodes are canonicalized.  It should
+         therefore be sufficient to check the TYPE_SIZE node pointers
+         rather than checking the actual size.  Unfortunately, we have
+         found some cases, such as in the Ada "integer" type, where
+         this is not the case.  Until this problem is solved, we need to
+         keep checking the actual size.  */
+      tree type_name = TYPE_NAME (type);
+      tree subtype_name = TYPE_NAME (subtype);
+
+      if (type_name != NULL && TREE_CODE (type_name) == TYPE_DECL)
+        type_name = DECL_NAME (type_name);
+
+      if (subtype_name != NULL && TREE_CODE (subtype_name) == TYPE_DECL)
+        subtype_name = DECL_NAME (subtype_name);
+
+      if (type_name == subtype_name)
+        return false;
     }
     }
-  return false;
+
+  return true;
 }
 
 /*  Given a pointer to a tree node for a subrange type, return a pointer
 }
 
 /*  Given a pointer to a tree node for a subrange type, return a pointer
@@ -7870,14 +8057,15 @@ subrange_type_die (tree type, dw_die_ref context_die)
   dw_die_ref subrange_die;
   tree name = TYPE_NAME (type);
   const HOST_WIDE_INT size_in_bytes = int_size_in_bytes (type);
   dw_die_ref subrange_die;
   tree name = TYPE_NAME (type);
   const HOST_WIDE_INT size_in_bytes = int_size_in_bytes (type);
+  tree subtype = TREE_TYPE (type);
 
   if (context_die == NULL)
     context_die = comp_unit_die;
 
 
   if (context_die == NULL)
     context_die = comp_unit_die;
 
-  if (TREE_CODE (TREE_TYPE (type)) == ENUMERAL_TYPE)
-    subtype_die = gen_enumeration_type_die (TREE_TYPE (type), context_die);
+  if (TREE_CODE (subtype) == ENUMERAL_TYPE)
+    subtype_die = gen_enumeration_type_die (subtype, context_die);
   else
   else
-    subtype_die = base_type_die (TREE_TYPE (type));
+    subtype_die = base_type_die (subtype);
 
   subrange_die = new_die (DW_TAG_subrange_type, context_die, type);
 
 
   subrange_die = new_die (DW_TAG_subrange_type, context_die, type);
 
@@ -7888,7 +8076,7 @@ subrange_type_die (tree type, dw_die_ref context_die)
       add_name_attribute (subrange_die, IDENTIFIER_POINTER (name));
     }
 
       add_name_attribute (subrange_die, IDENTIFIER_POINTER (name));
     }
 
-  if (int_size_in_bytes (TREE_TYPE (type)) != size_in_bytes)
+  if (int_size_in_bytes (subtype) != size_in_bytes)
     {
       /* The size of the subrange type and its base type do not match,
          so we need to generate a size attribute for the subrange type.  */
     {
       /* The size of the subrange type and its base type do not match,
          so we need to generate a size attribute for the subrange type.  */
@@ -8078,7 +8266,7 @@ reg_loc_descriptor (rtx rtl)
     return 0;
 
   reg = reg_number (rtl);
     return 0;
 
   reg = reg_number (rtl);
-  regs = (*targetm.dwarf_register_span) (rtl);
+  regs = targetm.dwarf_register_span (rtl);
 
   if (hard_regno_nregs[reg][GET_MODE (rtl)] > 1
       || regs)
 
   if (hard_regno_nregs[reg][GET_MODE (rtl)] > 1
       || regs)
@@ -8192,7 +8380,7 @@ int_loc_descriptor (HOST_WIDE_INT i)
 /* Return a location descriptor that designates a base+offset location.  */
 
 static dw_loc_descr_ref
 /* 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
 {
   dw_loc_descr_ref loc_result;
   /* For the "frame base", we use the frame pointer or stack pointer
@@ -8202,7 +8390,7 @@ based_loc_descr (unsigned int reg, HOST_WIDE_INT offset)
                                         ? HARD_FRAME_POINTER_REGNUM
                                         : STACK_POINTER_REGNUM);
 
                                         ? 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);
     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);
@@ -8236,10 +8424,15 @@ is_based_loc (rtx rtl)
    MODE is the mode of the memory reference, needed to handle some
    autoincrement addressing modes.
 
    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
    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;
 
 {
   dw_loc_descr_ref mem_loc_result = NULL;
 
@@ -8248,7 +8441,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode)
      actually within the array.  That's *not* necessarily the same as the
      zeroth element of the array.  */
 
      actually within the array.  That's *not* necessarily the same as the
      zeroth element of the array.  */
 
-  rtl = (*targetm.delegitimize_address) (rtl);
+  rtl = targetm.delegitimize_address (rtl);
 
   switch (GET_CODE (rtl))
     {
 
   switch (GET_CODE (rtl))
     {
@@ -8285,11 +8478,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)
         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:
       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;
       if (mem_loc_result != 0)
        add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
       break;
@@ -8356,10 +8550,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)),
     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
        {
       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;
 
          if (mem_loc_result == 0)
            break;
 
@@ -8371,7 +8567,8 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode)
          else
            {
              add_loc_descr (&mem_loc_result,
          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));
            }
              add_loc_descr (&mem_loc_result,
                             new_loc_descr (DW_OP_plus, 0, 0));
            }
@@ -8382,8 +8579,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.  */
       {
        /* 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;
 
        if (op0 == 0 || op1 == 0)
          break;
@@ -8402,7 +8601,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)
       /* 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;
 
       else
        return 0;
 
@@ -8420,8 +8620,8 @@ static dw_loc_descr_ref
 concat_loc_descriptor (rtx x0, rtx x1)
 {
   dw_loc_descr_ref cc_loc_result = NULL;
 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;
 
   if (x0_ref == 0 || x1_ref == 0)
     return 0;
@@ -8448,7 +8648,7 @@ concat_loc_descriptor (rtx x0, rtx x1)
    If we don't know how to describe it, return 0.  */
 
 static dw_loc_descr_ref
    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;
 
 {
   dw_loc_descr_ref loc_result = NULL;
 
@@ -8469,13 +8669,49 @@ loc_descriptor (rtx rtl)
       break;
 
     case MEM:
       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;
 
       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 ();
     }
     default:
       abort ();
     }
@@ -8493,7 +8729,7 @@ loc_descriptor_from_tree (tree loc, int addressp)
 {
   dw_loc_descr_ref ret, ret1;
   int indirect_p = 0;
 {
   dw_loc_descr_ref ret, ret1;
   int indirect_p = 0;
-  int unsignedp = TREE_UNSIGNED (TREE_TYPE (loc));
+  int unsignedp = TYPE_UNSIGNED (TREE_TYPE (loc));
   enum dwarf_location_atom op;
 
   /* ??? Most of the time we do not take proper care for sign/zero
   enum dwarf_location_atom op;
 
   /* ??? Most of the time we do not take proper care for sign/zero
@@ -8505,7 +8741,6 @@ loc_descriptor_from_tree (tree loc, int addressp)
     case ERROR_MARK:
       return 0;
 
     case ERROR_MARK:
       return 0;
 
-    case WITH_RECORD_EXPR:
     case PLACEHOLDER_EXPR:
       /* This case involves extracting fields from an object to determine the
         position of other fields.  We don't try to encode this here.  The
     case PLACEHOLDER_EXPR:
       /* This case involves extracting fields from an object to determine the
         position of other fields.  We don't try to encode this here.  The
@@ -8516,6 +8751,13 @@ loc_descriptor_from_tree (tree loc, int addressp)
     case CALL_EXPR:
       return 0;
 
     case CALL_EXPR:
       return 0;
 
+    case PREINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      /* There are no opcodes for these operations.  */
+      return 0;
+
     case ADDR_EXPR:
       /* We can support this only if we can look through conversions and
         find an INDIRECT_EXPR.  */
     case ADDR_EXPR:
       /* We can support this only if we can look through conversions and
         find an INDIRECT_EXPR.  */
@@ -8591,7 +8833,7 @@ loc_descriptor_from_tree (tree loc, int addressp)
                rtl = XEXP (rtl, 0);
              }
 
                rtl = XEXP (rtl, 0);
              }
 
-           ret = mem_loc_descriptor (rtl, mode);
+           ret = mem_loc_descriptor (rtl, mode, true);
          }
       }
       break;
          }
       }
       break;
@@ -8672,10 +8914,10 @@ loc_descriptor_from_tree (tree loc, int addressp)
        mode = GET_MODE (rtl);
        rtl = XEXP (rtl, 0);
 
        mode = GET_MODE (rtl);
        rtl = XEXP (rtl, 0);
 
-       rtl = (*targetm.delegitimize_address) (rtl);
+       rtl = targetm.delegitimize_address (rtl);
 
        indirect_p = 1;
 
        indirect_p = 1;
-       ret = mem_loc_descriptor (rtl, mode);
+       ret = mem_loc_descriptor (rtl, mode, true);
        break;
       }
 
        break;
       }
 
@@ -8746,28 +8988,28 @@ loc_descriptor_from_tree (tree loc, int addressp)
       goto do_binop;
 
     case LE_EXPR:
       goto do_binop;
 
     case LE_EXPR:
-      if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+      if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
        return 0;
 
       op = DW_OP_le;
       goto do_binop;
 
     case GE_EXPR:
        return 0;
 
       op = DW_OP_le;
       goto do_binop;
 
     case GE_EXPR:
-      if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+      if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
        return 0;
 
       op = DW_OP_ge;
       goto do_binop;
 
     case LT_EXPR:
        return 0;
 
       op = DW_OP_ge;
       goto do_binop;
 
     case LT_EXPR:
-      if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+      if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
        return 0;
 
       op = DW_OP_lt;
       goto do_binop;
 
     case GT_EXPR:
        return 0;
 
       op = DW_OP_lt;
       goto do_binop;
 
     case GT_EXPR:
-      if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+      if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
        return 0;
 
       op = DW_OP_gt;
        return 0;
 
       op = DW_OP_gt;
@@ -8812,11 +9054,17 @@ loc_descriptor_from_tree (tree loc, int addressp)
       add_loc_descr (&ret, new_loc_descr (op, 0, 0));
       break;
 
       add_loc_descr (&ret, new_loc_descr (op, 0, 0));
       break;
 
+    case MIN_EXPR:
     case MAX_EXPR:
     case MAX_EXPR:
-      loc = build (COND_EXPR, TREE_TYPE (loc),
-                  build (LT_EXPR, integer_type_node,
-                         TREE_OPERAND (loc, 0), TREE_OPERAND (loc, 1)),
-                  TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0));
+      {
+        const enum tree_code code =
+          TREE_CODE (loc) == MIN_EXPR ? GT_EXPR : LT_EXPR;
+
+        loc = build (COND_EXPR, TREE_TYPE (loc),
+                     build (code, integer_type_node,
+                            TREE_OPERAND (loc, 0), TREE_OPERAND (loc, 1)),
+                     TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0));
+      }
 
       /* ... fall through ...  */
 
 
       /* ... fall through ...  */
 
@@ -8851,6 +9099,9 @@ loc_descriptor_from_tree (tree loc, int addressp)
       }
       break;
 
       }
       break;
 
+    case EXPR_WITH_FILE_LOCATION:
+      return loc_descriptor_from_tree (EXPR_WFL_NODE (loc), addressp);
+
     default:
       /* Leave front-end specific codes as simply unknown.  This comes
         up, for instance, with the C STMT_EXPR.  */
     default:
       /* Leave front-end specific codes as simply unknown.  This comes
         up, for instance, with the C STMT_EXPR.  */
@@ -9160,6 +9411,56 @@ add_data_member_location_attribute (dw_die_ref die, tree decl)
   add_AT_loc (die, DW_AT_data_member_location, loc_descr);
 }
 
   add_AT_loc (die, DW_AT_data_member_location, loc_descr);
 }
 
+/* Writes integer values to dw_vec_const array.  */
+
+static void
+insert_int (HOST_WIDE_INT val, unsigned int size, unsigned char *dest)
+{
+  while (size != 0)
+    {
+      *dest++ = val & 0xff;
+      val >>= 8;
+      --size;
+    }
+}
+
+/* Reads integers from dw_vec_const array.  Inverse of insert_int.  */
+
+static HOST_WIDE_INT
+extract_int (const unsigned char *src, unsigned int size)
+{
+  HOST_WIDE_INT val = 0;
+
+  src += size;
+  while (size != 0)
+    {
+      val <<= 8;
+      val |= *--src & 0xff;
+      --size;
+    }
+  return val;
+}
+
+/* Writes floating point values to dw_vec_const array.  */
+
+static void
+insert_float (rtx rtl, unsigned char *array)
+{
+  REAL_VALUE_TYPE rv;
+  long val[4];
+  int i;
+
+  REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl);
+  real_to_target (val, &rv, GET_MODE (rtl));
+
+  /* real_to_target puts 32-bit pieces in each long.  Pack them.  */
+  for (i = 0; i < GET_MODE_SIZE (GET_MODE (rtl)) / 4; i++)
+    {
+      insert_int (val[i], 4, array);
+      array += 4;
+    }
+}
+
 /* Attach a DW_AT_const_value attribute for a variable or a parameter which
    does not have a "location" either in memory or in a register.  These
    things can arise in GNU C when a constant is passed as an actual parameter
 /* Attach a DW_AT_const_value attribute for a variable or a parameter which
    does not have a "location" either in memory or in a register.  These
    things can arise in GNU C when a constant is passed as an actual parameter
@@ -9192,14 +9493,11 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
 
        if (GET_MODE_CLASS (mode) == MODE_FLOAT)
          {
 
        if (GET_MODE_CLASS (mode) == MODE_FLOAT)
          {
-           unsigned length = GET_MODE_SIZE (mode) / 4;
-           long *array = ggc_alloc (sizeof (long) * length);
-           REAL_VALUE_TYPE rv;
-
-           REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl);
-           real_to_target (array, &rv, mode);
+           unsigned int length = GET_MODE_SIZE (mode);
+           unsigned char *array = ggc_alloc (length);
 
 
-           add_AT_float (die, DW_AT_const_value, length, array);
+           insert_float (rtl, array);
+           add_AT_vec (die, DW_AT_const_value, length / 4, 4, array);
          }
        else
          {
          }
        else
          {
@@ -9213,6 +9511,68 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
       }
       break;
 
       }
       break;
 
+    case CONST_VECTOR:
+      {
+       enum machine_mode mode = GET_MODE (rtl);
+       unsigned int elt_size = GET_MODE_UNIT_SIZE (mode);
+       unsigned int length = CONST_VECTOR_NUNITS (rtl);
+       unsigned char *array = ggc_alloc (length * elt_size);
+       unsigned int i;
+       unsigned char *p;
+
+       if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
+         {
+           for (i = 0, p = array; i < length; i++, p += elt_size)
+             {
+               rtx elt = CONST_VECTOR_ELT (rtl, i);
+               HOST_WIDE_INT lo, hi;
+               if (GET_CODE (elt) == CONST_INT)
+                 {
+                   lo = INTVAL (elt);
+                   hi = -(lo < 0);
+                 }
+               else if (GET_CODE (elt) == CONST_DOUBLE)
+                 {
+                   lo = CONST_DOUBLE_LOW (elt);
+                   hi = CONST_DOUBLE_HIGH (elt);
+                 }
+               else
+                 abort ();
+
+               if (elt_size <= sizeof (HOST_WIDE_INT))
+                 insert_int (lo, elt_size, p);
+               else if (elt_size == 2 * sizeof (HOST_WIDE_INT))
+                 {
+                   unsigned char *p0 = p;
+                   unsigned char *p1 = p + sizeof (HOST_WIDE_INT);
+
+                   if (WORDS_BIG_ENDIAN)
+                     {
+                       p0 = p1;
+                       p1 = p;
+                     }
+                   insert_int (lo, sizeof (HOST_WIDE_INT), p0);
+                   insert_int (hi, sizeof (HOST_WIDE_INT), p1);
+                 }
+               else
+                 abort ();
+             }
+         }
+       else if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+         {
+           for (i = 0, p = array; i < length; i++, p += elt_size)
+             {
+               rtx elt = CONST_VECTOR_ELT (rtl, i);
+               insert_float (elt, p);
+             }
+         }
+       else
+         abort ();
+
+       add_AT_vec (die, DW_AT_const_value, length, elt_size, array);
+      }
+      break;
+
     case CONST_STRING:
       add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0));
       break;
     case CONST_STRING:
       add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0));
       break;
@@ -9339,7 +9699,7 @@ rtl_for_decl_location (tree decl)
                  && TREE_CODE (decl) == VAR_DECL
                  && TREE_STATIC (decl))))
        {
                  && TREE_CODE (decl) == VAR_DECL
                  && TREE_STATIC (decl))))
        {
-         rtl = (*targetm.delegitimize_address) (rtl);
+         rtl = targetm.delegitimize_address (rtl);
          return rtl;
        }
       rtl = NULL_RTX;
          return rtl;
        }
       rtl = NULL_RTX;
@@ -9446,7 +9806,7 @@ rtl_for_decl_location (tree decl)
     }
 
   if (rtl)
     }
 
   if (rtl)
-    rtl = (*targetm.delegitimize_address) (rtl);
+    rtl = targetm.delegitimize_address (rtl);
 
   /* If we don't look past the constant pool, we risk emitting a
      reference to a constant pool entry that isn't referenced from
 
   /* If we don't look past the constant pool, we risk emitting a
      reference to a constant pool entry that isn't referenced from
@@ -9469,16 +9829,110 @@ rtl_for_decl_location (tree decl)
    function call evaluates to a compile-time constant address.  */
 
 static void
    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;
 {
   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 ();
 
 
   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_label;
+
+      /* 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;
   rtl = rtl_for_decl_location (decl);
   if (rtl == NULL_RTX)
     return;
@@ -9492,6 +9946,7 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl)
 
     case CONST_INT:
     case CONST_DOUBLE:
 
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CONST_STRING:
     case SYMBOL_REF:
     case LABEL_REF:
     case CONST_STRING:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -9515,9 +9970,9 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl)
        case REG:
        case SUBREG:
        case CONCAT:
        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:
       break;
 
     case PARALLEL:
@@ -9528,7 +9983,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.  */
        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));
        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));
@@ -9536,7 +9991,7 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl)
          {
            dw_loc_descr_ref temp;
 
          {
            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,
            add_loc_descr (&descr, temp);
            mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
            add_loc_descr (&descr,
@@ -9626,7 +10081,7 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
          || (bound_attr == DW_AT_lower_bound
              && (((is_c_family () || is_java ()) &&  integer_zerop (bound))
                  || (is_fortran () && integer_onep (bound)))))
          || (bound_attr == DW_AT_lower_bound
              && (((is_c_family () || is_java ()) &&  integer_zerop (bound))
                  || (is_fortran () && integer_onep (bound)))))
-       /* use the default */
+       /* Use the default.  */
        ;
       else
        add_AT_unsigned (subrange_die, bound_attr, tree_low_cst (bound, 0));
        ;
       else
        add_AT_unsigned (subrange_die, bound_attr, tree_low_cst (bound, 0));
@@ -9682,7 +10137,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,
          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);
        }
 
          add_AT_die_ref (subrange_die, bound_attr, decl_die);
        }
 
@@ -10440,24 +10895,24 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die)
       if (type_die->die_parent == NULL)
        add_child_die (scope_die_for (type, context_die), type_die);
 
       if (type_die->die_parent == NULL)
        add_child_die (scope_die_for (type, context_die), type_die);
 
-      for (link = TYPE_FIELDS (type);
+      for (link = TYPE_VALUES (type);
           link != NULL; link = TREE_CHAIN (link))
        {
          dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die, link);
           link != NULL; link = TREE_CHAIN (link))
        {
          dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die, link);
+         tree value = TREE_VALUE (link);
 
          add_name_attribute (enum_die,
                              IDENTIFIER_POINTER (TREE_PURPOSE (link)));
 
 
          add_name_attribute (enum_die,
                              IDENTIFIER_POINTER (TREE_PURPOSE (link)));
 
-         if (host_integerp (TREE_VALUE (link), 
-                            TREE_UNSIGNED (TREE_TYPE (TREE_VALUE (link)))))
-           {
-             if (tree_int_cst_sgn (TREE_VALUE (link)) < 0)
-               add_AT_int (enum_die, DW_AT_const_value,
-                           tree_low_cst (TREE_VALUE (link), 0));
-             else
-               add_AT_unsigned (enum_die, DW_AT_const_value,
-                                tree_low_cst (TREE_VALUE (link), 1));
-           }
+         if (host_integerp (value, TYPE_UNSIGNED (TREE_TYPE (value))))
+           /* DWARF2 does not provide a way of indicating whether or
+              not enumeration constants are signed or unsigned.  GDB
+              always assumes the values are signed, so we output all
+              values as if they were signed.  That means that
+              enumeration constants with very large unsigned values
+              will appear to have negative values in the debugger.  */
+           add_AT_int (enum_die, DW_AT_const_value,
+                       tree_low_cst (value, tree_int_cst_sgn (value) > 0));
        }
     }
   else
        }
     }
   else
@@ -10505,7 +10960,7 @@ gen_formal_parameter_die (tree node, dw_die_ref context_die)
 
       equate_decl_number_to_die (node, parm_die);
       if (! DECL_ABSTRACT (node))
 
       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;
 
 
       break;
 
@@ -10839,9 +11294,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.  */
       /* 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
 
 #if 0
       /* ??? This fails for nested inline functions, because context_display
@@ -11010,7 +11473,7 @@ gen_variable_die (tree decl, dw_die_ref context_die)
 
   if (! declaration && ! DECL_ABSTRACT (decl))
     {
 
   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
       add_pubname (decl, var_die);
     }
   else
@@ -11958,7 +12421,7 @@ force_type_die (tree type)
 {
   dw_die_ref type_die;
 
 {
   dw_die_ref type_die;
 
-  type_die = lookup_type_die (root_type (type));
+  type_die = lookup_type_die (type);
   if (!type_die)
     {
       dw_die_ref context_die;
   if (!type_die)
     {
       dw_die_ref context_die;
@@ -11971,7 +12434,7 @@ force_type_die (tree type)
        context_die = comp_unit_die;
 
       gen_type_die (type, context_die);
        context_die = comp_unit_die;
 
       gen_type_die (type, context_die);
-      type_die = lookup_type_die (root_type (type));
+      type_die = lookup_type_die (type);
       if (!type_die)
        abort();
     }
       if (!type_die)
        abort();
     }
@@ -12181,9 +12644,10 @@ gen_decl_die (tree decl, dw_die_ref context_die)
 
     case FIELD_DECL:
       /* Ignore the nameless fields that are used to skip bits but handle C++
 
     case FIELD_DECL:
       /* Ignore the nameless fields that are used to skip bits but handle C++
-        anonymous unions.  */
+        anonymous unions and structs.  */
       if (DECL_NAME (decl) != NULL_TREE
       if (DECL_NAME (decl) != NULL_TREE
-         || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE)
+         || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
+         || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE)
        {
          gen_type_die (member_declared_type (decl), context_die);
          gen_field_die (decl, context_die);
        {
          gen_type_die (member_declared_type (decl), context_die);
          gen_field_die (decl, context_die);
@@ -12243,6 +12707,15 @@ dwarf2out_global_decl (tree decl)
     dwarf2out_decl (decl);
 }
 
     dwarf2out_decl (decl);
 }
 
+/* Output debug information for type decl DECL.  Called from toplev.c
+   and from language front ends (to record built-in types).  */
+static void
+dwarf2out_type_decl (tree decl, int local)
+{
+  if (!local)
+    dwarf2out_decl (decl);
+}
+
 /* Output debug information for imported module or decl.  */ 
  
 static void
 /* Output debug information for imported module or decl.  */ 
  
 static void
@@ -12302,12 +12775,6 @@ dwarf2out_decl (tree decl)
       return;
 
     case FUNCTION_DECL:
       return;
 
     case FUNCTION_DECL:
-      /* Ignore this FUNCTION_DECL if it refers to a builtin declaration of a
-        builtin function.  Explicit programmer-supplied declarations of
-        these same functions should NOT be ignored however.  */
-      if (DECL_EXTERNAL (decl) && DECL_BUILT_IN (decl))
-       return;
-
       /* What we would really like to do here is to filter out all mere
         file-scope declarations of file-scope functions which are never
         referenced later within this translation unit (and keep all of ones
       /* What we would really like to do here is to filter out all mere
         file-scope declarations of file-scope functions which are never
         referenced later within this translation unit (and keep all of ones
@@ -12529,6 +12996,61 @@ init_file_table (void)
   file_table_last_lookup_index = 0;
 }
 
   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.  */
 /* 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.  */
@@ -12565,10 +13087,10 @@ dwarf2out_source_line (unsigned int line, const char *filename)
       else if (DECL_SECTION_NAME (current_function_decl))
        {
          dw_separate_line_info_ref line_info;
       else if (DECL_SECTION_NAME (current_function_decl))
        {
          dw_separate_line_info_ref line_info;
-         (*targetm.asm_out.internal_label) (asm_out_file, SEPARATE_LINE_CODE_LABEL,
+         targetm.asm_out.internal_label (asm_out_file, SEPARATE_LINE_CODE_LABEL,
                                     separate_line_info_table_in_use);
 
                                     separate_line_info_table_in_use);
 
-         /* expand the line info table if necessary */
+         /* Expand the line info table if necessary.  */
          if (separate_line_info_table_in_use
              == separate_line_info_table_allocated)
            {
          if (separate_line_info_table_in_use
              == separate_line_info_table_allocated)
            {
@@ -12595,7 +13117,7 @@ dwarf2out_source_line (unsigned int line, const char *filename)
        {
          dw_line_info_ref line_info;
 
        {
          dw_line_info_ref line_info;
 
-         (*targetm.asm_out.internal_label) (asm_out_file, LINE_CODE_LABEL,
+         targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL,
                                     line_info_table_in_use);
 
          /* Expand the line info table if necessary.  */
                                     line_info_table_in_use);
 
          /* Expand the line info table if necessary.  */
@@ -12701,10 +13223,14 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
 {
   init_file_table ();
 
 {
   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);
 
   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");
 
   /* Allocate the initial hunk of the decl_scope_table.  */
   VARRAY_TREE_INIT (decl_scope_table, 256, "decl_scope_table");
 
@@ -13099,7 +13625,7 @@ dwarf2out_finish (const char *filename)
 
   /* Output a terminator label for the .text section.  */
   text_section ();
 
   /* Output a terminator label for the .text section.  */
   text_section ();
-  (*targetm.asm_out.internal_label) (asm_out_file, TEXT_END_LABEL, 0);
+  targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0);
 
   /* Output the source line correspondence table.  We must do this
      even if there is no line information.  Otherwise, on an empty
 
   /* Output the source line correspondence table.  We must do this
      even if there is no line information.  Otherwise, on an empty