OSDN Git Service

* cgraph.c (hash_node, eq_node, cgraph_node, cgraph_remove_node)
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index e407a0b..92767ab 100644 (file)
@@ -149,7 +149,7 @@ collect2_eh_frame_section (void)
 
   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));
 }
 
@@ -243,6 +243,7 @@ typedef struct cfa_loc 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;
@@ -391,7 +392,9 @@ static void def_cfa_1 (const char *, dw_cfa_location *);
 #define FUNC_END_LABEL         "LFE"
 #endif
 
+#ifndef FRAME_BEGIN_LABEL
 #define FRAME_BEGIN_LABEL      "Lframe"
+#endif
 #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 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,
+                                     for_eh, /* 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
@@ -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;
+        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;
@@ -1966,7 +1988,7 @@ output_call_frame_info (int 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);
 
@@ -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.  */
 
-      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);
 
@@ -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)
+         && (! TARGET_USES_WEAK_UNWIND_INFO || ! DECL_ONE_ONLY (fde->decl))
          && !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, for_eh, /* 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,
@@ -2113,9 +2139,16 @@ output_call_frame_info (int 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");
@@ -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++];
+  fde->decl = current_function_decl;
   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_float,
+  dw_val_class_vec,
   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;
 
-/* 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 elt_size;
 }
-dw_float_const;
+dw_vec_const;
 
 /* 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;
-      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;
-      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;
@@ -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_type_decl (tree, int);
 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,10 +3307,11 @@ 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,
+  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
@@ -3281,7 +3320,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 +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;
 
+/* 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.  */
@@ -3562,6 +3627,9 @@ static GTY(()) unsigned ranges_table_in_use;
 /* 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;
@@ -3602,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 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 *);
@@ -3651,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_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 *);
@@ -3712,16 +3785,16 @@ static bool is_subrange_type (tree);
 static dw_die_ref subrange_type_die (tree, dw_die_ref);
 static dw_die_ref modified_type_die (tree, int, int, dw_die_ref);
 static int type_is_enum (tree);
-static unsigned int reg_number (rtx);
+static unsigned int dbx_reg_number (rtx);
 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);
@@ -3733,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);
+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 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);
@@ -4567,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_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;
-  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);
 }
 
@@ -4992,7 +5070,9 @@ is_fortran (void)
 {
   unsigned int lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
 
-  return lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90;
+  return (lang == DW_LANG_Fortran77
+         || lang == DW_LANG_Fortran90
+         || lang == DW_LANG_Fortran95);
 }
 
 /* Return TRUE if the language is Java.  */
@@ -5229,6 +5309,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 +5346,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
@@ -5305,8 +5449,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;
-       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));
@@ -5506,8 +5650,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_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);
@@ -5595,7 +5739,6 @@ same_dw_val_p (dw_val_node *v1, dw_val_node *v2, int *mark)
 {
   dw_loc_descr_ref loc1, loc2;
   rtx r1, r2;
-  unsigned i;
 
   if (v1->val_class != v2->val_class)
     return 0;
@@ -5609,12 +5752,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_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;
-      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;
@@ -6208,8 +6352,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_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;
@@ -6403,7 +6548,7 @@ value_format (dw_attr_ref a)
        }
     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;
@@ -6489,7 +6634,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.  */
-    (*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);
 }
@@ -6540,18 +6685,6 @@ output_loc_list (dw_loc_list_ref list_head)
 
   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)
     {
@@ -6684,16 +6817,24 @@ output_die (dw_die_ref die)
          }
          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 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;
          }
 
@@ -6844,7 +6985,7 @@ output_comp_unit (dw_die_ref die, int output_if_empty)
 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.  */
@@ -7714,7 +7855,7 @@ base_type_die (tree type)
                 || ! 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;
@@ -7724,7 +7865,7 @@ base_type_die (tree type)
 
     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;
@@ -7861,15 +8002,51 @@ is_subrange_type (tree 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
@@ -7882,14 +8059,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);
+  tree subtype = TREE_TYPE (type);
 
   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
-    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);
 
@@ -7900,7 +8078,7 @@ subrange_type_die (tree type, dw_die_ref context_die)
       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.  */
@@ -8064,10 +8242,10 @@ type_is_enum (tree type)
   return TREE_CODE (type) == ENUMERAL_TYPE;
 }
 
-/* Return the register number described by a given RTL node.  */
+/* Return the DBX register number described by a given RTL node.  */
 
 static unsigned int
-reg_number (rtx rtl)
+dbx_reg_number (rtx rtl)
 {
   unsigned regno = REGNO (rtl);
 
@@ -8089,10 +8267,10 @@ reg_loc_descriptor (rtx rtl)
   if (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
     return 0;
 
-  reg = reg_number (rtl);
-  regs = (*targetm.dwarf_register_span) (rtl);
+  reg = dbx_reg_number (rtl);
+  regs = targetm.dwarf_register_span (rtl);
 
-  if (hard_regno_nregs[reg][GET_MODE (rtl)] > 1
+  if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1
       || regs)
     return multiple_reg_loc_descriptor (rtl, regs);
   else
@@ -8121,8 +8299,8 @@ multiple_reg_loc_descriptor (rtx rtl, rtx regs)
   unsigned reg;
   dw_loc_descr_ref loc_result = NULL;
 
-  reg = reg_number (rtl);
-  nregs = hard_regno_nregs[reg][GET_MODE (rtl)];
+  reg = dbx_reg_number (rtl);
+  nregs = hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)];
 
   /* Simple, contiguous registers.  */
   if (regs == NULL_RTX)
@@ -8204,7 +8382,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 +8392,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,19 +8426,25 @@ 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;
+  enum dwarf_location_atom op;
 
   /* Note that for a dynamically sized array, the location we will generate a
      description of here will be the lowest numbered location which is
      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))
     {
@@ -8297,11 +8481,13 @@ 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 (dbx_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;
@@ -8367,11 +8553,13 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode)
     case PLUS:
     plus:
       if (is_based_loc (rtl))
-       mem_loc_result = based_loc_descr (reg_number (XEXP (rtl, 0)),
-                                         INTVAL (XEXP (rtl, 1)));
+       mem_loc_result = based_loc_descr (dbx_reg_number (XEXP (rtl, 0)),
+                                         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,26 +8571,45 @@ 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));
            }
        }
       break;
 
+    /* If a pseudo-reg is optimized away, it is possible for it to
+       be replaced with a MEM containing a multiply or shift.  */
     case MULT:
+      op = DW_OP_mul;
+      goto do_binop;
+
+    case ASHIFT:
+      op = DW_OP_shl;
+      goto do_binop;
+      
+    case ASHIFTRT:
+      op = DW_OP_shra;
+      goto do_binop;
+
+    case LSHIFTRT:
+      op = DW_OP_shr;
+      goto do_binop;
+
+    do_binop:
       {
-       /* 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;
 
        mem_loc_result = op0;
        add_loc_descr (&mem_loc_result, op1);
-       add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
+       add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0));
        break;
       }
 
@@ -8414,7 +8621,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 +8640,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 +8668,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 +8689,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 ();
     }
@@ -8505,7 +8749,7 @@ loc_descriptor_from_tree (tree loc, int addressp)
 {
   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
@@ -8517,7 +8761,6 @@ loc_descriptor_from_tree (tree loc, int addressp)
     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
@@ -8528,6 +8771,13 @@ loc_descriptor_from_tree (tree loc, int addressp)
     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.  */
@@ -8581,6 +8831,7 @@ loc_descriptor_from_tree (tree loc, int addressp)
       /* Fall through.  */
 
     case PARM_DECL:
+    case RESULT_DECL:
       {
        rtx rtl = rtl_for_decl_location (loc);
 
@@ -8603,7 +8854,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;
@@ -8684,10 +8935,10 @@ loc_descriptor_from_tree (tree loc, int addressp)
        mode = GET_MODE (rtl);
        rtl = XEXP (rtl, 0);
 
-       rtl = (*targetm.delegitimize_address) (rtl);
+       rtl = targetm.delegitimize_address (rtl);
 
        indirect_p = 1;
-       ret = mem_loc_descriptor (rtl, mode);
+       ret = mem_loc_descriptor (rtl, mode, true);
        break;
       }
 
@@ -8758,28 +9009,28 @@ loc_descriptor_from_tree (tree loc, int addressp)
       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:
-      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:
-      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:
-      if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+      if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
        return 0;
 
       op = DW_OP_gt;
@@ -8824,11 +9075,17 @@ loc_descriptor_from_tree (tree loc, int addressp)
       add_loc_descr (&ret, new_loc_descr (op, 0, 0));
       break;
 
+    case MIN_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 ...  */
 
@@ -9172,6 +9429,56 @@ add_data_member_location_attribute (dw_die_ref die, tree decl)
   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
@@ -9204,14 +9511,11 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
 
        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
          {
@@ -9225,6 +9529,68 @@ add_const_value_attribute (dw_die_ref die, rtx rtl)
       }
       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;
@@ -9330,10 +9696,7 @@ rtl_for_decl_location (tree decl)
      This happens (for example) for inlined-instances of inline function formal
      parameters which are never referenced.  This really shouldn't be
      happening.  All PARM_DECL nodes should get valid non-NULL
-     DECL_INCOMING_RTL values, but integrate.c doesn't currently generate these
-     values for inlined instances of inline function parameters, so when we see
-     such cases, we are just out-of-luck for the time being (until integrate.c
-     gets fixed).  */
+     DECL_INCOMING_RTL values.  FIXME.  */
 
   /* Use DECL_RTL as the "location" unless we find something better.  */
   rtl = DECL_RTL_IF_SET (decl);
@@ -9351,7 +9714,7 @@ rtl_for_decl_location (tree decl)
                  && TREE_CODE (decl) == VAR_DECL
                  && TREE_STATIC (decl))))
        {
-         rtl = (*targetm.delegitimize_address) (rtl);
+         rtl = targetm.delegitimize_address (rtl);
          return rtl;
        }
       rtl = NULL_RTX;
@@ -9408,6 +9771,25 @@ rtl_for_decl_location (tree decl)
                             plus_constant (XEXP (rtl, 0), offset));
        }
     }
+  else if (TREE_CODE (decl) == VAR_DECL
+          && rtl
+          && GET_CODE (rtl) == MEM
+          && GET_MODE (rtl) != TYPE_MODE (TREE_TYPE (decl))
+          && BYTES_BIG_ENDIAN)
+    {
+      int rsize = GET_MODE_SIZE (GET_MODE (rtl));
+      int dsize = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl)));
+
+      /* If a variable is declared "register" yet is smaller than
+        a register, then if we store the variable to memory, it
+        looks like we're storing a register-sized value, when in
+        fact we are not.  We need to adjust the offset of the
+        storage location to reflect the actual value's bytes,
+        else gdb will not be able to display it.  */
+      if (rsize > dsize)
+       rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (decl)),
+                          plus_constant (XEXP (rtl, 0), rsize-dsize));
+    }
 
   if (rtl != NULL_RTX)
     {
@@ -9458,7 +9840,7 @@ rtl_for_decl_location (tree decl)
     }
 
   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
@@ -9481,16 +9863,111 @@ 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)
+  else if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL
+          && TREE_CODE (decl) != RESULT_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;
@@ -9504,6 +9981,7 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl)
 
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case CONST_STRING:
     case SYMBOL_REF:
     case LABEL_REF:
@@ -9527,9 +10005,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 +10018,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 +10026,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,
@@ -9638,7 +10116,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)))))
-       /* use the default */
+       /* Use the default.  */
        ;
       else
        add_AT_unsigned (subrange_die, bound_attr, tree_low_cst (bound, 0));
@@ -9694,7 +10172,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);
        }
 
@@ -9703,6 +10181,7 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree b
 
     case VAR_DECL:
     case PARM_DECL:
+    case RESULT_DECL:
       {
        dw_die_ref decl_die = lookup_decl_die (bound);
 
@@ -10452,24 +10931,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);
 
-      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);
+         tree value = TREE_VALUE (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
@@ -10517,7 +10996,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,17 +11330,21 @@ 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
-        is not part of the state saved/restored for inline functions.  */
-      if (current_function_needs_context)
+      if (cfun->static_chain_decl)
        add_AT_location_description (subr_die, DW_AT_static_link,
-                            loc_descriptor (lookup_static_chain (decl)));
-#endif
+                loc_descriptor_from_tree (cfun->static_chain_decl, 0));
     }
 
   /* Now output descriptions of the arguments for this function. This gets
@@ -10937,6 +11420,10 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
      constructor function.  */
   if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK)
     {
+      /* Emit a DW_TAG_variable DIE for a named return value.  */
+      if (DECL_NAME (DECL_RESULT (decl)))
+       gen_decl_die (DECL_RESULT (decl), subr_die);
+
       current_function_has_inlines = 0;
       decls_for_scope (outer_scope, subr_die, 0);
 
@@ -11022,7 +11509,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
@@ -11281,6 +11768,8 @@ gen_compile_unit_die (const char *filename)
     language = DW_LANG_Ada95;
   else if (strcmp (language_string, "GNU F77") == 0)
     language = DW_LANG_Fortran77;
+  else if (strcmp (language_string, "GNU F95") == 0)
+    language = DW_LANG_Fortran95;
   else if (strcmp (language_string, "GNU Pascal") == 0)
     language = DW_LANG_Pascal83;
   else if (strcmp (language_string, "GNU Java") == 0)
@@ -12090,6 +12579,14 @@ gen_decl_die (tree decl, dw_die_ref context_die)
          && (current_function_decl == NULL_TREE || DECL_ARTIFICIAL (decl)))
        break;
 
+#if 0
+      /* FIXME */
+      /* This doesn't work because the C frontend sets DECL_ABSTRACT_ORIGIN
+        on local redeclarations of global functions.  That seems broken.  */
+      if (current_function_decl != decl)
+       /* This is only a declaration.  */;
+#endif
+
       /* If we're emitting a clone, emit info for the abstract instance.  */
       if (DECL_ORIGIN (decl) != decl)
        dwarf2out_abstract_function (DECL_ABSTRACT_ORIGIN (decl));
@@ -12163,6 +12660,7 @@ gen_decl_die (tree decl, dw_die_ref context_die)
       break;
 
     case VAR_DECL:
+    case RESULT_DECL:
       /* If we are in terse mode, don't generate any DIEs to represent any
         variable declarations or definitions.  */
       if (debug_info_level <= DINFO_LEVEL_TERSE)
@@ -12256,6 +12754,15 @@ dwarf2out_global_decl (tree 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
@@ -12284,8 +12791,8 @@ dwarf2out_imported_module_or_decl (tree decl, tree context)
   else
     scope_die = force_decl_die (context);
 
-  /* For TYPE_DECL, lookup TREE_TYPE.  */
-  if (TREE_CODE (decl) == TYPE_DECL)
+  /* For TYPE_DECL or CONST_DECL, lookup TREE_TYPE.  */
+  if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL)
     at_import_die = force_type_die (TREE_TYPE (decl));
   else
     at_import_die = force_decl_die (decl);
@@ -12315,12 +12822,6 @@ dwarf2out_decl (tree 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
@@ -12542,6 +13043,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.  */
@@ -12578,10 +13134,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;
-         (*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);
 
-         /* 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)
            {
@@ -12608,7 +13164,7 @@ dwarf2out_source_line (unsigned int line, const char *filename)
        {
          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.  */
@@ -12714,10 +13270,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");
 
@@ -13112,7 +13672,7 @@ dwarf2out_finish (const char *filename)
 
   /* 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