Fix fortran/85982 ICE in resolve_component.
[gcc.git] / gcc / final.c
index db3095c5526248cd7c35519a2e36c48e4fb87924..a3601964a8d31f2436e7c8e3d378345c8cf8dd60 100644 (file)
@@ -1,5 +1,5 @@
 /* Convert RTL to assembler code and output it, for GNU compiler.
 /* Convert RTL to assembler code and output it, for GNU compiler.
-   Copyright (C) 1987-2018 Free Software Foundation, Inc.
+   Copyright (C) 1987-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 
 This file is part of GCC.
 
@@ -75,12 +75,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pass.h"
 #include "tree-ssa.h"
 #include "cfgloop.h"
 #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 "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.  */
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data declarations.  */
@@ -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
 /* 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;
 
 /* Last insn processed by final_scan_insn.  */
 static rtx_insn *debug_insn;
@@ -121,11 +122,20 @@ static int last_linenum;
 /* Column number of last NOTE.  */
 static int last_columnnum;
 
 /* Column number of last NOTE.  */
 static int last_columnnum;
 
-/* Last discriminator written to assembly.  */
+/* Discriminator written to assembly.  */
 static int last_discriminator;
 
 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 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;
 
 /* Highest line number in current block.  */
 static int high_block_linenum;
@@ -140,6 +150,7 @@ static const char *last_filename;
 static const char *override_filename;
 static int override_linenum;
 static int override_columnnum;
 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;
 
 /* Whether to force emission of a line note before the next insn.  */
 static bool force_source_line = false;
@@ -196,7 +207,7 @@ static int dialect_number;
 /* Nonnull if the insn currently being emitted was a COND_EXEC pattern.  */
 rtx current_insn_predicate;
 
 /* 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.  */
 bool final_insns_dump_p;
 
 /* True if profile_function should be called, but hasn't been called yet.  */
@@ -219,7 +230,6 @@ static int alter_cond (rtx);
 #endif
 static int align_fuzz (rtx, rtx, int, unsigned);
 static void collect_fn_hard_reg_usage (void);
 #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.  */
 
 \f
 /* Initialize data in final at the beginning of a compilation.  */
 
@@ -326,15 +336,9 @@ int insn_current_align;
    for each insn we'll call the alignment chain of this insn in the following
    comments.  */
 
    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 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.  */
 
 
 /* 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
    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
 #endif
 
 #ifndef LOOP_ALIGN
-#define LOOP_ALIGN(LABEL) align_loops_log
+#define LOOP_ALIGN(LABEL) align_loops
 #endif
 
 #ifndef LABEL_ALIGN_AFTER_BARRIER
 #endif
 
 #ifndef LABEL_ALIGN_AFTER_BARRIER
@@ -484,33 +488,9 @@ get_attr_min_length (rtx_insn *insn)
 #endif
 
 #ifndef JUMP_ALIGN
 #endif
 
 #ifndef JUMP_ALIGN
-#define JUMP_ALIGN(LABEL) align_jumps_log
+#define JUMP_ALIGN(LABEL) align_jumps
 #endif
 
 #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)
 #ifndef ADDR_VEC_ALIGN
 static int
 final_addr_vec_align (rtx_jump_table_data *addr_vec)
@@ -535,27 +515,16 @@ final_addr_vec_align (rtx_jump_table_data *addr_vec)
 static int min_labelno, max_labelno;
 
 #define LABEL_TO_ALIGNMENT(LABEL) \
 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.  */
 
 
 /* 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);
 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
 }
 
 /* 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;
       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);
       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);
 
   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.
     /* 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 +635,14 @@ insn_current_reference_address (rtx_insn *branch)
 unsigned int
 compute_alignments (void)
 {
 unsigned int
 compute_alignments (void)
 {
-  int log, max_skip, max_log;
   basic_block bb;
   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 ();
 
   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))
 
   /* If not optimizing or optimizing for size, don't assign any alignments.  */
   if (! optimize || optimize_function_for_size_p (cfun))
@@ -691,7 +656,7 @@ compute_alignments (void)
     }
   loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
   profile_count count_threshold = cfun->cfg->count_max.apply_scale
     }
   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)
     {
 
   if (dump_file)
     {
@@ -717,8 +682,7 @@ compute_alignments (void)
                     bb_loop_depth (bb));
          continue;
        }
                     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 ();
 
       profile_count fallthru_count = profile_count::zero ();
       profile_count branch_count = profile_count::zero ();
 
@@ -760,18 +724,14 @@ compute_alignments (void)
       if (!has_fallthru
          && (branch_count > count_threshold
              || (bb->count > bb->prev_bb->count.apply_scale (10, 1)
       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)))))
        {
                      <= 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 (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.  */
        }
       /* 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 +742,14 @@ compute_alignments (void)
          && branch_count + fallthru_count > count_threshold
          && (branch_count
              > fallthru_count.apply_scale
          && 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 (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 ();
     }
 
   loop_optimizer_finalize ();
@@ -804,7 +759,7 @@ compute_alignments (void)
 
 /* Grow the LABEL_ALIGN array after new labels are created.  */
 
 
 /* Grow the LABEL_ALIGN array after new labels are created.  */
 
-static void 
+static void
 grow_label_align (void)
 {
   int old = max_labelno;
 grow_label_align (void)
 {
   int old = max_labelno;
@@ -816,14 +771,11 @@ grow_label_align (void)
   n_labels = max_labelno - min_labelno + 1;
   n_old_labels = old - min_labelno + 1;
 
   n_labels = max_labelno - min_labelno + 1;
   n_old_labels = old - min_labelno + 1;
 
-  label_align = 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);
 
   /* 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
 }
 
 /* Update the already computed alignment information.  LABEL_PAIRS is a vector
@@ -841,10 +793,7 @@ update_alignments (vec<rtx> &label_pairs)
 
   FOR_EACH_VEC_ELT (label_pairs, i, iter)
     if (i & 1)
 
   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;
 }
     else
       label = iter;
 }
@@ -902,15 +851,12 @@ shorten_branches (rtx_insn *first)
   rtx_insn *insn;
   int max_uid;
   int i;
   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_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 ();
 
   /* Compute maximum UID and allocate label_align / uid_shuid.  */
   max_uid = get_max_uid ();
@@ -925,17 +871,14 @@ shorten_branches (rtx_insn *first)
 
   /* Initialize label_align and set up uid_shuid to be strictly
      monotonically rising with insn order.  */
 
   /* 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).  */
 
      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))
     {
 
   for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn))
     {
-      int log;
-
       INSN_SHUID (insn) = i++;
       if (INSN_P (insn))
        continue;
       INSN_SHUID (insn) = i++;
       if (INSN_P (insn))
        continue;
@@ -943,22 +886,14 @@ shorten_branches (rtx_insn *first)
       if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
        {
          /* Merge in alignments computed by compute_alignments.  */
       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)
            {
 
          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.  */
            }
          /* ADDR_VECs only take room if read-only data goes into the text
             section.  */
@@ -966,17 +901,11 @@ shorten_branches (rtx_insn *first)
               || readonly_data_section == text_section)
              && table)
            {
               || 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))
        {
        }
       else if (BARRIER_P (insn))
        {
@@ -986,12 +915,9 @@ shorten_branches (rtx_insn *first)
               label = NEXT_INSN (label))
            if (LABEL_P (label))
              {
               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;
              }
        }
                break;
              }
        }
@@ -1015,18 +941,19 @@ shorten_branches (rtx_insn *first)
      alignment of n.  */
   uid_align = XCNEWVEC (rtx, max_uid);
 
      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;
     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.  */
       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;
          uid_align[uid] = align_tab[log];
          for (i = log - 1; i >= 0; i--)
            align_tab[i] = seq;
@@ -1077,8 +1004,10 @@ shorten_branches (rtx_insn *first)
                  max = shuid;
                  max_lab = lab;
                }
                  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);
            }
          XEXP (pat, 2) = gen_rtx_LABEL_REF (Pmode, min_lab);
          XEXP (pat, 3) = gen_rtx_LABEL_REF (Pmode, max_lab);
@@ -1112,7 +1041,7 @@ shorten_branches (rtx_insn *first)
 
       if (LABEL_P (insn))
        {
 
       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;
          if (log)
            {
              int align = 1 << log;
@@ -1220,7 +1149,7 @@ shorten_branches (rtx_insn *first)
 
          if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
            {
 
          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
 
 #ifdef CASE_VECTOR_SHORTEN_MODE
              /* If the mode of a following jump table was changed, we
@@ -1295,7 +1224,7 @@ shorten_branches (rtx_insn *first)
                   prev = PREV_INSN (prev))
                if (varying_length[INSN_UID (prev)] & 2)
                  {
                   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;
                  }
 
                    break;
                  }
 
@@ -1507,72 +1436,6 @@ asm_str_count (const char *templ)
   return count;
 }
 \f
   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
 /* Return true if DWARF2 debug info can be emitted for DECL.  */
 
 static bool
@@ -1676,6 +1539,7 @@ reemit_insn_block_notes (void)
            break;
 
          case NOTE_INSN_BEGIN_STMT:
            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;
 
            this_block = LOCATION_BLOCK (NOTE_MARKER_LOCATION (insn));
            goto set_cur_block_to_this_block;
 
@@ -1758,6 +1622,67 @@ get_some_local_dynamic_name ()
   return 0;
 }
 
   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
 /* 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 +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.
 
    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.  */
 
    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;
 
 {
   block_depth = 0;
 
@@ -1782,14 +1710,28 @@ 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_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 ();
 
 
   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))
   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 (!dwarf2_debug_info_emitted_p (current_function_decl))
     dwarf2out_begin_prologue (0, 0, NULL);
@@ -1846,14 +1788,14 @@ final_start_function (rtx_insn *first, FILE *file,
       TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
     }
 
       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_,
     {
       /* 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.  */
     }
 
   /* First output the function prologue: code to set up the stack frame.  */
@@ -1865,6 +1807,17 @@ final_start_function (rtx_insn *first, FILE *file,
     profile_after_prologue (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)
 {
 static void
 profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
 {
@@ -1994,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.  */
 
 /* 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;
 {
   rtx_insn *insn, *next;
-  int seen = 0;
 
   /* Used for -dA dump.  */
   basic_block *start_to_bb = NULL;
 
   /* Used for -dA dump.  */
   basic_block *start_to_bb = NULL;
@@ -2058,6 +2010,9 @@ final (rtx_insn *first, FILE *file, int optimize_p)
            }
          else
            insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
            }
          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,
        }
 
       dump_basic_block_info (file, insn, start_to_bb, end_to_bb,
@@ -2065,6 +2020,8 @@ final (rtx_insn *first, FILE *file, int optimize_p)
       insn = final_scan_insn (insn, file, optimize_p, 0, &seen);
     }
 
       insn = final_scan_insn (insn, file, optimize_p, 0, &seen);
     }
 
+  maybe_output_next_view (&seen);
+
   if (flag_debug_asm)
     {
       free (start_to_bb);
   if (flag_debug_asm)
     {
       free (start_to_bb);
@@ -2081,9 +2038,26 @@ final (rtx_insn *first, FILE *file, int optimize_p)
        delete_insn (insn);
     }
 }
        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 *
 \f
 const char *
-get_insn_template (int code, rtx insn)
+get_insn_template (int code, rtx_insn *insn)
 {
   switch (insn_data[code].output_format)
     {
 {
   switch (insn_data[code].output_format)
     {
@@ -2093,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.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 ();
 
     default:
       gcc_unreachable ();
@@ -2171,14 +2144,13 @@ asm_show_source (const char *filename, int linenum)
   if (!filename)
     return;
 
   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);
   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);
 }
 
   fputc ('\n', asm_out_file);
 }
 
@@ -2194,9 +2166,9 @@ 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.  */
 
    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;
 {
 #if HAVE_cc0
   rtx set;
@@ -2221,6 +2193,13 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
          break;
 
        case NOTE_INSN_SWITCH_TEXT_SECTIONS:
          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)
          in_cold_section_p = !in_cold_section_p;
 
          if (in_cold_section_p)
@@ -2254,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
              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;
 
            }
          break;
 
@@ -2267,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);
 
          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:
          break;
 
        case NOTE_INSN_EH_REGION_BEG:
@@ -2362,11 +2343,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_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:
                }
            }
          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
          if (debug_info_level == DINFO_LEVEL_NORMAL
              || debug_info_level == DINFO_LEVEL_VERBOSE
              || write_symbols == DWARF2_DEBUG
@@ -2397,12 +2381,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_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;
                }
              else
                {
                  override_filename = NULL;
                  override_linenum = 0;
                  override_columnnum = 0;
+                 override_discriminator = 0;
                }
            }
          break;
                }
            }
          break;
@@ -2421,9 +2407,11 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
          break;
 
        case NOTE_INSN_VAR_LOCATION:
          break;
 
        case NOTE_INSN_VAR_LOCATION:
-       case NOTE_INSN_CALL_ARG_LOCATION:
          if (!DECL_IGNORED_P (current_function_decl))
          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:
          break;
 
        case NOTE_INSN_BEGIN_STMT:
@@ -2431,9 +2419,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))
            {
          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);
              (*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;
 
            }
          break;
 
@@ -2451,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)
        {
         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
            {
 #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
 #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
 #else
-             ASM_OUTPUT_ALIGN (file, align);
+             ASM_OUTPUT_ALIGN (file, alignment.levels[0].log);
 #endif
 #endif
            }
 #endif
 #endif
            }
@@ -2629,6 +2630,10 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
 
            switch_to_section (current_function_section ());
 
 
            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
            break;
          }
        /* Output this line note if it is the first or the last line
@@ -2641,7 +2646,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);
            (*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)
 
        if (GET_CODE (body) == PARALLEL
            && GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
@@ -3108,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.  */
        /* 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;
          debug_hooks->var_location (insn);
 
        current_output_insn = debug_insn = 0;
@@ -3116,7 +3127,97 @@ final_scan_insn (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
     }
   return NEXT_INSN (insn);
 }
     }
   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
 \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.  */
 /* 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.  */
@@ -3140,6 +3241,7 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
       filename = xloc.file;
       linenum = xloc.line;
       columnnum = xloc.column;
       filename = xloc.file;
       linenum = xloc.line;
       columnnum = xloc.column;
+      discriminator = compute_discriminator (loc);
       force_source_line = true;
     }
   else if (override_filename)
       force_source_line = true;
     }
   else if (override_filename)
@@ -3147,6 +3249,7 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
       filename = override_filename;
       linenum = override_linenum;
       columnnum = override_columnnum;
       filename = override_filename;
       linenum = override_linenum;
       columnnum = override_columnnum;
+      discriminator = override_discriminator;
     }
   else if (INSN_HAS_LOCATION (insn))
     {
     }
   else if (INSN_HAS_LOCATION (insn))
     {
@@ -3154,12 +3257,14 @@ notice_source_line (rtx_insn *insn, bool *is_stmt)
       filename = xloc.file;
       linenum = xloc.line;
       columnnum = xloc.column;
       filename = xloc.file;
       linenum = xloc.line;
       columnnum = xloc.column;
+      discriminator = compute_discriminator (INSN_LOCATION (insn));
     }
   else
     {
       filename = NULL;
       linenum = 0;
       columnnum = 0;
     }
   else
     {
       filename = NULL;
       linenum = 0;
       columnnum = 0;
+      discriminator = 0;
     }
 
   if (filename == NULL)
     }
 
   if (filename == NULL)
@@ -4547,17 +4652,23 @@ rest_of_handle_final (void)
     delete_vta_debug_insns (false);
 
   assemble_start_function (current_function_decl, fnname);
     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
   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.  */
     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);
 
 
   assemble_end_function (current_function_decl, fnname);
 
@@ -4730,14 +4841,29 @@ rest_of_clean_state (void)
       SET_NEXT_INSN (insn) = NULL;
       SET_PREV_INSN (insn) = NULL;
 
       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
       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);
     }
 
        print_rtl_single (final_output, insn);
     }
 
@@ -4777,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.  */
   /* 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)
     {
       unsigned int pref = crtl->preferred_stack_boundary;
       if (crtl->stack_alignment_needed > crtl->preferred_stack_boundary)
@@ -4866,7 +4993,16 @@ collect_fn_hard_reg_usage (void)
   if (!targetm.call_fusage_contains_non_callee_clobbers)
     return;
 
   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))
     {
 
   for (insn = get_insns (); insn != NULL_RTX; insn = next_insn (insn))
     {
@@ -4877,97 +5013,23 @@ collect_fn_hard_reg_usage (void)
 
       if (CALL_P (insn)
          && !self_recursive_call_p (insn))
 
       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);
 
       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);
 
 
   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;
 }
 }