]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/final.c
Update copyright years.
[thirdparty/gcc.git] / gcc / final.c
index 1969ccbed0057fdc1149677ab33d4b51e9a63e74..296a9382e91b4443502c7e132b94e2c8b2008610 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-2022 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -75,12 +75,13 @@ 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"
+#include "common/common-target.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data declarations.  */
@@ -92,7 +93,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbxout.h"
 #endif
 
-/* Most ports that aren't using cc0 don't need to define CC_STATUS_INIT.
+/* Most ports don't need to define CC_STATUS_INIT.
    So define a null default for it to save conditionalization later.  */
 #ifndef CC_STATUS_INIT
 #define CC_STATUS_INIT
@@ -110,6 +111,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;
@@ -121,11 +123,20 @@ static int last_linenum;
 /* Column number of last NOTE.  */
 static int last_columnnum;
 
-/* Last discriminator written to assembly.  */
+/* 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;
@@ -140,6 +151,7 @@ static const char *last_filename;
 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;
@@ -163,17 +175,6 @@ static rtx last_ignored_compare = 0;
 
 static int insn_counter = 0;
 
-/* This variable contains machine-dependent flags (defined in tm.h)
-   set and examined by output routines
-   that describe how to interpret the condition codes properly.  */
-
-CC_STATUS cc_status;
-
-/* During output of an insn, this contains a copy of cc_status
-   from before the insn.  */
-
-CC_STATUS cc_prev_status;
-
 /* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen.  */
 
 static int block_depth;
@@ -196,7 +197,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.  */
@@ -214,12 +215,8 @@ static void output_asm_operand_names (rtx *, int *, int);
 #ifdef LEAF_REGISTERS
 static void leaf_renumber_regs (rtx_insn *);
 #endif
-#if HAVE_cc0
-static int alter_cond (rtx);
-#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.  */
 
@@ -326,15 +323,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 +463,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,33 +475,9 @@ 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_jump_table_data *addr_vec)
@@ -535,27 +502,16 @@ final_addr_vec_align (rtx_jump_table_data *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 +559,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 +592,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.
@@ -666,18 +622,14 @@ insn_current_reference_address (rtx_insn *branch)
 unsigned int
 compute_alignments (void)
 {
-  int log, max_skip, max_log;
   basic_block bb;
+  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, true);
 
   /* If not optimizing or optimizing for size, don't assign any alignments.  */
   if (! optimize || optimize_function_for_size_p (cfun))
@@ -691,7 +643,7 @@ compute_alignments (void)
     }
   loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
   profile_count count_threshold = cfun->cfg->count_max.apply_scale
-                (1, PARAM_VALUE (PARAM_ALIGN_THRESHOLD));
+                (1, param_align_threshold);
 
   if (dump_file)
     {
@@ -717,8 +669,7 @@ compute_alignments (void)
                     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 ();
 
@@ -760,18 +711,14 @@ compute_alignments (void)
       if (!has_fallthru
          && (branch_count > count_threshold
              || (bb->count > bb->prev_bb->count.apply_scale (10, 1)
-                 && (bb->prev_bb->count 
+                 && (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.  */
@@ -782,19 +729,14 @@ compute_alignments (void)
          && branch_count + fallthru_count > count_threshold
          && (branch_count
              > fallthru_count.apply_scale
-                   (PARAM_VALUE (PARAM_ALIGN_LOOP_ITERATIONS), 1)))
+                   (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 ();
@@ -804,7 +746,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;
@@ -816,14 +758,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, true);
 
   /* 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
@@ -841,10 +780,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;
 }
@@ -902,15 +838,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 ();
@@ -925,17 +858,14 @@ 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;
@@ -943,22 +873,14 @@ shorten_branches (rtx_insn *first)
       if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
        {
          /* Merge in alignments computed by compute_alignments.  */
-         log = LABEL_TO_ALIGNMENT (label);
-         if (max_log < log)
-           {
-             max_log = log;
-             max_skip = LABEL_TO_MAX_SKIP (label);
-           }
+         align_flags alignment = LABEL_TO_ALIGNMENT (label);
+         max_alignment = align_flags::max (max_alignment, alignment);
 
          rtx_jump_table_data *table = jump_table_for_label (label);
          if (!table)
            {
-             log = LABEL_ALIGN (label);
-             if (max_log < log)
-               {
-                 max_log = log;
-                 max_skip = targetm.asm_out.label_align_max_skip (label);
-               }
+             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.  */
@@ -966,17 +888,11 @@ shorten_branches (rtx_insn *first)
               || readonly_data_section == text_section)
              && table)
            {
-             log = ADDR_VEC_ALIGN (table);
-             if (max_log < log)
-               {
-                 max_log = log;
-                 max_skip = targetm.asm_out.label_align_max_skip (label);
-               }
+             align_flags alignment = align_flags (ADDR_VEC_ALIGN (table));
+             max_alignment = align_flags::max (max_alignment, alignment);
            }
-         LABEL_TO_ALIGNMENT (label) = max_log;
-         LABEL_TO_MAX_SKIP (label) = max_skip;
-         max_log = 0;
-         max_skip = 0;
+         LABEL_TO_ALIGNMENT (label) = max_alignment;
+         max_alignment = align_flags ();
        }
       else if (BARRIER_P (insn))
        {
@@ -986,12 +902,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;
              }
        }
@@ -1015,18 +928,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;
@@ -1077,8 +991,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);
@@ -1112,7 +1028,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;
@@ -1220,7 +1136,7 @@ shorten_branches (rtx_insn *first)
 
          if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
            {
-             int log = LABEL_TO_ALIGNMENT (label);
+             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
@@ -1295,7 +1211,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;
                  }
 
@@ -1507,78 +1423,13 @@ 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
 dwarf2_debug_info_emitted_p (tree decl)
 {
-  if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG)
+  /* When DWARF2 debug info is not generated internally.  */
+  if (!dwarf_debuginfo_p () && !dwarf_based_debuginfo_p ())
     return false;
 
   if (DECL_IGNORED_P (decl))
@@ -1676,6 +1527,7 @@ reemit_insn_block_notes (void)
            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;
 
@@ -1758,6 +1610,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
@@ -1765,12 +1678,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;
 
@@ -1782,18 +1698,36 @@ final_start_function (rtx_insn *first, FILE *file,
   last_linenum = LOCATION_LINE (prologue_location);
   last_columnnum = LOCATION_COLUMN (prologue_location);
   last_discriminator = discriminator = 0;
+  last_bb_discriminator = bb_discriminator = 0;
+  force_source_line = false;
 
   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_columnnum, 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, 0, NULL);
 
+  if (DECL_IGNORED_P (current_function_decl) && last_linenum && last_filename)
+    debug_hooks->set_ignored_loc (last_linenum, last_columnnum, last_filename);
+
 #ifdef LEAF_REG_REMAP
   if (crtl->uses_only_leaf_regs)
     leaf_renumber_regs (first);
@@ -1846,14 +1780,14 @@ final_start_function (rtx_insn *first, FILE *file,
       TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
     }
 
-  HOST_WIDE_INT min_frame_size = constant_lower_bound (get_frame_size ());
-  if (warn_frame_larger_than
-      && min_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",
-              min_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.  */
@@ -1865,6 +1799,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)
 {
@@ -1994,11 +1939,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;
@@ -2008,21 +1952,6 @@ final (rtx_insn *first, FILE *file, int optimize_p)
 
   last_ignored_compare = 0;
 
-  if (HAVE_cc0)
-    for (insn = first; insn; insn = NEXT_INSN (insn))
-      {
-       /* 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_P (lab) && LABEL_NUSES (lab) == 1)
-             {
-               LABEL_REFS (lab) = insn;
-             }
-         }
-      }
-
   init_recog ();
 
   CC_STATUS_INIT;
@@ -2058,6 +1987,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,
@@ -2065,6 +1997,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);
@@ -2081,9 +2015,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)
     {
@@ -2093,8 +2044,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 ();
@@ -2171,17 +2121,31 @@ 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);
 }
 
+/* Judge if an absolute jump table is relocatable.  */
+
+bool
+jumptable_relocatable (void)
+{
+  bool relocatable = false;
+
+  if (!CASE_VECTOR_PC_RELATIVE
+      && !targetm.asm_out.generate_pic_addr_diff_vec ()
+      && targetm_common.have_named_sections)
+     relocatable = targetm.asm_out.reloc_rw_mask ();
+
+  return relocatable;
+}
+
 /* The final scan for one insn, INSN.
    Args are same as in `final', except that INSN
    is the insn being scanned.
@@ -2194,13 +2158,10 @@ 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;
 
@@ -2221,8 +2182,16 @@ 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;
 
+         gcc_checking_assert (in_cold_section_p);
          if (in_cold_section_p)
            cold_function_name
              = clone_function_name (current_function_decl, "cold");
@@ -2236,6 +2205,10 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
            }
          else if (!DECL_IGNORED_P (current_function_decl))
            debug_hooks->switch_text_section ();
+         if (DECL_IGNORED_P (current_function_decl) && last_linenum
+             && last_filename)
+           debug_hooks->set_ignored_loc (last_linenum, last_columnnum,
+                                         last_filename);
 
          switch_to_section (current_function_section ());
          targetm.asm_out.function_switched_text_sections (asm_out_file,
@@ -2254,6 +2227,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;
 
@@ -2267,8 +2243,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:
@@ -2332,10 +2307,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
          break;
 
        case NOTE_INSN_BLOCK_BEG:
-         if (debug_info_level == DINFO_LEVEL_NORMAL
-             || debug_info_level == DINFO_LEVEL_VERBOSE
-             || write_symbols == DWARF2_DEBUG
-             || write_symbols == VMS_AND_DWARF2_DEBUG
+         if (debug_info_level >= DINFO_LEVEL_NORMAL
+             || dwarf_debuginfo_p ()
              || write_symbols == VMS_DEBUG)
            {
              int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
@@ -2362,15 +2335,16 @@ 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:
-         if (debug_info_level == DINFO_LEVEL_NORMAL
-             || debug_info_level == DINFO_LEVEL_VERBOSE
-             || write_symbols == DWARF2_DEBUG
-             || write_symbols == VMS_AND_DWARF2_DEBUG
+         maybe_output_next_view (seen);
+
+         if (debug_info_level >= DINFO_LEVEL_NORMAL
+             || dwarf_debuginfo_p ()
              || write_symbols == VMS_DEBUG)
            {
              int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
@@ -2397,12 +2371,14 @@ 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;
@@ -2421,9 +2397,11 @@ 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:
@@ -2431,9 +2409,22 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
          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;
 
@@ -2451,20 +2442,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
            }
@@ -2492,7 +2483,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
              int log_align;
 
              switch_to_section (targetm.asm_out.function_rodata_section
-                                (current_function_decl));
+                                (current_function_decl,
+                                 jumptable_relocatable ()));
 
 #ifdef ADDR_VEC_ALIGN
              log_align = ADDR_VEC_ALIGN (table);
@@ -2543,23 +2535,6 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
            || GET_CODE (body) == CLOBBER)
          break;
 
-#if HAVE_cc0
-       {
-         /* If there is a REG_CC_SETTER note on this insn, it means that
-            the setting of the condition code was done in the delay slot
-            of the insn that branched here.  So recover the cc status
-            from the insn that set it.  */
-
-         rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
-         if (note)
-           {
-             rtx_insn *other = as_a <rtx_insn *> (XEXP (note, 0));
-             NOTICE_UPDATE_CC (PATTERN (other), other);
-             cc_prev_status = cc_status;
-           }
-       }
-#endif
-
        /* Detect insns that are really jump-tables
           and output them as such.  */
 
@@ -2571,7 +2546,8 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 
            if (! JUMP_TABLES_IN_TEXT_SECTION)
              switch_to_section (targetm.asm_out.function_rodata_section
-                                (current_function_decl));
+                                (current_function_decl,
+                                 jumptable_relocatable ()));
            else
              switch_to_section (current_function_section ());
 
@@ -2629,6 +2605,10 @@ 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
@@ -2641,7 +2621,12 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
            (*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)
@@ -2769,182 +2754,6 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 
        body = PATTERN (insn);
 
-#if HAVE_cc0
-       set = single_set (insn);
-
-       /* Check for redundant test and compare instructions
-          (when the condition codes are already set up as desired).
-          This is done only when optimizing; if not optimizing,
-          it should be possible for the user to alter a variable
-          with the debugger in between statements
-          and the next statement should reexamine the variable
-          to compute the condition codes.  */
-
-       if (optimize_p)
-         {
-           if (set
-               && GET_CODE (SET_DEST (set)) == CC0
-               && insn != last_ignored_compare)
-             {
-               rtx src1, src2;
-               if (GET_CODE (SET_SRC (set)) == SUBREG)
-                 SET_SRC (set) = alter_subreg (&SET_SRC (set), true);
-
-               src1 = SET_SRC (set);
-               src2 = NULL_RTX;
-               if (GET_CODE (SET_SRC (set)) == COMPARE)
-                 {
-                   if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
-                     XEXP (SET_SRC (set), 0)
-                       = 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), true);
-                   if (XEXP (SET_SRC (set), 1)
-                       == CONST0_RTX (GET_MODE (XEXP (SET_SRC (set), 0))))
-                     src2 = XEXP (SET_SRC (set), 0);
-                 }
-               if ((cc_status.value1 != 0
-                    && rtx_equal_p (src1, cc_status.value1))
-                   || (cc_status.value2 != 0
-                       && rtx_equal_p (src1, cc_status.value2))
-                   || (src2 != 0 && cc_status.value1 != 0
-                       && rtx_equal_p (src2, cc_status.value1))
-                   || (src2 != 0 && cc_status.value2 != 0
-                       && rtx_equal_p (src2, cc_status.value2)))
-                 {
-                   /* Don't delete insn if it has an addressing side-effect.  */
-                   if (! FIND_REG_INC_NOTE (insn, NULL_RTX)
-                       /* or if anything in it is volatile.  */
-                       && ! volatile_refs_p (PATTERN (insn)))
-                     {
-                       /* We don't really delete the insn; just ignore it.  */
-                       last_ignored_compare = insn;
-                       break;
-                     }
-                 }
-             }
-         }
-
-       /* If this is a conditional branch, maybe modify it
-          if the cc's are in a nonstandard state
-          so that it accomplishes the same thing that it would
-          do straightforwardly if the cc's were set up normally.  */
-
-       if (cc_status.flags != 0
-           && JUMP_P (insn)
-           && GET_CODE (body) == SET
-           && SET_DEST (body) == pc_rtx
-           && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
-           && COMPARISON_P (XEXP (SET_SRC (body), 0))
-           && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx)
-         {
-           /* This function may alter the contents of its argument
-              and clear some of the cc_status.flags bits.
-              It may also return 1 meaning condition now always true
-              or -1 meaning condition now always false
-              or 2 meaning condition nontrivial but altered.  */
-           int result = alter_cond (XEXP (SET_SRC (body), 0));
-           /* If condition now has fixed value, replace the IF_THEN_ELSE
-              with its then-operand or its else-operand.  */
-           if (result == 1)
-             SET_SRC (body) = XEXP (SET_SRC (body), 1);
-           if (result == -1)
-             SET_SRC (body) = XEXP (SET_SRC (body), 2);
-
-           /* The jump is now either unconditional or a no-op.
-              If it has become a no-op, don't try to output it.
-              (It would not be recognized.)  */
-           if (SET_SRC (body) == pc_rtx)
-             {
-               delete_insn (insn);
-               break;
-             }
-           else if (ANY_RETURN_P (SET_SRC (body)))
-             /* Replace (set (pc) (return)) with (return).  */
-             PATTERN (insn) = body = SET_SRC (body);
-
-           /* Rerecognize the instruction if it has changed.  */
-           if (result != 0)
-             INSN_CODE (insn) = -1;
-         }
-
-       /* If this is a conditional trap, maybe modify it if the cc's
-          are in a nonstandard state so that it accomplishes the same
-          thing that it would do straightforwardly if the cc's were
-          set up normally.  */
-       if (cc_status.flags != 0
-           && NONJUMP_INSN_P (insn)
-           && GET_CODE (body) == TRAP_IF
-           && COMPARISON_P (TRAP_CONDITION (body))
-           && XEXP (TRAP_CONDITION (body), 0) == cc0_rtx)
-         {
-           /* This function may alter the contents of its argument
-              and clear some of the cc_status.flags bits.
-              It may also return 1 meaning condition now always true
-              or -1 meaning condition now always false
-              or 2 meaning condition nontrivial but altered.  */
-           int result = alter_cond (TRAP_CONDITION (body));
-
-           /* If TRAP_CONDITION has become always false, delete the
-              instruction.  */
-           if (result == -1)
-             {
-               delete_insn (insn);
-               break;
-             }
-
-           /* If TRAP_CONDITION has become always true, replace
-              TRAP_CONDITION with const_true_rtx.  */
-           if (result == 1)
-             TRAP_CONDITION (body) = const_true_rtx;
-
-           /* Rerecognize the instruction if it has changed.  */
-           if (result != 0)
-             INSN_CODE (insn) = -1;
-         }
-
-       /* Make same adjustments to instructions that examine the
-          condition codes without jumping and instructions that
-          handle conditional moves (if this machine has either one).  */
-
-       if (cc_status.flags != 0
-           && set != 0)
-         {
-           rtx cond_rtx, then_rtx, else_rtx;
-
-           if (!JUMP_P (insn)
-               && GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
-             {
-               cond_rtx = XEXP (SET_SRC (set), 0);
-               then_rtx = XEXP (SET_SRC (set), 1);
-               else_rtx = XEXP (SET_SRC (set), 2);
-             }
-           else
-             {
-               cond_rtx = SET_SRC (set);
-               then_rtx = const_true_rtx;
-               else_rtx = const0_rtx;
-             }
-
-           if (COMPARISON_P (cond_rtx)
-               && XEXP (cond_rtx, 0) == cc0_rtx)
-             {
-               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);
-             }
-         }
-
-#endif
-
        /* Do machine-specific peephole optimizations if desired.  */
 
        if (HAVE_peephole && optimize_p && !flag_no_peephole && !nopeepholes)
@@ -3012,17 +2821,6 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
            && GET_CODE (PATTERN (insn)) == COND_EXEC)
          current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));
 
-#if HAVE_cc0
-       cc_prev_status = cc_status;
-
-       /* Update `cc_status' for this instruction.
-          The instruction's output routine may change it further.
-          If the output routine for a jump insn needs to depend
-          on the cc status, it should look at cc_prev_status.  */
-
-       NOTICE_UPDATE_CC (body, insn);
-#endif
-
        current_output_insn = debug_insn = insn;
 
        /* Find the proper template for this insn.  */
@@ -3108,7 +2906,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;
@@ -3116,7 +2915,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.  */
@@ -3131,15 +3020,15 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
     {
       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;
-       }
+      if (xloc.line == 0
+         && (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)
@@ -3147,6 +3036,7 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
       filename = override_filename;
       linenum = override_linenum;
       columnnum = override_columnnum;
+      discriminator = override_discriminator;
     }
   else if (INSN_HAS_LOCATION (insn))
     {
@@ -3154,12 +3044,14 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
       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)
@@ -3320,167 +3212,6 @@ walk_alter_subreg (rtx *xp, bool *changed)
   return *xp;
 }
 \f
-#if HAVE_cc0
-
-/* Given BODY, the body of a jump instruction, alter the jump condition
-   as required by the bits that are set in cc_status.flags.
-   Not all of the bits there can be handled at this level in all cases.
-
-   The value is normally 0.
-   1 means that the condition has become always true.
-   -1 means that the condition has become always false.
-   2 means that COND has been altered.  */
-
-static int
-alter_cond (rtx cond)
-{
-  int value = 0;
-
-  if (cc_status.flags & CC_REVERSED)
-    {
-      value = 2;
-      PUT_CODE (cond, swap_condition (GET_CODE (cond)));
-    }
-
-  if (cc_status.flags & CC_INVERTED)
-    {
-      value = 2;
-      PUT_CODE (cond, reverse_condition (GET_CODE (cond)));
-    }
-
-  if (cc_status.flags & CC_NOT_POSITIVE)
-    switch (GET_CODE (cond))
-      {
-      case LE:
-      case LEU:
-      case GEU:
-       /* Jump becomes unconditional.  */
-       return 1;
-
-      case GT:
-      case GTU:
-      case LTU:
-       /* Jump becomes no-op.  */
-       return -1;
-
-      case GE:
-       PUT_CODE (cond, EQ);
-       value = 2;
-       break;
-
-      case LT:
-       PUT_CODE (cond, NE);
-       value = 2;
-       break;
-
-      default:
-       break;
-      }
-
-  if (cc_status.flags & CC_NOT_NEGATIVE)
-    switch (GET_CODE (cond))
-      {
-      case GE:
-      case GEU:
-       /* Jump becomes unconditional.  */
-       return 1;
-
-      case LT:
-      case LTU:
-       /* Jump becomes no-op.  */
-       return -1;
-
-      case LE:
-      case LEU:
-       PUT_CODE (cond, EQ);
-       value = 2;
-       break;
-
-      case GT:
-      case GTU:
-       PUT_CODE (cond, NE);
-       value = 2;
-       break;
-
-      default:
-       break;
-      }
-
-  if (cc_status.flags & CC_NO_OVERFLOW)
-    switch (GET_CODE (cond))
-      {
-      case GEU:
-       /* Jump becomes unconditional.  */
-       return 1;
-
-      case LEU:
-       PUT_CODE (cond, EQ);
-       value = 2;
-       break;
-
-      case GTU:
-       PUT_CODE (cond, NE);
-       value = 2;
-       break;
-
-      case LTU:
-       /* Jump becomes no-op.  */
-       return -1;
-
-      default:
-       break;
-      }
-
-  if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N))
-    switch (GET_CODE (cond))
-      {
-      default:
-       gcc_unreachable ();
-
-      case NE:
-       PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT);
-       value = 2;
-       break;
-
-      case EQ:
-       PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE);
-       value = 2;
-       break;
-      }
-
-  if (cc_status.flags & CC_NOT_SIGNED)
-    /* The flags are valid if signed condition operators are converted
-       to unsigned.  */
-    switch (GET_CODE (cond))
-      {
-      case LE:
-       PUT_CODE (cond, LEU);
-       value = 2;
-       break;
-
-      case LT:
-       PUT_CODE (cond, LTU);
-       value = 2;
-       break;
-
-      case GT:
-       PUT_CODE (cond, GTU);
-       value = 2;
-       break;
-
-      case GE:
-       PUT_CODE (cond, GEU);
-       value = 2;
-       break;
-
-      default:
-       break;
-      }
-
-  return value;
-}
-#endif
-\f
 /* Report inconsistency between the assembler template and the operands.
    In an `asm', it's the user's fault; otherwise, the compiler's fault.  */
 
@@ -4375,7 +4106,8 @@ leaf_function_p (void)
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     {
       if (CALL_P (insn)
-         && ! SIBLING_CALL_P (insn))
+         && ! SIBLING_CALL_P (insn)
+         && ! FAKE_CALL_P (insn))
        return 0;
       if (NONJUMP_INSN_P (insn)
          && GET_CODE (PATTERN (insn)) == SEQUENCE
@@ -4544,20 +4276,26 @@ rest_of_handle_final (void)
   /* Turn debug markers into notes if the var-tracking pass has not
      been invoked.  */
   if (!flag_var_tracking && MAY_HAVE_DEBUG_MARKER_INSNS)
-    variable_tracking_main ();
+    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);
+  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)))
+      && !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);
 
@@ -4730,14 +4468,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_BEGIN_STMT
-              && 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);
     }
 
@@ -4777,7 +4530,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)
@@ -4866,7 +4620,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))
     {
@@ -4877,97 +4640,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);
-    }
-
-  /* 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.  */
+      function_used_regs |= insn_used_regs;
 
-  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;
 }