The various TARGET_ASM_..._MAX_SKIP hooks take an insn
[gcc.git] / gcc / final.c
index 319d2389272d662fe6e0ec415984238995d1fb9d..d17b61b5506447c72bd61ef1c798abfe777872a4 100644 (file)
@@ -1,8 +1,5 @@
 /* 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, 2006, 2007, 2008, 2009,
-   2010, 2011
-   Free Software Foundation, Inc.
+   Copyright (C) 1987-2014 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -51,6 +48,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 
 #include "tree.h"
+#include "varasm.h"
+#include "hard-reg-set.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "regs.h"
@@ -59,7 +58,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "recog.h"
 #include "conditions.h"
 #include "flags.h"
-#include "hard-reg-set.h"
 #include "output.h"
 #include "except.h"
 #include "function.h"
@@ -72,18 +70,18 @@ along with GCC; see the file COPYING3.  If not see
 #include "targhooks.h"
 #include "debug.h"
 #include "expr.h"
-#include "cfglayout.h"
 #include "tree-pass.h"
-#include "tree-flow.h"
-#include "timevar.h"
 #include "cgraph.h"
+#include "tree-ssa.h"
 #include "coverage.h"
 #include "df.h"
-#include "vecprim.h"
 #include "ggc.h"
 #include "cfgloop.h"
 #include "params.h"
-#include "tree-pretty-print.h"
+#include "tree-pretty-print.h" /* for dump_function_header */
+#include "asan.h"
+#include "wide-int-print.h"
+#include "rtl-iter.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
@@ -106,11 +104,6 @@ along with GCC; see the file COPYING3.  If not see
 #define CC_STATUS_INIT
 #endif
 
-/* How to start an assembler comment.  */
-#ifndef ASM_COMMENT_START
-#define ASM_COMMENT_START ";#"
-#endif
-
 /* Is the given character a logical line separator for the assembler?  */
 #ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
 #define IS_ASM_LOGICAL_LINE_SEPARATOR(C, STR) ((C) == ';')
@@ -121,13 +114,12 @@ along with GCC; see the file COPYING3.  If not see
 #endif
 
 /* Bitflags used by final_scan_insn.  */
-#define SEEN_BB                1
-#define SEEN_NOTE      2
-#define SEEN_EMITTED   4
+#define SEEN_NOTE      1
+#define SEEN_EMITTED   2
 
 /* Last insn processed by final_scan_insn.  */
-static rtx debug_insn;
-rtx current_output_insn;
+static rtx_insn *debug_insn;
+rtx_insn *current_output_insn;
 
 /* Line number of last NOTE.  */
 static int last_linenum;
@@ -159,7 +151,7 @@ extern const int length_unit_log; /* This is defined in insn-attrtab.c.  */
 /* Nonzero while outputting an `asm' with operands.
    This means that inconsistencies are the user's fault, so don't die.
    The precise value is the insn being output, to pass to error_for_asm.  */
-rtx this_is_asm_operands;
+const rtx_insn *this_is_asm_operands;
 
 /* Number of operands of this insn, for an `asm' with operands.  */
 static unsigned int insn_noperands;
@@ -197,7 +189,7 @@ static int app_on;
 /* If we are outputting an insn sequence, this contains the sequence rtx.
    Zero otherwise.  */
 
-rtx final_sequence;
+rtx_sequence *final_sequence;
 
 #ifdef ASSEMBLER_DIALECT
 
@@ -211,19 +203,20 @@ rtx current_insn_predicate;
 /* True if printing into -fdump-final-insns= dump.  */   
 bool final_insns_dump_p;
 
-#ifdef HAVE_ATTR_length
+/* True if profile_function should be called, but hasn't been called yet.  */
+static bool need_profile_function;
+
 static int asm_insn_count (rtx);
-#endif
 static void profile_function (FILE *);
 static void profile_after_prologue (FILE *);
-static bool notice_source_line (rtx, bool *);
+static bool notice_source_line (rtx_insn *, bool *);
 static rtx walk_alter_subreg (rtx *, bool *);
 static void output_asm_name (void);
-static void output_alternate_entry_point (FILE *, rtx);
+static void output_alternate_entry_point (FILE *, rtx_insn *);
 static tree get_mem_expr_from_op (rtx, int *);
 static void output_asm_operand_names (rtx *, int *, int);
 #ifdef LEAF_REGISTERS
-static void leaf_renumber_regs (rtx);
+static void leaf_renumber_regs (rtx_insn *);
 #endif
 #ifdef HAVE_cc0
 static int alter_cond (rtx);
@@ -231,9 +224,9 @@ static int alter_cond (rtx);
 #ifndef ADDR_VEC_ALIGN
 static int final_addr_vec_align (rtx);
 #endif
-#ifdef HAVE_ATTR_length
 static int align_fuzz (rtx, rtx, int, unsigned);
-#endif
+static void collect_fn_hard_reg_usage (void);
+static tree get_call_fndecl (rtx_insn *);
 \f
 /* Initialize data in final at the beginning of a compilation.  */
 
@@ -320,7 +313,7 @@ dbr_sequence_length (void)
 
 static int *insn_lengths;
 
-VEC(int,heap) *insn_addresses_;
+vec<int> insn_addresses_;
 
 /* Max uid for which the above arrays are valid.  */
 static int insn_lengths_max_uid;
@@ -369,9 +362,8 @@ init_insn_lengths (void)
       insn_lengths = 0;
       insn_lengths_max_uid = 0;
     }
-#ifdef HAVE_ATTR_length
-  INSN_ADDRESSES_FREE ();
-#endif
+  if (HAVE_ATTR_length)
+    INSN_ADDRESSES_FREE ();
   if (uid_align)
     {
       free (uid_align);
@@ -382,15 +374,17 @@ init_insn_lengths (void)
 /* Obtain the current length of an insn.  If branch shortening has been done,
    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)
+static int
+get_attr_length_1 (rtx uncast_insn, int (*fallback_fn) (rtx))
 {
-#ifdef HAVE_ATTR_length
+  rtx_insn *insn = as_a <rtx_insn *> (uncast_insn);
   rtx body;
   int i;
   int length = 0;
 
+  if (!HAVE_ATTR_length)
+    return 0;
+
   if (insn_lengths_max_uid > INSN_UID (insn))
     return insn_lengths[INSN_UID (insn)];
   else
@@ -403,18 +397,8 @@ get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED,
        return 0;
 
       case CALL_INSN:
-       length = fallback_fn (insn);
-       break;
-
       case JUMP_INSN:
-       body = PATTERN (insn);
-       if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
-         {
-           /* Alignment is machine-dependent and should be handled by
-              ADDR_VEC_ALIGN.  */
-         }
-       else
-         length = fallback_fn (insn);
+       length = fallback_fn (insn);
        break;
 
       case INSN:
@@ -424,9 +408,9 @@ get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED,
 
        else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
          length = asm_insn_count (body) * fallback_fn (insn);
-       else if (GET_CODE (body) == SEQUENCE)
-         for (i = 0; i < XVECLEN (body, 0); i++)
-           length += get_attr_length_1 (XVECEXP (body, 0, i), fallback_fn);
+       else if (rtx_sequence *seq = dyn_cast <rtx_sequence *> (body))
+         for (i = 0; i < seq->len (); i++)
+           length += get_attr_length_1 (seq->insn (i), fallback_fn);
        else
          length = fallback_fn (insn);
        break;
@@ -439,11 +423,6 @@ get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED,
   ADJUST_INSN_LENGTH (insn, length);
 #endif
   return length;
-#else /* not HAVE_ATTR_length */
-  return 0;
-#define insn_default_length 0
-#define insn_min_length 0
-#endif /* not HAVE_ATTR_length */
 }
 
 /* Obtain the current length of an insn.  If branch shortening has been done,
@@ -520,25 +499,25 @@ get_attr_min_length (rtx insn)
 #endif
 
 int
-default_label_align_after_barrier_max_skip (rtx insn ATTRIBUTE_UNUSED)
+default_label_align_after_barrier_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED)
 {
   return 0;
 }
 
 int
-default_loop_align_max_skip (rtx insn ATTRIBUTE_UNUSED)
+default_loop_align_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED)
 {
   return align_loops_max_skip;
 }
 
 int
-default_label_align_max_skip (rtx insn ATTRIBUTE_UNUSED)
+default_label_align_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED)
 {
   return align_labels_max_skip;
 }
 
 int
-default_jump_align_max_skip (rtx insn ATTRIBUTE_UNUSED)
+default_jump_align_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED)
 {
   return align_jumps_max_skip;
 }
@@ -590,7 +569,6 @@ label_to_max_skip (rtx label)
   return 0;
 }
 
-#ifdef HAVE_ATTR_length
 /* The differences in addresses
    between a branch and its target might grow or shrink depending on
    the alignment the start insn of the range (the branch for a forward
@@ -659,7 +637,7 @@ align_fuzz (rtx start, rtx end, int known_align_log, unsigned int growth)
    to exclude the branch size.  */
 
 int
-insn_current_reference_address (rtx branch)
+insn_current_reference_address (rtx_insn *branch)
 {
   rtx dest, seq;
   int seq_uid;
@@ -693,7 +671,6 @@ insn_current_reference_address (rtx branch)
              + align_fuzz (dest, seq, length_unit_log, ~0));
     }
 }
-#endif /* HAVE_ATTR_length */
 \f
 /* Compute branch alignments based on frequency information in the
    CFG.  */
@@ -722,20 +699,21 @@ compute_alignments (void)
 
   if (dump_file)
     {
+      dump_reg_info (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)
+  FOR_EACH_BB_FN (bb, cfun)
     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)
+    fprintf (dump_file, "freq_max: %i\n",freq_max);
+  FOR_EACH_BB_FN (bb, cfun)
     {
-      rtx label = BB_HEAD (bb);
+      rtx_insn *label = BB_HEAD (bb);
       int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0;
       edge e;
       edge_iterator ei;
@@ -744,8 +722,10 @@ compute_alignments (void)
          || 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);
+           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 (bb));
          continue;
        }
       max_log = LABEL_ALIGN (label);
@@ -760,10 +740,11 @@ compute_alignments (void)
        }
       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);
+         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 (bb),
+                  fallthru_frequency, branch_frequency);
          if (!bb->loop_father->inner && bb->loop_father->num)
            fprintf (dump_file, " inner_loop");
          if (bb->loop_father->header == bb)
@@ -785,11 +766,11 @@ compute_alignments (void)
          && (branch_frequency > freq_threshold
              || (bb->frequency > bb->prev_bb->frequency * 10
                  && (bb->prev_bb->frequency
-                     <= ENTRY_BLOCK_PTR->frequency / 2))))
+                     <= ENTRY_BLOCK_PTR_FOR_FN (cfun)->frequency / 2))))
        {
          log = JUMP_ALIGN (label);
          if (dump_file)
-           fprintf(dump_file, "  jump alignment added.\n");
+           fprintf (dump_file, "  jump alignment added.\n");
          if (max_log < log)
            {
              max_log = log;
@@ -799,6 +780,8 @@ 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
+         && !(single_succ_p (bb)
+              && single_succ (bb) == EXIT_BLOCK_PTR_FOR_FN (cfun))
          && optimize_bb_for_speed_p (bb)
          && branch_frequency + fallthru_frequency > freq_threshold
          && (branch_frequency
@@ -806,7 +789,7 @@ compute_alignments (void)
        {
          log = LOOP_ALIGN (label);
          if (dump_file)
-           fprintf(dump_file, "  internal loop alignment added.\n");
+           fprintf (dump_file, "  internal loop alignment added.\n");
          if (max_log < log)
            {
              max_log = log;
@@ -822,26 +805,88 @@ compute_alignments (void)
   return 0;
 }
 
-struct rtl_opt_pass pass_compute_alignments =
+/* Grow the LABEL_ALIGN array after new labels are created.  */
+
+static void 
+grow_label_align (void)
+{
+  int old = max_labelno;
+  int n_labels;
+  int n_old_labels;
+
+  max_labelno = max_label_num ();
+
+  n_labels = max_labelno - min_labelno + 1;
+  n_old_labels = old - min_labelno + 1;
+
+  label_align = XRESIZEVEC (struct label_alignment, label_align, n_labels);
+
+  /* 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);
+
+  memset (label_align + n_old_labels, 0,
+          (n_labels - n_old_labels) * sizeof (struct label_alignment));
+}
+
+/* Update the already computed alignment information.  LABEL_PAIRS is a vector
+   made up of pairs of labels for which the alignment information of the first
+   element will be copied from that of the second element.  */
+
+void
+update_alignments (vec<rtx> &label_pairs)
+{
+  unsigned int i = 0;
+  rtx iter, label = NULL_RTX;
+
+  if (max_labelno != max_label_num ())
+    grow_label_align ();
+
+  FOR_EACH_VEC_ELT (label_pairs, i, iter)
+    if (i & 1)
+      {
+       LABEL_TO_ALIGNMENT (label) = LABEL_TO_ALIGNMENT (iter);
+       LABEL_TO_MAX_SKIP (label) = LABEL_TO_MAX_SKIP (iter);
+      }
+    else
+      label = iter;
+}
+
+namespace {
+
+const pass_data pass_data_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_verify_rtl_sharing
-  | TODO_ggc_collect                    /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "alignments", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
+class pass_compute_alignments : public rtl_opt_pass
+{
+public:
+  pass_compute_alignments (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_compute_alignments, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual unsigned int execute (function *) { return compute_alignments (); }
+
+}; // class pass_compute_alignments
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_compute_alignments (gcc::context *ctxt)
+{
+  return new pass_compute_alignments (ctxt);
+}
+
 \f
 /* Make a pass over all insns and compute their actual lengths by shortening
    any branches of variable length if possible.  */
@@ -855,24 +900,21 @@ struct rtl_opt_pass pass_compute_alignments =
    slots.  */
 
 void
-shorten_branches (rtx first ATTRIBUTE_UNUSED)
+shorten_branches (rtx_insn *first)
 {
-  rtx insn;
+  rtx_insn *insn;
   int max_uid;
   int i;
   int max_log;
   int max_skip;
-#ifdef HAVE_ATTR_length
 #define MAX_CODE_ALIGN 16
-  rtx seq;
+  rtx_insn *seq;
   int something_changed = 1;
   char *varying_length;
   rtx body;
   int uid;
   rtx align_tab[MAX_CODE_ALIGN];
 
-#endif
-
   /* Compute maximum UID and allocate label_align / uid_shuid.  */
   max_uid = get_max_uid ();
 
@@ -882,25 +924,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
   uid_shuid = XNEWVEC (int, max_uid);
 
   if (max_labelno != max_label_num ())
-    {
-      int old = max_labelno;
-      int n_labels;
-      int n_old_labels;
-
-      max_labelno = max_label_num ();
-
-      n_labels = max_labelno - min_labelno + 1;
-      n_old_labels = old - min_labelno + 1;
-
-      label_align = XRESIZEVEC (struct label_alignment, label_align, n_labels);
-
-      /* 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);
-
-      memset (label_align + n_old_labels, 0,
-             (n_labels - n_old_labels) * sizeof (struct label_alignment));
-    }
+    grow_label_align ();
 
   /* Initialize label_align and set up uid_shuid to be strictly
      monotonically rising with insn order.  */
@@ -921,7 +945,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
 
       if (LABEL_P (insn))
        {
-         rtx next;
+         rtx_insn *next;
          bool next_is_jumptable;
 
          /* Merge in alignments computed by compute_alignments.  */
@@ -963,7 +987,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
        }
       else if (BARRIER_P (insn))
        {
-         rtx label;
+         rtx_insn *label;
 
          for (label = insn; label && ! INSN_P (label);
               label = NEXT_INSN (label))
@@ -979,7 +1003,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
              }
        }
     }
-#ifdef HAVE_ATTR_length
+  if (!HAVE_ATTR_length)
+    return;
 
   /* Allocate the rest of the arrays.  */
   insn_lengths = XNEWVEC (int, max_uid);
@@ -1014,6 +1039,13 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
            align_tab[i] = seq;
        }
     }
+
+  /* When optimizing, we start assuming minimum length, and keep increasing
+     lengths as we find the need for this, till nothing changes.
+     When not optimizing, we start assuming maximum lengths, and
+     do a single pass to update the lengths.  */
+  bool increasing = optimize != 0;
+
 #ifdef CASE_VECTOR_SHORTEN_MODE
   if (optimize)
     {
@@ -1031,7 +1063,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
          int min_align;
          addr_diff_vec_flags flags;
 
-         if (!JUMP_P (insn)
+         if (! JUMP_TABLE_DATA_P (insn)
              || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
            continue;
          pat = PATTERN (insn);
@@ -1067,11 +1099,16 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
          flags.min_after_base = min > rel;
          flags.max_after_base = max > rel;
          ADDR_DIFF_VEC_FLAGS (pat) = flags;
+
+         if (increasing)
+           PUT_MODE (pat, CASE_VECTOR_SHORTEN_MODE (0, 0, pat));
        }
     }
 #endif /* CASE_VECTOR_SHORTEN_MODE */
 
   /* Compute initial lengths, addresses, and varying flags for each insn.  */
+  int (*length_fun) (rtx) = increasing ? insn_min_length : insn_default_length;
+
   for (insn_current_address = 0, insn = first;
        insn != 0;
        insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
@@ -1094,13 +1131,13 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
       INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid];
 
       if (NOTE_P (insn) || BARRIER_P (insn)
-         || LABEL_P (insn) || DEBUG_INSN_P(insn))
+         || LABEL_P (insn) || DEBUG_INSN_P (insn))
        continue;
       if (INSN_DELETED_P (insn))
        continue;
 
       body = PATTERN (insn);
-      if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
+      if (JUMP_TABLE_DATA_P (insn))
        {
          /* This only takes room if read-only data goes into the text
             section.  */
@@ -1113,30 +1150,32 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
        }
       else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
        insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);
-      else if (GET_CODE (body) == SEQUENCE)
+      else if (rtx_sequence *body_seq = dyn_cast <rtx_sequence *> (body))
        {
          int i;
          int const_delay_slots;
 #ifdef DELAY_SLOTS
-         const_delay_slots = const_num_delay_slots (XVECEXP (body, 0, 0));
+         const_delay_slots = const_num_delay_slots (body_seq->insn (0));
 #else
          const_delay_slots = 0;
 #endif
+         int (*inner_length_fun) (rtx)
+           = const_delay_slots ? length_fun : insn_default_length;
          /* Inside a delay slot sequence, we do not do any branch shortening
             if the shortening could change the number of delay slots
             of the branch.  */
-         for (i = 0; i < XVECLEN (body, 0); i++)
+         for (i = 0; i < body_seq->len (); i++)
            {
-             rtx inner_insn = XVECEXP (body, 0, i);
+             rtx_insn *inner_insn = body_seq->insn (i);
              int inner_uid = INSN_UID (inner_insn);
              int inner_length;
 
              if (GET_CODE (body) == ASM_INPUT
-                 || asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0)
+                 || asm_noperands (PATTERN (inner_insn)) >= 0)
                inner_length = (asm_insn_count (PATTERN (inner_insn))
                                * insn_default_length (inner_insn));
              else
-               inner_length = insn_default_length (inner_insn);
+               inner_length = inner_length_fun (inner_insn);
 
              insn_lengths[inner_uid] = inner_length;
              if (const_delay_slots)
@@ -1154,7 +1193,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
        }
       else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER)
        {
-         insn_lengths[uid] = insn_default_length (insn);
+         insn_lengths[uid] = length_fun (insn);
          varying_length[uid] = insn_variable_length_p (insn);
        }
 
@@ -1189,6 +1228,29 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
          if (LABEL_P (insn))
            {
              int log = LABEL_TO_ALIGNMENT (insn);
+
+#ifdef CASE_VECTOR_SHORTEN_MODE
+             /* If the mode of a following jump table was changed, we
+                may need to update the alignment of this label.  */
+             rtx_insn *next;
+             bool next_is_jumptable;
+
+             next = next_nonnote_insn (insn);
+             next_is_jumptable = next && JUMP_TABLE_DATA_P (next);
+             if ((JUMP_TABLES_IN_TEXT_SECTION
+                  || readonly_data_section == text_section)
+                 && next_is_jumptable)
+               {
+                 int newlog = ADDR_VEC_ALIGN (next);
+                 if (newlog != log)
+                   {
+                     log = newlog;
+                     LABEL_TO_ALIGNMENT (insn) = log;
+                     something_changed = 1;
+                   }
+               }
+#endif
+
              if (log > insn_current_align)
                {
                  int align = 1 << log;
@@ -1211,20 +1273,23 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
          INSN_ADDRESSES (uid) = insn_current_address;
 
 #ifdef CASE_VECTOR_SHORTEN_MODE
-         if (optimize && JUMP_P (insn)
+         if (optimize
+             && JUMP_TABLE_DATA_P (insn)
              && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
            {
              rtx body = PATTERN (insn);
              int old_length = insn_lengths[uid];
-             rtx rel_lab = XEXP (XEXP (body, 0), 0);
+             rtx_insn *rel_lab =
+               safe_as_a <rtx_insn *> (XEXP (XEXP (body, 0), 0));
              rtx min_lab = XEXP (XEXP (body, 2), 0);
              rtx max_lab = XEXP (XEXP (body, 3), 0);
              int rel_addr = INSN_ADDRESSES (INSN_UID (rel_lab));
              int min_addr = INSN_ADDRESSES (INSN_UID (min_lab));
              int max_addr = INSN_ADDRESSES (INSN_UID (max_lab));
-             rtx prev;
+             rtx_insn *prev;
              int rel_align = 0;
              addr_diff_vec_flags flags;
+             enum machine_mode vec_mode;
 
              /* Avoid automatic aggregate initialization.  */
              flags = ADDR_DIFF_VEC_FLAGS (body);
@@ -1303,9 +1368,12 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
                  else
                    max_addr += align_fuzz (max_lab, rel_lab, 0, 0);
                }
-             PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
-                                                       max_addr - rel_addr,
-                                                       body));
+             vec_mode = CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
+                                                  max_addr - rel_addr, body);
+             if (!increasing
+                 || (GET_MODE_SIZE (vec_mode)
+                     >= GET_MODE_SIZE (GET_MODE (body))))
+               PUT_MODE (body, vec_mode);
              if (JUMP_TABLES_IN_TEXT_SECTION
                  || readonly_data_section == text_section)
                {
@@ -1367,10 +1435,15 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
 
                  if (inner_length != insn_lengths[inner_uid])
                    {
-                     insn_lengths[inner_uid] = inner_length;
-                     something_changed = 1;
+                     if (!increasing || inner_length > insn_lengths[inner_uid])
+                       {
+                         insn_lengths[inner_uid] = inner_length;
+                         something_changed = 1;
+                       }
+                     else
+                       inner_length = insn_lengths[inner_uid];
                    }
-                 insn_current_address += insn_lengths[inner_uid];
+                 insn_current_address += inner_length;
                  new_length += inner_length;
                }
            }
@@ -1387,23 +1460,23 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
          insn_current_address += (new_length - tmp_length);
 #endif
 
-         if (new_length != insn_lengths[uid])
+         if (new_length != insn_lengths[uid]
+             && (!increasing || new_length > insn_lengths[uid]))
            {
              insn_lengths[uid] = new_length;
              something_changed = 1;
            }
+         else
+           insn_current_address += insn_lengths[uid] - new_length;
        }
       /* For a non-optimizing compile, do only a single pass.  */
-      if (!optimize)
+      if (!increasing)
        break;
     }
 
   free (varying_length);
-
-#endif /* HAVE_ATTR_length */
 }
 
-#ifdef HAVE_ATTR_length
 /* Given the body of an INSN known to be generated by an ASM statement, return
    the number of machine instructions likely to be generated for this insn.
    This is used to compute its length.  */
@@ -1420,7 +1493,6 @@ asm_insn_count (rtx body)
 
   return asm_str_count (templ);
 }
-#endif
 
 /* Return the number of machine instructions likely to be generated for the
    inline-asm template. */
@@ -1454,7 +1526,7 @@ typedef struct debug_prefix_map
 } debug_prefix_map;
 
 /* Linked list of such structures.  */
-debug_prefix_map *debug_prefix_maps;
+static debug_prefix_map *debug_prefix_maps;
 
 
 /* Record a debug file prefix mapping.  ARG is the argument to
@@ -1520,6 +1592,165 @@ dwarf2_debug_info_emitted_p (tree decl)
   return true;
 }
 
+/* Return scope resulting from combination of S1 and S2.  */
+static tree
+choose_inner_scope (tree s1, tree s2)
+{
+   if (!s1)
+     return s2;
+   if (!s2)
+     return s1;
+   if (BLOCK_NUMBER (s1) > BLOCK_NUMBER (s2))
+     return s1;
+   return s2;
+}
+
+/* Emit lexical block notes needed to change scope from S1 to S2.  */
+
+static void
+change_scope (rtx_insn *orig_insn, tree s1, tree s2)
+{
+  rtx_insn *insn = orig_insn;
+  tree com = NULL_TREE;
+  tree ts1 = s1, ts2 = s2;
+  tree s;
+
+  while (ts1 != ts2)
+    {
+      gcc_assert (ts1 && ts2);
+      if (BLOCK_NUMBER (ts1) > BLOCK_NUMBER (ts2))
+       ts1 = BLOCK_SUPERCONTEXT (ts1);
+      else if (BLOCK_NUMBER (ts1) < BLOCK_NUMBER (ts2))
+       ts2 = BLOCK_SUPERCONTEXT (ts2);
+      else
+       {
+         ts1 = BLOCK_SUPERCONTEXT (ts1);
+         ts2 = BLOCK_SUPERCONTEXT (ts2);
+       }
+    }
+  com = ts1;
+
+  /* Close scopes.  */
+  s = s1;
+  while (s != com)
+    {
+      rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
+      NOTE_BLOCK (note) = s;
+      s = BLOCK_SUPERCONTEXT (s);
+    }
+
+  /* Open scopes.  */
+  s = s2;
+  while (s != com)
+    {
+      insn = emit_note_before (NOTE_INSN_BLOCK_BEG, insn);
+      NOTE_BLOCK (insn) = s;
+      s = BLOCK_SUPERCONTEXT (s);
+    }
+}
+
+/* Rebuild all the NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes based
+   on the scope tree and the newly reordered instructions.  */
+
+static void
+reemit_insn_block_notes (void)
+{
+  tree cur_block = DECL_INITIAL (cfun->decl);
+  rtx_insn *insn;
+  rtx_note *note;
+
+  insn = get_insns ();
+  for (; insn; insn = NEXT_INSN (insn))
+    {
+      tree this_block;
+
+      /* Prevent lexical blocks from straddling section boundaries.  */
+      if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
+        {
+          for (tree s = cur_block; s != DECL_INITIAL (cfun->decl);
+               s = BLOCK_SUPERCONTEXT (s))
+            {
+              rtx_note *note = emit_note_before (NOTE_INSN_BLOCK_END, insn);
+              NOTE_BLOCK (note) = s;
+              note = emit_note_after (NOTE_INSN_BLOCK_BEG, insn);
+              NOTE_BLOCK (note) = s;
+            }
+        }
+
+      if (!active_insn_p (insn))
+        continue;
+
+      /* Avoid putting scope notes between jump table and its label.  */
+      if (JUMP_TABLE_DATA_P (insn))
+       continue;
+
+      this_block = insn_scope (insn);
+      /* For sequences compute scope resulting from merging all scopes
+        of instructions nested inside.  */
+      if (rtx_sequence *body = dyn_cast <rtx_sequence *> (PATTERN (insn)))
+       {
+         int i;
+
+         this_block = NULL;
+         for (i = 0; i < body->len (); i++)
+           this_block = choose_inner_scope (this_block,
+                                            insn_scope (body->insn (i)));
+       }
+      if (! this_block)
+       {
+         if (INSN_LOCATION (insn) == UNKNOWN_LOCATION)
+           continue;
+         else
+           this_block = DECL_INITIAL (cfun->decl);
+       }
+
+      if (this_block != cur_block)
+       {
+         change_scope (insn, cur_block, this_block);
+         cur_block = this_block;
+       }
+    }
+
+  /* change_scope emits before the insn, not after.  */
+  note = emit_note (NOTE_INSN_DELETED);
+  change_scope (note, cur_block, DECL_INITIAL (cfun->decl));
+  delete_insn (note);
+
+  reorder_blocks ();
+}
+
+static const char *some_local_dynamic_name;
+
+/* Locate some local-dynamic symbol still in use by this function
+   so that we can print its name in local-dynamic base patterns.
+   Return null if there are no local-dynamic references.  */
+
+const char *
+get_some_local_dynamic_name ()
+{
+  subrtx_iterator::array_type array;
+  rtx_insn *insn;
+
+  if (some_local_dynamic_name)
+    return some_local_dynamic_name;
+
+  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
+    if (NONDEBUG_INSN_P (insn))
+      FOR_EACH_SUBRTX (iter, array, PATTERN (insn), ALL)
+       {
+         const_rtx x = *iter;
+         if (GET_CODE (x) == SYMBOL_REF)
+           {
+             if (SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)
+               return some_local_dynamic_name = XSTR (x, 0);
+             if (CONSTANT_POOL_ADDRESS_P (x))
+               iter.substitute (get_pool_constant (x));
+           }
+       }
+
+  return 0;
+}
+
 /* 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
@@ -1531,19 +1762,24 @@ dwarf2_debug_info_emitted_p (tree decl)
      test and compare insns.  */
 
 void
-final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
+final_start_function (rtx_insn *first, FILE *file,
                      int optimize_p ATTRIBUTE_UNUSED)
 {
   block_depth = 0;
 
   this_is_asm_operands = 0;
 
-  last_filename = locator_file (prologue_locator);
-  last_linenum = locator_line (prologue_locator);
+  need_profile_function = false;
+
+  last_filename = LOCATION_FILE (prologue_location);
+  last_linenum = LOCATION_LINE (prologue_location);
   last_discriminator = discriminator = 0;
 
   high_block_linenum = high_function_linenum = last_linenum;
 
+  if (flag_sanitize & SANITIZE_ADDRESS)
+    asan_function_start ();
+
   if (!DECL_IGNORED_P (current_function_decl))
     debug_hooks->begin_prologue (last_linenum, last_filename);
 
@@ -1551,19 +1787,48 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
     dwarf2out_begin_prologue (0, NULL);
 
 #ifdef LEAF_REG_REMAP
-  if (current_function_uses_only_leaf_regs)
+  if (crtl->uses_only_leaf_regs)
     leaf_renumber_regs (first);
 #endif
 
   /* The Sun386i and perhaps other machines don't work right
      if the profiling code comes after the prologue.  */
   if (targetm.profile_before_prologue () && crtl->profile)
-    profile_function (file);
-
-#if defined (HAVE_prologue)
-  if (dwarf2out_do_frame ())
-    dwarf2out_frame_debug_init ();
+    {
+      if (targetm.asm_out.function_prologue
+         == default_function_pro_epilogue
+#ifdef HAVE_prologue
+         && HAVE_prologue
 #endif
+        )
+       {
+         rtx_insn *insn;
+         for (insn = first; insn; insn = NEXT_INSN (insn))
+           if (!NOTE_P (insn))
+             {
+               insn = NULL;
+               break;
+             }
+           else if (NOTE_KIND (insn) == NOTE_INSN_BASIC_BLOCK
+                    || NOTE_KIND (insn) == NOTE_INSN_FUNCTION_BEG)
+             break;
+           else if (NOTE_KIND (insn) == NOTE_INSN_DELETED
+                    || NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
+             continue;
+           else
+             {
+               insn = NULL;
+               break;
+             }
+
+         if (insn)
+           need_profile_function = true;
+         else
+           profile_function (file);
+       }
+      else
+       profile_function (file);
+    }
 
   /* If debugging, assign block numbers to all of the blocks in this
      function.  */
@@ -1589,11 +1854,6 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
   /* First output the function prologue: code to set up the stack frame.  */
   targetm.asm_out.function_prologue (file, get_frame_size ());
 
-#if defined (HAVE_prologue)
-  if (dwarf2out_do_frame ())
-    dwarf2out_frame_debug_after_prologue ();
-#endif
-
   /* If the machine represents the prologue as RTL, the profiling code must
      be emitted when NOTE_INSN_PROLOGUE_END is scanned.  */
 #ifdef HAVE_prologue
@@ -1676,6 +1936,8 @@ final_end_function (void)
   if (!dwarf2_debug_info_emitted_p (current_function_decl)
       && dwarf2out_do_frame ())
     dwarf2out_end_epilogue (last_linenum, last_filename);
+
+  some_local_dynamic_name = 0;
 }
 \f
 
@@ -1683,7 +1945,7 @@ final_end_function (void)
    output file, and INSN is the instruction being emitted.  */
 
 static void
-dump_basic_block_info (FILE *file, rtx insn, basic_block *start_to_bb,
+dump_basic_block_info (FILE *file, rtx_insn *insn, basic_block *start_to_bb,
                        basic_block *end_to_bb, int bb_map_size, int *bb_seqn)
 {
   basic_block bb;
@@ -1701,13 +1963,13 @@ dump_basic_block_info (FILE *file, rtx insn, basic_block *start_to_bb,
       if (bb->frequency)
         fprintf (file, " freq:%d", bb->frequency);
       if (bb->count)
-        fprintf (file, " count:" HOST_WIDEST_INT_PRINT_DEC,
+        fprintf (file, " count:%"PRId64,
                  bb->count);
       fprintf (file, " seq:%d", (*bb_seqn)++);
       fprintf (file, "\n%s PRED:", ASM_COMMENT_START);
       FOR_EACH_EDGE (e, ei, bb->preds)
         {
-          dump_edge_info (file, e, 0);
+          dump_edge_info (file, e, TDF_DETAILS, 0);
         }
       fprintf (file, "\n");
     }
@@ -1720,7 +1982,7 @@ dump_basic_block_info (FILE *file, rtx insn, basic_block *start_to_bb,
       fprintf (asm_out_file, "%s SUCC:", ASM_COMMENT_START);
       FOR_EACH_EDGE (e, ei, bb->succs)
        {
-         dump_edge_info (asm_out_file, e, 1);
+         dump_edge_info (asm_out_file, e, TDF_DETAILS, 1);
        }
       fprintf (file, "\n");
     }
@@ -1730,10 +1992,9 @@ dump_basic_block_info (FILE *file, rtx insn, basic_block *start_to_bb,
    For description of args, see `final_start_function', above.  */
 
 void
-final (rtx first, FILE *file, int optimize_p)
+final (rtx_insn *first, FILE *file, int optimize_p)
 {
-  rtx insn, next;
-  int max_uid = 0;
+  rtx_insn *insn, *next;
   int seen = 0;
 
   /* Used for -dA dump.  */
@@ -1744,23 +2005,21 @@ final (rtx first, FILE *file, int optimize_p)
 
   last_ignored_compare = 0;
 
+#ifdef HAVE_cc0
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
-      if (INSN_UID (insn) > max_uid)       /* Find largest UID.  */
-       max_uid = INSN_UID (insn);
-#ifdef HAVE_cc0
       /* If CC tracking across branches is enabled, record the insn which
         jumps to each branch only reached from one place.  */
       if (optimize_p && JUMP_P (insn))
        {
          rtx lab = JUMP_LABEL (insn);
-         if (lab && LABEL_NUSES (lab) == 1)
+         if (lab && LABEL_P (lab) && LABEL_NUSES (lab) == 1)
            {
              LABEL_REFS (lab) = insn;
            }
        }
-#endif
     }
+#endif
 
   init_recog ();
 
@@ -1774,27 +2033,30 @@ final (rtx first, FILE *file, int optimize_p)
       start_to_bb = XCNEWVEC (basic_block, bb_map_size);
       end_to_bb = XCNEWVEC (basic_block, bb_map_size);
 
-      FOR_EACH_BB_REVERSE (bb)
-       {
-         start_to_bb[INSN_UID (BB_HEAD (bb))] = bb;
-         end_to_bb[INSN_UID (BB_END (bb))] = bb;
-       }
+      /* There is no cfg for a thunk.  */
+      if (!cfun->is_thunk)
+       FOR_EACH_BB_REVERSE_FN (bb, cfun)
+         {
+           start_to_bb[INSN_UID (BB_HEAD (bb))] = bb;
+           end_to_bb[INSN_UID (BB_END (bb))] = bb;
+         }
     }
 
   /* Output the insns.  */
   for (insn = first; insn;)
     {
-#ifdef HAVE_ATTR_length
-      if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ())
+      if (HAVE_ATTR_length)
        {
-         /* This can be triggered by bugs elsewhere in the compiler if
-            new insns are created after init_insn_lengths is called.  */
-         gcc_assert (NOTE_P (insn));
-         insn_current_address = -1;
+         if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ())
+           {
+             /* This can be triggered by bugs elsewhere in the compiler if
+                new insns are created after init_insn_lengths is called.  */
+             gcc_assert (NOTE_P (insn));
+             insn_current_address = -1;
+           }
+         else
+           insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
        }
-      else
-       insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
-#endif /* HAVE_ATTR_length */
 
       dump_basic_block_info (file, insn, start_to_bb, end_to_bb,
                              bb_map_size, &bb_seqn);
@@ -1829,7 +2091,8 @@ get_insn_template (int code, rtx insn)
       return insn_data[code].output.multi[which_alternative];
     case INSN_OUTPUT_FORMAT_FUNCTION:
       gcc_assert (insn);
-      return (*insn_data[code].output.function) (recog_data.operand, insn);
+      return (*insn_data[code].output.function) (recog_data.operand,
+                                                as_a <rtx_insn *> (insn));
 
     default:
       gcc_unreachable ();
@@ -1842,7 +2105,7 @@ get_insn_template (int code, rtx insn)
 
    The case fall-through in this function is intentional.  */
 static void
-output_alternate_entry_point (FILE *file, rtx insn)
+output_alternate_entry_point (FILE *file, rtx_insn *insn)
 {
   const char *name = LABEL_NAME (insn);
 
@@ -1869,7 +2132,7 @@ output_alternate_entry_point (FILE *file, rtx insn)
 
 /* Given a CALL_INSN, find and return the nested CALL. */
 static rtx
-call_from_call_insn (rtx insn)
+call_from_call_insn (rtx_call_insn *insn)
 {
   rtx x;
   gcc_assert (CALL_P (insn));
@@ -1905,18 +2168,16 @@ call_from_call_insn (rtx insn)
 
    SEEN is used to track the end of the prologue, for emitting
    debug information.  We force the emission of a line note after
-   both NOTE_INSN_PROLOGUE_END and NOTE_INSN_FUNCTION_BEG, or
-   at the beginning of the second basic block, whichever comes
-   first.  */
+   both NOTE_INSN_PROLOGUE_END and NOTE_INSN_FUNCTION_BEG.  */
 
-rtx
-final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
+rtx_insn *
+final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
                 int nopeepholes ATTRIBUTE_UNUSED, int *seen)
 {
 #ifdef HAVE_cc0
   rtx set;
 #endif
-  rtx next;
+  rtx_insn *next;
 
   insn_counter++;
 
@@ -1945,19 +2206,26 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
          targetm.asm_out.function_switched_text_sections (asm_out_file,
                                                           current_function_decl,
                                                           in_cold_section_p);
+         /* Emit a label for the split cold section.  Form label name by
+            suffixing "cold" to the original function's name.  */
+         if (in_cold_section_p)
+           {
+             tree cold_function_name
+               = clone_function_name (current_function_decl, "cold");
+             ASM_OUTPUT_LABEL (asm_out_file,
+                               IDENTIFIER_POINTER (cold_function_name));
+           }
          break;
 
        case NOTE_INSN_BASIC_BLOCK:
-         if (targetm.asm_out.unwind_emit)
-           targetm.asm_out.unwind_emit (asm_out_file, insn);
-
-         if ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB)
+         if (need_profile_function)
            {
-             *seen |= SEEN_EMITTED;
-             force_source_line = true;
+             profile_function (asm_out_file);
+             need_profile_function = false;
            }
-         else
-           *seen |= SEEN_BB;
+
+         if (targetm.asm_out.unwind_emit)
+           targetm.asm_out.unwind_emit (asm_out_file, insn);
 
           discriminator = NOTE_BASIC_BLOCK (insn)->discriminator;
 
@@ -1988,13 +2256,11 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
          break;
 
        case NOTE_INSN_EPILOGUE_BEG:
-         (*debug_hooks->begin_epilogue) (last_linenum, last_filename);
+          if (!DECL_IGNORED_P (current_function_decl))
+            (*debug_hooks->begin_epilogue) (last_linenum, last_filename);
          targetm.asm_out.function_begin_epilogue (file);
          break;
 
-       case NOTE_INSN_CFA_RESTORE_STATE:
-         break;
-
        case NOTE_INSN_CFI:
          dwarf2out_emit_cfi (NOTE_CFI (insn));
          break;
@@ -2005,6 +2271,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
          break;
 
        case NOTE_INSN_FUNCTION_BEG:
+         if (need_profile_function)
+           {
+             profile_function (asm_out_file);
+             need_profile_function = false;
+           }
+
          app_disable ();
          if (!DECL_IGNORED_P (current_function_decl))
            debug_hooks->end_prologue (last_linenum, last_filename);
@@ -2098,6 +2370,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
          ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
          break;
 
+       case NOTE_INSN_DELETED_DEBUG_LABEL:
+         /* Similarly, but need to use different namespace for it.  */
+         if (CODE_LABEL_NUMBER (insn) != -1)
+           ASM_OUTPUT_DEBUG_LABEL (file, "LDL", CODE_LABEL_NUMBER (insn));
+         break;
+
        case NOTE_INSN_VAR_LOCATION:
        case NOTE_INSN_CALL_ARG_LOCATION:
          if (!DECL_IGNORED_P (current_function_decl))
@@ -2139,7 +2417,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
       CC_STATUS_INIT;
 
       if (!DECL_IGNORED_P (current_function_decl) && LABEL_NAME (insn))
-       debug_hooks->label (insn);
+       debug_hooks->label (as_a <rtx_code_label *> (insn));
 
       app_disable ();
 
@@ -2213,7 +2491,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
          rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
          if (note)
            {
-             NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0));
+             rtx_insn *other = as_a <rtx_insn *> (XEXP (note, 0));
+             NOTICE_UPDATE_CC (PATTERN (other), other);
              cc_prev_status = cc_status;
            }
        }
@@ -2222,7 +2501,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
        /* Detect insns that are really jump-tables
           and output them as such.  */
 
-       if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
+        if (JUMP_TABLE_DATA_P (insn))
          {
 #if !(defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC))
            int vlen, idx;
@@ -2369,29 +2648,29 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 
        app_disable ();
 
-       if (GET_CODE (body) == SEQUENCE)
+       if (rtx_sequence *seq = dyn_cast <rtx_sequence *> (body))
          {
            /* A delayed-branch sequence */
            int i;
 
-           final_sequence = body;
+           final_sequence = seq;
 
            /* The first insn in this SEQUENCE might be a JUMP_INSN that will
               force the restoration of a comparison that was previously
               thought unnecessary.  If that happens, cancel this sequence
               and cause that insn to be restored.  */
 
-           next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, 1, seen);
-           if (next != XVECEXP (body, 0, 1))
+           next = final_scan_insn (seq->insn (0), file, 0, 1, seen);
+           if (next != seq->insn (1))
              {
                final_sequence = 0;
                return next;
              }
 
-           for (i = 1; i < XVECLEN (body, 0); i++)
+           for (i = 1; i < seq->len (); i++)
              {
-               rtx insn = XVECEXP (body, 0, i);
-               rtx next = NEXT_INSN (insn);
+               rtx_insn *insn = seq->insn (i);
+               rtx_insn *next = NEXT_INSN (insn);
                /* We loop in case any instruction in a delay slot gets
                   split.  */
                do
@@ -2408,7 +2687,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
               called function.  Hence we don't preserve any CC-setting
               actions in these insns and the CC must be marked as being
               clobbered by the function.  */
-           if (CALL_P (XVECEXP (body, 0, 0)))
+           if (CALL_P (seq->insn (0)))
              {
                CC_STATUS_INIT;
              }
@@ -2438,7 +2717,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
              {
                rtx src1, src2;
                if (GET_CODE (SET_SRC (set)) == SUBREG)
-                 SET_SRC (set) = alter_subreg (&SET_SRC (set));
+                 SET_SRC (set) = alter_subreg (&SET_SRC (set), true);
 
                src1 = SET_SRC (set);
                src2 = NULL_RTX;
@@ -2446,10 +2725,10 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
                  {
                    if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
                      XEXP (SET_SRC (set), 0)
-                       = alter_subreg (&XEXP (SET_SRC (set), 0));
+                       = alter_subreg (&XEXP (SET_SRC (set), 0), true);
                    if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
                      XEXP (SET_SRC (set), 1)
-                       = alter_subreg (&XEXP (SET_SRC (set), 1));
+                       = alter_subreg (&XEXP (SET_SRC (set), 1), true);
                    if (XEXP (SET_SRC (set), 1)
                        == CONST0_RTX (GET_MODE (XEXP (SET_SRC (set), 0))))
                      src2 = XEXP (SET_SRC (set), 0);
@@ -2510,7 +2789,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
                delete_insn (insn);
                break;
              }
-           else if (GET_CODE (SET_SRC (body)) == RETURN)
+           else if (ANY_RETURN_P (SET_SRC (body)))
              /* Replace (set (pc) (return)) with (return).  */
              PATTERN (insn) = body = SET_SRC (body);
 
@@ -2577,36 +2856,19 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
                else_rtx = const0_rtx;
              }
 
-           switch (GET_CODE (cond_rtx))
+           if (COMPARISON_P (cond_rtx)
+               && XEXP (cond_rtx, 0) == cc0_rtx)
              {
-             case GTU:
-             case GT:
-             case LTU:
-             case LT:
-             case GEU:
-             case GE:
-             case LEU:
-             case LE:
-             case EQ:
-             case NE:
-               {
-                 int result;
-                 if (XEXP (cond_rtx, 0) != cc0_rtx)
-                   break;
-                 result = alter_cond (cond_rtx);
-                 if (result == 1)
-                   validate_change (insn, &SET_SRC (set), then_rtx, 0);
-                 else if (result == -1)
-                   validate_change (insn, &SET_SRC (set), else_rtx, 0);
-                 else if (result == 2)
-                   INSN_CODE (insn) = -1;
-                 if (SET_DEST (set) == SET_SRC (set))
-                   delete_insn (insn);
-               }
-               break;
-
-             default:
-               break;
+               int result;
+               result = alter_cond (cond_rtx);
+               if (result == 1)
+                 validate_change (insn, &SET_SRC (set), then_rtx, 0);
+               else if (result == -1)
+                 validate_change (insn, &SET_SRC (set), else_rtx, 0);
+               else if (result == 2)
+                 INSN_CODE (insn) = -1;
+               if (SET_DEST (set) == SET_SRC (set))
+                 delete_insn (insn);
              }
          }
 
@@ -2617,12 +2879,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 
        if (optimize_p && !flag_no_peephole && !nopeepholes)
          {
-           rtx next = peephole (insn);
+           rtx_insn *next = peephole (insn);
            /* When peepholing, if there were notes within the peephole,
               emit them before the peephole.  */
            if (next != 0 && next != NEXT_INSN (insn))
              {
-               rtx note, prev = PREV_INSN (insn);
+               rtx_insn *note, *prev = PREV_INSN (insn);
 
                for (note = NEXT_INSN (insn); note != next;
                     note = NEXT_INSN (note))
@@ -2633,12 +2895,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
                   when generating a far jump in a delayed branch
                   sequence.  */
                note = NEXT_INSN (insn);
-               PREV_INSN (note) = prev;
-               NEXT_INSN (prev) = note;
-               NEXT_INSN (PREV_INSN (next)) = insn;
-               PREV_INSN (insn) = PREV_INSN (next);
-               NEXT_INSN (insn) = next;
-               PREV_INSN (next) = insn;
+               SET_PREV_INSN (note) = prev;
+               SET_NEXT_INSN (prev) = note;
+               SET_NEXT_INSN (PREV_INSN (next)) = insn;
+               SET_PREV_INSN (insn) = PREV_INSN (next);
+               SET_NEXT_INSN (insn) = next;
+               SET_PREV_INSN (next) = insn;
              }
 
            /* PEEPHOLE might have changed this.  */
@@ -2654,11 +2916,16 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
        insn_code_number = recog_memoized (insn);
        cleanup_subreg_operands (insn);
 
-       /* Dump the insn in the assembly for debugging.  */
+       /* Dump the insn in the assembly for debugging (-dAP).
+          If the final dump is requested as slim RTL, dump slim
+          RTL to the assembly file also.  */
        if (flag_dump_rtl_in_asm)
          {
            print_rtx_head = ASM_COMMENT_START;
-           print_rtl_single (asm_out_file, insn);
+           if (! (dump_flags & TDF_SLIM))
+             print_rtl_single (asm_out_file, insn);
+           else
+             dump_insn_slim (asm_out_file, insn);
            print_rtx_head = "";
          }
 
@@ -2697,7 +2964,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
           needs to be reinserted.  */
        if (templ == 0)
          {
-           rtx prev;
+           rtx_insn *prev;
 
            gcc_assert (prev_nonnote_insn (insn) == last_ignored_compare);
 
@@ -2720,18 +2987,16 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
           be split.  */
        if (templ[0] == '#' && templ[1] == '\0')
          {
-           rtx new_rtx = try_split (body, insn, 0);
+           rtx_insn *new_rtx = try_split (body, insn, 0);
 
            /* If we didn't split the insn, go away.  */
            if (new_rtx == insn && PATTERN (new_rtx) == body)
              fatal_insn ("could not split insn", insn);
 
-#ifdef HAVE_ATTR_length
-           /* This instruction should have been split in shorten_branches,
-              to ensure that we would have valid length info for the
-              splitees.  */
-           gcc_unreachable ();
-#endif
+           /* If we have a length attribute, this instruction should have
+              been split in shorten_branches, to ensure that we would have
+              valid length info for the splitees.  */
+           gcc_assert (!HAVE_ATTR_length);
 
            return new_rtx;
          }
@@ -2743,9 +3008,9 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
            && targetm.asm_out.unwind_emit)
          targetm.asm_out.unwind_emit (asm_out_file, insn);
 
-       if (CALL_P (insn))
+       if (rtx_call_insn *call_insn = dyn_cast <rtx_call_insn *> (insn))
          {
-           rtx x = call_from_call_insn (insn);
+           rtx x = call_from_call_insn (call_insn);
            x = XEXP (x, 0);
            if (x && MEM_P (x) && GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
              {
@@ -2783,7 +3048,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
    breakpoint location.  */
 
 static bool
-notice_source_line (rtx insn, bool *is_stmt)
+notice_source_line (rtx_insn *insn, bool *is_stmt)
 {
   const char *filename;
   int linenum;
@@ -2793,10 +3058,16 @@ notice_source_line (rtx insn, bool *is_stmt)
       filename = override_filename;
       linenum = override_linenum;
     }
+  else if (INSN_HAS_LOCATION (insn))
+    {
+      expanded_location xloc = insn_location (insn);
+      filename = xloc.file;
+      linenum = xloc.line;
+    }
   else
     {
-      filename = insn_file (insn);
-      linenum = insn_line (insn);
+      filename = NULL;
+      linenum = 0;
     }
 
   if (filename == NULL)
@@ -2833,7 +3104,7 @@ notice_source_line (rtx insn, bool *is_stmt)
    directly to the desired hard register.  */
 
 void
-cleanup_subreg_operands (rtx insn)
+cleanup_subreg_operands (rtx_insn *insn)
 {
   int i;
   bool changed = false;
@@ -2847,7 +3118,7 @@ cleanup_subreg_operands (rtx insn)
         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], true);
          changed = true;
        }
       else if (GET_CODE (recog_data.operand[i]) == PLUS
@@ -2860,7 +3131,7 @@ cleanup_subreg_operands (rtx insn)
     {
       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], true);
          changed = true;
        }
       else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS
@@ -2872,11 +3143,11 @@ cleanup_subreg_operands (rtx insn)
     df_insn_rescan (insn);
 }
 
-/* If X is a SUBREG, replace it with a REG or a MEM,
-   based on the thing it is a subreg of.  */
+/* If X is a SUBREG, try to replace it with a REG or a MEM, based on
+   the thing it is a subreg of.  Do it anyway if FINAL_P.  */
 
 rtx
-alter_subreg (rtx *xp)
+alter_subreg (rtx *xp, bool final_p)
 {
   rtx x = *xp;
   rtx y = SUBREG_REG (x);
@@ -2900,16 +3171,19 @@ alter_subreg (rtx *xp)
             offset += difference % UNITS_PER_WORD;
         }
 
-      *xp = adjust_address (y, GET_MODE (x), offset);
+      if (final_p)
+       *xp = adjust_address (y, GET_MODE (x), offset);
+      else
+       *xp = adjust_address_nv (y, GET_MODE (x), offset);
     }
   else
     {
       rtx new_rtx = simplify_subreg (GET_MODE (x), y, GET_MODE (y),
-                                SUBREG_BYTE (x));
+                                    SUBREG_BYTE (x));
 
       if (new_rtx != 0)
        *xp = new_rtx;
-      else if (REG_P (y))
+      else if (final_p && REG_P (y))
        {
          /* Simplify_subreg can't handle some REG cases, but we have to.  */
          unsigned int regno;
@@ -2949,7 +3223,7 @@ walk_alter_subreg (rtx *xp, bool *changed)
 
     case SUBREG:
       *changed = true;
-      return alter_subreg (xp);
+      return alter_subreg (xp, true);
 
     default:
       break;
@@ -3162,10 +3436,11 @@ output_asm_name (void)
               insn_data[num].name);
       if (insn_data[num].n_alternatives > 1)
        fprintf (asm_out_file, "/%d", which_alternative + 1);
-#ifdef HAVE_ATTR_length
-      fprintf (asm_out_file, "\t[length = %d]",
-              get_attr_length (debug_insn));
-#endif
+
+      if (HAVE_ATTR_length)
+       fprintf (asm_out_file, "\t[length = %d]",
+                get_attr_length (debug_insn));
+
       /* Clear this so only the first assembler insn
         of any rtl insn will get the special comment for -dp.  */
       debug_insn = 0;
@@ -3245,6 +3520,96 @@ output_asm_operand_names (rtx *operands, int *oporder, int nops)
     }
 }
 
+#ifdef ASSEMBLER_DIALECT
+/* Helper function to parse assembler dialects in the asm string.
+   This is called from output_asm_insn and asm_fprintf.  */
+static const char *
+do_assembler_dialects (const char *p, int *dialect)
+{
+  char c = *(p - 1);
+
+  switch (c)
+    {
+    case '{':
+      {
+        int i;
+
+        if (*dialect)
+          output_operand_lossage ("nested assembly dialect alternatives");
+        else
+          *dialect = 1;
+
+        /* If we want the first dialect, do nothing.  Otherwise, skip
+           DIALECT_NUMBER of strings ending with '|'.  */
+        for (i = 0; i < dialect_number; i++)
+          {
+            while (*p && *p != '}')
+             {
+               if (*p == '|')
+                 {
+                   p++;
+                   break;
+                 }
+
+               /* Skip over any character after a percent sign.  */
+               if (*p == '%')
+                 p++;
+               if (*p)
+                 p++;
+             }
+
+            if (*p == '}')
+             break;
+          }
+
+        if (*p == '\0')
+          output_operand_lossage ("unterminated assembly dialect alternative");
+      }
+      break;
+
+    case '|':
+      if (*dialect)
+        {
+          /* Skip to close brace.  */
+          do
+            {
+             if (*p == '\0')
+               {
+                 output_operand_lossage ("unterminated assembly dialect alternative");
+                 break;
+               }
+
+             /* Skip over any character after a percent sign.  */
+             if (*p == '%' && p[1])
+               {
+                 p += 2;
+                 continue;
+               }
+
+             if (*p++ == '}')
+               break;
+            }
+          while (1);
+
+          *dialect = 0;
+        }
+      else
+        putc (c, asm_out_file);
+      break;
+
+    case '}':
+      if (! *dialect)
+        putc (c, asm_out_file);
+      *dialect = 0;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  return p;
+}
+#endif
+
 /* Output text from TEMPLATE to the assembler output file,
    obeying %-directions to substitute operands taken from
    the vector OPERANDS.
@@ -3311,63 +3676,24 @@ output_asm_insn (const char *templ, rtx *operands)
 
 #ifdef ASSEMBLER_DIALECT
       case '{':
-       {
-         int i;
-
-         if (dialect)
-           output_operand_lossage ("nested assembly dialect alternatives");
-         else
-           dialect = 1;
-
-         /* If we want the first dialect, do nothing.  Otherwise, skip
-            DIALECT_NUMBER of strings ending with '|'.  */
-         for (i = 0; i < dialect_number; i++)
-           {
-             while (*p && *p != '}' && *p++ != '|')
-               ;
-             if (*p == '}')
-               break;
-             if (*p == '|')
-               p++;
-           }
-
-         if (*p == '\0')
-           output_operand_lossage ("unterminated assembly dialect alternative");
-       }
-       break;
-
-      case '|':
-       if (dialect)
-         {
-           /* Skip to close brace.  */
-           do
-             {
-               if (*p == '\0')
-                 {
-                   output_operand_lossage ("unterminated assembly dialect alternative");
-                   break;
-                 }
-             }
-           while (*p++ != '}');
-           dialect = 0;
-         }
-       else
-         putc (c, asm_out_file);
-       break;
-
       case '}':
-       if (! dialect)
-         putc (c, asm_out_file);
-       dialect = 0;
+      case '|':
+       p = do_assembler_dialects (p, &dialect);
        break;
 #endif
 
       case '%':
-       /* %% outputs a single %.  */
-       if (*p == '%')
+       /* %% outputs a single %.  %{, %} and %| print {, } and | respectively
+          if ASSEMBLER_DIALECT defined and these characters have a special
+          meaning as dialect delimiters.*/
+       if (*p == '%'
+#ifdef ASSEMBLER_DIALECT
+           || *p == '{' || *p == '}' || *p == '|'
+#endif
+           )
          {
+           putc (*p, asm_out_file);
            p++;
-           putc (c, asm_out_file);
          }
        /* %= outputs a number which is unique to each insn in the entire
           compilation.  This is useful for making local labels that are
@@ -3476,7 +3802,7 @@ output_asm_label (rtx x)
   char buf[256];
 
   if (GET_CODE (x) == LABEL_REF)
-    x = XEXP (x, 0);
+    x = LABEL_REF_LABEL (x);
   if (LABEL_P (x)
       || (NOTE_P (x)
          && NOTE_KIND (x) == NOTE_INSN_DELETED_LABEL))
@@ -3487,38 +3813,19 @@ output_asm_label (rtx x)
   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);
+  subrtx_iterator::array_type array;
+  FOR_EACH_SUBRTX (iter, array, x, ALL)
+    {
+      const_rtx x = *iter;
+      if (GET_CODE (x) == SYMBOL_REF)
+       if (tree t = SYMBOL_REF_DECL (x))
+         assemble_external (t);
+    }
 }
 
 /* Print operand X using machine-dependent assembler syntax.
@@ -3534,7 +3841,7 @@ void
 output_operand (rtx x, int code ATTRIBUTE_UNUSED)
 {
   if (x && GET_CODE (x) == SUBREG)
-    x = alter_subreg (&x);
+    x = alter_subreg (&x, true);
 
   /* X must not be a pseudo reg.  */
   gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER);
@@ -3544,7 +3851,7 @@ output_operand (rtx x, int code ATTRIBUTE_UNUSED)
   if (x == NULL_RTX)
     return;
 
-  for_each_rtx (&x, mark_symbol_ref_as_used, NULL);
+  mark_symbol_refs_as_used (x);
 }
 
 /* Print a memory reference operand for address X using
@@ -3585,7 +3892,7 @@ output_addr_const (FILE *file, rtx x)
       break;
 
     case LABEL_REF:
-      x = XEXP (x, 0);
+      x = LABEL_REF_LABEL (x);
       /* Fall through.  */
     case CODE_LABEL:
       ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
@@ -3606,8 +3913,21 @@ output_addr_const (FILE *file, rtx x)
       output_addr_const (file, XEXP (x, 0));
       break;
 
+    case CONST_WIDE_INT:
+      /* We do not know the mode here so we have to use a round about
+        way to build a wide-int to get it printed properly.  */
+      {
+       wide_int w = wide_int::from_array (&CONST_WIDE_INT_ELT (x, 0),
+                                          CONST_WIDE_INT_NUNITS (x),
+                                          CONST_WIDE_INT_NUNITS (x)
+                                          * HOST_BITS_PER_WIDE_INT,
+                                          false);
+       print_decs (w, file);
+      }
+      break;
+
     case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode)
+      if (CONST_DOUBLE_AS_INT_P (x))
        {
          /* We can use %d if the number is one word and positive.  */
          if (CONST_DOUBLE_HIGH (x))
@@ -3627,8 +3947,7 @@ output_addr_const (FILE *file, rtx x)
       break;
 
     case CONST_FIXED:
-      fprintf (file, HOST_WIDE_INT_PRINT_HEX,
-              (unsigned HOST_WIDE_INT) CONST_FIXED_VALUE_LOW (x));
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_FIXED_VALUE_LOW (x));
       break;
 
     case PLUS:
@@ -3712,6 +4031,97 @@ output_quoted_string (FILE *asm_file, const char *string)
 #endif
 }
 \f
+/* Write a HOST_WIDE_INT number in hex form 0x1234, fast. */
+
+void
+fprint_whex (FILE *f, unsigned HOST_WIDE_INT value)
+{
+  char buf[2 + CHAR_BIT * sizeof (value) / 4];
+  if (value == 0)
+    putc ('0', f);
+  else
+    {
+      char *p = buf + sizeof (buf);
+      do
+        *--p = "0123456789abcdef"[value % 16];
+      while ((value /= 16) != 0);
+      *--p = 'x';
+      *--p = '0';
+      fwrite (p, 1, buf + sizeof (buf) - p, f);
+    }
+}
+
+/* Internal function that prints an unsigned long in decimal in reverse.
+   The output string IS NOT null-terminated. */
+
+static int
+sprint_ul_rev (char *s, unsigned long value)
+{
+  int i = 0;
+  do
+    {
+      s[i] = "0123456789"[value % 10];
+      value /= 10;
+      i++;
+      /* alternate version, without modulo */
+      /* oldval = value; */
+      /* value /= 10; */
+      /* s[i] = "0123456789" [oldval - 10*value]; */
+      /* i++ */
+    }
+  while (value != 0);
+  return i;
+}
+
+/* Write an unsigned long as decimal to a file, fast. */
+
+void
+fprint_ul (FILE *f, unsigned long value)
+{
+  /* python says: len(str(2**64)) == 20 */
+  char s[20];
+  int i;
+
+  i = sprint_ul_rev (s, value);
+
+  /* It's probably too small to bother with string reversal and fputs. */
+  do
+    {
+      i--;
+      putc (s[i], f);
+    }
+  while (i != 0);
+}
+
+/* Write an unsigned long as decimal to a string, fast.
+   s must be wide enough to not overflow, at least 21 chars.
+   Returns the length of the string (without terminating '\0'). */
+
+int
+sprint_ul (char *s, unsigned long value)
+{
+  int len;
+  char tmp_c;
+  int i;
+  int j;
+
+  len = sprint_ul_rev (s, value);
+  s[len] = '\0';
+
+  /* Reverse the string. */
+  i = 0;
+  j = len - 1;
+  while (i < j)
+    {
+      tmp_c = s[i];
+      s[i] = s[j];
+      s[j] = tmp_c;
+      i++; j--;
+    }
+
+  return len;
+}
+
 /* A poor man's fprintf, with the added features of %I, %R, %L, and %U.
    %R prints the value of REGISTER_PREFIX.
    %L prints the value of LOCAL_LABEL_PREFIX.
@@ -3727,6 +4137,9 @@ asm_fprintf (FILE *file, const char *p, ...)
 {
   char buf[10];
   char *q, c;
+#ifdef ASSEMBLER_DIALECT
+  int dialect = 0;
+#endif
   va_list argptr;
 
   va_start (argptr, p);
@@ -3738,29 +4151,9 @@ asm_fprintf (FILE *file, const char *p, ...)
       {
 #ifdef ASSEMBLER_DIALECT
       case '{':
-       {
-         int i;
-
-         /* If we want the first dialect, do nothing.  Otherwise, skip
-            DIALECT_NUMBER of strings ending with '|'.  */
-         for (i = 0; i < dialect_number; i++)
-           {
-             while (*p && *p++ != '|')
-               ;
-
-             if (*p == '|')
-               p++;
-           }
-       }
-       break;
-
-      case '|':
-       /* Skip to close brace.  */
-       while (*p && *p++ != '}')
-         ;
-       break;
-
       case '}':
+      case '|':
+       p = do_assembler_dialects (p, &dialect);
        break;
 #endif
 
@@ -3882,158 +4275,16 @@ asm_fprintf (FILE *file, const char *p, ...)
   va_end (argptr);
 }
 \f
-/* Split up a CONST_DOUBLE or integer constant rtx
-   into two rtx's for single words,
-   storing in *FIRST the word that comes first in memory in the target
-   and in *SECOND the other.  */
-
-void
-split_double (rtx value, rtx *first, rtx *second)
-{
-  if (CONST_INT_P (value))
-    {
-      if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD))
-       {
-         /* In this case the CONST_INT holds both target words.
-            Extract the bits from it into two word-sized pieces.
-            Sign extend each half to HOST_WIDE_INT.  */
-         unsigned HOST_WIDE_INT low, high;
-         unsigned HOST_WIDE_INT mask, sign_bit, sign_extend;
-         unsigned bits_per_word = BITS_PER_WORD;
-
-         /* Set sign_bit to the most significant bit of a word.  */
-         sign_bit = 1;
-         sign_bit <<= bits_per_word - 1;
-
-         /* Set mask so that all bits of the word are set.  We could
-            have used 1 << BITS_PER_WORD instead of basing the
-            calculation on sign_bit.  However, on machines where
-            HOST_BITS_PER_WIDE_INT == BITS_PER_WORD, it could cause a
-            compiler warning, even though the code would never be
-            executed.  */
-         mask = sign_bit << 1;
-         mask--;
-
-         /* Set sign_extend as any remaining bits.  */
-         sign_extend = ~mask;
-
-         /* Pick the lower word and sign-extend it.  */
-         low = INTVAL (value);
-         low &= mask;
-         if (low & sign_bit)
-           low |= sign_extend;
-
-         /* Pick the higher word, shifted to the least significant
-            bits, and sign-extend it.  */
-         high = INTVAL (value);
-         high >>= bits_per_word - 1;
-         high >>= 1;
-         high &= mask;
-         if (high & sign_bit)
-           high |= sign_extend;
-
-         /* Store the words in the target machine order.  */
-         if (WORDS_BIG_ENDIAN)
-           {
-             *first = GEN_INT (high);
-             *second = GEN_INT (low);
-           }
-         else
-           {
-             *first = GEN_INT (low);
-             *second = GEN_INT (high);
-           }
-       }
-      else
-       {
-         /* The rule for using CONST_INT for a wider mode
-            is that we regard the value as signed.
-            So sign-extend it.  */
-         rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx);
-         if (WORDS_BIG_ENDIAN)
-           {
-             *first = high;
-             *second = value;
-           }
-         else
-           {
-             *first = value;
-             *second = high;
-           }
-       }
-    }
-  else if (GET_CODE (value) != CONST_DOUBLE)
-    {
-      if (WORDS_BIG_ENDIAN)
-       {
-         *first = const0_rtx;
-         *second = value;
-       }
-      else
-       {
-         *first = value;
-         *second = const0_rtx;
-       }
-    }
-  else if (GET_MODE (value) == VOIDmode
-          /* This is the old way we did CONST_DOUBLE integers.  */
-          || GET_MODE_CLASS (GET_MODE (value)) == MODE_INT)
-    {
-      /* In an integer, the words are defined as most and least significant.
-        So order them by the target's convention.  */
-      if (WORDS_BIG_ENDIAN)
-       {
-         *first = GEN_INT (CONST_DOUBLE_HIGH (value));
-         *second = GEN_INT (CONST_DOUBLE_LOW (value));
-       }
-      else
-       {
-         *first = GEN_INT (CONST_DOUBLE_LOW (value));
-         *second = GEN_INT (CONST_DOUBLE_HIGH (value));
-       }
-    }
-  else
-    {
-      REAL_VALUE_TYPE r;
-      long l[2];
-      REAL_VALUE_FROM_CONST_DOUBLE (r, value);
-
-      /* Note, this converts the REAL_VALUE_TYPE to the target's
-        format, splits up the floating point double and outputs
-        exactly 32 bits of it into each of l[0] and l[1] --
-        not necessarily BITS_PER_WORD bits.  */
-      REAL_VALUE_TO_TARGET_DOUBLE (r, l);
-
-      /* If 32 bits is an entire word for the target, but not for the host,
-        then sign-extend on the host so that the number will look the same
-        way on the host that it would on the target.  See for instance
-        simplify_unary_operation.  The #if is needed to avoid compiler
-        warnings.  */
-
-#if HOST_BITS_PER_LONG > 32
-      if (BITS_PER_WORD < HOST_BITS_PER_LONG && BITS_PER_WORD == 32)
-       {
-         if (l[0] & ((long) 1 << 31))
-           l[0] |= ((long) (-1) << 32);
-         if (l[1] & ((long) 1 << 31))
-           l[1] |= ((long) (-1) << 32);
-       }
-#endif
-
-      *first = GEN_INT (l[0]);
-      *second = GEN_INT (l[1]);
-    }
-}
-\f
 /* Return nonzero if this function has no function calls.  */
 
 int
 leaf_function_p (void)
 {
-  rtx insn;
-  rtx link;
+  rtx_insn *insn;
 
-  if (crtl->profile || profile_arc_flag)
+  /* Some back-ends (e.g. s390) want leaf functions to stay leaf
+     functions even if they call mcount.  */
+  if (crtl->profile && !targetm.keep_leaf_when_profiled ())
     return 0;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
@@ -4047,21 +4298,6 @@ leaf_function_p (void)
          && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
        return 0;
     }
-  for (link = crtl->epilogue_delay_list;
-       link;
-       link = XEXP (link, 1))
-    {
-      insn = XEXP (link, 0);
-
-      if (CALL_P (insn)
-         && ! SIBLING_CALL_P (insn))
-       return 0;
-      if (NONJUMP_INSN_P (insn)
-         && GET_CODE (PATTERN (insn)) == SEQUENCE
-         && CALL_P (XVECEXP (PATTERN (insn), 0, 0))
-         && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
-       return 0;
-    }
 
   return 1;
 }
@@ -4071,7 +4307,7 @@ leaf_function_p (void)
    output templates to customary add branch prediction hints.
  */
 int
-final_forward_branch_p (rtx insn)
+final_forward_branch_p (rtx_insn *insn)
 {
   int insn_id, label_id;
 
@@ -4121,9 +4357,9 @@ only_leaf_regs_used (void)
    available in leaf functions.  */
 
 static void
-leaf_renumber_regs (rtx first)
+leaf_renumber_regs (rtx_insn *first)
 {
-  rtx insn;
+  rtx_insn *insn;
 
   /* Renumber only the actual patterns.
      The reg-notes can contain frame pointer refs,
@@ -4131,11 +4367,6 @@ 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 = crtl->epilogue_delay_list;
-       insn;
-       insn = XEXP (insn, 1))
-    if (INSN_P (XEXP (insn, 0)))
-      leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0)));
 }
 
 /* Scan IN_RTX and its subexpressions, and renumber all regs into those
@@ -4238,6 +4469,8 @@ rest_of_handle_final (void)
   assemble_start_function (current_function_decl, fnname);
   final_start_function (get_insns (), asm_out_file, optimize);
   final (get_insns (), asm_out_file, optimize);
+  if (flag_use_caller_save)
+    collect_fn_hard_reg_usage ();
   final_end_function ();
 
   /* The IA-64 ".handlerdata" directive must be issued before the ".endp"
@@ -4287,25 +4520,41 @@ rest_of_handle_final (void)
   return 0;
 }
 
-struct rtl_opt_pass pass_final =
+namespace {
+
+const pass_data pass_data_final =
 {
- {
-  RTL_PASS,
-  "final",                              /* 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 */
- }
+  RTL_PASS, /* type */
+  "final", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_FINAL, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
+class pass_final : public rtl_opt_pass
+{
+public:
+  pass_final (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_final, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual unsigned int execute (function *) { return rest_of_handle_final (); }
+
+}; // class pass_final
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_final (gcc::context *ctxt)
+{
+  return new pass_final (ctxt);
+}
+
 
 static unsigned int
 rest_of_handle_shorten_branches (void)
@@ -4315,30 +4564,49 @@ rest_of_handle_shorten_branches (void)
   return 0;
 }
 
-struct rtl_opt_pass pass_shorten_branches =
+namespace {
+
+const pass_data pass_data_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 */
-  0                                     /* todo_flags_finish */
- }
+  RTL_PASS, /* type */
+  "shorten", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_SHORTEN_BRANCH, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
 
+class pass_shorten_branches : public rtl_opt_pass
+{
+public:
+  pass_shorten_branches (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_shorten_branches, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual unsigned int execute (function *)
+    {
+      return rest_of_handle_shorten_branches ();
+    }
+
+}; // class pass_shorten_branches
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_shorten_branches (gcc::context *ctxt)
+{
+  return new pass_shorten_branches (ctxt);
+}
+
 
 static unsigned int
 rest_of_clean_state (void)
 {
-  rtx insn, next;
+  rtx_insn *insn, *next;
   FILE *final_output = NULL;
   int save_unnumbered = flag_dump_unnumbered;
   int save_noaddr = flag_dump_noaddr;
@@ -4380,8 +4648,8 @@ rest_of_clean_state (void)
   for (insn = get_insns (); insn; insn = next)
     {
       next = NEXT_INSN (insn);
-      NEXT_INSN (insn) = NULL;
-      PREV_INSN (insn) = NULL;
+      SET_NEXT_INSN (insn) = NULL;
+      SET_PREV_INSN (insn) = NULL;
 
       if (final_output
          && (!NOTE_P (insn) ||
@@ -4389,7 +4657,7 @@ rest_of_clean_state (void)
               && NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION
               && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
               && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
-              && NOTE_KIND (insn) != NOTE_INSN_CFA_RESTORE_STATE)))
+              && NOTE_KIND (insn) != NOTE_INSN_DELETED_DEBUG_LABEL)))
        print_rtl_single (final_output, insn);
     }
 
@@ -4441,8 +4709,8 @@ rest_of_clean_state (void)
       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;
+      cgraph_node::rtl_info (current_function_decl)
+       ->preferred_incoming_stack_boundary = pref;
     }
 
   /* Make sure volatile mem refs aren't considered valid operands for
@@ -4461,21 +4729,172 @@ rest_of_clean_state (void)
   return 0;
 }
 
-struct rtl_opt_pass pass_clean_state =
+namespace {
+
+const pass_data pass_data_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 */
- }
+  RTL_PASS, /* type */
+  "*clean_state", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_FINAL, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  PROP_rtl, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
 };
+
+class pass_clean_state : public rtl_opt_pass
+{
+public:
+  pass_clean_state (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_clean_state, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual unsigned int execute (function *)
+    {
+      return rest_of_clean_state ();
+    }
+
+}; // class pass_clean_state
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_clean_state (gcc::context *ctxt)
+{
+  return new pass_clean_state (ctxt);
+}
+
+/* Return true if INSN is a call to the the current function.  */
+
+static bool
+self_recursive_call_p (rtx_insn *insn)
+{
+  tree fndecl = get_call_fndecl (insn);
+  return (fndecl == current_function_decl
+         && decl_binds_to_current_def_p (fndecl));
+}
+
+/* Collect hard register usage for the current function.  */
+
+static void
+collect_fn_hard_reg_usage (void)
+{
+  rtx_insn *insn;
+#ifdef STACK_REGS
+  int i;
+#endif
+  struct cgraph_rtl_info *node;
+  HARD_REG_SET function_used_regs;
+
+  /* ??? To be removed when all the ports have been fixed.  */
+  if (!targetm.call_fusage_contains_non_callee_clobbers)
+    return;
+
+  CLEAR_HARD_REG_SET (function_used_regs);
+
+  for (insn = get_insns (); insn != NULL_RTX; insn = next_insn (insn))
+    {
+      HARD_REG_SET insn_used_regs;
+
+      if (!NONDEBUG_INSN_P (insn))
+       continue;
+
+      if (CALL_P (insn)
+         && !self_recursive_call_p (insn))
+       {
+         if (!get_call_reg_set_usage (insn, &insn_used_regs,
+                                      call_used_reg_set))
+           return;
+
+         IOR_HARD_REG_SET (function_used_regs, insn_used_regs);
+       }
+
+      find_all_hard_reg_sets (insn, &insn_used_regs, false);
+      IOR_HARD_REG_SET (function_used_regs, insn_used_regs);
+    }
+
+  /* Be conservative - mark fixed and global registers as used.  */
+  IOR_HARD_REG_SET (function_used_regs, fixed_reg_set);
+
+#ifdef STACK_REGS
+  /* Handle STACK_REGS conservatively, since the df-framework does not
+     provide accurate information for them.  */
+
+  for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
+    SET_HARD_REG_BIT (function_used_regs, i);
+#endif
+
+  /* The information we have gathered is only interesting if it exposes a
+     register from the call_used_regs that is not used in this function.  */
+  if (hard_reg_set_subset_p (call_used_reg_set, function_used_regs))
+    return;
+
+  node = cgraph_node::rtl_info (current_function_decl);
+  gcc_assert (node != NULL);
+
+  COPY_HARD_REG_SET (node->function_used_regs, function_used_regs);
+  node->function_used_regs_valid = 1;
+}
+
+/* Get the declaration of the function called by INSN.  */
+
+static tree
+get_call_fndecl (rtx_insn *insn)
+{
+  rtx note, datum;
+
+  note = find_reg_note (insn, REG_CALL_DECL, NULL_RTX);
+  if (note == NULL_RTX)
+    return NULL_TREE;
+
+  datum = XEXP (note, 0);
+  if (datum != NULL_RTX)
+    return SYMBOL_REF_DECL (datum);
+
+  return NULL_TREE;
+}
+
+/* Return the cgraph_rtl_info of the function called by INSN.  Returns NULL for
+   call targets that can be overwritten.  */
+
+static struct cgraph_rtl_info *
+get_call_cgraph_rtl_info (rtx_insn *insn)
+{
+  tree fndecl;
+
+  if (insn == NULL_RTX)
+    return NULL;
+
+  fndecl = get_call_fndecl (insn);
+  if (fndecl == NULL_TREE
+      || !decl_binds_to_current_def_p (fndecl))
+    return NULL;
+
+  return cgraph_node::rtl_info (fndecl);
+}
+
+/* Find hard registers used by function call instruction INSN, and return them
+   in REG_SET.  Return DEFAULT_SET in REG_SET if not found.  */
+
+bool
+get_call_reg_set_usage (rtx_insn *insn, HARD_REG_SET *reg_set,
+                       HARD_REG_SET default_set)
+{
+  if (flag_use_caller_save)
+    {
+      struct cgraph_rtl_info *node = get_call_cgraph_rtl_info (insn);
+      if (node != NULL
+         && node->function_used_regs_valid)
+       {
+         COPY_HARD_REG_SET (*reg_set, node->function_used_regs);
+         AND_HARD_REG_SET (*reg_set, default_set);
+         return true;
+       }
+    }
+
+  COPY_HARD_REG_SET (*reg_set, default_set);
+  return false;
+}