]> oss.titaniummirror.com Git - msp430-gcc.git/blobdiff - gcc/final.c
Imported gcc-4.4.3
[msp430-gcc.git] / gcc / final.c
index d86ed5e7c71a977ed900f46aac74a5ea1f0dbb90..1735a73207dcb53241a1fe96c4adfb181dd230f8 100644 (file)
@@ -1,12 +1,13 @@
 /* Convert RTL to assembler code and output it, for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
 /* Convert RTL to assembler code and output it, for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* This is the final pass of the compiler.
    It looks at the rtl code for a function and outputs assembler code.
 
 /* This is the final pass of the compiler.
    It looks at the rtl code for a function and outputs assembler code.
@@ -46,6 +46,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 
 #include "tree.h"
 #include "rtl.h"
 
 #include "tree.h"
 #include "rtl.h"
@@ -68,6 +70,16 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "target.h"
 #include "debug.h"
 #include "expr.h"
 #include "target.h"
 #include "debug.h"
 #include "expr.h"
+#include "cfglayout.h"
+#include "tree-pass.h"
+#include "timevar.h"
+#include "cgraph.h"
+#include "coverage.h"
+#include "df.h"
+#include "vecprim.h"
+#include "ggc.h"
+#include "cfgloop.h"
+#include "params.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
@@ -78,6 +90,14 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "dwarf2out.h"
 #endif
 
 #include "dwarf2out.h"
 #endif
 
+#ifdef DBX_DEBUGGING_INFO
+#include "dbxout.h"
+#endif
+
+#ifdef SDB_DEBUGGING_INFO
+#include "sdbout.h"
+#endif
+
 /* If we aren't using cc0, CC_STATUS_INIT shouldn't exist.  So define a
    null default for it to save conditionalization later.  */
 #ifndef CC_STATUS_INIT
 /* If we aren't using cc0, CC_STATUS_INIT shouldn't exist.  So define a
    null default for it to save conditionalization later.  */
 #ifndef CC_STATUS_INIT
@@ -91,13 +111,18 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 /* Is the given character a logical line separator for the assembler?  */
 #ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
 
 /* Is the given character a logical line separator for the assembler?  */
 #ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
-#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';')
+#define IS_ASM_LOGICAL_LINE_SEPARATOR(C, STR) ((C) == ';')
 #endif
 
 #ifndef JUMP_TABLES_IN_TEXT_SECTION
 #define JUMP_TABLES_IN_TEXT_SECTION 0
 #endif
 
 #endif
 
 #ifndef JUMP_TABLES_IN_TEXT_SECTION
 #define JUMP_TABLES_IN_TEXT_SECTION 0
 #endif
 
+/* Bitflags used by final_scan_insn.  */
+#define SEEN_BB                1
+#define SEEN_NOTE      2
+#define SEEN_EMITTED   4
+
 /* Last insn processed by final_scan_insn.  */
 static rtx debug_insn;
 rtx current_output_insn;
 /* Last insn processed by final_scan_insn.  */
 static rtx debug_insn;
 rtx current_output_insn;
@@ -114,15 +139,19 @@ static int high_function_linenum;
 /* Filename of last NOTE.  */
 static const char *last_filename;
 
 /* Filename of last NOTE.  */
 static const char *last_filename;
 
-/* Number of instrumented arcs when profile_arc_flag is set.  */
-extern int count_instrumented_edges;
+/* Override filename and line number.  */
+static const char *override_filename;
+static int override_linenum;
 
 
-extern int length_unit_log; /* This is defined in insn-attrtab.c.  */
+/* Whether to force emission of a line note before the next insn.  */
+static bool force_source_line = false;
+
+extern const int length_unit_log; /* This is defined in insn-attrtab.c.  */
 
 /* Nonzero while outputting an `asm' with operands.
 
 /* Nonzero while outputting an `asm' with operands.
-   This means that inconsistencies are the user's fault, so don't abort.
+   This means that inconsistencies are the user's fault, so don't die.
    The precise value is the insn being output, to pass to error_for_asm.  */
    The precise value is the insn being output, to pass to error_for_asm.  */
-static rtx this_is_asm_operands;
+rtx this_is_asm_operands;
 
 /* Number of operands of this insn, for an `asm' with operands.  */
 static unsigned int insn_noperands;
 
 /* Number of operands of this insn, for an `asm' with operands.  */
 static unsigned int insn_noperands;
@@ -131,10 +160,6 @@ static unsigned int insn_noperands;
 
 static rtx last_ignored_compare = 0;
 
 
 static rtx last_ignored_compare = 0;
 
-/* Flag indicating this insn is the start of a new basic block.  */
-
-static int new_block = 1;
-
 /* Assign a unique number to each insn that is output.
    This can be used to generate unique local labels.  */
 
 /* Assign a unique number to each insn that is output.
    This can be used to generate unique local labels.  */
 
@@ -153,23 +178,6 @@ CC_STATUS cc_status;
 CC_STATUS cc_prev_status;
 #endif
 
 CC_STATUS cc_prev_status;
 #endif
 
-/* Indexed by hardware reg number, is 1 if that register is ever
-   used in the current function.
-
-   In life_analysis, or in stupid_life_analysis, this is set
-   up to record the hard regs used explicitly.  Reload adds
-   in the hard regs used for holding pseudo regs.  Final uses
-   it to generate the code in the function prologue and epilogue
-   to save and restore registers as needed.  */
-
-char regs_ever_live[FIRST_PSEUDO_REGISTER];
-
-/* Nonzero means current function must be given a frame pointer.
-   Set in stmt.c if anything is allocated on the stack there.
-   Set in reload1.c if anything is allocated on the stack there.  */
-
-int frame_pointer_needed;
-
 /* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen.  */
 
 static int block_depth;
 /* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen.  */
 
 static int block_depth;
@@ -189,44 +197,40 @@ rtx final_sequence;
 static int dialect_number;
 #endif
 
 static int dialect_number;
 #endif
 
-/* Indexed by line number, nonzero if there is a note for that line.  */
-
-static char *line_note_exists;
-
 #ifdef HAVE_conditional_execution
 /* Nonnull if the insn currently being emitted was a COND_EXEC pattern.  */
 rtx current_insn_predicate;
 #endif
 
 #ifdef HAVE_ATTR_length
 #ifdef HAVE_conditional_execution
 /* Nonnull if the insn currently being emitted was a COND_EXEC pattern.  */
 rtx current_insn_predicate;
 #endif
 
 #ifdef HAVE_ATTR_length
-static int asm_insn_count      PARAMS ((rtx));
-#endif
-static void profile_function   PARAMS ((FILE *));
-static void profile_after_prologue PARAMS ((FILE *));
-static void notice_source_line PARAMS ((rtx));
-static rtx walk_alter_subreg   PARAMS ((rtx *));
-static void output_asm_name    PARAMS ((void));
-static tree get_mem_expr_from_op       PARAMS ((rtx, int *));
-static void output_asm_operand_names PARAMS ((rtx *, int *, int));
-static void output_operand     PARAMS ((rtx, int));
+static int asm_insn_count (rtx);
+#endif
+static void profile_function (FILE *);
+static void profile_after_prologue (FILE *);
+static bool notice_source_line (rtx);
+static rtx walk_alter_subreg (rtx *, bool *);
+static void output_asm_name (void);
+static void output_alternate_entry_point (FILE *, rtx);
+static tree get_mem_expr_from_op (rtx, int *);
+static void output_asm_operand_names (rtx *, int *, int);
+static void output_operand (rtx, int);
 #ifdef LEAF_REGISTERS
 #ifdef LEAF_REGISTERS
-static void leaf_renumber_regs PARAMS ((rtx));
+static void leaf_renumber_regs (rtx);
 #endif
 #ifdef HAVE_cc0
 #endif
 #ifdef HAVE_cc0
-static int alter_cond          PARAMS ((rtx));
+static int alter_cond (rtx);
 #endif
 #ifndef ADDR_VEC_ALIGN
 #endif
 #ifndef ADDR_VEC_ALIGN
-static int final_addr_vec_align PARAMS ((rtx));
+static int final_addr_vec_align (rtx);
 #endif
 #ifdef HAVE_ATTR_length
 #endif
 #ifdef HAVE_ATTR_length
-static int align_fuzz          PARAMS ((rtx, rtx, int, unsigned));
+static int align_fuzz (rtx, rtx, int, unsigned);
 #endif
 \f
 /* Initialize data in final at the beginning of a compilation.  */
 
 void
 #endif
 \f
 /* Initialize data in final at the beginning of a compilation.  */
 
 void
-init_final (filename)
-     const char *filename ATTRIBUTE_UNUSED;
+init_final (const char *filename ATTRIBUTE_UNUSED)
 {
   app_on = 0;
   final_sequence = 0;
 {
   app_on = 0;
   final_sequence = 0;
@@ -236,156 +240,19 @@ init_final (filename)
 #endif
 }
 
 #endif
 }
 
-/* Called at end of source file,
-   to output the block-profiling table for this entire compilation.  */
-
-void
-end_final (filename)
-     const char *filename;
-{
-  if (profile_arc_flag)
-    {
-      char name[20];
-      int align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
-      int size, rounded;
-      int long_bytes = LONG_TYPE_SIZE / BITS_PER_UNIT;
-      int gcov_type_bytes = GCOV_TYPE_SIZE / BITS_PER_UNIT;
-      int pointer_bytes = POINTER_SIZE / BITS_PER_UNIT;
-      unsigned int align2 = LONG_TYPE_SIZE;
-
-      size = gcov_type_bytes * count_instrumented_edges;
-      rounded = size;
-
-      rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
-      rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
-                * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
-
-      /* ??? This _really_ ought to be done with a structure layout
-        and with assemble_constructor.  If long_bytes != pointer_bytes
-        we'll be emitting unaligned data at some point.  */
-      if (long_bytes != pointer_bytes)
-       abort ();
-
-      data_section ();
-
-      /* Output the main header, of 11 words:
-        0:  1 if this file is initialized, else 0.
-        1:  address of file name (LPBX1).
-        2:  address of table of counts (LPBX2).
-        3:  number of counts in the table.
-        4:  always 0, for compatibility with Sun.
-
-         The following are GNU extensions:
-
-        5:  address of table of start addrs of basic blocks (LPBX3).
-        6:  Number of bytes in this header.
-        7:  address of table of function names (LPBX4).
-        8:  address of table of line numbers (LPBX5) or 0.
-        9:  address of table of file names (LPBX6) or 0.
-       10:  space reserved for basic block profiling.  */
-
-      ASM_OUTPUT_ALIGN (asm_out_file, align);
-
-      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0);
-
-      /* Zero word.  */
-      assemble_integer (const0_rtx, long_bytes, align2, 1);
-
-      /* Address of filename.  */
-      ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1);
-      assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
-                       align2, 1);
-
-      /* Address of count table.  */
-      ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
-      assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
-                       align2, 1);
-
-      /* Count of the # of instrumented arcs.  */
-      assemble_integer (GEN_INT (count_instrumented_edges),
-                       long_bytes, align2, 1);
-
-      /* Zero word (link field).  */
-      assemble_integer (const0_rtx, pointer_bytes, align2, 1);
-
-      assemble_integer (const0_rtx, pointer_bytes, align2, 1);
-
-      /* Byte count for extended structure.  */
-      assemble_integer (GEN_INT (11 * UNITS_PER_WORD), long_bytes, align2, 1);
-
-      /* Address of function name table.  */
-      assemble_integer (const0_rtx, pointer_bytes, align2, 1);
-
-      /* Address of line number and filename tables if debugging.  */
-      assemble_integer (const0_rtx, pointer_bytes, align2, 1);
-      assemble_integer (const0_rtx, pointer_bytes, align2, 1);
-
-      /* Space for extension ptr (link field).  */
-      assemble_integer (const0_rtx, UNITS_PER_WORD, align2, 1);
-
-      /* Output the file name changing the suffix to .d for
-        Sun tcov compatibility.  */
-      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1);
-      {
-       char *cwd = getpwd ();
-       int len = strlen (filename) + strlen (cwd) + 1;
-       char *data_file = (char *) alloca (len + 4);
-
-       strcpy (data_file, cwd);
-       strcat (data_file, "/");
-       strcat (data_file, filename);
-       strip_off_ending (data_file, len);
-       strcat (data_file, ".da");
-       assemble_string (data_file, strlen (data_file) + 1);
-      }
-
-      /* Make space for the table of counts.  */
-      if (size == 0)
-       {
-         /* Realign data section.  */
-         ASM_OUTPUT_ALIGN (asm_out_file, align);
-         ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 2);
-         if (size != 0)
-           assemble_zeros (size);
-       }
-      else
-       {
-         ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
-#ifdef ASM_OUTPUT_SHARED_LOCAL
-         if (flag_shared_data)
-           ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
-         else
-#endif
-#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
-           ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name,
-                                          size, BIGGEST_ALIGNMENT);
-#else
-#ifdef ASM_OUTPUT_ALIGNED_LOCAL
-           ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
-                                     BIGGEST_ALIGNMENT);
-#else
-           ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
-#endif
-#endif
-       }
-    }
-}
-
 /* Default target function prologue and epilogue assembler output.
 
    If not overridden for epilogue code, then the function body itself
    contains return instructions wherever needed.  */
 void
 /* Default target function prologue and epilogue assembler output.
 
    If not overridden for epilogue code, then the function body itself
    contains return instructions wherever needed.  */
 void
-default_function_pro_epilogue (file, size)
-     FILE *file ATTRIBUTE_UNUSED;
-     HOST_WIDE_INT size ATTRIBUTE_UNUSED;
+default_function_pro_epilogue (FILE *file ATTRIBUTE_UNUSED,
+                              HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
 }
 
 /* Default target hook that outputs nothing to a stream.  */
 void
 {
 }
 
 /* Default target hook that outputs nothing to a stream.  */
 void
-no_asm_to_stream (file)
-     FILE *file ATTRIBUTE_UNUSED;
+no_asm_to_stream (FILE *file ATTRIBUTE_UNUSED)
 {
 }
 
 {
 }
 
@@ -393,7 +260,7 @@ no_asm_to_stream (file)
    Used before the output from an `asm' statement.  */
 
 void
    Used before the output from an `asm' statement.  */
 
 void
-app_enable ()
+app_enable (void)
 {
   if (! app_on)
     {
 {
   if (! app_on)
     {
@@ -406,7 +273,7 @@ app_enable ()
    Called from varasm.c before most kinds of output.  */
 
 void
    Called from varasm.c before most kinds of output.  */
 
 void
-app_disable ()
+app_disable (void)
 {
   if (app_on)
     {
 {
   if (app_on)
     {
@@ -421,7 +288,7 @@ app_disable ()
 
 #ifdef DELAY_SLOTS
 int
 
 #ifdef DELAY_SLOTS
 int
-dbr_sequence_length ()
+dbr_sequence_length (void)
 {
   if (final_sequence != 0)
     return XVECLEN (final_sequence, 0) - 1;
 {
   if (final_sequence != 0)
     return XVECLEN (final_sequence, 0) - 1;
@@ -438,9 +305,7 @@ dbr_sequence_length ()
 
 static int *insn_lengths;
 
 
 static int *insn_lengths;
 
-#ifdef HAVE_ATTR_length
-varray_type insn_addresses_;
-#endif
+VEC(int,heap) *insn_addresses_;
 
 /* Max uid for which the above arrays are valid.  */
 static int insn_lengths_max_uid;
 
 /* Max uid for which the above arrays are valid.  */
 static int insn_lengths_max_uid;
@@ -476,7 +341,7 @@ static struct label_alignment *label_align;
 /* Indicate that branch shortening hasn't yet been done.  */
 
 void
 /* Indicate that branch shortening hasn't yet been done.  */
 
 void
-init_insn_lengths ()
+init_insn_lengths (void)
 {
   if (uid_shuid)
     {
 {
   if (uid_shuid)
     {
@@ -500,11 +365,11 @@ init_insn_lengths ()
 }
 
 /* Obtain the current length of an insn.  If branch shortening has been done,
 }
 
 /* Obtain the current length of an insn.  If branch shortening has been done,
-   get its actual length.  Otherwise, get its maximum length.  */
-
-int
-get_attr_length (insn)
-     rtx insn ATTRIBUTE_UNUSED;
+   get its actual length.  Otherwise, use FALLBACK_FN to calculate the
+   length.  */
+static inline int
+get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED,
+                  int (*fallback_fn) (rtx) ATTRIBUTE_UNUSED)
 {
 #ifdef HAVE_ATTR_length
   rtx body;
 {
 #ifdef HAVE_ATTR_length
   rtx body;
@@ -522,18 +387,18 @@ get_attr_length (insn)
        return 0;
 
       case CALL_INSN:
        return 0;
 
       case CALL_INSN:
-       length = insn_default_length (insn);
+       length = fallback_fn (insn);
        break;
 
       case JUMP_INSN:
        body = PATTERN (insn);
        break;
 
       case JUMP_INSN:
        body = PATTERN (insn);
-        if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
+       if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
          {
            /* Alignment is machine-dependent and should be handled by
               ADDR_VEC_ALIGN.  */
          }
        else
          {
            /* Alignment is machine-dependent and should be handled by
               ADDR_VEC_ALIGN.  */
          }
        else
-         length = insn_default_length (insn);
+         length = fallback_fn (insn);
        break;
 
       case INSN:
        break;
 
       case INSN:
@@ -542,12 +407,12 @@ get_attr_length (insn)
          return 0;
 
        else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
          return 0;
 
        else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
-         length = asm_insn_count (body) * insn_default_length (insn);
+         length = asm_insn_count (body) * fallback_fn (insn);
        else if (GET_CODE (body) == SEQUENCE)
          for (i = 0; i < XVECLEN (body, 0); i++)
        else if (GET_CODE (body) == SEQUENCE)
          for (i = 0; i < XVECLEN (body, 0); i++)
-           length += get_attr_length (XVECEXP (body, 0, i));
+           length += get_attr_length_1 (XVECEXP (body, 0, i), fallback_fn);
        else
        else
-         length = insn_default_length (insn);
+         length = fallback_fn (insn);
        break;
 
       default:
        break;
 
       default:
@@ -560,8 +425,26 @@ get_attr_length (insn)
   return length;
 #else /* not HAVE_ATTR_length */
   return 0;
   return length;
 #else /* not HAVE_ATTR_length */
   return 0;
+#define insn_default_length 0
+#define insn_min_length 0
 #endif /* not HAVE_ATTR_length */
 }
 #endif /* not HAVE_ATTR_length */
 }
+
+/* Obtain the current length of an insn.  If branch shortening has been done,
+   get its actual length.  Otherwise, get its maximum length.  */
+int
+get_attr_length (rtx insn)
+{
+  return get_attr_length_1 (insn, insn_default_length);
+}
+
+/* Obtain the current length of an insn.  If branch shortening has been done,
+   get its actual length.  Otherwise, get its minimum length.  */
+int
+get_attr_min_length (rtx insn)
+{
+  return get_attr_length_1 (insn, insn_min_length);
+}
 \f
 /* Code to handle alignment inside shorten_branches.  */
 
 \f
 /* Code to handle alignment inside shorten_branches.  */
 
@@ -638,8 +521,7 @@ get_attr_length (insn)
 
 #ifndef ADDR_VEC_ALIGN
 static int
 
 #ifndef ADDR_VEC_ALIGN
 static int
-final_addr_vec_align (addr_vec)
-     rtx addr_vec;
+final_addr_vec_align (rtx addr_vec)
 {
   int align = GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec)));
 
 {
   int align = GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec)));
 
@@ -669,8 +551,7 @@ static int min_labelno, max_labelno;
 /* For the benefit of port specific code do this also as a function.  */
 
 int
 /* For the benefit of port specific code do this also as a function.  */
 
 int
-label_to_alignment (label)
-     rtx label;
+label_to_alignment (rtx label)
 {
   return LABEL_TO_ALIGNMENT (label);
 }
 {
   return LABEL_TO_ALIGNMENT (label);
 }
@@ -705,10 +586,7 @@ label_to_alignment (label)
    The return value is undefined for any other value of GROWTH.  */
 
 static int
    The return value is undefined for any other value of GROWTH.  */
 
 static int
-align_fuzz (start, end, known_align_log, growth)
-     rtx start, end;
-     int known_align_log;
-     unsigned growth;
+align_fuzz (rtx start, rtx end, int known_align_log, unsigned int growth)
 {
   int uid = INSN_UID (start);
   rtx align_label;
 {
   int uid = INSN_UID (start);
   rtx align_label;
@@ -747,8 +625,7 @@ align_fuzz (start, end, known_align_log, growth)
    to exclude the branch size.  */
 
 int
    to exclude the branch size.  */
 
 int
-insn_current_reference_address (branch)
-     rtx branch;
+insn_current_reference_address (rtx branch)
 {
   rtx dest, seq;
   int seq_uid;
 {
   rtx dest, seq;
   int seq_uid;
@@ -758,7 +635,7 @@ insn_current_reference_address (branch)
 
   seq = NEXT_INSN (PREV_INSN (branch));
   seq_uid = INSN_UID (seq);
 
   seq = NEXT_INSN (PREV_INSN (branch));
   seq_uid = INSN_UID (seq);
-  if (GET_CODE (branch) != JUMP_INSN)
+  if (!JUMP_P (branch))
     /* This can happen for example on the PA; the objective is to know the
        offset to address something in front of the start of the function.
        Thus, we can treat it like a backward branch.
     /* This can happen for example on the PA; the objective is to know the
        offset to address something in front of the start of the function.
        Thus, we can treat it like a backward branch.
@@ -784,11 +661,16 @@ insn_current_reference_address (branch)
 }
 #endif /* HAVE_ATTR_length */
 \f
 }
 #endif /* HAVE_ATTR_length */
 \f
-void
-compute_alignments ()
+/* Compute branch alignments based on frequency information in the
+   CFG.  */
+
+unsigned int
+compute_alignments (void)
 {
 {
-  int i;
   int log, max_skip, max_log;
   int log, max_skip, max_log;
+  basic_block bb;
+  int freq_max = 0;
+  int freq_threshold = 0;
 
   if (label_align)
     {
 
   if (label_align)
     {
@@ -798,32 +680,62 @@ compute_alignments ()
 
   max_labelno = max_label_num ();
   min_labelno = get_first_label_num ();
 
   max_labelno = max_label_num ();
   min_labelno = get_first_label_num ();
-  label_align = (struct label_alignment *)
-    xcalloc (max_labelno - min_labelno + 1, sizeof (struct label_alignment));
+  label_align = XCNEWVEC (struct label_alignment, max_labelno - min_labelno + 1);
 
   /* If not optimizing or optimizing for size, don't assign any alignments.  */
 
   /* If not optimizing or optimizing for size, don't assign any alignments.  */
-  if (! optimize || optimize_size)
-    return;
+  if (! optimize || optimize_function_for_size_p (cfun))
+    return 0;
 
 
-  for (i = 0; i < n_basic_blocks; i++)
+  if (dump_file)
+    {
+      dump_flow_info (dump_file, TDF_DETAILS);
+      flow_loops_dump (dump_file, NULL, 1);
+      loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
+    }
+  FOR_EACH_BB (bb)
+    if (bb->frequency > freq_max)
+      freq_max = bb->frequency;
+  freq_threshold = freq_max / PARAM_VALUE (PARAM_ALIGN_THRESHOLD);
+
+  if (dump_file)
+    fprintf(dump_file, "freq_max: %i\n",freq_max);
+  FOR_EACH_BB (bb)
     {
     {
-      basic_block bb = BASIC_BLOCK (i);
-      rtx label = bb->head;
+      rtx label = BB_HEAD (bb);
       int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0;
       edge e;
       int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0;
       edge e;
+      edge_iterator ei;
 
 
-      if (GET_CODE (label) != CODE_LABEL)
-       continue;
+      if (!LABEL_P (label)
+         || optimize_bb_for_size_p (bb))
+       {
+         if (dump_file)
+           fprintf(dump_file, "BB %4i freq %4i loop %2i loop_depth %2i skipped.\n",
+                   bb->index, bb->frequency, bb->loop_father->num, bb->loop_depth);
+         continue;
+       }
       max_log = LABEL_ALIGN (label);
       max_skip = LABEL_ALIGN_MAX_SKIP;
 
       max_log = LABEL_ALIGN (label);
       max_skip = LABEL_ALIGN_MAX_SKIP;
 
-      for (e = bb->pred; e; e = e->pred_next)
+      FOR_EACH_EDGE (e, ei, bb->preds)
        {
          if (e->flags & EDGE_FALLTHRU)
            has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e);
          else
            branch_frequency += EDGE_FREQUENCY (e);
        }
        {
          if (e->flags & EDGE_FALLTHRU)
            has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e);
          else
            branch_frequency += EDGE_FREQUENCY (e);
        }
+      if (dump_file)
+       {
+         fprintf(dump_file, "BB %4i freq %4i loop %2i loop_depth %2i fall %4i branch %4i",
+                 bb->index, bb->frequency, bb->loop_father->num,
+                 bb->loop_depth,
+                 fallthru_frequency, branch_frequency);
+         if (!bb->loop_father->inner && bb->loop_father->num)
+           fprintf (dump_file, " inner_loop");
+         if (bb->loop_father->header == bb)
+           fprintf (dump_file, " loop_header");
+         fprintf (dump_file, "\n");
+       }
 
       /* There are two purposes to align block with no fallthru incoming edge:
         1) to avoid fetch stalls when branch destination is near cache boundary
 
       /* There are two purposes to align block with no fallthru incoming edge:
         1) to avoid fetch stalls when branch destination is near cache boundary
@@ -836,12 +748,14 @@ compute_alignments ()
         when function is called.  */
 
       if (!has_fallthru
         when function is called.  */
 
       if (!has_fallthru
-         && (branch_frequency > BB_FREQ_MAX / 10
-             || (bb->frequency > BASIC_BLOCK (i - 1)->frequency * 10
-                 && (BASIC_BLOCK (i - 1)->frequency
+         && (branch_frequency > freq_threshold
+             || (bb->frequency > bb->prev_bb->frequency * 10
+                 && (bb->prev_bb->frequency
                      <= ENTRY_BLOCK_PTR->frequency / 2))))
        {
          log = JUMP_ALIGN (label);
                      <= ENTRY_BLOCK_PTR->frequency / 2))))
        {
          log = JUMP_ALIGN (label);
+         if (dump_file)
+           fprintf(dump_file, "  jump alignment added.\n");
          if (max_log < log)
            {
              max_log = log;
          if (max_log < log)
            {
              max_log = log;
@@ -849,12 +763,16 @@ compute_alignments ()
            }
        }
       /* In case block is frequent and reached mostly by non-fallthru edge,
            }
        }
       /* In case block is frequent and reached mostly by non-fallthru edge,
-        align it.  It is most likely an first block of loop.  */
+        align it.  It is most likely a first block of loop.  */
       if (has_fallthru
       if (has_fallthru
-         && branch_frequency + fallthru_frequency > BB_FREQ_MAX / 10
-         && branch_frequency > fallthru_frequency * 5)
+         && optimize_bb_for_speed_p (bb)
+         && branch_frequency + fallthru_frequency > freq_threshold
+         && (branch_frequency
+             > fallthru_frequency * PARAM_VALUE (PARAM_ALIGN_LOOP_ITERATIONS)))
        {
          log = LOOP_ALIGN (label);
        {
          log = LOOP_ALIGN (label);
+         if (dump_file)
+           fprintf(dump_file, "  internal loop alignment added.\n");
          if (max_log < log)
            {
              max_log = log;
          if (max_log < log)
            {
              max_log = log;
@@ -864,17 +782,39 @@ compute_alignments ()
       LABEL_TO_ALIGNMENT (label) = max_log;
       LABEL_TO_MAX_SKIP (label) = max_skip;
     }
       LABEL_TO_ALIGNMENT (label) = max_log;
       LABEL_TO_MAX_SKIP (label) = max_skip;
     }
+
+  if (dump_file)
+    {
+      loop_optimizer_finalize ();
+      free_dominance_info (CDI_DOMINATORS);
+    }
+  return 0;
 }
 }
+
+struct rtl_opt_pass pass_compute_alignments =
+{
+ {
+  RTL_PASS,
+  "alignments",                         /* name */
+  NULL,                                 /* gate */
+  compute_alignments,                   /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  0,                                    /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func | TODO_verify_rtl_sharing
+  | TODO_ggc_collect                    /* todo_flags_finish */
+ }
+};
+
 \f
 /* Make a pass over all insns and compute their actual lengths by shortening
    any branches of variable length if possible.  */
 
 \f
 /* Make a pass over all insns and compute their actual lengths by shortening
    any branches of variable length if possible.  */
 
-/* Give a default value for the lowest address in a function.  */
-
-#ifndef FIRST_INSN_ADDRESS
-#define FIRST_INSN_ADDRESS 0
-#endif
-
 /* shorten_branches might be called multiple times:  for example, the SH
    port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG.
    In order to do this, it needs proper length information, which it obtains
 /* shorten_branches might be called multiple times:  for example, the SH
    port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG.
    In order to do this, it needs proper length information, which it obtains
@@ -884,8 +824,7 @@ compute_alignments ()
    slots.  */
 
 void
    slots.  */
 
 void
-shorten_branches (first)
-     rtx first ATTRIBUTE_UNUSED;
+shorten_branches (rtx first ATTRIBUTE_UNUSED)
 {
   rtx insn;
   int max_uid;
 {
   rtx insn;
   int max_uid;
@@ -906,7 +845,10 @@ shorten_branches (first)
   /* Compute maximum UID and allocate label_align / uid_shuid.  */
   max_uid = get_max_uid ();
 
   /* Compute maximum UID and allocate label_align / uid_shuid.  */
   max_uid = get_max_uid ();
 
-  uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid);
+  /* Free uid_shuid before reallocating it.  */
+  free (uid_shuid);
+
+  uid_shuid = XNEWVEC (int, max_uid);
 
   if (max_labelno != max_label_num ())
     {
 
   if (max_labelno != max_label_num ())
     {
@@ -919,13 +861,11 @@ shorten_branches (first)
       n_labels = max_labelno - min_labelno + 1;
       n_old_labels = old - min_labelno + 1;
 
       n_labels = max_labelno - min_labelno + 1;
       n_old_labels = old - min_labelno + 1;
 
-      label_align = (struct label_alignment *) xrealloc
-       (label_align, n_labels * sizeof (struct label_alignment));
+      label_align = XRESIZEVEC (struct label_alignment, label_align, n_labels);
 
 
-      /* Range of labels grows monotonically in the function.  Abort here
+      /* Range of labels grows monotonically in the function.  Failing here
          means that the initialization of array got lost.  */
          means that the initialization of array got lost.  */
-      if (n_old_labels > n_labels)
-       abort ();
+      gcc_assert (n_old_labels <= n_labels);
 
       memset (label_align + n_old_labels, 0,
              (n_labels - n_old_labels) * sizeof (struct label_alignment));
 
       memset (label_align + n_old_labels, 0,
              (n_labels - n_old_labels) * sizeof (struct label_alignment));
@@ -946,14 +886,9 @@ shorten_branches (first)
 
       INSN_SHUID (insn) = i++;
       if (INSN_P (insn))
 
       INSN_SHUID (insn) = i++;
       if (INSN_P (insn))
-       {
-         /* reorg might make the first insn of a loop being run once only,
-             and delete the label in front of it.  Then we want to apply
-             the loop alignment to the new label created by reorg, which
-             is separated by the former loop start insn from the
-            NOTE_INSN_LOOP_BEG.  */
-       }
-      else if (GET_CODE (insn) == CODE_LABEL)
+       continue;
+
+      if (LABEL_P (insn))
        {
          rtx next;
 
        {
          rtx next;
 
@@ -971,15 +906,12 @@ shorten_branches (first)
              max_log = log;
              max_skip = LABEL_ALIGN_MAX_SKIP;
            }
              max_log = log;
              max_skip = LABEL_ALIGN_MAX_SKIP;
            }
-         next = NEXT_INSN (insn);
+         next = next_nonnote_insn (insn);
          /* ADDR_VECs only take room if read-only data goes into the text
             section.  */
          if (JUMP_TABLES_IN_TEXT_SECTION
          /* ADDR_VECs only take room if read-only data goes into the text
             section.  */
          if (JUMP_TABLES_IN_TEXT_SECTION
-#if !defined(READONLY_DATA_SECTION)
-             || 1
-#endif
-             )
-           if (next && GET_CODE (next) == JUMP_INSN)
+             || readonly_data_section == text_section)
+           if (next && JUMP_P (next))
              {
                rtx nextbody = PATTERN (next);
                if (GET_CODE (nextbody) == ADDR_VEC
              {
                rtx nextbody = PATTERN (next);
                if (GET_CODE (nextbody) == ADDR_VEC
@@ -998,13 +930,13 @@ shorten_branches (first)
          max_log = 0;
          max_skip = 0;
        }
          max_log = 0;
          max_skip = 0;
        }
-      else if (GET_CODE (insn) == BARRIER)
+      else if (BARRIER_P (insn))
        {
          rtx label;
 
          for (label = insn; label && ! INSN_P (label);
               label = NEXT_INSN (label))
        {
          rtx label;
 
          for (label = insn; label && ! INSN_P (label);
               label = NEXT_INSN (label))
-           if (GET_CODE (label) == CODE_LABEL)
+           if (LABEL_P (label))
              {
                log = LABEL_ALIGN_AFTER_BARRIER (insn);
                if (max_log < log)
              {
                log = LABEL_ALIGN_AFTER_BARRIER (insn);
                if (max_log < log)
@@ -1019,20 +951,20 @@ shorten_branches (first)
 #ifdef HAVE_ATTR_length
 
   /* Allocate the rest of the arrays.  */
 #ifdef HAVE_ATTR_length
 
   /* Allocate the rest of the arrays.  */
-  insn_lengths = (int *) xmalloc (max_uid * sizeof (*insn_lengths));
+  insn_lengths = XNEWVEC (int, max_uid);
   insn_lengths_max_uid = max_uid;
   /* Syntax errors can lead to labels being outside of the main insn stream.
      Initialize insn_addresses, so that we get reproducible results.  */
   INSN_ADDRESSES_ALLOC (max_uid);
 
   insn_lengths_max_uid = max_uid;
   /* Syntax errors can lead to labels being outside of the main insn stream.
      Initialize insn_addresses, so that we get reproducible results.  */
   INSN_ADDRESSES_ALLOC (max_uid);
 
-  varying_length = (char *) xcalloc (max_uid, sizeof (char));
+  varying_length = XCNEWVEC (char, max_uid);
 
   /* Initialize uid_align.  We scan instructions
      from end to start, and keep in align_tab[n] the last seen insn
      that does an alignment of at least n+1, i.e. the successor
      in the alignment chain for an insn that does / has a known
      alignment of n.  */
 
   /* Initialize uid_align.  We scan instructions
      from end to start, and keep in align_tab[n] the last seen insn
      that does an alignment of at least n+1, i.e. the successor
      in the alignment chain for an insn that does / has a known
      alignment of n.  */
-  uid_align = (rtx *) xcalloc (max_uid, sizeof *uid_align);
+  uid_align = XCNEWVEC (rtx, max_uid);
 
   for (i = MAX_CODE_ALIGN; --i >= 0;)
     align_tab[i] = NULL_RTX;
 
   for (i = MAX_CODE_ALIGN; --i >= 0;)
     align_tab[i] = NULL_RTX;
@@ -1041,7 +973,7 @@ shorten_branches (first)
     {
       int uid = INSN_UID (seq);
       int log;
     {
       int uid = INSN_UID (seq);
       int log;
-      log = (GET_CODE (seq) == CODE_LABEL ? LABEL_TO_ALIGNMENT (seq) : 0);
+      log = (LABEL_P (seq) ? LABEL_TO_ALIGNMENT (seq) : 0);
       uid_align[uid] = align_tab[0];
       if (log)
        {
       uid_align[uid] = align_tab[0];
       if (log)
        {
@@ -1068,13 +1000,12 @@ shorten_branches (first)
          int min_align;
          addr_diff_vec_flags flags;
 
          int min_align;
          addr_diff_vec_flags flags;
 
-         if (GET_CODE (insn) != JUMP_INSN
+         if (!JUMP_P (insn)
              || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
            continue;
          pat = PATTERN (insn);
          len = XVECLEN (pat, 1);
              || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
            continue;
          pat = PATTERN (insn);
          len = XVECLEN (pat, 1);
-         if (len <= 0)
-           abort ();
+         gcc_assert (len > 0);
          min_align = MAX_CODE_ALIGN;
          for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--)
            {
          min_align = MAX_CODE_ALIGN;
          for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--)
            {
@@ -1093,10 +1024,11 @@ shorten_branches (first)
              if (min_align > LABEL_TO_ALIGNMENT (lab))
                min_align = LABEL_TO_ALIGNMENT (lab);
            }
              if (min_align > LABEL_TO_ALIGNMENT (lab))
                min_align = LABEL_TO_ALIGNMENT (lab);
            }
-         XEXP (pat, 2) = gen_rtx_LABEL_REF (VOIDmode, min_lab);
-         XEXP (pat, 3) = gen_rtx_LABEL_REF (VOIDmode, max_lab);
+         XEXP (pat, 2) = gen_rtx_LABEL_REF (Pmode, min_lab);
+         XEXP (pat, 3) = gen_rtx_LABEL_REF (Pmode, max_lab);
          insn_shuid = INSN_SHUID (insn);
          rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0));
          insn_shuid = INSN_SHUID (insn);
          rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0));
+         memset (&flags, 0, sizeof (flags));
          flags.min_align = min_align;
          flags.base_after_vec = rel > insn_shuid;
          flags.min_after_vec  = min > insn_shuid;
          flags.min_align = min_align;
          flags.base_after_vec = rel > insn_shuid;
          flags.min_after_vec  = min > insn_shuid;
@@ -1109,7 +1041,7 @@ shorten_branches (first)
 #endif /* CASE_VECTOR_SHORTEN_MODE */
 
   /* Compute initial lengths, addresses, and varying flags for each insn.  */
 #endif /* CASE_VECTOR_SHORTEN_MODE */
 
   /* Compute initial lengths, addresses, and varying flags for each insn.  */
-  for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
+  for (insn_current_address = 0, insn = first;
        insn != 0;
        insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
     {
        insn != 0;
        insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
     {
@@ -1117,7 +1049,7 @@ shorten_branches (first)
 
       insn_lengths[uid] = 0;
 
 
       insn_lengths[uid] = 0;
 
-      if (GET_CODE (insn) == CODE_LABEL)
+      if (LABEL_P (insn))
        {
          int log = LABEL_TO_ALIGNMENT (insn);
          if (log)
        {
          int log = LABEL_TO_ALIGNMENT (insn);
          if (log)
@@ -1128,10 +1060,10 @@ shorten_branches (first)
            }
        }
 
            }
        }
 
-      INSN_ADDRESSES (uid) = insn_current_address;
+      INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid];
 
 
-      if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER
-         || GET_CODE (insn) == CODE_LABEL)
+      if (NOTE_P (insn) || BARRIER_P (insn)
+         || LABEL_P (insn))
        continue;
       if (INSN_DELETED_P (insn))
        continue;
        continue;
       if (INSN_DELETED_P (insn))
        continue;
@@ -1142,10 +1074,7 @@ shorten_branches (first)
          /* This only takes room if read-only data goes into the text
             section.  */
          if (JUMP_TABLES_IN_TEXT_SECTION
          /* This only takes room if read-only data goes into the text
             section.  */
          if (JUMP_TABLES_IN_TEXT_SECTION
-#if !defined(READONLY_DATA_SECTION)
-             || 1
-#endif
-             )
+             || readonly_data_section == text_section)
            insn_lengths[uid] = (XVECLEN (body,
                                          GET_CODE (body) == ADDR_DIFF_VEC)
                                 * GET_MODE_SIZE (GET_MODE (body)));
            insn_lengths[uid] = (XVECLEN (body,
                                          GET_CODE (body) == ADDR_DIFF_VEC)
                                 * GET_MODE_SIZE (GET_MODE (body)));
@@ -1214,7 +1143,7 @@ shorten_branches (first)
     {
       something_changed = 0;
       insn_current_align = MAX_CODE_ALIGN - 1;
     {
       something_changed = 0;
       insn_current_align = MAX_CODE_ALIGN - 1;
-      for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
+      for (insn_current_address = 0, insn = first;
           insn != 0;
           insn = NEXT_INSN (insn))
        {
           insn != 0;
           insn = NEXT_INSN (insn))
        {
@@ -1226,7 +1155,7 @@ shorten_branches (first)
 
          uid = INSN_UID (insn);
 
 
          uid = INSN_UID (insn);
 
-         if (GET_CODE (insn) == CODE_LABEL)
+         if (LABEL_P (insn))
            {
              int log = LABEL_TO_ALIGNMENT (insn);
              if (log > insn_current_align)
            {
              int log = LABEL_TO_ALIGNMENT (insn);
              if (log > insn_current_align)
@@ -1251,7 +1180,7 @@ shorten_branches (first)
          INSN_ADDRESSES (uid) = insn_current_address;
 
 #ifdef CASE_VECTOR_SHORTEN_MODE
          INSN_ADDRESSES (uid) = insn_current_address;
 
 #ifdef CASE_VECTOR_SHORTEN_MODE
-         if (optimize && GET_CODE (insn) == JUMP_INSN
+         if (optimize && JUMP_P (insn)
              && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
            {
              rtx body = PATTERN (insn);
              && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
            {
              rtx body = PATTERN (insn);
@@ -1347,10 +1276,7 @@ shorten_branches (first)
                                                        max_addr - rel_addr,
                                                        body));
              if (JUMP_TABLES_IN_TEXT_SECTION
                                                        max_addr - rel_addr,
                                                        body));
              if (JUMP_TABLES_IN_TEXT_SECTION
-#if !defined(READONLY_DATA_SECTION)
-                 || 1
-#endif
-                 )
+                 || readonly_data_section == text_section)
                {
                  insn_lengths[uid]
                    = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)));
                {
                  insn_lengths[uid]
                    = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)));
@@ -1365,7 +1291,7 @@ shorten_branches (first)
 
          if (! (varying_length[uid]))
            {
 
          if (! (varying_length[uid]))
            {
-             if (GET_CODE (insn) == INSN
+             if (NONJUMP_INSN_P (insn)
                  && GET_CODE (PATTERN (insn)) == SEQUENCE)
                {
                  int i;
                  && GET_CODE (PATTERN (insn)) == SEQUENCE)
                {
                  int i;
@@ -1380,14 +1306,14 @@ shorten_branches (first)
 
                      insn_current_address += insn_lengths[inner_uid];
                    }
 
                      insn_current_address += insn_lengths[inner_uid];
                    }
-                }
+               }
              else
                insn_current_address += insn_lengths[uid];
 
              continue;
            }
 
              else
                insn_current_address += insn_lengths[uid];
 
              continue;
            }
 
-         if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
+         if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
            {
              int i;
 
            {
              int i;
 
@@ -1452,25 +1378,94 @@ shorten_branches (first)
    This is used to compute its length.  */
 
 static int
    This is used to compute its length.  */
 
 static int
-asm_insn_count (body)
-     rtx body;
+asm_insn_count (rtx body)
 {
 {
-  const char *template;
+  const char *templ;
   int count = 1;
 
   if (GET_CODE (body) == ASM_INPUT)
   int count = 1;
 
   if (GET_CODE (body) == ASM_INPUT)
-    template = XSTR (body, 0);
+    templ = XSTR (body, 0);
   else
   else
-    template = decode_asm_operands (body, NULL, NULL, NULL, NULL);
+    templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
 
 
-  for (; *template; template++)
-    if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n')
+  if (!*templ)
+    return 0;
+
+  for (; *templ; templ++)
+    if (IS_ASM_LOGICAL_LINE_SEPARATOR (*templ, templ)
+       || *templ == '\n')
       count++;
 
   return count;
 }
 #endif
 \f
       count++;
 
   return count;
 }
 #endif
 \f
+/* ??? This is probably the wrong place for these.  */
+/* Structure recording the mapping from source file and directory
+   names at compile time to those to be embedded in debug
+   information.  */
+typedef struct debug_prefix_map
+{
+  const char *old_prefix;
+  const char *new_prefix;
+  size_t old_len;
+  size_t new_len;
+  struct debug_prefix_map *next;
+} debug_prefix_map;
+
+/* Linked list of such structures.  */
+debug_prefix_map *debug_prefix_maps;
+
+
+/* Record a debug file prefix mapping.  ARG is the argument to
+   -fdebug-prefix-map and must be of the form OLD=NEW.  */
+
+void
+add_debug_prefix_map (const char *arg)
+{
+  debug_prefix_map *map;
+  const char *p;
+
+  p = strchr (arg, '=');
+  if (!p)
+    {
+      error ("invalid argument %qs to -fdebug-prefix-map", arg);
+      return;
+    }
+  map = XNEW (debug_prefix_map);
+  map->old_prefix = ggc_alloc_string (arg, p - arg);
+  map->old_len = p - arg;
+  p++;
+  map->new_prefix = ggc_strdup (p);
+  map->new_len = strlen (p);
+  map->next = debug_prefix_maps;
+  debug_prefix_maps = map;
+}
+
+/* Perform user-specified mapping of debug filename prefixes.  Return
+   the new name corresponding to FILENAME.  */
+
+const char *
+remap_debug_filename (const char *filename)
+{
+  debug_prefix_map *map;
+  char *s;
+  const char *name;
+  size_t name_len;
+
+  for (map = debug_prefix_maps; map; map = map->next)
+    if (strncmp (filename, map->old_prefix, map->old_len) == 0)
+      break;
+  if (!map)
+    return filename;
+  name = filename + map->old_len;
+  name_len = strlen (name) + 1;
+  s = (char *) alloca (name_len + map->new_len);
+  memcpy (s, map->new_prefix, map->new_len);
+  memcpy (s + map->new_len, name, name_len);
+  return ggc_strdup (s);
+}
+\f
 /* Output assembler code for the start of a function,
    and initialize some of the variables in this file
    for the new function.  The label for the function and associated
 /* Output assembler code for the start of a function,
    and initialize some of the variables in this file
    for the new function.  The label for the function and associated
@@ -1482,35 +1477,21 @@ asm_insn_count (body)
      test and compare insns.  */
 
 void
      test and compare insns.  */
 
 void
-final_start_function (first, file, optimize)
-     rtx first;
-     FILE *file;
-     int optimize ATTRIBUTE_UNUSED;
+final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
+                     int optimize ATTRIBUTE_UNUSED)
 {
   block_depth = 0;
 
   this_is_asm_operands = 0;
 
 {
   block_depth = 0;
 
   this_is_asm_operands = 0;
 
-#ifdef NON_SAVING_SETJMP
-  /* A function that calls setjmp should save and restore all the
-     call-saved registers on a system where longjmp clobbers them.  */
-  if (NON_SAVING_SETJMP && current_function_calls_setjmp)
-    {
-      int i;
-
-      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-       if (!call_used_regs[i])
-         regs_ever_live[i] = 1;
-    }
-#endif
+  last_filename = locator_file (prologue_locator);
+  last_linenum = locator_line (prologue_locator);
 
 
-  if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED)
-    notice_source_line (first);
   high_block_linenum = high_function_linenum = last_linenum;
 
   (*debug_hooks->begin_prologue) (last_linenum, last_filename);
 
   high_block_linenum = high_function_linenum = last_linenum;
 
   (*debug_hooks->begin_prologue) (last_linenum, last_filename);
 
-#if defined (DWARF2_UNWIND_INFO) || defined (IA64_UNWIND_INFO)
+#if defined (DWARF2_UNWIND_INFO) || defined (TARGET_UNWIND_INFO)
   if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG)
     dwarf2out_begin_prologue (0, NULL);
 #endif
   if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG)
     dwarf2out_begin_prologue (0, NULL);
 #endif
@@ -1523,21 +1504,20 @@ final_start_function (first, file, optimize)
   /* The Sun386i and perhaps other machines don't work right
      if the profiling code comes after the prologue.  */
 #ifdef PROFILE_BEFORE_PROLOGUE
   /* The Sun386i and perhaps other machines don't work right
      if the profiling code comes after the prologue.  */
 #ifdef PROFILE_BEFORE_PROLOGUE
-  if (current_function_profile)
+  if (crtl->profile)
     profile_function (file);
 #endif /* PROFILE_BEFORE_PROLOGUE */
 
 #if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
   if (dwarf2out_do_frame ())
     profile_function (file);
 #endif /* PROFILE_BEFORE_PROLOGUE */
 
 #if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
   if (dwarf2out_do_frame ())
-    dwarf2out_frame_debug (NULL_RTX);
+    dwarf2out_frame_debug (NULL_RTX, false);
 #endif
 
   /* If debugging, assign block numbers to all of the blocks in this
      function.  */
   if (write_symbols)
     {
 #endif
 
   /* If debugging, assign block numbers to all of the blocks in this
      function.  */
   if (write_symbols)
     {
-      remove_unnecessary_notes ();
-      reorder_blocks ();
+      reemit_insn_block_notes ();
       number_blocks (current_function_decl);
       /* We never actually put out begin/end notes for the top-level
         block in the function.  But, conceptually, that block is
       number_blocks (current_function_decl);
       /* We never actually put out begin/end notes for the top-level
         block in the function.  But, conceptually, that block is
@@ -1545,14 +1525,17 @@ final_start_function (first, file, optimize)
       TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
     }
 
       TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
     }
 
-  /* First output the function prologue: code to set up the stack frame.  */
-  (*targetm.asm_out.function_prologue) (file, get_frame_size ());
+  if (warn_frame_larger_than
+    && get_frame_size () > frame_larger_than_size)
+  {
+      /* Issue a warning */
+      warning (OPT_Wframe_larger_than_,
+               "the frame size of %wd bytes is larger than %wd bytes",
+               get_frame_size (), frame_larger_than_size);
+  }
 
 
-#ifdef VMS_DEBUGGING_INFO
-  /* Output label after the prologue of the function.  */
-  if (write_symbols == VMS_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
-    vmsdbgout_after_prologue ();
-#endif
+  /* First output the function prologue: code to set up the stack frame.  */
+  targetm.asm_out.function_prologue (file, get_frame_size ());
 
   /* If the machine represents the prologue as RTL, the profiling code must
      be emitted when NOTE_INSN_PROLOGUE_END is scanned.  */
 
   /* If the machine represents the prologue as RTL, the profiling code must
      be emitted when NOTE_INSN_PROLOGUE_END is scanned.  */
@@ -1563,51 +1546,45 @@ final_start_function (first, file, optimize)
 }
 
 static void
 }
 
 static void
-profile_after_prologue (file)
-     FILE *file ATTRIBUTE_UNUSED;
+profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
 {
 #ifndef PROFILE_BEFORE_PROLOGUE
 {
 #ifndef PROFILE_BEFORE_PROLOGUE
-  if (current_function_profile)
+  if (crtl->profile)
     profile_function (file);
 #endif /* not PROFILE_BEFORE_PROLOGUE */
 }
 
 static void
     profile_function (file);
 #endif /* not PROFILE_BEFORE_PROLOGUE */
 }
 
 static void
-profile_function (file)
-     FILE *file ATTRIBUTE_UNUSED;
+profile_function (FILE *file ATTRIBUTE_UNUSED)
 {
 #ifndef NO_PROFILE_COUNTERS
 {
 #ifndef NO_PROFILE_COUNTERS
-  int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
+# define NO_PROFILE_COUNTERS   0
 #endif
 #if defined(ASM_OUTPUT_REG_PUSH)
 #endif
 #if defined(ASM_OUTPUT_REG_PUSH)
-#if defined(STRUCT_VALUE_INCOMING_REGNUM) || defined(STRUCT_VALUE_REGNUM)
-  int sval = current_function_returns_struct;
-#endif
+  int sval = cfun->returns_struct;
+  rtx svrtx = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), 1);
 #if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM)
 #if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM)
-  int cxt = current_function_needs_context;
+  int cxt = cfun->static_chain_decl != NULL;
 #endif
 #endif /* ASM_OUTPUT_REG_PUSH */
 
 #endif
 #endif /* ASM_OUTPUT_REG_PUSH */
 
-#ifndef NO_PROFILE_COUNTERS
-  data_section ();
-  ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
-  ASM_OUTPUT_INTERNAL_LABEL (file, "LP", current_function_profile_label_no);
-  assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
-#endif
+  if (! NO_PROFILE_COUNTERS)
+    {
+      int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
+      switch_to_section (data_section);
+      ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
+      targetm.asm_out.internal_label (file, "LP", current_function_funcdef_no);
+      assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
+    }
 
 
-  function_section (current_function_decl);
+  switch_to_section (current_function_section ());
 
 
-#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
-  if (sval)
-    ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_INCOMING_REGNUM);
-#else
-#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
-  if (sval)
+#if defined(ASM_OUTPUT_REG_PUSH)
+  if (sval && svrtx != NULL_RTX && REG_P (svrtx))
     {
     {
-      ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM);
+      ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx));
     }
 #endif
     }
 #endif
-#endif
 
 #if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
   if (cxt)
 
 #if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
   if (cxt)
@@ -1621,7 +1598,7 @@ profile_function (file)
 #endif
 #endif
 
 #endif
 #endif
 
-  FUNCTION_PROFILER (file, current_function_profile_label_no);
+  FUNCTION_PROFILER (file, current_function_funcdef_no);
 
 #if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
   if (cxt)
 
 #if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
   if (cxt)
@@ -1635,17 +1612,12 @@ profile_function (file)
 #endif
 #endif
 
 #endif
 #endif
 
-#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
-  if (sval)
-    ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_INCOMING_REGNUM);
-#else
-#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
-  if (sval)
+#if defined(ASM_OUTPUT_REG_PUSH)
+  if (sval && svrtx != NULL_RTX && REG_P (svrtx))
     {
     {
-      ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM);
+      ASM_OUTPUT_REG_POP (file, REGNO (svrtx));
     }
 #endif
     }
 #endif
-#endif
 }
 
 /* Output assembler code for the end of a function.
 }
 
 /* Output assembler code for the end of a function.
@@ -1653,7 +1625,7 @@ profile_function (file)
    even though not all of them are needed.  */
 
 void
    even though not all of them are needed.  */
 
 void
-final_end_function ()
+final_end_function (void)
 {
   app_disable ();
 
 {
   app_disable ();
 
@@ -1661,88 +1633,38 @@ final_end_function ()
 
   /* Finally, output the function epilogue:
      code to restore the stack frame and return to the caller.  */
 
   /* Finally, output the function epilogue:
      code to restore the stack frame and return to the caller.  */
-  (*targetm.asm_out.function_epilogue) (asm_out_file, get_frame_size ());
+  targetm.asm_out.function_epilogue (asm_out_file, get_frame_size ());
 
   /* And debug output.  */
 
   /* And debug output.  */
-  (*debug_hooks->end_epilogue) ();
+  (*debug_hooks->end_epilogue) (last_linenum, last_filename);
 
 #if defined (DWARF2_UNWIND_INFO)
   if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG
       && dwarf2out_do_frame ())
 
 #if defined (DWARF2_UNWIND_INFO)
   if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG
       && dwarf2out_do_frame ())
-    dwarf2out_end_epilogue ();
+    dwarf2out_end_epilogue (last_linenum, last_filename);
 #endif
 }
 \f
 /* Output assembler code for some insns: all or part of a function.
 #endif
 }
 \f
 /* Output assembler code for some insns: all or part of a function.
-   For description of args, see `final_start_function', above.
-
-   PRESCAN is 1 if we are not really outputting,
-     just scanning as if we were outputting.
-   Prescanning deletes and rearranges insns just like ordinary output.
-   PRESCAN is -2 if we are outputting after having prescanned.
-   In this case, don't try to delete or rearrange insns
-   because that has already been done.
-   Prescanning is done only on certain machines.  */
+   For description of args, see `final_start_function', above.  */
 
 void
 
 void
-final (first, file, optimize, prescan)
-     rtx first;
-     FILE *file;
-     int optimize;
-     int prescan;
+final (rtx first, FILE *file, int optimize)
 {
   rtx insn;
 {
   rtx insn;
-  int max_line = 0;
   int max_uid = 0;
   int max_uid = 0;
+  int seen = 0;
 
   last_ignored_compare = 0;
 
   last_ignored_compare = 0;
-  new_block = 1;
-
-  /* Make a map indicating which line numbers appear in this function.
-     When producing SDB debugging info, delete troublesome line number
-     notes from inlined functions in other files as well as duplicate
-     line number notes.  */
-#ifdef SDB_DEBUGGING_INFO
-  if (write_symbols == SDB_DEBUG)
-    {
-      rtx last = 0;
-      for (insn = first; insn; insn = NEXT_INSN (insn))
-       if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
-         {
-           if ((RTX_INTEGRATED_P (insn)
-                && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0)
-                || (last != 0
-                    && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
-                    && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)))
-             {
-               delete_insn (insn);     /* Use delete_note.  */
-               continue;
-             }
-           last = insn;
-           if (NOTE_LINE_NUMBER (insn) > max_line)
-             max_line = NOTE_LINE_NUMBER (insn);
-         }
-    }
-  else
-#endif
-    {
-      for (insn = first; insn; insn = NEXT_INSN (insn))
-       if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > max_line)
-         max_line = NOTE_LINE_NUMBER (insn);
-    }
-
-  line_note_exists = (char *) xcalloc (max_line + 1, sizeof (char));
 
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
 
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
-      if (INSN_UID (insn) > max_uid)       /* find largest UID */
+      if (INSN_UID (insn) > max_uid)       /* Find largest UID.  */
        max_uid = INSN_UID (insn);
        max_uid = INSN_UID (insn);
-      if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
-       line_note_exists[NOTE_LINE_NUMBER (insn)] = 1;
 #ifdef HAVE_cc0
       /* If CC tracking across branches is enabled, record the insn which
         jumps to each branch only reached from one place.  */
 #ifdef HAVE_cc0
       /* If CC tracking across branches is enabled, record the insn which
         jumps to each branch only reached from one place.  */
-      if (optimize && GET_CODE (insn) == JUMP_INSN)
+      if (optimize && JUMP_P (insn))
        {
          rtx lab = JUMP_LABEL (insn);
          if (lab && LABEL_NUSES (lab) == 1)
        {
          rtx lab = JUMP_LABEL (insn);
          if (lab && LABEL_NUSES (lab) == 1)
@@ -1758,53 +1680,99 @@ final (first, file, optimize, prescan)
   CC_STATUS_INIT;
 
   /* Output the insns.  */
   CC_STATUS_INIT;
 
   /* Output the insns.  */
-  for (insn = NEXT_INSN (first); insn;)
+  for (insn = first; insn;)
     {
 #ifdef HAVE_ATTR_length
       if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ())
        {
     {
 #ifdef HAVE_ATTR_length
       if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ())
        {
-#ifdef STACK_REGS
-         /* Irritatingly, the reg-stack pass is creating new instructions
-            and because of REG_DEAD note abuse it has to run after
-            shorten_branches.  Fake address of -1 then.  */
-         insn_current_address = -1;
-#else
          /* This can be triggered by bugs elsewhere in the compiler if
             new insns are created after init_insn_lengths is called.  */
          /* This can be triggered by bugs elsewhere in the compiler if
             new insns are created after init_insn_lengths is called.  */
-         abort ();
-#endif
+         gcc_assert (NOTE_P (insn));
+         insn_current_address = -1;
        }
       else
        insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
 #endif /* HAVE_ATTR_length */
 
        }
       else
        insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
 #endif /* HAVE_ATTR_length */
 
-      insn = final_scan_insn (insn, file, optimize, prescan, 0);
+      insn = final_scan_insn (insn, file, optimize, 0, &seen);
     }
     }
-
-  free (line_note_exists);
-  line_note_exists = NULL;
 }
 \f
 const char *
 }
 \f
 const char *
-get_insn_template (code, insn)
-     int code;
-     rtx insn;
+get_insn_template (int code, rtx insn)
 {
 {
-  const void *output = insn_data[code].output;
   switch (insn_data[code].output_format)
     {
     case INSN_OUTPUT_FORMAT_SINGLE:
   switch (insn_data[code].output_format)
     {
     case INSN_OUTPUT_FORMAT_SINGLE:
-      return (const char *) output;
+      return insn_data[code].output.single;
     case INSN_OUTPUT_FORMAT_MULTI:
     case INSN_OUTPUT_FORMAT_MULTI:
-      return ((const char *const *) output)[which_alternative];
+      return insn_data[code].output.multi[which_alternative];
     case INSN_OUTPUT_FORMAT_FUNCTION:
     case INSN_OUTPUT_FORMAT_FUNCTION:
-      if (insn == NULL)
-       abort ();
-      return (*(insn_output_fn) output) (recog_data.operand, insn);
+      gcc_assert (insn);
+      return (*insn_data[code].output.function) (recog_data.operand, insn);
 
     default:
 
     default:
-      abort ();
+      gcc_unreachable ();
+    }
+}
+
+/* Emit the appropriate declaration for an alternate-entry-point
+   symbol represented by INSN, to FILE.  INSN is a CODE_LABEL with
+   LABEL_KIND != LABEL_NORMAL.
+
+   The case fall-through in this function is intentional.  */
+static void
+output_alternate_entry_point (FILE *file, rtx insn)
+{
+  const char *name = LABEL_NAME (insn);
+
+  switch (LABEL_KIND (insn))
+    {
+    case LABEL_WEAK_ENTRY:
+#ifdef ASM_WEAKEN_LABEL
+      ASM_WEAKEN_LABEL (file, name);
+#endif
+    case LABEL_GLOBAL_ENTRY:
+      targetm.asm_out.globalize_label (file, name);
+    case LABEL_STATIC_ENTRY:
+#ifdef ASM_OUTPUT_TYPE_DIRECTIVE
+      ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
+#endif
+      ASM_OUTPUT_LABEL (file, name);
+      break;
+
+    case LABEL_NORMAL:
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Given a CALL_INSN, find and return the nested CALL. */
+static rtx
+call_from_call_insn (rtx insn)
+{
+  rtx x;
+  gcc_assert (CALL_P (insn));
+  x = PATTERN (insn);
+
+  while (GET_CODE (x) != CALL)
+    {
+      switch (GET_CODE (x))
+       {
+       default:
+         gcc_unreachable ();
+       case COND_EXEC:
+         x = COND_EXEC_CODE (x);
+         break;
+       case PARALLEL:
+         x = XVECEXP (x, 0, 0);
+         break;
+       case SET:
+         x = XEXP (x, 1);
+         break;
+       }
     }
     }
+  return x;
 }
 
 /* The final scan for one insn, INSN.
 }
 
 /* The final scan for one insn, INSN.
@@ -1813,19 +1781,22 @@ get_insn_template (code, insn)
    Value returned is the next insn to be scanned.
 
    NOPEEPHOLES is the flag to disallow peephole processing (currently
    Value returned is the next insn to be scanned.
 
    NOPEEPHOLES is the flag to disallow peephole processing (currently
-   used for within delayed branch sequence output).  */
+   used for within delayed branch sequence output).
+
+   SEEN is used to track the end of the prologue, for emitting
+   debug information.  We force the emission of a line note after
+   both NOTE_INSN_PROLOGUE_END and NOTE_INSN_FUNCTION_BEG, or
+   at the beginning of the second basic block, whichever comes
+   first.  */
 
 rtx
 
 rtx
-final_scan_insn (insn, file, optimize, prescan, nopeepholes)
-     rtx insn;
-     FILE *file;
-     int optimize ATTRIBUTE_UNUSED;
-     int prescan;
-     int nopeepholes ATTRIBUTE_UNUSED;
+final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
+                int nopeepholes ATTRIBUTE_UNUSED, int *seen)
 {
 #ifdef HAVE_cc0
   rtx set;
 #endif
 {
 #ifdef HAVE_cc0
   rtx set;
 #endif
+  rtx next;
 
   insn_counter++;
 
 
   insn_counter++;
 
@@ -1837,32 +1808,40 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
   switch (GET_CODE (insn))
     {
     case NOTE:
   switch (GET_CODE (insn))
     {
     case NOTE:
-      if (prescan > 0)
-       break;
-
-      switch (NOTE_LINE_NUMBER (insn))
+      switch (NOTE_KIND (insn))
        {
        case NOTE_INSN_DELETED:
        {
        case NOTE_INSN_DELETED:
-       case NOTE_INSN_LOOP_BEG:
-       case NOTE_INSN_LOOP_END:
-       case NOTE_INSN_LOOP_END_TOP_COND:
-       case NOTE_INSN_LOOP_CONT:
-       case NOTE_INSN_LOOP_VTOP:
-       case NOTE_INSN_FUNCTION_END:
-       case NOTE_INSN_REPEATED_LINE_NUMBER:
-       case NOTE_INSN_RANGE_BEG:
-       case NOTE_INSN_RANGE_END:
-       case NOTE_INSN_LIVE:
-       case NOTE_INSN_EXPECTED_VALUE:
+         break;
+
+       case NOTE_INSN_SWITCH_TEXT_SECTIONS:
+         in_cold_section_p = !in_cold_section_p;
+#ifdef DWARF2_UNWIND_INFO
+         if (dwarf2out_do_frame ())
+           dwarf2out_switch_text_section ();
+         else
+#endif
+           (*debug_hooks->switch_text_section) ();
+
+         switch_to_section (current_function_section ());
          break;
 
        case NOTE_INSN_BASIC_BLOCK:
          break;
 
        case NOTE_INSN_BASIC_BLOCK:
-#ifdef IA64_UNWIND_INFO
-         IA64_UNWIND_EMIT (asm_out_file, insn);
+#ifdef TARGET_UNWIND_INFO
+         targetm.asm_out.unwind_emit (asm_out_file, insn);
 #endif
 #endif
+
          if (flag_debug_asm)
            fprintf (asm_out_file, "\t%s basic block %d\n",
                     ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index);
          if (flag_debug_asm)
            fprintf (asm_out_file, "\t%s basic block %d\n",
                     ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index);
+
+         if ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB)
+           {
+             *seen |= SEEN_EMITTED;
+             force_source_line = true;
+           }
+         else
+           *seen |= SEEN_BB;
+
          break;
 
        case NOTE_INSN_EH_REGION_BEG:
          break;
 
        case NOTE_INSN_EH_REGION_BEG:
@@ -1876,23 +1855,40 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
          break;
 
        case NOTE_INSN_PROLOGUE_END:
          break;
 
        case NOTE_INSN_PROLOGUE_END:
-         (*targetm.asm_out.function_end_prologue) (file);
+         targetm.asm_out.function_end_prologue (file);
          profile_after_prologue (file);
          profile_after_prologue (file);
+
+         if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
+           {
+             *seen |= SEEN_EMITTED;
+             force_source_line = true;
+           }
+         else
+           *seen |= SEEN_NOTE;
+
          break;
 
        case NOTE_INSN_EPILOGUE_BEG:
          break;
 
        case NOTE_INSN_EPILOGUE_BEG:
-         (*targetm.asm_out.function_begin_epilogue) (file);
+         targetm.asm_out.function_begin_epilogue (file);
          break;
 
        case NOTE_INSN_FUNCTION_BEG:
          app_disable ();
          break;
 
        case NOTE_INSN_FUNCTION_BEG:
          app_disable ();
-         (*debug_hooks->end_prologue) (last_linenum);
+         (*debug_hooks->end_prologue) (last_linenum, last_filename);
+
+         if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
+           {
+             *seen |= SEEN_EMITTED;
+             force_source_line = true;
+           }
+         else
+           *seen |= SEEN_NOTE;
+
          break;
 
        case NOTE_INSN_BLOCK_BEG:
          if (debug_info_level == DINFO_LEVEL_NORMAL
              || debug_info_level == DINFO_LEVEL_VERBOSE
          break;
 
        case NOTE_INSN_BLOCK_BEG:
          if (debug_info_level == DINFO_LEVEL_NORMAL
              || debug_info_level == DINFO_LEVEL_VERBOSE
-             || write_symbols == DWARF_DEBUG
              || write_symbols == DWARF2_DEBUG
              || write_symbols == VMS_AND_DWARF2_DEBUG
              || write_symbols == VMS_DEBUG)
              || write_symbols == DWARF2_DEBUG
              || write_symbols == VMS_AND_DWARF2_DEBUG
              || write_symbols == VMS_DEBUG)
@@ -1909,12 +1905,23 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
              /* Mark this block as output.  */
              TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
            }
              /* Mark this block as output.  */
              TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
            }
+         if (write_symbols == DBX_DEBUG
+             || write_symbols == SDB_DEBUG)
+           {
+             location_t *locus_ptr
+               = block_nonartificial_location (NOTE_BLOCK (insn));
+
+             if (locus_ptr != NULL)
+               {
+                 override_filename = LOCATION_FILE (*locus_ptr);
+                 override_linenum = LOCATION_LINE (*locus_ptr);
+               }
+           }
          break;
 
        case NOTE_INSN_BLOCK_END:
          if (debug_info_level == DINFO_LEVEL_NORMAL
              || debug_info_level == DINFO_LEVEL_VERBOSE
          break;
 
        case NOTE_INSN_BLOCK_END:
          if (debug_info_level == DINFO_LEVEL_NORMAL
              || debug_info_level == DINFO_LEVEL_VERBOSE
-             || write_symbols == DWARF_DEBUG
              || write_symbols == DWARF2_DEBUG
              || write_symbols == VMS_AND_DWARF2_DEBUG
              || write_symbols == VMS_DEBUG)
              || write_symbols == DWARF2_DEBUG
              || write_symbols == VMS_AND_DWARF2_DEBUG
              || write_symbols == VMS_DEBUG)
@@ -1925,11 +1932,28 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
 
              /* End of a symbol-block.  */
              --block_depth;
 
              /* End of a symbol-block.  */
              --block_depth;
-             if (block_depth < 0)
-               abort ();
+             gcc_assert (block_depth >= 0);
 
              (*debug_hooks->end_block) (high_block_linenum, n);
            }
 
              (*debug_hooks->end_block) (high_block_linenum, n);
            }
+         if (write_symbols == DBX_DEBUG
+             || write_symbols == SDB_DEBUG)
+           {
+             tree outer_block = BLOCK_SUPERCONTEXT (NOTE_BLOCK (insn));
+             location_t *locus_ptr
+               = block_nonartificial_location (outer_block);
+
+             if (locus_ptr != NULL)
+               {
+                 override_filename = LOCATION_FILE (*locus_ptr);
+                 override_linenum = LOCATION_LINE (*locus_ptr);
+               }
+             else
+               {
+                 override_filename = NULL;
+                 override_linenum = 0;
+               }
+           }
          break;
 
        case NOTE_INSN_DELETED_LABEL:
          break;
 
        case NOTE_INSN_DELETED_LABEL:
@@ -1939,57 +1963,12 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
          ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
          break;
 
          ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
          break;
 
-       case 0:
+       case NOTE_INSN_VAR_LOCATION:
+         (*debug_hooks->var_location) (insn);
          break;
 
        default:
          break;
 
        default:
-         if (NOTE_LINE_NUMBER (insn) <= 0)
-           abort ();
-
-         /* This note is a line-number.  */
-         {
-           rtx note;
-           int note_after = 0;
-
-           /* If there is anything real after this note, output it.
-              If another line note follows, omit this one.  */
-           for (note = NEXT_INSN (insn); note; note = NEXT_INSN (note))
-             {
-               if (GET_CODE (note) != NOTE && GET_CODE (note) != CODE_LABEL)
-                 break;
-
-               /* These types of notes can be significant
-                  so make sure the preceding line number stays.  */
-               else if (GET_CODE (note) == NOTE
-                        && (NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_BEG
-                            || NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_END
-                            || NOTE_LINE_NUMBER (note) == NOTE_INSN_FUNCTION_BEG))
-                 break;
-               else if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) > 0)
-                 {
-                   /* Another line note follows; we can delete this note
-                      if no intervening line numbers have notes elsewhere.  */
-                   int num;
-                   for (num = NOTE_LINE_NUMBER (insn) + 1;
-                        num < NOTE_LINE_NUMBER (note);
-                        num++)
-                     if (line_note_exists[num])
-                       break;
-
-                   if (num >= NOTE_LINE_NUMBER (note))
-                     note_after = 1;
-                   break;
-                 }
-             }
-
-           /* Output this line note if it is the first or the last line
-              note in a row.  */
-           if (!note_after)
-             {
-               notice_source_line (insn);
-               (*debug_hooks->source_line) (last_linenum, last_filename);
-             }
-         }
+         gcc_unreachable ();
          break;
        }
       break;
          break;
        }
       break;
@@ -1997,7 +1976,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
     case BARRIER:
 #if defined (DWARF2_UNWIND_INFO)
       if (dwarf2out_do_frame ())
     case BARRIER:
 #if defined (DWARF2_UNWIND_INFO)
       if (dwarf2out_do_frame ())
-       dwarf2out_frame_debug (insn);
+       dwarf2out_frame_debug (insn, false);
 #endif
       break;
 
 #endif
       break;
 
@@ -2015,58 +1994,28 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
            {
 #ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
              ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip);
            {
 #ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
              ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip);
+#else
+#ifdef ASM_OUTPUT_ALIGN_WITH_NOP
+              ASM_OUTPUT_ALIGN_WITH_NOP (file, align);
 #else
              ASM_OUTPUT_ALIGN (file, align);
 #else
              ASM_OUTPUT_ALIGN (file, align);
+#endif
 #endif
            }
        }
 #ifdef HAVE_cc0
       CC_STATUS_INIT;
 #endif
            }
        }
 #ifdef HAVE_cc0
       CC_STATUS_INIT;
-      /* If this label is reached from only one place, set the condition
-        codes from the instruction just before the branch.  */
-
-      /* Disabled because some insns set cc_status in the C output code
-        and NOTICE_UPDATE_CC alone can set incorrect status.  */
-      if (0 /* optimize && LABEL_NUSES (insn) == 1*/)
-       {
-         rtx jump = LABEL_REFS (insn);
-         rtx barrier = prev_nonnote_insn (insn);
-         rtx prev;
-         /* If the LABEL_REFS field of this label has been set to point
-            at a branch, the predecessor of the branch is a regular
-            insn, and that branch is the only way to reach this label,
-            set the condition codes based on the branch and its
-            predecessor.  */
-         if (barrier && GET_CODE (barrier) == BARRIER
-             && jump && GET_CODE (jump) == JUMP_INSN
-             && (prev = prev_nonnote_insn (jump))
-             && GET_CODE (prev) == INSN)
-           {
-             NOTICE_UPDATE_CC (PATTERN (prev), prev);
-             NOTICE_UPDATE_CC (PATTERN (jump), jump);
-           }
-       }
-#endif
-      if (prescan > 0)
-       break;
-      new_block = 1;
-
-#ifdef FINAL_PRESCAN_LABEL
-      FINAL_PRESCAN_INSN (insn, NULL, 0);
 #endif
 
       if (LABEL_NAME (insn))
        (*debug_hooks->label) (insn);
 
 #endif
 
       if (LABEL_NAME (insn))
        (*debug_hooks->label) (insn);
 
-      if (app_on)
-       {
-         fputs (ASM_APP_OFF, file);
-         app_on = 0;
-       }
-      if (NEXT_INSN (insn) != 0
-         && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN)
+      app_disable ();
+
+      next = next_nonnote_insn (insn);
+      if (next != 0 && JUMP_P (next))
        {
        {
-         rtx nextbody = PATTERN (NEXT_INSN (insn));
+         rtx nextbody = PATTERN (next);
 
          /* If this label is followed by a jump-table,
             make sure we put the label in the read-only section.  Also
 
          /* If this label is followed by a jump-table,
             make sure we put the label in the read-only section.  Also
@@ -2084,63 +2033,66 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
                {
                  int log_align;
 
                {
                  int log_align;
 
-                 readonly_data_section ();
+                 switch_to_section (targetm.asm_out.function_rodata_section
+                                    (current_function_decl));
 
 #ifdef ADDR_VEC_ALIGN
 
 #ifdef ADDR_VEC_ALIGN
-                 log_align = ADDR_VEC_ALIGN (NEXT_INSN (insn));
+                 log_align = ADDR_VEC_ALIGN (next);
 #else
                  log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
 #endif
                  ASM_OUTPUT_ALIGN (file, log_align);
                }
              else
 #else
                  log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
 #endif
                  ASM_OUTPUT_ALIGN (file, log_align);
                }
              else
-               function_section (current_function_decl);
+               switch_to_section (current_function_section ());
 
 #ifdef ASM_OUTPUT_CASE_LABEL
              ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
 
 #ifdef ASM_OUTPUT_CASE_LABEL
              ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
-                                    NEXT_INSN (insn));
+                                    next);
 #else
 #else
-             if (LABEL_ALTERNATE_NAME (insn))
-               ASM_OUTPUT_ALTERNATE_LABEL_NAME (file, insn);
-             else
-               ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
+             targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
 #endif
 #endif
              break;
            }
        }
 #endif
 #endif
              break;
            }
        }
-      if (LABEL_ALTERNATE_NAME (insn))
-       ASM_OUTPUT_ALTERNATE_LABEL_NAME (file, insn);
+      if (LABEL_ALT_ENTRY_P (insn))
+       output_alternate_entry_point (file, insn);
       else
       else
-       ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
+       targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
       break;
 
     default:
       {
        rtx body = PATTERN (insn);
        int insn_code_number;
       break;
 
     default:
       {
        rtx body = PATTERN (insn);
        int insn_code_number;
-       const char *template;
-       rtx note;
+       const char *templ;
 
 
+#ifdef HAVE_conditional_execution
+       /* Reset this early so it is correct for ASM statements.  */
+       current_insn_predicate = NULL_RTX;
+#endif
        /* An INSN, JUMP_INSN or CALL_INSN.
           First check for special kinds that recog doesn't recognize.  */
 
        /* An INSN, JUMP_INSN or CALL_INSN.
           First check for special kinds that recog doesn't recognize.  */
 
-       if (GET_CODE (body) == USE /* These are just declarations */
+       if (GET_CODE (body) == USE /* These are just declarations */
            || GET_CODE (body) == CLOBBER)
          break;
 
 #ifdef HAVE_cc0
            || GET_CODE (body) == CLOBBER)
          break;
 
 #ifdef HAVE_cc0
-       /* If there is a REG_CC_SETTER note on this insn, it means that
-          the setting of the condition code was done in the delay slot
-          of the insn that branched here.  So recover the cc status
-          from the insn that set it.  */
+       {
+         /* If there is a REG_CC_SETTER note on this insn, it means that
+            the setting of the condition code was done in the delay slot
+            of the insn that branched here.  So recover the cc status
+            from the insn that set it.  */
 
 
-       note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
-       if (note)
-         {
-           NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0));
-           cc_prev_status = cc_status;
-         }
+         rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
+         if (note)
+           {
+             NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0));
+             cc_prev_status = cc_status;
+           }
+       }
 #endif
 
        /* Detect insns that are really jump-tables
 #endif
 
        /* Detect insns that are really jump-tables
@@ -2152,14 +2104,13 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
            int vlen, idx;
 #endif
 
            int vlen, idx;
 #endif
 
-           if (prescan > 0)
-             break;
+           if (! JUMP_TABLES_IN_TEXT_SECTION)
+             switch_to_section (targetm.asm_out.function_rodata_section
+                                (current_function_decl));
+           else
+             switch_to_section (current_function_section ());
 
 
-           if (app_on)
-             {
-               fputs (ASM_APP_OFF, file);
-               app_on = 0;
-             }
+           app_disable ();
 
 #if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
            if (GET_CODE (body) == ADDR_VEC)
 
 #if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
            if (GET_CODE (body) == ADDR_VEC)
@@ -2167,7 +2118,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
 #ifdef ASM_OUTPUT_ADDR_VEC
                ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body);
 #else
 #ifdef ASM_OUTPUT_ADDR_VEC
                ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body);
 #else
-               abort ();
+               gcc_unreachable ();
 #endif
              }
            else
 #endif
              }
            else
@@ -2175,7 +2126,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
 #ifdef ASM_OUTPUT_ADDR_DIFF_VEC
                ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body);
 #else
 #ifdef ASM_OUTPUT_ADDR_DIFF_VEC
                ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body);
 #else
-               abort ();
+               gcc_unreachable ();
 #endif
              }
 #else
 #endif
              }
 #else
@@ -2188,7 +2139,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
                    ASM_OUTPUT_ADDR_VEC_ELT
                      (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
 #else
                    ASM_OUTPUT_ADDR_VEC_ELT
                      (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
 #else
-                   abort ();
+                   gcc_unreachable ();
 #endif
                  }
                else
 #endif
                  }
                else
@@ -2200,7 +2151,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
                       CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
                       CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
 #else
                       CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
                       CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
 #else
-                   abort ();
+                   gcc_unreachable ();
 #endif
                  }
              }
 #endif
                  }
              }
@@ -2211,10 +2162,16 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
 #endif
 #endif
 
 #endif
 #endif
 
-           function_section (current_function_decl);
+           switch_to_section (current_function_section ());
 
            break;
          }
 
            break;
          }
+       /* Output this line note if it is the first or the last line
+          note in a row.  */
+       if (notice_source_line (insn))
+         {
+           (*debug_hooks->source_line) (last_linenum, last_filename);
+         }
 
        if (GET_CODE (body) == ASM_INPUT)
          {
 
        if (GET_CODE (body) == ASM_INPUT)
          {
@@ -2222,17 +2179,21 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
 
            /* There's no telling what that did to the condition codes.  */
            CC_STATUS_INIT;
 
            /* There's no telling what that did to the condition codes.  */
            CC_STATUS_INIT;
-           if (prescan > 0)
-             break;
 
            if (string[0])
              {
 
            if (string[0])
              {
-               if (! app_on)
-                 {
-                   fputs (ASM_APP_ON, file);
-                   app_on = 1;
-                 }
+               expanded_location loc;
+
+               app_enable ();
+               loc = expand_location (ASM_INPUT_SOURCE_LOCATION (body));
+               if (*loc.file && loc.line)
+                 fprintf (asm_out_file, "%s %i \"%s\" 1\n",
+                          ASM_COMMENT_START, loc.line, loc.file);
                fprintf (asm_out_file, "\t%s\n", string);
                fprintf (asm_out_file, "\t%s\n", string);
+#if HAVE_AS_LINE_ZERO
+               if (*loc.file && loc.line)
+                 fprintf (asm_out_file, "%s 0 \"\" 2\n", ASM_COMMENT_START);
+#endif
              }
            break;
          }
              }
            break;
          }
@@ -2241,57 +2202,66 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
        if (asm_noperands (body) >= 0)
          {
            unsigned int noperands = asm_noperands (body);
        if (asm_noperands (body) >= 0)
          {
            unsigned int noperands = asm_noperands (body);
-           rtx *ops = (rtx *) alloca (noperands * sizeof (rtx));
+           rtx *ops = XALLOCAVEC (rtx, noperands);
            const char *string;
            const char *string;
+           location_t loc;
+           expanded_location expanded;
 
            /* There's no telling what that did to the condition codes.  */
            CC_STATUS_INIT;
 
            /* There's no telling what that did to the condition codes.  */
            CC_STATUS_INIT;
-           if (prescan > 0)
-             break;
 
            /* Get out the operand values.  */
 
            /* Get out the operand values.  */
-           string = decode_asm_operands (body, ops, NULL, NULL, NULL);
-           /* Inhibit aborts on what would otherwise be compiler bugs.  */
+           string = decode_asm_operands (body, ops, NULL, NULL, NULL, &loc);
+           /* Inhibit dying on what would otherwise be compiler bugs.  */
            insn_noperands = noperands;
            this_is_asm_operands = insn;
            insn_noperands = noperands;
            this_is_asm_operands = insn;
+           expanded = expand_location (loc);
+
+#ifdef FINAL_PRESCAN_INSN
+           FINAL_PRESCAN_INSN (insn, ops, insn_noperands);
+#endif
 
            /* Output the insn using them.  */
            if (string[0])
              {
 
            /* Output the insn using them.  */
            if (string[0])
              {
-               if (! app_on)
-                 {
-                   fputs (ASM_APP_ON, file);
-                   app_on = 1;
-                 }
+               app_enable ();
+               if (expanded.file && expanded.line)
+                 fprintf (asm_out_file, "%s %i \"%s\" 1\n",
+                          ASM_COMMENT_START, expanded.line, expanded.file);
                output_asm_insn (string, ops);
                output_asm_insn (string, ops);
+#if HAVE_AS_LINE_ZERO
+               if (expanded.file && expanded.line)
+                 fprintf (asm_out_file, "%s 0 \"\" 2\n", ASM_COMMENT_START);
+#endif
              }
 
            this_is_asm_operands = 0;
            break;
          }
 
              }
 
            this_is_asm_operands = 0;
            break;
          }
 
-       if (prescan <= 0 && app_on)
-         {
-           fputs (ASM_APP_OFF, file);
-           app_on = 0;
-         }
+       app_disable ();
 
        if (GET_CODE (body) == SEQUENCE)
          {
            /* A delayed-branch sequence */
            int i;
 
        if (GET_CODE (body) == SEQUENCE)
          {
            /* A delayed-branch sequence */
            int i;
-           rtx next;
 
 
-           if (prescan > 0)
-             break;
            final_sequence = body;
 
            final_sequence = body;
 
+           /* Record the delay slots' frame information before the branch.
+              This is needed for delayed calls: see execute_cfa_program().  */
+#if defined (DWARF2_UNWIND_INFO)
+           if (dwarf2out_do_frame ())
+             for (i = 1; i < XVECLEN (body, 0); i++)
+               dwarf2out_frame_debug (XVECEXP (body, 0, i), false);
+#endif
+
            /* The first insn in this SEQUENCE might be a JUMP_INSN that will
               force the restoration of a comparison that was previously
               thought unnecessary.  If that happens, cancel this sequence
               and cause that insn to be restored.  */
 
            /* The first insn in this SEQUENCE might be a JUMP_INSN that will
               force the restoration of a comparison that was previously
               thought unnecessary.  If that happens, cancel this sequence
               and cause that insn to be restored.  */
 
-           next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1);
+           next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, 1, seen);
            if (next != XVECEXP (body, 0, 1))
              {
                final_sequence = 0;
            if (next != XVECEXP (body, 0, 1))
              {
                final_sequence = 0;
@@ -2305,7 +2275,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
                /* We loop in case any instruction in a delay slot gets
                   split.  */
                do
                /* We loop in case any instruction in a delay slot gets
                   split.  */
                do
-                 insn = final_scan_insn (insn, file, 0, prescan, 1);
+                 insn = final_scan_insn (insn, file, 0, 1, seen);
                while (insn != next);
              }
 #ifdef DBR_OUTPUT_SEQEND
                while (insn != next);
              }
 #ifdef DBR_OUTPUT_SEQEND
@@ -2318,7 +2288,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
               called function.  Hence we don't preserve any CC-setting
               actions in these insns and the CC must be marked as being
               clobbered by the function.  */
               called function.  Hence we don't preserve any CC-setting
               actions in these insns and the CC must be marked as being
               clobbered by the function.  */
-           if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN)
+           if (CALL_P (XVECEXP (body, 0, 0)))
              {
                CC_STATUS_INIT;
              }
              {
                CC_STATUS_INIT;
              }
@@ -2342,10 +2312,6 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
 
        if (optimize)
          {
 
        if (optimize)
          {
-#if 0
-           rtx set = single_set (insn);
-#endif
-
            if (set
                && GET_CODE (SET_DEST (set)) == CC0
                && insn != last_ignored_compare)
            if (set
                && GET_CODE (SET_DEST (set)) == CC0
                && insn != last_ignored_compare)
@@ -2380,20 +2346,6 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
          }
 #endif
 
          }
 #endif
 
-#ifndef STACK_REGS
-       /* Don't bother outputting obvious no-ops, even without -O.
-          This optimization is fast and doesn't interfere with debugging.
-          Don't do this if the insn is in a delay slot, since this
-          will cause an improper number of delay insns to be written.  */
-       if (final_sequence == 0
-           && prescan >= 0
-           && GET_CODE (insn) == INSN && GET_CODE (body) == SET
-           && GET_CODE (SET_SRC (body)) == REG
-           && GET_CODE (SET_DEST (body)) == REG
-           && REGNO (SET_SRC (body)) == REGNO (SET_DEST (body)))
-         break;
-#endif
-
 #ifdef HAVE_cc0
        /* If this is a conditional branch, maybe modify it
           if the cc's are in a nonstandard state
 #ifdef HAVE_cc0
        /* If this is a conditional branch, maybe modify it
           if the cc's are in a nonstandard state
@@ -2401,15 +2353,12 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
           do straightforwardly if the cc's were set up normally.  */
 
        if (cc_status.flags != 0
           do straightforwardly if the cc's were set up normally.  */
 
        if (cc_status.flags != 0
-           && GET_CODE (insn) == JUMP_INSN
+           && JUMP_P (insn)
            && GET_CODE (body) == SET
            && SET_DEST (body) == pc_rtx
            && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
            && GET_CODE (body) == SET
            && SET_DEST (body) == pc_rtx
            && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
-           && GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<'
-           && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx
-           /* This is done during prescan; it is not done again
-              in final scan when prescan has been done.  */
-           && prescan >= 0)
+           && COMPARISON_P (XEXP (SET_SRC (body), 0))
+           && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx)
          {
            /* This function may alter the contents of its argument
               and clear some of the cc_status.flags bits.
          {
            /* This function may alter the contents of its argument
               and clear some of the cc_status.flags bits.
@@ -2441,6 +2390,41 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
              INSN_CODE (insn) = -1;
          }
 
              INSN_CODE (insn) = -1;
          }
 
+       /* If this is a conditional trap, maybe modify it if the cc's
+          are in a nonstandard state so that it accomplishes the same
+          thing that it would do straightforwardly if the cc's were
+          set up normally.  */
+       if (cc_status.flags != 0
+           && NONJUMP_INSN_P (insn)
+           && GET_CODE (body) == TRAP_IF
+           && COMPARISON_P (TRAP_CONDITION (body))
+           && XEXP (TRAP_CONDITION (body), 0) == cc0_rtx)
+         {
+           /* This function may alter the contents of its argument
+              and clear some of the cc_status.flags bits.
+              It may also return 1 meaning condition now always true
+              or -1 meaning condition now always false
+              or 2 meaning condition nontrivial but altered.  */
+           int result = alter_cond (TRAP_CONDITION (body));
+
+           /* If TRAP_CONDITION has become always false, delete the
+              instruction.  */
+           if (result == -1)
+             {
+               delete_insn (insn);
+               break;
+             }
+
+           /* If TRAP_CONDITION has become always true, replace
+              TRAP_CONDITION with const_true_rtx.  */
+           if (result == 1)
+             TRAP_CONDITION (body) = const_true_rtx;
+
+           /* Rerecognize the instruction if it has changed.  */
+           if (result != 0)
+             INSN_CODE (insn) = -1;
+         }
+
        /* Make same adjustments to instructions that examine the
           condition codes without jumping and instructions that
           handle conditional moves (if this machine has either one).  */
        /* Make same adjustments to instructions that examine the
           condition codes without jumping and instructions that
           handle conditional moves (if this machine has either one).  */
@@ -2450,7 +2434,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
          {
            rtx cond_rtx, then_rtx, else_rtx;
 
          {
            rtx cond_rtx, then_rtx, else_rtx;
 
-           if (GET_CODE (insn) != JUMP_INSN
+           if (!JUMP_P (insn)
                && GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
              {
                cond_rtx = XEXP (SET_SRC (set), 0);
                && GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
              {
                cond_rtx = XEXP (SET_SRC (set), 0);
@@ -2509,14 +2493,16 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
               emit them before the peephole.  */
            if (next != 0 && next != NEXT_INSN (insn))
              {
               emit them before the peephole.  */
            if (next != 0 && next != NEXT_INSN (insn))
              {
-               rtx prev = PREV_INSN (insn);
+               rtx note, prev = PREV_INSN (insn);
 
                for (note = NEXT_INSN (insn); note != next;
                     note = NEXT_INSN (note))
 
                for (note = NEXT_INSN (insn); note != next;
                     note = NEXT_INSN (note))
-                 final_scan_insn (note, file, optimize, prescan, nopeepholes);
+                 final_scan_insn (note, file, optimize, nopeepholes, seen);
 
 
-               /* In case this is prescan, put the notes
-                  in proper position for later rescan.  */
+               /* Put the notes in the proper position for a later
+                  rescan.  For example, the SH target can do this
+                  when generating a far jump in a delayed branch
+                  sequence.  */
                note = NEXT_INSN (insn);
                PREV_INSN (note) = prev;
                NEXT_INSN (prev) = note;
                note = NEXT_INSN (insn);
                PREV_INSN (note) = prev;
                NEXT_INSN (prev) = note;
@@ -2539,13 +2525,13 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
        insn_code_number = recog_memoized (insn);
        cleanup_subreg_operands (insn);
 
        insn_code_number = recog_memoized (insn);
        cleanup_subreg_operands (insn);
 
-       /* Dump the insn in the assembly for debugging.  */
-       if (flag_dump_rtl_in_asm)
-         {
-           print_rtx_head = ASM_COMMENT_START;
-           print_rtl_single (asm_out_file, insn);
-           print_rtx_head = "";
-         }
+       /* Dump the insn in the assembly for debugging.  */
+       if (flag_dump_rtl_in_asm)
+         {
+           print_rtx_head = ASM_COMMENT_START;
+           print_rtl_single (asm_out_file, insn);
+           print_rtx_head = "";
+         }
 
        if (! constrain_operands_cached (1))
          fatal_insn_not_found (insn);
 
        if (! constrain_operands_cached (1))
          fatal_insn_not_found (insn);
@@ -2560,8 +2546,6 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
 #ifdef HAVE_conditional_execution
        if (GET_CODE (PATTERN (insn)) == COND_EXEC)
          current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));
 #ifdef HAVE_conditional_execution
        if (GET_CODE (PATTERN (insn)) == COND_EXEC)
          current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));
-       else
-         current_insn_predicate = NULL_RTX;
 #endif
 
 #ifdef HAVE_cc0
 #endif
 
 #ifdef HAVE_cc0
@@ -2578,23 +2562,21 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
        current_output_insn = debug_insn = insn;
 
 #if defined (DWARF2_UNWIND_INFO)
        current_output_insn = debug_insn = insn;
 
 #if defined (DWARF2_UNWIND_INFO)
-       if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ())
-         dwarf2out_frame_debug (insn);
+       if (CALL_P (insn) && dwarf2out_do_frame ())
+         dwarf2out_frame_debug (insn, false);
 #endif
 
        /* Find the proper template for this insn.  */
 #endif
 
        /* Find the proper template for this insn.  */
-       template = get_insn_template (insn_code_number, insn);
+       templ = get_insn_template (insn_code_number, insn);
 
        /* If the C code returns 0, it means that it is a jump insn
           which follows a deleted test insn, and that test insn
           needs to be reinserted.  */
 
        /* If the C code returns 0, it means that it is a jump insn
           which follows a deleted test insn, and that test insn
           needs to be reinserted.  */
-       if (template == 0)
+       if (templ == 0)
          {
            rtx prev;
 
          {
            rtx prev;
 
-           if (prev_nonnote_insn (insn) != last_ignored_compare)
-             abort ();
-           new_block = 0;
+           gcc_assert (prev_nonnote_insn (insn) == last_ignored_compare);
 
            /* We have already processed the notes between the setter and
               the user.  Make sure we don't process them again, this is
 
            /* We have already processed the notes between the setter and
               the user.  Make sure we don't process them again, this is
@@ -2604,7 +2586,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
                 prev != last_ignored_compare;
                 prev = PREV_INSN (prev))
              {
                 prev != last_ignored_compare;
                 prev = PREV_INSN (prev))
              {
-               if (GET_CODE (prev) == NOTE)
+               if (NOTE_P (prev))
                  delete_insn (prev);   /* Use delete_note.  */
              }
 
                  delete_insn (prev);   /* Use delete_note.  */
              }
 
@@ -2613,152 +2595,193 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
 
        /* If the template is the string "#", it means that this insn must
           be split.  */
 
        /* If the template is the string "#", it means that this insn must
           be split.  */
-       if (template[0] == '#' && template[1] == '\0')
+       if (templ[0] == '#' && templ[1] == '\0')
          {
          {
-           rtx new = try_split (body, insn, 0);
+           rtx new_rtx = try_split (body, insn, 0);
 
            /* If we didn't split the insn, go away.  */
 
            /* If we didn't split the insn, go away.  */
-           if (new == insn && PATTERN (new) == body)
+           if (new_rtx == insn && PATTERN (new_rtx) == body)
              fatal_insn ("could not split insn", insn);
 
 #ifdef HAVE_ATTR_length
            /* This instruction should have been split in shorten_branches,
               to ensure that we would have valid length info for the
               splitees.  */
              fatal_insn ("could not split insn", insn);
 
 #ifdef HAVE_ATTR_length
            /* This instruction should have been split in shorten_branches,
               to ensure that we would have valid length info for the
               splitees.  */
-           abort ();
+           gcc_unreachable ();
 #endif
 
 #endif
 
-           new_block = 0;
-           return new;
+           return new_rtx;
          }
 
          }
 
-       if (prescan > 0)
-         break;
-
-#ifdef IA64_UNWIND_INFO
-       IA64_UNWIND_EMIT (asm_out_file, insn);
+#ifdef TARGET_UNWIND_INFO
+       /* ??? This will put the directives in the wrong place if
+          get_insn_template outputs assembly directly.  However calling it
+          before get_insn_template breaks if the insns is split.  */
+       targetm.asm_out.unwind_emit (asm_out_file, insn);
 #endif
 #endif
-       /* Output assembler code from the template.  */
 
 
-       output_asm_insn (template, recog_data.operand);
+       if (CALL_P (insn))
+         {
+           rtx x = call_from_call_insn (insn);
+           x = XEXP (x, 0);
+           if (x && MEM_P (x) && GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
+             {
+               tree t;
+               x = XEXP (x, 0);
+               t = SYMBOL_REF_DECL (x);
+               if (t)
+                 assemble_external (t);
+             }
+         }
+
+       /* Output assembler code from the template.  */
+       output_asm_insn (templ, recog_data.operand);
 
 
+       /* If necessary, report the effect that the instruction has on
+          the unwind info.   We've already done this for delay slots
+          and call instructions.  */
 #if defined (DWARF2_UNWIND_INFO)
 #if defined (DWARF2_UNWIND_INFO)
-#if defined (HAVE_prologue)
-       if (GET_CODE (insn) == INSN && dwarf2out_do_frame ())
-         dwarf2out_frame_debug (insn);
-#else
-       if (!ACCUMULATE_OUTGOING_ARGS
-           && GET_CODE (insn) == INSN
-           && dwarf2out_do_frame ())
-         dwarf2out_frame_debug (insn);
-#endif
+       if (final_sequence == 0
+#if !defined (HAVE_prologue)
+           && !ACCUMULATE_OUTGOING_ARGS
 #endif
 #endif
-
-#if 0
-       /* It's not at all clear why we did this and doing so interferes
-          with tests we'd like to do to use REG_WAS_0 notes, so let's try
-          with this out.  */
-
-       /* Mark this insn as having been output.  */
-       INSN_DELETED_P (insn) = 1;
+           && dwarf2out_do_frame ())
+         dwarf2out_frame_debug (insn, true);
 #endif
 
 #endif
 
-       /* Emit information for vtable gc.  */
-       note = find_reg_note (insn, REG_VTABLE_REF, NULL_RTX);
-       if (note)
-         assemble_vtable_entry (XEXP (XEXP (note, 0), 0),
-                                INTVAL (XEXP (XEXP (note, 0), 1)));
-
        current_output_insn = debug_insn = 0;
       }
     }
   return NEXT_INSN (insn);
 }
 \f
        current_output_insn = debug_insn = 0;
       }
     }
   return NEXT_INSN (insn);
 }
 \f
-/* Output debugging info to the assembler file FILE
-   based on the NOTE-insn INSN, assumed to be a line number.  */
+/* Return whether a source line note needs to be emitted before INSN.  */
 
 
-static void
-notice_source_line (insn)
-     rtx insn;
+static bool
+notice_source_line (rtx insn)
 {
 {
-  const char *filename = NOTE_SOURCE_FILE (insn);
+  const char *filename;
+  int linenum;
 
 
-  last_filename = filename;
-  last_linenum = NOTE_LINE_NUMBER (insn);
-  high_block_linenum = MAX (last_linenum, high_block_linenum);
-  high_function_linenum = MAX (last_linenum, high_function_linenum);
+  if (override_filename)
+    {
+      filename = override_filename;
+      linenum = override_linenum;
+    }
+  else
+    {
+      filename = insn_file (insn);
+      linenum = insn_line (insn);
+    }
+
+  if (filename
+      && (force_source_line
+         || filename != last_filename
+         || last_linenum != linenum))
+    {
+      force_source_line = false;
+      last_filename = filename;
+      last_linenum = linenum;
+      high_block_linenum = MAX (last_linenum, high_block_linenum);
+      high_function_linenum = MAX (last_linenum, high_function_linenum);
+      return true;
+    }
+  return false;
 }
 \f
 /* For each operand in INSN, simplify (subreg (reg)) so that it refers
    directly to the desired hard register.  */
 
 void
 }
 \f
 /* For each operand in INSN, simplify (subreg (reg)) so that it refers
    directly to the desired hard register.  */
 
 void
-cleanup_subreg_operands (insn)
-     rtx insn;
+cleanup_subreg_operands (rtx insn)
 {
   int i;
 {
   int i;
+  bool changed = false;
   extract_insn_cached (insn);
   for (i = 0; i < recog_data.n_operands; i++)
     {
   extract_insn_cached (insn);
   for (i = 0; i < recog_data.n_operands; i++)
     {
-      /* The following test cannot use recog_data.operand when tesing
+      /* The following test cannot use recog_data.operand when testing
         for a SUBREG: the underlying object might have been changed
         already if we are inside a match_operator expression that
         matches the else clause.  Instead we test the underlying
         expression directly.  */
       if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG)
         for a SUBREG: the underlying object might have been changed
         already if we are inside a match_operator expression that
         matches the else clause.  Instead we test the underlying
         expression directly.  */
       if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG)
-       recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]);
+       {
+         recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]);
+         changed = true;
+       }
       else if (GET_CODE (recog_data.operand[i]) == PLUS
               || GET_CODE (recog_data.operand[i]) == MULT
       else if (GET_CODE (recog_data.operand[i]) == PLUS
               || GET_CODE (recog_data.operand[i]) == MULT
-              || GET_CODE (recog_data.operand[i]) == MEM)
-       recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]);
+              || MEM_P (recog_data.operand[i]))
+       recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i], &changed);
     }
 
   for (i = 0; i < recog_data.n_dups; i++)
     {
       if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG)
     }
 
   for (i = 0; i < recog_data.n_dups; i++)
     {
       if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG)
-       *recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]);
+       {
+         *recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]);
+         changed = true;
+       }
       else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS
               || GET_CODE (*recog_data.dup_loc[i]) == MULT
       else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS
               || GET_CODE (*recog_data.dup_loc[i]) == MULT
-              || GET_CODE (*recog_data.dup_loc[i]) == MEM)
-       *recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]);
+              || MEM_P (*recog_data.dup_loc[i]))
+       *recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i], &changed);
     }
     }
+  if (changed)
+    df_insn_rescan (insn);
 }
 
 /* If X is a SUBREG, replace it with a REG or a MEM,
    based on the thing it is a subreg of.  */
 
 rtx
 }
 
 /* If X is a SUBREG, replace it with a REG or a MEM,
    based on the thing it is a subreg of.  */
 
 rtx
-alter_subreg (xp)
-     rtx *xp;
+alter_subreg (rtx *xp)
 {
   rtx x = *xp;
   rtx y = SUBREG_REG (x);
 
   /* simplify_subreg does not remove subreg from volatile references.
      We are required to.  */
 {
   rtx x = *xp;
   rtx y = SUBREG_REG (x);
 
   /* simplify_subreg does not remove subreg from volatile references.
      We are required to.  */
-  if (GET_CODE (y) == MEM)
-    *xp = adjust_address (y, GET_MODE (x), SUBREG_BYTE (x));
+  if (MEM_P (y))
+    {
+      int offset = SUBREG_BYTE (x);
+
+      /* For paradoxical subregs on big-endian machines, SUBREG_BYTE
+        contains 0 instead of the proper offset.  See simplify_subreg.  */
+      if (offset == 0
+         && GET_MODE_SIZE (GET_MODE (y)) < GET_MODE_SIZE (GET_MODE (x)))
+        {
+          int difference = GET_MODE_SIZE (GET_MODE (y))
+                          - GET_MODE_SIZE (GET_MODE (x));
+          if (WORDS_BIG_ENDIAN)
+            offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+          if (BYTES_BIG_ENDIAN)
+            offset += difference % UNITS_PER_WORD;
+        }
+
+      *xp = adjust_address (y, GET_MODE (x), offset);
+    }
   else
     {
   else
     {
-      rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y),
+      rtx new_rtx = simplify_subreg (GET_MODE (x), y, GET_MODE (y),
                                 SUBREG_BYTE (x));
 
                                 SUBREG_BYTE (x));
 
-      if (new != 0)
-       *xp = new;
-      /* Simplify_subreg can't handle some REG cases, but we have to.  */
-      else if (GET_CODE (y) == REG)
+      if (new_rtx != 0)
+       *xp = new_rtx;
+      else if (REG_P (y))
        {
        {
-         unsigned int regno = subreg_hard_regno (x, 1);
-         PUT_CODE (x, REG);
-         REGNO (x) = regno;
-         ORIGINAL_REGNO (x) = ORIGINAL_REGNO (y);
-         /* This field has a different meaning for REGs and SUBREGs.  Make
-            sure to clear it!  */
-         x->used = 0;
+         /* Simplify_subreg can't handle some REG cases, but we have to.  */
+         unsigned int regno;
+         HOST_WIDE_INT offset;
+
+         regno = subreg_regno (x);
+         if (subreg_lowpart_p (x))
+           offset = byte_lowpart_offset (GET_MODE (x), GET_MODE (y));
+         else
+           offset = SUBREG_BYTE (x);
+         *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, offset);
        }
        }
-      else
-       abort ();
     }
 
   return *xp;
     }
 
   return *xp;
@@ -2767,23 +2790,25 @@ alter_subreg (xp)
 /* Do alter_subreg on all the SUBREGs contained in X.  */
 
 static rtx
 /* Do alter_subreg on all the SUBREGs contained in X.  */
 
 static rtx
-walk_alter_subreg (xp)
-     rtx *xp;
+walk_alter_subreg (rtx *xp, bool *changed)
 {
   rtx x = *xp;
   switch (GET_CODE (x))
     {
     case PLUS:
     case MULT:
 {
   rtx x = *xp;
   switch (GET_CODE (x))
     {
     case PLUS:
     case MULT:
-      XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
-      XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1));
+    case AND:
+      XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0), changed);
+      XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1), changed);
       break;
 
     case MEM:
       break;
 
     case MEM:
-      XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
+    case ZERO_EXTEND:
+      XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0), changed);
       break;
 
     case SUBREG:
       break;
 
     case SUBREG:
+      *changed = true;
       return alter_subreg (xp);
 
     default:
       return alter_subreg (xp);
 
     default:
@@ -2805,8 +2830,7 @@ walk_alter_subreg (xp)
    2 means that COND has been altered.  */
 
 static int
    2 means that COND has been altered.  */
 
 static int
-alter_cond (cond)
-     rtx cond;
+alter_cond (rtx cond)
 {
   int value = 0;
 
 {
   int value = 0;
 
@@ -2909,7 +2933,7 @@ alter_cond (cond)
     switch (GET_CODE (cond))
       {
       default:
     switch (GET_CODE (cond))
       {
       default:
-       abort ();
+       gcc_unreachable ();
 
       case NE:
        PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT);
 
       case NE:
        PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT);
@@ -2959,18 +2983,19 @@ alter_cond (cond)
    In an `asm', it's the user's fault; otherwise, the compiler's fault.  */
 
 void
    In an `asm', it's the user's fault; otherwise, the compiler's fault.  */
 
 void
-output_operand_lossage VPARAMS ((const char *msgid, ...))
+output_operand_lossage (const char *cmsgid, ...)
 {
   char *fmt_string;
   char *new_message;
   const char *pfx_str;
 {
   char *fmt_string;
   char *new_message;
   const char *pfx_str;
-  VA_OPEN (ap, msgid);
-  VA_FIXEDARG (ap, const char *, msgid);
+  va_list ap;
 
 
-  pfx_str = this_is_asm_operands ? _("invalid `asm': ") : "output_operand: ";
-  asprintf (&fmt_string, "%s%s", pfx_str, _(msgid));
+  va_start (ap, cmsgid);
+
+  pfx_str = this_is_asm_operands ? _("invalid 'asm': ") : "output_operand: ";
+  asprintf (&fmt_string, "%s%s", pfx_str, _(cmsgid));
   vasprintf (&new_message, fmt_string, ap);
   vasprintf (&new_message, fmt_string, ap);
-  
+
   if (this_is_asm_operands)
     error_for_asm (this_is_asm_operands, "%s", new_message);
   else
   if (this_is_asm_operands)
     error_for_asm (this_is_asm_operands, "%s", new_message);
   else
@@ -2978,7 +3003,7 @@ output_operand_lossage VPARAMS ((const char *msgid, ...))
 
   free (fmt_string);
   free (new_message);
 
   free (fmt_string);
   free (new_message);
-  VA_CLOSE (ap);
+  va_end (ap);
 }
 \f
 /* Output of assembler code from a template, and its subroutines.  */
 }
 \f
 /* Output of assembler code from a template, and its subroutines.  */
@@ -2987,7 +3012,7 @@ output_operand_lossage VPARAMS ((const char *msgid, ...))
    alternative used.  */
 
 static void
    alternative used.  */
 
 static void
-output_asm_name ()
+output_asm_name (void)
 {
   if (debug_insn)
     {
 {
   if (debug_insn)
     {
@@ -3012,21 +3037,16 @@ output_asm_name ()
    corresponds to the address of the object and 0 if to the object.  */
 
 static tree
    corresponds to the address of the object and 0 if to the object.  */
 
 static tree
-get_mem_expr_from_op (op, paddressp)
-     rtx op;
-     int *paddressp;
+get_mem_expr_from_op (rtx op, int *paddressp)
 {
   tree expr;
   int inner_addressp;
 
   *paddressp = 0;
 
 {
   tree expr;
   int inner_addressp;
 
   *paddressp = 0;
 
-  if (op == NULL)
-    return 0;
-
-  if (GET_CODE (op) == REG && ORIGINAL_REGNO (op) >= FIRST_PSEUDO_REGISTER)
-    return REGNO_DECL (ORIGINAL_REGNO (op));
-  else if (GET_CODE (op) != MEM)
+  if (REG_P (op))
+    return REG_EXPR (op);
+  else if (!MEM_P (op))
     return 0;
 
   if (MEM_EXPR (op) != 0)
     return 0;
 
   if (MEM_EXPR (op) != 0)
@@ -3045,8 +3065,8 @@ get_mem_expr_from_op (op, paddressp)
           && (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp)))
     return expr;
 
           && (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp)))
     return expr;
 
-  while (GET_RTX_CLASS (GET_CODE (op)) == '1'
-        || GET_RTX_CLASS (GET_CODE (op)) == '2')
+  while (GET_RTX_CLASS (GET_CODE (op)) == RTX_UNARY
+        || GET_RTX_CLASS (GET_CODE (op)) == RTX_BIN_ARITH)
     op = XEXP (op, 0);
 
   expr = get_mem_expr_from_op (op, &inner_addressp);
     op = XEXP (op, 0);
 
   expr = get_mem_expr_from_op (op, &inner_addressp);
@@ -3058,10 +3078,7 @@ get_mem_expr_from_op (op, paddressp)
    is the number of operands to write.  */
 
 static void
    is the number of operands to write.  */
 
 static void
-output_asm_operand_names (operands, oporder, nops)
-     rtx *operands;
-     int *oporder;
-     int nops;
+output_asm_operand_names (rtx *operands, int *oporder, int nops)
 {
   int wrote = 0;
   int i;
 {
   int wrote = 0;
   int i;
@@ -3069,16 +3086,22 @@ output_asm_operand_names (operands, oporder, nops)
   for (i = 0; i < nops; i++)
     {
       int addressp;
   for (i = 0; i < nops; i++)
     {
       int addressp;
-      tree expr = get_mem_expr_from_op (operands[oporder[i]], &addressp);
+      rtx op = operands[oporder[i]];
+      tree expr = get_mem_expr_from_op (op, &addressp);
 
 
+      fprintf (asm_out_file, "%c%s",
+              wrote ? ',' : '\t', wrote ? "" : ASM_COMMENT_START);
+      wrote = 1;
       if (expr)
        {
       if (expr)
        {
-         fprintf (asm_out_file, "%c%s %s",
-                  wrote ? ',' : '\t', wrote ? "" : ASM_COMMENT_START,
+         fprintf (asm_out_file, "%s",
                   addressp ? "*" : "");
          print_mem_expr (asm_out_file, expr);
          wrote = 1;
        }
                   addressp ? "*" : "");
          print_mem_expr (asm_out_file, expr);
          wrote = 1;
        }
+      else if (REG_P (op) && ORIGINAL_REGNO (op)
+              && ORIGINAL_REGNO (op) != REGNO (op))
+       fprintf (asm_out_file, " tmp%i", ORIGINAL_REGNO (op));
     }
 }
 
     }
 }
 
@@ -3099,9 +3122,7 @@ output_asm_operand_names (operands, oporder, nops)
       of the operand, with no other punctuation.  */
 
 void
       of the operand, with no other punctuation.  */
 
 void
-output_asm_insn (template, operands)
-     const char *template;
-     rtx *operands;
+output_asm_insn (const char *templ, rtx *operands)
 {
   const char *p;
   int c;
 {
   const char *p;
   int c;
@@ -3114,11 +3135,11 @@ output_asm_insn (template, operands)
 
   /* An insn may return a null string template
      in a case where no assembler code is needed.  */
 
   /* An insn may return a null string template
      in a case where no assembler code is needed.  */
-  if (*template == 0)
+  if (*templ == 0)
     return;
 
   memset (opoutput, 0, sizeof opoutput);
     return;
 
   memset (opoutput, 0, sizeof opoutput);
-  p = template;
+  p = templ;
   putc ('\t', asm_out_file);
 
 #ifdef ASM_OUTPUT_OPCODE
   putc ('\t', asm_out_file);
 
 #ifdef ASM_OUTPUT_OPCODE
@@ -3224,61 +3245,66 @@ output_asm_insn (template, operands)
        else if (ISALPHA (*p))
          {
            int letter = *p++;
        else if (ISALPHA (*p))
          {
            int letter = *p++;
-           c = atoi (p);
+           unsigned long opnum;
+           char *endptr;
 
 
-           if (! ISDIGIT (*p))
-             output_operand_lossage ("operand number missing after %%-letter");
-           else if (this_is_asm_operands
-                    && (c < 0 || (unsigned int) c >= insn_noperands))
+           opnum = strtoul (p, &endptr, 10);
+
+           if (endptr == p)
+             output_operand_lossage ("operand number missing "
+                                     "after %%-letter");
+           else if (this_is_asm_operands && opnum >= insn_noperands)
              output_operand_lossage ("operand number out of range");
            else if (letter == 'l')
              output_operand_lossage ("operand number out of range");
            else if (letter == 'l')
-             output_asm_label (operands[c]);
+             output_asm_label (operands[opnum]);
            else if (letter == 'a')
            else if (letter == 'a')
-             output_address (operands[c]);
+             output_address (operands[opnum]);
            else if (letter == 'c')
              {
            else if (letter == 'c')
              {
-               if (CONSTANT_ADDRESS_P (operands[c]))
-                 output_addr_const (asm_out_file, operands[c]);
+               if (CONSTANT_ADDRESS_P (operands[opnum]))
+                 output_addr_const (asm_out_file, operands[opnum]);
                else
                else
-                 output_operand (operands[c], 'c');
+                 output_operand (operands[opnum], 'c');
              }
            else if (letter == 'n')
              {
              }
            else if (letter == 'n')
              {
-               if (GET_CODE (operands[c]) == CONST_INT)
+               if (GET_CODE (operands[opnum]) == CONST_INT)
                  fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
                  fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
-                          - INTVAL (operands[c]));
+                          - INTVAL (operands[opnum]));
                else
                  {
                    putc ('-', asm_out_file);
                else
                  {
                    putc ('-', asm_out_file);
-                   output_addr_const (asm_out_file, operands[c]);
+                   output_addr_const (asm_out_file, operands[opnum]);
                  }
              }
            else
                  }
              }
            else
-             output_operand (operands[c], letter);
+             output_operand (operands[opnum], letter);
 
 
-           if (!opoutput[c])
-             oporder[ops++] = c;
-           opoutput[c] = 1;
+           if (!opoutput[opnum])
+             oporder[ops++] = opnum;
+           opoutput[opnum] = 1;
 
 
-           while (ISDIGIT (c = *p))
-             p++;
+           p = endptr;
+           c = *p;
          }
        /* % followed by a digit outputs an operand the default way.  */
        else if (ISDIGIT (*p))
          {
          }
        /* % followed by a digit outputs an operand the default way.  */
        else if (ISDIGIT (*p))
          {
-           c = atoi (p);
-           if (this_is_asm_operands
-               && (c < 0 || (unsigned int) c >= insn_noperands))
+           unsigned long opnum;
+           char *endptr;
+
+           opnum = strtoul (p, &endptr, 10);
+           if (this_is_asm_operands && opnum >= insn_noperands)
              output_operand_lossage ("operand number out of range");
            else
              output_operand_lossage ("operand number out of range");
            else
-             output_operand (operands[c], 0);
+             output_operand (operands[opnum], 0);
 
 
-           if (!opoutput[c])
-             oporder[ops++] = c;
-           opoutput[c] = 1;
+           if (!opoutput[opnum])
+             oporder[ops++] = opnum;
+           opoutput[opnum] = 1;
 
 
-           while (ISDIGIT (c = *p))
-             p++;
+           p = endptr;
+           c = *p;
          }
        /* % followed by punctuation: output something for that
           punctuation character alone, with no operand.
          }
        /* % followed by punctuation: output something for that
           punctuation character alone, with no operand.
@@ -3307,23 +3333,56 @@ output_asm_insn (template, operands)
 /* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol.  */
 
 void
 /* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol.  */
 
 void
-output_asm_label (x)
-     rtx x;
+output_asm_label (rtx x)
 {
   char buf[256];
 
   if (GET_CODE (x) == LABEL_REF)
     x = XEXP (x, 0);
 {
   char buf[256];
 
   if (GET_CODE (x) == LABEL_REF)
     x = XEXP (x, 0);
-  if (GET_CODE (x) == CODE_LABEL
-      || (GET_CODE (x) == NOTE
-         && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL))
+  if (LABEL_P (x)
+      || (NOTE_P (x)
+         && NOTE_KIND (x) == NOTE_INSN_DELETED_LABEL))
     ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
   else
     ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
   else
-    output_operand_lossage ("`%%l' operand isn't a label");
+    output_operand_lossage ("'%%l' operand isn't a label");
 
   assemble_name (asm_out_file, buf);
 }
 
 
   assemble_name (asm_out_file, buf);
 }
 
+/* Helper rtx-iteration-function for mark_symbol_refs_as_used and
+   output_operand.  Marks SYMBOL_REFs as referenced through use of
+   assemble_external.  */
+
+static int
+mark_symbol_ref_as_used (rtx *xp, void *dummy ATTRIBUTE_UNUSED)
+{
+  rtx x = *xp;
+
+  /* If we have a used symbol, we may have to emit assembly
+     annotations corresponding to whether the symbol is external, weak
+     or has non-default visibility.  */
+  if (GET_CODE (x) == SYMBOL_REF)
+    {
+      tree t;
+
+      t = SYMBOL_REF_DECL (x);
+      if (t)
+       assemble_external (t);
+
+      return -1;
+    }
+
+  return 0;
+}
+
+/* Marks SYMBOL_REFs in x as referenced through use of assemble_external.  */
+
+void
+mark_symbol_refs_as_used (rtx x)
+{
+  for_each_rtx (&x, mark_symbol_ref_as_used, NULL);
+}
+
 /* Print operand X using machine-dependent assembler syntax.
    The macro PRINT_OPERAND is defined just to control this function.
    CODE is a non-digit that preceded the operand-number in the % spec,
 /* Print operand X using machine-dependent assembler syntax.
    The macro PRINT_OPERAND is defined just to control this function.
    CODE is a non-digit that preceded the operand-number in the % spec,
@@ -3335,20 +3394,20 @@ output_asm_label (x)
    by PRINT_OPERAND.  */
 
 static void
    by PRINT_OPERAND.  */
 
 static void
-output_operand (x, code)
-     rtx x;
-     int code ATTRIBUTE_UNUSED;
+output_operand (rtx x, int code ATTRIBUTE_UNUSED)
 {
   if (x && GET_CODE (x) == SUBREG)
     x = alter_subreg (&x);
 
 {
   if (x && GET_CODE (x) == SUBREG)
     x = alter_subreg (&x);
 
-  /* If X is a pseudo-register, abort now rather than writing trash to the
-     assembler file.  */
-
-  if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
-    abort ();
+  /* X must not be a pseudo reg.  */
+  gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER);
 
   PRINT_OPERAND (asm_out_file, x, code);
 
   PRINT_OPERAND (asm_out_file, x, code);
+
+  if (x == NULL_RTX)
+    return;
+
+  for_each_rtx (&x, mark_symbol_ref_as_used, NULL);
 }
 
 /* Print a memory reference operand for address X
 }
 
 /* Print a memory reference operand for address X
@@ -3356,10 +3415,10 @@ output_operand (x, code)
    The macro PRINT_OPERAND_ADDRESS exists just to control this function.  */
 
 void
    The macro PRINT_OPERAND_ADDRESS exists just to control this function.  */
 
 void
-output_address (x)
-     rtx x;
+output_address (rtx x)
 {
 {
-  walk_alter_subreg (&x);
+  bool changed = false;
+  walk_alter_subreg (&x, &changed);
   PRINT_OPERAND_ADDRESS (asm_out_file, x);
 }
 \f
   PRINT_OPERAND_ADDRESS (asm_out_file, x);
 }
 \f
@@ -3368,9 +3427,7 @@ output_address (x)
    that may appear in these expressions.  */
 
 void
    that may appear in these expressions.  */
 
 void
-output_addr_const (file, x)
-     FILE *file;
-     rtx x;
+output_addr_const (FILE *file, rtx x)
 {
   char buf[256];
 
 {
   char buf[256];
 
@@ -3382,6 +3439,11 @@ output_addr_const (file, x)
       break;
 
     case SYMBOL_REF:
       break;
 
     case SYMBOL_REF:
+      if (SYMBOL_REF_DECL (x))
+       {
+         mark_decl_referenced (SYMBOL_REF_DECL (x));
+         assemble_external (SYMBOL_REF_DECL (x));
+       }
 #ifdef ASM_OUTPUT_SYMBOL_REF
       ASM_OUTPUT_SYMBOL_REF (file, x);
 #else
 #ifdef ASM_OUTPUT_SYMBOL_REF
       ASM_OUTPUT_SYMBOL_REF (file, x);
 #else
@@ -3417,9 +3479,11 @@ output_addr_const (file, x)
          /* We can use %d if the number is one word and positive.  */
          if (CONST_DOUBLE_HIGH (x))
            fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
          /* We can use %d if the number is one word and positive.  */
          if (CONST_DOUBLE_HIGH (x))
            fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
-                    CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
+                    (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x),
+                    (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x));
          else if (CONST_DOUBLE_LOW (x) < 0)
          else if (CONST_DOUBLE_LOW (x) < 0)
-           fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
+           fprintf (file, HOST_WIDE_INT_PRINT_HEX,
+                    (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x));
          else
            fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
        }
          else
            fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
        }
@@ -3429,6 +3493,11 @@ output_addr_const (file, x)
        output_operand_lossage ("floating constant misused");
       break;
 
        output_operand_lossage ("floating constant misused");
       break;
 
+    case CONST_FIXED:
+      fprintf (file, HOST_WIDE_INT_PRINT_HEX,
+              (unsigned HOST_WIDE_INT) CONST_FIXED_VALUE_LOW (x));
+      break;
+
     case PLUS:
       /* Some assemblers need integer constants to appear last (eg masm).  */
       if (GET_CODE (XEXP (x, 0)) == CONST_INT)
     case PLUS:
       /* Some assemblers need integer constants to appear last (eg masm).  */
       if (GET_CODE (XEXP (x, 0)) == CONST_INT)
@@ -3472,6 +3541,7 @@ output_addr_const (file, x)
     case ZERO_EXTEND:
     case SIGN_EXTEND:
     case SUBREG:
     case ZERO_EXTEND:
     case SIGN_EXTEND:
     case SUBREG:
+    case TRUNCATE:
       output_addr_const (file, XEXP (x, 0));
       break;
 
       output_addr_const (file, XEXP (x, 0));
       break;
 
@@ -3492,19 +3562,18 @@ output_addr_const (file, x)
    %U prints the value of USER_LABEL_PREFIX.
    %I prints the value of IMMEDIATE_PREFIX.
    %O runs ASM_OUTPUT_OPCODE to transform what follows in the string.
    %U prints the value of USER_LABEL_PREFIX.
    %I prints the value of IMMEDIATE_PREFIX.
    %O runs ASM_OUTPUT_OPCODE to transform what follows in the string.
-   Also supported are %d, %x, %s, %e, %f, %g and %%.
+   Also supported are %d, %i, %u, %x, %X, %o, %c, %s and %%.
 
    We handle alternate assembler dialects here, just like output_asm_insn.  */
 
 void
 
    We handle alternate assembler dialects here, just like output_asm_insn.  */
 
 void
-asm_fprintf VPARAMS ((FILE *file, const char *p, ...))
+asm_fprintf (FILE *file, const char *p, ...)
 {
   char buf[10];
   char *q, c;
 {
   char buf[10];
   char *q, c;
+  va_list argptr;
 
 
-  VA_OPEN (argptr, p);
-  VA_FIXEDARG (argptr, FILE *, file);
-  VA_FIXEDARG (argptr, const char *, p);
+  va_start (argptr, p);
 
   buf[0] = '%';
 
 
   buf[0] = '%';
 
@@ -3542,6 +3611,11 @@ asm_fprintf VPARAMS ((FILE *file, const char *p, ...))
       case '%':
        c = *p++;
        q = &buf[1];
       case '%':
        c = *p++;
        q = &buf[1];
+       while (strchr ("-+ #0", c))
+         {
+           *q++ = c;
+           c = *p++;
+         }
        while (ISDIGIT (c) || c == '.')
          {
            *q++ = c;
        while (ISDIGIT (c) || c == '.')
          {
            *q++ = c;
@@ -3550,32 +3624,24 @@ asm_fprintf VPARAMS ((FILE *file, const char *p, ...))
        switch (c)
          {
          case '%':
        switch (c)
          {
          case '%':
-           fprintf (file, "%%");
+           putc ('%', file);
            break;
 
          case 'd':  case 'i':  case 'u':
            break;
 
          case 'd':  case 'i':  case 'u':
-         case 'x':  case 'p':  case 'X':
-         case 'o':
+         case 'x':  case 'X':  case 'o':
+         case 'c':
            *q++ = c;
            *q = 0;
            fprintf (file, buf, va_arg (argptr, int));
            break;
 
          case 'w':
            *q++ = c;
            *q = 0;
            fprintf (file, buf, va_arg (argptr, int));
            break;
 
          case 'w':
-           /* This is a prefix to the 'd', 'i', 'u', 'x', 'p', and 'X' cases,
-              but we do not check for those cases.  It means that the value
-              is a HOST_WIDE_INT, which may be either `int' or `long'.  */
-
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
-#else
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
-           *q++ = 'l';
-#else
-           *q++ = 'l';
-           *q++ = 'l';
-#endif
-#endif
-
+           /* This is a prefix to the 'd', 'i', 'u', 'x', 'X', and
+              'o' cases, but we do not check for those cases.  It
+              means that the value is a HOST_WIDE_INT, which may be
+              either `long' or `long long'.  */
+           memcpy (q, HOST_WIDE_INT_PRINT, strlen (HOST_WIDE_INT_PRINT));
+           q += strlen (HOST_WIDE_INT_PRINT);
            *q++ = *p++;
            *q = 0;
            fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT));
            *q++ = *p++;
            *q = 0;
            fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT));
@@ -3583,17 +3649,22 @@ asm_fprintf VPARAMS ((FILE *file, const char *p, ...))
 
          case 'l':
            *q++ = c;
 
          case 'l':
            *q++ = c;
-           *q++ = *p++;
-           *q = 0;
-           fprintf (file, buf, va_arg (argptr, long));
-           break;
+#ifdef HAVE_LONG_LONG
+           if (*p == 'l')
+             {
+               *q++ = *p++;
+               *q++ = *p++;
+               *q = 0;
+               fprintf (file, buf, va_arg (argptr, long long));
+             }
+           else
+#endif
+             {
+               *q++ = *p++;
+               *q = 0;
+               fprintf (file, buf, va_arg (argptr, long));
+             }
 
 
-         case 'e':
-         case 'f':
-         case 'g':
-           *q++ = c;
-           *q = 0;
-           fprintf (file, buf, va_arg (argptr, double));
            break;
 
          case 's':
            break;
 
          case 's':
@@ -3631,7 +3702,7 @@ asm_fprintf VPARAMS ((FILE *file, const char *p, ...))
            break;
 
 #ifdef ASM_FPRINTF_EXTENSIONS
            break;
 
 #ifdef ASM_FPRINTF_EXTENSIONS
-           /* Upper case letters are reserved for general use by asm_fprintf
+           /* Uppercase letters are reserved for general use by asm_fprintf
               and so are not available to target specific code.  In order to
               prevent the ASM_FPRINTF_EXTENSIONS macro from using them then,
               they are defined here.  As they get turned into real extensions
               and so are not available to target specific code.  In order to
               prevent the ASM_FPRINTF_EXTENSIONS macro from using them then,
               they are defined here.  As they get turned into real extensions
@@ -3645,14 +3716,14 @@ asm_fprintf VPARAMS ((FILE *file, const char *p, ...))
          ASM_FPRINTF_EXTENSIONS (file, argptr, p)
 #endif
          default:
          ASM_FPRINTF_EXTENSIONS (file, argptr, p)
 #endif
          default:
-           abort ();
+           gcc_unreachable ();
          }
        break;
 
       default:
          }
        break;
 
       default:
-       fputc (c, file);
+       putc (c, file);
       }
       }
-  VA_CLOSE (argptr);
+  va_end (argptr);
 }
 \f
 /* Split up a CONST_DOUBLE or integer constant rtx
 }
 \f
 /* Split up a CONST_DOUBLE or integer constant rtx
@@ -3661,9 +3732,7 @@ asm_fprintf VPARAMS ((FILE *file, const char *p, ...))
    and in *SECOND the other.  */
 
 void
    and in *SECOND the other.  */
 
 void
-split_double (value, first, second)
-     rtx value;
-     rtx *first, *second;
+split_double (rtx value, rtx *first, rtx *second)
 {
   if (GET_CODE (value) == CONST_INT)
     {
 {
   if (GET_CODE (value) == CONST_INT)
     {
@@ -3768,7 +3837,6 @@ split_double (value, first, second)
     }
   else
     {
     }
   else
     {
-#ifdef REAL_ARITHMETIC
       REAL_VALUE_TYPE r;
       long l[2];
       REAL_VALUE_FROM_CONST_DOUBLE (r, value);
       REAL_VALUE_TYPE r;
       long l[2];
       REAL_VALUE_FROM_CONST_DOUBLE (r, value);
@@ -3795,69 +3863,45 @@ split_double (value, first, second)
        }
 #endif
 
        }
 #endif
 
-      *first = GEN_INT ((HOST_WIDE_INT) l[0]);
-      *second = GEN_INT ((HOST_WIDE_INT) l[1]);
-#else
-      if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
-          || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
-         && ! flag_pretend_float)
-       abort ();
-
-      if (
-#ifdef HOST_WORDS_BIG_ENDIAN
-         WORDS_BIG_ENDIAN
-#else
-         ! WORDS_BIG_ENDIAN
-#endif
-         )
-       {
-         /* Host and target agree => no need to swap.  */
-         *first = GEN_INT (CONST_DOUBLE_LOW (value));
-         *second = GEN_INT (CONST_DOUBLE_HIGH (value));
-       }
-      else
-       {
-         *second = GEN_INT (CONST_DOUBLE_LOW (value));
-         *first = GEN_INT (CONST_DOUBLE_HIGH (value));
-       }
-#endif /* no REAL_ARITHMETIC */
+      *first = GEN_INT (l[0]);
+      *second = GEN_INT (l[1]);
     }
 }
 \f
 /* Return nonzero if this function has no function calls.  */
 
 int
     }
 }
 \f
 /* Return nonzero if this function has no function calls.  */
 
 int
-leaf_function_p ()
+leaf_function_p (void)
 {
   rtx insn;
   rtx link;
 
 {
   rtx insn;
   rtx link;
 
-  if (current_function_profile || profile_arc_flag)
+  if (crtl->profile || profile_arc_flag)
     return 0;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     {
     return 0;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     {
-      if (GET_CODE (insn) == CALL_INSN
+      if (CALL_P (insn)
          && ! SIBLING_CALL_P (insn))
        return 0;
          && ! SIBLING_CALL_P (insn))
        return 0;
-      if (GET_CODE (insn) == INSN
+      if (NONJUMP_INSN_P (insn)
          && GET_CODE (PATTERN (insn)) == SEQUENCE
          && GET_CODE (PATTERN (insn)) == SEQUENCE
-         && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN
+         && CALL_P (XVECEXP (PATTERN (insn), 0, 0))
          && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
        return 0;
     }
          && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
        return 0;
     }
-  for (link = current_function_epilogue_delay_list;
+  for (link = crtl->epilogue_delay_list;
        link;
        link = XEXP (link, 1))
     {
       insn = XEXP (link, 0);
 
        link;
        link = XEXP (link, 1))
     {
       insn = XEXP (link, 0);
 
-      if (GET_CODE (insn) == CALL_INSN
+      if (CALL_P (insn)
          && ! SIBLING_CALL_P (insn))
        return 0;
          && ! SIBLING_CALL_P (insn))
        return 0;
-      if (GET_CODE (insn) == INSN
+      if (NONJUMP_INSN_P (insn)
          && GET_CODE (PATTERN (insn)) == SEQUENCE
          && GET_CODE (PATTERN (insn)) == SEQUENCE
-         && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN
+         && CALL_P (XVECEXP (PATTERN (insn), 0, 0))
          && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
        return 0;
     }
          && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
        return 0;
     }
@@ -3865,22 +3909,20 @@ leaf_function_p ()
   return 1;
 }
 
   return 1;
 }
 
-/* Return 1 if branch is an forward branch.
+/* Return 1 if branch is a forward branch.
    Uses insn_shuid array, so it works only in the final pass.  May be used by
    output templates to customary add branch prediction hints.
  */
 int
    Uses insn_shuid array, so it works only in the final pass.  May be used by
    output templates to customary add branch prediction hints.
  */
 int
-final_forward_branch_p (insn)
-     rtx insn;
+final_forward_branch_p (rtx insn)
 {
   int insn_id, label_id;
 {
   int insn_id, label_id;
-  if (!uid_shuid)
-    abort ();
+
+  gcc_assert (uid_shuid);
   insn_id = INSN_SHUID (insn);
   label_id = INSN_SHUID (JUMP_LABEL (insn));
   /* We've hit some insns that does not have id information available.  */
   insn_id = INSN_SHUID (insn);
   label_id = INSN_SHUID (JUMP_LABEL (insn));
   /* We've hit some insns that does not have id information available.  */
-  if (!insn_id || !label_id)
-    abort ();
+  gcc_assert (insn_id && label_id);
   return insn_id < label_id;
 }
 
   return insn_id < label_id;
 }
 
@@ -3899,19 +3941,19 @@ final_forward_branch_p (insn)
    safely renumbered.  */
 
 int
    safely renumbered.  */
 
 int
-only_leaf_regs_used ()
+only_leaf_regs_used (void)
 {
   int i;
 {
   int i;
-  char *permitted_reg_in_leaf_functions = LEAF_REGISTERS;
+  const char *const permitted_reg_in_leaf_functions = LEAF_REGISTERS;
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    if ((regs_ever_live[i] || global_regs[i])
+    if ((df_regs_ever_live_p (i) || global_regs[i])
        && ! permitted_reg_in_leaf_functions[i])
       return 0;
 
        && ! permitted_reg_in_leaf_functions[i])
       return 0;
 
-  if (current_function_uses_pic_offset_table
+  if (crtl->uses_pic_offset_table
       && pic_offset_table_rtx != 0
       && pic_offset_table_rtx != 0
-      && GET_CODE (pic_offset_table_rtx) == REG
+      && REG_P (pic_offset_table_rtx)
       && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
     return 0;
 
       && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
     return 0;
 
@@ -3922,8 +3964,7 @@ only_leaf_regs_used ()
    available in leaf functions.  */
 
 static void
    available in leaf functions.  */
 
 static void
-leaf_renumber_regs (first)
-     rtx first;
+leaf_renumber_regs (rtx first)
 {
   rtx insn;
 
 {
   rtx insn;
 
@@ -3933,7 +3974,7 @@ leaf_renumber_regs (first)
   for (insn = first; insn; insn = NEXT_INSN (insn))
     if (INSN_P (insn))
       leaf_renumber_regs_insn (PATTERN (insn));
   for (insn = first; insn; insn = NEXT_INSN (insn))
     if (INSN_P (insn))
       leaf_renumber_regs_insn (PATTERN (insn));
-  for (insn = current_function_epilogue_delay_list;
+  for (insn = crtl->epilogue_delay_list;
        insn;
        insn = XEXP (insn, 1))
     if (INSN_P (XEXP (insn, 0)))
        insn;
        insn = XEXP (insn, 1))
     if (INSN_P (XEXP (insn, 0)))
@@ -3944,8 +3985,7 @@ leaf_renumber_regs (first)
    available in leaf functions.  */
 
 void
    available in leaf functions.  */
 
 void
-leaf_renumber_regs_insn (in_rtx)
-     rtx in_rtx;
+leaf_renumber_regs_insn (rtx in_rtx)
 {
   int i, j;
   const char *format_ptr;
 {
   int i, j;
   const char *format_ptr;
@@ -3957,7 +3997,7 @@ leaf_renumber_regs_insn (in_rtx)
      renumbered_regs would be 1 for an output-register;
      they  */
 
      renumbered_regs would be 1 for an output-register;
      they  */
 
-  if (GET_CODE (in_rtx) == REG)
+  if (REG_P (in_rtx))
     {
       int newreg;
 
     {
       int newreg;
 
@@ -3974,11 +4014,10 @@ leaf_renumber_regs_insn (in_rtx)
          return;
        }
       newreg = LEAF_REG_REMAP (newreg);
          return;
        }
       newreg = LEAF_REG_REMAP (newreg);
-      if (newreg < 0)
-       abort ();
-      regs_ever_live[REGNO (in_rtx)] = 0;
-      regs_ever_live[newreg] = 1;
-      REGNO (in_rtx) = newreg;
+      gcc_assert (newreg >= 0);
+      df_set_regs_ever_live (REGNO (in_rtx), false);
+      df_set_regs_ever_live (newreg, true);
+      SET_REGNO (in_rtx, newreg);
       in_rtx->used = 1;
     }
 
       in_rtx->used = 1;
     }
 
@@ -4018,7 +4057,293 @@ leaf_renumber_regs_insn (in_rtx)
        break;
 
       default:
        break;
 
       default:
-       abort ();
+       gcc_unreachable ();
       }
 }
 #endif
       }
 }
 #endif
+
+
+/* When -gused is used, emit debug info for only used symbols. But in
+   addition to the standard intercepted debug_hooks there are some direct
+   calls into this file, i.e., dbxout_symbol, dbxout_parms, and dbxout_reg_params.
+   Those routines may also be called from a higher level intercepted routine. So
+   to prevent recording data for an inner call to one of these for an intercept,
+   we maintain an intercept nesting counter (debug_nesting). We only save the
+   intercepted arguments if the nesting is 1.  */
+int debug_nesting = 0;
+
+static tree *symbol_queue;
+int symbol_queue_index = 0;
+static int symbol_queue_size = 0;
+
+/* Generate the symbols for any queued up type symbols we encountered
+   while generating the type info for some originally used symbol.
+   This might generate additional entries in the queue.  Only when
+   the nesting depth goes to 0 is this routine called.  */
+
+void
+debug_flush_symbol_queue (void)
+{
+  int i;
+
+  /* Make sure that additionally queued items are not flushed
+     prematurely.  */
+
+  ++debug_nesting;
+
+  for (i = 0; i < symbol_queue_index; ++i)
+    {
+      /* If we pushed queued symbols then such symbols must be
+         output no matter what anyone else says.  Specifically,
+         we need to make sure dbxout_symbol() thinks the symbol was
+         used and also we need to override TYPE_DECL_SUPPRESS_DEBUG
+         which may be set for outside reasons.  */
+      int saved_tree_used = TREE_USED (symbol_queue[i]);
+      int saved_suppress_debug = TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]);
+      TREE_USED (symbol_queue[i]) = 1;
+      TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = 0;
+
+#ifdef DBX_DEBUGGING_INFO
+      dbxout_symbol (symbol_queue[i], 0);
+#endif
+
+      TREE_USED (symbol_queue[i]) = saved_tree_used;
+      TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = saved_suppress_debug;
+    }
+
+  symbol_queue_index = 0;
+  --debug_nesting;
+}
+
+/* Queue a type symbol needed as part of the definition of a decl
+   symbol.  These symbols are generated when debug_flush_symbol_queue()
+   is called.  */
+
+void
+debug_queue_symbol (tree decl)
+{
+  if (symbol_queue_index >= symbol_queue_size)
+    {
+      symbol_queue_size += 10;
+      symbol_queue = XRESIZEVEC (tree, symbol_queue, symbol_queue_size);
+    }
+
+  symbol_queue[symbol_queue_index++] = decl;
+}
+
+/* Free symbol queue.  */
+void
+debug_free_queue (void)
+{
+  if (symbol_queue)
+    {
+      free (symbol_queue);
+      symbol_queue = NULL;
+      symbol_queue_size = 0;
+    }
+}
+\f
+/* Turn the RTL into assembly.  */
+static unsigned int
+rest_of_handle_final (void)
+{
+  rtx x;
+  const char *fnname;
+
+  /* Get the function's name, as described by its RTL.  This may be
+     different from the DECL_NAME name used in the source file.  */
+
+  x = DECL_RTL (current_function_decl);
+  gcc_assert (MEM_P (x));
+  x = XEXP (x, 0);
+  gcc_assert (GET_CODE (x) == SYMBOL_REF);
+  fnname = XSTR (x, 0);
+
+  assemble_start_function (current_function_decl, fnname);
+  final_start_function (get_insns (), asm_out_file, optimize);
+  final (get_insns (), asm_out_file, optimize);
+  final_end_function ();
+
+#ifdef TARGET_UNWIND_INFO
+  /* ??? The IA-64 ".handlerdata" directive must be issued before
+     the ".endp" directive that closes the procedure descriptor.  */
+  output_function_exception_table (fnname);
+#endif
+
+  assemble_end_function (current_function_decl, fnname);
+
+#ifndef TARGET_UNWIND_INFO
+  /* Otherwise, it feels unclean to switch sections in the middle.  */
+  output_function_exception_table (fnname);
+#endif
+
+  user_defined_section_attribute = false;
+
+  /* Free up reg info memory.  */
+  free_reg_info ();
+
+  if (! quiet_flag)
+    fflush (asm_out_file);
+
+  /* Write DBX symbols if requested.  */
+
+  /* Note that for those inline functions where we don't initially
+     know for certain that we will be generating an out-of-line copy,
+     the first invocation of this routine (rest_of_compilation) will
+     skip over this code by doing a `goto exit_rest_of_compilation;'.
+     Later on, wrapup_global_declarations will (indirectly) call
+     rest_of_compilation again for those inline functions that need
+     to have out-of-line copies generated.  During that call, we
+     *will* be routed past here.  */
+
+  timevar_push (TV_SYMOUT);
+  (*debug_hooks->function_decl) (current_function_decl);
+  timevar_pop (TV_SYMOUT);
+
+  /* Release the blocks that are linked to DECL_INITIAL() to free the memory.  */
+  DECL_INITIAL (current_function_decl) = error_mark_node;
+
+  if (DECL_STATIC_CONSTRUCTOR (current_function_decl)
+      && targetm.have_ctors_dtors)
+    targetm.asm_out.constructor (XEXP (DECL_RTL (current_function_decl), 0),
+                                decl_init_priority_lookup
+                                  (current_function_decl));
+  if (DECL_STATIC_DESTRUCTOR (current_function_decl)
+      && targetm.have_ctors_dtors)
+    targetm.asm_out.destructor (XEXP (DECL_RTL (current_function_decl), 0),
+                               decl_fini_priority_lookup
+                                 (current_function_decl));
+  return 0;
+}
+
+struct rtl_opt_pass pass_final =
+{
+ {
+  RTL_PASS,
+  NULL,                                 /* name */
+  NULL,                                 /* gate */
+  rest_of_handle_final,                 /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_FINAL,                             /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_ggc_collect                      /* todo_flags_finish */
+ }
+};
+
+
+static unsigned int
+rest_of_handle_shorten_branches (void)
+{
+  /* Shorten branches.  */
+  shorten_branches (get_insns ());
+  return 0;
+}
+
+struct rtl_opt_pass pass_shorten_branches =
+{
+ {
+  RTL_PASS,
+  "shorten",                            /* name */
+  NULL,                                 /* gate */
+  rest_of_handle_shorten_branches,      /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_FINAL,                             /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func                        /* todo_flags_finish */
+ }
+};
+
+
+static unsigned int
+rest_of_clean_state (void)
+{
+  rtx insn, next;
+
+  /* It is very important to decompose the RTL instruction chain here:
+     debug information keeps pointing into CODE_LABEL insns inside the function
+     body.  If these remain pointing to the other insns, we end up preserving
+     whole RTL chain and attached detailed debug info in memory.  */
+  for (insn = get_insns (); insn; insn = next)
+    {
+      next = NEXT_INSN (insn);
+      NEXT_INSN (insn) = NULL;
+      PREV_INSN (insn) = NULL;
+    }
+
+  /* In case the function was not output,
+     don't leave any temporary anonymous types
+     queued up for sdb output.  */
+#ifdef SDB_DEBUGGING_INFO
+  if (write_symbols == SDB_DEBUG)
+    sdbout_types (NULL_TREE);
+#endif
+
+  reload_completed = 0;
+  epilogue_completed = 0;
+#ifdef STACK_REGS
+  regstack_completed = 0;
+#endif
+
+  /* Clear out the insn_length contents now that they are no
+     longer valid.  */
+  init_insn_lengths ();
+
+  /* Show no temporary slots allocated.  */
+  init_temp_slots ();
+
+  free_bb_for_insn ();
+
+  if (targetm.binds_local_p (current_function_decl))
+    {
+      unsigned int pref = crtl->preferred_stack_boundary;
+      if (crtl->stack_alignment_needed > crtl->preferred_stack_boundary)
+        pref = crtl->stack_alignment_needed;
+      cgraph_rtl_info (current_function_decl)->preferred_incoming_stack_boundary
+        = pref;
+    }
+
+  /* Make sure volatile mem refs aren't considered valid operands for
+     arithmetic insns.  We must call this here if this is a nested inline
+     function, since the above code leaves us in the init_recog state,
+     and the function context push/pop code does not save/restore volatile_ok.
+
+     ??? Maybe it isn't necessary for expand_start_function to call this
+     anymore if we do it here?  */
+
+  init_recog_no_volatile ();
+
+  /* We're done with this function.  Free up memory if we can.  */
+  free_after_parsing (cfun);
+  free_after_compilation (cfun);
+  return 0;
+}
+
+struct rtl_opt_pass pass_clean_state =
+{
+ {
+  RTL_PASS,
+  NULL,                                 /* name */
+  NULL,                                 /* gate */
+  rest_of_clean_state,                  /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_FINAL,                             /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  PROP_rtl,                             /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  0                                     /* todo_flags_finish */
+ }
+};
+