]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/final.c
PR fortran/95090 - ICE: identifier overflow
[thirdparty/gcc.git] / gcc / final.c
index 24833815276530d744d83e8a20a7ba61b20717f3..a3601964a8d31f2436e7c8e3d378345c8cf8dd60 100644 (file)
@@ -1,5 +1,5 @@
 /* Convert RTL to assembler code and output it, for GNU compiler.
-   Copyright (C) 1987-2017 Free Software Foundation, Inc.
+   Copyright (C) 1987-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -75,10 +75,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "tree-ssa.h"
 #include "cfgloop.h"
-#include "params.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "rtl-iter.h"
 #include "print-rtl.h"
+#include "function-abi.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data declarations.  */
@@ -90,8 +92,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbxout.h"
 #endif
 
-#include "sdbout.h"
-
 /* Most ports that aren't using cc0 don't need to define CC_STATUS_INIT.
    So define a null default for it to save conditionalization later.  */
 #ifndef CC_STATUS_INIT
@@ -110,6 +110,7 @@ along with GCC; see the file COPYING3.  If not see
 /* Bitflags used by final_scan_insn.  */
 #define SEEN_NOTE      1
 #define SEEN_EMITTED   2
+#define SEEN_NEXT_VIEW 4
 
 /* Last insn processed by final_scan_insn.  */
 static rtx_insn *debug_insn;
@@ -118,11 +119,23 @@ rtx_insn *current_output_insn;
 /* Line number of last NOTE.  */
 static int last_linenum;
 
-/* Last discriminator written to assembly.  */
+/* Column number of last NOTE.  */
+static int last_columnnum;
+
+/* Discriminator written to assembly.  */
 static int last_discriminator;
 
-/* Discriminator of current block.  */
+/* Discriminator to be written to assembly for current instruction.
+   Note: actual usage depends on loc_discriminator_kind setting.  */
 static int discriminator;
+static inline int compute_discriminator (location_t loc);
+
+/* Discriminator identifying current basic block among others sharing
+   the same locus.  */
+static int bb_discriminator;
+
+/* Basic block discriminator for previous instruction.  */
+static int last_bb_discriminator;
 
 /* Highest line number in current block.  */
 static int high_block_linenum;
@@ -133,9 +146,11 @@ static int high_function_linenum;
 /* Filename of last NOTE.  */
 static const char *last_filename;
 
-/* Override filename and line number.  */
+/* Override filename, line and column number.  */
 static const char *override_filename;
 static int override_linenum;
+static int override_columnnum;
+static int override_discriminator;
 
 /* Whether to force emission of a line note before the next insn.  */
 static bool force_source_line = false;
@@ -192,7 +207,7 @@ static int dialect_number;
 /* Nonnull if the insn currently being emitted was a COND_EXEC pattern.  */
 rtx current_insn_predicate;
 
-/* True if printing into -fdump-final-insns= dump.  */   
+/* True if printing into -fdump-final-insns= dump.  */
 bool final_insns_dump_p;
 
 /* True if profile_function should be called, but hasn't been called yet.  */
@@ -213,12 +228,8 @@ static void leaf_renumber_regs (rtx_insn *);
 #if HAVE_cc0
 static int alter_cond (rtx);
 #endif
-#ifndef ADDR_VEC_ALIGN
-static int final_addr_vec_align (rtx_insn *);
-#endif
 static int align_fuzz (rtx, rtx, int, unsigned);
 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.  */
 
@@ -238,8 +249,7 @@ init_final (const char *filename ATTRIBUTE_UNUSED)
    If not overridden for epilogue code, then the function body itself
    contains return instructions wherever needed.  */
 void
-default_function_pro_epilogue (FILE *file ATTRIBUTE_UNUSED,
-                              HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+default_function_pro_epilogue (FILE *)
 {
 }
 
@@ -326,15 +336,9 @@ int insn_current_align;
    for each insn we'll call the alignment chain of this insn in the following
    comments.  */
 
-struct label_alignment
-{
-  short alignment;
-  short max_skip;
-};
-
 static rtx *uid_align;
 static int *uid_shuid;
-static struct label_alignment *label_align;
+static vec<align_flags> label_align;
 
 /* Indicate that branch shortening hasn't yet been done.  */
 
@@ -472,11 +476,11 @@ get_attr_min_length (rtx_insn *insn)
    address mod X to one mod Y, which is Y - X.  */
 
 #ifndef LABEL_ALIGN
-#define LABEL_ALIGN(LABEL) align_labels_log
+#define LABEL_ALIGN(LABEL) align_labels
 #endif
 
 #ifndef LOOP_ALIGN
-#define LOOP_ALIGN(LABEL) align_loops_log
+#define LOOP_ALIGN(LABEL) align_loops
 #endif
 
 #ifndef LABEL_ALIGN_AFTER_BARRIER
@@ -484,38 +488,14 @@ get_attr_min_length (rtx_insn *insn)
 #endif
 
 #ifndef JUMP_ALIGN
-#define JUMP_ALIGN(LABEL) align_jumps_log
+#define JUMP_ALIGN(LABEL) align_jumps
 #endif
 
-int
-default_label_align_after_barrier_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED)
-{
-  return 0;
-}
-
-int
-default_loop_align_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED)
-{
-  return align_loops_max_skip;
-}
-
-int
-default_label_align_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED)
-{
-  return align_labels_max_skip;
-}
-
-int
-default_jump_align_max_skip (rtx_insn *insn ATTRIBUTE_UNUSED)
-{
-  return align_jumps_max_skip;
-}
-
 #ifndef ADDR_VEC_ALIGN
 static int
-final_addr_vec_align (rtx_insn *addr_vec)
+final_addr_vec_align (rtx_jump_table_data *addr_vec)
 {
-  int align = GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec)));
+  int align = GET_MODE_SIZE (addr_vec->get_data_mode ());
 
   if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
     align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
@@ -535,27 +515,16 @@ final_addr_vec_align (rtx_insn *addr_vec)
 static int min_labelno, max_labelno;
 
 #define LABEL_TO_ALIGNMENT(LABEL) \
-  (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].alignment)
-
-#define LABEL_TO_MAX_SKIP(LABEL) \
-  (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip)
+  (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno])
 
 /* For the benefit of port specific code do this also as a function.  */
 
-int
+align_flags
 label_to_alignment (rtx 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;
+  return align_flags ();
 }
 
 /* The differences in addresses
@@ -603,8 +572,8 @@ align_fuzz (rtx start, rtx end, int known_align_log, unsigned int growth)
       align_addr = INSN_ADDRESSES (uid) - insn_lengths[uid];
       if (uid_shuid[uid] > end_shuid)
        break;
-      known_align_log = LABEL_TO_ALIGNMENT (align_label);
-      new_align = 1 << known_align_log;
+      align_flags alignment = LABEL_TO_ALIGNMENT (align_label);
+      new_align = 1 << alignment.levels[0].log;
       if (new_align < known_align)
        continue;
       fuzz += (-align_addr ^ growth) & (new_align - known_align);
@@ -636,7 +605,7 @@ insn_current_reference_address (rtx_insn *branch)
 
   rtx_insn *seq = NEXT_INSN (PREV_INSN (branch));
   seq_uid = INSN_UID (seq);
-  if (!JUMP_P (branch))
+  if (!jump_to_label_p (branch))
     /* This can happen for example on the PA; the objective is to know the
        offset to address something in front of the start of the function.
        Thus, we can treat it like a backward branch.
@@ -661,26 +630,19 @@ insn_current_reference_address (rtx_insn *branch)
     }
 }
 \f
-/* Compute branch alignments based on frequency information in the
-   CFG.  */
+/* Compute branch alignments based on CFG profile.  */
 
 unsigned int
 compute_alignments (void)
 {
-  int log, max_skip, max_log;
   basic_block bb;
-  int freq_max = 0;
-  int freq_threshold = 0;
+  align_flags max_alignment;
 
-  if (label_align)
-    {
-      free (label_align);
-      label_align = 0;
-    }
+  label_align.truncate (0);
 
   max_labelno = max_label_num ();
   min_labelno = get_first_label_num ();
-  label_align = XCNEWVEC (struct label_alignment, max_labelno - min_labelno + 1);
+  label_align.safe_grow_cleared (max_labelno - min_labelno + 1);
 
   /* If not optimizing or optimizing for size, don't assign any alignments.  */
   if (! optimize || optimize_function_for_size_p (cfun))
@@ -693,17 +655,19 @@ compute_alignments (void)
       flow_loops_dump (dump_file, NULL, 1);
     }
   loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
-  FOR_EACH_BB_FN (bb, cfun)
-    if (bb->frequency > freq_max)
-      freq_max = bb->frequency;
-  freq_threshold = freq_max / PARAM_VALUE (PARAM_ALIGN_THRESHOLD);
+  profile_count count_threshold = cfun->cfg->count_max.apply_scale
+                (1, param_align_threshold);
 
   if (dump_file)
-    fprintf (dump_file, "freq_max: %i\n",freq_max);
+    {
+      fprintf (dump_file, "count_max: ");
+      cfun->cfg->count_max.dump (dump_file);
+      fprintf (dump_file, "\n");
+    }
   FOR_EACH_BB_FN (bb, cfun)
     {
       rtx_insn *label = BB_HEAD (bb);
-      int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0;
+      bool has_fallthru = 0;
       edge e;
       edge_iterator ei;
 
@@ -712,34 +676,40 @@ compute_alignments (void)
        {
          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 %4i loop %2i loop_depth %2i skipped.\n",
+                    bb->index,
+                    bb->loop_father->num,
                     bb_loop_depth (bb));
          continue;
        }
-      max_log = LABEL_ALIGN (label);
-      max_skip = targetm.asm_out.label_align_max_skip (label);
+      max_alignment = LABEL_ALIGN (label);
+      profile_count fallthru_count = profile_count::zero ();
+      profile_count branch_count = profile_count::zero ();
 
       FOR_EACH_EDGE (e, ei, bb->preds)
        {
          if (e->flags & EDGE_FALLTHRU)
-           has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e);
+           has_fallthru = 1, fallthru_count += e->count ();
          else
-           branch_frequency += EDGE_FREQUENCY (e);
+           branch_count += e->count ();
        }
       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 (bb),
-                  fallthru_frequency, branch_frequency);
+         fprintf (dump_file, "BB %4i loop %2i loop_depth"
+                  " %2i fall ",
+                  bb->index, bb->loop_father->num,
+                  bb_loop_depth (bb));
+         fallthru_count.dump (dump_file);
+         fprintf (dump_file, " branch ");
+         branch_count.dump (dump_file);
          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");
        }
+      if (!fallthru_count.initialized_p () || !branch_count.initialized_p ())
+       continue;
 
       /* There are two purposes to align block with no fallthru incoming edge:
         1) to avoid fetch stalls when branch destination is near cache boundary
@@ -752,19 +722,16 @@ compute_alignments (void)
         when function is called.  */
 
       if (!has_fallthru
-         && (branch_frequency > freq_threshold
-             || (bb->frequency > bb->prev_bb->frequency * 10
-                 && (bb->prev_bb->frequency
-                     <= ENTRY_BLOCK_PTR_FOR_FN (cfun)->frequency / 2))))
+         && (branch_count > count_threshold
+             || (bb->count > bb->prev_bb->count.apply_scale (10, 1)
+                 && (bb->prev_bb->count
+                     <= ENTRY_BLOCK_PTR_FOR_FN (cfun)
+                          ->count.apply_scale (1, 2)))))
        {
-         log = JUMP_ALIGN (label);
+         align_flags alignment = JUMP_ALIGN (label);
          if (dump_file)
            fprintf (dump_file, "  jump alignment added.\n");
-         if (max_log < log)
-           {
-             max_log = log;
-             max_skip = targetm.asm_out.jump_align_max_skip (label);
-           }
+         max_alignment = align_flags::max (max_alignment, alignment);
        }
       /* In case block is frequent and reached mostly by non-fallthru edge,
         align it.  It is most likely a first block of loop.  */
@@ -772,21 +739,17 @@ compute_alignments (void)
          && !(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
-             > fallthru_frequency * PARAM_VALUE (PARAM_ALIGN_LOOP_ITERATIONS)))
+         && branch_count + fallthru_count > count_threshold
+         && (branch_count
+             > fallthru_count.apply_scale
+                   (param_align_loop_iterations, 1)))
        {
-         log = LOOP_ALIGN (label);
+         align_flags alignment = LOOP_ALIGN (label);
          if (dump_file)
            fprintf (dump_file, "  internal loop alignment added.\n");
-         if (max_log < log)
-           {
-             max_log = log;
-             max_skip = targetm.asm_out.loop_align_max_skip (label);
-           }
+         max_alignment = align_flags::max (max_alignment, alignment);
        }
-      LABEL_TO_ALIGNMENT (label) = max_log;
-      LABEL_TO_MAX_SKIP (label) = max_skip;
+      LABEL_TO_ALIGNMENT (label) = max_alignment;
     }
 
   loop_optimizer_finalize ();
@@ -796,7 +759,7 @@ compute_alignments (void)
 
 /* Grow the LABEL_ALIGN array after new labels are created.  */
 
-static void 
+static void
 grow_label_align (void)
 {
   int old = max_labelno;
@@ -808,14 +771,11 @@ grow_label_align (void)
   n_labels = max_labelno - min_labelno + 1;
   n_old_labels = old - min_labelno + 1;
 
-  label_align = XRESIZEVEC (struct label_alignment, label_align, n_labels);
+  label_align.safe_grow_cleared (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
@@ -833,10 +793,7 @@ update_alignments (vec<rtx> &label_pairs)
 
   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);
-      }
+      LABEL_TO_ALIGNMENT (label) = LABEL_TO_ALIGNMENT (iter);
     else
       label = iter;
 }
@@ -894,15 +851,12 @@ shorten_branches (rtx_insn *first)
   rtx_insn *insn;
   int max_uid;
   int i;
-  int max_log;
-  int max_skip;
-#define MAX_CODE_ALIGN 16
   rtx_insn *seq;
   int something_changed = 1;
   char *varying_length;
   rtx body;
   int uid;
-  rtx align_tab[MAX_CODE_ALIGN];
+  rtx align_tab[MAX_CODE_ALIGN + 1];
 
   /* Compute maximum UID and allocate label_align / uid_shuid.  */
   max_uid = get_max_uid ();
@@ -917,62 +871,41 @@ shorten_branches (rtx_insn *first)
 
   /* Initialize label_align and set up uid_shuid to be strictly
      monotonically rising with insn order.  */
-  /* We use max_log here to keep track of the maximum alignment we want to
+  /* We use alignment here to keep track of the maximum alignment we want to
      impose on the next CODE_LABEL (or the current one if we are processing
      the CODE_LABEL itself).  */
 
-  max_log = 0;
-  max_skip = 0;
+  align_flags max_alignment;
 
   for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn))
     {
-      int log;
-
       INSN_SHUID (insn) = i++;
       if (INSN_P (insn))
        continue;
 
-      if (LABEL_P (insn))
+      if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
        {
-         rtx_insn *next;
-         bool next_is_jumptable;
-
          /* Merge in alignments computed by compute_alignments.  */
-         log = LABEL_TO_ALIGNMENT (insn);
-         if (max_log < log)
-           {
-             max_log = log;
-             max_skip = LABEL_TO_MAX_SKIP (insn);
-           }
+         align_flags alignment = LABEL_TO_ALIGNMENT (label);
+         max_alignment = align_flags::max (max_alignment, alignment);
 
-         next = next_nonnote_insn (insn);
-         next_is_jumptable = next && JUMP_TABLE_DATA_P (next);
-         if (!next_is_jumptable)
+         rtx_jump_table_data *table = jump_table_for_label (label);
+         if (!table)
            {
-             log = LABEL_ALIGN (insn);
-             if (max_log < log)
-               {
-                 max_log = log;
-                 max_skip = targetm.asm_out.label_align_max_skip (insn);
-               }
+             align_flags alignment = LABEL_ALIGN (label);
+             max_alignment = align_flags::max (max_alignment, alignment);
            }
          /* ADDR_VECs only take room if read-only data goes into the text
             section.  */
          if ((JUMP_TABLES_IN_TEXT_SECTION
               || readonly_data_section == text_section)
-             && next_is_jumptable)
+             && table)
            {
-             log = ADDR_VEC_ALIGN (next);
-             if (max_log < log)
-               {
-                 max_log = log;
-                 max_skip = targetm.asm_out.label_align_max_skip (insn);
-               }
+             align_flags alignment = align_flags (ADDR_VEC_ALIGN (table));
+             max_alignment = align_flags::max (max_alignment, alignment);
            }
-         LABEL_TO_ALIGNMENT (insn) = max_log;
-         LABEL_TO_MAX_SKIP (insn) = max_skip;
-         max_log = 0;
-         max_skip = 0;
+         LABEL_TO_ALIGNMENT (label) = max_alignment;
+         max_alignment = align_flags ();
        }
       else if (BARRIER_P (insn))
        {
@@ -982,12 +915,9 @@ shorten_branches (rtx_insn *first)
               label = NEXT_INSN (label))
            if (LABEL_P (label))
              {
-               log = LABEL_ALIGN_AFTER_BARRIER (insn);
-               if (max_log < log)
-                 {
-                   max_log = log;
-                   max_skip = targetm.asm_out.label_align_after_barrier_max_skip (label);
-                 }
+               align_flags alignment
+                 = align_flags (LABEL_ALIGN_AFTER_BARRIER (insn));
+               max_alignment = align_flags::max (max_alignment, alignment);
                break;
              }
        }
@@ -1011,18 +941,19 @@ shorten_branches (rtx_insn *first)
      alignment of n.  */
   uid_align = XCNEWVEC (rtx, max_uid);
 
-  for (i = MAX_CODE_ALIGN; --i >= 0;)
+  for (i = MAX_CODE_ALIGN + 1; --i >= 0;)
     align_tab[i] = NULL_RTX;
   seq = get_last_insn ();
   for (; seq; seq = PREV_INSN (seq))
     {
       int uid = INSN_UID (seq);
       int log;
-      log = (LABEL_P (seq) ? LABEL_TO_ALIGNMENT (seq) : 0);
+      log = (LABEL_P (seq) ? LABEL_TO_ALIGNMENT (seq).levels[0].log : 0);
       uid_align[uid] = align_tab[0];
       if (log)
        {
          /* Found an alignment label.  */
+         gcc_checking_assert (log < MAX_CODE_ALIGN + 1);
          uid_align[uid] = align_tab[log];
          for (i = log - 1; i >= 0; i--)
            align_tab[i] = seq;
@@ -1073,8 +1004,10 @@ shorten_branches (rtx_insn *first)
                  max = shuid;
                  max_lab = lab;
                }
-             if (min_align > LABEL_TO_ALIGNMENT (lab))
-               min_align = LABEL_TO_ALIGNMENT (lab);
+
+             int label_alignment = LABEL_TO_ALIGNMENT (lab).levels[0].log;
+             if (min_align > label_alignment)
+               min_align = label_alignment;
            }
          XEXP (pat, 2) = gen_rtx_LABEL_REF (Pmode, min_lab);
          XEXP (pat, 3) = gen_rtx_LABEL_REF (Pmode, max_lab);
@@ -1108,7 +1041,7 @@ shorten_branches (rtx_insn *first)
 
       if (LABEL_P (insn))
        {
-         int log = LABEL_TO_ALIGNMENT (insn);
+         int log = LABEL_TO_ALIGNMENT (insn).levels[0].log;
          if (log)
            {
              int align = 1 << log;
@@ -1126,7 +1059,7 @@ shorten_branches (rtx_insn *first)
        continue;
 
       body = PATTERN (insn);
-      if (JUMP_TABLE_DATA_P (insn))
+      if (rtx_jump_table_data *table = dyn_cast <rtx_jump_table_data *> (insn))
        {
          /* This only takes room if read-only data goes into the text
             section.  */
@@ -1134,7 +1067,7 @@ shorten_branches (rtx_insn *first)
              || readonly_data_section == text_section)
            insn_lengths[uid] = (XVECLEN (body,
                                          GET_CODE (body) == ADDR_DIFF_VEC)
-                                * GET_MODE_SIZE (GET_MODE (body)));
+                                * GET_MODE_SIZE (table->get_data_mode ()));
          /* Alignment is handled by ADDR_VEC_ALIGN.  */
        }
       else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
@@ -1214,28 +1147,27 @@ shorten_branches (rtx_insn *first)
 
          uid = INSN_UID (insn);
 
-         if (LABEL_P (insn))
+         if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
            {
-             int log = LABEL_TO_ALIGNMENT (insn);
+             int log = LABEL_TO_ALIGNMENT (label).levels[0].log;
 
 #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)
+
+             if (JUMP_TABLES_IN_TEXT_SECTION
+                 || readonly_data_section == text_section)
                {
-                 int newlog = ADDR_VEC_ALIGN (next);
-                 if (newlog != log)
+                 rtx_jump_table_data *table = jump_table_for_label (label);
+                 if (table)
                    {
-                     log = newlog;
-                     LABEL_TO_ALIGNMENT (insn) = log;
-                     something_changed = 1;
+                     int newlog = ADDR_VEC_ALIGN (table);
+                     if (newlog != log)
+                       {
+                         log = newlog;
+                         LABEL_TO_ALIGNMENT (insn) = log;
+                         something_changed = 1;
+                       }
                    }
                }
 #endif
@@ -1266,6 +1198,7 @@ shorten_branches (rtx_insn *first)
              && JUMP_TABLE_DATA_P (insn)
              && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
            {
+             rtx_jump_table_data *table = as_a <rtx_jump_table_data *> (insn);
              rtx body = PATTERN (insn);
              int old_length = insn_lengths[uid];
              rtx_insn *rel_lab =
@@ -1278,7 +1211,7 @@ shorten_branches (rtx_insn *first)
              rtx_insn *prev;
              int rel_align = 0;
              addr_diff_vec_flags flags;
-             machine_mode vec_mode;
+             scalar_int_mode vec_mode;
 
              /* Avoid automatic aggregate initialization.  */
              flags = ADDR_DIFF_VEC_FLAGS (body);
@@ -1291,7 +1224,7 @@ shorten_branches (rtx_insn *first)
                   prev = PREV_INSN (prev))
                if (varying_length[INSN_UID (prev)] & 2)
                  {
-                   rel_align = LABEL_TO_ALIGNMENT (prev);
+                   rel_align = LABEL_TO_ALIGNMENT (prev).levels[0].log;
                    break;
                  }
 
@@ -1361,13 +1294,14 @@ shorten_branches (rtx_insn *first)
                                                   max_addr - rel_addr, body);
              if (!increasing
                  || (GET_MODE_SIZE (vec_mode)
-                     >= GET_MODE_SIZE (GET_MODE (body))))
+                     >= GET_MODE_SIZE (table->get_data_mode ())))
                PUT_MODE (body, vec_mode);
              if (JUMP_TABLES_IN_TEXT_SECTION
                  || readonly_data_section == text_section)
                {
                  insn_lengths[uid]
-                   = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)));
+                   = (XVECLEN (body, 1)
+                      * GET_MODE_SIZE (table->get_data_mode ()));
                  insn_current_address += insn_lengths[uid];
                  if (insn_lengths[uid] != old_length)
                    something_changed = 1;
@@ -1502,72 +1436,6 @@ asm_str_count (const char *templ)
   return count;
 }
 \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.  */
-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;
-};
-
-/* Linked list of such structures.  */
-static 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 = xstrndup (arg, p - arg);
-  map->old_len = p - arg;
-  p++;
-  map->new_prefix = xstrdup (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 (filename_ncmp (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
 /* Return true if DWARF2 debug info can be emitted for DECL.  */
 
 static bool
@@ -1647,7 +1515,6 @@ 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))
@@ -1655,17 +1522,30 @@ reemit_insn_block_notes (void)
       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 (NOTE_P (insn))
+       switch (NOTE_KIND (insn))
+         {
+         case 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;
+               }
+           }
+           break;
+
+         case NOTE_INSN_BEGIN_STMT:
+         case NOTE_INSN_INLINE_ENTRY:
+           this_block = LOCATION_BLOCK (NOTE_MARKER_LOCATION (insn));
+           goto set_cur_block_to_this_block;
+
+         default:
+           continue;
+       }
 
       if (!active_insn_p (insn))
         continue;
@@ -1686,6 +1566,7 @@ reemit_insn_block_notes (void)
            this_block = choose_inner_scope (this_block,
                                             insn_scope (body->insn (i)));
        }
+    set_cur_block_to_this_block:
       if (! this_block)
        {
          if (INSN_LOCATION (insn) == UNKNOWN_LOCATION)
@@ -1702,7 +1583,7 @@ reemit_insn_block_notes (void)
     }
 
   /* change_scope emits before the insn, not after.  */
-  note = emit_note (NOTE_INSN_DELETED);
+  rtx_note *note = emit_note (NOTE_INSN_DELETED);
   change_scope (note, cur_block, DECL_INITIAL (cfun->decl));
   delete_insn (note);
 
@@ -1741,6 +1622,67 @@ get_some_local_dynamic_name ()
   return 0;
 }
 
+/* Arrange for us to emit a source location note before any further
+   real insns or section changes, by setting the SEEN_NEXT_VIEW bit in
+   *SEEN, as long as we are keeping track of location views.  The bit
+   indicates we have referenced the next view at the current PC, so we
+   have to emit it.  This should be called next to the var_location
+   debug hook.  */
+
+static inline void
+set_next_view_needed (int *seen)
+{
+  if (debug_variable_location_views)
+    *seen |= SEEN_NEXT_VIEW;
+}
+
+/* Clear the flag in *SEEN indicating we need to emit the next view.
+   This should be called next to the source_line debug hook.  */
+
+static inline void
+clear_next_view_needed (int *seen)
+{
+  *seen &= ~SEEN_NEXT_VIEW;
+}
+
+/* Test whether we have a pending request to emit the next view in
+   *SEEN, and emit it if needed, clearing the request bit.  */
+
+static inline void
+maybe_output_next_view (int *seen)
+{
+  if ((*seen & SEEN_NEXT_VIEW) != 0)
+    {
+      clear_next_view_needed (seen);
+      (*debug_hooks->source_line) (last_linenum, last_columnnum,
+                                  last_filename, last_discriminator,
+                                  false);
+    }
+}
+
+/* We want to emit param bindings (before the first begin_stmt) in the
+   initial view, if we are emitting views.  To that end, we may
+   consume initial notes in the function, processing them in
+   final_start_function, before signaling the beginning of the
+   prologue, rather than in final.
+
+   We don't test whether the DECLs are PARM_DECLs: the assumption is
+   that there will be a NOTE_INSN_BEGIN_STMT marker before any
+   non-parameter NOTE_INSN_VAR_LOCATION.  It's ok if the marker is not
+   there, we'll just have more variable locations bound in the initial
+   view, which is consistent with their being bound without any code
+   that would give them a value.  */
+
+static inline bool
+in_initial_view_p (rtx_insn *insn)
+{
+  return (!DECL_IGNORED_P (current_function_decl)
+         && debug_variable_location_views
+         && insn && GET_CODE (insn) == NOTE
+         && (NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION
+             || NOTE_KIND (insn) == NOTE_INSN_DELETED));
+}
+
 /* 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
@@ -1748,12 +1690,15 @@ get_some_local_dynamic_name ()
 
    FIRST is the first insn of the rtl for the function being compiled.
    FILE is the file to write assembler code to.
+   SEEN should be initially set to zero, and it may be updated to
+   indicate we have references to the next location view, that would
+   require us to emit it at the current PC.
    OPTIMIZE_P is nonzero if we should eliminate redundant
      test and compare insns.  */
 
-void
-final_start_function (rtx_insn *first, FILE *file,
-                     int optimize_p ATTRIBUTE_UNUSED)
+static void
+final_start_function_1 (rtx_insn **firstp, FILE *file, int *seen,
+                       int optimize_p ATTRIBUTE_UNUSED)
 {
   block_depth = 0;
 
@@ -1763,18 +1708,33 @@ final_start_function (rtx_insn *first, FILE *file,
 
   last_filename = LOCATION_FILE (prologue_location);
   last_linenum = LOCATION_LINE (prologue_location);
+  last_columnnum = LOCATION_COLUMN (prologue_location);
   last_discriminator = discriminator = 0;
+  last_bb_discriminator = bb_discriminator = 0;
 
   high_block_linenum = high_function_linenum = last_linenum;
 
   if (flag_sanitize & SANITIZE_ADDRESS)
     asan_function_start ();
 
+  rtx_insn *first = *firstp;
+  if (in_initial_view_p (first))
+    {
+      do
+       {
+         final_scan_insn (first, file, 0, 0, seen);
+         first = NEXT_INSN (first);
+       }
+      while (in_initial_view_p (first));
+      *firstp = first;
+    }
+
   if (!DECL_IGNORED_P (current_function_decl))
-    debug_hooks->begin_prologue (last_linenum, last_filename);
+    debug_hooks->begin_prologue (last_linenum, last_columnnum,
+                                last_filename);
 
   if (!dwarf2_debug_info_emitted_p (current_function_decl))
-    dwarf2out_begin_prologue (0, NULL);
+    dwarf2out_begin_prologue (0, 0, NULL);
 
 #ifdef LEAF_REG_REMAP
   if (crtl->uses_only_leaf_regs)
@@ -1828,17 +1788,18 @@ final_start_function (rtx_insn *first, FILE *file,
       TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
     }
 
-  if (warn_frame_larger_than
-    && get_frame_size () > frame_larger_than_size)
-  {
+  unsigned HOST_WIDE_INT min_frame_size
+    = constant_lower_bound (get_frame_size ());
+  if (min_frame_size > (unsigned HOST_WIDE_INT) warn_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);
-  }
+              "the frame size of %wu bytes is larger than %wu bytes",
+              min_frame_size, warn_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 ());
+  targetm.asm_out.function_prologue (file);
 
   /* If the machine represents the prologue as RTL, the profiling code must
      be emitted when NOTE_INSN_PROLOGUE_END is scanned.  */
@@ -1846,6 +1807,17 @@ final_start_function (rtx_insn *first, FILE *file,
     profile_after_prologue (file);
 }
 
+/* This is an exported final_start_function_1, callable without SEEN.  */
+
+void
+final_start_function (rtx_insn *first, FILE *file,
+                     int optimize_p ATTRIBUTE_UNUSED)
+{
+  int seen = 0;
+  final_start_function_1 (&first, file, &seen, optimize_p);
+  gcc_assert (seen == 0);
+}
+
 static void
 profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
 {
@@ -1911,7 +1883,7 @@ final_end_function (void)
 
   /* Finally, output the function epilogue:
      code to restore the stack frame and return to the caller.  */
-  targetm.asm_out.function_epilogue (asm_out_file, get_frame_size ());
+  targetm.asm_out.function_epilogue (asm_out_file);
 
   /* And debug output.  */
   if (!DECL_IGNORED_P (current_function_decl))
@@ -1944,11 +1916,11 @@ dump_basic_block_info (FILE *file, rtx_insn *insn, basic_block *start_to_bb,
       edge_iterator ei;
 
       fprintf (file, "%s BLOCK %d", ASM_COMMENT_START, bb->index);
-      if (bb->frequency)
-        fprintf (file, " freq:%d", bb->frequency);
-      if (bb->count)
-        fprintf (file, " count:%" PRId64,
-                 bb->count);
+      if (bb->count.initialized_p ())
+       {
+          fprintf (file, ", count:");
+         bb->count.dump (file);
+       }
       fprintf (file, " seq:%d", (*bb_seqn)++);
       fprintf (file, "\n%s PRED:", ASM_COMMENT_START);
       FOR_EACH_EDGE (e, ei, bb->preds)
@@ -1975,11 +1947,10 @@ dump_basic_block_info (FILE *file, rtx_insn *insn, basic_block *start_to_bb,
 /* Output assembler code for some insns: all or part of a function.
    For description of args, see `final_start_function', above.  */
 
-void
-final (rtx_insn *first, FILE *file, int optimize_p)
+static void
+final_1 (rtx_insn *first, FILE *file, int seen, int optimize_p)
 {
   rtx_insn *insn, *next;
-  int seen = 0;
 
   /* Used for -dA dump.  */
   basic_block *start_to_bb = NULL;
@@ -2039,6 +2010,9 @@ final (rtx_insn *first, FILE *file, int optimize_p)
            }
          else
            insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
+         /* final can be seen as an iteration of shorten_branches that
+            does nothing (since a fixed point has already been reached).  */
+         insn_last_address = insn_current_address;
        }
 
       dump_basic_block_info (file, insn, start_to_bb, end_to_bb,
@@ -2046,6 +2020,8 @@ final (rtx_insn *first, FILE *file, int optimize_p)
       insn = final_scan_insn (insn, file, optimize_p, 0, &seen);
     }
 
+  maybe_output_next_view (&seen);
+
   if (flag_debug_asm)
     {
       free (start_to_bb);
@@ -2062,9 +2038,26 @@ final (rtx_insn *first, FILE *file, int optimize_p)
        delete_insn (insn);
     }
 }
+
+/* This is an exported final_1, callable without SEEN.  */
+
+void
+final (rtx_insn *first, FILE *file, int optimize_p)
+{
+  /* Those that use the internal final_start_function_1/final_1 API
+     skip initial debug bind notes in final_start_function_1, and pass
+     the modified FIRST to final_1.  But those that use the public
+     final_start_function/final APIs, final_start_function can't move
+     FIRST because it's not passed by reference, so if they were
+     skipped there, skip them again here.  */
+  while (in_initial_view_p (first))
+    first = NEXT_INSN (first);
+
+  final_1 (first, file, 0, optimize_p);
+}
 \f
 const char *
-get_insn_template (int code, rtx insn)
+get_insn_template (int code, rtx_insn *insn)
 {
   switch (insn_data[code].output_format)
     {
@@ -2074,8 +2067,7 @@ 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,
-                                                as_a <rtx_insn *> (insn));
+      return (*insn_data[code].output.function) (recog_data.operand, insn);
 
     default:
       gcc_unreachable ();
@@ -2152,14 +2144,13 @@ asm_show_source (const char *filename, int linenum)
   if (!filename)
     return;
 
-  int line_size;
-  const char *line = location_get_source_line (filename, linenum, &line_size);
+  char_span line = location_get_source_line (filename, linenum);
   if (!line)
     return;
 
   fprintf (asm_out_file, "%s %s:%i: ", ASM_COMMENT_START, filename, linenum);
-  /* "line" is not 0-terminated, so we must use line_size.  */
-  fwrite (line, 1, line_size, asm_out_file);
+  /* "line" is not 0-terminated, so we must use its length.  */
+  fwrite (line.get_buffer (), 1, line.length (), asm_out_file);
   fputc ('\n', asm_out_file);
 }
 
@@ -2175,14 +2166,15 @@ asm_show_source (const char *filename, int linenum)
    debug information.  We force the emission of a line note after
    both NOTE_INSN_PROLOGUE_END and NOTE_INSN_FUNCTION_BEG.  */
 
-rtx_insn *
-final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
-                int nopeepholes ATTRIBUTE_UNUSED, int *seen)
+static rtx_insn *
+final_scan_insn_1 (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
+                  int nopeepholes ATTRIBUTE_UNUSED, int *seen)
 {
 #if HAVE_cc0
   rtx set;
 #endif
   rtx_insn *next;
+  rtx_jump_table_data *table;
 
   insn_counter++;
 
@@ -2201,10 +2193,26 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
          break;
 
        case NOTE_INSN_SWITCH_TEXT_SECTIONS:
+         maybe_output_next_view (seen);
+
+         output_function_exception_table (0);
+
+         if (targetm.asm_out.unwind_emit)
+           targetm.asm_out.unwind_emit (asm_out_file, insn);
+
          in_cold_section_p = !in_cold_section_p;
 
+         if (in_cold_section_p)
+           cold_function_name
+             = clone_function_name (current_function_decl, "cold");
+
          if (dwarf2out_do_frame ())
-           dwarf2out_switch_text_section ();
+           {
+             dwarf2out_switch_text_section ();
+             if (!dwarf2_debug_info_emitted_p (current_function_decl)
+                 && !DECL_IGNORED_P (current_function_decl))
+               debug_hooks->switch_text_section ();
+           }
          else if (!DECL_IGNORED_P (current_function_decl))
            debug_hooks->switch_text_section ();
 
@@ -2216,8 +2224,6 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
             suffixing "cold" to the original function's name.  */
          if (in_cold_section_p)
            {
-             cold_function_name
-               = clone_function_name (current_function_decl, "cold");
 #ifdef ASM_DECLARE_COLD_FUNCTION_NAME
              ASM_DECLARE_COLD_FUNCTION_NAME (asm_out_file,
                                              IDENTIFIER_POINTER
@@ -2227,6 +2233,9 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
              ASM_OUTPUT_LABEL (asm_out_file,
                                IDENTIFIER_POINTER (cold_function_name));
 #endif
+             if (dwarf2out_do_frame ()
+                 && cfun->fde->dw_fde_second_begin != NULL)
+               ASM_OUTPUT_LABEL (asm_out_file, cfun->fde->dw_fde_second_begin);
            }
          break;
 
@@ -2240,8 +2249,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
          if (targetm.asm_out.unwind_emit)
            targetm.asm_out.unwind_emit (asm_out_file, insn);
 
-          discriminator = NOTE_BASIC_BLOCK (insn)->discriminator;
-
+         bb_discriminator = NOTE_BASIC_BLOCK (insn)->discriminator;
          break;
 
        case NOTE_INSN_EH_REGION_BEG:
@@ -2325,8 +2333,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
              TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
              BLOCK_IN_COLD_SECTION_P (NOTE_BLOCK (insn)) = in_cold_section_p;
            }
-         if (write_symbols == DBX_DEBUG
-             || write_symbols == SDB_DEBUG)
+         if (write_symbols == DBX_DEBUG)
            {
              location_t *locus_ptr
                = block_nonartificial_location (NOTE_BLOCK (insn));
@@ -2335,11 +2342,15 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
                {
                  override_filename = LOCATION_FILE (*locus_ptr);
                  override_linenum = LOCATION_LINE (*locus_ptr);
+                 override_columnnum = LOCATION_COLUMN (*locus_ptr);
+                 override_discriminator = compute_discriminator (*locus_ptr);
                }
            }
          break;
 
        case NOTE_INSN_BLOCK_END:
+         maybe_output_next_view (seen);
+
          if (debug_info_level == DINFO_LEVEL_NORMAL
              || debug_info_level == DINFO_LEVEL_VERBOSE
              || write_symbols == DWARF2_DEBUG
@@ -2359,8 +2370,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
              gcc_assert (BLOCK_IN_COLD_SECTION_P (NOTE_BLOCK (insn))
                          == in_cold_section_p);
            }
-         if (write_symbols == DBX_DEBUG
-             || write_symbols == SDB_DEBUG)
+         if (write_symbols == DBX_DEBUG)
            {
              tree outer_block = BLOCK_SUPERCONTEXT (NOTE_BLOCK (insn));
              location_t *locus_ptr
@@ -2370,11 +2380,15 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
                {
                  override_filename = LOCATION_FILE (*locus_ptr);
                  override_linenum = LOCATION_LINE (*locus_ptr);
+                 override_columnnum = LOCATION_COLUMN (*locus_ptr);
+                 override_discriminator = compute_discriminator (*locus_ptr);
                }
              else
                {
                  override_filename = NULL;
                  override_linenum = 0;
+                 override_columnnum = 0;
+                 override_discriminator = 0;
                }
            }
          break;
@@ -2393,9 +2407,35 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
          break;
 
        case NOTE_INSN_VAR_LOCATION:
-       case NOTE_INSN_CALL_ARG_LOCATION:
          if (!DECL_IGNORED_P (current_function_decl))
-           debug_hooks->var_location (insn);
+           {
+             debug_hooks->var_location (insn);
+             set_next_view_needed (seen);
+           }
+         break;
+
+       case NOTE_INSN_BEGIN_STMT:
+         gcc_checking_assert (cfun->debug_nonbind_markers);
+         if (!DECL_IGNORED_P (current_function_decl)
+             && notice_source_line (insn, NULL))
+           {
+           output_source_line:
+             (*debug_hooks->source_line) (last_linenum, last_columnnum,
+                                          last_filename, last_discriminator,
+                                          true);
+             clear_next_view_needed (seen);
+           }
+         break;
+
+       case NOTE_INSN_INLINE_ENTRY:
+         gcc_checking_assert (cfun->debug_nonbind_markers);
+         if (!DECL_IGNORED_P (current_function_decl)
+             && notice_source_line (insn, NULL))
+           {
+             (*debug_hooks->inline_entry) (LOCATION_BLOCK
+                                           (NOTE_MARKER_LOCATION (insn)));
+             goto output_source_line;
+           }
          break;
 
        default:
@@ -2412,20 +2452,20 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
         some insn, e.g. sh.c output_branchy_insn.  */
       if (CODE_LABEL_NUMBER (insn) <= max_labelno)
        {
-         int align = LABEL_TO_ALIGNMENT (insn);
-#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
-         int max_skip = LABEL_TO_MAX_SKIP (insn);
-#endif
-
-         if (align && NEXT_INSN (insn))
+         align_flags alignment = LABEL_TO_ALIGNMENT (insn);
+         if (alignment.levels[0].log && NEXT_INSN (insn))
            {
 #ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
-             ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip);
+             /* Output both primary and secondary alignment.  */
+             ASM_OUTPUT_MAX_SKIP_ALIGN (file, alignment.levels[0].log,
+                                        alignment.levels[0].maxskip);
+             ASM_OUTPUT_MAX_SKIP_ALIGN (file, alignment.levels[1].log,
+                                        alignment.levels[1].maxskip);
 #else
 #ifdef ASM_OUTPUT_ALIGN_WITH_NOP
-              ASM_OUTPUT_ALIGN_WITH_NOP (file, align);
+              ASM_OUTPUT_ALIGN_WITH_NOP (file, alignment.levels[0].log);
 #else
-             ASM_OUTPUT_ALIGN (file, align);
+             ASM_OUTPUT_ALIGN (file, alignment.levels[0].log);
 #endif
 #endif
            }
@@ -2437,11 +2477,11 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 
       app_disable ();
 
-      next = next_nonnote_insn (insn);
       /* 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))
+      table = jump_table_for_label (as_a <rtx_code_label *> (insn));
+      if (table)
        {
 #if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
          /* In this case, the case vector is being moved by the
@@ -2456,7 +2496,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
                                 (current_function_decl));
 
 #ifdef ADDR_VEC_ALIGN
-             log_align = ADDR_VEC_ALIGN (next);
+             log_align = ADDR_VEC_ALIGN (table);
 #else
              log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
 #endif
@@ -2466,8 +2506,7 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
            switch_to_section (current_function_section ());
 
 #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), table);
 #else
          targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
 #endif
@@ -2485,7 +2524,15 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
        rtx body = PATTERN (insn);
        int insn_code_number;
        const char *templ;
-       bool is_stmt;
+       bool is_stmt, *is_stmt_p;
+
+       if (MAY_HAVE_DEBUG_MARKER_INSNS && cfun->debug_nonbind_markers)
+         {
+           is_stmt = false;
+           is_stmt_p = NULL;
+         }
+       else
+         is_stmt_p = &is_stmt;
 
        /* Reset this early so it is correct for ASM statements.  */
        current_insn_predicate = NULL_RTX;
@@ -2583,18 +2630,28 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 
            switch_to_section (current_function_section ());
 
+           if (debug_variable_location_views
+               && !DECL_IGNORED_P (current_function_decl))
+             debug_hooks->var_location (insn);
+
            break;
          }
        /* Output this line note if it is the first or the last line
           note in a row.  */
        if (!DECL_IGNORED_P (current_function_decl)
-           && notice_source_line (insn, &is_stmt))
+           && notice_source_line (insn, is_stmt_p))
          {
            if (flag_verbose_asm)
              asm_show_source (last_filename, last_linenum);
-           (*debug_hooks->source_line) (last_linenum, last_filename,
-                                        last_discriminator, is_stmt);
+           (*debug_hooks->source_line) (last_linenum, last_columnnum,
+                                        last_filename, last_discriminator,
+                                        is_stmt);
+           clear_next_view_needed (seen);
          }
+       else
+         maybe_output_next_view (seen);
+
+       gcc_checking_assert (!DEBUG_INSN_P (insn));
 
        if (GET_CODE (body) == PARALLEL
            && GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
@@ -3061,7 +3118,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
        /* Let the debug info back-end know about this call.  We do this only
           after the instruction has been emitted because labels that may be
           created to reference the call instruction must appear after it.  */
-       if (call_insn != NULL && !DECL_IGNORED_P (current_function_decl))
+       if ((debug_variable_location_views || call_insn != NULL)
+           && !DECL_IGNORED_P (current_function_decl))
          debug_hooks->var_location (insn);
 
        current_output_insn = debug_insn = 0;
@@ -3069,7 +3127,97 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
     }
   return NEXT_INSN (insn);
 }
+
+/* This is a wrapper around final_scan_insn_1 that allows ports to
+   call it recursively without a known value for SEEN.  The value is
+   saved at the outermost call, and recovered for recursive calls.
+   Recursive calls MUST pass NULL, or the same pointer if they can
+   otherwise get to it.  */
+
+rtx_insn *
+final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p,
+                int nopeepholes, int *seen)
+{
+  static int *enclosing_seen;
+  static int recursion_counter;
+
+  gcc_assert (seen || recursion_counter);
+  gcc_assert (!recursion_counter || !seen || seen == enclosing_seen);
+
+  if (!recursion_counter++)
+    enclosing_seen = seen;
+  else if (!seen)
+    seen = enclosing_seen;
+
+  rtx_insn *ret = final_scan_insn_1 (insn, file, optimize_p, nopeepholes, seen);
+
+  if (!--recursion_counter)
+    enclosing_seen = NULL;
+
+  return ret;
+}
+
 \f
+
+/* Map DECLs to instance discriminators.  This is allocated and
+   defined in ada/gcc-interfaces/trans.c, when compiling with -gnateS.
+   Mappings from this table are saved and restored for LTO, so
+   link-time compilation will have this map set, at least in
+   partitions containing at least one DECL with an associated instance
+   discriminator.  */
+
+decl_to_instance_map_t *decl_to_instance_map;
+
+/* Return the instance number assigned to DECL.  */
+
+static inline int
+map_decl_to_instance (const_tree decl)
+{
+  int *inst;
+
+  if (!decl_to_instance_map || !decl || !DECL_P (decl))
+    return 0;
+
+  inst = decl_to_instance_map->get (decl);
+
+  if (!inst)
+    return 0;
+
+  return *inst;
+}
+
+/* Set DISCRIMINATOR to the appropriate value, possibly derived from LOC.  */
+
+static inline int
+compute_discriminator (location_t loc)
+{
+  int discriminator;
+
+  if (!decl_to_instance_map)
+    discriminator = bb_discriminator;
+  else
+    {
+      tree block = LOCATION_BLOCK (loc);
+
+      while (block && TREE_CODE (block) == BLOCK
+            && !inlined_function_outer_scope_p (block))
+       block = BLOCK_SUPERCONTEXT (block);
+
+      tree decl;
+
+      if (!block)
+       decl = current_function_decl;
+      else if (DECL_P (block))
+       decl = block;
+      else
+       decl = block_ultimate_origin (block);
+
+      discriminator = map_decl_to_instance (decl);
+    }
+
+  return discriminator;
+}
+
 /* 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.  */
@@ -3078,23 +3226,45 @@ static bool
 notice_source_line (rtx_insn *insn, bool *is_stmt)
 {
   const char *filename;
-  int linenum;
+  int linenum, columnnum;
 
-  if (override_filename)
+  if (NOTE_MARKER_P (insn))
+    {
+      location_t loc = NOTE_MARKER_LOCATION (insn);
+      expanded_location xloc = expand_location (loc);
+      if (xloc.line == 0)
+       {
+         gcc_checking_assert (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION
+                              || LOCATION_LOCUS (loc) == BUILTINS_LOCATION);
+         return false;
+       }
+      filename = xloc.file;
+      linenum = xloc.line;
+      columnnum = xloc.column;
+      discriminator = compute_discriminator (loc);
+      force_source_line = true;
+    }
+  else if (override_filename)
     {
       filename = override_filename;
       linenum = override_linenum;
+      columnnum = override_columnnum;
+      discriminator = override_discriminator;
     }
   else if (INSN_HAS_LOCATION (insn))
     {
       expanded_location xloc = insn_location (insn);
       filename = xloc.file;
       linenum = xloc.line;
+      columnnum = xloc.column;
+      discriminator = compute_discriminator (INSN_LOCATION (insn));
     }
   else
     {
       filename = NULL;
       linenum = 0;
+      columnnum = 0;
+      discriminator = 0;
     }
 
   if (filename == NULL)
@@ -3102,13 +3272,16 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
 
   if (force_source_line
       || filename != last_filename
-      || last_linenum != linenum)
+      || last_linenum != linenum
+      || (debug_column_info && last_columnnum != columnnum))
     {
       force_source_line = false;
       last_filename = filename;
       last_linenum = linenum;
+      last_columnnum = columnnum;
       last_discriminator = discriminator;
-      *is_stmt = true;
+      if (is_stmt)
+       *is_stmt = true;
       high_block_linenum = MAX (last_linenum, high_block_linenum);
       high_function_linenum = MAX (last_linenum, high_function_linenum);
       return true;
@@ -3120,7 +3293,8 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
          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;
+      if (is_stmt)
+       *is_stmt = false;
       return true;
     }
 
@@ -3183,20 +3357,12 @@ alter_subreg (rtx *xp, bool final_p)
      We are required to.  */
   if (MEM_P (y))
     {
-      int offset = SUBREG_BYTE (x);
+      poly_int64 offset = SUBREG_BYTE (x);
 
       /* For paradoxical subregs on big-endian machines, SUBREG_BYTE
         contains 0 instead of the proper offset.  See simplify_subreg.  */
-      if (offset == 0
-         && GET_MODE_SIZE (GET_MODE (y)) < GET_MODE_SIZE (GET_MODE (x)))
-        {
-          int difference = GET_MODE_SIZE (GET_MODE (y))
-                          - GET_MODE_SIZE (GET_MODE (x));
-          if (WORDS_BIG_ENDIAN)
-            offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
-          if (BYTES_BIG_ENDIAN)
-            offset += difference % UNITS_PER_WORD;
-        }
+      if (paradoxical_subreg_p (x))
+       offset = byte_lowpart_offset (GET_MODE (x), GET_MODE (y));
 
       if (final_p)
        *xp = adjust_address (y, GET_MODE (x), offset);
@@ -3214,7 +3380,7 @@ alter_subreg (rtx *xp, bool final_p)
        {
          /* Simplify_subreg can't handle some REG cases, but we have to.  */
          unsigned int regno;
-         HOST_WIDE_INT offset;
+         poly_int64 offset;
 
          regno = subreg_regno (x);
          if (subreg_lowpart_p (x))
@@ -3457,16 +3623,20 @@ output_asm_name (void)
 {
   if (debug_insn)
     {
-      int num = INSN_CODE (debug_insn);
-      fprintf (asm_out_file, "\t%s %d\t%s",
-              ASM_COMMENT_START, INSN_UID (debug_insn),
-              insn_data[num].name);
-      if (insn_data[num].n_alternatives > 1)
-       fprintf (asm_out_file, "/%d", which_alternative + 1);
+      fprintf (asm_out_file, "\t%s %d\t",
+              ASM_COMMENT_START, INSN_UID (debug_insn));
 
+      fprintf (asm_out_file, "[c=%d",
+              insn_cost (debug_insn, optimize_insn_for_speed_p ()));
       if (HAVE_ATTR_length)
-       fprintf (asm_out_file, "\t[length = %d]",
+       fprintf (asm_out_file, " l=%d",
                 get_attr_length (debug_insn));
+      fprintf (asm_out_file, "]  ");
+
+      int num = INSN_CODE (debug_insn);
+      fprintf (asm_out_file, "%s", insn_data[num].name);
+      if (insn_data[num].n_alternatives > 1)
+       fprintf (asm_out_file, "/%d", which_alternative);
 
       /* Clear this so only the first assembler insn
         of any rtl insn will get the special comment for -dp.  */
@@ -3812,6 +3982,10 @@ output_asm_insn (const char *templ, rtx *operands)
        putc (c, asm_out_file);
       }
 
+  /* Try to keep the asm a bit more readable.  */
+  if ((flag_verbose_asm || flag_print_asm_name) && strlen (templ) < 9)
+    putc ('\t', asm_out_file);
+
   /* Write out the variable names for operands, if we know them.  */
   if (flag_verbose_asm)
     output_asm_operand_names (operands, oporder, ops);
@@ -4295,6 +4469,9 @@ leaf_function_p (void)
 {
   rtx_insn *insn;
 
+  /* Ensure we walk the entire function body.  */
+  gcc_assert (!in_sequence_p ());
+
   /* 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 ())
@@ -4442,11 +4619,9 @@ leaf_renumber_regs_insn (rtx in_rtx)
        break;
 
       case 'E':
-       if (NULL != XVEC (in_rtx, i))
-         {
-           for (j = 0; j < XVECLEN (in_rtx, i); j++)
-             leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j));
-         }
+       if (XVEC (in_rtx, i) != NULL)
+         for (j = 0; j < XVECLEN (in_rtx, i); j++)
+           leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j));
        break;
 
       case 'S':
@@ -4454,6 +4629,7 @@ leaf_renumber_regs_insn (rtx in_rtx)
       case '0':
       case 'i':
       case 'w':
+      case 'p':
       case 'n':
       case 'u':
        break;
@@ -4470,17 +4646,29 @@ rest_of_handle_final (void)
 {
   const char *fnname = get_fnname_from_decl (current_function_decl);
 
+  /* Turn debug markers into notes if the var-tracking pass has not
+     been invoked.  */
+  if (!flag_var_tracking && MAY_HAVE_DEBUG_MARKER_INSNS)
+    delete_vta_debug_insns (false);
+
   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_ipa_ra)
+  rtx_insn *first = get_insns ();
+  int seen = 0;
+  final_start_function_1 (&first, asm_out_file, &seen, optimize);
+  final_1 (first, asm_out_file, seen, optimize);
+  if (flag_ipa_ra
+      && !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl))
+      /* Functions with naked attributes are supported only with basic asm
+        statements in the body, thus for supported use cases the information
+        on clobbered registers is not available.  */
+      && !lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)))
     collect_fn_hard_reg_usage ();
   final_end_function ();
 
   /* The IA-64 ".handlerdata" directive must be issued before the ".endp"
      directive that closes the procedure descriptor.  Similarly, for x64 SEH.
      Otherwise it's not strictly necessary, but it doesn't hurt either.  */
-  output_function_exception_table (fnname);
+  output_function_exception_table (crtl->has_bb_partition ? 1 : 0);
 
   assemble_end_function (current_function_decl, fnname);
 
@@ -4626,7 +4814,7 @@ rest_of_clean_state (void)
        {
          flag_dump_noaddr = flag_dump_unnumbered = 1;
          if (flag_compare_debug_opt || flag_compare_debug)
-           dump_flags |= TDF_NOUID;
+           dump_flags |= TDF_NOUID | TDF_COMPARE_DEBUG;
          dump_function_header (final_output, current_function_decl,
                                dump_flags);
          final_insns_dump_p = true;
@@ -4653,13 +4841,29 @@ rest_of_clean_state (void)
       SET_NEXT_INSN (insn) = NULL;
       SET_PREV_INSN (insn) = NULL;
 
+      rtx_insn *call_insn = insn;
+      if (NONJUMP_INSN_P (call_insn)
+         && GET_CODE (PATTERN (call_insn)) == SEQUENCE)
+       {
+         rtx_sequence *seq = as_a <rtx_sequence *> (PATTERN (call_insn));
+         call_insn = seq->insn (0);
+       }
+      if (CALL_P (call_insn))
+       {
+         rtx note
+           = find_reg_note (call_insn, REG_CALL_ARG_LOCATION, NULL_RTX);
+         if (note)
+           remove_note (call_insn, note);
+       }
+
       if (final_output
-         && (!NOTE_P (insn) ||
-             (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
-              && 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_DELETED_DEBUG_LABEL)))
+         && (!NOTE_P (insn)
+             || (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
+                 && NOTE_KIND (insn) != NOTE_INSN_BEGIN_STMT
+                 && NOTE_KIND (insn) != NOTE_INSN_INLINE_ENTRY
+                 && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
+                 && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
+                 && NOTE_KIND (insn) != NOTE_INSN_DELETED_DEBUG_LABEL)))
        print_rtl_single (final_output, insn);
     }
 
@@ -4677,12 +4881,6 @@ rest_of_clean_state (void)
        }
     }
 
-  /* In case the function was not output,
-     don't leave any temporary anonymous types
-     queued up for sdb output.  */
-  if (SDB_DEBUGGING_INFO && write_symbols == SDB_DEBUG)
-    sdbout_types (NULL_TREE);
-
   flag_rerun_cse_after_global_opts = 0;
   reload_completed = 0;
   epilogue_completed = 0;
@@ -4705,7 +4903,8 @@ rest_of_clean_state (void)
   /* We can reduce stack alignment on call site only when we are sure that
      the function body just produced will be actually used in the final
      executable.  */
-  if (decl_binds_to_current_def_p (current_function_decl))
+  if (flag_ipa_stack_alignment
+      && decl_binds_to_current_def_p (current_function_decl))
     {
       unsigned int pref = crtl->preferred_stack_boundary;
       if (crtl->stack_alignment_needed > crtl->preferred_stack_boundary)
@@ -4794,7 +4993,16 @@ collect_fn_hard_reg_usage (void)
   if (!targetm.call_fusage_contains_non_callee_clobbers)
     return;
 
-  CLEAR_HARD_REG_SET (function_used_regs);
+  /* Be conservative - mark fixed and global registers as used.  */
+  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
 
   for (insn = get_insns (); insn != NULL_RTX; insn = next_insn (insn))
     {
@@ -4805,97 +5013,23 @@ collect_fn_hard_reg_usage (void)
 
       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);
-       }
+       function_used_regs
+         |= insn_callee_abi (insn).full_and_partial_reg_clobbers ();
 
       find_all_hard_reg_sets (insn, &insn_used_regs, false);
-      IOR_HARD_REG_SET (function_used_regs, insn_used_regs);
-    }
+      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
+      if (hard_reg_set_subset_p (crtl->abi->full_and_partial_reg_clobbers (),
+                                function_used_regs))
+       return;
+    }
 
-  /* 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;
+  /* Mask out fully-saved registers, so that they don't affect equality
+     comparisons between function_abis.  */
+  function_used_regs &= crtl->abi->full_and_partial_reg_clobbers ();
 
   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_ipa_ra)
-    {
-      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;
+  node->function_used_regs = function_used_regs;
 }