OSDN Git Service

* gcc.doxy: Rename from tree-ssa.doxy.
[pf3gnuchains/gcc-fork.git] / gcc / final.c
index 6d99a92..759bf10 100644 (file)
@@ -1,13 +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, 2003, 2004, 2005
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    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
    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
-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
@@ -16,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, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, 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.
@@ -72,6 +71,12 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "debug.h"
 #include "expr.h"
 #include "cfglayout.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"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
@@ -86,6 +91,10 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "dbxout.h"
 #endif
 
 #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
@@ -106,12 +115,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #define JUMP_TABLES_IN_TEXT_SECTION 0
 #endif
 
 #define JUMP_TABLES_IN_TEXT_SECTION 0
 #endif
 
-#if defined(READONLY_DATA_SECTION) || defined(READONLY_DATA_SECTION_ASM_OP)
-#define HAVE_READONLY_DATA_SECTION 1
-#else
-#define HAVE_READONLY_DATA_SECTION 0
-#endif
-
 /* Bitflags used by final_scan_insn.  */
 #define SEEN_BB                1
 #define SEEN_NOTE      2
 /* Bitflags used by final_scan_insn.  */
 #define SEEN_BB                1
 #define SEEN_NOTE      2
@@ -133,7 +136,10 @@ static int high_function_linenum;
 /* Filename of last NOTE.  */
 static const char *last_filename;
 
 /* Filename of last NOTE.  */
 static const char *last_filename;
 
-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.
    This means that inconsistencies are the user's fault, so don't die.
 
 /* Nonzero while outputting an `asm' with operands.
    This means that inconsistencies are the user's fault, so don't die.
@@ -165,23 +171,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];
-
-/* Like regs_ever_live, but 1 if a reg is set or clobbered from an asm.
-   Unlike regs_ever_live, elements of this array corresponding to
-   eliminable regs like the frame pointer are set if an asm sets them.  */
-
-char regs_asm_clobbered[FIRST_PSEUDO_REGISTER];
-
 /* Nonzero means current function must be given a frame pointer.
    Initialized in function.c to 0.  Set only in reload1.c as per
    the needs of the function.  */
 /* Nonzero means current function must be given a frame pointer.
    Initialized in function.c to 0.  Set only in reload1.c as per
    the needs of the function.  */
@@ -218,7 +207,7 @@ static int asm_insn_count (rtx);
 static void profile_function (FILE *);
 static void profile_after_prologue (FILE *);
 static bool notice_source_line (rtx);
 static void profile_function (FILE *);
 static void profile_after_prologue (FILE *);
 static bool notice_source_line (rtx);
-static rtx walk_alter_subreg (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_name (void);
 static void output_alternate_entry_point (FILE *, rtx);
 static tree get_mem_expr_from_op (rtx, int *);
@@ -315,7 +304,7 @@ dbr_sequence_length (void)
 
 static int *insn_lengths;
 
 
 static int *insn_lengths;
 
-varray_type insn_addresses_;
+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;
@@ -375,10 +364,11 @@ init_insn_lengths (void)
 }
 
 /* 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 (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;
@@ -396,7 +386,7 @@ get_attr_length (rtx insn ATTRIBUTE_UNUSED)
        return 0;
 
       case CALL_INSN:
        return 0;
 
       case CALL_INSN:
-       length = insn_default_length (insn);
+       length = fallback_fn (insn);
        break;
 
       case JUMP_INSN:
        break;
 
       case JUMP_INSN:
@@ -407,7 +397,7 @@ get_attr_length (rtx insn ATTRIBUTE_UNUSED)
               ADDR_VEC_ALIGN.  */
          }
        else
               ADDR_VEC_ALIGN.  */
          }
        else
-         length = insn_default_length (insn);
+         length = fallback_fn (insn);
        break;
 
       case INSN:
        break;
 
       case INSN:
@@ -416,12 +406,12 @@ get_attr_length (rtx insn ATTRIBUTE_UNUSED)
          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++)
            length += get_attr_length (XVECEXP (body, 0, i));
        else
        else if (GET_CODE (body) == SEQUENCE)
          for (i = 0; i < XVECLEN (body, 0); i++)
            length += get_attr_length (XVECEXP (body, 0, i));
        else
-         length = insn_default_length (insn);
+         length = fallback_fn (insn);
        break;
 
       default:
        break;
 
       default:
@@ -434,8 +424,26 @@ get_attr_length (rtx insn ATTRIBUTE_UNUSED)
   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.  */
 
@@ -652,7 +660,10 @@ insn_current_reference_address (rtx branch)
 }
 #endif /* HAVE_ATTR_length */
 \f
 }
 #endif /* HAVE_ATTR_length */
 \f
-void
+/* Compute branch alignments based on frequency information in the
+   CFG.  */
+
+static unsigned int
 compute_alignments (void)
 {
   int log, max_skip, max_log;
 compute_alignments (void)
 {
   int log, max_skip, max_log;
@@ -666,12 +677,11 @@ compute_alignments (void)
 
   max_labelno = max_label_num ();
   min_labelno = get_first_label_num ();
 
   max_labelno = max_label_num ();
   min_labelno = get_first_label_num ();
-  label_align = 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 (! optimize || optimize_size)
 
   /* If not optimizing or optimizing for size, don't assign any alignments.  */
   if (! optimize || optimize_size)
-    return;
+    return 0;
 
   FOR_EACH_BB (bb)
     {
 
   FOR_EACH_BB (bb)
     {
@@ -734,7 +744,26 @@ compute_alignments (void)
       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;
     }
+  return 0;
 }
 }
+
+struct tree_opt_pass pass_compute_alignments =
+{
+  NULL,                                 /* 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 */
+  0,                                    /* todo_flags_finish */
+  0                                     /* letter */
+};
+
 \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.  */
@@ -771,8 +800,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
 
   /* Free uid_shuid before reallocating it.  */
   free (uid_shuid);
 
   /* Free uid_shuid before reallocating it.  */
   free (uid_shuid);
-  
-  uid_shuid = xmalloc (max_uid * sizeof *uid_shuid);
+
+  uid_shuid = XNEWVEC (int, max_uid);
 
   if (max_labelno != max_label_num ())
     {
 
   if (max_labelno != max_label_num ())
     {
@@ -811,14 +840,9 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
 
       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 (LABEL_P (insn))
+       continue;
+
+      if (LABEL_P (insn))
        {
          rtx next;
 
        {
          rtx next;
 
@@ -839,7 +863,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
          next = next_nonnote_insn (insn);
          /* ADDR_VECs only take room if read-only data goes into the text
             section.  */
          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 || !HAVE_READONLY_DATA_SECTION)
+         if (JUMP_TABLES_IN_TEXT_SECTION
+             || readonly_data_section == text_section)
            if (next && JUMP_P (next))
              {
                rtx nextbody = PATTERN (next);
            if (next && JUMP_P (next))
              {
                rtx nextbody = PATTERN (next);
@@ -880,20 +905,20 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
 #ifdef HAVE_ATTR_length
 
   /* Allocate the rest of the arrays.  */
 #ifdef HAVE_ATTR_length
 
   /* Allocate the rest of the arrays.  */
-  insn_lengths = 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 = 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 = 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;
@@ -1002,7 +1027,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
        {
          /* This only takes room if read-only data goes into the text
             section.  */
        {
          /* This only takes room if read-only data goes into the text
             section.  */
-         if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
+         if (JUMP_TABLES_IN_TEXT_SECTION
+             || 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)));
@@ -1203,7 +1229,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
              PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
                                                        max_addr - rel_addr,
                                                        body));
              PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
                                                        max_addr - rel_addr,
                                                        body));
-             if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
+             if (JUMP_TABLES_IN_TEXT_SECTION
+                 || 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)));
@@ -1313,7 +1340,7 @@ asm_insn_count (rtx body)
   if (GET_CODE (body) == ASM_INPUT)
     template = XSTR (body, 0);
   else
   if (GET_CODE (body) == ASM_INPUT)
     template = XSTR (body, 0);
   else
-    template = decode_asm_operands (body, NULL, NULL, NULL, NULL);
+    template = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
 
   for (; *template; template++)
     if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n')
 
   for (; *template; template++)
     if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n')
@@ -1374,7 +1401,6 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
      function.  */
   if (write_symbols)
     {
      function.  */
   if (write_symbols)
     {
-      remove_unnecessary_notes ();
       reemit_insn_block_notes ();
       number_blocks (current_function_decl);
       /* We never actually put out begin/end notes for the top-level
       reemit_insn_block_notes ();
       number_blocks (current_function_decl);
       /* We never actually put out begin/end notes for the top-level
@@ -1420,13 +1446,13 @@ profile_function (FILE *file ATTRIBUTE_UNUSED)
   if (! NO_PROFILE_COUNTERS)
     {
       int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
   if (! NO_PROFILE_COUNTERS)
     {
       int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
-      data_section ();
+      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);
     }
 
       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);
     }
 
-  current_function_section (current_function_decl);
+  switch_to_section (current_function_section ());
 
 #if defined(ASM_OUTPUT_REG_PUSH)
   if (sval && svrtx != NULL_RTX && REG_P (svrtx))
 
 #if defined(ASM_OUTPUT_REG_PUSH)
   if (sval && svrtx != NULL_RTX && REG_P (svrtx))
@@ -1502,33 +1528,6 @@ final (rtx first, FILE *file, int optimize)
 
   last_ignored_compare = 0;
 
 
   last_ignored_compare = 0;
 
-#ifdef SDB_DEBUGGING_INFO
-  /* When producing SDB debugging info, delete troublesome line number
-     notes from inlined functions in other files as well as duplicate
-     line number notes.  */
-  if (write_symbols == SDB_DEBUG)
-    {
-      rtx last = 0;
-      for (insn = first; insn; insn = NEXT_INSN (insn))
-       if (NOTE_P (insn) && NOTE_LINE_NUMBER (insn) > 0)
-         {
-           if (last != 0
-#ifdef USE_MAPPED_LOCATION
-               && NOTE_SOURCE_LOCATION (insn) == NOTE_SOURCE_LOCATION (last)
-#else
-               && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
-               && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)
-#endif
-             )
-             {
-               delete_insn (insn);     /* Use delete_note.  */
-               continue;
-             }
-           last = insn;
-         }
-    }
-#endif
-
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
       if (INSN_UID (insn) > max_uid)       /* Find largest UID.  */
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
       if (INSN_UID (insn) > max_uid)       /* Find largest UID.  */
@@ -1552,7 +1551,7 @@ final (rtx first, FILE *file, int optimize)
   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 ())
@@ -1652,37 +1651,18 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
   switch (GET_CODE (insn))
     {
     case NOTE:
   switch (GET_CODE (insn))
     {
     case NOTE:
-      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_FUNCTION_END:
-       case NOTE_INSN_REPEATED_LINE_NUMBER:
-       case NOTE_INSN_EXPECTED_VALUE:
          break;
 
        case NOTE_INSN_SWITCH_TEXT_SECTIONS:
          break;
 
        case NOTE_INSN_SWITCH_TEXT_SECTIONS:
-         
-         /* The presence of this note indicates that this basic block
-            belongs in the "cold" section of the .o file.  If we are
-            not already writing to the cold section we need to change
-            to it.  */
-
-         if (last_text_section == in_text)
-           {
-             (*debug_hooks->switch_text_section) ();
-             unlikely_text_section ();
-           }
-         else
-           {
-             (*debug_hooks->switch_text_section) ();
-             text_section ();
-           }
+         in_cold_section_p = !in_cold_section_p;
+         (*debug_hooks->switch_text_section) ();
+         switch_to_section (current_function_section ());
          break;
          break;
-         
+
        case NOTE_INSN_BASIC_BLOCK:
        case NOTE_INSN_BASIC_BLOCK:
-         
 #ifdef TARGET_UNWIND_INFO
          targetm.asm_out.unwind_emit (asm_out_file, insn);
 #endif
 #ifdef TARGET_UNWIND_INFO
          targetm.asm_out.unwind_emit (asm_out_file, insn);
 #endif
@@ -1694,7 +1674,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
          if ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB)
            {
              *seen |= SEEN_EMITTED;
          if ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB)
            {
              *seen |= SEEN_EMITTED;
-             last_filename = NULL;
+             force_source_line = true;
            }
          else
            *seen |= SEEN_BB;
            }
          else
            *seen |= SEEN_BB;
@@ -1718,7 +1698,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
          if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
            {
              *seen |= SEEN_EMITTED;
          if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
            {
              *seen |= SEEN_EMITTED;
-             last_filename = NULL;
+             force_source_line = true;
            }
          else
            *seen |= SEEN_NOTE;
            }
          else
            *seen |= SEEN_NOTE;
@@ -1736,7 +1716,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
          if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
            {
              *seen |= SEEN_EMITTED;
          if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
            {
              *seen |= SEEN_EMITTED;
-             last_filename = NULL;
+             force_source_line = true;
            }
          else
            *seen |= SEEN_NOTE;
            }
          else
            *seen |= SEEN_NOTE;
@@ -1794,11 +1774,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
          (*debug_hooks->var_location) (insn);
          break;
 
          (*debug_hooks->var_location) (insn);
          break;
 
-       case 0:
-         break;
-
        default:
        default:
-         gcc_assert (NOTE_LINE_NUMBER (insn) > 0);
+         gcc_unreachable ();
          break;
        }
       break;
          break;
        }
       break;
@@ -1891,7 +1868,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
                {
                  int log_align;
 
                {
                  int log_align;
 
-                 targetm.asm_out.function_rodata_section (current_function_decl);
+                 switch_to_section (targetm.asm_out.function_rodata_section
+                                    (current_function_decl));
 
 #ifdef ADDR_VEC_ALIGN
                  log_align = ADDR_VEC_ALIGN (next);
 
 #ifdef ADDR_VEC_ALIGN
                  log_align = ADDR_VEC_ALIGN (next);
@@ -1901,7 +1879,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
                  ASM_OUTPUT_ALIGN (file, log_align);
                }
              else
                  ASM_OUTPUT_ALIGN (file, log_align);
                }
              else
-               current_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),
@@ -1925,6 +1903,10 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
        int insn_code_number;
        const char *template;
 
        int insn_code_number;
        const char *template;
 
+#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.  */
 
@@ -1958,9 +1940,10 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 #endif
 
            if (! JUMP_TABLES_IN_TEXT_SECTION)
 #endif
 
            if (! JUMP_TABLES_IN_TEXT_SECTION)
-             targetm.asm_out.function_rodata_section (current_function_decl);
+             switch_to_section (targetm.asm_out.function_rodata_section
+                                (current_function_decl));
            else
            else
-             current_function_section (current_function_decl);
+             switch_to_section (current_function_section ());
 
            if (app_on)
              {
 
            if (app_on)
              {
@@ -2018,7 +2001,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 #endif
 #endif
 
 #endif
 #endif
 
-           current_function_section (current_function_decl);
+           switch_to_section (current_function_section ());
 
            break;
          }
 
            break;
          }
@@ -2038,12 +2021,27 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
            if (string[0])
              {
 
            if (string[0])
              {
+               location_t loc;
+
                if (! app_on)
                  {
                    fputs (ASM_APP_ON, file);
                    app_on = 1;
                  }
                if (! app_on)
                  {
                    fputs (ASM_APP_ON, file);
                    app_on = 1;
                  }
+#ifdef USE_MAPPED_LOCATION
+               loc = ASM_INPUT_SOURCE_LOCATION (body);
+#else
+               loc.file = ASM_INPUT_SOURCE_FILE (body);
+               loc.line = ASM_INPUT_SOURCE_LINE (body);
+#endif
+               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;
          }
@@ -2054,12 +2052,13 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
            unsigned int noperands = asm_noperands (body);
            rtx *ops = alloca (noperands * sizeof (rtx));
            const char *string;
            unsigned int noperands = asm_noperands (body);
            rtx *ops = alloca (noperands * sizeof (rtx));
            const char *string;
+           location_t loc;
 
            /* There's no telling what that did to the condition codes.  */
            CC_STATUS_INIT;
 
            /* Get out the operand values.  */
 
            /* There's no telling what that did to the condition codes.  */
            CC_STATUS_INIT;
 
            /* Get out the operand values.  */
-           string = decode_asm_operands (body, ops, NULL, NULL, NULL);
+           string = decode_asm_operands (body, ops, NULL, NULL, NULL, &loc);
            /* Inhibit dieing on what would otherwise be compiler bugs.  */
            insn_noperands = noperands;
            this_is_asm_operands = insn;
            /* Inhibit dieing on what would otherwise be compiler bugs.  */
            insn_noperands = noperands;
            this_is_asm_operands = insn;
@@ -2076,7 +2075,14 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
                    fputs (ASM_APP_ON, file);
                    app_on = 1;
                  }
                    fputs (ASM_APP_ON, file);
                    app_on = 1;
                  }
+               if (loc.file && loc.line)
+                 fprintf (asm_out_file, "%s %i \"%s\" 1\n",
+                          ASM_COMMENT_START, loc.line, loc.file);
                output_asm_insn (string, ops);
                output_asm_insn (string, ops);
+#if HAVE_AS_LINE_ZERO
+               if (loc.file && loc.line)
+                 fprintf (asm_out_file, "%s 0 \"\" 2\n", ASM_COMMENT_START);
+#endif
              }
 
            this_is_asm_operands = 0;
              }
 
            this_is_asm_operands = 0;
@@ -2238,6 +2244,76 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
              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;
+         }
+
+       /* 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).  */
@@ -2359,8 +2435,6 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 #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
@@ -2456,8 +2530,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
   return NEXT_INSN (insn);
 }
 \f
   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 bool
 notice_source_line (rtx insn)
 
 static bool
 notice_source_line (rtx insn)
@@ -2465,8 +2538,12 @@ notice_source_line (rtx insn)
   const char *filename = insn_file (insn);
   int linenum = insn_line (insn);
 
   const char *filename = insn_file (insn);
   int linenum = insn_line (insn);
 
-  if (filename && (filename != last_filename || last_linenum != linenum))
+  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);
       last_filename = filename;
       last_linenum = linenum;
       high_block_linenum = MAX (last_linenum, high_block_linenum);
@@ -2483,6 +2560,7 @@ void
 cleanup_subreg_operands (rtx insn)
 {
   int i;
 cleanup_subreg_operands (rtx insn)
 {
   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++)
     {
@@ -2492,22 +2570,30 @@ cleanup_subreg_operands (rtx insn)
         matches the else clause.  Instead we test the underlying
         expression directly.  */
       if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG)
         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
               || MEM_P (recog_data.operand[i]))
       else if (GET_CODE (recog_data.operand[i]) == PLUS
               || GET_CODE (recog_data.operand[i]) == MULT
               || MEM_P (recog_data.operand[i]))
-       recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[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
               || MEM_P (*recog_data.dup_loc[i]))
       else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS
               || GET_CODE (*recog_data.dup_loc[i]) == MULT
               || MEM_P (*recog_data.dup_loc[i]))
-       *recog_data.dup_loc[i] = walk_alter_subreg (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,
 }
 
 /* If X is a SUBREG, replace it with a REG or a MEM,
@@ -2561,7 +2647,7 @@ alter_subreg (rtx *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 (rtx *xp)
+walk_alter_subreg (rtx *xp, bool *changed)
 {
   rtx x = *xp;
   switch (GET_CODE (x))
 {
   rtx x = *xp;
   switch (GET_CODE (x))
@@ -2569,16 +2655,17 @@ walk_alter_subreg (rtx *xp)
     case PLUS:
     case MULT:
     case AND:
     case PLUS:
     case MULT:
     case AND:
-      XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
-      XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1));
+      XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0), changed);
+      XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1), changed);
       break;
 
     case MEM:
     case ZERO_EXTEND:
       break;
 
     case MEM:
     case ZERO_EXTEND:
-      XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
+      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:
@@ -3017,7 +3104,7 @@ output_asm_insn (const char *template, rtx *operands)
            int letter = *p++;
            unsigned long opnum;
            char *endptr;
            int letter = *p++;
            unsigned long opnum;
            char *endptr;
-           
+
            opnum = strtoul (p, &endptr, 10);
 
            if (endptr == p)
            opnum = strtoul (p, &endptr, 10);
 
            if (endptr == p)
@@ -3062,7 +3149,7 @@ output_asm_insn (const char *template, rtx *operands)
          {
            unsigned long opnum;
            char *endptr;
          {
            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");
            opnum = strtoul (p, &endptr, 10);
            if (this_is_asm_operands && opnum >= insn_noperands)
              output_operand_lossage ("operand number out of range");
@@ -3111,7 +3198,7 @@ output_asm_label (rtx x)
     x = XEXP (x, 0);
   if (LABEL_P (x)
       || (NOTE_P (x)
     x = XEXP (x, 0);
   if (LABEL_P (x)
       || (NOTE_P (x)
-         && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL))
+         && NOTE_KIND (x) == NOTE_INSN_DELETED_LABEL))
     ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
   else
     output_operand_lossage ("'%%l' operand isn't a label");
     ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
   else
     output_operand_lossage ("'%%l' operand isn't a label");
@@ -3148,7 +3235,8 @@ output_operand (rtx x, int code ATTRIBUTE_UNUSED)
 void
 output_address (rtx x)
 {
 void
 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
@@ -3636,7 +3724,7 @@ int
 final_forward_branch_p (rtx insn)
 {
   int insn_id, label_id;
 final_forward_branch_p (rtx insn)
 {
   int insn_id, label_id;
-  
+
   gcc_assert (uid_shuid);
   insn_id = INSN_SHUID (insn);
   label_id = INSN_SHUID (JUMP_LABEL (insn));
   gcc_assert (uid_shuid);
   insn_id = INSN_SHUID (insn);
   label_id = INSN_SHUID (JUMP_LABEL (insn));
@@ -3666,7 +3754,7 @@ only_leaf_regs_used (void)
   const char *const permitted_reg_in_leaf_functions = LEAF_REGISTERS;
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
   const char *const permitted_reg_in_leaf_functions = LEAF_REGISTERS;
 
   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;
 
@@ -3734,9 +3822,9 @@ leaf_renumber_regs_insn (rtx in_rtx)
        }
       newreg = LEAF_REG_REMAP (newreg);
       gcc_assert (newreg >= 0);
        }
       newreg = LEAF_REG_REMAP (newreg);
       gcc_assert (newreg >= 0);
-      regs_ever_live[REGNO (in_rtx)] = 0;
-      regs_ever_live[newreg] = 1;
-      REGNO (in_rtx) = newreg;
+      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;
     }
 
@@ -3812,7 +3900,7 @@ debug_flush_symbol_queue (void)
 
   for (i = 0; i < symbol_queue_index; ++i)
     {
 
   for (i = 0; i < symbol_queue_index; ++i)
     {
-      /* If we pushed queued symbols then such symbols are must be
+      /* 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
          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
@@ -3862,3 +3950,198 @@ debug_free_queue (void)
       symbol_queue_size = 0;
     }
 }
       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);
+  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 tree_opt_pass pass_final =
+{
+  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 */
+  0                                     /* letter */
+};
+
+
+static unsigned int
+rest_of_handle_shorten_branches (void)
+{
+  /* Shorten branches.  */
+  shorten_branches (get_insns ());
+  return 0;
+}
+
+struct tree_opt_pass pass_shorten_branches =
+{
+  "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 */
+  0                                     /* letter */
+};
+
+
+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))
+    {
+      int pref = cfun->preferred_stack_boundary;
+      if (cfun->stack_alignment_needed > cfun->preferred_stack_boundary)
+        pref = cfun->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 tree_opt_pass pass_clean_state =
+{
+  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 */
+  0                                     /* letter */
+};
+