OSDN Git Service

* Makefile.in (local-distclean): Remove leftover built files.
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index 4e520fe..cb4f6f7 100644 (file)
@@ -169,11 +169,13 @@ dw_fde_node;
   ((((SIZE) + (BOUNDARY) - 1) / (BOUNDARY)) * (BOUNDARY))
 
 /* Offsets recorded in opcodes are a multiple of this alignment factor.  */
+#ifndef DWARF_CIE_DATA_ALIGNMENT
 #ifdef STACK_GROWS_DOWNWARD
 #define DWARF_CIE_DATA_ALIGNMENT (-((int) UNITS_PER_WORD))
 #else
 #define DWARF_CIE_DATA_ALIGNMENT ((int) UNITS_PER_WORD)
 #endif
+#endif /* not DWARF_CIE_DATA_ALIGNMENT */
 
 /* A pointer to the base of a table that contains frame description
    information for each routine.  */
@@ -527,10 +529,10 @@ static void def_cfa_1                     PARAMS ((const char *, dw_cfa_location *));
 /* This is similar to the default ASM_OUTPUT_ASCII, except that no trailing
    newline is produced.  When flag_debug_asm is asserted, we add commentary
    at the end of the line, so we must avoid output of a newline here.  */
-#ifndef ASM_OUTPUT_DWARF_STRING
-#define ASM_OUTPUT_DWARF_STRING(FILE,P) \
+#ifndef ASM_OUTPUT_DWARF_NSTRING
+#define ASM_OUTPUT_DWARF_NSTRING(FILE,P,SLEN) \
   do {                                                                       \
-    register int slen = strlen(P);                                            \
+    register int slen = (SLEN);                                               \
     register const char *p = (P);                                            \
     register int i;                                                          \
     fprintf (FILE, "\t.ascii \"");                                           \
@@ -550,6 +552,8 @@ static void def_cfa_1                       PARAMS ((const char *, dw_cfa_location *));
   }                                                                          \
   while (0)
 #endif
+#define ASM_OUTPUT_DWARF_STRING(FILE,P) \
+  ASM_OUTPUT_DWARF_NSTRING (FILE, P, strlen (P))
 
 /* The DWARF 2 CFA column which tracks the return address.  Normally this
    is the column for PC, or the first column after all of the hard
@@ -940,6 +944,18 @@ reg_save (label, reg, sreg, offset)
       else
        cfi->dw_cfi_opc = DW_CFA_offset;
 
+#ifdef ENABLE_CHECKING
+      {
+       /* If we get an offset that is not a multiple of
+          DWARF_CIE_DATA_ALIGNMENT, there is either a bug in the
+          definition of DWARF_CIE_DATA_ALIGNMENT, or a bug in the machine
+          description.  */
+       long check_offset = offset / DWARF_CIE_DATA_ALIGNMENT;
+
+       if (check_offset * DWARF_CIE_DATA_ALIGNMENT != offset)
+         abort ();
+      }
+#endif
       offset /= DWARF_CIE_DATA_ALIGNMENT;
       if (offset < 0)
        {
@@ -1193,7 +1209,7 @@ dwarf2out_stack_adjust (insn)
     }
   else
     return;
-  
+
   if (offset == 0)
     return;
 
@@ -2162,6 +2178,7 @@ typedef struct dw_loc_descr_struct
   enum dwarf_location_atom dw_loc_opc;
   dw_val_node dw_loc_oprnd1;
   dw_val_node dw_loc_oprnd2;
+  int dw_loc_addr;
 }
 dw_loc_descr_node;
 
@@ -2631,7 +2648,10 @@ size_of_locs (loc)
   register unsigned long size = 0;
 
   for (; loc != NULL; loc = loc->dw_loc_next)
-    size += size_of_loc_descr (loc);
+    {
+      loc->dw_loc_addr = size;
+      size += size_of_loc_descr (loc);
+    }
 
   return size;
 }
@@ -2669,8 +2689,17 @@ output_loc_operands (loc)
       break;
     case DW_OP_skip:
     case DW_OP_bra:
-      ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int);
-      fputc ('\n', asm_out_file);
+      {
+       int offset;
+
+       if (val1->val_class == dw_val_class_loc)
+         offset = val1->v.val_loc->dw_loc_addr - (loc->dw_loc_addr + 3);
+       else
+         abort ();
+
+       ASM_OUTPUT_DWARF_DATA2 (asm_out_file, offset);
+       fputc ('\n', asm_out_file);
+      }
       break;
 #else
     case DW_OP_addr:
@@ -2827,9 +2856,16 @@ build_cfa_loc (cfa)
     abort ();
 
   if (cfa->base_offset)
-    head = new_loc_descr (DW_OP_breg0 + cfa->reg, cfa->base_offset, 0);
-  else
+    {
+      if (cfa->reg <= 31)
+       head = new_loc_descr (DW_OP_breg0 + cfa->reg, cfa->base_offset, 0);
+      else
+       head = new_loc_descr (DW_OP_bregx, cfa->reg, cfa->base_offset);
+    }
+  else if (cfa->reg <= 31)
     head = new_loc_descr (DW_OP_reg0 + cfa->reg, 0, 0);
+  else
+    head = new_loc_descr (DW_OP_regx, cfa->reg, 0);
   head->dw_loc_oprnd1.val_class = dw_val_class_const;
   tmp = new_loc_descr (DW_OP_deref, 0, 0);
   add_loc_descr (&head, tmp);
@@ -3093,10 +3129,14 @@ extern int flag_traditional;
   (DWARF_ROUND (2 * DWARF_OFFSET_SIZE + 4, DWARF2_ADDR_SIZE * 2) \
    - (2 * DWARF_OFFSET_SIZE + 4))
 
-/* The default is to have gcc emit the line number tables.  */
+/* Use assembler line directives if available.  */
 #ifndef DWARF2_ASM_LINE_DEBUG_INFO
+#ifdef HAVE_AS_DWARF2_DEBUG_LINE
+#define DWARF2_ASM_LINE_DEBUG_INFO 1
+#else
 #define DWARF2_ASM_LINE_DEBUG_INFO 0
 #endif
+#endif
 
 /* Define the architecture-dependent minimum instruction length (in bytes).
    In this implementation of DWARF, this field is used for information
@@ -3135,21 +3175,25 @@ static dw_die_ref comp_unit_die;
 /* A list of DIEs with a NULL parent waiting to be relocated.  */
 static limbo_die_node *limbo_die_list = 0;
 
-/* Pointer to an array of filenames referenced by this compilation unit.  */
-static char **file_table;
-
-/* Total number of entries in the table (i.e. array) pointed to by
-   `file_table'.  This is the *total* and includes both used and unused
-   slots.  */
-static unsigned file_table_allocated;
-
-/* Number of entries in the file_table which are actually in use.  */
-static unsigned file_table_in_use;
+/* Structure used by lookup_filename to manage sets of filenames.  */
+struct file_table
+{
+  char **table;
+  unsigned allocated;
+  unsigned in_use;
+  unsigned last_lookup_index;
+};
 
 /* Size (in elements) of increments by which we may expand the filename
    table.  */
 #define FILE_TABLE_INCREMENT 64
 
+/* Filenames referenced by declarations this compilation unit.  */
+static struct file_table decl_file_table;
+
+/* Filenames referenced by line numbers in this compilation unit.  */
+static struct file_table line_file_table;
+
 /* Local pointer to the name of the main input file.  Initialized in
    dwarf2out_init.  */
 static const char *primary_filename;
@@ -3398,6 +3442,7 @@ static void output_pubnames               PARAMS ((void));
 static void add_arange                 PARAMS ((tree, dw_die_ref));
 static void output_aranges             PARAMS ((void));
 static void output_line_info           PARAMS ((void));
+static void output_file_names           PARAMS ((void));
 static dw_die_ref base_type_die                PARAMS ((tree));
 static tree root_type                  PARAMS ((tree));
 static int is_base_type                        PARAMS ((tree));
@@ -3405,11 +3450,13 @@ static dw_die_ref modified_type_die     PARAMS ((tree, int, int, dw_die_ref));
 static int type_is_enum                        PARAMS ((tree));
 static unsigned int reg_number         PARAMS ((rtx));
 static dw_loc_descr_ref reg_loc_descriptor PARAMS ((rtx));
+static dw_loc_descr_ref int_loc_descriptor PARAMS ((HOST_WIDE_INT));
 static dw_loc_descr_ref based_loc_descr        PARAMS ((unsigned, long));
 static int is_based_loc                        PARAMS ((rtx));
 static dw_loc_descr_ref mem_loc_descriptor PARAMS ((rtx, enum machine_mode mode));
 static dw_loc_descr_ref concat_loc_descriptor PARAMS ((rtx, rtx));
 static dw_loc_descr_ref loc_descriptor PARAMS ((rtx));
+static dw_loc_descr_ref loc_descriptor_from_tree PARAMS ((tree, int));
 static HOST_WIDE_INT ceiling           PARAMS ((HOST_WIDE_INT, unsigned int));
 static tree field_type                 PARAMS ((tree));
 static unsigned int simple_type_align_in_bits PARAMS ((tree));
@@ -3419,6 +3466,7 @@ static void add_AT_location_description   PARAMS ((dw_die_ref,
                                                 enum dwarf_attribute, rtx));
 static void add_data_member_location_attribute PARAMS ((dw_die_ref, tree));
 static void add_const_value_attribute  PARAMS ((dw_die_ref, rtx));
+static rtx rtl_for_decl_location       PARAMS ((tree));
 static void add_location_or_const_value_attribute PARAMS ((dw_die_ref, tree));
 static void tree_add_const_value_attribute PARAMS ((dw_die_ref, tree));
 static void add_name_attribute         PARAMS ((dw_die_ref, const char *));
@@ -3475,7 +3523,9 @@ static void gen_block_die         PARAMS ((tree, dw_die_ref, int));
 static void decls_for_scope            PARAMS ((tree, dw_die_ref, int));
 static int is_redundant_typedef                PARAMS ((tree));
 static void gen_decl_die               PARAMS ((tree, dw_die_ref));
-static unsigned lookup_filename                PARAMS ((const char *));
+static unsigned lookup_filename                PARAMS ((struct file_table *,
+                                                const char *));
+static void init_file_table            PARAMS ((struct file_table *));
 static void add_incomplete_type                PARAMS ((tree));
 static void retry_incomplete_types     PARAMS ((void));
 static void gen_type_die_for_member    PARAMS ((tree, tree, dw_die_ref));
@@ -3557,9 +3607,6 @@ static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 #ifndef BSS_END_LABEL
 #define BSS_END_LABEL           "Lebss"
 #endif
-#ifndef INSN_LABEL_FMT
-#define INSN_LABEL_FMT         "LI%u_"
-#endif
 #ifndef BLOCK_BEGIN_LABEL
 #define BLOCK_BEGIN_LABEL      "LBB"
 #endif
@@ -3599,15 +3646,7 @@ static rtx
 save_rtx (orig)
      register rtx orig;
 {
-  if (ggc_p)
-    VARRAY_PUSH_RTX (used_rtx_varray, orig);
-  else
-    {
-      push_obstacks_nochange ();
-      end_temporary_allocation ();
-      orig = copy_rtx (orig);
-      pop_obstacks ();
-    }
+  VARRAY_PUSH_RTX (used_rtx_varray, orig);
 
   return orig;
 }
@@ -4609,7 +4648,7 @@ free_AT (a)
     case dw_val_class_float:
       free (a->dw_attr_val.v.val_float.array);
       break;
-      
+
     default:
       break;
     }
@@ -4820,7 +4859,7 @@ equate_decl_number_to_die (decl, decl_die)
        = (dw_die_ref *) xrealloc (decl_die_table,
                                   sizeof (dw_die_ref) * num_allocated);
 
-      bzero ((char *) &decl_die_table[decl_die_table_allocated],
+      memset ((char *) &decl_die_table[decl_die_table_allocated], 0,
             (num_allocated - decl_die_table_allocated) * sizeof (dw_die_ref));
       decl_die_table_allocated = num_allocated;
     }
@@ -4948,7 +4987,7 @@ print_dwarf_line_table (outfile)
     {
       line_info = &line_info_table[i];
       fprintf (outfile, "%5d: ", i);
-      fprintf (outfile, "%-20s", file_table[line_info->dw_file_num]);
+      fprintf (outfile, "%-20s", line_file_table.table[line_info->dw_file_num]);
       fprintf (outfile, "%6ld", line_info->dw_line_num);
       fprintf (outfile, "\n");
     }
@@ -5356,7 +5395,7 @@ break_out_includes (die)
 
 #if 0
   /* We can only use this in debugging, since the frontend doesn't check
-     to make sure that we leave every include file we enter.  */     
+     to make sure that we leave every include file we enter.  */
   if (unit != NULL)
     abort ();
 #endif
@@ -5452,7 +5491,7 @@ build_abbrev_table (die)
            = (dw_die_ref *) xrealloc (abbrev_die_table,
                                       sizeof (dw_die_ref) * n_alloc);
 
-         bzero ((char *) &abbrev_die_table[abbrev_die_table_allocated],
+         memset ((char *) &abbrev_die_table[abbrev_die_table_allocated], 0,
                 (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref));
          abbrev_die_table_allocated = n_alloc;
        }
@@ -5632,10 +5671,10 @@ size_of_line_prolog ()
      null byte used to terminate the table.  */
   size += 1;
 
-  for (ft_index = 1; ft_index < file_table_in_use; ++ft_index)
+  for (ft_index = 1; ft_index < decl_file_table.in_use; ++ft_index)
     {
       /* File name entry.  */
-      size += size_of_string (file_table[ft_index]);
+      size += size_of_string (decl_file_table.table[ft_index]);
 
       /* Include directory index.  */
       size += size_of_uleb128 (0);
@@ -6080,7 +6119,7 @@ static void
 output_comp_unit (die)
      dw_die_ref die;
 {
-  char *secname;
+  const char *secname;
 
   if (die->die_child == 0)
     return;
@@ -6096,12 +6135,13 @@ output_comp_unit (die)
 
   if (die->die_symbol)
     {
-      secname = (char *) alloca (strlen (die->die_symbol) + 24);
-      sprintf (secname, ".gnu.linkonce.wi.%s", die->die_symbol);
+      char *tmp = (char *) alloca (strlen (die->die_symbol) + 24);
+      sprintf (tmp, ".gnu.linkonce.wi.%s", die->die_symbol);
+      secname = tmp;
       die->die_symbol = NULL;
     }
   else
-    secname = (char *) DEBUG_INFO_SECTION;
+    secname = (const char *) DEBUG_INFO_SECTION;
 
   /* Output debugging information.  */
   fputc ('\n', asm_out_file);
@@ -6356,6 +6396,314 @@ output_aranges ()
   fputc ('\n', asm_out_file);
 }
 
+
+/* Data structure containing information about input files.  */
+struct file_info
+{
+  char *path;          /* Complete file name.  */
+  char *fname;         /* File name part.  */
+  int length;          /* Length of entire string.  */
+  int file_idx;                /* Index in input file table.  */
+  int dir_idx;         /* Index in directory table.  */
+};
+
+/* Data structure containing information about directories with source
+   files.  */
+struct dir_info
+{
+  char *path;          /* Path including directory name.  */
+  int length;          /* Path length.  */
+  int prefix;          /* Index of directory entry which is a prefix.  */
+  int nbytes;          /* Total number of bytes in all file names excluding
+                          paths.  */
+  int count;           /* Number of files in this directory.  */
+  int dir_idx;         /* Index of directory used as base.  */
+  int used;            /* Used in the end?  */
+};
+
+/* Callback function for file_info comparison.  We sort by looking at
+   the directories in the path.  */
+static int
+file_info_cmp (p1, p2)
+     const void *p1;
+     const void *p2;
+{
+  const struct file_info *s1 = p1;
+  const struct file_info *s2 = p2;
+  unsigned char *cp1;
+  unsigned char *cp2;
+
+  /* Take care of file names without directories.  */
+  if (s1->path == s1->fname)
+    return -1;
+  else if (s2->path == s2->fname)
+    return 1;
+
+  cp1 = (unsigned char *) s1->path;
+  cp2 = (unsigned char *) s2->path;
+
+  while (1)
+    {
+      ++cp1;
+      ++cp2;
+      /* Reached the end of the first path?  */
+      if (cp1 == (unsigned char *) s1->fname)
+       /* It doesn't really matter in which order files from the
+          same directory are sorted in.  Therefore don't test for
+          the second path reaching the end.  */
+       return -1;
+      else if (cp2 == (unsigned char *) s2->fname)
+       return 1;
+
+      /* Character of current path component the same?  */
+      if (*cp1 != *cp2)
+       return *cp1 - *cp2;
+    }
+}
+
+/* Output the directory table and the file name table.  We try to minimize
+   the total amount of memory needed.  A heuristic is used to avoid large
+   slowdowns with many input files.  */
+static void
+output_file_names ()
+{
+  struct file_info *files;
+  struct dir_info *dirs;
+  int *saved;
+  int *savehere;
+  int *backmap;
+  int ndirs;
+  int idx_offset;
+  int i;
+  int idx;
+
+  /* Allocate the various arrays we need.  */
+  files = (struct file_info *) alloca (line_file_table.in_use
+                                      * sizeof (struct file_info));
+  dirs = (struct dir_info *) alloca (line_file_table.in_use
+                                    * sizeof (struct dir_info));
+
+  /* Sort the file names.  */
+   for (i = 1; i < (int) line_file_table.in_use; ++i)
+    {
+      char *f;
+
+      /* Skip all leading "./".  */
+      f = line_file_table.table[i];
+      while (f[0] == '.' && f[1] == '/')
+       f += 2;
+
+      /* Create a new array entry.  */
+      files[i].path = f;
+      files[i].length = strlen (f);
+      files[i].file_idx = i;
+
+      /* Search for the file name part.  */
+      f = strrchr (f, '/');
+      files[i].fname = f == NULL ? files[i].path : f + 1;
+    }
+  qsort (files + 1, line_file_table.in_use - 1, sizeof (files[0]),
+        file_info_cmp);
+
+  /* Find all the different directories used.  */
+  dirs[0].path = files[1].path;
+  dirs[0].length = files[1].fname - files[1].path;
+  dirs[0].prefix = -1;
+  dirs[0].nbytes = files[1].length - dirs[1].length + 1;
+  dirs[0].count = 1;
+  dirs[0].dir_idx = 0;
+  dirs[0].used = 0;
+  files[1].dir_idx = 0;
+  ndirs = 1;
+
+  for (i = 2; i < (int) line_file_table.in_use; ++i)
+    if (files[i].fname - files[i].path == dirs[ndirs - 1].length
+       && memcmp (dirs[ndirs - 1].path, files[i].path,
+                  dirs[ndirs - 1].length) == 0)
+      {
+       /* Same directory as last entry.  */
+       files[i].dir_idx = ndirs - 1;
+       dirs[ndirs - 1].nbytes += files[i].length - dirs[ndirs - 1].length + 1;
+       ++dirs[ndirs - 1].count;
+      }
+    else
+      {
+       int j;
+
+       /* This is a new directory.  */
+       dirs[ndirs].path = files[i].path;
+       dirs[ndirs].length = files[i].fname - files[i].path;
+       dirs[ndirs].nbytes = files[i].length - dirs[i].length + 1;
+       dirs[ndirs].count = 1;
+       dirs[ndirs].dir_idx = ndirs;
+       dirs[ndirs].used = 0;
+       files[i].dir_idx = ndirs;
+
+       /* Search for a prefix.  */
+       dirs[ndirs].prefix = -1;
+       for (j = 0; j < ndirs; ++j)
+         if (dirs[j].length < dirs[ndirs].length
+             && dirs[j].length != 0
+             && memcmp (dirs[j].path, dirs[ndirs].path, dirs[j].length) == 0)
+           dirs[ndirs].prefix = j;
+
+       ++ndirs;
+      }
+
+  /* Now to the actual work.  We have to find a subset of the
+     directories which allow expressing the file name using references
+     to the directory table with the least amount of characters.  We
+     do not do an exhaustive search where we would have to check out
+     every combination of every single possible prefix.  Instead we
+     use a heuristic which provides nearly optimal results in most
+     cases and never is much off.  */
+  saved = (int *) alloca (ndirs * sizeof (int));
+  savehere = (int *) alloca (ndirs * sizeof (int));
+
+  memset (saved, '\0', ndirs * sizeof (saved[0]));
+  for (i = 0; i < ndirs; ++i)
+    {
+      int j;
+      int total;
+
+      /* We can always safe some space for the current directory.  But
+        this does not mean it will be enough to justify adding the
+        directory.  */
+      savehere[i] = dirs[i].length;
+      total = (savehere[i] - saved[i]) * dirs[i].count;
+
+      for (j = i + 1; j < ndirs; ++j)
+       {
+         savehere[j] = 0;
+
+         if (saved[j] < dirs[i].length)
+           {
+             /* Determine whether the dirs[i] path is a prefix of the
+                dirs[j] path.  */
+             int k;
+
+              k = dirs[j].prefix;
+              while (k != -1 && k != i)
+                k = dirs[k].prefix;
+
+              if (k == i)
+                {
+                  /* Yes it is.  We can possibly safe some memory but
+                     writing the filenames in dirs[j] relative to
+                     dirs[i].  */
+                  savehere[j] = dirs[i].length;
+                  total += (savehere[j] - saved[j]) * dirs[j].count;
+                }
+           }
+       }
+
+      /* Check whether we can safe enough to justify adding the dirs[i]
+        directory.  */
+      if (total > dirs[i].length + 1)
+       {
+          /* It's worthwhile adding.  */
+          for (j = i; j < ndirs; ++j)
+           if (savehere[j] > 0)
+             {
+               /* Remember how much we saved for this directory so far.  */
+               saved[j] = savehere[j];
+
+               /* Remember the prefix directory.  */
+               dirs[j].dir_idx = i;
+             }
+       }
+    }
+
+  /* We have to emit them in the order they appear in the line_file_table
+     array since the index is used in the debug info generation.  To
+     do this efficiently we generate a back-mapping of the indices
+     first.  */
+  backmap = (int *) alloca (line_file_table.in_use * sizeof (int));
+  for (i = 1; i < (int) line_file_table.in_use; ++i)
+    {
+      backmap[files[i].file_idx] = i;
+      /* Mark this directory as used.  */
+      dirs[dirs[files[i].dir_idx].dir_idx].used = 1;
+    }
+
+  /* That was it.  We are ready to emit the information.  First the
+     directory name table.  Here we have to make sure that the first
+     actually emitted directory name has the index one.  Zero is
+     reserved for the current working directory.  Make sure we do not
+     confuse these indices with the one for the constructed table
+     (even though most of the time they are identical).  */
+  idx = 1;
+  idx_offset = dirs[0].path[0] == '/' ? 1 : 0;
+  for (i = 1 - idx_offset; i < ndirs; ++i)
+    if (dirs[i].used != 0)
+      {
+       dirs[i].used = idx++;
+
+       if (flag_debug_asm)
+         {
+           ASM_OUTPUT_DWARF_NSTRING (asm_out_file,
+                                     dirs[i].path, dirs[i].length - 1);
+           fprintf (asm_out_file, "%s Directory Entry: 0x%x\n",
+                    ASM_COMMENT_START, dirs[i].used);
+         }
+       else
+         {
+           ASM_OUTPUT_ASCII (asm_out_file, dirs[i].path, dirs[i].length - 1);
+           ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+           fputc ('\n', asm_out_file);
+         }
+      }
+  /* Correct the index for the current working directory entry if it
+     exists.  */
+  if (idx_offset == 0)
+    dirs[0].used = 0;
+  /* Terminate the directory name array.  */
+  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+  if (flag_debug_asm)
+    fprintf (asm_out_file, "\t%s End directory table", ASM_COMMENT_START);
+  fputc ('\n', asm_out_file);
+
+  /* Now write all the file names.  */
+  for (i = 1; i < (int) line_file_table.in_use; ++i)
+    {
+      int file_idx = backmap[i];
+      int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
+
+      if (flag_debug_asm)
+       {
+         ASM_OUTPUT_DWARF_STRING (asm_out_file,
+                                  files[file_idx].path
+                                  + dirs[dir_idx].length);
+         fprintf (asm_out_file, "%s File Entry: 0x%x\n",
+                  ASM_COMMENT_START, i);
+       }
+      else
+       ASM_OUTPUT_ASCII (asm_out_file,
+                         files[file_idx].path + dirs[dir_idx].length,
+                         (files[file_idx].length
+                          - dirs[dir_idx].length) + 1);
+
+      /* Include directory index.  */
+      output_uleb128 (dirs[dir_idx].used);
+      fputc ('\n', asm_out_file);
+
+      /* Modification time.  */
+      output_uleb128 (0);
+      fputc ('\n', asm_out_file);
+
+      /* File length in bytes.  */
+      output_uleb128 (0);
+      fputc ('\n', asm_out_file);
+    }
+
+  /* Terminate the file name table */
+  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+  if (flag_debug_asm)
+    fprintf (asm_out_file, "\t%s End file name table", ASM_COMMENT_START);
+  fputc ('\n', asm_out_file);
+}
+
+
 /* Output the source line number correspondence information.  This
    information goes into the .debug_line section.  */
 
@@ -6366,7 +6714,6 @@ output_line_info ()
   char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES];
   register unsigned opc;
   register unsigned n_op_args;
-  register unsigned long ft_index;
   register unsigned long lt_index;
   register unsigned long current_line;
   register long line_offset;
@@ -6442,48 +6789,8 @@ output_line_info ()
       fputc ('\n', asm_out_file);
     }
 
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "%s Include Directory Table\n", ASM_COMMENT_START);
-
-  /* Include directory table is empty, at present */
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
-  fputc ('\n', asm_out_file);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "%s File Name Table\n", ASM_COMMENT_START);
-
-  for (ft_index = 1; ft_index < file_table_in_use; ++ft_index)
-    {
-      if (flag_debug_asm)
-       {
-         ASM_OUTPUT_DWARF_STRING (asm_out_file, file_table[ft_index]);
-         fprintf (asm_out_file, "%s File Entry: 0x%lx",
-                  ASM_COMMENT_START, ft_index);
-       }
-      else
-       {
-         ASM_OUTPUT_ASCII (asm_out_file,
-                           file_table[ft_index],
-                           (int) strlen (file_table[ft_index]) + 1);
-       }
-
-      fputc ('\n', asm_out_file);
-
-      /* Include directory index */
-      output_uleb128 (0);
-      fputc ('\n', asm_out_file);
-
-      /* Modification time */
-      output_uleb128 (0);
-      fputc ('\n', asm_out_file);
-
-      /* File length in bytes */
-      output_uleb128 (0);
-      fputc ('\n', asm_out_file);
-    }
-
-  /* Terminate the file name table */
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
-  fputc ('\n', asm_out_file);
+  /* Write out the information about the files we use.  */
+  output_file_names ();
 
   /* We used to set the address register to the first location in the text
      section here, but that didn't accomplish anything since we already
@@ -6564,7 +6871,8 @@ output_line_info ()
          fputc ('\n', asm_out_file);
          output_uleb128 (current_file);
          if (flag_debug_asm)
-           fprintf (asm_out_file, " (\"%s\")", file_table[current_file]);
+           fprintf (asm_out_file, " (\"%s\")",
+                    line_file_table.table[current_file]);
 
          fputc ('\n', asm_out_file);
        }
@@ -6736,7 +7044,8 @@ output_line_info ()
          fputc ('\n', asm_out_file);
          output_uleb128 (current_file);
          if (flag_debug_asm)
-           fprintf (asm_out_file, " (\"%s\")", file_table[current_file]);
+           fprintf (asm_out_file, " (\"%s\")",
+                    line_file_table.table[current_file]);
 
          fputc ('\n', asm_out_file);
        }
@@ -7160,6 +7469,46 @@ reg_loc_descriptor (rtl)
   return loc_result;
 }
 
+/* Return a location descriptor that designates a constant.  */
+
+static dw_loc_descr_ref
+int_loc_descriptor (i)
+     HOST_WIDE_INT i;
+{
+  enum dwarf_location_atom op;
+
+  /* Pick the smallest representation of a constant, rather than just
+     defaulting to the LEB encoding.  */
+  if (i >= 0)
+    {
+      if (i <= 31)
+       op = DW_OP_lit0 + i;
+      else if (i <= 0xff)
+       op = DW_OP_const1u;
+      else if (i <= 0xffff)
+       op = DW_OP_const2u;
+      else if (HOST_BITS_PER_WIDE_INT == 32
+              || i <= 0xffffffff)
+       op = DW_OP_const4u;
+      else
+       op = DW_OP_constu;
+    }
+  else
+    {
+      if (i >= -0x80)
+       op = DW_OP_const1s;
+      else if (i >= -0x8000)
+       op = DW_OP_const2s;
+      else if (HOST_BITS_PER_WIDE_INT == 32
+              || i >= -0x80000000)
+       op = DW_OP_const4s;
+      else
+       op = DW_OP_consts;
+    }
+
+  return new_loc_descr (op, i, 0);
+}
+
 /* Return a location descriptor that designates a base+offset location.  */
 
 static dw_loc_descr_ref
@@ -7261,12 +7610,22 @@ mem_loc_descriptor (rtl, mode)
       break;
 
     case MEM:
-      mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode);
-      add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
+      {
+       dw_loc_descr_ref deref;
+
+       mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
+
+       if (GET_MODE_SIZE (mode) == DWARF2_ADDR_SIZE)
+         deref = new_loc_descr (DW_OP_deref, 0, 0);
+       else
+         deref = new_loc_descr (DW_OP_deref_size, GET_MODE_SIZE (mode), 0);
+
+       add_loc_descr (&mem_loc_result, deref);
+      }
       break;
 
-     case LABEL_REF:
-       /* Some ports can transform a symbol ref into a label ref, because
+    case LABEL_REF:
+      /* Some ports can transform a symbol ref into a label ref, because
         the symbol ref is too far away and has to be dumped into a constant
         pool.  */
     case CONST:
@@ -7293,24 +7652,37 @@ mem_loc_descriptor (rtl, mode)
                                          INTVAL (XEXP (rtl, 1)));
       else
        {
-         add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0),
-                                                             mode));
-         add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1),
-                                                             mode));
-         add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_plus, 0, 0));
+         mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode);
+
+         if (GET_CODE (XEXP (rtl, 1)) == CONST_INT
+             && INTVAL (XEXP (rtl, 1)) >= 0)
+           {
+             add_loc_descr (&mem_loc_result,
+                            new_loc_descr (DW_OP_plus_uconst,
+                                           INTVAL (XEXP (rtl, 1)), 0));
+           }
+         else
+           {
+             add_loc_descr (&mem_loc_result,
+                            mem_loc_descriptor (XEXP (rtl, 1), mode));
+             add_loc_descr (&mem_loc_result,
+                            new_loc_descr (DW_OP_plus, 0, 0));
+           }
        }
       break;
 
     case MULT:
       /* If a pseudo-reg is optimized away, it is possible for it to
         be replaced with a MEM containing a multiply.  */
-      add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0), mode));
-      add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1), mode));
+      add_loc_descr (&mem_loc_result,
+                    mem_loc_descriptor (XEXP (rtl, 0), mode));
+      add_loc_descr (&mem_loc_result,
+                    mem_loc_descriptor (XEXP (rtl, 1), mode));
       add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
       break;
 
     case CONST_INT:
-      mem_loc_result = new_loc_descr (DW_OP_constu, INTVAL (rtl), 0);
+      mem_loc_result = int_loc_descriptor (INTVAL (rtl));
       break;
 
     default:
@@ -7386,6 +7758,262 @@ loc_descriptor (rtl)
   return loc_result;
 }
 
+/* Similar, but generate the descriptor from trees instead of rtl.
+   This comes up particularly with variable length arrays.  */
+
+static dw_loc_descr_ref
+loc_descriptor_from_tree (loc, addressp)
+     tree loc;
+     int addressp;
+{
+  dw_loc_descr_ref ret = NULL;
+  int indirect_size = 0;
+  int unsignedp = TREE_UNSIGNED (TREE_TYPE (loc));
+  enum dwarf_location_atom op;
+
+  /* ??? Most of the time we do not take proper care for sign/zero
+     extending the values properly.  Hopefully this won't be a real
+     problem...  */
+
+  switch (TREE_CODE (loc))
+    {
+    case ERROR_MARK:
+      break;
+
+    case VAR_DECL:
+    case PARM_DECL:
+      {
+       rtx rtl = rtl_for_decl_location (loc);
+       enum machine_mode mode = DECL_MODE (loc);
+
+       if (rtl == NULL_RTX)
+         break;
+       else if (CONSTANT_P (rtl))
+         {
+           ret = new_loc_descr (DW_OP_addr, 0, 0);
+           ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
+           ret->dw_loc_oprnd1.v.val_addr = rtl;
+           indirect_size = GET_MODE_SIZE (mode);
+         }
+       else
+         {
+           if (GET_CODE (rtl) == MEM)
+             {
+               indirect_size = GET_MODE_SIZE (mode);
+               rtl = XEXP (rtl, 0);
+             }
+           ret = mem_loc_descriptor (rtl, mode);
+         }
+      }
+      break;
+
+    case INDIRECT_REF:
+      ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
+      indirect_size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (loc)));
+      break;
+
+    case COMPONENT_REF:
+    case BIT_FIELD_REF:
+    case ARRAY_REF:
+      {
+       tree obj, offset;
+       HOST_WIDE_INT bitsize, bitpos, bytepos;
+       enum machine_mode mode;
+       int volatilep;
+       unsigned int alignment;
+
+       obj = get_inner_reference (loc, &bitsize, &bitpos, &offset, &mode,
+                                  &unsignedp, &volatilep, &alignment);
+       ret = loc_descriptor_from_tree (obj, 1);
+
+       if (offset != NULL_TREE)
+         {
+           /* Variable offset.  */
+           add_loc_descr (&ret, loc_descriptor_from_tree (offset, 0));
+           add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
+         }
+
+       if (addressp)
+         {
+           /* We cannot address anything not on a unit boundary.  */
+           if (bitpos % BITS_PER_UNIT != 0)
+             abort ();
+         }
+       else
+         {
+           if (bitpos % BITS_PER_UNIT != 0
+               || bitsize % BITS_PER_UNIT != 0)
+             {
+               /* ??? We could handle this by loading and shifting etc.
+                  Wait until someone needs it before expending the effort.  */
+               abort ();
+             }
+
+           indirect_size = bitsize / BITS_PER_UNIT;
+         }
+
+       bytepos = bitpos / BITS_PER_UNIT;
+       if (bytepos > 0)
+         add_loc_descr (&ret, new_loc_descr (DW_OP_plus_uconst, bytepos, 0));
+       else if (bytepos < 0)
+         {
+           add_loc_descr (&ret, int_loc_descriptor (bytepos));
+           add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0));
+         }
+       break;
+      }
+
+    case INTEGER_CST:
+      if (host_integerp (loc, 0))
+       ret = int_loc_descriptor (tree_low_cst (loc, 0));
+      break;
+      break;
+
+    case BIT_AND_EXPR:
+      op = DW_OP_and;
+      goto do_binop;
+    case BIT_XOR_EXPR:
+      op = DW_OP_xor;
+      goto do_binop;
+    case BIT_IOR_EXPR:
+      op = DW_OP_or;
+      goto do_binop;
+    case TRUNC_DIV_EXPR:
+      op = DW_OP_div;
+      goto do_binop;
+    case MINUS_EXPR:
+      op = DW_OP_minus;
+      goto do_binop;
+    case TRUNC_MOD_EXPR:
+      op = DW_OP_mod;
+      goto do_binop;
+    case MULT_EXPR:
+      op = DW_OP_mul;
+      goto do_binop;
+    case LSHIFT_EXPR:
+      op = DW_OP_shl;
+      goto do_binop;
+    case RSHIFT_EXPR:
+      op = (unsignedp ? DW_OP_shr : DW_OP_shra);
+      goto do_binop;
+    case PLUS_EXPR:
+      if (TREE_CODE (TREE_OPERAND (loc, 1)) == INTEGER_CST
+         && host_integerp (TREE_OPERAND (loc, 1), 0))
+       {
+         ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
+         add_loc_descr (&ret,
+                        new_loc_descr (DW_OP_plus_uconst,
+                                       tree_low_cst (TREE_OPERAND (loc, 1),
+                                                     0),
+                                       0));
+         break;
+       }
+      op = DW_OP_plus;
+      goto do_binop;
+    case LE_EXPR:
+      if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+       break;
+      op = DW_OP_le;
+      goto do_binop;
+    case GE_EXPR:
+      if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+       break;
+      op = DW_OP_ge;
+      goto do_binop;
+    case LT_EXPR:
+      if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+       break;
+      op = DW_OP_lt;
+      goto do_binop;
+    case GT_EXPR:
+      if (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (loc, 0))))
+       break;
+      op = DW_OP_gt;
+      goto do_binop;
+    case EQ_EXPR:
+      op = DW_OP_eq;
+      goto do_binop;
+    case NE_EXPR:
+      op = DW_OP_ne;
+      goto do_binop;
+
+    do_binop:
+      ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
+      add_loc_descr (&ret, loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0));
+      add_loc_descr (&ret, new_loc_descr (op, 0, 0));
+      break;
+
+    case BIT_NOT_EXPR:
+      op = DW_OP_not;
+      goto do_unop;
+    case ABS_EXPR:
+      op = DW_OP_abs;
+      goto do_unop;
+    case NEGATE_EXPR:
+      op = DW_OP_neg;
+      goto do_unop;
+
+    do_unop:
+      ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
+      add_loc_descr (&ret, new_loc_descr (op, 0, 0));
+      break;
+
+    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));
+      /* FALLTHRU */
+
+    case COND_EXPR:
+      {
+       dw_loc_descr_ref bra_node, jump_node, tmp;
+
+       ret = loc_descriptor_from_tree (TREE_OPERAND (loc, 0), 0);
+       bra_node = new_loc_descr (DW_OP_bra, 0, 0);
+       add_loc_descr (&ret, bra_node);
+
+       tmp = loc_descriptor_from_tree (TREE_OPERAND (loc, 2), 0);
+       add_loc_descr (&ret, tmp);
+       jump_node = new_loc_descr (DW_OP_skip, 0, 0);
+       add_loc_descr (&ret, jump_node);
+
+       tmp = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0);
+       add_loc_descr (&ret, tmp);
+       bra_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
+       bra_node->dw_loc_oprnd1.v.val_loc = tmp;
+
+       /* ??? Need a node to point the skip at.  Use a nop.  */
+       tmp = new_loc_descr (DW_OP_nop, 0, 0);
+       add_loc_descr (&ret, tmp);
+       jump_node->dw_loc_oprnd1.val_class = dw_val_class_loc;
+       jump_node->dw_loc_oprnd1.v.val_loc = tmp;
+      }
+      break;
+
+    default:
+      abort ();
+    }
+
+  /* If we can't fill the request for an address, die.  */
+  if (addressp && indirect_size == 0)
+    abort ();
+
+  /* If we've got an address and don't want one, dereference.  */
+  if (!addressp && indirect_size > 0)
+    {
+      if (indirect_size > DWARF2_ADDR_SIZE)
+       abort ();
+      if (indirect_size == DWARF2_ADDR_SIZE)
+       op = DW_OP_deref;
+      else
+       op = DW_OP_deref_size;
+      add_loc_descr (&ret, new_loc_descr (op, indirect_size, 0));
+    }
+
+  return ret;
+}
+
 /* Given a value, round it up to the lowest multiple of `boundary'
    which is not less than the value itself.  */
 
@@ -7440,17 +8068,17 @@ static inline unsigned HOST_WIDE_INT
 simple_type_size_in_bits (type)
      register tree type;
 {
+  tree type_size_tree;
+
   if (TREE_CODE (type) == ERROR_MARK)
     return BITS_PER_WORD;
-  else
-    {
-      register tree type_size_tree = TYPE_SIZE (type);
-
-      if (! host_integerp (type_size_tree, 1))
-       return TYPE_ALIGN (type);
+  type_size_tree = TYPE_SIZE (type);
 
-      return tree_low_cst (type_size_tree, 1);
-    }
+  if (type_size_tree == NULL_TREE)
+    return 0;
+  if (! host_integerp (type_size_tree, 1))
+    return TYPE_ALIGN (type);
+  return tree_low_cst (type_size_tree, 1);
 }
 
 /* Given a pointer to what is assumed to be a FIELD_DECL node, compute and
@@ -7485,14 +8113,10 @@ field_byte_offset (decl)
   type = field_type (decl);
   field_size_tree = DECL_SIZE (decl);
 
-  /* If there was an error, the size could be zero.  */
+  /* The size could be unspecified if there was an error, or for
+     a flexible array member.  */
   if (! field_size_tree)
-    {
-      if (errorcount)
-       return 0;
-
-      abort ();
-    }
+    field_size_tree = bitsize_zero_node;
 
   /* We cannot yet cope with fields whose positions are variable, so
      for now, when we see such things, we simply return 0.  Someday, we may
@@ -7502,7 +8126,7 @@ field_byte_offset (decl)
 
   bitpos_int = int_bit_position (decl);
 
-    /* If we don't know the size of the field, pretend it's a full word.  */
+  /* If we don't know the size of the field, pretend it's a full word.  */
   if (host_integerp (field_size_tree, 1))
     field_size_in_bits = tree_low_cst (field_size_tree, 1);
   else
@@ -7755,31 +8379,11 @@ add_const_value_attribute (die, rtl)
 
 }
 
-/* Generate *either* an DW_AT_location attribute or else an DW_AT_const_value
-   data attribute for a variable or a parameter.  We generate the
-   DW_AT_const_value attribute only in those cases where the given variable
-   or parameter does not have a true "location" either in memory or in a
-   register.  This can happen (for example) when a constant is passed as an
-   actual argument in a call to an inline function.  (It's possible that
-   these things can crop up in other ways also.)  Note that one type of
-   constant value which can be passed into an inlined function is a constant
-   pointer.  This can happen for example if an actual argument in an inlined
-   function call evaluates to a compile-time constant address.  */
-
-static void
-add_location_or_const_value_attribute (die, decl)
-     register dw_die_ref die;
-     register tree decl;
+static rtx
+rtl_for_decl_location (decl)
+     tree decl;
 {
   register rtx rtl;
-  register tree declared_type;
-  register tree passed_type;
-
-  if (TREE_CODE (decl) == ERROR_MARK)
-    return;
-
-  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL)
-    abort ();
 
   /* Here we have to decide where we are going to say the parameter "lives"
      (as far as the debugger is concerned).  We only have a couple of
@@ -7863,8 +8467,8 @@ add_location_or_const_value_attribute (die, decl)
     {
       if (rtl == NULL_RTX || is_pseudo_reg (rtl))
        {
-         declared_type = type_main_variant (TREE_TYPE (decl));
-         passed_type = type_main_variant (DECL_ARG_TYPE (decl));
+         tree declared_type = type_main_variant (TREE_TYPE (decl));
+         tree passed_type = type_main_variant (DECL_ARG_TYPE (decl));
 
          /* This decl represents a formal parameter which was optimized out.
             Note that DECL_INCOMING_RTL may be NULL in here, but we handle
@@ -7911,14 +8515,45 @@ add_location_or_const_value_attribute (die, decl)
        }
     }
 
-  if (rtl == NULL_RTX)
-    return;
-
-  rtl = eliminate_regs (rtl, 0, NULL_RTX);
+  if (rtl != NULL_RTX)
+    {
+      rtl = eliminate_regs (rtl, 0, NULL_RTX);
 #ifdef LEAF_REG_REMAP
-  if (current_function_uses_only_leaf_regs)
-    leaf_renumber_regs_insn (rtl);
+      if (current_function_uses_only_leaf_regs)
+       leaf_renumber_regs_insn (rtl);
 #endif
+    }
+
+  return rtl;
+}
+
+/* Generate *either* an DW_AT_location attribute or else an DW_AT_const_value
+   data attribute for a variable or a parameter.  We generate the
+   DW_AT_const_value attribute only in those cases where the given variable
+   or parameter does not have a true "location" either in memory or in a
+   register.  This can happen (for example) when a constant is passed as an
+   actual argument in a call to an inline function.  (It's possible that
+   these things can crop up in other ways also.)  Note that one type of
+   constant value which can be passed into an inlined function is a constant
+   pointer.  This can happen for example if an actual argument in an inlined
+   function call evaluates to a compile-time constant address.  */
+
+static void
+add_location_or_const_value_attribute (die, decl)
+     register dw_die_ref die;
+     register tree decl;
+{
+  register rtx rtl;
+
+  if (TREE_CODE (decl) == ERROR_MARK)
+    return;
+
+  if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL)
+    abort ();
+
+  rtl = rtl_for_decl_location (decl);
+  if (rtl == NULL_RTX)
+    return;
 
   switch (GET_CODE (rtl))
     {
@@ -7983,7 +8618,7 @@ tree_add_const_value_attribute (var_die, decl)
     default:;
     }
 }
-     
+
 /* Generate an DW_AT_name attribute given some string value to be included as
    the value of the attribute.  */
 
@@ -8089,15 +8724,43 @@ add_bound_info (subrange_die, bound_attr, bound)
       /* Else leave out the attribute.  */
       break;
 
-    case MAX_EXPR:
     case VAR_DECL:
-    case COMPONENT_REF:
-      /* ??? These types of bounds can be created by the Ada front end,
-        and it isn't clear how to emit debug info for them.  */
-      break;
+    case PARM_DECL:
+      {
+       dw_die_ref decl_die = lookup_decl_die (bound);
+
+       /* ??? Can this happen, or should the variable have been bound
+          first?  Probably it can, since I imagine that we try to create
+          the types of parameters in the order in which they exist in
+          the list, and won't have created a forward reference to a
+          later parameter.  */
+       if (decl_die != NULL)
+         add_AT_die_ref (subrange_die, bound_attr, decl_die);
+       break;
+      }
 
     default:
-      abort ();
+      {
+       /* Otherwise try to create a stack operation procedure to
+          evaluate the value of the array bound.  */
+
+       dw_die_ref ctx, decl_die;
+       dw_loc_descr_ref loc;
+
+       loc = loc_descriptor_from_tree (bound, 0);
+       if (loc == NULL)
+         break;
+
+       ctx = lookup_decl_die (current_function_decl);
+
+       decl_die = new_die (DW_TAG_variable, ctx);
+       add_AT_flag (decl_die, DW_AT_artificial, 1);
+       add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
+       add_AT_loc (decl_die, DW_AT_location, loc);
+
+       add_AT_die_ref (subrange_die, bound_attr, decl_die);
+       break;
+      }
     }
 }
 
@@ -8385,7 +9048,8 @@ add_src_coords_attributes (die, decl)
      register dw_die_ref die;
      register tree decl;
 {
-  register unsigned file_index = lookup_filename (DECL_SOURCE_FILE (decl));
+  register unsigned file_index = lookup_filename (&decl_file_table,
+                                                 DECL_SOURCE_FILE (decl));
 
   add_AT_unsigned (die, DW_AT_decl_file, file_index);
   add_AT_unsigned (die, DW_AT_decl_line, DECL_SOURCE_LINE (decl));
@@ -9122,7 +9786,7 @@ gen_subprogram_die (decl, context_die)
   else if (old_die)
     {
       register unsigned file_index
-       = lookup_filename (DECL_SOURCE_FILE (decl));
+       = lookup_filename (&decl_file_table, DECL_SOURCE_FILE (decl));
 
       if (get_AT_flag (old_die, DW_AT_declaration) != 1)
        {
@@ -9379,7 +10043,7 @@ gen_variable_die (decl, context_die)
       if (DECL_NAME (decl))
        {
          register unsigned file_index
-           = lookup_filename (DECL_SOURCE_FILE (decl));
+           = lookup_filename (&decl_file_table, DECL_SOURCE_FILE (decl));
 
          if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index)
            add_AT_unsigned (var_die, DW_AT_decl_file, file_index);
@@ -9437,7 +10101,6 @@ gen_label_die (decl, context_die)
   register dw_die_ref lbl_die = new_die (DW_TAG_label, context_die);
   register rtx insn;
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
-  char label2[MAX_ARTIFICIAL_LABEL_BYTES];
 
   if (origin != NULL)
     add_abstract_origin_attribute (lbl_die, origin);
@@ -9465,9 +10128,7 @@ gen_label_die (decl, context_die)
          if (INSN_DELETED_P (insn))
            abort ();
 
-         sprintf (label2, INSN_LABEL_FMT, current_funcdef_number);
-         ASM_GENERATE_INTERNAL_LABEL (label, label2,
-                                      (unsigned) INSN_UID (insn));
+         ASM_GENERATE_INTERNAL_LABEL (label, "L", CODE_LABEL_NUMBER (insn));
          add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
        }
     }
@@ -10417,7 +11078,7 @@ dwarf2out_add_library_unit_info (filename, context_list)
 
       TREE_PUBLIC (context_list_decl) = TRUE;
       add_name_attribute (unit_die, context_list);
-      file_index = lookup_filename (filename);
+      file_index = lookup_filename (&decl_file_table, filename);
       add_AT_unsigned (unit_die, DW_AT_decl_file, file_index);
       add_pubname (context_list_decl, unit_die);
     }
@@ -10546,7 +11207,7 @@ dwarf2out_begin_block (blocknum)
      register unsigned blocknum;
 {
   function_section (current_function_decl);
-  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
+  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
 }
 
 /* Output a marker (i.e. a label) for the end of the generated code for a
@@ -10557,7 +11218,7 @@ dwarf2out_end_block (blocknum)
      register unsigned blocknum;
 {
   function_section (current_function_decl);
-  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
+  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
 }
 
 /* Returns nonzero if it is appropriate not to emit any debugging
@@ -10579,24 +11240,6 @@ dwarf2out_ignore_block (block)
   return 1;
 }
 
-/* Output a marker (i.e. a label) at a point in the assembly code which
-   corresponds to a given source level label.  */
-
-void
-dwarf2out_label (insn)
-     register rtx insn;
-{
-  char label[MAX_ARTIFICIAL_LABEL_BYTES];
-
-  if (debug_info_level >= DINFO_LEVEL_NORMAL)
-    {
-      function_section (current_function_decl);
-      sprintf (label, INSN_LABEL_FMT, current_funcdef_number);
-      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, label,
-                                (unsigned) INSN_UID (insn));
-    }
-}
-
 /* Lookup a filename (in the list of filenames that we know about here in
    dwarf2out.c) and return its "index".  The index of each (known) filename is
    just a unique number which is associated with only that one filename.
@@ -10609,41 +11252,54 @@ dwarf2out_label (insn)
    was looked up last.  This handles the majority of all searches.  */
 
 static unsigned
-lookup_filename (file_name)
+lookup_filename (t, file_name)
+     struct file_table *t;
      const char *file_name;
 {
-  static unsigned last_file_lookup_index = 0;
   register unsigned i;
 
-  /* Check to see if the file name that was searched on the previous call
-     matches this file name. If so, return the index.  */
-  if (last_file_lookup_index != 0)
-    if (strcmp (file_name, file_table[last_file_lookup_index]) == 0)
-      return last_file_lookup_index;
+  /* Check to see if the file name that was searched on the previous
+     call matches this file name.  If so, return the index.  */
+  if (t->last_lookup_index != 0)
+    if (strcmp (file_name, t->table[t->last_lookup_index]) == 0)
+      return t->last_lookup_index;
 
   /* Didn't match the previous lookup, search the table */
-  for (i = 1; i < file_table_in_use; ++i)
-    if (strcmp (file_name, file_table[i]) == 0)
+  for (i = 1; i < t->in_use; ++i)
+    if (strcmp (file_name, t->table[i]) == 0)
       {
-       last_file_lookup_index = i;
+       t->last_lookup_index = i;
        return i;
       }
 
   /* Prepare to add a new table entry by making sure there is enough space in
      the table to do so.  If not, expand the current table.  */
-  if (file_table_in_use == file_table_allocated)
+  if (i == t->allocated)
     {
-      file_table_allocated += FILE_TABLE_INCREMENT;
-      file_table
-       = (char **) xrealloc (file_table,
-                             file_table_allocated * sizeof (char *));
+      t->allocated = i + FILE_TABLE_INCREMENT;
+      t->table = (char **)
+       xrealloc (t->table, t->allocated * sizeof (char *));
     }
 
   /* Add the new entry to the end of the filename table.  */
-  file_table[file_table_in_use] = xstrdup (file_name);
-  last_file_lookup_index = file_table_in_use++;
+  t->table[i] = xstrdup (file_name);
+  t->in_use = i + 1;
+  t->last_lookup_index = i;
+
+  return i;
+}
+
+static void
+init_file_table (t)
+     struct file_table *t;
+{
+  /* Allocate the initial hunk of the file_table.  */
+  t->table = (char **) xcalloc (FILE_TABLE_INCREMENT, sizeof (char *));
+  t->allocated = FILE_TABLE_INCREMENT;
 
-  return last_file_lookup_index;
+  /* Skip the first entry - file numbers begin at 1.  */
+  t->in_use = 1;
+  t->last_lookup_index = 0;
 }
 
 /* Output a label to mark the beginning of a source code line entry
@@ -10661,19 +11317,26 @@ dwarf2out_line (filename, line)
 
       if (DWARF2_ASM_LINE_DEBUG_INFO)
        {
-         static const char *lastfile;
+         unsigned old_in_use = line_file_table.in_use;
+         unsigned file_num = lookup_filename (&line_file_table, filename);
 
          /* Emit the .file and .loc directives understood by GNU as.  */
-         if (lastfile == 0 || strcmp (filename, lastfile))
+#if 0
+         /* ??? As of 2000-11-25, gas has a bug in which it doesn't
+            actually use the file number argument.  It merely remembers
+            the last .file directive emitted.  */
+         if (file_num >= old_in_use)
+           fprintf (asm_out_file, "\t.file %d \"%s\"\n", file_num, filename);
+         fprintf (asm_out_file, "\t.loc %d %d 0\n", file_num, line);
+#else
+         static int last_file_num;
+         if (file_num != last_file_num)
            {
-             if (lastfile == 0)
-               ggc_add_string_root ((char **) &lastfile, 1);
-
+             last_file_num = file_num;
              fprintf (asm_out_file, "\t.file 0 \"%s\"\n", filename);
-             lastfile = filename;
            }
-
          fprintf (asm_out_file, "\t.loc 0 %d 0\n", line);
+#endif
 
          /* Indicate that line number info exists.  */
          ++line_info_table_in_use;
@@ -10706,7 +11369,7 @@ dwarf2out_line (filename, line)
          /* Add the new entry at the end of the line_info_table.  */
          line_info
            = &separate_line_info_table[separate_line_info_table_in_use++];
-         line_info->dw_file_num = lookup_filename (filename);
+         line_info->dw_file_num = lookup_filename (&line_file_table, filename);
          line_info->dw_line_num = line;
          line_info->function = current_funcdef_number;
        }
@@ -10733,7 +11396,7 @@ dwarf2out_line (filename, line)
 
          /* Add the new entry at the end of the line_info_table.  */
          line_info = &line_info_table[line_info_table_in_use++];
-         line_info->dw_file_num = lookup_filename (filename);
+         line_info->dw_file_num = lookup_filename (&line_file_table, filename);
          line_info->dw_line_num = line;
        }
     }
@@ -10764,7 +11427,7 @@ dwarf2out_end_source_file ()
     {
       /* Record the end of the file for break_out_includes.  */
       new_die (DW_TAG_GNU_EINCL, comp_unit_die);
-    }      
+    }
 }
 
 /* Called from check_newline in c-parse.y.  The `buffer' parameter contains
@@ -10805,12 +11468,8 @@ dwarf2out_init (asm_out_file, main_input_filename)
   /* Remember the name of the primary input file.  */
   primary_filename = main_input_filename;
 
-  /* Allocate the initial hunk of the file_table.  */
-  file_table = (char **) xcalloc (FILE_TABLE_INCREMENT, sizeof (char *));
-  file_table_allocated = FILE_TABLE_INCREMENT;
-
-  /* Skip the first entry - file numbers begin at 1.  */
-  file_table_in_use = 1;
+  init_file_table (&decl_file_table);
+  init_file_table (&line_file_table);
 
   /* Allocate the initial hunk of the decl_die_table.  */
   decl_die_table
@@ -10847,11 +11506,8 @@ dwarf2out_init (asm_out_file, main_input_filename)
      invoked when the given (base) source file was compiled.  */
   comp_unit_die = gen_compile_unit_die (main_input_filename);
 
-  if (ggc_p)
-    {
-      VARRAY_RTX_INIT (used_rtx_varray, 32, "used_rtx_varray");
-      ggc_add_rtx_varray_root (&used_rtx_varray, 1);
-    }
+  VARRAY_RTX_INIT (used_rtx_varray, 32, "used_rtx_varray");
+  ggc_add_rtx_varray_root (&used_rtx_varray, 1);
 
   ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label, ABBREV_SECTION_LABEL, 0);