OSDN Git Service

Give names to some currently nameless passes (this
[pf3gnuchains/gcc-fork.git] / gcc / final.c
index 906e50c..2508443 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, 2008, 2009
    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, 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.
@@ -72,6 +71,15 @@ Software Foundation, 59 Temple Place - Suite 330, 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"
+#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
@@ -86,6 +94,10 @@ Software Foundation, 59 Temple Place - Suite 330, 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
@@ -99,19 +111,13 @@ 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
 
-#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
@@ -124,6 +130,12 @@ rtx current_output_insn;
 /* Line number of last NOTE.  */
 static int last_linenum;
 
 /* Line number of last NOTE.  */
 static int last_linenum;
 
+/* Last discriminator written to assembly.  */
+static int last_discriminator;
+
+/* Discriminator of current block.  */
+static int discriminator;
+
 /* Highest line number in current block.  */
 static int high_block_linenum;
 
 /* Highest line number in current block.  */
 static int high_block_linenum;
 
@@ -133,10 +145,17 @@ 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.  */
+/* Override filename and line number.  */
+static const char *override_filename;
+static int override_linenum;
+
+/* 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.  */
 rtx this_is_asm_operands;
 
    The precise value is the insn being output, to pass to error_for_asm.  */
 rtx this_is_asm_operands;
 
@@ -165,29 +184,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.  */
-
-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;
@@ -217,8 +213,8 @@ static int asm_insn_count (rtx);
 #endif
 static void profile_function (FILE *);
 static void profile_after_prologue (FILE *);
 #endif
 static void profile_function (FILE *);
 static void profile_after_prologue (FILE *);
-static bool notice_source_line (rtx);
-static rtx walk_alter_subreg (rtx *);
+static bool notice_source_line (rtx, bool *);
+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 +311,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 +371,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 +393,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 +404,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 +413,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++)
        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:
@@ -434,8 +431,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.  */
 
@@ -544,7 +559,17 @@ static int min_labelno, max_labelno;
 int
 label_to_alignment (rtx label)
 {
 int
 label_to_alignment (rtx label)
 {
-  return LABEL_TO_ALIGNMENT (label);
+  if (CODE_LABEL_NUMBER (label) <= max_labelno)
+    return LABEL_TO_ALIGNMENT (label);
+  return 0;
+}
+
+int
+label_to_max_skip (rtx label)
+{
+  if (CODE_LABEL_NUMBER (label) <= max_labelno)
+    return LABEL_TO_MAX_SKIP (label);
+  return 0;
 }
 
 #ifdef HAVE_ATTR_length
 }
 
 #ifdef HAVE_ATTR_length
@@ -652,11 +677,16 @@ 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.  */
+
+unsigned int
 compute_alignments (void)
 {
   int log, max_skip, max_log;
   basic_block bb;
 compute_alignments (void)
 {
   int log, max_skip, max_log;
   basic_block bb;
+  int freq_max = 0;
+  int freq_threshold = 0;
 
   if (label_align)
     {
 
   if (label_align)
     {
@@ -666,13 +696,25 @@ 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 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;
+
+  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)
     {
       rtx label = BB_HEAD (bb);
   FOR_EACH_BB (bb)
     {
       rtx label = BB_HEAD (bb);
@@ -681,8 +723,13 @@ compute_alignments (void)
       edge_iterator ei;
 
       if (!LABEL_P (label)
       edge_iterator ei;
 
       if (!LABEL_P (label)
-         || probably_never_executed_bb_p (bb))
-       continue;
+         || 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;
 
@@ -693,6 +740,18 @@ compute_alignments (void)
          else
            branch_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
@@ -705,12 +764,14 @@ compute_alignments (void)
         when function is called.  */
 
       if (!has_fallthru
         when function is called.  */
 
       if (!has_fallthru
-         && (branch_frequency > BB_FREQ_MAX / 10
+         && (branch_frequency > freq_threshold
              || (bb->frequency > bb->prev_bb->frequency * 10
                  && (bb->prev_bb->frequency
                      <= ENTRY_BLOCK_PTR->frequency / 2))))
        {
          log = JUMP_ALIGN (label);
              || (bb->frequency > bb->prev_bb->frequency * 10
                  && (bb->prev_bb->frequency
                      <= 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;
@@ -720,11 +781,14 @@ compute_alignments (void)
       /* In case block is frequent and reached mostly by non-fallthru edge,
         align it.  It is most likely a first block of loop.  */
       if (has_fallthru
       /* In case block is frequent and reached mostly by non-fallthru edge,
         align it.  It is most likely a first block of loop.  */
       if (has_fallthru
-         && maybe_hot_bb_p (bb)
-         && branch_frequency + fallthru_frequency > BB_FREQ_MAX / 10
-         && branch_frequency > fallthru_frequency * 2)
+         && 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;
@@ -734,7 +798,35 @@ 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;
     }
+
+  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 */
+  TV_NONE,                              /* 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.  */
@@ -771,8 +863,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 ())
     {
@@ -785,10 +877,9 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
       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 = 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.  */
       gcc_assert (n_old_labels <= n_labels);
 
          means that the initialization of array got lost.  */
       gcc_assert (n_old_labels <= n_labels);
 
@@ -811,16 +902,12 @@ 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;
+         bool next_is_jumptable;
 
          /* Merge in alignments computed by compute_alignments.  */
          log = LABEL_TO_ALIGNMENT (insn);
 
          /* Merge in alignments computed by compute_alignments.  */
          log = LABEL_TO_ALIGNMENT (insn);
@@ -830,30 +917,30 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
              max_skip = LABEL_TO_MAX_SKIP (insn);
            }
 
              max_skip = LABEL_TO_MAX_SKIP (insn);
            }
 
-         log = LABEL_ALIGN (insn);
-         if (max_log < log)
+         next = next_nonnote_insn (insn);
+         next_is_jumptable = next && JUMP_TABLE_DATA_P (next);
+         if (!next_is_jumptable)
            {
            {
-             max_log = log;
-             max_skip = LABEL_ALIGN_MAX_SKIP;
+             log = LABEL_ALIGN (insn);
+             if (max_log < log)
+               {
+                 max_log = log;
+                 max_skip = LABEL_ALIGN_MAX_SKIP;
+               }
            }
            }
-         next = next_nonnote_insn (insn);
          /* ADDR_VECs only take room if read-only data goes into the text
             section.  */
          /* 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 (next && JUMP_P (next))
-             {
-               rtx nextbody = PATTERN (next);
-               if (GET_CODE (nextbody) == ADDR_VEC
-                   || GET_CODE (nextbody) == ADDR_DIFF_VEC)
-                 {
-                   log = ADDR_VEC_ALIGN (next);
-                   if (max_log < log)
-                     {
-                       max_log = log;
-                       max_skip = LABEL_ALIGN_MAX_SKIP;
-                     }
-                 }
-             }
+         if ((JUMP_TABLES_IN_TEXT_SECTION
+              || readonly_data_section == text_section)
+             && next_is_jumptable)
+           {
+             log = ADDR_VEC_ALIGN (next);
+             if (max_log < log)
+               {
+                 max_log = log;
+                 max_skip = LABEL_ALIGN_MAX_SKIP;
+               }
+           }
          LABEL_TO_ALIGNMENT (insn) = max_log;
          LABEL_TO_MAX_SKIP (insn) = max_skip;
          max_log = 0;
          LABEL_TO_ALIGNMENT (insn) = max_log;
          LABEL_TO_MAX_SKIP (insn) = max_skip;
          max_log = 0;
@@ -880,20 +967,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;
@@ -953,8 +1040,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
              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));
          memset (&flags, 0, sizeof (flags));
          insn_shuid = INSN_SHUID (insn);
          rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0));
          memset (&flags, 0, sizeof (flags));
@@ -1002,7 +1089,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 +1291,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)));
@@ -1307,22 +1396,92 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
 static int
 asm_insn_count (rtx body)
 {
 static int
 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);
+
+  if (!*templ)
+    return 0;
 
 
-  for (; *template; template++)
-    if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n')
+  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
@@ -1343,6 +1502,7 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
 
   last_filename = locator_file (prologue_locator);
   last_linenum = locator_line (prologue_locator);
 
   last_filename = locator_file (prologue_locator);
   last_linenum = locator_line (prologue_locator);
+  last_discriminator = discriminator = 0;
 
   high_block_linenum = high_function_linenum = last_linenum;
 
 
   high_block_linenum = high_function_linenum = last_linenum;
 
@@ -1361,7 +1521,7 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
   /* 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 */
 
     profile_function (file);
 #endif /* PROFILE_BEFORE_PROLOGUE */
 
@@ -1374,7 +1534,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
@@ -1383,6 +1542,15 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
       TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
     }
 
       TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
     }
 
+  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);
+  }
+
   /* First output the function prologue: code to set up the stack frame.  */
   targetm.asm_out.function_prologue (file, get_frame_size ());
 
   /* First output the function prologue: code to set up the stack frame.  */
   targetm.asm_out.function_prologue (file, get_frame_size ());
 
@@ -1398,7 +1566,7 @@ static void
 profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
 {
 #ifndef PROFILE_BEFORE_PROLOGUE
 profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
 {
 #ifndef PROFILE_BEFORE_PROLOGUE
-  if (current_function_profile)
+  if (crtl->profile)
     profile_function (file);
 #endif /* not PROFILE_BEFORE_PROLOGUE */
 }
     profile_function (file);
 #endif /* not PROFILE_BEFORE_PROLOGUE */
 }
@@ -1410,7 +1578,7 @@ profile_function (FILE *file ATTRIBUTE_UNUSED)
 # define NO_PROFILE_COUNTERS   0
 #endif
 #if defined(ASM_OUTPUT_REG_PUSH)
 # define NO_PROFILE_COUNTERS   0
 #endif
 #if defined(ASM_OUTPUT_REG_PUSH)
-  int sval = current_function_returns_struct;
+  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)
   int cxt = cfun->static_chain_decl != NULL;
   rtx svrtx = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), 1);
 #if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM)
   int cxt = cfun->static_chain_decl != NULL;
@@ -1420,17 +1588,19 @@ 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);
     }
 
-  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))
-    ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx));
+    {
+      ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx));
+    }
 #endif
 
 #if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
 #endif
 
 #if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
@@ -1461,7 +1631,9 @@ profile_function (FILE *file ATTRIBUTE_UNUSED)
 
 #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))
-    ASM_OUTPUT_REG_POP (file, REGNO (svrtx));
+    {
+      ASM_OUTPUT_REG_POP (file, REGNO (svrtx));
+    }
 #endif
 }
 
 #endif
 }
 
@@ -1491,18 +1663,10 @@ final_end_function (void)
 }
 \f
 /* Output assembler code for some insns: all or part of a function.
 }
 \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 (rtx first, FILE *file, int optimize, int prescan)
+final (rtx first, FILE *file, int optimize)
 {
   rtx insn;
   int max_uid = 0;
 {
   rtx insn;
   int max_uid = 0;
@@ -1510,33 +1674,6 @@ final (rtx first, FILE *file, int optimize, int prescan)
 
   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.  */
@@ -1560,7 +1697,7 @@ final (rtx first, FILE *file, int optimize, int 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 ())
@@ -1574,7 +1711,7 @@ final (rtx first, FILE *file, int optimize, int prescan)
        insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
 #endif /* HAVE_ATTR_length */
 
        insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
 #endif /* HAVE_ATTR_length */
 
-      insn = final_scan_insn (insn, file, optimize, prescan, 0, &seen);
+      insn = final_scan_insn (insn, file, optimize, 0, &seen);
     }
 }
 \f
     }
 }
 \f
@@ -1627,33 +1764,32 @@ output_alternate_entry_point (FILE *file, rtx insn)
     }
 }
 
     }
 }
 
-/* Return boolean indicating if there is a NOTE_INSN_UNLIKELY_EXECUTED_CODE
-   note in the instruction chain (going forward) between the current
-   instruction, and the next 'executable' instruction.  */
-
-bool
-scan_ahead_for_unlikely_executed_note (rtx insn)
+/* Given a CALL_INSN, find and return the nested CALL. */
+static rtx
+call_from_call_insn (rtx insn)
 {
 {
-  rtx temp;
-  int bb_note_count = 0;
+  rtx x;
+  gcc_assert (CALL_P (insn));
+  x = PATTERN (insn);
 
 
-  for (temp = insn; temp; temp = NEXT_INSN (temp))
+  while (GET_CODE (x) != CALL)
     {
     {
-      if (NOTE_P (temp)
-         && NOTE_LINE_NUMBER (temp) == NOTE_INSN_UNLIKELY_EXECUTED_CODE)
-       return true;
-      if (NOTE_P (temp)
-         && NOTE_LINE_NUMBER (temp) == NOTE_INSN_BASIC_BLOCK)
+      switch (GET_CODE (x))
        {
        {
-         bb_note_count++;
-         if (bb_note_count > 1)
-           return false;
+       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;
        }
        }
-      if (INSN_P (temp))
-       return false;
     }
     }
-  
-  return false;
+  return x;
 }
 
 /* The final scan for one insn, INSN.
 }
 
 /* The final scan for one insn, INSN.
@@ -1672,8 +1808,7 @@ scan_ahead_for_unlikely_executed_note (rtx insn)
 
 rtx
 final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
 rtx
 final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
-                int prescan, int nopeepholes ATTRIBUTE_UNUSED,
-                int *seen)
+                int nopeepholes ATTRIBUTE_UNUSED, int *seen)
 {
 #ifdef HAVE_cc0
   rtx set;
 {
 #ifdef HAVE_cc0
   rtx set;
@@ -1690,43 +1825,24 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
   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_FUNCTION_END:
-       case NOTE_INSN_REPEATED_LINE_NUMBER:
-       case NOTE_INSN_EXPECTED_VALUE:
          break;
 
          break;
 
-       case NOTE_INSN_UNLIKELY_EXECUTED_CODE:
-         
-         /* 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.  */
-         
-         unlikely_text_section ();
+       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;
          break;
-         
-       case NOTE_INSN_BASIC_BLOCK:
-         
-         /* If we are performing the optimization that partitions
-            basic blocks into hot & cold sections of the .o file,
-            then at the start of each new basic block, before
-            beginning to write code for the basic block, we need to
-            check to see whether the basic block belongs in the hot
-            or cold section of the .o file, and change the section we
-            are writing to appropriately.  */
-         
-         if (flag_reorder_blocks_and_partition
-             && !scan_ahead_for_unlikely_executed_note (insn))
-           function_section (current_function_decl);
 
 
+       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
@@ -1738,11 +1854,13 @@ 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;
 
+          discriminator = NOTE_BASIC_BLOCK (insn)->discriminator;
+
          break;
 
        case NOTE_INSN_EH_REGION_BEG:
          break;
 
        case NOTE_INSN_EH_REGION_BEG:
@@ -1762,7 +1880,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;
@@ -1770,9 +1888,19 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
          break;
 
        case NOTE_INSN_EPILOGUE_BEG:
          break;
 
        case NOTE_INSN_EPILOGUE_BEG:
+#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_epilogue)
+         if (dwarf2out_do_frame ())
+           dwarf2out_begin_epilogue (insn);
+#endif
          targetm.asm_out.function_begin_epilogue (file);
          break;
 
          targetm.asm_out.function_begin_epilogue (file);
          break;
 
+       case NOTE_INSN_CFA_RESTORE_STATE:
+#if defined (DWARF2_UNWIND_INFO)
+         dwarf2out_frame_debug_restore_state ();
+#endif
+         break;
+
        case NOTE_INSN_FUNCTION_BEG:
          app_disable ();
          (*debug_hooks->end_prologue) (last_linenum, last_filename);
        case NOTE_INSN_FUNCTION_BEG:
          app_disable ();
          (*debug_hooks->end_prologue) (last_linenum, last_filename);
@@ -1780,7 +1908,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;
@@ -1806,6 +1934,18 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
              /* 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:
          break;
 
        case NOTE_INSN_BLOCK_END:
@@ -1825,6 +1965,24 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
              (*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:
@@ -1838,11 +1996,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;
@@ -1879,104 +2034,49 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
        }
 #ifdef HAVE_cc0
       CC_STATUS_INIT;
        }
 #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 && BARRIER_P (barrier)
-             && jump && JUMP_P (jump)
-             && (prev = prev_nonnote_insn (jump))
-             && NONJUMP_INSN_P (prev))
-           {
-             NOTICE_UPDATE_CC (PATTERN (prev), prev);
-             NOTICE_UPDATE_CC (PATTERN (jump), jump);
-           }
-       }
 #endif
 #endif
-      if (prescan > 0)
-       break;
 
       if (LABEL_NAME (insn))
        (*debug_hooks->label) (insn);
 
 
       if (LABEL_NAME (insn))
        (*debug_hooks->label) (insn);
 
-      /* If we are doing the optimization that partitions hot & cold
-        basic blocks into separate sections of the .o file, we need
-        to ensure the jump table ends up in the correct section...  */
-      
-      if (flag_reorder_blocks_and_partition
-         && targetm.have_named_sections)
-       {
-         rtx tmp_table, tmp_label;
-         if (LABEL_P (insn)
-             && tablejump_p (NEXT_INSN (insn), &tmp_label, &tmp_table))
-           {
-             /* Do nothing; Do NOT change the current section.  */
-           }
-         else if (scan_ahead_for_unlikely_executed_note (insn)) 
-           unlikely_text_section ();
-         else if (in_unlikely_text_section ())
-           function_section (current_function_decl);
-       }
-
-      if (app_on)
-       {
-         fputs (ASM_APP_OFF, file);
-         app_on = 0;
-       }
+      app_disable ();
 
       next = next_nonnote_insn (insn);
 
       next = next_nonnote_insn (insn);
-      if (next != 0 && JUMP_P (next))
+      /* If this label is followed by a jump-table, make sure we put
+        the label in the read-only section.  Also possibly write the
+        label and jump table together.  */
+      if (next != 0 && JUMP_TABLE_DATA_P (next))
        {
        {
-         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
-            possibly write the label and jump table together.  */
-
-         if (GET_CODE (nextbody) == ADDR_VEC
-             || GET_CODE (nextbody) == ADDR_DIFF_VEC)
-           {
 #if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
 #if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
-             /* In this case, the case vector is being moved by the
-                target, so don't output the label at all.  Leave that
-                to the back end macros.  */
+         /* In this case, the case vector is being moved by the
+            target, so don't output the label at all.  Leave that
+            to the back end macros.  */
 #else
 #else
-             if (! JUMP_TABLES_IN_TEXT_SECTION)
-               {
-                 int log_align;
+         if (! JUMP_TABLES_IN_TEXT_SECTION)
+           {
+             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
 
 #ifdef ADDR_VEC_ALIGN
-                 log_align = ADDR_VEC_ALIGN (next);
+             log_align = ADDR_VEC_ALIGN (next);
 #else
 #else
-                 log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
+             log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
 #endif
 #endif
-                 ASM_OUTPUT_ALIGN (file, log_align);
-               }
-             else
-               function_section (current_function_decl);
+             ASM_OUTPUT_ALIGN (file, log_align);
+           }
+         else
+           switch_to_section (current_function_section ());
 
 #ifdef ASM_OUTPUT_CASE_LABEL
 
 #ifdef ASM_OUTPUT_CASE_LABEL
-             ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
-                                    next);
+         ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
+                                next);
 #else
 #else
-             targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
+         targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
 #endif
 #endif
 #endif
 #endif
-             break;
-           }
+         break;
        }
       if (LABEL_ALT_ENTRY_P (insn))
        output_alternate_entry_point (file, insn);
        }
       if (LABEL_ALT_ENTRY_P (insn))
        output_alternate_entry_point (file, insn);
@@ -1988,8 +2088,13 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
       {
        rtx body = PATTERN (insn);
        int insn_code_number;
       {
        rtx body = PATTERN (insn);
        int insn_code_number;
-       const char *template;
+       const char *templ;
+       bool is_stmt;
 
 
+#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.  */
 
@@ -2022,19 +2127,13 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
            int vlen, idx;
 #endif
 
            int vlen, idx;
 #endif
 
-           if (prescan > 0)
-             break;
-
            if (! JUMP_TABLES_IN_TEXT_SECTION)
            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
-             function_section (current_function_decl);
+             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)
@@ -2086,15 +2185,18 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 #endif
 #endif
 
 #endif
 #endif
 
-           function_section (current_function_decl);
+           switch_to_section (current_function_section ());
 
            break;
          }
        /* Output this line note if it is the first or the last line
           note in a row.  */
 
            break;
          }
        /* Output this line note if it is the first or the last line
           note in a row.  */
-       if (notice_source_line (insn))
+       if (notice_source_line (insn, &is_stmt))
          {
          {
-           (*debug_hooks->source_line) (last_linenum, last_filename);
+           (*debug_hooks->source_line) (last_linenum,
+                                        last_filename,
+                                        last_discriminator,
+                                        is_stmt);
          }
 
        if (GET_CODE (body) == ASM_INPUT)
          }
 
        if (GET_CODE (body) == ASM_INPUT)
@@ -2103,17 +2205,21 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
            /* 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;
          }
@@ -2122,19 +2228,20 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
        if (asm_noperands (body) >= 0)
          {
            unsigned int noperands = asm_noperands (body);
        if (asm_noperands (body) >= 0)
          {
            unsigned int noperands = asm_noperands (body);
-           rtx *ops = 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);
 
 #ifdef FINAL_PRESCAN_INSN
            FINAL_PRESCAN_INSN (insn, ops, insn_noperands);
@@ -2143,31 +2250,32 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
            /* 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
              }
 
              }
 
+           if (targetm.asm_out.final_postscan_insn)
+             targetm.asm_out.final_postscan_insn (file, insn, ops,
+                                                  insn_noperands);
+
            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;
 
-           if (prescan > 0)
-             break;
            final_sequence = body;
 
            /* Record the delay slots' frame information before the branch.
            final_sequence = body;
 
            /* Record the delay slots' frame information before the branch.
@@ -2183,7 +2291,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
               thought unnecessary.  If that happens, cancel this sequence
               and cause that insn to be restored.  */
 
               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, seen);
+           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;
@@ -2197,7 +2305,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
                /* 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, seen);
+                 insn = final_scan_insn (insn, file, 0, 1, seen);
                while (insn != next);
              }
 #ifdef DBR_OUTPUT_SEQEND
                while (insn != next);
              }
 #ifdef DBR_OUTPUT_SEQEND
@@ -2238,9 +2346,13 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
                && GET_CODE (SET_DEST (set)) == CC0
                && insn != last_ignored_compare)
              {
                && GET_CODE (SET_DEST (set)) == CC0
                && insn != last_ignored_compare)
              {
+               rtx src1, src2;
                if (GET_CODE (SET_SRC (set)) == SUBREG)
                  SET_SRC (set) = alter_subreg (&SET_SRC (set));
                if (GET_CODE (SET_SRC (set)) == SUBREG)
                  SET_SRC (set) = alter_subreg (&SET_SRC (set));
-               else if (GET_CODE (SET_SRC (set)) == COMPARE)
+
+               src1 = SET_SRC (set);
+               src2 = NULL_RTX;
+               if (GET_CODE (SET_SRC (set)) == COMPARE)
                  {
                    if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
                      XEXP (SET_SRC (set), 0)
                  {
                    if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
                      XEXP (SET_SRC (set), 0)
@@ -2248,11 +2360,18 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
                    if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
                      XEXP (SET_SRC (set), 1)
                        = alter_subreg (&XEXP (SET_SRC (set), 1));
                    if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
                      XEXP (SET_SRC (set), 1)
                        = alter_subreg (&XEXP (SET_SRC (set), 1));
+                   if (XEXP (SET_SRC (set), 1)
+                       == CONST0_RTX (GET_MODE (XEXP (SET_SRC (set), 0))))
+                     src2 = XEXP (SET_SRC (set), 0);
                  }
                if ((cc_status.value1 != 0
                  }
                if ((cc_status.value1 != 0
-                    && rtx_equal_p (SET_SRC (set), cc_status.value1))
+                    && rtx_equal_p (src1, cc_status.value1))
                    || (cc_status.value2 != 0
                    || (cc_status.value2 != 0
-                       && rtx_equal_p (SET_SRC (set), cc_status.value2)))
+                       && rtx_equal_p (src1, cc_status.value2))
+                   || (src2 != 0 && cc_status.value1 != 0
+                       && rtx_equal_p (src2, cc_status.value1))
+                   || (src2 != 0 && cc_status.value2 != 0
+                       && rtx_equal_p (src2, cc_status.value2)))
                  {
                    /* Don't delete insn if it has an addressing side-effect.  */
                    if (! FIND_REG_INC_NOTE (insn, NULL_RTX)
                  {
                    /* Don't delete insn if it has an addressing side-effect.  */
                    if (! FIND_REG_INC_NOTE (insn, NULL_RTX)
@@ -2266,9 +2385,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
                  }
              }
          }
                  }
              }
          }
-#endif
 
 
-#ifdef HAVE_cc0
        /* If this is a conditional branch, maybe modify it
           if the cc's are in a nonstandard state
           so that it accomplishes the same thing that it would
        /* If this is a conditional branch, maybe modify it
           if the cc's are in a nonstandard state
           so that it accomplishes the same thing that it would
@@ -2280,10 +2397,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
            && SET_DEST (body) == pc_rtx
            && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
            && COMPARISON_P (XEXP (SET_SRC (body), 0))
            && SET_DEST (body) == pc_rtx
            && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
            && COMPARISON_P (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)
+           && 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.
@@ -2315,6 +2429,41 @@ 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;
+         }
+
        /* 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).  */
@@ -2387,10 +2536,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
                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, seen);
+                 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;
@@ -2434,8 +2585,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
@@ -2457,12 +2606,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 #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;
 
@@ -2485,12 +2634,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
        /* 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
              fatal_insn ("could not split insn", insn);
 
 #ifdef HAVE_ATTR_length
@@ -2500,12 +2649,9 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
            gcc_unreachable ();
 #endif
 
            gcc_unreachable ();
 #endif
 
-           return new;
+           return new_rtx;
          }
 
          }
 
-       if (prescan > 0)
-         break;
-
 #ifdef TARGET_UNWIND_INFO
        /* ??? This will put the directives in the wrong place if
           get_insn_template outputs assembly directly.  However calling it
 #ifdef TARGET_UNWIND_INFO
        /* ??? This will put the directives in the wrong place if
           get_insn_template outputs assembly directly.  However calling it
@@ -2513,8 +2659,28 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
        targetm.asm_out.unwind_emit (asm_out_file, insn);
 #endif
 
        targetm.asm_out.unwind_emit (asm_out_file, insn);
 #endif
 
+       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 assembler code from the template.  */
-       output_asm_insn (template, recog_data.operand);
+       output_asm_insn (templ, recog_data.operand);
+
+       /* Some target machines need to postscan each insn after
+          it is output.  */
+       if (targetm.asm_out.final_postscan_insn)
+         targetm.asm_out.final_postscan_insn (file, insn, recog_data.operand,
+                                              recog_data.n_operands);
 
        /* If necessary, report the effect that the instruction has on
           the unwind info.   We've already done this for delay slots
 
        /* If necessary, report the effect that the instruction has on
           the unwind info.   We've already done this for delay slots
@@ -2534,23 +2700,54 @@ 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.
+   Sets IS_STMT to TRUE if the line should be marked as a possible
+   breakpoint location.  */
 
 static bool
 
 static bool
-notice_source_line (rtx insn)
+notice_source_line (rtx insn, bool *is_stmt)
 {
 {
-  const char *filename = insn_file (insn);
-  int linenum = insn_line (insn);
+  const char *filename;
+  int linenum;
 
 
-  if (filename && (filename != last_filename || last_linenum != linenum))
+  if (override_filename)
+    {
+      filename = override_filename;
+      linenum = override_linenum;
+    }
+  else
     {
     {
+      filename = insn_file (insn);
+      linenum = insn_line (insn);
+    }
+
+  if (filename == NULL)
+    return false;
+
+  if (force_source_line
+      || filename != last_filename
+      || last_linenum != linenum)
+    {
+      force_source_line = false;
       last_filename = filename;
       last_linenum = linenum;
       last_filename = filename;
       last_linenum = linenum;
+      last_discriminator = discriminator;
+      *is_stmt = true;
       high_block_linenum = MAX (last_linenum, high_block_linenum);
       high_function_linenum = MAX (last_linenum, high_function_linenum);
       return true;
     }
       high_block_linenum = MAX (last_linenum, high_block_linenum);
       high_function_linenum = MAX (last_linenum, high_function_linenum);
       return true;
     }
+
+  if (SUPPORTS_DISCRIMINATOR && last_discriminator != discriminator)
+    {
+      /* If the discriminator changed, but the line number did not,
+         output the line table entry with is_stmt false so the
+         debugger does not treat this as a breakpoint location.  */
+      last_discriminator = discriminator;
+      *is_stmt = false;
+      return true;
+    }
+
   return false;
 }
 \f
   return false;
 }
 \f
@@ -2561,6 +2758,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++)
     {
@@ -2570,22 +2768,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,
@@ -2620,17 +2826,23 @@ alter_subreg (rtx *xp)
     }
   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;
-      else
+      if (new_rtx != 0)
+       *xp = new_rtx;
+      else if (REG_P (y))
        {
          /* Simplify_subreg can't handle some REG cases, but we have to.  */
        {
          /* Simplify_subreg can't handle some REG cases, but we have to.  */
-         unsigned int regno = subreg_regno (x);
-         gcc_assert (REG_P (y));
-         *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, SUBREG_BYTE (x));
+         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);
        }
     }
 
        }
     }
 
@@ -2640,7 +2852,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))
@@ -2648,16 +2860,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:
@@ -2832,17 +3045,17 @@ alter_cond (rtx 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 (const char *msgid, ...)
+output_operand_lossage (const char *cmsgid, ...)
 {
   char *fmt_string;
   char *new_message;
   const char *pfx_str;
   va_list ap;
 
 {
   char *fmt_string;
   char *new_message;
   const char *pfx_str;
   va_list ap;
 
-  va_start (ap, msgid);
+  va_start (ap, cmsgid);
 
   pfx_str = this_is_asm_operands ? _("invalid 'asm': ") : "output_operand: ";
 
   pfx_str = this_is_asm_operands ? _("invalid 'asm': ") : "output_operand: ";
-  asprintf (&fmt_string, "%s%s", pfx_str, _(msgid));
+  asprintf (&fmt_string, "%s%s", pfx_str, _(cmsgid));
   vasprintf (&new_message, fmt_string, ap);
 
   if (this_is_asm_operands)
   vasprintf (&new_message, fmt_string, ap);
 
   if (this_is_asm_operands)
@@ -2914,7 +3127,7 @@ get_mem_expr_from_op (rtx op, int *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)) == RTX_UNARY
+  while (UNARY_P (op)
         || GET_RTX_CLASS (GET_CODE (op)) == RTX_BIN_ARITH)
     op = XEXP (op, 0);
 
         || GET_RTX_CLASS (GET_CODE (op)) == RTX_BIN_ARITH)
     op = XEXP (op, 0);
 
@@ -2971,7 +3184,7 @@ output_asm_operand_names (rtx *operands, int *oporder, int nops)
       of the operand, with no other punctuation.  */
 
 void
       of the operand, with no other punctuation.  */
 
 void
-output_asm_insn (const char *template, rtx *operands)
+output_asm_insn (const char *templ, rtx *operands)
 {
   const char *p;
   int c;
 {
   const char *p;
   int c;
@@ -2984,11 +3197,11 @@ output_asm_insn (const char *template, rtx *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
@@ -3096,7 +3309,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)
@@ -3117,7 +3330,7 @@ output_asm_insn (const char *template, rtx *operands)
              }
            else if (letter == 'n')
              {
              }
            else if (letter == 'n')
              {
-               if (GET_CODE (operands[opnum]) == CONST_INT)
+               if (CONST_INT_P (operands[opnum]))
                  fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
                           - INTVAL (operands[opnum]));
                else
                  fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
                           - INTVAL (operands[opnum]));
                else
@@ -3141,7 +3354,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");
@@ -3190,7 +3403,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");
@@ -3198,6 +3411,40 @@ output_asm_label (rtx x)
   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,
@@ -3214,11 +3461,15 @@ 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.  */
+  /* 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);
   gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER);
 
   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
@@ -3228,7 +3479,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
@@ -3250,7 +3502,10 @@ output_addr_const (FILE *file, rtx x)
 
     case SYMBOL_REF:
       if (SYMBOL_REF_DECL (x))
 
     case SYMBOL_REF:
       if (SYMBOL_REF_DECL (x))
-       mark_decl_referenced (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
@@ -3286,9 +3541,11 @@ output_addr_const (FILE *file, rtx 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));
        }
@@ -3298,9 +3555,14 @@ output_addr_const (FILE *file, rtx 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).  */
     case PLUS:
       /* Some assemblers need integer constants to appear last (eg masm).  */
-      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
+      if (CONST_INT_P (XEXP (x, 0)))
        {
          output_addr_const (file, XEXP (x, 1));
          if (INTVAL (XEXP (x, 0)) >= 0)
        {
          output_addr_const (file, XEXP (x, 1));
          if (INTVAL (XEXP (x, 0)) >= 0)
@@ -3310,7 +3572,7 @@ output_addr_const (FILE *file, rtx x)
       else
        {
          output_addr_const (file, XEXP (x, 0));
       else
        {
          output_addr_const (file, XEXP (x, 0));
-         if (GET_CODE (XEXP (x, 1)) != CONST_INT
+         if (!CONST_INT_P (XEXP (x, 1))
              || INTVAL (XEXP (x, 1)) >= 0)
            fprintf (file, "+");
          output_addr_const (file, XEXP (x, 1));
              || INTVAL (XEXP (x, 1)) >= 0)
            fprintf (file, "+");
          output_addr_const (file, XEXP (x, 1));
@@ -3326,7 +3588,7 @@ output_addr_const (FILE *file, rtx x)
 
       output_addr_const (file, XEXP (x, 0));
       fprintf (file, "-");
 
       output_addr_const (file, XEXP (x, 0));
       fprintf (file, "-");
-      if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0)
+      if ((CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) >= 0)
          || GET_CODE (XEXP (x, 1)) == PC
          || GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
        output_addr_const (file, XEXP (x, 1));
          || GET_CODE (XEXP (x, 1)) == PC
          || GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
        output_addr_const (file, XEXP (x, 1));
@@ -3341,6 +3603,7 @@ output_addr_const (FILE *file, rtx 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;
 
@@ -3533,7 +3796,7 @@ asm_fprintf (FILE *file, const char *p, ...)
 void
 split_double (rtx value, rtx *first, rtx *second)
 {
 void
 split_double (rtx value, rtx *first, rtx *second)
 {
-  if (GET_CODE (value) == CONST_INT)
+  if (CONST_INT_P (value))
     {
       if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD))
        {
     {
       if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD))
        {
@@ -3675,7 +3938,7 @@ 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))
@@ -3689,7 +3952,7 @@ leaf_function_p (void)
          && ! 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))
     {
        link;
        link = XEXP (link, 1))
     {
@@ -3716,7 +3979,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));
@@ -3746,11 +4009,11 @@ 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;
 
-  if (current_function_uses_pic_offset_table
+  if (crtl->uses_pic_offset_table
       && pic_offset_table_rtx != 0
       && REG_P (pic_offset_table_rtx)
       && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
       && pic_offset_table_rtx != 0
       && REG_P (pic_offset_table_rtx)
       && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
@@ -3773,7 +4036,7 @@ leaf_renumber_regs (rtx 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)))
@@ -3814,9 +4077,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;
     }
 
@@ -3892,7 +4155,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
@@ -3924,8 +4187,7 @@ debug_queue_symbol (tree decl)
   if (symbol_queue_index >= symbol_queue_size)
     {
       symbol_queue_size += 10;
   if (symbol_queue_index >= symbol_queue_size)
     {
       symbol_queue_size += 10;
-      symbol_queue = xrealloc (symbol_queue,
-                              symbol_queue_size * sizeof (tree));
+      symbol_queue = XRESIZEVEC (tree, symbol_queue, symbol_queue_size);
     }
 
   symbol_queue[symbol_queue_index++] = decl;
     }
 
   symbol_queue[symbol_queue_index++] = decl;
@@ -3942,3 +4204,264 @@ 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);
+
+  /* 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;
+  FILE *final_output = NULL;
+  int save_unnumbered = flag_dump_unnumbered;
+  int save_noaddr = flag_dump_noaddr;
+
+  if (flag_dump_final_insns)
+    {
+      final_output = fopen (flag_dump_final_insns, "a");
+      if (!final_output)
+       {
+         error ("could not open final insn dump file %qs: %s",
+                flag_dump_final_insns, strerror (errno));
+         flag_dump_final_insns = NULL;
+       }
+      else
+       {
+         const char *aname;
+
+         aname = (IDENTIFIER_POINTER
+                  (DECL_ASSEMBLER_NAME (current_function_decl)));
+         fprintf (final_output, "\n;; Function (%s) %s\n\n", aname,
+            cfun->function_frequency == FUNCTION_FREQUENCY_HOT
+            ? " (hot)"
+            : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
+            ? " (unlikely executed)"
+            : "");
+
+         flag_dump_noaddr = flag_dump_unnumbered = 1;
+
+         for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+           if (LABEL_P (insn))
+             INSN_UID (insn) = CODE_LABEL_NUMBER (insn);
+           else
+             INSN_UID (insn) = 0;
+       }
+    }
+
+  /* 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;
+
+      if (final_output
+         && (!NOTE_P (insn) ||
+             (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
+              && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
+              && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END)))
+       print_rtl_single (final_output, insn);
+
+    }
+
+  if (final_output)
+    {
+      flag_dump_noaddr = save_noaddr;
+      flag_dump_unnumbered = save_unnumbered;
+
+      if (fclose (final_output))
+       {
+         error ("could not close final insn dump file %qs: %s",
+                flag_dump_final_insns, strerror (errno));
+         flag_dump_final_insns = 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
+
+  flag_rerun_cse_after_global_opts = 0;
+  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,
+  "*clean_state",                       /* 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 */
+ }
+};