OSDN Git Service

* config/m68hc11/m68hc11.c (m68hc11_gen_highpart): Don't use
[pf3gnuchains/gcc-fork.git] / gcc / dwarf2out.c
index 1b55383..13a7e57 100644 (file)
@@ -1,5 +1,5 @@
 /* Output Dwarf2 format symbol table information from the GNU C compiler.
-   Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000
+   Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001
    Free Software Foundation, Inc.
    Contributed by Gary Funck (gary@intrepid.com).
    Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com).
@@ -37,7 +37,6 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
-#include "defaults.h"
 #include "tree.h"
 #include "flags.h"
 #include "rtl.h"
@@ -45,16 +44,42 @@ Boston, MA 02111-1307, USA.  */
 #include "regs.h"
 #include "insn-config.h"
 #include "reload.h"
+#include "function.h"
 #include "output.h"
 #include "expr.h"
 #include "except.h"
 #include "dwarf2.h"
 #include "dwarf2out.h"
+#include "dwarf2asm.h"
 #include "toplev.h"
 #include "varray.h"
 #include "ggc.h"
 #include "md5.h"
 #include "tm_p.h"
+#include "diagnostic.h"
+#include "debug.h"
+
+#ifdef DWARF2_DEBUGGING_INFO
+static void dwarf2out_source_line      PARAMS ((unsigned int, const char *));
+#endif
+
+/* DWARF2 Abbreviation Glossary:
+   CFA = Canonical Frame Address
+          a fixed address on the stack which identifies a call frame.
+          We define it to be the value of SP just before the call insn.
+          The CFA register and offset, which may change during the course
+          of the function, are used to calculate its value at runtime.
+   CFI = Call Frame Instruction
+          an instruction for the DWARF2 abstract machine
+   CIE = Common Information Entry
+          information describing information common to one or more FDEs
+   DIE = Debugging Information Entry
+   FDE = Frame Description Entry
+          information describing the stack call frame, in particular,
+          how to restore registers
+
+   DW_CFA_... = DWARF2 CFA call frame instruction
+   DW_TAG_... = DWARF2 DIE tag */
 
 /* Decide whether we want to emit frame unwind information for the current
    translation unit.  */
@@ -68,11 +93,18 @@ dwarf2out_do_frame ()
 #endif
 #ifdef DWARF2_UNWIND_INFO
          || flag_unwind_tables
-         || (flag_exceptions && ! exceptions_via_longjmp)
+         || (flag_exceptions && ! USING_SJLJ_EXCEPTIONS)
 #endif
          );
 }
 
+/* The number of the current function definition for which debugging
+   information is being generated.  These numbers range from 1 up to the
+   maximum number of function definitions contained within the current
+   compilation unit.  These numbers are used to create unique label id's
+   unique to each function definition.  */
+unsigned current_funcdef_number = 0;
+
 #if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
 
 /* How to start an assembler comment.  */
@@ -132,22 +164,15 @@ typedef struct dw_fde_struct
   const char *dw_fde_current_label;
   const char *dw_fde_end;
   dw_cfi_ref dw_fde_cfi;
-  int nothrow;
+  unsigned funcdef_number;
+  unsigned nothrow : 1;
+  unsigned uses_eh_lsda : 1;
 }
 dw_fde_node;
 
 /* Maximum size (in bytes) of an artificially generated label.   */
 #define MAX_ARTIFICIAL_LABEL_BYTES     30
 
-/* Make sure we know the sizes of the various types dwarf can describe. These
-   are only defaults.  If the sizes are different for your target, you should
-   override these values by defining the appropriate symbols in your tm.h
-   file.  */
-
-#ifndef CHAR_TYPE_SIZE
-#define CHAR_TYPE_SIZE BITS_PER_UNIT
-#endif
-
 /* The size of the target's pointer type.  */
 #ifndef PTR_SIZE
 #define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
@@ -178,11 +203,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.  */
@@ -201,13 +228,6 @@ static unsigned fde_table_in_use;
 /* A list of call frame insns for the CIE.  */
 static dw_cfi_ref cie_cfi_head;
 
-/* The number of the current function definition for which debugging
-   information is being generated.  These numbers range from 1 up to the
-   maximum number of function definitions contained within the current
-   compilation unit.  These numbers are used to create unique label id's
-   unique to each function definition.  */
-static unsigned current_funcdef_number = 0;
-
 /* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram
    attribute that accelerates the lookup of the FDE associated
    with the subprogram.  This variable holds the table index of the FDE
@@ -220,19 +240,19 @@ static char *stripattributes              PARAMS ((const char *));
 static const char *dwarf_cfi_name      PARAMS ((unsigned));
 static dw_cfi_ref new_cfi              PARAMS ((void));
 static void add_cfi                    PARAMS ((dw_cfi_ref *, dw_cfi_ref));
-static unsigned long size_of_uleb128   PARAMS ((unsigned long));
-static unsigned long size_of_sleb128   PARAMS ((long));
-static void output_uleb128             PARAMS ((unsigned long));
-static void output_sleb128             PARAMS ((long));
 static void add_fde_cfi                        PARAMS ((const char *, dw_cfi_ref));
 static void lookup_cfa_1               PARAMS ((dw_cfi_ref, dw_cfa_location *));
 static void lookup_cfa                 PARAMS ((dw_cfa_location *));
 static void reg_save                   PARAMS ((const char *, unsigned,
                                                 unsigned, long));
 static void initial_return_save                PARAMS ((rtx));
-static void output_cfi                 PARAMS ((dw_cfi_ref, dw_fde_ref));
+static long stack_adjust_offset                PARAMS ((rtx));
+static void output_cfi                 PARAMS ((dw_cfi_ref, dw_fde_ref, int));
 static void output_call_frame_info     PARAMS ((int));
 static void dwarf2out_stack_adjust     PARAMS ((rtx));
+static void queue_reg_save             PARAMS ((const char *, rtx, long));
+static void flush_queued_reg_saves     PARAMS ((void));
+static bool clobbers_queued_reg_save   PARAMS ((rtx));
 static void dwarf2out_frame_debug_expr PARAMS ((rtx, const char *));
 
 /* Support for complex CFA locations.  */
@@ -243,25 +263,9 @@ static struct dw_loc_descr_struct *build_cfa_loc
                                        PARAMS ((dw_cfa_location *));
 static void def_cfa_1                  PARAMS ((const char *, dw_cfa_location *));
 
-/* Definitions of defaults for assembler-dependent names of various
-   pseudo-ops and section names.
-   Theses may be overridden in the tm.h file (if necessary) for a particular
-   assembler.  */
-
-#ifdef OBJECT_FORMAT_ELF
-#ifndef UNALIGNED_SHORT_ASM_OP
-#define UNALIGNED_SHORT_ASM_OP ".2byte"
-#endif
-#ifndef UNALIGNED_INT_ASM_OP
-#define UNALIGNED_INT_ASM_OP   ".4byte"
-#endif
-#ifndef UNALIGNED_DOUBLE_INT_ASM_OP
-#define UNALIGNED_DOUBLE_INT_ASM_OP    ".8byte"
-#endif
-#endif /* OBJECT_FORMAT_ELF */
-
-#ifndef ASM_BYTE_OP
-#define ASM_BYTE_OP            ".byte"
+/* How to start an assembler comment.  */
+#ifndef ASM_COMMENT_START
+#define ASM_COMMENT_START ";#"
 #endif
 
 /* Data and reference forms for relocatable data.  */
@@ -270,7 +274,7 @@ static void def_cfa_1                       PARAMS ((const char *, dw_cfa_location *));
 
 /* Pseudo-op for defining a new section.  */
 #ifndef SECTION_ASM_OP
-#define SECTION_ASM_OP ".section"
+#define SECTION_ASM_OP "\t.section\t"
 #endif
 
 /* The default format used by the ASM_OUTPUT_SECTION macro (see below) to
@@ -281,12 +285,12 @@ static void def_cfa_1                     PARAMS ((const char *, dw_cfa_location *));
 #ifdef PUSHSECTION_FORMAT
 #define SECTION_FORMAT PUSHSECTION_FORMAT
 #else
-#define SECTION_FORMAT         "\t%s\t%s\n"
+#define SECTION_FORMAT         "%s%s\n"
 #endif
 #endif
 
-#ifndef FRAME_SECTION
-#define FRAME_SECTION          ".debug_frame"
+#ifndef DEBUG_FRAME_SECTION
+#define DEBUG_FRAME_SECTION    ".debug_frame"
 #endif
 
 #ifndef FUNC_BEGIN_LABEL
@@ -298,9 +302,14 @@ static void def_cfa_1                      PARAMS ((const char *, dw_cfa_location *));
 #define CIE_AFTER_SIZE_LABEL   "LSCIE"
 #define CIE_END_LABEL          "LECIE"
 #define CIE_LENGTH_LABEL       "LLCIE"
-#define FDE_AFTER_SIZE_LABEL   "LSFDE"
+#define FDE_LABEL              "LSFDE"
+#define FDE_AFTER_SIZE_LABEL   "LASFDE"
 #define FDE_END_LABEL          "LEFDE"
 #define FDE_LENGTH_LABEL       "LLFDE"
+#define LINE_NUMBER_BEGIN_LABEL        "LSLT"
+#define LINE_NUMBER_END_LABEL  "LELT"
+#define LN_PROLOG_AS_LABEL     "LASLTP"
+#define LN_PROLOG_END_LABEL    "LELTP"
 #define DIE_LABEL_PREFIX       "DW"
 
 /* Definitions of defaults for various types of primitive assembly language
@@ -312,217 +321,11 @@ static void def_cfa_1                    PARAMS ((const char *, dw_cfa_location *));
   fprintf ((FILE), SECTION_FORMAT, SECTION_ASM_OP, SECTION)
 #endif
 
-#ifndef ASM_OUTPUT_DWARF_DATA1
-#define ASM_OUTPUT_DWARF_DATA1(FILE,VALUE) \
-  fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) (VALUE))
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_DELTA1
-#define ASM_OUTPUT_DWARF_DELTA1(FILE,LABEL1,LABEL2)                    \
- do {  fprintf ((FILE), "\t%s\t", ASM_BYTE_OP);                        \
-       assemble_name (FILE, LABEL1);                                   \
-       fprintf (FILE, "-");                                            \
-       assemble_name (FILE, LABEL2);                                   \
-  } while (0)
-#endif
-
-#ifdef UNALIGNED_INT_ASM_OP
-
-#ifndef UNALIGNED_OFFSET_ASM_OP
-#define UNALIGNED_OFFSET_ASM_OP \
-  (DWARF_OFFSET_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
-#endif
-
-#ifndef UNALIGNED_WORD_ASM_OP
-#define UNALIGNED_WORD_ASM_OP                                          \
-  ((DWARF2_ADDR_SIZE) == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP               \
-   : (DWARF2_ADDR_SIZE) == 2 ? UNALIGNED_SHORT_ASM_OP                  \
-   : UNALIGNED_INT_ASM_OP)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_DELTA2
-#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2)                    \
- do {  fprintf ((FILE), "\t%s\t", UNALIGNED_SHORT_ASM_OP);             \
-       assemble_name (FILE, LABEL1);                                   \
-       fprintf (FILE, "-");                                            \
-       assemble_name (FILE, LABEL2);                                   \
-  } while (0)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_DELTA4
-#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2)                    \
- do {  fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP);               \
-       assemble_name (FILE, LABEL1);                                   \
-       fprintf (FILE, "-");                                            \
-       assemble_name (FILE, LABEL2);                                   \
-  } while (0)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_DELTA
-#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2)                     \
- do {  fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP);            \
-       assemble_name (FILE, LABEL1);                                   \
-       fprintf (FILE, "-");                                            \
-       assemble_name (FILE, LABEL2);                                   \
-  } while (0)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_ADDR_DELTA
-#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2)                        \
- do {  fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP);              \
-       assemble_name (FILE, LABEL1);                                   \
-       fprintf (FILE, "-");                                            \
-       assemble_name (FILE, LABEL2);                                   \
-  } while (0)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_ADDR
-#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL)                              \
- do {  fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP);              \
-       assemble_name (FILE, LABEL);                                    \
-  } while (0)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_ADDR_CONST
-#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,RTX)                          \
-  do {                                                                 \
-    fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP);                 \
-    output_addr_const ((FILE), (RTX));                                 \
-  } while (0)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_OFFSET4
-#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \
- do {  fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP);               \
-       assemble_name (FILE, LABEL);                                    \
-  } while (0)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_OFFSET
-#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL)                            \
- do {  fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP);            \
-       assemble_name (FILE, LABEL);                                    \
-  } while (0)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_DATA2
-#define ASM_OUTPUT_DWARF_DATA2(FILE,VALUE) \
-  fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_SHORT_ASM_OP, (unsigned) (VALUE))
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_DATA4
-#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \
-  fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_INT_ASM_OP, (unsigned) (VALUE))
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_DATA8
-#define ASM_OUTPUT_DWARF_DATA8(FILE,VALUE) \
-  fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_DOUBLE_INT_ASM_OP, \
-          (unsigned long) (VALUE))
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_DATA
-#define ASM_OUTPUT_DWARF_DATA(FILE,VALUE) \
-  fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_OFFSET_ASM_OP, \
-          (unsigned long) (VALUE))
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_ADDR_DATA
-#define ASM_OUTPUT_DWARF_ADDR_DATA(FILE,VALUE) \
-  fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_WORD_ASM_OP, \
-          (unsigned long) (VALUE))
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_CONST_DOUBLE
-#define ASM_OUTPUT_DWARF_CONST_DOUBLE(FILE,HIGH_VALUE,LOW_VALUE)       \
-  do {                                                                 \
-    if (WORDS_BIG_ENDIAN)                                              \
-      {                                                                        \
-       fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (HIGH_VALUE));\
-       fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (LOW_VALUE));\
-      }                                                                        \
-    else                                                               \
-      {                                                                        \
-       fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (LOW_VALUE)); \
-       fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (HIGH_VALUE)); \
-      }                                                                        \
-  } while (0)
-#endif
-
-#else /* UNALIGNED_INT_ASM_OP */
-
-/* We don't have unaligned support, let's hope the normal output works for
-   .debug_frame.  But we know it won't work for .debug_info.  */
-
-#ifdef DWARF2_DEBUGGING_INFO
- #error DWARF2_DEBUGGING_INFO requires UNALIGNED_INT_ASM_OP.
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_ADDR
-#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \
-  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, LABEL), DWARF2_ADDR_SIZE, 1)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_ADDR_CONST
-#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,RTX) ASM_OUTPUT_DWARF_ADDR (FILE,RTX)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_OFFSET4
-#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \
-  assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_OFFSET
-#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \
-  assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_DELTA2
-#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2)                    \
-  assemble_integer (gen_rtx_MINUS (HImode,                             \
-                                  gen_rtx_SYMBOL_REF (Pmode, LABEL1),  \
-                                  gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \
-                   2, 1)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_DELTA4
-#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2)                    \
-  assemble_integer (gen_rtx_MINUS (SImode,                             \
-                                  gen_rtx_SYMBOL_REF (Pmode, LABEL1),  \
-                                  gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \
-                   4, 1)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_ADDR_DELTA
-#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2)                        \
-  assemble_integer (gen_rtx_MINUS (Pmode,                              \
-                                  gen_rtx_SYMBOL_REF (Pmode, LABEL1),  \
-                                  gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \
-                   DWARF2_ADDR_SIZE, 1)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_DELTA
-#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \
-  ASM_OUTPUT_DWARF_DELTA4 (FILE,LABEL1,LABEL2)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_DATA2
-#define ASM_OUTPUT_DWARF_DATA2(FILE,VALUE) \
-  assemble_integer (GEN_INT (VALUE), 2, 1)
-#endif
-
-#ifndef ASM_OUTPUT_DWARF_DATA4
-#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \
-  assemble_integer (GEN_INT (VALUE), 4, 1)
-#endif
-
-#endif /* UNALIGNED_INT_ASM_OP */
-
 #ifdef SET_ASM_OP
 #ifndef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
 #define ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL(FILE, SY, HI, LO)            \
  do {                                                                  \
-  fprintf (FILE, "\t%s\t", SET_ASM_OP);                                        \
+  fprintf (FILE, "%s", SET_ASM_OP);                                    \
   assemble_name (FILE, SY);                                            \
   fputc (',', FILE);                                                   \
   assemble_name (FILE, HI);                                            \
@@ -532,33 +335,6 @@ static void def_cfa_1                      PARAMS ((const char *, dw_cfa_location *));
 #endif
 #endif /* SET_ASM_OP */
 
-/* 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) \
-  do {                                                                       \
-    register int slen = strlen(P);                                            \
-    register const char *p = (P);                                            \
-    register int i;                                                          \
-    fprintf (FILE, "\t.ascii \"");                                           \
-    for (i = 0; i < slen; i++)                                               \
-      {                                                                              \
-         register int c = p[i];                                              \
-         if (c == '\"' || c == '\\')                                         \
-           putc ('\\', FILE);                                                \
-         if (ISPRINT(c))                                                     \
-           putc (c, FILE);                                                   \
-         else                                                                \
-           {                                                                 \
-             fprintf (FILE, "\\%o", c);                                      \
-           }                                                                 \
-      }                                                                              \
-    fprintf (FILE, "\\0\"");                                                 \
-  }                                                                          \
-  while (0)
-#endif
-
 /* 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
    registers.  */
@@ -589,7 +365,7 @@ expand_builtin_dwarf_fp_regnum ()
 #ifndef INCOMING_FRAME_SP_OFFSET
 #define INCOMING_FRAME_SP_OFFSET 0
 #endif
-
+\f
 /* Return a pointer to a copy of the section string name S with all
    attributes stripped off, and an asterisk prepended (for assemble_name).  */
 
@@ -628,9 +404,7 @@ expand_builtin_init_dwarf_reg_sizes (address)
       if (offset < 0)
        continue;
 
-      emit_move_insn (change_address (mem, mode,
-                                     plus_constant (addr, offset)),
-                     GEN_INT (size));
+      emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size));
     }
 }
 
@@ -830,11 +604,11 @@ lookup_cfa (loc)
 }
 
 /* The current rule for calculating the DWARF2 canonical frame address.  */
-dw_cfa_location cfa;
+static dw_cfa_location cfa;
 
 /* The register used for saving registers to the stack, and its offset
    from the CFA.  */
-dw_cfa_location cfa_store;
+static dw_cfa_location cfa_store;
 
 /* The running total of the size of arguments pushed onto the stack.  */
 static long args_size;
@@ -860,7 +634,7 @@ dwarf2out_def_cfa (label, reg, offset)
   def_cfa_1 (label, &loc);
 }
 
-/* This routine does the actual work. The CFA is now calculated from
+/* This routine does the actual work.  The CFA is now calculated from
    the dw_cfa_location structure.  */
 static void
 def_cfa_1 (label, loc_p)
@@ -884,6 +658,8 @@ def_cfa_1 (label, loc_p)
     {
       if (loc.indirect == 0
          || loc.base_offset == old_cfa.base_offset)
+       /* Nothing changed so no need to issue any call frame
+           instructions.  */
        return;
     }
 
@@ -891,6 +667,9 @@ def_cfa_1 (label, loc_p)
 
   if (loc.reg == old_cfa.reg && !loc.indirect)
     {
+      /* Construct a "DW_CFA_def_cfa_offset <offset>" instruction,
+        indicating the CFA register did not change but the offset
+        did.  */
       cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
       cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset;
     }
@@ -899,6 +678,9 @@ def_cfa_1 (label, loc_p)
   else if (loc.offset == old_cfa.offset && old_cfa.reg != (unsigned long) -1
           && !loc.indirect)
     {
+      /* Construct a "DW_CFA_def_cfa_register <register>" instruction,
+        indicating the CFA register has changed to <register> but the
+        offset has not changed.  */
       cfi->dw_cfi_opc = DW_CFA_def_cfa_register;
       cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
     }
@@ -906,12 +688,18 @@ def_cfa_1 (label, loc_p)
 
   else if (loc.indirect == 0)
     {
+      /* Construct a "DW_CFA_def_cfa <register> <offset>" instruction,
+        indicating the CFA register has changed to <register> with
+        the specified offset.  */
       cfi->dw_cfi_opc = DW_CFA_def_cfa;
       cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
       cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset;
     }
   else
     {
+      /* Construct a DW_CFA_def_cfa_expression instruction to
+        calculate the CFA using a full location expression since no
+        register-offset pair is available.  */
       struct dw_loc_descr_struct *loc_list;
       cfi->dw_cfi_opc = DW_CFA_def_cfa_expression;
       loc_list = build_cfa_loc (&loc);
@@ -948,6 +736,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)
        {
@@ -1096,7 +896,8 @@ initial_return_save (rtl)
 /* Given a SET, calculate the amount of stack adjustment it
    contains. */
 
-static long stack_adjust_offset (pattern)
+static long
+stack_adjust_offset (pattern)
   rtx pattern;
 {
   rtx src = SET_SRC (pattern);
@@ -1121,11 +922,21 @@ static long stack_adjust_offset (pattern)
       src = XEXP (dest, 0);
       code = GET_CODE (src);
 
-      if (! (code == PRE_DEC || code == PRE_INC)
+      if (! (code == PRE_DEC || code == PRE_INC
+            || code == PRE_MODIFY)
          || XEXP (src, 0) != stack_pointer_rtx)
        return 0;
 
-      offset = GET_MODE_SIZE (GET_MODE (dest));
+      if (code == PRE_MODIFY)
+       {
+         rtx val = XEXP (XEXP (src, 1), 1);
+         /* We handle only adjustments by constant amount.  */
+         if (GET_CODE (XEXP (src, 1)) != PLUS ||
+             GET_CODE (val) != CONST_INT)
+           abort();
+         offset = -INTVAL (val);
+       }
+      else offset = GET_MODE_SIZE (GET_MODE (dest));
     }
   else
     return 0;
@@ -1147,7 +958,7 @@ dwarf2out_stack_adjust (insn)
   long offset;
   const char *label;
 
-  if (! asynchronous_exceptions && GET_CODE (insn) == CALL_INSN)
+  if (! flag_non_call_exceptions && GET_CODE (insn) == CALL_INSN)
     {
       /* Extract the size of the args from the CALL rtx itself.  */
 
@@ -1164,7 +975,7 @@ dwarf2out_stack_adjust (insn)
 
   /* If only calls can throw, and we have a frame pointer,
      save up adjustments until we see the CALL_INSN.  */
-  else if (! asynchronous_exceptions
+  else if (! flag_non_call_exceptions
           && cfa.reg != STACK_POINTER_REGNUM)
     return;
 
@@ -1200,7 +1011,7 @@ dwarf2out_stack_adjust (insn)
     }
   else
     return;
-  
+
   if (offset == 0)
     return;
 
@@ -1219,15 +1030,219 @@ dwarf2out_stack_adjust (insn)
   dwarf2out_args_size (label, args_size);
 }
 
-/* A temporary register used in adjusting SP or setting up the store_reg.  */
-static unsigned cfa_temp_reg;
+/* We delay emitting a register save until either (a) we reach the end
+   of the prologue or (b) the register is clobbered.  This clusters
+   register saves so that there are fewer pc advances.  */
 
-/* A temporary value used in adjusting SP or setting up the store_reg.  */
-static long cfa_temp_value;
+struct queued_reg_save
+{
+  struct queued_reg_save *next;
+  rtx reg;
+  long cfa_offset;
+};
 
-/* Record call frame debugging information for an expression, which either
-   sets SP or FP (adjusting how we calculate the frame address) or saves a
-   register to the stack.  */
+static struct queued_reg_save *queued_reg_saves;
+static const char *last_reg_save_label;
+
+static void
+queue_reg_save (label, reg, offset)
+     const char *label;
+     rtx reg;
+     long offset;
+{
+  struct queued_reg_save *q = (struct queued_reg_save *) xmalloc (sizeof (*q));
+
+  q->next = queued_reg_saves;
+  q->reg = reg;
+  q->cfa_offset = offset;
+  queued_reg_saves = q;
+
+  last_reg_save_label = label;
+}
+
+static void
+flush_queued_reg_saves ()
+{
+  struct queued_reg_save *q, *next;
+
+  for (q = queued_reg_saves; q ; q = next)
+    {
+      dwarf2out_reg_save (last_reg_save_label, REGNO (q->reg), q->cfa_offset);
+      next = q->next;
+      free (q);
+    }
+
+  queued_reg_saves = NULL;
+  last_reg_save_label = NULL;
+}
+
+static bool
+clobbers_queued_reg_save (insn)
+     rtx insn;
+{
+  struct queued_reg_save *q;
+
+  for (q = queued_reg_saves; q ; q = q->next)
+    if (modified_in_p (q->reg, insn))
+      return true;
+
+  return false;
+}
+  
+
+/* A temporary register holding an integral value used in adjusting SP
+   or setting up the store_reg.  The "offset" field holds the integer
+   value, not an offset.  */
+static dw_cfa_location cfa_temp;
+
+/* Record call frame debugging information for an expression EXPR,
+   which either sets SP or FP (adjusting how we calculate the frame
+   address) or saves a register to the stack.  LABEL indicates the
+   address of EXPR.
+
+   This function encodes a state machine mapping rtxes to actions on
+   cfa, cfa_store, and cfa_temp.reg.  We describe these rules so
+   users need not read the source code.
+
+  The High-Level Picture
+
+  Changes in the register we use to calculate the CFA: Currently we
+  assume that if you copy the CFA register into another register, we
+  should take the other one as the new CFA register; this seems to
+  work pretty well.  If it's wrong for some target, it's simple
+  enough not to set RTX_FRAME_RELATED_P on the insn in question.
+
+  Changes in the register we use for saving registers to the stack:
+  This is usually SP, but not always.  Again, we deduce that if you
+  copy SP into another register (and SP is not the CFA register),
+  then the new register is the one we will be using for register
+  saves.  This also seems to work.
+
+  Register saves: There's not much guesswork about this one; if
+  RTX_FRAME_RELATED_P is set on an insn which modifies memory, it's a
+  register save, and the register used to calculate the destination
+  had better be the one we think we're using for this purpose.
+
+  Except: If the register being saved is the CFA register, and the
+  offset is non-zero, we are saving the CFA, so we assume we have to
+  use DW_CFA_def_cfa_expression.  If the offset is 0, we assume that
+  the intent is to save the value of SP from the previous frame.
+
+  Invariants / Summaries of Rules
+
+  cfa         current rule for calculating the CFA.  It usually
+              consists of a register and an offset.
+  cfa_store    register used by prologue code to save things to the stack
+              cfa_store.offset is the offset from the value of
+              cfa_store.reg to the actual CFA
+  cfa_temp     register holding an integral value.  cfa_temp.offset
+              stores the value, which will be used to adjust the
+              stack pointer.  cfa_temp is also used like cfa_store,
+              to track stores to the stack via fp or a temp reg.
+  Rules  1- 4: Setting a register's value to cfa.reg or an expression
+              with cfa.reg as the first operand changes the cfa.reg and its
+              cfa.offset.  Rule 1 and 4 also set cfa_temp.reg and
+              cfa_temp.offset.
+
+  Rules  6- 9: Set a non-cfa.reg register value to a constant or an
+              expression yielding a constant.  This sets cfa_temp.reg
+              and cfa_temp.offset.
+
+  Rule 5:      Create a new register cfa_store used to save items to the
+              stack.
+
+  Rules 10-14: Save a register to the stack.  Define offset as the
+              difference of the original location and cfa_store's
+              location (or cfa_temp's location if cfa_temp is used).
+
+  The Rules
+
+  "{a,b}" indicates a choice of a xor b.
+  "<reg>:cfa.reg" indicates that <reg> must equal cfa.reg.
+
+  Rule 1:
+  (set <reg1> <reg2>:cfa.reg)
+  effects: cfa.reg = <reg1>
+           cfa.offset unchanged
+          cfa_temp.reg = <reg1>
+          cfa_temp.offset = cfa.offset
+
+  Rule 2:
+  (set sp ({minus,plus,losum} {sp,fp}:cfa.reg {<const_int>,<reg>:cfa_temp.reg}))
+  effects: cfa.reg = sp if fp used
+          cfa.offset += {+/- <const_int>, cfa_temp.offset} if cfa.reg==sp
+          cfa_store.offset += {+/- <const_int>, cfa_temp.offset}
+            if cfa_store.reg==sp
+
+  Rule 3:
+  (set fp ({minus,plus,losum} <reg>:cfa.reg <const_int>))
+  effects: cfa.reg = fp
+          cfa_offset += +/- <const_int>
+
+  Rule 4:
+  (set <reg1> ({plus,losum} <reg2>:cfa.reg <const_int>))
+  constraints: <reg1> != fp
+              <reg1> != sp
+  effects: cfa.reg = <reg1>
+          cfa_temp.reg = <reg1>
+          cfa_temp.offset = cfa.offset
+
+  Rule 5:
+  (set <reg1> (plus <reg2>:cfa_temp.reg sp:cfa.reg))
+  constraints: <reg1> != fp
+              <reg1> != sp
+  effects: cfa_store.reg = <reg1>
+          cfa_store.offset = cfa.offset - cfa_temp.offset
+
+  Rule 6:
+  (set <reg> <const_int>)
+  effects: cfa_temp.reg = <reg>
+          cfa_temp.offset = <const_int>
+
+  Rule 7:
+  (set <reg1>:cfa_temp.reg (ior <reg2>:cfa_temp.reg <const_int>))
+  effects: cfa_temp.reg = <reg1>
+          cfa_temp.offset |= <const_int>
+
+  Rule 8:
+  (set <reg> (high <exp>))
+  effects: none
+
+  Rule 9:
+  (set <reg> (lo_sum <exp> <const_int>))
+  effects: cfa_temp.reg = <reg>
+          cfa_temp.offset = <const_int>
+
+  Rule 10:
+  (set (mem (pre_modify sp:cfa_store (???? <reg1> <const_int>))) <reg2>)
+  effects: cfa_store.offset -= <const_int>
+          cfa.offset = cfa_store.offset if cfa.reg == sp
+          cfa.reg = sp
+          cfa.base_offset = -cfa_store.offset
+
+  Rule 11:
+  (set (mem ({pre_inc,pre_dec} sp:cfa_store.reg)) <reg>)
+  effects: cfa_store.offset += -/+ mode_size(mem)
+          cfa.offset = cfa_store.offset if cfa.reg == sp
+          cfa.reg = sp
+          cfa.base_offset = -cfa_store.offset
+
+  Rule 12:
+  (set (mem ({minus,plus,losum} <reg1>:{cfa_store,cfa_temp} <const_int>)) <reg2>)
+  effects: cfa.reg = <reg1>
+          cfa.base_offset = -/+ <const_int> - {cfa_store,cfa_temp}.offset
+
+  Rule 13:
+  (set (mem <reg1>:{cfa_store,cfa_temp}) <reg2>)
+  effects: cfa.reg = <reg1>
+          cfa.base_offset = -{cfa_store,cfa_temp}.offset
+
+  Rule 14:
+  (set (mem (postinc <reg1>:cfa_temp <const_int>)) <reg2>)
+  effects: cfa.reg = <reg1>
+          cfa.base_offset = -cfa_temp.offset
+          cfa_temp.offset -= mode_size(mem)  */
 
 static void
 dwarf2out_frame_debug_expr (expr, label)
@@ -1239,7 +1254,7 @@ dwarf2out_frame_debug_expr (expr, label)
 
   /* If RTX_FRAME_RELATED_P is set on a PARALLEL, process each member of
      the PARALLEL independently. The first element is always processed if
-     it is a SET. This is for backward compatability.   Other elements
+     it is a SET. This is for backward compatibility.   Other elements
      are processed only if they are SETs and the RTX_FRAME_RELATED_P
      flag is set in them.  */
 
@@ -1269,6 +1284,7 @@ dwarf2out_frame_debug_expr (expr, label)
   switch (GET_CODE (dest))
     {
     case REG:
+      /* Rule 1 */
       /* Update the CFA rule wrt SP or FP.  Make sure src is
          relative to the current CFA register.  */
       switch (GET_CODE (src))
@@ -1286,12 +1302,16 @@ dwarf2out_frame_debug_expr (expr, label)
             FP.  So we just rely on the backends to only set
             RTX_FRAME_RELATED_P on appropriate insns.  */
          cfa.reg = REGNO (dest);
+         cfa_temp.reg = cfa.reg;
+         cfa_temp.offset = cfa.offset;
          break;
 
        case PLUS:
        case MINUS:
+       case LO_SUM:
          if (dest == stack_pointer_rtx)
            {
+             /* Rule 2 */
              /* Adjusting SP.  */
              switch (GET_CODE (XEXP (src, 1)))
                {
@@ -1299,9 +1319,9 @@ dwarf2out_frame_debug_expr (expr, label)
                  offset = INTVAL (XEXP (src, 1));
                  break;
                case REG:
-                 if ((unsigned) REGNO (XEXP (src, 1)) != cfa_temp_reg)
+                 if ((unsigned) REGNO (XEXP (src, 1)) != cfa_temp.reg)
                    abort ();
-                 offset = cfa_temp_value;
+                 offset = cfa_temp.offset;
                  break;
                default:
                  abort ();
@@ -1314,10 +1334,13 @@ dwarf2out_frame_debug_expr (expr, label)
                    abort ();
                  cfa.reg = STACK_POINTER_REGNUM;
                }
+             else if (GET_CODE (src) == LO_SUM)
+               /* Assume we've set the source reg of the LO_SUM from sp.  */
+               ;
              else if (XEXP (src, 0) != stack_pointer_rtx)
                abort ();
 
-             if (GET_CODE (src) == PLUS)
+             if (GET_CODE (src) != MINUS)
                offset = -offset;
              if (cfa.reg == STACK_POINTER_REGNUM)
                cfa.offset += offset;
@@ -1326,6 +1349,7 @@ dwarf2out_frame_debug_expr (expr, label)
            }
          else if (dest == hard_frame_pointer_rtx)
            {
+             /* Rule 3 */
              /* Either setting the FP from an offset of the SP,
                 or adjusting the FP */
              if (! frame_pointer_needed)
@@ -1336,7 +1360,7 @@ dwarf2out_frame_debug_expr (expr, label)
                  && GET_CODE (XEXP (src, 1)) == CONST_INT)
                {
                  offset = INTVAL (XEXP (src, 1));
-                 if (GET_CODE (src) == PLUS)
+                 if (GET_CODE (src) != MINUS)
                    offset = -offset;
                  cfa.offset += offset;
                  cfa.reg = HARD_FRAME_POINTER_REGNUM;
@@ -1346,31 +1370,68 @@ dwarf2out_frame_debug_expr (expr, label)
            }
          else
            {
-             if (GET_CODE (src) != PLUS
-                 || XEXP (src, 1) != stack_pointer_rtx)
-               abort ();
-             if (GET_CODE (XEXP (src, 0)) != REG
-                 || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp_reg)
+             if (GET_CODE (src) == MINUS)
                abort ();
-             if (cfa.reg != STACK_POINTER_REGNUM)
+
+             /* Rule 4 */
+             if (GET_CODE (XEXP (src, 0)) == REG
+                 && REGNO (XEXP (src, 0)) == cfa.reg
+                 && GET_CODE (XEXP (src, 1)) == CONST_INT)
+               {
+                 /* Setting a temporary CFA register that will be copied
+                    into the FP later on.  */
+                 offset = - INTVAL (XEXP (src, 1));
+                 cfa.offset += offset;
+                 cfa.reg = REGNO (dest);
+                 /* Or used to save regs to the stack.  */
+                 cfa_temp.reg = cfa.reg;
+                 cfa_temp.offset = cfa.offset;
+               }
+             /* Rule 5 */
+             else if (GET_CODE (XEXP (src, 0)) == REG
+                      && REGNO (XEXP (src, 0)) == cfa_temp.reg
+                      && XEXP (src, 1) == stack_pointer_rtx)
+               {
+                 /* Setting a scratch register that we will use instead
+                    of SP for saving registers to the stack.  */
+                 if (cfa.reg != STACK_POINTER_REGNUM)
+                   abort ();
+                 cfa_store.reg = REGNO (dest);
+                 cfa_store.offset = cfa.offset - cfa_temp.offset;
+               }
+             /* Rule 9 */
+             else if (GET_CODE (src) == LO_SUM
+                      && GET_CODE (XEXP (src, 1)) == CONST_INT)
+               {
+                 cfa_temp.reg = REGNO (dest);
+                 cfa_temp.offset = INTVAL (XEXP (src, 1));
+               }
+             else
                abort ();
-             cfa_store.reg = REGNO (dest);
-             cfa_store.offset = cfa.offset - cfa_temp_value;
            }
          break;
 
+         /* Rule 6 */
        case CONST_INT:
-         cfa_temp_reg = REGNO (dest);
-         cfa_temp_value = INTVAL (src);
+         cfa_temp.reg = REGNO (dest);
+         cfa_temp.offset = INTVAL (src);
          break;
 
+         /* Rule 7 */
        case IOR:
          if (GET_CODE (XEXP (src, 0)) != REG
-             || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp_reg
-             || (unsigned) REGNO (dest) != cfa_temp_reg
+             || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp.reg
              || GET_CODE (XEXP (src, 1)) != CONST_INT)
            abort ();
-         cfa_temp_value |= INTVAL (XEXP (src, 1));
+         if ((unsigned) REGNO (dest) != cfa_temp.reg)
+           cfa_temp.reg = REGNO (dest);
+         cfa_temp.offset |= INTVAL (XEXP (src, 1));
+         break;
+
+         /* Skip over HIGH, assuming it will be followed by a LO_SUM,
+            which will fill in all of the bits.  */
+         /* Rule 8 */
+       case HIGH:
          break;
 
        default:
@@ -1379,16 +1440,6 @@ dwarf2out_frame_debug_expr (expr, label)
       def_cfa_1 (label, &cfa);
       break;
 
-      /* Skip over HIGH, assuming it will be followed by a LO_SUM, which
-        will fill in all of the bits.  */
-    case HIGH:
-      break;
-
-    case LO_SUM:
-      cfa_temp_reg = REGNO (dest);
-      cfa_temp_value = INTVAL (XEXP (src, 1));
-      break;
-
     case MEM:
       if (GET_CODE (src) != REG)
        abort ();
@@ -1397,7 +1448,24 @@ dwarf2out_frame_debug_expr (expr, label)
         CFA register.  */
       switch (GET_CODE (XEXP (dest, 0)))
        {
+         /* Rule 10 */
          /* With a push.  */
+       case PRE_MODIFY:
+         /* We can't handle variable size modifications.  */
+         if (GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1)) != CONST_INT)
+           abort();
+         offset = -INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1));
+
+         if (REGNO (XEXP (XEXP (dest, 0), 0)) != STACK_POINTER_REGNUM
+             || cfa_store.reg != STACK_POINTER_REGNUM)
+           abort ();
+         cfa_store.offset += offset;
+         if (cfa.reg == STACK_POINTER_REGNUM)
+           cfa.offset = cfa_store.offset;
+
+         offset = -cfa_store.offset;
+         break;
+         /* Rule 11 */
        case PRE_INC:
        case PRE_DEC:
          offset = GET_MODE_SIZE (GET_MODE (dest));
@@ -1414,23 +1482,42 @@ dwarf2out_frame_debug_expr (expr, label)
          offset = -cfa_store.offset;
          break;
 
+         /* Rule 12 */
          /* With an offset.  */
        case PLUS:
        case MINUS:
+       case LO_SUM:
+         if (GET_CODE (XEXP (XEXP (dest, 0), 1)) != CONST_INT)
+           abort ();
          offset = INTVAL (XEXP (XEXP (dest, 0), 1));
          if (GET_CODE (XEXP (dest, 0)) == MINUS)
            offset = -offset;
 
-         if (cfa_store.reg != (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)))
+         if (cfa_store.reg == (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)))
+           offset -= cfa_store.offset;
+         else if (cfa_temp.reg == (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)))
+           offset -= cfa_temp.offset;
+         else
            abort ();
-         offset -= cfa_store.offset;
          break;
 
+         /* Rule 13 */
          /* Without an offset.  */
        case REG:
-         if (cfa_store.reg != (unsigned) REGNO (XEXP (dest, 0)))
+         if (cfa_store.reg == (unsigned) REGNO (XEXP (dest, 0)))
+           offset = -cfa_store.offset;
+         else if (cfa_temp.reg == (unsigned) REGNO (XEXP (dest, 0)))
+           offset = -cfa_temp.offset;
+         else
            abort ();
-         offset = -cfa_store.offset;
+         break;
+
+         /* Rule 14 */
+       case POST_INC:
+         if (cfa_temp.reg != (unsigned) REGNO (XEXP (XEXP (dest, 0), 0)))
+           abort ();
+         offset = -cfa_temp.offset;
+         cfa_temp.offset -= GET_MODE_SIZE (GET_MODE (dest));
          break;
 
        default:
@@ -1450,7 +1537,7 @@ dwarf2out_frame_debug_expr (expr, label)
                 on the ARM.  */
 
              def_cfa_1 (label, &cfa);
-             dwarf2out_reg_save (label, STACK_POINTER_REGNUM, offset);
+             queue_reg_save (label, stack_pointer_rtx, offset);
              break;
            }
          else
@@ -1472,7 +1559,7 @@ dwarf2out_frame_debug_expr (expr, label)
        }
 
       def_cfa_1 (label, &cfa);
-      dwarf2out_reg_save (label, REGNO (src), offset);
+      queue_reg_save (label, src, offset);
       break;
 
     default:
@@ -1493,20 +1580,27 @@ dwarf2out_frame_debug (insn)
 
   if (insn == NULL_RTX)
     {
+      /* Flush any queued register saves.  */
+      flush_queued_reg_saves ();
+
       /* Set up state for generating call frame debug info.  */
       lookup_cfa (&cfa);
       if (cfa.reg != (unsigned long) DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM))
        abort ();
       cfa.reg = STACK_POINTER_REGNUM;
       cfa_store = cfa;
-      cfa_temp_reg = -1;
-      cfa_temp_value = 0;
+      cfa_temp.reg = -1;
+      cfa_temp.offset = 0;
       return;
     }
 
+  if (GET_CODE (insn) != INSN || clobbers_queued_reg_save (insn))
+    flush_queued_reg_saves ();
+
   if (! RTX_FRAME_RELATED_P (insn))
     {
-      dwarf2out_stack_adjust (insn);
+      if (!ACCUMULATE_OUTGOING_ARGS)
+        dwarf2out_stack_adjust (insn);
       return;
     }
 
@@ -1521,222 +1615,95 @@ dwarf2out_frame_debug (insn)
   dwarf2out_frame_debug_expr (insn, label);
 }
 
-/* Return the size of an unsigned LEB128 quantity.  */
-
-static inline unsigned long
-size_of_uleb128 (value)
-     register unsigned long value;
-{
-  register unsigned long size = 0;
-  register unsigned byte;
-
-  do
-    {
-      byte = (value & 0x7f);
-      value >>= 7;
-      size += 1;
-    }
-  while (value != 0);
-
-  return size;
-}
-
-/* Return the size of a signed LEB128 quantity.  */
-
-static inline unsigned long
-size_of_sleb128 (value)
-     register long value;
-{
-  register unsigned long size = 0;
-  register unsigned byte;
-
-  do
-    {
-      byte = (value & 0x7f);
-      value >>= 7;
-      size += 1;
-    }
-  while (!(((value == 0) && ((byte & 0x40) == 0))
-          || ((value == -1) && ((byte & 0x40) != 0))));
-
-  return size;
-}
-
-/* Output an unsigned LEB128 quantity.  */
-
-static void
-output_uleb128 (value)
-     register unsigned long value;
-{
-  unsigned long save_value = value;
-
-  fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP);
-  do
-    {
-      register unsigned byte = (value & 0x7f);
-      value >>= 7;
-      if (value != 0)
-       /* More bytes to follow.  */
-       byte |= 0x80;
-
-      fprintf (asm_out_file, "0x%x", byte);
-      if (value != 0)
-       fprintf (asm_out_file, ",");
-    }
-  while (value != 0);
-
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s ULEB128 0x%lx", ASM_COMMENT_START, save_value);
-}
-
-/* Output an signed LEB128 quantity.  */
-
-static void
-output_sleb128 (value)
-     register long value;
-{
-  register int more;
-  register unsigned byte;
-  long save_value = value;
-
-  fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP);
-  do
-    {
-      byte = (value & 0x7f);
-      /* arithmetic shift */
-      value >>= 7;
-      more = !((((value == 0) && ((byte & 0x40) == 0))
-               || ((value == -1) && ((byte & 0x40) != 0))));
-      if (more)
-       byte |= 0x80;
-
-      fprintf (asm_out_file, "0x%x", byte);
-      if (more)
-       fprintf (asm_out_file, ",");
-    }
-
-  while (more);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s SLEB128 %ld", ASM_COMMENT_START, save_value);
-}
-
 /* Output a Call Frame Information opcode and its operand(s).  */
 
 static void
-output_cfi (cfi, fde)
+output_cfi (cfi, fde, for_eh)
      register dw_cfi_ref cfi;
      register dw_fde_ref fde;
+     int for_eh;
 {
   if (cfi->dw_cfi_opc == DW_CFA_advance_loc)
     {
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
-                             cfi->dw_cfi_opc
-                             | (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f));
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s DW_CFA_advance_loc 0x%lx",
-                ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data (1, (cfi->dw_cfi_opc
+                              | (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f)),
+                          "DW_CFA_advance_loc 0x%lx",
+                          cfi->dw_cfi_oprnd1.dw_cfi_offset);
     }
-
   else if (cfi->dw_cfi_opc == DW_CFA_offset)
     {
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
-                             cfi->dw_cfi_opc
-                             | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f));
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s DW_CFA_offset, column 0x%lx",
-                ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
-
-      fputc ('\n', asm_out_file);
-      output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data (1, (cfi->dw_cfi_opc
+                              | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f)),
+                          "DW_CFA_offset, column 0x%lx",
+                          cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+      dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset, NULL);
     }
   else if (cfi->dw_cfi_opc == DW_CFA_restore)
     {
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
-                             cfi->dw_cfi_opc
-                             | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f));
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s DW_CFA_restore, column 0x%lx",
-                ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
-
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data (1, (cfi->dw_cfi_opc
+                              | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f)),
+                          "DW_CFA_restore, column 0x%lx",
+                          cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
     }
   else
     {
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, cfi->dw_cfi_opc);
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START,
-                dwarf_cfi_name (cfi->dw_cfi_opc));
+      dw2_asm_output_data (1, cfi->dw_cfi_opc,
+                          "%s", dwarf_cfi_name (cfi->dw_cfi_opc));
 
-      fputc ('\n', asm_out_file);
       switch (cfi->dw_cfi_opc)
        {
        case DW_CFA_set_loc:
-         ASM_OUTPUT_DWARF_ADDR (asm_out_file, cfi->dw_cfi_oprnd1.dw_cfi_addr);
-         fputc ('\n', asm_out_file);
+         if (for_eh)
+           dw2_asm_output_encoded_addr_rtx (
+               ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0),
+               gen_rtx_SYMBOL_REF (Pmode, cfi->dw_cfi_oprnd1.dw_cfi_addr),
+               NULL);
+         else
+           dw2_asm_output_addr (DWARF2_ADDR_SIZE,
+                                cfi->dw_cfi_oprnd1.dw_cfi_addr, NULL);
          break;
        case DW_CFA_advance_loc1:
-         ASM_OUTPUT_DWARF_DELTA1 (asm_out_file,
-                                  cfi->dw_cfi_oprnd1.dw_cfi_addr,
-                                  fde->dw_fde_current_label);
-         fputc ('\n', asm_out_file);
+         dw2_asm_output_delta (1, cfi->dw_cfi_oprnd1.dw_cfi_addr,
+                               fde->dw_fde_current_label, NULL);
          fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
          break;
        case DW_CFA_advance_loc2:
-         ASM_OUTPUT_DWARF_DELTA2 (asm_out_file,
-                                  cfi->dw_cfi_oprnd1.dw_cfi_addr,
-                                  fde->dw_fde_current_label);
-          fputc ('\n', asm_out_file);
+         dw2_asm_output_delta (2, cfi->dw_cfi_oprnd1.dw_cfi_addr,
+                               fde->dw_fde_current_label, NULL);
          fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
          break;
        case DW_CFA_advance_loc4:
-         ASM_OUTPUT_DWARF_DELTA4 (asm_out_file,
-                                  cfi->dw_cfi_oprnd1.dw_cfi_addr,
-                                  fde->dw_fde_current_label);
-         fputc ('\n', asm_out_file);
+         dw2_asm_output_delta (4, cfi->dw_cfi_oprnd1.dw_cfi_addr,
+                               fde->dw_fde_current_label, NULL);
          fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
          break;
-#ifdef MIPS_DEBUGGING_INFO
        case DW_CFA_MIPS_advance_loc8:
-         /* TODO: not currently implemented.  */
-         abort ();
+         dw2_asm_output_delta (8, cfi->dw_cfi_oprnd1.dw_cfi_addr,
+                               fde->dw_fde_current_label, NULL);
+         fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
          break;
-#endif
        case DW_CFA_offset_extended:
        case DW_CFA_GNU_negative_offset_extended:
        case DW_CFA_def_cfa:
-         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
-         fputc ('\n', asm_out_file);
-         output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
-         fputc ('\n', asm_out_file);
+         dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, NULL);
+         dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset, NULL);
          break;
        case DW_CFA_restore_extended:
        case DW_CFA_undefined:
-         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
-         fputc ('\n', asm_out_file);
-         break;
        case DW_CFA_same_value:
        case DW_CFA_def_cfa_register:
-         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
-         fputc ('\n', asm_out_file);
+         dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, NULL);
          break;
        case DW_CFA_register:
-         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
-         fputc ('\n', asm_out_file);
-         output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_reg_num);
-         fputc ('\n', asm_out_file);
+         dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, NULL);
+         dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, NULL);
          break;
        case DW_CFA_def_cfa_offset:
-         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
-         fputc ('\n', asm_out_file);
+       case DW_CFA_GNU_args_size:
+         dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset, NULL);
          break;
        case DW_CFA_GNU_window_save:
          break;
-       case DW_CFA_GNU_args_size:
-         output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
-         fputc ('\n', asm_out_file);
-         break;
        case DW_CFA_def_cfa_expression:
          output_cfa_loc (cfi);
          break;
@@ -1754,29 +1721,31 @@ static void
 output_call_frame_info (for_eh)
      int for_eh;
 {
-  register unsigned long i;
+  register unsigned int i;
   register dw_fde_ref fde;
   register dw_cfi_ref cfi;
   char l1[20], l2[20];
-#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
-  char ld[20];
-#endif
-
-  /* Do we want to include a pointer to the exception table?  */
-  int eh_ptr = for_eh && exception_table_p ();
+  int any_lsda_needed = 0;
+  char augmentation[6];
+  int augmentation_size;
+  int fde_encoding = DW_EH_PE_absptr;
+  int per_encoding = DW_EH_PE_absptr;
+  int lsda_encoding = DW_EH_PE_absptr;
 
   /* If we don't have any functions we'll want to unwind out of, don't
      emit any EH unwind information.  */
   if (for_eh)
     {
+      int any_eh_needed = 0;
       for (i = 0; i < fde_table_in_use; ++i)
-       if (! fde_table[i].nothrow)
-         goto found;
-      return;
-    found:;
-    }
+       if (fde_table[i].uses_eh_lsda)
+         any_eh_needed = any_lsda_needed = 1;
+       else if (! fde_table[i].nothrow)
+         any_eh_needed = 1;
 
-  fputc ('\n', asm_out_file);
+      if (! any_eh_needed)
+       return;
+    }
 
   /* We're going to be generating comments, so turn on app.  */
   if (flag_debug_asm)
@@ -1790,145 +1759,143 @@ output_call_frame_info (for_eh)
       tree label = get_file_function_name ('F');
 
       force_data_section ();
-      ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DWARF2_ADDR_SIZE));
+      ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
       ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
       ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
 #endif
       assemble_label ("__FRAME_BEGIN__");
     }
   else
-    ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION);
+    ASM_OUTPUT_SECTION (asm_out_file, DEBUG_FRAME_SECTION);
 
   /* Output the CIE.  */
   ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh);
   ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh);
-#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
-  ASM_GENERATE_INTERNAL_LABEL (ld, CIE_LENGTH_LABEL, for_eh);
-  if (for_eh)
-    ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
-  else
-    ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld);
-#else
-  if (for_eh)
-    ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1);
-  else
-    ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
-#endif
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Length of Common Information Entry",
-            ASM_COMMENT_START);
-
-  fputc ('\n', asm_out_file);
+  dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
+                       "Length of Common Information Entry");
   ASM_OUTPUT_LABEL (asm_out_file, l1);
 
-  if (for_eh)
-    /* Now that the CIE pointer is PC-relative for EH,
-       use 0 to identify the CIE.  */
-    ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
-  else
-    ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
+  /* Now that the CIE pointer is PC-relative for EH,
+     use 0 to identify the CIE.  */
+  dw2_asm_output_data ((for_eh ? 4 : DWARF_OFFSET_SIZE),
+                      (for_eh ? 0 : DW_CIE_ID),
+                      "CIE Identifier Tag");
 
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s CIE Identifier Tag", ASM_COMMENT_START);
+  dw2_asm_output_data (1, DW_CIE_VERSION, "CIE Version");
 
-  fputc ('\n', asm_out_file);
-  if (! for_eh && DWARF_OFFSET_SIZE == 8)
+  augmentation[0] = 0;
+  augmentation_size = 0;
+  if (for_eh)
     {
-      ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
-      fputc ('\n', asm_out_file);
-    }
+      char *p;
 
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_CIE_VERSION);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s CIE Version", ASM_COMMENT_START);
+      /* Augmentation:
+        z      Indicates that a uleb128 is present to size the
+               augmentation section.
+        L      Indicates the encoding (and thus presence) of
+               an LSDA pointer in the FDE augmentation.
+        R      Indicates a non-default pointer encoding for
+               FDE code pointers.
+        P      Indicates the presence of an encoding + language
+               personality routine in the CIE augmentation.  */
 
-  fputc ('\n', asm_out_file);
-  if (eh_ptr)
-    {
-      /* The CIE contains a pointer to the exception region info for the
-         frame.  Make the augmentation string three bytes (including the
-         trailing null) so the pointer is 4-byte aligned.  The Solaris ld
-         can't handle unaligned relocs.  */
-      if (flag_debug_asm)
+      fde_encoding = 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);
+
+      p = augmentation + 1;
+      if (eh_personality_libfunc)
        {
-         ASM_OUTPUT_DWARF_STRING (asm_out_file, "eh");
-         fprintf (asm_out_file, "\t%s CIE Augmentation", ASM_COMMENT_START);
+         *p++ = 'P';
+         augmentation_size += 1 + size_of_encoded_value (per_encoding);
        }
-      else
+      if (any_lsda_needed)
        {
-         ASM_OUTPUT_ASCII (asm_out_file, "eh", 3);
+         *p++ = 'L';
+         augmentation_size += 1;
+       }
+      if (fde_encoding != DW_EH_PE_absptr)
+       {
+         *p++ = 'R';
+         augmentation_size += 1;
+       }
+      if (p > augmentation + 1)
+       {
+         augmentation[0] = 'z';
+          *p = '\0';
+       }
+
+      /* Ug.  Some platforms can't do unaligned dynamic relocations at all.  */
+      if (eh_personality_libfunc && per_encoding == DW_EH_PE_aligned)
+       {
+         int offset = (  4             /* Length */
+                       + 4             /* CIE Id */
+                       + 1             /* CIE version */
+                       + strlen (augmentation) + 1     /* Augmentation */
+                       + size_of_uleb128 (1)           /* Code alignment */
+                       + size_of_sleb128 (DWARF_CIE_DATA_ALIGNMENT)
+                       + 1             /* RA column */
+                       + 1             /* Augmentation size */
+                       + 1             /* Personality encoding */ );
+         int pad = -offset & (PTR_SIZE - 1);
+
+         augmentation_size += pad;
+
+         /* Augmentations should be small, so there's scarce need to
+            iterate for a solution.  Die if we exceed one uleb128 byte.  */
+         if (size_of_uleb128 (augmentation_size) != 1)
+           abort ();
        }
-      fputc ('\n', asm_out_file);
-
-      ASM_OUTPUT_DWARF_ADDR (asm_out_file, "__EXCEPTION_TABLE__");
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s pointer to exception region info",
-                ASM_COMMENT_START);
-    }
-  else
-    {
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s CIE Augmentation (none)",
-                ASM_COMMENT_START);
     }
+  dw2_asm_output_nstring (augmentation, -1, "CIE Augmentation");
 
-  fputc ('\n', asm_out_file);
-  output_uleb128 (1);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, " (CIE Code Alignment Factor)");
+  dw2_asm_output_data_uleb128 (1, "CIE Code Alignment Factor");
 
-  fputc ('\n', asm_out_file);
-  output_sleb128 (DWARF_CIE_DATA_ALIGNMENT);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, " (CIE Data Alignment Factor)");
+  dw2_asm_output_data_sleb128 (DWARF_CIE_DATA_ALIGNMENT,
+                              "CIE Data Alignment Factor");
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_FRAME_RETURN_COLUMN);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START);
+  dw2_asm_output_data (1, DWARF_FRAME_RETURN_COLUMN, "CIE RA Column");
 
-  fputc ('\n', asm_out_file);
+  if (augmentation[0])
+    {
+      dw2_asm_output_data_uleb128 (augmentation_size, "Augmentation size");
+      if (eh_personality_libfunc)
+       {
+         dw2_asm_output_data (1, per_encoding, "Personality (%s)",
+                              eh_data_format_name (per_encoding));
+         dw2_asm_output_encoded_addr_rtx (per_encoding,
+                                          eh_personality_libfunc, NULL);
+       }
+      if (any_lsda_needed)
+       dw2_asm_output_data (1, lsda_encoding, "LSDA Encoding (%s)",
+                            eh_data_format_name (lsda_encoding));
+      if (fde_encoding != DW_EH_PE_absptr)
+       dw2_asm_output_data (1, fde_encoding, "FDE Encoding (%s)",
+                            eh_data_format_name (fde_encoding));
+    }
 
   for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
-    output_cfi (cfi, NULL);
+    output_cfi (cfi, NULL, for_eh);
 
   /* Pad the CIE out to an address sized boundary.  */
-  ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DWARF2_ADDR_SIZE));
+  ASM_OUTPUT_ALIGN (asm_out_file, 
+                   floor_log2 (for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE));
   ASM_OUTPUT_LABEL (asm_out_file, l2);
-#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
-  ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s CIE Length Symbol", ASM_COMMENT_START);
-  fputc ('\n', asm_out_file);
-#endif
 
   /* Loop through all of the FDE's.  */
   for (i = 0; i < fde_table_in_use; ++i)
     {
       fde = &fde_table[i];
 
-      /* Don't emit EH unwind info for leaf functions.  */
-      if (for_eh && fde->nothrow)
+      /* Don't emit EH unwind info for leaf functions that don't need it.  */
+      if (for_eh && fde->nothrow && ! fde->uses_eh_lsda)
        continue;
 
+      ASM_OUTPUT_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);
-#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
-      ASM_GENERATE_INTERNAL_LABEL (ld, FDE_LENGTH_LABEL, for_eh + i * 2);
-      if (for_eh)
-       ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
-      else
-       ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld);
-#else
-      if (for_eh)
-       ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1);
-      else
-       ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
-#endif
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s FDE Length", ASM_COMMENT_START);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_delta (for_eh ? 4 : DWARF_OFFSET_SIZE, l2, l1,
+                           "FDE Length");
       ASM_OUTPUT_LABEL (asm_out_file, l1);
 
       /* ??? This always emits a 4 byte offset when for_eh is true, but it
@@ -1940,48 +1907,86 @@ output_call_frame_info (for_eh)
         If the for_eh case is changed, then the struct in frame.c has
         to be adjusted appropriately.  */
       if (for_eh)
-       ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l1, "__FRAME_BEGIN__");
+       dw2_asm_output_delta (4, l1, "__FRAME_BEGIN__", "FDE CIE offset");
       else
-       ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (FRAME_SECTION));
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s FDE CIE offset", ASM_COMMENT_START);
+       dw2_asm_output_offset (DWARF_OFFSET_SIZE,
+                              stripattributes (DEBUG_FRAME_SECTION),
+                              "FDE CIE offset");
 
-      fputc ('\n', asm_out_file);
-      ASM_OUTPUT_DWARF_ADDR (asm_out_file, fde->dw_fde_begin);
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s FDE initial location", ASM_COMMENT_START);
+      if (for_eh)
+       {
+         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");
+       }
+      else
+       {
+         dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_begin,
+                              "FDE initial location");
+         dw2_asm_output_delta (DWARF2_ADDR_SIZE, 
+                               fde->dw_fde_end, fde->dw_fde_begin, 
+                               "FDE address range");
+       }
 
-      fputc ('\n', asm_out_file);
-      ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file,
-                                  fde->dw_fde_end, fde->dw_fde_begin);
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s FDE address range", ASM_COMMENT_START);
+      if (augmentation[0])
+       {
+         if (any_lsda_needed)
+           {
+             int size = size_of_encoded_value (lsda_encoding);
 
-      fputc ('\n', asm_out_file);
+             if (lsda_encoding == DW_EH_PE_aligned)
+               {
+                 int offset = (  4             /* Length */
+                               + 4             /* CIE offset */
+                               + 2 * size_of_encoded_value (fde_encoding)
+                               + 1             /* Augmentation size */ );
+                 int pad = -offset & (PTR_SIZE - 1);
+
+                 size += pad;
+                 if (size_of_uleb128 (size) != 1)
+                   abort ();
+               }
+
+             dw2_asm_output_data_uleb128 (size, "Augmentation size");
+
+             if (fde->uses_eh_lsda)
+               {
+                 ASM_GENERATE_INTERNAL_LABEL (l1, "LLSDA",
+                                              fde->funcdef_number);
+                 dw2_asm_output_encoded_addr_rtx (
+                       lsda_encoding, gen_rtx_SYMBOL_REF (Pmode, l1),
+                       "Language Specific Data Area");
+               }
+             else
+               {
+                 if (lsda_encoding == DW_EH_PE_aligned)
+                   ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+                 dw2_asm_output_data (size_of_encoded_value (lsda_encoding),
+                                      0, "Language Specific Data Area (none)");
+               }
+           }
+         else
+           dw2_asm_output_data_uleb128 (0, "Augmentation size");
+       }
 
       /* Loop through the Call Frame Instructions associated with
         this FDE.  */
       fde->dw_fde_current_label = fde->dw_fde_begin;
       for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
-       output_cfi (cfi, fde);
+       output_cfi (cfi, fde, for_eh);
 
       /* Pad the FDE out to an address sized boundary.  */
-      ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DWARF2_ADDR_SIZE));
+      ASM_OUTPUT_ALIGN (asm_out_file, 
+                       floor_log2 ((for_eh ? PTR_SIZE : DWARF2_ADDR_SIZE)));
       ASM_OUTPUT_LABEL (asm_out_file, l2);
-#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
-      ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s FDE Length Symbol", ASM_COMMENT_START);
-      fputc ('\n', asm_out_file);
-#endif
     }
+
 #ifndef EH_FRAME_SECTION
   if (for_eh)
-    {
-      /* Emit terminating zero for table.  */
-      ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
-      fputc ('\n', asm_out_file);
-    }
+    dw2_asm_output_data (4, 0, "End of Table");
 #endif
 #ifdef MIPS_DEBUGGING_INFO
   /* Work around Irix 6 assembler bug whereby labels at the end of a section
@@ -1998,19 +2003,42 @@ output_call_frame_info (for_eh)
    the prologue.  */
 
 void
-dwarf2out_begin_prologue ()
+dwarf2out_begin_prologue (line, file)
+     unsigned int line ATTRIBUTE_UNUSED;
+     const char *file ATTRIBUTE_UNUSED;
 {
   char label[MAX_ARTIFICIAL_LABEL_BYTES];
   register dw_fde_ref fde;
 
+  current_function_func_begin_label = 0;
+
+#ifdef IA64_UNWIND_INFO
+  /* ??? current_function_func_begin_label is also used by except.c
+     for call-site information.  We must emit this label if it might
+     be used.  */
+  if ((! flag_exceptions || USING_SJLJ_EXCEPTIONS)
+      && ! dwarf2out_do_frame ())
+    return;
+#else
+  if (! dwarf2out_do_frame ())
+    return;
+#endif
+
   ++current_funcdef_number;
 
   function_section (current_function_decl);
   ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
                               current_funcdef_number);
-  ASM_OUTPUT_LABEL (asm_out_file, label);
+  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, FUNC_BEGIN_LABEL,
+                         current_funcdef_number);
   current_function_func_begin_label = get_identifier (label);
 
+#ifdef IA64_UNWIND_INFO
+  /* We can elide the fde allocation if we're not emitting debug info.  */
+  if (! dwarf2out_do_frame ())
+    return;
+#endif
+
   /* Expand the fde table if necessary.  */
   if (fde_table_in_use == fde_table_allocated)
     {
@@ -2029,9 +2057,18 @@ dwarf2out_begin_prologue ()
   fde->dw_fde_current_label = NULL;
   fde->dw_fde_end = NULL;
   fde->dw_fde_cfi = NULL;
+  fde->funcdef_number = current_funcdef_number;
   fde->nothrow = current_function_nothrow;
+  fde->uses_eh_lsda = cfun->uses_eh_lsda;
 
   args_size = old_args_size = 0;
+
+  /* We only want to output line number information for the genuine
+     dwarf2 prologue case, not the eh frame case.  */
+#ifdef DWARF2_DEBUGGING_INFO
+  if (file)
+    dwarf2out_source_line (line, file);
+#endif
 }
 
 /* Output a marker (i.e. a label) for the absolute end of the generated code
@@ -2077,11 +2114,11 @@ dwarf2out_frame_finish ()
 #ifdef MIPS_DEBUGGING_INFO
   if (write_symbols == DWARF2_DEBUG)
     output_call_frame_info (0);
-  if (flag_unwind_tables || (flag_exceptions && ! exceptions_via_longjmp))
+  if (flag_unwind_tables || (flag_exceptions && ! USING_SJLJ_EXCEPTIONS))
     output_call_frame_info (1);
 #else
   if (write_symbols == DWARF2_DEBUG
-      || flag_unwind_tables || (flag_exceptions && ! exceptions_via_longjmp))
+      || flag_unwind_tables || (flag_exceptions && ! USING_SJLJ_EXCEPTIONS))
     output_call_frame_info (1);
 #endif
 }
@@ -2092,6 +2129,7 @@ dwarf2out_frame_finish ()
 typedef struct dw_val_struct *dw_val_ref;
 typedef struct die_struct *dw_die_ref;
 typedef struct dw_loc_descr_struct *dw_loc_descr_ref;
+typedef struct dw_loc_list_struct *dw_loc_list_ref;
 
 /* Each DIE may have a series of attribute/value pairs.  Values
    can take on several forms.  The forms that are used in this
@@ -2101,6 +2139,7 @@ typedef enum
 {
   dw_val_class_addr,
   dw_val_class_loc,
+  dw_val_class_loc_list,
   dw_val_class_const,
   dw_val_class_unsigned_const,
   dw_val_class_long_long,
@@ -2142,6 +2181,7 @@ typedef struct dw_val_struct
   union
     {
       rtx val_addr;
+      dw_loc_list_ref  val_loc_list;
       dw_loc_descr_ref val_loc;
       long int val_int;
       long unsigned val_unsigned;
@@ -2169,9 +2209,23 @@ 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;
 
+/* Location lists are ranges + location descriptions for that range,
+   so you can track variables that are in different places over
+   their entire life. */
+typedef struct dw_loc_list_struct
+{
+  dw_loc_list_ref dw_loc_next;
+  const char *begin; /* Label for begin address of range */
+  const char *end;  /* Label for end address of range */
+  char *ll_symbol; /* Label for beginning of location list. Only on head of list */
+  const char *section; /* Section this loclist is relative to */
+  dw_loc_descr_ref expr;
+} dw_loc_list_node;
+
 static const char *dwarf_stack_op_name PARAMS ((unsigned));
 static dw_loc_descr_ref new_loc_descr  PARAMS ((enum dwarf_location_atom,
                                                 unsigned long,
@@ -2510,6 +2564,7 @@ new_loc_descr (op, oprnd1, oprnd2)
   return descr;
 }
 
+
 /* Add a location description term to a location description expression.  */
 
 static inline void
@@ -2638,7 +2693,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;
 }
@@ -2656,28 +2714,34 @@ output_loc_operands (loc)
     {
 #ifdef DWARF2_DEBUGGING_INFO
     case DW_OP_addr:
-      ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, val1->v.val_addr);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val1->v.val_addr, NULL);
       break;
     case DW_OP_const2u:
     case DW_OP_const2s:
-      ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data (2, val1->v.val_int, NULL);
       break;
     case DW_OP_const4u:
     case DW_OP_const4s:
-      ASM_OUTPUT_DWARF_DATA4 (asm_out_file, val1->v.val_int);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data (4, val1->v.val_int, NULL);
       break;
     case DW_OP_const8u:
     case DW_OP_const8s:
-      abort ();
-      fputc ('\n', asm_out_file);
+      if (HOST_BITS_PER_LONG < 64)
+       abort ();
+      dw2_asm_output_data (8, val1->v.val_int, NULL);
       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 ();
+
+       dw2_asm_output_data (2, offset, NULL);
+      }
       break;
 #else
     case DW_OP_addr:
@@ -2697,24 +2761,19 @@ output_loc_operands (loc)
 #endif
     case DW_OP_const1u:
     case DW_OP_const1s:
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data (1, val1->v.val_int, NULL);
       break;
     case DW_OP_constu:
-      output_uleb128 (val1->v.val_unsigned);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
       break;
     case DW_OP_consts:
-      output_sleb128 (val1->v.val_int);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data_sleb128 (val1->v.val_int, NULL);
       break;
     case DW_OP_pick:
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_int);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data (1, val1->v.val_int, NULL);
       break;
     case DW_OP_plus_uconst:
-      output_uleb128 (val1->v.val_unsigned);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
       break;
     case DW_OP_breg0:
     case DW_OP_breg1:
@@ -2748,31 +2807,24 @@ output_loc_operands (loc)
     case DW_OP_breg29:
     case DW_OP_breg30:
     case DW_OP_breg31:
-      output_sleb128 (val1->v.val_int);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data_sleb128 (val1->v.val_int, NULL);
       break;
     case DW_OP_regx:
-      output_uleb128 (val1->v.val_unsigned);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
       break;
     case DW_OP_fbreg:
-      output_sleb128 (val1->v.val_int);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data_sleb128 (val1->v.val_int, NULL);
       break;
     case DW_OP_bregx:
-      output_uleb128 (val1->v.val_unsigned);
-      fputc ('\n', asm_out_file);
-      output_sleb128 (val2->v.val_int);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+      dw2_asm_output_data_sleb128 (val2->v.val_int, NULL);
       break;
     case DW_OP_piece:
-      output_uleb128 (val1->v.val_unsigned);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
       break;
     case DW_OP_deref_size:
     case DW_OP_xderef_size:
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data (1, val1->v.val_int, NULL);
       break;
     default:
       /* Other codes have no operands.  */
@@ -2789,12 +2841,8 @@ output_loc_sequence (loc)
   for (; loc != NULL; loc = loc->dw_loc_next)
     {
       /* Output the opcode.  */
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, loc->dw_loc_opc);
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START,
-                dwarf_stack_op_name (loc->dw_loc_opc));
-
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data (1, loc->dw_loc_opc,
+                          "%s", dwarf_stack_op_name (loc->dw_loc_opc));
 
       /* Output the operand(s) (if any).  */
       output_loc_operands (loc);
@@ -2814,8 +2862,7 @@ output_cfa_loc (cfi)
   /* Output the size of the block.  */
   loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
   size = size_of_locs (loc);
-  output_uleb128 (size);
-  fputc ('\n', asm_out_file);
+  dw2_asm_output_data_uleb128 (size, NULL);
 
   /* Now output the operations themselves.  */
   output_loc_sequence (loc);
@@ -2834,9 +2881,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);
@@ -2950,8 +3004,8 @@ get_cfa_from_loc_descr (cfa, loc)
          cfa->offset = ptr->dw_loc_oprnd1.v.val_unsigned;
          break;
        default:
-         fatal ("DW_LOC_OP %s not implememnted yet.\n",
-                dwarf_stack_op_name (ptr->dw_loc_opc));
+         internal_error ("DW_LOC_OP %s not implememnted\n",
+                         dwarf_stack_op_name (ptr->dw_loc_opc));
        }
     }
 }
@@ -2960,6 +3014,47 @@ get_cfa_from_loc_descr (cfa, loc)
 /* And now, the support for symbolic debugging information.  */
 #ifdef DWARF2_DEBUGGING_INFO
 
+static void dwarf2out_init             PARAMS ((const char *));
+static void dwarf2out_finish           PARAMS ((const char *));
+static void dwarf2out_define           PARAMS ((unsigned int, const char *));
+static void dwarf2out_undef            PARAMS ((unsigned int, const char *));
+static void dwarf2out_start_source_file        PARAMS ((unsigned, const char *));
+static void dwarf2out_end_source_file  PARAMS ((unsigned));
+static void dwarf2out_begin_block      PARAMS ((unsigned, unsigned));
+static void dwarf2out_end_block                PARAMS ((unsigned, unsigned));
+static bool dwarf2out_ignore_block     PARAMS ((tree));
+static void dwarf2out_global_decl      PARAMS ((tree));
+static void dwarf2out_abstract_function PARAMS ((tree));
+
+/* The debug hooks structure.  */
+
+struct gcc_debug_hooks dwarf2_debug_hooks =
+{
+  dwarf2out_init,
+  dwarf2out_finish,
+  dwarf2out_define,
+  dwarf2out_undef,
+  dwarf2out_start_source_file,
+  dwarf2out_end_source_file,
+  dwarf2out_begin_block,
+  dwarf2out_end_block,
+  dwarf2out_ignore_block,
+  dwarf2out_source_line,
+  dwarf2out_begin_prologue,
+  debug_nothing_int,           /* end_prologue */
+  dwarf2out_end_epilogue,
+  debug_nothing_tree,          /* begin_function */
+  debug_nothing_int,           /* end_function */
+  dwarf2out_decl,              /* function_decl */
+  dwarf2out_global_decl,
+  debug_nothing_tree,          /* deferred_inline_function */
+  /* The DWARF 2 backend tries to reduce debugging bloat by not
+     emitting the abstract description of inline functions until
+     something tries to reference them.  */
+  dwarf2out_abstract_function, /* outlining_inline_function */
+  debug_nothing_rtx            /* label */
+};
+\f
 /* NOTE: In the comments in this file, many references are made to
    "Debugging Information Entries".  This term is abbreviated as `DIE'
    throughout the remainder of this file.  */
@@ -3028,6 +3123,7 @@ typedef struct die_struct
   dw_die_ref die_sib;
   dw_offset die_offset;
   unsigned long die_abbrev;
+  int die_mark;
 }
 die_node;
 
@@ -3099,10 +3195,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
@@ -3141,21 +3241,22 @@ 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 this compilation unit.  */
+static struct file_table file_table;
+
 /* Local pointer to the name of the main input file.  Initialized in
    dwarf2out_init.  */
 static const char *primary_filename;
@@ -3259,6 +3360,9 @@ static unsigned arange_table_in_use;
    arange_table.  */
 #define ARANGE_TABLE_INCREMENT 64
 
+/* Whether we have location lists that need outputting */
+static unsigned have_location_lists;
+
 /* A pointer to the base of a list of incomplete types which might be
    completed at some later time.  */
 
@@ -3329,6 +3433,9 @@ static void add_AT_fde_ref                PARAMS ((dw_die_ref,
 static void add_AT_loc                 PARAMS ((dw_die_ref,
                                                 enum dwarf_attribute,
                                                 dw_loc_descr_ref));
+static void add_AT_loc_list            PARAMS ((dw_die_ref,
+                                                enum dwarf_attribute,
+                                                dw_loc_list_ref));
 static void add_AT_addr                        PARAMS ((dw_die_ref,
                                                 enum dwarf_attribute,
                                                 rtx));
@@ -3376,24 +3483,23 @@ static void compute_section_prefix      PARAMS ((dw_die_ref));
 static int is_type_die                 PARAMS ((dw_die_ref));
 static int is_comdat_die               PARAMS ((dw_die_ref));
 static int is_symbol_die               PARAMS ((dw_die_ref));
-static char *gen_internal_sym          PARAMS ((void));
 static void assign_symbol_names                PARAMS ((dw_die_ref));
 static void break_out_includes         PARAMS ((dw_die_ref));
 static void add_sibling_attributes     PARAMS ((dw_die_ref));
 static void build_abbrev_table         PARAMS ((dw_die_ref));
+static void output_location_lists      PARAMS ((dw_die_ref));
 static unsigned long size_of_string    PARAMS ((const char *));
 static int constant_size               PARAMS ((long unsigned));
 static unsigned long size_of_die       PARAMS ((dw_die_ref));
 static void calc_die_sizes             PARAMS ((dw_die_ref));
-static void clear_die_sizes            PARAMS ((dw_die_ref));
-static unsigned long size_of_line_prolog PARAMS ((void));
+static void mark_dies                  PARAMS ((dw_die_ref));
+static void unmark_dies                        PARAMS ((dw_die_ref));
 static unsigned long size_of_pubnames  PARAMS ((void));
 static unsigned long size_of_aranges   PARAMS ((void));
 static enum dwarf_form value_format    PARAMS ((dw_attr_ref));
 static void output_value_format                PARAMS ((dw_attr_ref));
 static void output_abbrev_section      PARAMS ((void));
 static void output_die_symbol          PARAMS ((dw_die_ref));
-static void output_symbolic_ref                PARAMS ((dw_die_ref));
 static void output_die                 PARAMS ((dw_die_ref));
 static void output_compilation_unit_header PARAMS ((void));
 static void output_comp_unit           PARAMS ((dw_die_ref));
@@ -3403,6 +3509,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));
@@ -3410,21 +3517,26 @@ 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));
+static unsigned int simple_decl_align_in_bits PARAMS ((tree));
 static unsigned HOST_WIDE_INT simple_type_size_in_bits PARAMS ((tree));
 static HOST_WIDE_INT field_byte_offset PARAMS ((tree));
 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 *));
 static void add_bound_info             PARAMS ((dw_die_ref,
                                                 enum dwarf_attribute, tree));
@@ -3480,37 +3592,46 @@ 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 void init_file_table            PARAMS ((void));
 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));
-static void gen_abstract_function      PARAMS ((tree));
 static rtx save_rtx                    PARAMS ((rtx));
 static void splice_child_die           PARAMS ((dw_die_ref, dw_die_ref));
+static int file_info_cmp               PARAMS ((const void *, const void *));
+static dw_loc_list_ref new_loc_list     PARAMS ((dw_loc_descr_ref, 
+                                                const char *, const char *,
+                                                const char *, unsigned));
+static void add_loc_descr_to_loc_list   PARAMS ((dw_loc_list_ref *,
+                                                dw_loc_descr_ref,
+                                                const char *, const char *, const char *));
+static void output_loc_list            PARAMS ((dw_loc_list_ref));
+static char *gen_internal_sym          PARAMS ((const char *));
 
 /* Section names used to hold DWARF debugging information.  */
 #ifndef DEBUG_INFO_SECTION
 #define DEBUG_INFO_SECTION     ".debug_info"
 #endif
-#ifndef ABBREV_SECTION
-#define ABBREV_SECTION         ".debug_abbrev"
+#ifndef DEBUG_ABBREV_SECTION
+#define DEBUG_ABBREV_SECTION   ".debug_abbrev"
 #endif
-#ifndef ARANGES_SECTION
-#define ARANGES_SECTION                ".debug_aranges"
+#ifndef DEBUG_ARANGES_SECTION
+#define DEBUG_ARANGES_SECTION  ".debug_aranges"
 #endif
-#ifndef DW_MACINFO_SECTION
-#define DW_MACINFO_SECTION     ".debug_macinfo"
+#ifndef DEBUG_MACINFO_SECTION
+#define DEBUG_MACINFO_SECTION  ".debug_macinfo"
 #endif
 #ifndef DEBUG_LINE_SECTION
 #define DEBUG_LINE_SECTION     ".debug_line"
 #endif
-#ifndef LOC_SECTION
-#define LOC_SECTION            ".debug_loc"
+#ifndef DEBUG_LOC_SECTION
+#define DEBUG_LOC_SECTION      ".debug_loc"
 #endif
-#ifndef PUBNAMES_SECTION
-#define PUBNAMES_SECTION       ".debug_pubnames"
+#ifndef DEBUG_PUBNAMES_SECTION
+#define DEBUG_PUBNAMES_SECTION ".debug_pubnames"
 #endif
-#ifndef STR_SECTION
-#define STR_SECTION            ".debug_str"
+#ifndef DEBUG_STR_SECTION
+#define DEBUG_STR_SECTION      ".debug_str"
 #endif
 
 /* Standard ELF section names for compiled code and data.  */
@@ -3528,18 +3649,23 @@ static void splice_child_die            PARAMS ((dw_die_ref, dw_die_ref));
    the section names themselves.  */
 
 #ifndef TEXT_SECTION_LABEL
-#define TEXT_SECTION_LABEL      "Ltext"
+#define TEXT_SECTION_LABEL             "Ltext"
 #endif
 #ifndef DEBUG_LINE_SECTION_LABEL
-#define DEBUG_LINE_SECTION_LABEL "Ldebug_line"
+#define DEBUG_LINE_SECTION_LABEL       "Ldebug_line"
 #endif
 #ifndef DEBUG_INFO_SECTION_LABEL
-#define DEBUG_INFO_SECTION_LABEL "Ldebug_info"
+#define DEBUG_INFO_SECTION_LABEL       "Ldebug_info"
 #endif
-#ifndef ABBREV_SECTION_LABEL
-#define ABBREV_SECTION_LABEL     "Ldebug_abbrev"
+#ifndef DEBUG_ABBREV_SECTION_LABEL
+#define DEBUG_ABBREV_SECTION_LABEL     "Ldebug_abbrev"
+#endif
+#ifndef DEBUG_LOC_SECTION_LABEL
+#define DEBUG_LOC_SECTION_LABEL                "Ldebug_loc"
+#endif
+#ifndef DEBUG_MACINFO_SECTION_LABEL
+#define DEBUG_MACINFO_SECTION_LABEL     "Ldebug_macinfo"
 #endif
-
 /* Definitions of defaults for formats and names of various special
    (artificial) labels which may be generated within this file (when the -g
    options is used and DWARF_DEBUGGING_INFO is in effect.
@@ -3551,7 +3677,8 @@ static char text_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char abbrev_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char debug_info_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 static char debug_line_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
-
+static char macinfo_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
+static char loc_section_label[MAX_ARTIFICIAL_LABEL_BYTES];
 #ifndef TEXT_END_LABEL
 #define TEXT_END_LABEL         "Letext"
 #endif
@@ -3561,9 +3688,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
@@ -3603,15 +3727,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;
 }
@@ -3624,7 +3740,7 @@ is_pseudo_reg (rtl)
 {
   return ((GET_CODE (rtl) == REG && REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
          || (GET_CODE (rtl) == SUBREG
-             && REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER));
+             && REGNO (SUBREG_REG (rtl)) >= FIRST_PSEUDO_REGISTER));
 }
 
 /* Return a reference to a type, with its const and volatile qualifiers
@@ -4396,6 +4512,34 @@ AT_loc (a)
   abort ();
 }
 
+static inline void
+add_AT_loc_list (die, attr_kind, loc_list)
+     register dw_die_ref die;
+     register enum dwarf_attribute attr_kind;
+     register dw_loc_list_ref loc_list;
+{
+  register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+
+  attr->dw_attr_next = NULL;
+  attr->dw_attr = attr_kind;
+  attr->dw_attr_val.val_class = dw_val_class_loc_list;
+  attr->dw_attr_val.v.val_loc_list = loc_list;
+  add_dwarf_attr (die, attr);
+  have_location_lists = 1;
+}
+
+static inline dw_loc_list_ref AT_loc_list PARAMS ((dw_attr_ref));
+
+static inline dw_loc_list_ref
+AT_loc_list (a)
+     register dw_attr_ref a;
+{
+  if (a && AT_class (a) == dw_val_class_loc_list)
+    return a->dw_attr_val.v.val_loc_list;
+
+  abort ();
+}
+
 /* Add an address constant attribute value to a DIE.  */
 
 static inline void
@@ -4610,6 +4754,10 @@ free_AT (a)
       free (a->dw_attr_val.v.val_str);
       break;
 
+    case dw_val_class_float:
+      free (a->dw_attr_val.v.val_float.array);
+      break;
+
     default:
       break;
     }
@@ -4740,16 +4888,9 @@ new_die (tag_value, parent_die)
      register enum dwarf_tag tag_value;
      register dw_die_ref parent_die;
 {
-  register dw_die_ref die = (dw_die_ref) xmalloc (sizeof (die_node));
+  register dw_die_ref die = (dw_die_ref) xcalloc (1, sizeof (die_node));
 
   die->die_tag = tag_value;
-  die->die_abbrev = 0;
-  die->die_offset = 0;
-  die->die_child = NULL;
-  die->die_parent = NULL;
-  die->die_sib = NULL;
-  die->die_attr = NULL;
-  die->die_symbol = NULL;
 
   if (parent_die != NULL)
     add_child_die (parent_die, die);
@@ -4820,7 +4961,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;
     }
@@ -4876,6 +5017,9 @@ print_die (die, outfile)
        case dw_val_class_loc:
          fprintf (outfile, "location descriptor");
          break;
+       case dw_val_class_loc_list:
+         fprintf (outfile, "location list -> label:%s", AT_loc_list (a)->ll_symbol);
+         break;
        case dw_val_class_const:
          fprintf (outfile, "%ld", AT_int (a));
          break;
@@ -4896,7 +5040,7 @@ print_die (die, outfile)
        case dw_val_class_die_ref:
          if (AT_ref (a) != NULL)
            {
-             if (AT_ref (a)->die_offset == 0)
+             if (AT_ref (a)->die_symbol)
                fprintf (outfile, "die -> label: %s", AT_ref (a)->die_symbol);
              else
                fprintf (outfile, "die -> %lu", AT_ref (a)->die_offset);
@@ -4948,7 +5092,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", file_table.table[line_info->dw_file_num]);
       fprintf (outfile, "%6ld", line_info->dw_line_num);
       fprintf (outfile, "\n");
     }
@@ -5182,7 +5326,7 @@ compute_section_prefix (unit_die)
   die_checksum (unit_die, &ctx);
   md5_finish_ctx (&ctx, checksum);
 
-  p = file_name_nondirectory (get_AT_string (unit_die, DW_AT_name));
+  p = lbasename (get_AT_string (unit_die, DW_AT_name));
   name = (char *) alloca (strlen (p) + 64);
   sprintf (name, "%s.", p);
 
@@ -5270,18 +5414,19 @@ is_symbol_die (c)
 {
   if (is_type_die (c))
     return 1;
-  if (get_AT (c, DW_AT_declaration)
+  if (get_AT (c, DW_AT_declaration) 
       && ! get_AT (c, DW_AT_specification))
     return 1;
   return 0;
 }
 
 static char *
-gen_internal_sym ()
+gen_internal_sym (prefix)
+       const char *prefix;
 {
   char buf[256];
   static int label_num;
-  ASM_GENERATE_INTERNAL_LABEL (buf, "LDIE", label_num++);
+  ASM_GENERATE_INTERNAL_LABEL (buf, prefix, label_num++);
   return xstrdup (buf);
 }
 
@@ -5303,7 +5448,7 @@ assign_symbol_names (die)
          die->die_symbol = xstrdup (p);
        }
       else
-       die->die_symbol = gen_internal_sym ();
+       die->die_symbol = gen_internal_sym ("LDIE");
     }
 
   for (c = die->die_child; c != NULL; c = c->die_sib)
@@ -5356,7 +5501,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
@@ -5388,6 +5533,24 @@ add_sibling_attributes (die)
     add_sibling_attributes (c);
 }
 
+/* Output all location lists for the DIE and it's children */
+static void
+output_location_lists (die)
+     register dw_die_ref die;
+{
+  dw_die_ref c;
+  dw_attr_ref d_attr;
+  for (d_attr = die->die_attr; d_attr; d_attr = d_attr->dw_attr_next)
+    {
+      if (AT_class (d_attr) == dw_val_class_loc_list)
+       {
+         output_loc_list (AT_loc_list (d_attr));
+       }
+    }
+  for (c = die->die_child; c != NULL; c = c->die_sib)
+    output_location_lists (c);
+
+}
 /* The format of each DIE (and its attribute value pairs)
    is encoded in an abbreviation table.  This routine builds the
    abbreviation table and assigns a unique abbreviation id for
@@ -5399,16 +5562,16 @@ build_abbrev_table (die)
      register dw_die_ref die;
 {
   register unsigned long abbrev_id;
-  register unsigned long n_alloc;
+  register unsigned int n_alloc;
   register dw_die_ref c;
   register dw_attr_ref d_attr, a_attr;
 
   /* Scan the DIE references, and mark as external any that refer to
-     DIEs from other CUs (i.e. those with cleared die_offset).  */
+     DIEs from other CUs (i.e. those which are not marked).  */
   for (d_attr = die->die_attr; d_attr; d_attr = d_attr->dw_attr_next)
     {
       if (AT_class (d_attr) == dw_val_class_die_ref
-         && AT_ref (d_attr)->die_offset == 0)
+         && AT_ref (d_attr)->die_mark == 0)
        {
          if (AT_ref (d_attr)->die_symbol == 0)
            abort ();
@@ -5452,7 +5615,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;
        }
@@ -5526,6 +5689,9 @@ size_of_die (die)
            size += lsize;
          }
          break;
+       case dw_val_class_loc_list:
+         size += DWARF_OFFSET_SIZE;
+         break;
        case dw_val_class_const:
          size += size_of_sleb128 (AT_int (a));
          break;
@@ -5533,7 +5699,7 @@ size_of_die (die)
          size += constant_size (AT_unsigned (a));
          break;
        case dw_val_class_long_long:
-         size += 1 + 8; /* block */
+         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 */
@@ -5586,57 +5752,31 @@ calc_die_sizes (die)
     next_die_offset += 1;
 }
 
-/* Clear the offsets and sizes for a die and its children.  We do this so
+/* Set the marks for a die and its children.  We do this so
    that we know whether or not a reference needs to use FORM_ref_addr; only
-   DIEs in the same CU will have non-zero offsets available.  */
+   DIEs in the same CU will be marked.  We used to clear out the offset
+   and use that as the flag, but ran into ordering problems.  */
 
 static void
-clear_die_sizes (die)
+mark_dies (die)
      dw_die_ref die;
 {
   register dw_die_ref c;
-  die->die_offset = 0;
+  die->die_mark = 1;
   for (c = die->die_child; c; c = c->die_sib)
-    clear_die_sizes (c);
+    mark_dies (c);
 }
 
-/* Return the size of the line information prolog generated for the
-   compilation unit.  */
+/* Clear the marks for a die and its children.  */
 
-static unsigned long
-size_of_line_prolog ()
+static void
+unmark_dies (die)
+     dw_die_ref die;
 {
-  register unsigned long size;
-  register unsigned long ft_index;
-
-  size = DWARF_LINE_PROLOG_HEADER_SIZE;
-
-  /* Count the size of the table giving number of args for each
-     standard opcode.  */
-  size += DWARF_LINE_OPCODE_BASE - 1;
-
-  /* Include directory table is empty (at present).  Count only the
-     null byte used to terminate the table.  */
-  size += 1;
-
-  for (ft_index = 1; ft_index < file_table_in_use; ++ft_index)
-    {
-      /* File name entry.  */
-      size += size_of_string (file_table[ft_index]);
-
-      /* Include directory index.  */
-      size += size_of_uleb128 (0);
-
-      /* Modification time.  */
-      size += size_of_uleb128 (0);
-
-      /* File length in bytes.  */
-      size += size_of_uleb128 (0);
-    }
-
-  /* Count the file table terminator.  */
-  size += 1;
-  return size;
+  register dw_die_ref c;
+  die->die_mark = 0;
+  for (c = die->die_child; c; c = c->die_sib)
+    unmark_dies (c);
 }
 
 /* Return the size of the .debug_pubnames table  generated for the
@@ -5687,6 +5827,10 @@ value_format (a)
     {
     case dw_val_class_addr:
       return DW_FORM_addr;
+    case dw_val_class_loc_list:
+      /* FIXME: Could be DW_FORM_data8, with a > 32 bit size
+        .debug_loc section */
+      return DW_FORM_data4;
     case dw_val_class_loc:
       switch (constant_size (size_of_locs (AT_loc (a))))
        {
@@ -5744,12 +5888,7 @@ output_value_format (a)
      dw_attr_ref a;
 {
   enum dwarf_form form = value_format (a);
-
-  output_uleb128 (form);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, " (%s)", dwarf_form_name (form));
-
-  fputc ('\n', asm_out_file);
+  dw2_asm_output_data_uleb128 (form, "(%s)", dwarf_form_name (form));
 }
 
 /* Output the .debug_abbrev section which defines the DIE abbreviation
@@ -5765,45 +5904,30 @@ output_abbrev_section ()
     {
       register dw_die_ref abbrev = abbrev_die_table[abbrev_id];
 
-      output_uleb128 (abbrev_id);
-      if (flag_debug_asm)
-       fprintf (asm_out_file, " (abbrev code)");
-
-      fputc ('\n', asm_out_file);
-      output_uleb128 (abbrev->die_tag);
-      if (flag_debug_asm)
-       fprintf (asm_out_file, " (TAG: %s)",
-                dwarf_tag_name (abbrev->die_tag));
-
-      fputc ('\n', asm_out_file);
-      fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP,
-              abbrev->die_child != NULL ? DW_children_yes : DW_children_no);
+      dw2_asm_output_data_uleb128 (abbrev_id, "(abbrev code)");
 
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s %s",
-                ASM_COMMENT_START,
-                (abbrev->die_child != NULL
-                 ? "DW_children_yes" : "DW_children_no"));
+      dw2_asm_output_data_uleb128 (abbrev->die_tag, "(TAG: %s)",
+                                  dwarf_tag_name (abbrev->die_tag));
 
-      fputc ('\n', asm_out_file);
+      if (abbrev->die_child != NULL)
+       dw2_asm_output_data (1, DW_children_yes, "DW_children_yes");
+      else
+       dw2_asm_output_data (1, DW_children_no, "DW_children_no");
 
       for (a_attr = abbrev->die_attr; a_attr != NULL;
           a_attr = a_attr->dw_attr_next)
        {
-         output_uleb128 (a_attr->dw_attr);
-         if (flag_debug_asm)
-           fprintf (asm_out_file, " (%s)",
-                    dwarf_attr_name (a_attr->dw_attr));
-
-         fputc ('\n', asm_out_file);
+         dw2_asm_output_data_uleb128 (a_attr->dw_attr, "(%s)",
+                                      dwarf_attr_name (a_attr->dw_attr));
          output_value_format (a_attr);
        }
 
-      fprintf (asm_out_file, "\t%s\t0,0\n", ASM_BYTE_OP);
+      dw2_asm_output_data (1, 0, NULL);
+      dw2_asm_output_data (1, 0, NULL);
     }
 
   /* Terminate the table.  */
-  fprintf (asm_out_file, "\t%s\t0\n", ASM_BYTE_OP);
+  dw2_asm_output_data (1, 0, NULL);
 }
 
 /* Output a symbol we can use to refer to this DIE from another CU.  */
@@ -5825,20 +5949,88 @@ output_die_symbol (die)
   ASM_OUTPUT_LABEL (asm_out_file, sym);
 }
 
-/* Output a symbolic (i.e. FORM_ref_addr) reference to TARGET_DIE.  */
-
+/* Return a new location list, given the begin and end range, and the
+   expression. gensym tells us whether to generate a new internal
+   symbol for this location list node, which is done for the head of
+   the list only. */ 
+static inline dw_loc_list_ref
+new_loc_list (expr, begin, end, section, gensym)
+     register dw_loc_descr_ref expr;
+     register const char *begin;
+     register const char *end;
+     register const char *section;
+     register unsigned gensym;
+{
+  register dw_loc_list_ref retlist
+    = (dw_loc_list_ref) xcalloc (1, sizeof (dw_loc_list_node));
+  retlist->begin = begin;
+  retlist->end = end;
+  retlist->expr = expr;
+  retlist->section = section;
+  if (gensym) 
+    retlist->ll_symbol = gen_internal_sym ("LLST");
+  return retlist;
+}
+
+/* Add a location description expression to a location list */
 static inline void
-output_symbolic_ref (target_die)
-     dw_die_ref target_die;
+add_loc_descr_to_loc_list (list_head, descr, begin, end, section)
+     register dw_loc_list_ref *list_head;
+     register dw_loc_descr_ref descr;
+     register const char *begin;
+     register const char *end;
+     register const char *section;
 {
-  char *sym = target_die->die_symbol;
+  register dw_loc_list_ref *d;
+  
+  /* Find the end of the chain. */
+  for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
+    ;
+  /* Add a new location list node to the list */
+  *d = new_loc_list (descr, begin, end, section, 0);
+}
 
-  if (sym == 0)
-    abort ();
 
-  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, sym);
-}
 
+/* Output the location list given to us */
+static void
+output_loc_list (list_head)
+     register dw_loc_list_ref list_head;
+{
+  register dw_loc_list_ref curr=list_head;
+  ASM_OUTPUT_LABEL (asm_out_file, list_head->ll_symbol);
+  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");
+    }
+  for (curr = list_head; curr != NULL; curr=curr->dw_loc_next)
+    {
+      int size;
+      dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
+                           "Location list begin address (%s)",
+                           list_head->ll_symbol);
+      dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->end, curr->section,
+                           "Location list end address (%s)",
+                           list_head->ll_symbol);
+      size = size_of_locs (curr->expr);
+      
+      /* Output the block length for this list of location operations.  */
+      dw2_asm_output_data (constant_size (size), size, "%s",
+                          "Location expression size");
+      
+      output_loc_sequence (curr->expr);
+    }
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, 0,
+                      "Location list terminator begin (%s)",
+                      list_head->ll_symbol);
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, 0,
+                      "Location list terminator end (%s)",
+                      list_head->ll_symbol);
+}
 /* Output the DIE and its attributes.  Called recursively to generate
    the definitions of each child DIE.  */
 
@@ -5855,42 +6047,24 @@ output_die (die)
   if (die->die_symbol)
     output_die_symbol (die);
 
-  output_uleb128 (die->die_abbrev);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, " (DIE (0x%lx) %s)",
-            die->die_offset, dwarf_tag_name (die->die_tag));
-
-  fputc ('\n', asm_out_file);
+  dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (0x%lx) %s)",
+                              die->die_offset, dwarf_tag_name (die->die_tag));
 
   for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
     {
+      const char *name = dwarf_attr_name (a->dw_attr);
+
       switch (AT_class (a))
        {
        case dw_val_class_addr:
-         ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, AT_addr (a));
+         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, AT_addr (a), "%s", name);
          break;
 
        case dw_val_class_loc:
          size = size_of_locs (AT_loc (a));
 
          /* Output the block length for this list of location operations.  */
-         switch (constant_size (size))
-           {
-           case 1:
-             ASM_OUTPUT_DWARF_DATA1 (asm_out_file, size);
-             break;
-           case 2:
-             ASM_OUTPUT_DWARF_DATA2 (asm_out_file, size);
-             break;
-           default:
-             abort ();
-           }
-
-         if (flag_debug_asm)
-           fprintf (asm_out_file, "\t%s %s",
-                    ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
-
-         fputc ('\n', asm_out_file);
+         dw2_asm_output_data (constant_size (size), size, "%s", name);
 
          output_loc_sequence (AT_loc (a));
          break;
@@ -5899,121 +6073,101 @@ output_die (die)
          /* ??? It would be slightly more efficient to use a scheme like is
             used for unsigned constants below, but gdb 4.x does not sign
             extend.  Gdb 5.x does sign extend.  */
-         output_sleb128 (AT_int (a));
+         dw2_asm_output_data_sleb128 (AT_int (a), "%s", name);
          break;
 
        case dw_val_class_unsigned_const:
-         switch (constant_size (AT_unsigned (a)))
-           {
-           case 1:
-             ASM_OUTPUT_DWARF_DATA1 (asm_out_file, AT_unsigned (a));
-             break;
-           case 2:
-             ASM_OUTPUT_DWARF_DATA2 (asm_out_file, AT_unsigned (a));
-             break;
-           case 4:
-             ASM_OUTPUT_DWARF_DATA4 (asm_out_file, AT_unsigned (a));
-             break;
-           case 8:
-             ASM_OUTPUT_DWARF_DATA8 (asm_out_file, AT_unsigned (a));
-             break;
-           default:
-             abort ();
-           }
+         dw2_asm_output_data (constant_size (AT_unsigned (a)),
+                              AT_unsigned (a), "%s", name);
          break;
 
        case dw_val_class_long_long:
-         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 8);
-         if (flag_debug_asm)
-           fprintf (asm_out_file, "\t%s %s",
-                    ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
-
-         fputc ('\n', asm_out_file);
-         ASM_OUTPUT_DWARF_CONST_DOUBLE (asm_out_file,
-                                        a->dw_attr_val.v.val_long_long.hi,
-                                        a->dw_attr_val.v.val_long_long.low);
+         {
+           unsigned HOST_WIDE_INT first, second;
 
-         if (flag_debug_asm)
-           fprintf (asm_out_file,
-                    "\t%s long long constant", ASM_COMMENT_START);
+           dw2_asm_output_data (1, 2*HOST_BITS_PER_LONG/HOST_BITS_PER_CHAR,
+                                "%s", name);
 
-         fputc ('\n', asm_out_file);
+           if (WORDS_BIG_ENDIAN)
+             {
+               first = a->dw_attr_val.v.val_long_long.hi;
+               second = a->dw_attr_val.v.val_long_long.low;
+             }
+           else
+             {
+               first = a->dw_attr_val.v.val_long_long.low;
+               second = a->dw_attr_val.v.val_long_long.hi;
+             }
+           dw2_asm_output_data (HOST_BITS_PER_LONG/HOST_BITS_PER_CHAR,
+                                first, "long long constant");
+           dw2_asm_output_data (HOST_BITS_PER_LONG/HOST_BITS_PER_CHAR,
+                                second, NULL);
+         }
          break;
 
        case dw_val_class_float:
          {
            register unsigned int i;
-           ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
-                                   a->dw_attr_val.v.val_float.length * 4);
-           if (flag_debug_asm)
-             fprintf (asm_out_file, "\t%s %s",
-                      ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
 
-           fputc ('\n', asm_out_file);
-           for (i = 0; i < a->dw_attr_val.v.val_float.length; ++i)
-             {
-               ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
-                                       a->dw_attr_val.v.val_float.array[i]);
-               if (flag_debug_asm)
-                 fprintf (asm_out_file, "\t%s fp constant word %u",
-                          ASM_COMMENT_START, i);
+           dw2_asm_output_data (1, a->dw_attr_val.v.val_float.length * 4,
+                                "%s", name);
 
-               fputc ('\n', asm_out_file);
-             }
+           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);
            break;
          }
 
        case dw_val_class_flag:
-         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, AT_flag (a));
+         dw2_asm_output_data (1, AT_flag (a), "%s", name);
+         break;
+        case dw_val_class_loc_list:
+         {
+           char *sym = AT_loc_list (a)->ll_symbol;
+           if (sym == 0)
+             abort();
+           dw2_asm_output_delta (DWARF_OFFSET_SIZE, sym, loc_section_label, name);
+         }
          break;
-
        case dw_val_class_die_ref:
          if (AT_ref_external (a))
-           output_symbolic_ref (AT_ref (a));
+           {
+             char *sym = AT_ref (a)->die_symbol;
+             if (sym == 0)
+               abort ();
+             dw2_asm_output_offset (DWARF2_ADDR_SIZE, sym, "%s", name);
+           }
+         else if (AT_ref (a)->die_offset == 0)
+           abort ();
          else
-           ASM_OUTPUT_DWARF_DATA (asm_out_file, AT_ref (a)->die_offset);
+           dw2_asm_output_data (DWARF_OFFSET_SIZE, AT_ref (a)->die_offset,
+                                "%s", name);
          break;
 
        case dw_val_class_fde_ref:
          {
            char l1[20];
-           ASM_GENERATE_INTERNAL_LABEL
-             (l1, FDE_AFTER_SIZE_LABEL, a->dw_attr_val.v.val_fde_index * 2);
-           ASM_OUTPUT_DWARF_OFFSET (asm_out_file, l1);
-           fprintf (asm_out_file, " - %d", DWARF_OFFSET_SIZE);
+           ASM_GENERATE_INTERNAL_LABEL (l1, FDE_LABEL,
+                                        a->dw_attr_val.v.val_fde_index * 2);
+           dw2_asm_output_offset (DWARF_OFFSET_SIZE, l1, "%s", name);
          }
          break;
 
        case dw_val_class_lbl_id:
-         ASM_OUTPUT_DWARF_ADDR (asm_out_file, AT_lbl (a));
+         dw2_asm_output_addr (DWARF2_ADDR_SIZE, AT_lbl (a), "%s", name);
          break;
 
        case dw_val_class_lbl_offset:
-         ASM_OUTPUT_DWARF_OFFSET (asm_out_file, AT_lbl (a));
+         dw2_asm_output_offset (DWARF_OFFSET_SIZE, AT_lbl (a), "%s", name);
          break;
 
        case dw_val_class_str:
-         if (flag_debug_asm)
-           ASM_OUTPUT_DWARF_STRING (asm_out_file, AT_string (a));
-         else
-           ASM_OUTPUT_ASCII (asm_out_file, AT_string (a),
-                             (int) strlen (AT_string (a)) + 1);
+         dw2_asm_output_nstring (AT_string (a), -1, "%s", name);
          break;
 
        default:
          abort ();
        }
-
-      if (AT_class (a) != dw_val_class_loc
-         && AT_class (a) != dw_val_class_long_long
-         && AT_class (a) != dw_val_class_float)
-       {
-         if (flag_debug_asm)
-           fprintf (asm_out_file, "\t%s %s",
-                    ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
-
-         fputc ('\n', asm_out_file);
-       }
     }
 
   for (c = die->die_child; c != NULL; c = c->die_sib)
@@ -6022,12 +6176,8 @@ output_die (die)
   if (die->die_child != NULL)
     {
       /* Add null byte to terminate sibling list.  */
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s end of children of DIE 0x%lx",
-                ASM_COMMENT_START, die->die_offset);
-
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data (1, 0, "end of children of DIE 0x%lx",
+                          die->die_offset);
     }
 }
 
@@ -6037,28 +6187,15 @@ output_die (die)
 static void
 output_compilation_unit_header ()
 {
-  ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset - DWARF_OFFSET_SIZE);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Length of Compilation Unit Info.",
-            ASM_COMMENT_START);
-
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s DWARF version number", ASM_COMMENT_START);
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset - DWARF_OFFSET_SIZE,
+                      "Length of Compilation Unit Info");
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, abbrev_section_label);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Offset Into Abbrev. Section",
-            ASM_COMMENT_START);
+  dw2_asm_output_data (2, DWARF_VERSION, "DWARF version number");
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF2_ADDR_SIZE);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Pointer Size (in bytes)", ASM_COMMENT_START);
+  dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label,
+                        "Offset Into Abbrev. Section");
 
-  fputc ('\n', asm_out_file);
+  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)");
 }
 
 /* Output the compilation unit DIE and its children.  */
@@ -6067,36 +6204,42 @@ static void
 output_comp_unit (die)
      dw_die_ref die;
 {
-  char *secname;
+  const char *secname;
 
-  if (die->die_child == 0)
-    return;
+  /* Even if there are no children of this DIE, we must output the
+     information about the compilation unit.  Otherwise, on an empty
+     translation unit, we will generate a present, but empty,
+     .debug_info section.  IRIX 6.5 `nm' will then complain when
+     examining the file.
+     
+     Mark all the DIEs in this CU so we know which get local refs.  */
+  mark_dies (die);
+
+  build_abbrev_table (die);
 
   /* Initialize the beginning DIE offset - and calculate sizes/offsets.   */
   next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
   calc_die_sizes (die);
 
-  build_abbrev_table (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);
   ASM_OUTPUT_SECTION (asm_out_file, secname);
   output_compilation_unit_header ();
   output_die (die);
 
-  /* Leave the sizes on the main CU, since we do it last and we use the
-     sizes in output_pubnames.  */
+  /* Leave the marks on the main CU, so we can check them in
+     output_pubnames.  */
   if (die->die_symbol)
-    clear_die_sizes (die);
+    unmark_dies (die);
 }
 
 /* The DWARF2 pubname for a nested thingy looks like "A::f".  The output
@@ -6146,60 +6289,32 @@ output_pubnames ()
   register unsigned i;
   register unsigned long pubnames_length = size_of_pubnames ();
 
-  ASM_OUTPUT_DWARF_DATA (asm_out_file, pubnames_length);
-
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Length of Public Names Info.",
-            ASM_COMMENT_START);
-
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length,
+                      "Length of Public Names Info");
 
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START);
+  dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, debug_info_section_label);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.",
-            ASM_COMMENT_START);
+  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
+                        "Offset of Compilation Unit Info");
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Compilation Unit Length", ASM_COMMENT_START);
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset,
+                      "Compilation Unit Length");
 
-  fputc ('\n', asm_out_file);
   for (i = 0; i < pubname_table_in_use; ++i)
     {
       register pubname_ref pub = &pubname_table[i];
 
       /* We shouldn't see pubnames for DIEs outside of the main CU.  */
-      if (pub->die->die_offset == 0)
+      if (pub->die->die_mark == 0)
        abort ();
 
-      ASM_OUTPUT_DWARF_DATA (asm_out_file, pub->die->die_offset);
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s DIE offset", ASM_COMMENT_START);
-
-      fputc ('\n', asm_out_file);
-
-      if (flag_debug_asm)
-       {
-         ASM_OUTPUT_DWARF_STRING (asm_out_file, pub->name);
-         fprintf (asm_out_file, "%s external name", ASM_COMMENT_START);
-       }
-      else
-       {
-         ASM_OUTPUT_ASCII (asm_out_file, pub->name,
-                           (int) strlen (pub->name) + 1);
-       }
+      dw2_asm_output_data (DWARF_OFFSET_SIZE, pub->die->die_offset,
+                          "DIE offset");
 
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_nstring (pub->name, -1, "external name");
     }
 
-  ASM_OUTPUT_DWARF_DATA (asm_out_file, 0);
-  fputc ('\n', asm_out_file);
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, NULL);
 }
 
 /* Add a new entry to .debug_aranges if appropriate.  */
@@ -6233,70 +6348,48 @@ output_aranges ()
   register unsigned i;
   register unsigned long aranges_length = size_of_aranges ();
 
-  ASM_OUTPUT_DWARF_DATA (asm_out_file, aranges_length);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Length of Address Ranges Info.",
-            ASM_COMMENT_START);
+  dw2_asm_output_data (DWARF_OFFSET_SIZE, aranges_length,
+                      "Length of Address Ranges Info");
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START);
+  dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_OFFSET (asm_out_file, debug_info_section_label);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.",
-            ASM_COMMENT_START);
+  dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label,
+                        "Offset of Compilation Unit Info");
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF2_ADDR_SIZE);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Size of Address", ASM_COMMENT_START);
+  dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Size of Address");
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Size of Segment Descriptor",
-            ASM_COMMENT_START);
-
-  fputc ('\n', asm_out_file);
+  dw2_asm_output_data (1, 0, "Size of Segment Descriptor");
 
   /* We need to align to twice the pointer size here.  */
   if (DWARF_ARANGES_PAD_SIZE)
     {
-      /* Pad using a 2 bytes word so that padding is correct
-         for any pointer size.  */
-      ASM_OUTPUT_DWARF_DATA2 (asm_out_file, 0);
-      for (i = 2; i < DWARF_ARANGES_PAD_SIZE; i += 2)
-       fprintf (asm_out_file, ",0");
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s Pad to %d byte boundary",
-                ASM_COMMENT_START, 2 * DWARF2_ADDR_SIZE);
+      /* Pad using a 2 byte words so that padding is correct for any
+         pointer size.  */
+      dw2_asm_output_data (2, 0, "Pad to %d byte boundary",
+                          2 * DWARF2_ADDR_SIZE);
+      for (i = 2; i < (unsigned) DWARF_ARANGES_PAD_SIZE; i += 2)
+       dw2_asm_output_data (2, 0, NULL);
     }
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_ADDR (asm_out_file, text_section_label);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START);
-
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, text_end_label,
-                              text_section_label);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "%s Length", ASM_COMMENT_START);
+  dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_section_label, "Address");
+  dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
+                       text_section_label, "Length");
 
-  fputc ('\n', asm_out_file);
   for (i = 0; i < arange_table_in_use; ++i)
     {
       dw_die_ref die = arange_table[i];
 
       /* We shouldn't see aranges for DIEs outside of the main CU.  */
-      if (die->die_offset == 0)
+      if (die->die_mark == 0)
        abort ();
 
       if (die->die_tag == DW_TAG_subprogram)
-       ASM_OUTPUT_DWARF_ADDR (asm_out_file, get_AT_low_pc (die));
+       {
+         dw2_asm_output_addr (DWARF2_ADDR_SIZE, get_AT_low_pc (die),
+                                "Address");
+         dw2_asm_output_delta (DWARF2_ADDR_SIZE, get_AT_hi_pc (die),
+                               get_AT_low_pc (die), "Length");
+       }
       else
        {
          /* A static variable; extract the symbol from DW_AT_location.
@@ -6312,45 +6405,300 @@ output_aranges ()
          if (loc->dw_loc_opc != DW_OP_addr)
            abort ();
 
-         ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file,
-                                      loc->dw_loc_oprnd1.v.val_addr);
+         dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE,
+                                  loc->dw_loc_oprnd1.v.val_addr, "Address");
+         dw2_asm_output_data (DWARF2_ADDR_SIZE,
+                              get_AT_unsigned (die, DW_AT_byte_size),
+                              "Length");
        }
+    }
 
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START);
+  /* Output the terminator words.  */
+  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
+  dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, NULL);
+}
 
-      fputc ('\n', asm_out_file);
-      if (die->die_tag == DW_TAG_subprogram)
-       ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, get_AT_hi_pc (die),
-                                    get_AT_low_pc (die));
-      else
-       ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file,
-                                   get_AT_unsigned (die, DW_AT_byte_size));
 
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "%s Length", ASM_COMMENT_START);
+/* 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 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;
 
-      fputc ('\n', asm_out_file);
+  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 terminator words.  */
-  ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0);
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0);
-  fputc ('\n', asm_out_file);
+/* 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 (file_table.in_use
+                                      * sizeof (struct file_info));
+  dirs = (struct dir_info *) alloca (file_table.in_use
+                                    * sizeof (struct dir_info));
+
+  /* Sort the file names.  */
+  for (i = 1; i < (int) file_table.in_use; ++i)
+    {
+      char *f;
+
+      /* Skip all leading "./".  */
+      f = 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, 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].count = 1;
+  dirs[0].dir_idx = 0;
+  dirs[0].used = 0;
+  files[1].dir_idx = 0;
+  ndirs = 1;
+
+  for (i = 2; i < (int) 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].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].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 > 1
+             && (dirs[ndirs].prefix == -1
+                 || dirs[j].length > dirs[dirs[ndirs].prefix].length)
+             && 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 save 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 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 (file_table.in_use * sizeof (int));
+  for (i = 1; i < (int) 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].length > 0 ? 1 : 0;
+  for (i = 1 - idx_offset; i < ndirs; ++i)
+    if (dirs[i].used != 0)
+      {
+       dirs[i].used = idx++;
+       dw2_asm_output_nstring (dirs[i].path, dirs[i].length - 1,
+                               "Directory Entry: 0x%x", dirs[i].used);
+      }
+  dw2_asm_output_data (1, 0, "End directory table");
+
+  /* Correct the index for the current working directory entry if it
+     exists.  */
+  if (idx_offset == 0)
+    dirs[0].used = 0;
+
+  /* Now write all the file names.  */
+  for (i = 1; i < (int) file_table.in_use; ++i)
+    {
+      int file_idx = backmap[i];
+      int dir_idx = dirs[files[file_idx].dir_idx].dir_idx;
+
+      dw2_asm_output_nstring (files[file_idx].path + dirs[dir_idx].length, -1,
+                             "File Entry: 0x%x", i);
+
+      /* Include directory index.  */
+      dw2_asm_output_data_uleb128 (dirs[dir_idx].used, NULL);
+
+      /* Modification time.  */
+      dw2_asm_output_data_uleb128 (0, NULL);
+
+      /* File length in bytes.  */
+      dw2_asm_output_data_uleb128 (0, NULL);
+    }
+  dw2_asm_output_data (1, 0, "End file name table");
 }
 
+
 /* Output the source line number correspondence information.  This
    information goes into the .debug_line section.  */
 
 static void
 output_line_info ()
 {
+  char l1[20], l2[20], p1[20], p2[20];
   char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
   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;
@@ -6358,52 +6706,35 @@ output_line_info ()
   register unsigned long current_file;
   register unsigned long function;
 
-  ASM_OUTPUT_DWARF_DELTA (asm_out_file, ".LTEND", ".LTSTART");
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Length of Source Line Info.",
-            ASM_COMMENT_START);
+  ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (p1, LN_PROLOG_AS_LABEL, 0);
+  ASM_GENERATE_INTERNAL_LABEL (p2, LN_PROLOG_END_LABEL, 0);
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_LABEL (asm_out_file, ".LTSTART");
-  ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START);
+  dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1,
+                       "Length of Source Line Info");
+  ASM_OUTPUT_LABEL (asm_out_file, l1);
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_prolog ());
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Prolog Length", ASM_COMMENT_START);
+  dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version");
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_MIN_INSTR_LENGTH);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Minimum Instruction Length",
-            ASM_COMMENT_START);
+  dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length");
+  ASM_OUTPUT_LABEL (asm_out_file, p1);
 
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_DEFAULT_IS_STMT_START);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Default is_stmt_start flag",
-            ASM_COMMENT_START);
+  dw2_asm_output_data (1, DWARF_LINE_MIN_INSTR_LENGTH,
+                      "Minimum Instruction Length");
 
-  fputc ('\n', asm_out_file);
-  fprintf (asm_out_file, "\t%s\t%d", ASM_BYTE_OP, DWARF_LINE_BASE);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Line Base Value (Special Opcodes)",
-            ASM_COMMENT_START);
+  dw2_asm_output_data (1, DWARF_LINE_DEFAULT_IS_STMT_START,
+                      "Default is_stmt_start flag");
 
-  fputc ('\n', asm_out_file);
-  fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_RANGE);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Line Range Value (Special Opcodes)",
-            ASM_COMMENT_START);
+  dw2_asm_output_data (1, DWARF_LINE_BASE,
+                      "Line Base Value (Special Opcodes)");
 
-  fputc ('\n', asm_out_file);
-  fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_OPCODE_BASE);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s Special Opcode Base", ASM_COMMENT_START);
+  dw2_asm_output_data (1, DWARF_LINE_RANGE,
+                      "Line Range Value (Special Opcodes)");
+
+  dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE,
+                      "Special Opcode Base");
 
-  fputc ('\n', asm_out_file);
   for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; ++opc)
     {
       switch (opc)
@@ -6419,55 +6750,14 @@ output_line_info ()
          n_op_args = 0;
          break;
        }
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, n_op_args);
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s opcode: 0x%x has %d args",
-                ASM_COMMENT_START, opc, n_op_args);
-      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);
+      dw2_asm_output_data (1, n_op_args, "opcode: 0x%x has %d args",
+                          opc, n_op_args);
     }
 
-  /* 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 ();
+  ASM_OUTPUT_LABEL (asm_out_file, p2);
 
   /* 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
@@ -6495,44 +6785,31 @@ output_line_info ()
        continue;
 #endif
 
-      /* Emit debug info for the address of the current line, choosing
-        the encoding that uses the least amount of space.  */
-      /* ??? Unfortunately, we have little choice here currently, and must
-        always use the most general form.  Gcc does not know the address
-        delta itself, so we can't use DW_LNS_advance_pc.  There are no known
-        dwarf2 aware assemblers at this time, so we can't use any special
-        pseudo ops that would allow the assembler to optimally encode this for
-        us.  Many ports do have length attributes which will give an upper
-        bound on the address range.  We could perhaps use length attributes
-        to determine when it is safe to use DW_LNS_fixed_advance_pc.  */
+      /* Emit debug info for the address of the current line.
+
+        Unfortunately, we have little choice here currently, and must always
+        use the most general form.  Gcc does not know the address delta
+        itself, so we can't use DW_LNS_advance_pc.  Many ports do have length
+        attributes which will give an upper bound on the address range.  We
+        could perhaps use length attributes to determine when it is safe to
+        use DW_LNS_fixed_advance_pc.  */
+
       ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index);
       if (0)
        {
          /* This can handle deltas up to 0xffff.  This takes 3 bytes.  */
-         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
-         if (flag_debug_asm)
-           fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
-                    ASM_COMMENT_START);
-
-         fputc ('\n', asm_out_file);
-         ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, prev_line_label);
-         fputc ('\n', asm_out_file);
+         dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
+                              "DW_LNS_fixed_advance_pc");
+         dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
        }
       else
        {
          /* This can handle any delta.  This takes
              4+DWARF2_ADDR_SIZE bytes.  */
-         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
-         if (flag_debug_asm)
-           fprintf (asm_out_file, "\t%s DW_LNE_set_address",
-                    ASM_COMMENT_START);
-         fputc ('\n', asm_out_file);
-         output_uleb128 (1 + DWARF2_ADDR_SIZE);
-         fputc ('\n', asm_out_file);
-         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
-         fputc ('\n', asm_out_file);
-         ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
-         fputc ('\n', asm_out_file);
+         dw2_asm_output_data (1, 0, "DW_LNE_set_address");
+         dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+         dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+         dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
        }
       strcpy (prev_line_label, line_label);
 
@@ -6541,16 +6818,9 @@ output_line_info ()
       if (line_info->dw_file_num != current_file)
        {
          current_file = line_info->dw_file_num;
-         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file);
-         if (flag_debug_asm)
-           fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START);
-
-         fputc ('\n', asm_out_file);
-         output_uleb128 (current_file);
-         if (flag_debug_asm)
-           fprintf (asm_out_file, " (\"%s\")", file_table[current_file]);
-
-         fputc ('\n', asm_out_file);
+         dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
+         dw2_asm_output_data_uleb128 (current_file, "(\"%s\")",
+                                      file_table.table[current_file]);
        }
 
       /* Emit debug info for the current line number, choosing the encoding
@@ -6565,77 +6835,44 @@ output_line_info ()
              /* This can handle deltas from -10 to 234, using the current
                 definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE.  This
                 takes 1 byte.  */
-             ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
-                                     DWARF_LINE_OPCODE_BASE + line_delta);
-             if (flag_debug_asm)
-               fprintf (asm_out_file,
-                        "\t%s line %ld", ASM_COMMENT_START, current_line);
-
-             fputc ('\n', asm_out_file);
+             dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
+                                  "line %lu", current_line);
            }
          else
            {
              /* This can handle any delta.  This takes at least 4 bytes,
                 depending on the value being encoded.  */
-             ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line);
-             if (flag_debug_asm)
-               fprintf (asm_out_file, "\t%s advance to line %ld",
-                        ASM_COMMENT_START, current_line);
-
-             fputc ('\n', asm_out_file);
-             output_sleb128 (line_offset);
-             fputc ('\n', asm_out_file);
-             ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy);
-             if (flag_debug_asm)
-               fprintf (asm_out_file, "\t%s DW_LNS_copy", ASM_COMMENT_START);
-             fputc ('\n', asm_out_file);
+             dw2_asm_output_data (1, DW_LNS_advance_line,
+                                  "advance to line %lu", current_line);
+             dw2_asm_output_data_sleb128 (line_offset, NULL);
+             dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
            }
        }
       else
        {
          /* We still need to start a new row, so output a copy insn.  */
-         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy);
-         if (flag_debug_asm)
-           fprintf (asm_out_file, "\t%s DW_LNS_copy", ASM_COMMENT_START);
-         fputc ('\n', asm_out_file);
+         dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
        }
     }
 
   /* Emit debug info for the address of the end of the function.  */
   if (0)
     {
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
-                ASM_COMMENT_START);
-
-      fputc ('\n', asm_out_file);
-      ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, text_end_label, prev_line_label);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
+                          "DW_LNS_fixed_advance_pc");
+      dw2_asm_output_delta (2, text_end_label, prev_line_label, NULL);
     }
   else
     {
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
-      if (flag_debug_asm)
-       fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START);
-      fputc ('\n', asm_out_file);
-      output_uleb128 (1 + DWARF2_ADDR_SIZE);
-      fputc ('\n', asm_out_file);
-      ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
-      fputc ('\n', asm_out_file);
-      ASM_OUTPUT_DWARF_ADDR (asm_out_file, text_end_label);
-      fputc ('\n', asm_out_file);
+      dw2_asm_output_data (1, 0, "DW_LNE_set_address");
+      dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+      dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+      dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_end_label, NULL);
     }
 
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
-  if (flag_debug_asm)
-    fprintf (asm_out_file, "\t%s DW_LNE_end_sequence", ASM_COMMENT_START);
-
-  fputc ('\n', asm_out_file);
-  output_uleb128 (1);
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence);
-  fputc ('\n', asm_out_file);
+  dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
+  dw2_asm_output_data_uleb128 (1, NULL);
+  dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
 
   function = 0;
   current_file = 1;
@@ -6663,47 +6900,26 @@ output_line_info ()
          function = line_info->function;
 
          /* Set the address register to the first line in the function */
-         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
-         if (flag_debug_asm)
-           fprintf (asm_out_file, "\t%s DW_LNE_set_address",
-                    ASM_COMMENT_START);
-
-         fputc ('\n', asm_out_file);
-         output_uleb128 (1 + DWARF2_ADDR_SIZE);
-         fputc ('\n', asm_out_file);
-         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
-         fputc ('\n', asm_out_file);
-         ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
-         fputc ('\n', asm_out_file);
+         dw2_asm_output_data (1, 0, "DW_LNE_set_address");
+         dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+         dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+         dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
        }
       else
        {
          /* ??? See the DW_LNS_advance_pc comment above.  */
          if (0)
            {
-             ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
-             if (flag_debug_asm)
-               fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
-                        ASM_COMMENT_START);
-
-             fputc ('\n', asm_out_file);
-             ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label,
-                                      prev_line_label);
-             fputc ('\n', asm_out_file);
+             dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
+                                  "DW_LNS_fixed_advance_pc");
+             dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
            }
          else
            {
-             ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
-             if (flag_debug_asm)
-               fprintf (asm_out_file, "\t%s DW_LNE_set_address",
-                        ASM_COMMENT_START);
-             fputc ('\n', asm_out_file);
-             output_uleb128 (1 + DWARF2_ADDR_SIZE);
-             fputc ('\n', asm_out_file);
-             ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
-             fputc ('\n', asm_out_file);
-             ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
-             fputc ('\n', asm_out_file);
+             dw2_asm_output_data (1, 0, "DW_LNE_set_address");
+             dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+             dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+             dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
            }
        }
       strcpy (prev_line_label, line_label);
@@ -6713,16 +6929,9 @@ output_line_info ()
       if (line_info->dw_file_num != current_file)
        {
          current_file = line_info->dw_file_num;
-         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file);
-         if (flag_debug_asm)
-           fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START);
-
-         fputc ('\n', asm_out_file);
-         output_uleb128 (current_file);
-         if (flag_debug_asm)
-           fprintf (asm_out_file, " (\"%s\")", file_table[current_file]);
-
-         fputc ('\n', asm_out_file);
+         dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file");
+         dw2_asm_output_data_uleb128 (current_file, "(\"%s\")",
+                                      file_table.table[current_file]);
        }
 
       /* Emit debug info for the current line number, choosing the encoding
@@ -6733,39 +6942,18 @@ output_line_info ()
          line_delta = line_offset - DWARF_LINE_BASE;
          current_line = line_info->dw_line_num;
          if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
-           {
-             ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
-                                     DWARF_LINE_OPCODE_BASE + line_delta);
-             if (flag_debug_asm)
-               fprintf (asm_out_file,
-                        "\t%s line %ld", ASM_COMMENT_START, current_line);
-
-             fputc ('\n', asm_out_file);
-           }
+           dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta,
+                                "line %lu", current_line);
          else
            {
-             ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line);
-             if (flag_debug_asm)
-               fprintf (asm_out_file, "\t%s advance to line %ld",
-                        ASM_COMMENT_START, current_line);
-
-             fputc ('\n', asm_out_file);
-             output_sleb128 (line_offset);
-             fputc ('\n', asm_out_file);
-             ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy);
-             if (flag_debug_asm)
-               fprintf (asm_out_file, "\t%s DW_LNS_copy", ASM_COMMENT_START);
-             fputc ('\n', asm_out_file);
+             dw2_asm_output_data (1, DW_LNS_advance_line,
+                                  "advance to line %lu", current_line);
+             dw2_asm_output_data_sleb128 (line_offset, NULL);
+             dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
            }
        }
       else
-       {
-         /* We still need to start a new row, so output a copy insn.  */
-         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy);
-         if (flag_debug_asm)
-           fprintf (asm_out_file, "\t%s DW_LNS_copy", ASM_COMMENT_START);
-         fputc ('\n', asm_out_file);
-       }
+       dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy");
 
 #if 0
     cont:
@@ -6783,47 +6971,27 @@ output_line_info ()
          ASM_GENERATE_INTERNAL_LABEL (line_label, FUNC_END_LABEL, function);
          if (0)
            {
-             ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
-             if (flag_debug_asm)
-               fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
-                        ASM_COMMENT_START);
-
-             fputc ('\n', asm_out_file);
-             ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label,
-                                      prev_line_label);
-             fputc ('\n', asm_out_file);
+             dw2_asm_output_data (1, DW_LNS_fixed_advance_pc,
+                                  "DW_LNS_fixed_advance_pc");
+             dw2_asm_output_delta (2, line_label, prev_line_label, NULL);
            }
          else
            {
-             ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
-             if (flag_debug_asm)
-               fprintf (asm_out_file, "\t%s DW_LNE_set_address",
-                        ASM_COMMENT_START);
-             fputc ('\n', asm_out_file);
-             output_uleb128 (1 + DWARF2_ADDR_SIZE);
-             fputc ('\n', asm_out_file);
-             ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
-             fputc ('\n', asm_out_file);
-             ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
-             fputc ('\n', asm_out_file);
+             dw2_asm_output_data (1, 0, "DW_LNE_set_address");
+             dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL);
+             dw2_asm_output_data (1, DW_LNE_set_address, NULL);
+             dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL);
            }
 
          /* Output the marker for the end of this sequence.  */
-         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
-         if (flag_debug_asm)
-           fprintf (asm_out_file, "\t%s DW_LNE_end_sequence",
-                    ASM_COMMENT_START);
-
-         fputc ('\n', asm_out_file);
-         output_uleb128 (1);
-         fputc ('\n', asm_out_file);
-         ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence);
-         fputc ('\n', asm_out_file);
+         dw2_asm_output_data (1, 0, "DW_LNE_end_sequence");
+         dw2_asm_output_data_uleb128 (1, NULL);
+         dw2_asm_output_data (1, DW_LNE_end_sequence, NULL);
        }
     }
 
   /* Output the marker for the end of the line number info.  */
-  ASM_OUTPUT_LABEL (asm_out_file, ".LTEND");
+  ASM_OUTPUT_LABEL (asm_out_file, l2);
 }
 \f
 /* Given a pointer to a tree node for some base type, return a pointer to
@@ -6978,6 +7146,7 @@ is_base_type (type)
     case FILE_TYPE:
     case OFFSET_TYPE:
     case LANG_TYPE:
+    case VECTOR_TYPE:
       return 0;
 
     default:
@@ -7004,22 +7173,35 @@ modified_type_die (type, is_const_type, is_volatile_type, context_die)
 
   if (code != ERROR_MARK)
     {
-      type = build_type_variant (type, is_const_type, is_volatile_type);
-
-      mod_type_die = lookup_type_die (type);
-      if (mod_type_die)
-       return mod_type_die;
+      tree qualified_type;
+
+      /* See if we already have the appropriately qualified variant of
+        this type.  */
+      qualified_type 
+       = get_qualified_type (type,
+                             ((is_const_type ? TYPE_QUAL_CONST : 0)
+                              | (is_volatile_type 
+                                 ? TYPE_QUAL_VOLATILE : 0)));
+      /* If we do, then we can just use its DIE, if it exists.  */
+      if (qualified_type)
+       {
+         mod_type_die = lookup_type_die (qualified_type);
+         if (mod_type_die)
+           return mod_type_die;
+       }
 
       /* Handle C typedef types.  */
-      if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
-         && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
+      if (qualified_type && TYPE_NAME (qualified_type) 
+         && TREE_CODE (TYPE_NAME (qualified_type)) == TYPE_DECL
+         && DECL_ORIGINAL_TYPE (TYPE_NAME (qualified_type)))
        {
-         tree dtype = TREE_TYPE (TYPE_NAME (type));
-         if (type == dtype)
+         tree type_name = TYPE_NAME (qualified_type);
+         tree dtype = TREE_TYPE (type_name);
+         if (qualified_type == dtype)
            {
              /* For a named type, use the typedef.  */
-             gen_type_die (type, context_die);
-             mod_type_die = lookup_type_die (type);
+             gen_type_die (qualified_type, context_die);
+             mod_type_die = lookup_type_die (qualified_type);
            }
 
          else if (is_const_type < TYPE_READONLY (dtype)
@@ -7027,7 +7209,7 @@ modified_type_die (type, is_const_type, is_volatile_type, context_die)
            /* cv-unqualified version of named type.  Just use the unnamed
               type to which it refers.  */
            mod_type_die
-             = modified_type_die (DECL_ORIGINAL_TYPE (TYPE_NAME (type)),
+             = modified_type_die (DECL_ORIGINAL_TYPE (type_name),
                                   is_const_type, is_volatile_type,
                                   context_die);
          /* Else cv-qualified version of named type; fall through.  */
@@ -7080,6 +7262,10 @@ modified_type_die (type, is_const_type, is_volatile_type, context_die)
          if (mod_type_die == NULL)
            abort ();
        }
+
+      /* We want to equate the qualified type to the die below.  */
+      if (qualified_type)
+       type = qualified_type;
     }
 
   equate_type_number_to_die (type, mod_type_die);
@@ -7144,6 +7330,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
@@ -7212,6 +7438,7 @@ mem_loc_descriptor (rtl, mode)
     {
     case POST_INC:
     case POST_DEC:
+    case POST_MODIFY:
       /* POST_INC and POST_DEC can be handled just like a SUBREG.  So we
         just fall into the SUBREG code.  */
 
@@ -7223,7 +7450,7 @@ mem_loc_descriptor (rtl, mode)
          up an entire register.  For now, just assume that it is
          legitimate to make the Dwarf info refer to the whole register which
          contains the given subreg.  */
-      rtl = XEXP (rtl, 0);
+      rtl = SUBREG_REG (rtl);
 
       /* Fall through.  */
 
@@ -7245,21 +7472,37 @@ mem_loc_descriptor (rtl, mode)
       break;
 
     case MEM:
-      mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode);
+      mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
       add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
       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:
     case SYMBOL_REF:
+      /* Alternatively, the symbol in the constant pool might be referenced
+        by a different symbol.  */
+      if (GET_CODE (rtl) == SYMBOL_REF
+         && CONSTANT_POOL_ADDRESS_P (rtl))
+       {
+         rtx tmp = get_pool_constant (rtl);
+         if (GET_CODE (tmp) == SYMBOL_REF)
+           rtl = tmp;
+       }
+
       mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
       mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
       mem_loc_result->dw_loc_oprnd1.v.val_addr = save_rtx (rtl);
       break;
 
+    case PRE_MODIFY:
+      /* Extract the PLUS expression nested inside and fall into
+         PLUS code below.  */
+      rtl = XEXP (rtl, 1);
+      goto plus;
+
     case PRE_INC:
     case PRE_DEC:
       /* Turn these into a PLUS expression and fall into the PLUS code
@@ -7272,29 +7515,43 @@ mem_loc_descriptor (rtl, mode)
       /* Fall through.  */
 
     case PLUS:
+    plus:
       if (is_based_loc (rtl))
        mem_loc_result = based_loc_descr (reg_number (XEXP (rtl, 0)),
                                          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:
@@ -7347,7 +7604,7 @@ loc_descriptor (rtl)
          up an entire register.  For now, just assume that it is
          legitimate to make the Dwarf info refer to the whole register which
          contains the given subreg.  */
-      rtl = XEXP (rtl, 0);
+      rtl = SUBREG_REG (rtl);
 
       /* Fall through.  */
 
@@ -7355,19 +7612,288 @@ loc_descriptor (rtl)
       loc_result = reg_loc_descriptor (rtl);
       break;
 
-    case MEM:
-      loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
+    case MEM:
+      loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
+      break;
+
+    case CONCAT:
+      loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1));
+      break;
+
+    default:
+      abort ();
+    }
+
+  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 WITH_RECORD_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
+        only user of this is Ada, which encodes the needed information using
+        the names of types.  */
+      return ret;
+
+    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 NOP_EXPR:
+    case CONVERT_EXPR:
+    case NON_LVALUE_EXPR:
+    case SAVE_EXPR:
+      return loc_descriptor_from_tree (TREE_OPERAND (loc, 0), addressp);
+
+    case COMPONENT_REF:
+    case BIT_FIELD_REF:
+    case ARRAY_REF:
+    case ARRAY_RANGE_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;
+
+    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 CONCAT:
-      loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1));
+    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 ();
     }
 
-  return loc_result;
+  /* 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'
@@ -7402,10 +7928,9 @@ field_type (decl)
   return type;
 }
 
-/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
-   node, return the alignment in bits for the type, or else return
-   BITS_PER_WORD if the node actually turns out to be an
-   ERROR_MARK node.  */
+/* Given a pointer to a tree node, return the alignment in bits for
+   it, or else return BITS_PER_WORD if the node actually turns out to
+   be an ERROR_MARK node.  */
 
 static inline unsigned
 simple_type_align_in_bits (type)
@@ -7414,6 +7939,13 @@ simple_type_align_in_bits (type)
   return (TREE_CODE (type) != ERROR_MARK) ? TYPE_ALIGN (type) : BITS_PER_WORD;
 }
 
+static inline unsigned
+simple_decl_align_in_bits (decl)
+     register tree decl;
+{
+  return (TREE_CODE (decl) != ERROR_MARK) ? DECL_ALIGN (decl) : BITS_PER_WORD;
+}
+
 /* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
    node, return the size in bits for the type if it is a constant, or else
    return the alignment for the type if the type's size is not constant, or
@@ -7424,17 +7956,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);
+  type_size_tree = TYPE_SIZE (type);
 
-      if (! host_integerp (type_size_tree, 1))
-       return TYPE_ALIGN (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
@@ -7448,10 +7980,9 @@ static HOST_WIDE_INT
 field_byte_offset (decl)
      register tree decl;
 {
-  unsigned int type_align_in_bytes;
   unsigned int type_align_in_bits;
+  unsigned int decl_align_in_bits;
   unsigned HOST_WIDE_INT type_size_in_bits;
-  HOST_WIDE_INT object_offset_in_align_units;
   HOST_WIDE_INT object_offset_in_bits;
   HOST_WIDE_INT object_offset_in_bytes;
   tree type;
@@ -7469,14 +8000,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
@@ -7486,7 +8013,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
@@ -7494,7 +8021,7 @@ field_byte_offset (decl)
 
   type_size_in_bits = simple_type_size_in_bits (type);
   type_align_in_bits = simple_type_align_in_bits (type);
-  type_align_in_bytes = type_align_in_bits / BITS_PER_UNIT;
+  decl_align_in_bits = simple_decl_align_in_bits (decl);
 
   /* Note that the GCC front-end doesn't make any attempt to keep track of
      the starting bit offset (relative to the start of the containing
@@ -7541,14 +8068,25 @@ field_byte_offset (decl)
 
   /* This is the tricky part.  Use some fancy footwork to deduce where the
      lowest addressed bit of the containing object must be.  */
-  object_offset_in_bits
-    = ceiling (deepest_bitpos, type_align_in_bits) - type_size_in_bits;
+  object_offset_in_bits = deepest_bitpos - type_size_in_bits;
 
-  /* Compute the offset of the containing object in "alignment units".  */
-  object_offset_in_align_units = object_offset_in_bits / type_align_in_bits;
+  /* Round up to type_align by default.  This works best for bitfields.  */
+  object_offset_in_bits += type_align_in_bits - 1;
+  object_offset_in_bits /= type_align_in_bits;
+  object_offset_in_bits *= type_align_in_bits;
+
+  if (object_offset_in_bits > bitpos_int)
+    {
+      /* Sigh, the decl must be packed.  */
+      object_offset_in_bits = deepest_bitpos - type_size_in_bits;
+
+      /* Round up to decl_align instead.  */
+      object_offset_in_bits += decl_align_in_bits - 1;
+      object_offset_in_bits /= decl_align_in_bits;
+      object_offset_in_bits *= decl_align_in_bits;
+    }
 
-  /* Compute the offset of the containing object in bytes.  */
-  object_offset_in_bytes = object_offset_in_align_units * type_align_in_bytes;
+  object_offset_in_bytes = object_offset_in_bits / BITS_PER_UNIT;
 
   return object_offset_in_bytes;
 }
@@ -7658,12 +8196,28 @@ add_const_value_attribute (die, rtl)
   switch (GET_CODE (rtl))
     {
     case CONST_INT:
-      /* Note that a CONST_INT rtx could represent either an integer or a
-         floating-point constant.  A CONST_INT is used whenever the constant
-         will fit into a single word.  In all such cases, the original mode
-         of the constant value is wiped out, and the CONST_INT rtx is
-         assigned VOIDmode.  */
-      add_AT_unsigned (die, DW_AT_const_value, (unsigned) INTVAL (rtl));
+      /* Note that a CONST_INT rtx could represent either an integer
+        or a floating-point constant.  A CONST_INT is used whenever
+        the constant will fit into a single word.  In all such
+        cases, the original mode of the constant value is wiped
+        out, and the CONST_INT rtx is assigned VOIDmode.  */
+      {
+       HOST_WIDE_INT val = INTVAL (rtl);
+       
+       /* ??? We really should be using HOST_WIDE_INT throughout.  */
+       if (val < 0)
+         {
+           if ((long) val != val)
+             abort ();
+           add_AT_int (die, DW_AT_const_value, (long) val);
+         }
+       else
+         {
+           if ((unsigned long) val != (unsigned HOST_WIDE_INT) val)
+             abort ();
+           add_AT_int (die, DW_AT_const_value, (unsigned long) val);
+         }
+      }
       break;
 
     case CONST_DOUBLE:
@@ -7676,8 +8230,8 @@ add_const_value_attribute (die, rtl)
 
        if (GET_MODE_CLASS (mode) == MODE_FLOAT)
          {
-           register unsigned length = GET_MODE_SIZE (mode) / sizeof (long);
-           long array[4];
+           register unsigned length = GET_MODE_SIZE (mode) / 4;
+           long *array = (long *) xmalloc (sizeof (long) * length);
            REAL_VALUE_TYPE rv;
 
            REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl);
@@ -7703,8 +8257,13 @@ add_const_value_attribute (die, rtl)
            add_AT_float (die, DW_AT_const_value, length, array);
          }
        else
-         add_AT_long_long (die, DW_AT_const_value,
-                           CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
+         {
+           /* ??? We really should be using HOST_WIDE_INT throughout.  */
+           if (HOST_BITS_PER_LONG != HOST_BITS_PER_WIDE_INT)
+             abort ();
+           add_AT_long_long (die, DW_AT_const_value,
+                             CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
+         }
       }
       break;
 
@@ -7739,31 +8298,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
@@ -7841,14 +8380,14 @@ add_location_or_const_value_attribute (die, decl)
      gets fixed).  */
 
   /* Use DECL_RTL as the "location" unless we find something better.  */
-  rtl = DECL_RTL (decl);
+  rtl = DECL_RTL_IF_SET (decl);
 
   if (TREE_CODE (decl) == PARM_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
@@ -7895,14 +8434,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))
     {
@@ -7934,6 +8504,40 @@ add_location_or_const_value_attribute (die, decl)
     }
 }
 
+/* If we don't have a copy of this variable in memory for some reason (such
+   as a C++ member constant that doesn't have an out-of-line definition),
+   we should tell the debugger about the constant value.  */
+
+static void
+tree_add_const_value_attribute (var_die, decl)
+     dw_die_ref var_die;
+     tree decl;
+{
+  tree init = DECL_INITIAL (decl);
+  tree type = TREE_TYPE (decl);
+
+  if (TREE_READONLY (decl) && ! TREE_THIS_VOLATILE (decl) && init
+      && initializer_constant_valid_p (init, type) == null_pointer_node)
+    /* OK */;
+  else
+    return;
+
+  switch (TREE_CODE (type))
+    {
+    case INTEGER_TYPE:
+      if (host_integerp (init, 0))
+       add_AT_unsigned (var_die, DW_AT_const_value,
+                        TREE_INT_CST_LOW (init));
+      else
+       add_AT_long_long (var_die, DW_AT_const_value,
+                         TREE_INT_CST_HIGH (init),
+                         TREE_INT_CST_LOW (init));
+      break;
+
+    default:;
+    }
+}
+
 /* Generate an DW_AT_name attribute given some string value to be included as
    the value of the attribute.  */
 
@@ -8012,8 +8616,8 @@ add_bound_info (subrange_die, bound_attr, bound)
         We assume that a MEM rtx is safe because gcc wouldn't put the
         value there unless it was going to be used repeatedly in the
         function, i.e. for cleanups.  */
-      if (! optimize || (SAVE_EXPR_RTL (bound)
-                        && GET_CODE (SAVE_EXPR_RTL (bound)) == MEM))
+      if (SAVE_EXPR_RTL (bound)
+         && (! optimize || GET_CODE (SAVE_EXPR_RTL (bound)) == MEM))
        {
          register dw_die_ref ctx = lookup_decl_die (current_function_decl);
          register dw_die_ref decl_die = new_die (DW_TAG_variable, ctx);
@@ -8039,15 +8643,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;
+      }
     }
 }
 
@@ -8290,7 +8922,7 @@ add_abstract_origin_attribute (die, origin)
        fn = TYPE_STUB_DECL (fn);
       fn = decl_function_context (fn);
       if (fn)
-       gen_abstract_function (fn);
+       dwarf2out_abstract_function (fn);
     }
 
   if (DECL_P (origin))
@@ -8360,7 +8992,8 @@ add_name_and_src_coords_attributes (die, decl)
 
       if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL)
          && TREE_PUBLIC (decl)
-         && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
+         && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)
+         && !DECL_ABSTRACT (decl))
        add_AT_string (die, DW_AT_MIPS_linkage_name,
                       IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
     }
@@ -8906,24 +9539,22 @@ gen_formal_types_die (function_or_method_type, context_die)
 {
   register tree link;
   register tree formal_type = NULL;
-  register tree first_parm_type = TYPE_ARG_TYPES (function_or_method_type);
+  register tree first_parm_type;
+  tree arg;
 
-#if 0
-  /* In the case where we are generating a formal types list for a C++
-     non-static member function type, skip over the first thing on the
-     TYPE_ARG_TYPES list because it only represents the type of the hidden
-     `this pointer'.  The debugger should be able to figure out (without
-     being explicitly told) that this non-static member function type takes a
-     `this pointer' and should be able to figure what the type of that hidden
-     parameter is from the DW_AT_member attribute of the parent
-     DW_TAG_subroutine_type DIE.  */
-  if (TREE_CODE (function_or_method_type) == METHOD_TYPE)
-    first_parm_type = TREE_CHAIN (first_parm_type);
-#endif
+  if (TREE_CODE (function_or_method_type) == FUNCTION_DECL)
+    {
+      arg = DECL_ARGUMENTS (function_or_method_type);
+      function_or_method_type = TREE_TYPE (function_or_method_type);
+    }
+  else
+    arg = NULL_TREE;
+  
+  first_parm_type = TYPE_ARG_TYPES (function_or_method_type);
 
   /* Make our first pass over the list of formal parameter types and output a
      DW_TAG_formal_parameter DIE for each one.  */
-  for (link = first_parm_type; link; link = TREE_CHAIN (link))
+  for (link = first_parm_type; link; )
     {
       register dw_die_ref parm_die;
 
@@ -8933,9 +9564,14 @@ gen_formal_types_die (function_or_method_type, context_die)
 
       /* Output a (nameless) DIE to represent the formal parameter itself.  */
       parm_die = gen_formal_parameter_die (formal_type, context_die);
-      if (TREE_CODE (function_or_method_type) == METHOD_TYPE
-         && link == first_parm_type)
+      if ((TREE_CODE (function_or_method_type) == METHOD_TYPE
+          && link == first_parm_type)
+         || (arg && DECL_ARTIFICIAL (arg)))
        add_AT_flag (parm_die, DW_AT_artificial, 1);
+
+      link = TREE_CHAIN (link);
+      if (arg)
+       arg = TREE_CHAIN (arg);
     }
 
   /* If this function type has an ellipsis, add a
@@ -8992,22 +9628,40 @@ gen_type_die_for_member (type, member, context_die)
    out-of-line instances of.  */
 
 static void
-gen_abstract_function (decl)
+dwarf2out_abstract_function (decl)
      tree decl;
 {
-  register dw_die_ref old_die = lookup_decl_die (decl);
+  register dw_die_ref old_die;
   tree save_fn;
+  tree context;
+  int was_abstract = DECL_ABSTRACT (decl);
 
+  /* Make sure we have the actual abstract inline, not a clone.  */
+  decl = DECL_ORIGIN (decl);
+
+  old_die = lookup_decl_die (decl);  
   if (old_die && get_AT_unsigned (old_die, DW_AT_inline))
     /* We've already generated the abstract instance.  */
     return;
 
+  /* Be sure we've emitted the in-class declaration DIE (if any) first, so
+     we don't get confused by DECL_ABSTRACT.  */
+  if (debug_info_level > DINFO_LEVEL_TERSE)
+    {
+      context = decl_class_context (decl);
+      if (context)
+       gen_type_die_for_member
+         (context, decl, decl_function_context (decl) ? NULL : comp_unit_die);
+    }
+  /* Pretend we've just finished compiling this function.  */
   save_fn = current_function_decl;
   current_function_decl = decl;
 
   set_decl_abstract_flags (decl, 1);
   dwarf2out_decl (decl);
-  set_decl_abstract_flags (decl, 0);
+  if (! was_abstract)
+    set_decl_abstract_flags (decl, 0);
 
   current_function_decl = save_fn;
 }
@@ -9058,23 +9712,15 @@ gen_subprogram_die (decl, context_die)
       subr_die = new_die (DW_TAG_subprogram, context_die);
       add_abstract_origin_attribute (subr_die, origin);
     }
-  else if (old_die && DECL_ABSTRACT (decl)
-          && get_AT_unsigned (old_die, DW_AT_inline))
-    {
-      /* This must be a redefinition of an extern inline function.
-        We can just reuse the old die here.  */
-      subr_die = old_die;
-
-      /* Clear out the inlined attribute and parm types.  */
-      remove_AT (subr_die, DW_AT_inline);
-      remove_children (subr_die);
-    }
   else if (old_die)
     {
-      register unsigned file_index
-       = lookup_filename (DECL_SOURCE_FILE (decl));
+      unsigned file_index = lookup_filename (DECL_SOURCE_FILE (decl));
 
-      if (get_AT_flag (old_die, DW_AT_declaration) != 1)
+      if (!get_AT_flag (old_die, DW_AT_declaration)
+         /* We can have a normal definition following an inline one in the
+            case of redefinition of GNU C extern inlines.
+            It seems reasonable to use AT_specification in this case.  */
+         && !get_AT_unsigned (old_die, DW_AT_inline))
        {
          /* ??? This can happen if there is a bug in the program, for
             instance, if it has duplicate function definitions.  Ideally,
@@ -9089,12 +9735,11 @@ gen_subprogram_die (decl, context_die)
       /* If the definition comes from the same place as the declaration,
         maybe use the old DIE.  We always want the DIE for this function
         that has the *_pc attributes to be under comp_unit_die so the
-        debugger can find it.  For inlines, that is the concrete instance,
-        so we can use the old DIE here.  For non-inline methods, we want a
-        specification DIE at toplevel, so we need a new DIE.  For local
-        class methods, this doesn't apply; we just use the old DIE.  */
-      if ((DECL_ABSTRACT (decl) || old_die->die_parent == comp_unit_die
-          || context_die == NULL)
+        debugger can find it.  We also need to do this for abstract
+        instances of inlines, since the spec requires the out-of-line copy
+        to have the same parent.  For local class methods, this doesn't
+        apply; we just use the old DIE.  */
+      if ((old_die->die_parent == comp_unit_die || context_die == NULL)
          && (DECL_ARTIFICIAL (decl)
              || (get_AT_unsigned (old_die, DW_AT_decl_file) == file_index
                  && (get_AT_unsigned (old_die, DW_AT_decl_line)
@@ -9145,15 +9790,17 @@ gen_subprogram_die (decl, context_die)
 
   if (declaration)
     {
-      if (! origin)
-       add_AT_flag (subr_die, DW_AT_declaration, 1);
-
-      /* The first time we see a member function, it is in the context of
-         the class to which it belongs.  We make sure of this by emitting
-         the class first.  The next time is the definition, which is
-         handled above.  The two may come from the same source text.  */
-      if (DECL_CONTEXT (decl) || DECL_ABSTRACT (decl))
-       equate_decl_number_to_die (decl, subr_die);
+      if (!(old_die && get_AT_unsigned (old_die, DW_AT_inline)))
+       {
+         add_AT_flag (subr_die, DW_AT_declaration, 1);
+
+         /* The first time we see a member function, it is in the context of
+            the class to which it belongs.  We make sure of this by emitting
+            the class first.  The next time is the definition, which is
+            handled above.  The two may come from the same source text.  */
+         if (DECL_CONTEXT (decl) || DECL_ABSTRACT (decl))
+           equate_decl_number_to_die (decl, subr_die);
+       }
     }
   else if (DECL_ABSTRACT (decl))
     {
@@ -9176,7 +9823,7 @@ gen_subprogram_die (decl, context_die)
     }
   else if (!DECL_EXTERNAL (decl))
     {
-      if (origin == NULL_TREE)
+      if (!(old_die && get_AT_unsigned (old_die, DW_AT_inline)))
        equate_decl_number_to_die (decl, subr_die);
 
       ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
@@ -9226,7 +9873,7 @@ gen_subprogram_die (decl, context_die)
   if (debug_info_level <= DINFO_LEVEL_TERSE)
     ;
   else if (declaration)
-    gen_formal_types_die (TREE_TYPE (decl), subr_die);
+    gen_formal_types_die (decl, subr_die);
   else
     {
       /* Generate DIEs to represent all known formal parameters */
@@ -9328,8 +9975,7 @@ gen_variable_die (decl, context_die)
       add_AT_die_ref (var_die, DW_AT_specification, old_die);
       if (DECL_NAME (decl))
        {
-         register unsigned file_index
-           = lookup_filename (DECL_SOURCE_FILE (decl));
+         unsigned file_index = lookup_filename (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);
@@ -9372,6 +10018,8 @@ gen_variable_die (decl, context_die)
       add_location_or_const_value_attribute (var_die, decl);
       add_pubname (decl, var_die);
     }
+  else
+    tree_add_const_value_attribute (var_die, decl);
 }
 
 /* Generate a DIE to represent a label identifier.  */
@@ -9385,7 +10033,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);
@@ -9413,9 +10060,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);
        }
     }
@@ -9461,7 +10106,7 @@ gen_inlined_subroutine_die (stmt, context_die, depth)
       char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
       /* Emit info for the abstract instance first, if we haven't yet.  */
-      gen_abstract_function (decl);
+      dwarf2out_abstract_function (decl);
 
       add_abstract_origin_attribute (subr_die, decl);
       ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
@@ -9704,6 +10349,10 @@ gen_member_die (type, context_die)
   /* Now output info about the function members (if any).  */
   for (member = TYPE_METHODS (type); member; member = TREE_CHAIN (member))
     {
+      /* Don't include clones in the member list.  */
+      if (DECL_ABSTRACT_ORIGIN (member))
+       continue;
+
       child = lookup_decl_die (member);
       if (child)
        splice_child_die (context_die, child);
@@ -10232,20 +10881,23 @@ gen_decl_die (decl, context_die)
          && (current_function_decl == NULL_TREE || DECL_ARTIFICIAL (decl)))
        break;
 
+      /* If we're emitting a clone, emit info for the abstract instance.  */
+      if (DECL_ORIGIN (decl) != decl)
+       dwarf2out_abstract_function (DECL_ABSTRACT_ORIGIN (decl));
       /* If we're emitting an out-of-line copy of an inline function,
         emit info for the abstract instance and set up to refer to it.  */
-      if (DECL_INLINE (decl) && ! DECL_ABSTRACT (decl)
-         && ! class_scope_p (context_die)
-         /* gen_abstract_function won't emit a die if this is just a
-            declaration.  We must avoid setting DECL_ABSTRACT_ORIGIN in
-            that case, because that works only if we have a die.  */
-         && DECL_INITIAL (decl) != NULL_TREE)
+      else if (DECL_INLINE (decl) && ! DECL_ABSTRACT (decl)
+              && ! class_scope_p (context_die)
+              /* dwarf2out_abstract_function won't emit a die if this is just
+                 a declaration.  We must avoid setting DECL_ABSTRACT_ORIGIN in
+                 that case, because that works only if we have a die.  */
+              && DECL_INITIAL (decl) != NULL_TREE)
        {
-         gen_abstract_function (decl);
+         dwarf2out_abstract_function (decl);
          set_decl_origin_self (decl);
        }
-
-      if (debug_info_level > DINFO_LEVEL_TERSE)
+      /* Otherwise we're emitting the primary DIE for this decl.  */
+      else if (debug_info_level > DINFO_LEVEL_TERSE)
        {
          /* Before we describe the FUNCTION_DECL itself, make sure that we
             have described its return type.  */
@@ -10371,6 +11023,21 @@ dwarf2out_add_library_unit_info (filename, context_list)
     }
 }
 
+/* Debug information for a global DECL.  Called from toplev.c after
+   compilation proper has finished.  */
+static void
+dwarf2out_global_decl (decl)
+     tree decl;
+{
+  /* Output DWARF2 information for file-scope tentative data object
+     declarations, file-scope (extern) function declarations (which
+     had no corresponding body) and file-scope tagged type
+     declarations and definitions which have not yet been forced out.  */
+
+  if (TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))
+    dwarf2out_decl (decl);
+}
+
 /* Write the debugging output for DECL.  */
 
 void
@@ -10489,23 +11156,25 @@ dwarf2out_decl (decl)
 /* Output a marker (i.e. a label) for the beginning of the generated code for
    a lexical block.  */
 
-void
-dwarf2out_begin_block (blocknum)
-     register unsigned blocknum;
+static void
+dwarf2out_begin_block (line, blocknum)
+     unsigned int line ATTRIBUTE_UNUSED;
+     unsigned int 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
    lexical block.  */
 
-void
-dwarf2out_end_block (blocknum)
-     register unsigned blocknum;
+static void
+dwarf2out_end_block (line, blocknum)
+     unsigned int line ATTRIBUTE_UNUSED;
+     unsigned int 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
@@ -10515,7 +11184,7 @@ dwarf2out_end_block (blocknum)
    as we would end up with orphans, and in the presence of scheduling
    we may end up calling them anyway.  */
 
-int
+static bool
 dwarf2out_ignore_block (block)
      tree block;
 {
@@ -10527,24 +11196,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.
@@ -10560,68 +11211,83 @@ static unsigned
 lookup_filename (file_name)
      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;
+  /* ??? Why isn't DECL_SOURCE_FILE left null instead.  */
+  if (strcmp (file_name, "<internal>") == 0
+      || strcmp (file_name, "<built-in>") == 0)
+    return 0;
+
+  /* Check to see if the file name that was searched on the previous
+     call matches this file name.  If so, return the index.  */
+  if (file_table.last_lookup_index != 0)
+    if (strcmp (file_name, file_table.table[file_table.last_lookup_index]) == 0)
+      return file_table.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 < file_table.in_use; ++i)
+    if (strcmp (file_name, file_table.table[i]) == 0)
       {
-       last_file_lookup_index = i;
+       file_table.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 == file_table.allocated)
     {
-      file_table_allocated += FILE_TABLE_INCREMENT;
-      file_table
-       = (char **) xrealloc (file_table,
-                             file_table_allocated * sizeof (char *));
+      file_table.allocated = i + FILE_TABLE_INCREMENT;
+      file_table.table = (char **)
+       xrealloc (file_table.table, file_table.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++;
+  file_table.table[i] = xstrdup (file_name);
+  file_table.in_use = i + 1;
+  file_table.last_lookup_index = i;
 
-  return last_file_lookup_index;
+  if (DWARF2_ASM_LINE_DEBUG_INFO)
+    fprintf (asm_out_file, "\t.file %u \"%s\"\n", i, file_name);
+
+  return i;
+}
+
+static void
+init_file_table ()
+{
+  /* Allocate the initial hunk of the file_table.  */
+  file_table.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;
+  file_table.last_lookup_index = 0;
 }
 
 /* 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.  */
 
-void
-dwarf2out_line (filename, line)
+static void
+dwarf2out_source_line (line, filename)
+     unsigned int line;
      register const char *filename;
-     register unsigned line;
 {
   if (debug_info_level >= DINFO_LEVEL_NORMAL)
     {
       function_section (current_function_decl);
 
+      /* If requested, emit something human-readable.  */
+      if (flag_debug_asm)
+       fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START,
+                filename, line);
+
       if (DWARF2_ASM_LINE_DEBUG_INFO)
        {
-         static const char *lastfile;
-
-         /* Emit the .file and .loc directives understood by GNU as.  */
-         if (lastfile == 0 || strcmp (filename, lastfile))
-           {
-             if (lastfile == 0)
-               ggc_add_string_root ((char **) &lastfile, 1);
-
-             fprintf (asm_out_file, "\t.file 0 \"%s\"\n", filename);
-             lastfile = filename;
-           }
+         unsigned file_num = lookup_filename (filename);
 
-         fprintf (asm_out_file, "\t.loc 0 %d 0\n", line);
+         /* Emit the .loc directive understood by GNU as.  */
+         fprintf (asm_out_file, "\t.loc %d %d 0\n", file_num, line);
 
          /* Indicate that line number info exists.  */
          ++line_info_table_in_use;
@@ -10635,9 +11301,6 @@ dwarf2out_line (filename, line)
          register dw_separate_line_info_ref line_info;
          ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, SEPARATE_LINE_CODE_LABEL,
                                     separate_line_info_table_in_use);
-         if (flag_debug_asm)
-           fprintf (asm_out_file, "\t%s line %d", ASM_COMMENT_START, line);
-         fputc ('\n', asm_out_file);
 
          /* expand the line info table if necessary */
          if (separate_line_info_table_in_use
@@ -10664,9 +11327,6 @@ dwarf2out_line (filename, line)
 
          ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, LINE_CODE_LABEL,
                                     line_info_table_in_use);
-         if (flag_debug_asm)
-           fprintf (asm_out_file, "\t%s line %d", ASM_COMMENT_START, line);
-         fputc ('\n', asm_out_file);
 
          /* Expand the line info table if necessary.  */
          if (line_info_table_in_use == line_info_table_allocated)
@@ -10687,12 +11347,12 @@ dwarf2out_line (filename, line)
     }
 }
 
-/* Record the beginning of a new source file, for later output
-   of the .debug_macinfo section.  At present, unimplemented.  */
+/* Record the beginning of a new source file. */
 
-void
-dwarf2out_start_source_file (filename)
-     register const char *filename ATTRIBUTE_UNUSED;
+static void
+dwarf2out_start_source_file (lineno, filename)
+     register unsigned int lineno;
+     register const char *filename;
 {
   if (flag_eliminate_dwarf2_dups)
     {
@@ -10700,26 +11360,38 @@ dwarf2out_start_source_file (filename)
       dw_die_ref bincl_die = new_die (DW_TAG_GNU_BINCL, comp_unit_die);
       add_AT_string (bincl_die, DW_AT_name, filename);
     }
+  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+    {
+      ASM_OUTPUT_SECTION (asm_out_file, DEBUG_MACINFO_SECTION);
+      dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
+      dw2_asm_output_data_uleb128 (lineno, "Included from line number %d", lineno);
+      dw2_asm_output_data_uleb128 (lookup_filename (filename), "Filename we just started");
+    }
 }
 
-/* Record the end of a source file, for later output
-   of the .debug_macinfo section.  At present, unimplemented.  */
+/* Record the end of a source file.  */
 
-void
-dwarf2out_end_source_file ()
+static void
+dwarf2out_end_source_file (lineno)
+     unsigned int lineno ATTRIBUTE_UNUSED;
 {
   if (flag_eliminate_dwarf2_dups)
     {
       /* Record the end of the file for break_out_includes.  */
       new_die (DW_TAG_GNU_EINCL, comp_unit_die);
-    }      
+    }
+  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+    {
+      ASM_OUTPUT_SECTION (asm_out_file, DEBUG_MACINFO_SECTION);
+      dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
+    }
 }
 
-/* Called from check_newline in c-parse.y.  The `buffer' parameter contains
+/* Called from debug_define in toplev.c.  The `buffer' parameter contains
    the tail part of the directive line, i.e. the part which is past the
    initial whitespace, #, whitespace, directive-name, whitespace part.  */
 
-void
+static void
 dwarf2out_define (lineno, buffer)
      register unsigned lineno ATTRIBUTE_UNUSED;
      register const char *buffer ATTRIBUTE_UNUSED;
@@ -10727,38 +11399,51 @@ dwarf2out_define (lineno, buffer)
   static int initialized = 0;
   if (!initialized)
     {
-      dwarf2out_start_source_file (primary_filename);
+      dwarf2out_start_source_file (0, primary_filename);
       initialized = 1;
     }
+  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+    {
+      ASM_OUTPUT_SECTION (asm_out_file, DEBUG_MACINFO_SECTION);
+      dw2_asm_output_data (1, DW_MACINFO_define, "Define macro");
+      dw2_asm_output_data_uleb128 (lineno, "At line number %d", lineno);
+      dw2_asm_output_nstring (buffer, -1, "The macro");
+    }
 }
 
-/* Called from check_newline in c-parse.y.  The `buffer' parameter contains
+/* Called from debug_undef in toplev.c.  The `buffer' parameter contains
    the tail part of the directive line, i.e. the part which is past the
    initial whitespace, #, whitespace, directive-name, whitespace part.  */
 
-void
+static void
 dwarf2out_undef (lineno, buffer)
      register unsigned lineno ATTRIBUTE_UNUSED;
      register const char *buffer ATTRIBUTE_UNUSED;
 {
+  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+    {
+      ASM_OUTPUT_SECTION (asm_out_file, DEBUG_MACINFO_SECTION);
+      dw2_asm_output_data (1, DW_MACINFO_undef, "Undefine macro");
+      dw2_asm_output_data_uleb128 (lineno, "At line number %d", lineno);
+      dw2_asm_output_nstring (buffer, -1, "The macro");
+    }
 }
 
 /* Set up for Dwarf output at the start of compilation.  */
 
-void
-dwarf2out_init (asm_out_file, main_input_filename)
-     register FILE *asm_out_file;
+static void
+dwarf2out_init (main_input_filename)
      register const char *main_input_filename;
 {
+  init_file_table ();
+
   /* 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;
+  /* Add it to the file table first, under the assumption that we'll
+     be emitting line number data for it first, which avoids having
+     to add an initial DW_LNS_set_file.  */
+  lookup_filename (main_input_filename);
 
   /* Allocate the initial hunk of the decl_die_table.  */
   decl_die_table
@@ -10795,14 +11480,12 @@ 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);
+  ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
+                              DEBUG_ABBREV_SECTION_LABEL, 0);
   if (DWARF2_GENERATE_TEXT_SECTION_LABEL)
     ASM_GENERATE_INTERNAL_LABEL (text_section_label, TEXT_SECTION_LABEL, 0);
   else
@@ -10811,8 +11494,10 @@ dwarf2out_init (asm_out_file, main_input_filename)
                               DEBUG_INFO_SECTION_LABEL, 0);
   ASM_GENERATE_INTERNAL_LABEL (debug_line_section_label,
                               DEBUG_LINE_SECTION_LABEL, 0);
-
-  ASM_OUTPUT_SECTION (asm_out_file, ABBREV_SECTION);
+  ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL, 0);
+  ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LOC_SECTION);
+  ASM_OUTPUT_LABEL (asm_out_file, loc_section_label);
+  ASM_OUTPUT_SECTION (asm_out_file, DEBUG_ABBREV_SECTION);
   ASM_OUTPUT_LABEL (asm_out_file, abbrev_section_label);
   if (DWARF2_GENERATE_TEXT_SECTION_LABEL)
     {
@@ -10823,16 +11508,24 @@ dwarf2out_init (asm_out_file, main_input_filename)
   ASM_OUTPUT_LABEL (asm_out_file, debug_info_section_label);
   ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LINE_SECTION);
   ASM_OUTPUT_LABEL (asm_out_file, debug_line_section_label);
+  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+    {
+      ASM_OUTPUT_SECTION (asm_out_file, DEBUG_MACINFO_SECTION);
+      ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
+                                  DEBUG_MACINFO_SECTION_LABEL, 0);
+      ASM_OUTPUT_LABEL (asm_out_file, macinfo_section_label);
+    }
 }
 
 /* Output stuff that dwarf requires at the end of every file,
    and generate the DWARF-2 debugging info.  */
 
-void
-dwarf2out_finish ()
+static void
+dwarf2out_finish (input_filename)
+     register const char *input_filename ATTRIBUTE_UNUSED;
 {
   limbo_die_node *node, *next_node;
-  dw_die_ref die;
+  dw_die_ref die = 0;
 
   /* Traverse the limbo die list, and add parent/child links.  The only
      dies without parents that should be here are concrete instances of
@@ -10878,48 +11571,44 @@ dwarf2out_finish ()
     add_sibling_attributes (node->die);
 
   /* Output a terminator label for the .text section.  */
-  fputc ('\n', asm_out_file);
   ASM_OUTPUT_SECTION (asm_out_file, TEXT_SECTION);
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, TEXT_END_LABEL, 0);
 
 #if 0
   /* Output a terminator label for the .data section.  */
-  fputc ('\n', asm_out_file);
   ASM_OUTPUT_SECTION (asm_out_file, DATA_SECTION);
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, DATA_END_LABEL, 0);
 
   /* Output a terminator label for the .bss section.  */
-  fputc ('\n', asm_out_file);
   ASM_OUTPUT_SECTION (asm_out_file, BSS_SECTION);
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BSS_END_LABEL, 0);
 #endif
 
-  /* Output the source line correspondence table.  */
-  if (line_info_table_in_use > 1 || separate_line_info_table_in_use)
+  /* Output the source line correspondence table.  We must do this
+     even if there is no line information.  Otherwise, on an empty
+     translation unit, we will generate a present, but empty,
+     .debug_info section.  IRIX 6.5 `nm' will then complain when
+     examining the file.  */
+  if (! DWARF2_ASM_LINE_DEBUG_INFO)
     {
-      if (! DWARF2_ASM_LINE_DEBUG_INFO)
-       {
-         fputc ('\n', asm_out_file);
-         ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LINE_SECTION);
-         output_line_info ();
-       }
-
-      /* We can only use the low/high_pc attributes if all of the code
-        was in .text.  */
-      if (separate_line_info_table_in_use == 0)
-       {
-         add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, text_section_label);
-         add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label);
-       }
+      ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LINE_SECTION);
+      output_line_info ();
+    }
 
-      add_AT_lbl_offset (comp_unit_die, DW_AT_stmt_list,
-                        debug_line_section_label);
+  /* We can only use the low/high_pc attributes if all of the code was
+     in .text.  */
+  if (separate_line_info_table_in_use == 0)
+    {
+      add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, text_section_label);
+      add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label);
     }
 
-#if 0 /* unimplemented */
-  if (debug_info_level >= DINFO_LEVEL_VERBOSE && primary)
-    add_AT_unsigned (die, DW_AT_macro_info, 0);
-#endif
+  if (debug_info_level >= DINFO_LEVEL_NORMAL)
+    add_AT_lbl_offset (comp_unit_die, DW_AT_stmt_list,
+                      debug_line_section_label);
+
+  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+    add_AT_lbl_offset (comp_unit_die, DW_AT_macro_info, macinfo_section_label);
 
   /* Output all of the compilation units.  We put the main one last so that
      the offsets are available to output_pubnames.  */
@@ -10928,15 +11617,13 @@ dwarf2out_finish ()
   output_comp_unit (comp_unit_die);
 
   /* Output the abbreviation table.  */
-  fputc ('\n', asm_out_file);
-  ASM_OUTPUT_SECTION (asm_out_file, ABBREV_SECTION);
+  ASM_OUTPUT_SECTION (asm_out_file, DEBUG_ABBREV_SECTION);
   output_abbrev_section ();
 
   if (pubname_table_in_use)
     {
       /* Output public names table.  */
-      fputc ('\n', asm_out_file);
-      ASM_OUTPUT_SECTION (asm_out_file, PUBNAMES_SECTION);
+      ASM_OUTPUT_SECTION (asm_out_file, DEBUG_PUBNAMES_SECTION);
       output_pubnames ();
     }
 
@@ -10945,9 +11632,24 @@ dwarf2out_finish ()
   if (fde_table_in_use)
     {
       /* Output the address range information.  */
-      fputc ('\n', asm_out_file);
-      ASM_OUTPUT_SECTION (asm_out_file, ARANGES_SECTION);
+      ASM_OUTPUT_SECTION (asm_out_file, DEBUG_ARANGES_SECTION);
       output_aranges ();
     }
+  /* Output location list section if necessary */
+  if (have_location_lists)
+    {
+      /* Output the location lists info. */
+      ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LOC_SECTION);
+      output_location_lists (die);
+      have_location_lists = 0;
+    }
+
+  /* Have to end the primary source file. */
+  if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+    { 
+      ASM_OUTPUT_SECTION (asm_out_file, DEBUG_MACINFO_SECTION);
+      dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
+    }
+  
 }
 #endif /* DWARF2_DEBUGGING_INFO */