]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/var-tracking.c
Update copyright years.
[thirdparty/gcc.git] / gcc / var-tracking.c
index 16327bd43f331420dcc3e14d71feffe8f0b0c48f..ce1d92027c452d503c33108db2e90b69403ad7f9 100644 (file)
@@ -1,5 +1,5 @@
 /* Variable tracking routines for the GNU compiler.
-   Copyright (C) 2002-2017 Free Software Foundation, Inc.
+   Copyright (C) 2002-2022 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
 #include "tree-dfa.h"
 #include "tree-ssa.h"
 #include "cselib.h"
-#include "params.h"
 #include "tree-pretty-print.h"
 #include "rtl-iter.h"
 #include "fibonacci_heap.h"
+#include "print-rtl.h"
+#include "function-abi.h"
 
 typedef fibonacci_heap <long, basic_block_def> bb_heap_t;
-typedef fibonacci_node <long, basic_block_def> bb_heap_node_t;
 
 /* var-tracking.c assumes that tree code with the same value as VALUE rtx code
    has no chance to appear in REG_EXPR/MEM_EXPRs and isn't a decl.
@@ -304,6 +304,9 @@ struct expand_depth
   int entryvals;
 };
 
+/* Type for dependencies actively used when expand FROM into cur_loc.  */
+typedef vec<loc_exp_dep, va_heap, vl_embed> deps_vec;
+
 /* This data structure is allocated for one-part variables at the time
    of emitting notes.  */
 struct onepart_aux
@@ -324,7 +327,7 @@ struct onepart_aux
   /* The depth of the cur_loc expression.  */
   expand_depth depth;
   /* Dependencies actively used when expand FROM into cur_loc.  */
-  vec<loc_exp_dep, va_heap, vl_embed> deps;
+  deps_vec deps;
 };
 
 /* Structure describing one part of variable.  */
@@ -395,8 +398,9 @@ struct variable
 static inline HOST_WIDE_INT
 int_mem_offset (const_rtx mem)
 {
-  if (MEM_OFFSET_KNOWN_P (mem))
-    return MEM_OFFSET (mem);
+  HOST_WIDE_INT offset;
+  if (MEM_OFFSET_KNOWN_P (mem) && MEM_OFFSET (mem).is_constant (&offset))
+    return offset;
   return 0;
 }
 
@@ -432,10 +436,16 @@ int_mem_offset (const_rtx mem)
                               : NULL)
 #define VAR_LOC_FROM(var) (VAR_LOC_1PAUX (var)->from)
 #define VAR_LOC_DEPTH(var) (VAR_LOC_1PAUX (var)->depth)
-#define VAR_LOC_DEP_VEC(var) (VAR_LOC_1PAUX (var)                \
-                             ? &VAR_LOC_1PAUX (var)->deps        \
-                             : NULL)
+#define VAR_LOC_DEP_VEC(var) var_loc_dep_vec (var)
 
+/* Implements the VAR_LOC_DEP_VEC above as a function to work around
+   a bogus -Wnonnull (PR c/95554). */
+
+static inline deps_vec*
+var_loc_dep_vec (variable *var)
+{
+  return VAR_LOC_1PAUX (var) ? &VAR_LOC_1PAUX (var)->deps : NULL;
+}
 
 
 typedef unsigned int dvuid;
@@ -673,7 +683,6 @@ static bool dataflow_set_different (dataflow_set *, dataflow_set *);
 static void dataflow_set_destroy (dataflow_set *);
 
 static bool track_expr_p (tree, bool);
-static bool same_variable_part_p (rtx, tree, HOST_WIDE_INT);
 static void add_uses_1 (rtx *, void *);
 static void add_stores (rtx, const_rtx, void *);
 static bool compute_bb_dataflow (basic_block);
@@ -704,7 +713,6 @@ static void delete_variable_part (dataflow_set *, rtx,
 static void emit_notes_in_bb (basic_block, dataflow_set *);
 static void vt_emit_notes (void);
 
-static bool vt_get_decl_and_offset (rtx, tree *, HOST_WIDE_INT *);
 static void vt_add_function_parameters (void);
 static bool vt_initialize (void);
 static void vt_finalize (void);
@@ -918,19 +926,20 @@ static HOST_WIDE_INT cfa_base_offset;
    or hard_frame_pointer_rtx.  */
 
 static inline rtx
-compute_cfa_pointer (HOST_WIDE_INT adjustment)
+compute_cfa_pointer (poly_int64 adjustment)
 {
   return plus_constant (Pmode, cfa_base_rtx, adjustment + cfa_base_offset);
 }
 
 /* Adjustment for hard_frame_pointer_rtx to cfa base reg,
    or -1 if the replacement shouldn't be done.  */
-static HOST_WIDE_INT hard_frame_pointer_adjustment = -1;
+static poly_int64 hard_frame_pointer_adjustment = -1;
 
 /* Data for adjust_mems callback.  */
 
-struct adjust_mem_data
+class adjust_mem_data
 {
+public:
   bool store;
   machine_mode mem_mode;
   HOST_WIDE_INT stack_adjust;
@@ -965,6 +974,24 @@ use_narrower_mode_test (rtx x, const_rtx subreg)
          case MULT:
            break;
          case ASHIFT:
+           if (GET_MODE (XEXP (x, 1)) != VOIDmode)
+             {
+               enum machine_mode mode = GET_MODE (subreg);
+               rtx op1 = XEXP (x, 1);
+               enum machine_mode op1_mode = GET_MODE (op1);
+               if (GET_MODE_PRECISION (as_a <scalar_int_mode> (mode))
+                   < GET_MODE_PRECISION (as_a <scalar_int_mode> (op1_mode)))
+                 {
+                   poly_uint64 byte = subreg_lowpart_offset (mode, op1_mode);
+                   if (GET_CODE (op1) == SUBREG || GET_CODE (op1) == CONCAT)
+                     {
+                       if (!simplify_subreg (mode, op1, op1_mode, byte))
+                         return false;
+                     }
+                   else if (!validate_subreg (mode, op1_mode, op1, byte))
+                     return false;
+                 }
+             }
            iter.substitute (XEXP (x, 0));
            break;
          default:
@@ -1012,11 +1039,12 @@ use_narrower_mode (rtx x, scalar_int_mode mode, scalar_int_mode wmode)
 static rtx
 adjust_mems (rtx loc, const_rtx old_rtx, void *data)
 {
-  struct adjust_mem_data *amd = (struct adjust_mem_data *) data;
+  class adjust_mem_data *amd = (class adjust_mem_data *) data;
   rtx mem, addr = loc, tem;
   machine_mode mem_mode_save;
   bool store_save;
   scalar_int_mode tem_mode, tem_subreg_mode;
+  poly_int64 size;
   switch (GET_CODE (loc))
     {
     case REG:
@@ -1030,7 +1058,7 @@ adjust_mems (rtx loc, const_rtx old_rtx, void *data)
        return compute_cfa_pointer (amd->stack_adjust);
       else if (loc == hard_frame_pointer_rtx
               && frame_pointer_needed
-              && hard_frame_pointer_adjustment != -1
+              && maybe_ne (hard_frame_pointer_adjustment, -1)
               && cfa_base_rtx)
        return compute_cfa_pointer (hard_frame_pointer_adjustment);
       gcc_checking_assert (loc != virtual_incoming_args_rtx);
@@ -1061,11 +1089,9 @@ adjust_mems (rtx loc, const_rtx old_rtx, void *data)
       return mem;
     case PRE_INC:
     case PRE_DEC:
-      addr = gen_rtx_PLUS (GET_MODE (loc), XEXP (loc, 0),
-                          gen_int_mode (GET_CODE (loc) == PRE_INC
-                                        ? GET_MODE_SIZE (amd->mem_mode)
-                                        : -GET_MODE_SIZE (amd->mem_mode),
-                                        GET_MODE (loc)));
+      size = GET_MODE_SIZE (amd->mem_mode);
+      addr = plus_constant (GET_MODE (loc), XEXP (loc, 0),
+                           GET_CODE (loc) == PRE_INC ? size : -size);
       /* FALLTHRU */
     case POST_INC:
     case POST_DEC:
@@ -1073,12 +1099,10 @@ adjust_mems (rtx loc, const_rtx old_rtx, void *data)
        addr = XEXP (loc, 0);
       gcc_assert (amd->mem_mode != VOIDmode && amd->mem_mode != BLKmode);
       addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
-      tem = gen_rtx_PLUS (GET_MODE (loc), XEXP (loc, 0),
-                         gen_int_mode ((GET_CODE (loc) == PRE_INC
-                                        || GET_CODE (loc) == POST_INC)
-                                       ? GET_MODE_SIZE (amd->mem_mode)
-                                       : -GET_MODE_SIZE (amd->mem_mode),
-                                       GET_MODE (loc)));
+      size = GET_MODE_SIZE (amd->mem_mode);
+      tem = plus_constant (GET_MODE (loc), XEXP (loc, 0),
+                          (GET_CODE (loc) == PRE_INC
+                           || GET_CODE (loc) == POST_INC) ? size : -size);
       store_save = amd->store;
       amd->store = false;
       tem = simplify_replace_fn_rtx (tem, old_rtx, adjust_mems, data);
@@ -1125,7 +1149,7 @@ adjust_mems (rtx loc, const_rtx old_rtx, void *data)
       if (tem == NULL_RTX)
        tem = gen_rtx_raw_SUBREG (GET_MODE (loc), addr, SUBREG_BYTE (loc));
     finish_subreg:
-      if (MAY_HAVE_DEBUG_INSNS
+      if (MAY_HAVE_DEBUG_BIND_INSNS
          && GET_CODE (tem) == SUBREG
          && (GET_CODE (SUBREG_REG (tem)) == PLUS
              || GET_CODE (SUBREG_REG (tem)) == MINUS
@@ -1223,7 +1247,7 @@ adjust_insn (basic_block bb, rtx_insn *insn)
   amd.stack_adjust = -VTI (bb)->out.stack_adjust;
 
   amd.store = true;
-  note_stores (PATTERN (insn), adjust_mem_stores, &amd);
+  note_stores (insn, adjust_mem_stores, &amd);
 
   amd.store = false;
   if (GET_CODE (PATTERN (insn)) == PARALLEL
@@ -1337,7 +1361,7 @@ dv_onepart_p (decl_or_value dv)
 {
   tree decl;
 
-  if (!MAY_HAVE_DEBUG_INSNS)
+  if (!MAY_HAVE_DEBUG_BIND_INSNS)
     return NOT_ONEPART;
 
   if (dv_is_value_p (dv))
@@ -1850,6 +1874,32 @@ var_reg_decl_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
   set_variable_part (set, loc, dv, offset, initialized, set_src, iopt);
 }
 
+/* Return true if we should track a location that is OFFSET bytes from
+   a variable.  Store the constant offset in *OFFSET_OUT if so.  */
+
+static bool
+track_offset_p (poly_int64 offset, HOST_WIDE_INT *offset_out)
+{
+  HOST_WIDE_INT const_offset;
+  if (!offset.is_constant (&const_offset)
+      || !IN_RANGE (const_offset, 0, MAX_VAR_PARTS - 1))
+    return false;
+  *offset_out = const_offset;
+  return true;
+}
+
+/* Return the offset of a register that track_offset_p says we
+   should track.  */
+
+static HOST_WIDE_INT
+get_tracked_reg_offset (rtx loc)
+{
+  HOST_WIDE_INT offset;
+  if (!track_offset_p (REG_OFFSET (loc), &offset))
+    gcc_unreachable ();
+  return offset;
+}
+
 /* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  */
 
 static void
@@ -1857,7 +1907,7 @@ var_reg_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
             rtx set_src)
 {
   tree decl = REG_EXPR (loc);
-  HOST_WIDE_INT offset = REG_OFFSET (loc);
+  HOST_WIDE_INT offset = get_tracked_reg_offset (loc);
 
   var_reg_decl_set (set, loc, initialized,
                    dv_from_decl (decl), offset, set_src, INSERT);
@@ -1903,7 +1953,7 @@ var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify,
                        enum var_init_status initialized, rtx set_src)
 {
   tree decl = REG_EXPR (loc);
-  HOST_WIDE_INT offset = REG_OFFSET (loc);
+  HOST_WIDE_INT offset = get_tracked_reg_offset (loc);
   attrs *node, *next;
   attrs **nextp;
 
@@ -1944,10 +1994,10 @@ var_reg_delete (dataflow_set *set, rtx loc, bool clobber)
   attrs **nextp = &set->regs[REGNO (loc)];
   attrs *node, *next;
 
-  if (clobber)
+  HOST_WIDE_INT offset;
+  if (clobber && track_offset_p (REG_OFFSET (loc), &offset))
     {
       tree decl = REG_EXPR (loc);
-      HOST_WIDE_INT offset = REG_OFFSET (loc);
 
       decl = var_debug_decl (decl);
 
@@ -2134,7 +2184,7 @@ get_addr_from_local_cache (dataflow_set *set, rtx const loc)
 static rtx
 vt_canonicalize_addr (dataflow_set *set, rtx oloc)
 {
-  HOST_WIDE_INT ofst = 0;
+  poly_int64 ofst = 0, term;
   machine_mode mode = GET_MODE (oloc);
   rtx loc = oloc;
   rtx x;
@@ -2143,9 +2193,9 @@ vt_canonicalize_addr (dataflow_set *set, rtx oloc)
   while (retry)
     {
       while (GET_CODE (loc) == PLUS
-            && GET_CODE (XEXP (loc, 1)) == CONST_INT)
+            && poly_int_rtx_p (XEXP (loc, 1), &term))
        {
-         ofst += INTVAL (XEXP (loc, 1));
+         ofst += term;
          loc = XEXP (loc, 0);
        }
 
@@ -2170,10 +2220,11 @@ vt_canonicalize_addr (dataflow_set *set, rtx oloc)
            loc = get_addr_from_global_cache (loc);
 
          /* Consolidate plus_constants.  */
-         while (ofst && GET_CODE (loc) == PLUS
-                && GET_CODE (XEXP (loc, 1)) == CONST_INT)
+         while (maybe_ne (ofst, 0)
+                && GET_CODE (loc) == PLUS
+                && poly_int_rtx_p (XEXP (loc, 1), &term))
            {
-             ofst += INTVAL (XEXP (loc, 1));
+             ofst += term;
              loc = XEXP (loc, 0);
            }
 
@@ -2189,12 +2240,10 @@ vt_canonicalize_addr (dataflow_set *set, rtx oloc)
     }
 
   /* Add OFST back in.  */
-  if (ofst)
+  if (maybe_ne (ofst, 0))
     {
       /* Don't build new RTL if we can help it.  */
-      if (GET_CODE (oloc) == PLUS
-         && XEXP (oloc, 0) == loc
-         && INTVAL (XEXP (oloc, 1)) == ofst)
+      if (strip_offset (oloc, &term) == loc && known_eq (term, ofst))
        return oloc;
 
       loc = plus_constant (mode, loc, ofst);
@@ -2401,7 +2450,6 @@ unsuitable_loc (rtx loc)
     {
     case PC:
     case SCRATCH:
-    case CC0:
     case ASM_INPUT:
     case ASM_OPERANDS:
       return true;
@@ -3497,6 +3545,12 @@ loc_cmp (rtx x, rtx y)
        else
          return 1;
 
+      case 'p':
+       r = compare_sizes_for_sort (SUBREG_BYTE (x), SUBREG_BYTE (y));
+       if (r != 0)
+         return r;
+       break;
+
       case 'V':
       case 'E':
        /* Compare the vector length first.  */
@@ -4853,15 +4907,14 @@ dataflow_set_clear_at_call (dataflow_set *set, rtx_insn *call_insn)
 {
   unsigned int r;
   hard_reg_set_iterator hrsi;
-  HARD_REG_SET invalidated_regs;
 
-  get_call_reg_set_usage (call_insn, &invalidated_regs,
-                         regs_invalidated_by_call);
+  HARD_REG_SET callee_clobbers
+    = insn_callee_abi (call_insn).full_reg_clobbers ();
 
-  EXECUTE_IF_SET_IN_HARD_REG_SET (invalidated_regs, 0, r, hrsi)
+  EXECUTE_IF_SET_IN_HARD_REG_SET (callee_clobbers, 0, r, hrsi)
     var_regno_delete (set, r);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       set->traversed_vars = set->vars;
       shared_hash_htab (set->vars)
@@ -5177,20 +5230,20 @@ track_expr_p (tree expr, bool need_rtl)
              || (TREE_CODE (realdecl) == MEM_REF
                  && TREE_CODE (TREE_OPERAND (realdecl, 0)) == ADDR_EXPR))
            {
-             HOST_WIDE_INT bitsize, bitpos, maxsize;
+             HOST_WIDE_INT bitsize, bitpos;
              bool reverse;
              tree innerdecl
-               = get_ref_base_and_extent (realdecl, &bitpos, &bitsize,
-                                          &maxsize, &reverse);
-             if (!DECL_P (innerdecl)
+               = get_ref_base_and_extent_hwi (realdecl, &bitpos,
+                                              &bitsize, &reverse);
+             if (!innerdecl
+                 || !DECL_P (innerdecl)
                  || DECL_IGNORED_P (innerdecl)
                  /* Do not track declarations for parts of tracked record
                     parameters since we want to track them as a whole.  */
                  || tracked_record_parameter_p (innerdecl)
                  || TREE_STATIC (innerdecl)
-                 || bitsize <= 0
-                 || bitpos + bitsize > 256
-                 || bitsize != maxsize)
+                 || bitsize == 0
+                 || bitpos + bitsize > 256)
                return 0;
              else
                realdecl = expr;
@@ -5232,7 +5285,7 @@ track_expr_p (tree expr, bool need_rtl)
          && !tracked_record_parameter_p (realdecl))
        return 0;
       if (MEM_SIZE_KNOWN_P (decl_rtl)
-         && MEM_SIZE (decl_rtl) > MAX_VAR_PARTS)
+         && maybe_gt (MEM_SIZE (decl_rtl), MAX_VAR_PARTS))
        return 0;
     }
 
@@ -5245,10 +5298,10 @@ track_expr_p (tree expr, bool need_rtl)
    EXPR+OFFSET.  */
 
 static bool
-same_variable_part_p (rtx loc, tree expr, HOST_WIDE_INT offset)
+same_variable_part_p (rtx loc, tree expr, poly_int64 offset)
 {
   tree expr2;
-  HOST_WIDE_INT offset2;
+  poly_int64 offset2;
 
   if (! DECL_P (expr))
     return false;
@@ -5272,7 +5325,7 @@ same_variable_part_p (rtx loc, tree expr, HOST_WIDE_INT offset)
   expr = var_debug_decl (expr);
   expr2 = var_debug_decl (expr2);
 
-  return (expr == expr2 && offset == offset2);
+  return (expr == expr2 && known_eq (offset, offset2));
 }
 
 /* LOC is a REG or MEM that we would like to track if possible.
@@ -5286,7 +5339,7 @@ same_variable_part_p (rtx loc, tree expr, HOST_WIDE_INT offset)
    from EXPR in *OFFSET_OUT (if nonnull).  */
 
 static bool
-track_loc_p (rtx loc, tree expr, HOST_WIDE_INT offset, bool store_reg_p,
+track_loc_p (rtx loc, tree expr, poly_int64 offset, bool store_reg_p,
             machine_mode *mode_out, HOST_WIDE_INT *offset_out)
 {
   machine_mode mode;
@@ -5320,19 +5373,20 @@ track_loc_p (rtx loc, tree expr, HOST_WIDE_INT offset, bool store_reg_p,
        || (store_reg_p
           && !COMPLEX_MODE_P (DECL_MODE (expr))
           && hard_regno_nregs (REGNO (loc), DECL_MODE (expr)) == 1))
-      && offset + byte_lowpart_offset (DECL_MODE (expr), mode) == 0)
+      && known_eq (offset + byte_lowpart_offset (DECL_MODE (expr), mode), 0))
     {
       mode = DECL_MODE (expr);
       offset = 0;
     }
 
-  if (offset < 0 || offset >= MAX_VAR_PARTS)
+  HOST_WIDE_INT const_offset;
+  if (!track_offset_p (offset, &const_offset))
     return false;
 
   if (mode_out)
     *mode_out = mode;
   if (offset_out)
-    *offset_out = offset;
+    *offset_out = const_offset;
   return true;
 }
 
@@ -5343,7 +5397,7 @@ track_loc_p (rtx loc, tree expr, HOST_WIDE_INT offset, bool store_reg_p,
 static rtx
 var_lowpart (machine_mode mode, rtx loc)
 {
-  unsigned int offset, reg_offset, regno;
+  unsigned int regno;
 
   if (GET_MODE (loc) == mode)
     return loc;
@@ -5351,12 +5405,12 @@ var_lowpart (machine_mode mode, rtx loc)
   if (!REG_P (loc) && !MEM_P (loc))
     return NULL;
 
-  offset = byte_lowpart_offset (mode, GET_MODE (loc));
+  poly_uint64 offset = byte_lowpart_offset (mode, GET_MODE (loc));
 
   if (MEM_P (loc))
     return adjust_address_nv (loc, mode, offset);
 
-  reg_offset = subreg_lowpart_offset (mode, GET_MODE (loc));
+  poly_uint64 reg_offset = subreg_lowpart_offset (mode, GET_MODE (loc));
   regno = REGNO (loc) + subreg_regno_offset (REGNO (loc), GET_MODE (loc),
                                             reg_offset, mode);
   return gen_rtx_REG_offset (loc, mode, regno, offset);
@@ -5535,7 +5589,7 @@ use_type (rtx loc, struct count_use_info *cui, machine_mode *modep)
                  variable names such as VALUEs (never happens) or
                  DEBUG_EXPRs (only happens in the presence of debug
                  insns).  */
-              && (!MAY_HAVE_DEBUG_INSNS
+              && (!MAY_HAVE_DEBUG_BIND_INSNS
                   || !rtx_debug_expr_p (XEXP (loc, 0))))
        return MO_USE;
       else
@@ -5606,7 +5660,6 @@ non_suitable_const (const_rtx x)
        case DEBUG_EXPR:
        case PC:
        case SCRATCH:
-       case CC0:
        case ASM_INPUT:
        case ASM_OPERANDS:
          return true;
@@ -5796,7 +5849,7 @@ add_uses_1 (rtx *x, void *cui)
    compile time for ridiculously complex expressions, although they're
    seldom useful, and they may often have to be discarded as not
    representable anyway.  */
-#define EXPR_USE_DEPTH (PARAM_VALUE (PARAM_MAX_VARTRACK_EXPR_DEPTH))
+#define EXPR_USE_DEPTH (param_max_vartrack_expr_depth)
 
 /* Attempt to reverse the EXPR operation in the debug info and record
    it in the cselib table.  Say for reg1 = reg2 + 6 even when reg2 is
@@ -5856,7 +5909,7 @@ reverse_op (rtx val, const_rtx expr, rtx_insn *insn)
        && (GET_CODE (l->loc) != CONST || !references_value_p (l->loc, 0)))
       return;
     /* Avoid creating too large locs lists.  */
-    else if (count == PARAM_VALUE (PARAM_MAX_VARTRACK_REVERSE_OP_SIZE))
+    else if (count == param_max_vartrack_reverse_op_size)
       return;
 
   switch (GET_CODE (src))
@@ -5933,7 +5986,9 @@ add_stores (rtx loc, const_rtx expr, void *cuip)
          mo.type = MO_CLOBBER;
          mo.u.loc = loc;
          if (GET_CODE (expr) == SET
-             && SET_DEST (expr) == loc
+             && (SET_DEST (expr) == loc
+                 || (GET_CODE (SET_DEST (expr)) == STRICT_LOW_PART
+                     && XEXP (SET_DEST (expr), 0) == loc))
              && !unsuitable_loc (SET_SRC (expr))
              && find_use_val (loc, mode, cui))
            {
@@ -6063,10 +6118,25 @@ add_stores (rtx loc, const_rtx expr, void *cuip)
     }
 
   if (loc == stack_pointer_rtx
-      && hard_frame_pointer_adjustment != -1
+      && (maybe_ne (hard_frame_pointer_adjustment, -1)
+         || (!frame_pointer_needed && !ACCUMULATE_OUTGOING_ARGS))
       && preserve)
     cselib_set_value_sp_based (v);
 
+  /* Don't record MO_VAL_SET for VALUEs that can be described using
+     cfa_base_rtx or cfa_base_rtx + CONST_INT, cselib already knows
+     all the needed equivalences and they shouldn't change depending
+     on which register holds that VALUE in some instruction.  */
+  if (!frame_pointer_needed
+      && cfa_base_rtx
+      && cselib_sp_derived_value_p (v)
+      && loc == stack_pointer_rtx)
+    {
+      if (preserve)
+       preserve_value (v);
+      return;
+    }
+
   nloc = replace_expr_with_values (oloc);
   if (nloc)
     oloc = nloc;
@@ -6243,14 +6313,12 @@ prepare_call_arguments (basic_block bb, rtx_insn *insn)
                  && targetm.calls.struct_value_rtx (type, 0) == 0)
                {
                  tree struct_addr = build_pointer_type (TREE_TYPE (type));
-                 machine_mode mode = TYPE_MODE (struct_addr);
+                 function_arg_info arg (struct_addr, /*named=*/true);
                  rtx reg;
                  INIT_CUMULATIVE_ARGS (args_so_far_v, type, NULL_RTX, fndecl,
                                        nargs + 1);
-                 reg = targetm.calls.function_arg (args_so_far, mode,
-                                                   struct_addr, true);
-                 targetm.calls.function_arg_advance (args_so_far, mode,
-                                                     struct_addr, true);
+                 reg = targetm.calls.function_arg (args_so_far, arg);
+                 targetm.calls.function_arg_advance (args_so_far, arg);
                  if (reg == NULL_RTX)
                    {
                      for (; link; link = XEXP (link, 1))
@@ -6268,11 +6336,9 @@ prepare_call_arguments (basic_block bb, rtx_insn *insn)
                                      nargs);
              if (obj_type_ref && TYPE_ARG_TYPES (type) != void_list_node)
                {
-                 machine_mode mode;
                  t = TYPE_ARG_TYPES (type);
-                 mode = TYPE_MODE (TREE_VALUE (t));
-                 this_arg = targetm.calls.function_arg (args_so_far, mode,
-                                                        TREE_VALUE (t), true);
+                 function_arg_info arg (TREE_VALUE (t), /*named=*/true);
+                 this_arg = targetm.calls.function_arg (args_so_far, arg);
                  if (this_arg && !REG_P (this_arg))
                    this_arg = NULL_RTX;
                  else if (this_arg == NULL_RTX)
@@ -6339,7 +6405,7 @@ prepare_call_arguments (basic_block bb, rtx_insn *insn)
 
            if (!frame_pointer_needed)
              {
-               struct adjust_mem_data amd;
+               class adjust_mem_data amd;
                amd.mem_mode = VOIDmode;
                amd.stack_adjust = -VTI (bb)->out.stack_adjust;
                amd.store = true;
@@ -6380,30 +6446,24 @@ prepare_call_arguments (basic_block bb, rtx_insn *insn)
          }
        if (t && t != void_list_node)
          {
-           tree argtype = TREE_VALUE (t);
-           machine_mode mode = TYPE_MODE (argtype);
            rtx reg;
-           if (pass_by_reference (&args_so_far_v, mode, argtype, true))
-             {
-               argtype = build_pointer_type (argtype);
-               mode = TYPE_MODE (argtype);
-             }
-           reg = targetm.calls.function_arg (args_so_far, mode,
-                                             argtype, true);
-           if (TREE_CODE (argtype) == REFERENCE_TYPE
-               && INTEGRAL_TYPE_P (TREE_TYPE (argtype))
+           function_arg_info arg (TREE_VALUE (t), /*named=*/true);
+           apply_pass_by_reference_rules (&args_so_far_v, arg);
+           reg = targetm.calls.function_arg (args_so_far, arg);
+           if (TREE_CODE (arg.type) == REFERENCE_TYPE
+               && INTEGRAL_TYPE_P (TREE_TYPE (arg.type))
                && reg
                && REG_P (reg)
-               && GET_MODE (reg) == mode
-               && (GET_MODE_CLASS (mode) == MODE_INT
-                   || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
+               && GET_MODE (reg) == arg.mode
+               && (GET_MODE_CLASS (arg.mode) == MODE_INT
+                   || GET_MODE_CLASS (arg.mode) == MODE_PARTIAL_INT)
                && REG_P (x)
                && REGNO (x) == REGNO (reg)
-               && GET_MODE (x) == mode
+               && GET_MODE (x) == arg.mode
                && item)
              {
                machine_mode indmode
-                 = TYPE_MODE (TREE_TYPE (argtype));
+                 = TYPE_MODE (TREE_TYPE (arg.type));
                rtx mem = gen_rtx_MEM (indmode, x);
                cselib_val *val = cselib_lookup (mem, indmode, 0, VOIDmode);
                if (val && cselib_preserved_value_p (val))
@@ -6443,8 +6503,7 @@ prepare_call_arguments (basic_block bb, rtx_insn *insn)
                        }
                  }
              }
-           targetm.calls.function_arg_advance (args_so_far, mode,
-                                               argtype, true);
+           targetm.calls.function_arg_advance (args_so_far, arg);
            t = TREE_CHAIN (t);
          }
       }
@@ -6593,7 +6652,7 @@ add_with_sets (rtx_insn *insn, struct cselib_set *sets, int n_sets)
      insert notes before it without worrying about any
      notes that MO_USEs might emit after the insn.  */
   cui.store_p = true;
-  note_stores (PATTERN (insn), add_stores, &cui);
+  note_stores (insn, add_stores, &cui);
   n2 = VTI (bb)->mos.length () - 1;
   mos = VTI (bb)->mos.address ();
 
@@ -6700,7 +6759,7 @@ compute_bb_dataflow (basic_block bb)
   dataflow_set_copy (&old_out, out);
   dataflow_set_copy (out, in);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     local_get_addr_cache = new hash_map<rtx, rtx>;
 
   FOR_EACH_VEC_ELT (VTI (bb)->mos, i, mo)
@@ -6982,7 +7041,7 @@ compute_bb_dataflow (basic_block bb)
        }
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       delete local_get_addr_cache;
       local_get_addr_cache = NULL;
@@ -7015,61 +7074,75 @@ vt_find_locations (void)
   int *rc_order;
   int i;
   int htabsz = 0;
-  int htabmax = PARAM_VALUE (PARAM_MAX_VARTRACK_SIZE);
+  int htabmax = param_max_vartrack_size;
   bool success = true;
+  unsigned int n_blocks_processed = 0;
 
   timevar_push (TV_VAR_TRACKING_DATAFLOW);
   /* Compute reverse completion order of depth first search of the CFG
      so that the data-flow runs faster.  */
   rc_order = XNEWVEC (int, n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS);
   bb_order = XNEWVEC (int, last_basic_block_for_fn (cfun));
-  pre_and_rev_post_order_compute (NULL, rc_order, false);
-  for (i = 0; i < n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS; i++)
+  auto_bitmap exit_bbs;
+  bitmap_set_bit (exit_bbs, EXIT_BLOCK);
+  auto_vec<std::pair<int, int> > toplevel_scc_extents;
+  int n = rev_post_order_and_mark_dfs_back_seme
+    (cfun, single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)), exit_bbs, true,
+     rc_order, &toplevel_scc_extents);
+  for (i = 0; i < n; i++)
     bb_order[rc_order[i]] = i;
-  free (rc_order);
 
-  auto_sbitmap visited (last_basic_block_for_fn (cfun));
   in_worklist = sbitmap_alloc (last_basic_block_for_fn (cfun));
   in_pending = sbitmap_alloc (last_basic_block_for_fn (cfun));
   bitmap_clear (in_worklist);
+  bitmap_clear (in_pending);
+
+  /* We're performing the dataflow iteration independently over the
+     toplevel SCCs plus leading non-cyclic entry blocks and separately
+     over the tail.  That ensures best memory locality and the least
+     number of visited blocks.  */
+  unsigned extent = 0;
+  int curr_start = -1;
+  int curr_end = -1;
+  do
+    {
+      curr_start = curr_end + 1;
+      if (toplevel_scc_extents.length () <= extent)
+       curr_end = n - 1;
+      else
+       curr_end = toplevel_scc_extents[extent++].second;
 
-  FOR_EACH_BB_FN (bb, cfun)
-    pending->insert (bb_order[bb->index], bb);
-  bitmap_ones (in_pending);
-
-  while (success && !pending->empty ())
-    {
-      std::swap (worklist, pending);
-      std::swap (in_worklist, in_pending);
-
-      bitmap_clear (visited);
+      for (int i = curr_start; i <= curr_end; ++i)
+       {
+         pending->insert (i, BASIC_BLOCK_FOR_FN (cfun, rc_order[i]));
+         bitmap_set_bit (in_pending, rc_order[i]);
+       }
 
-      while (!worklist->empty ())
+      while (success && !pending->empty ())
        {
-         bb = worklist->extract_min ();
-         bitmap_clear_bit (in_worklist, bb->index);
-         gcc_assert (!bitmap_bit_p (visited, bb->index));
-         if (!bitmap_bit_p (visited, bb->index))
+         std::swap (worklist, pending);
+         std::swap (in_worklist, in_pending);
+
+         while (!worklist->empty ())
            {
              bool changed;
              edge_iterator ei;
              int oldinsz, oldoutsz;
 
-             bitmap_set_bit (visited, bb->index);
+             bb = worklist->extract_min ();
+             bitmap_clear_bit (in_worklist, bb->index);
 
              if (VTI (bb)->in.vars)
                {
-                 htabsz
-                   -= shared_hash_htab (VTI (bb)->in.vars)->size ()
-                       + shared_hash_htab (VTI (bb)->out.vars)->size ();
+                 htabsz -= (shared_hash_htab (VTI (bb)->in.vars)->size ()
+                            + shared_hash_htab (VTI (bb)->out.vars)->size ());
                  oldinsz = shared_hash_htab (VTI (bb)->in.vars)->elements ();
-                 oldoutsz
-                   = shared_hash_htab (VTI (bb)->out.vars)->elements ();
+                 oldoutsz = shared_hash_htab (VTI (bb)->out.vars)->elements ();
                }
              else
                oldinsz = oldoutsz = 0;
 
-             if (MAY_HAVE_DEBUG_INSNS)
+             if (MAY_HAVE_DEBUG_BIND_INSNS)
                {
                  dataflow_set *in = &VTI (bb)->in, *first_out = NULL;
                  bool first = true, adjust = false;
@@ -7125,15 +7198,16 @@ vt_find_locations (void)
                }
 
              changed = compute_bb_dataflow (bb);
-             htabsz += shared_hash_htab (VTI (bb)->in.vars)->size ()
-                        + shared_hash_htab (VTI (bb)->out.vars)->size ();
+             n_blocks_processed++;
+             htabsz += (shared_hash_htab (VTI (bb)->in.vars)->size ()
+                        + shared_hash_htab (VTI (bb)->out.vars)->size ());
 
              if (htabmax && htabsz > htabmax)
                {
-                 if (MAY_HAVE_DEBUG_INSNS)
+                 if (MAY_HAVE_DEBUG_BIND_INSNS)
                    inform (DECL_SOURCE_LOCATION (cfun->decl),
                            "variable tracking size limit exceeded with "
-                           "-fvar-tracking-assignments, retrying without");
+                           "%<-fvar-tracking-assignments%>, retrying without");
                  else
                    inform (DECL_SOURCE_LOCATION (cfun->decl),
                            "variable tracking size limit exceeded");
@@ -7148,8 +7222,11 @@ vt_find_locations (void)
                      if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
                        continue;
 
-                     if (bitmap_bit_p (visited, e->dest->index))
+                     /* Iterate to an earlier block in RPO in the next
+                        round, iterate to the same block immediately.  */
+                     if (bb_order[e->dest->index] < bb_order[bb->index])
                        {
+                         gcc_assert (bb_order[e->dest->index] >= curr_start);
                          if (!bitmap_bit_p (in_pending, e->dest->index))
                            {
                              /* Send E->DEST to next round.  */
@@ -7158,9 +7235,11 @@ vt_find_locations (void)
                                               e->dest);
                            }
                        }
-                     else if (!bitmap_bit_p (in_worklist, e->dest->index))
+                     else if (bb_order[e->dest->index] <= curr_end
+                              && !bitmap_bit_p (in_worklist, e->dest->index))
                        {
-                         /* Add E->DEST to current round.  */
+                         /* Add E->DEST to current round or delay
+                            processing if it is in the next SCC.  */
                          bitmap_set_bit (in_worklist, e->dest->index);
                          worklist->insert (bb_order[e->dest->index],
                                            e->dest);
@@ -7170,8 +7249,8 @@ vt_find_locations (void)
 
              if (dump_file)
                fprintf (dump_file,
-                        "BB %i: in %i (was %i), out %i (was %i), rem %i + %i, tsz %i\n",
-                        bb->index,
+                        "BB %i: in %i (was %i), out %i (was %i), rem %i + %i, "
+                        "tsz %i\n", bb->index,
                         (int)shared_hash_htab (VTI (bb)->in.vars)->size (),
                         oldinsz,
                         (int)shared_hash_htab (VTI (bb)->out.vars)->size (),
@@ -7189,11 +7268,16 @@ vt_find_locations (void)
            }
        }
     }
+  while (curr_end != n - 1);
+
+  statistics_counter_event (cfun, "compute_bb_dataflow times",
+                           n_blocks_processed);
 
-  if (success && MAY_HAVE_DEBUG_INSNS)
+  if (success && MAY_HAVE_DEBUG_BIND_INSNS)
     FOR_EACH_BB_FN (bb, cfun)
       gcc_assert (VTI (bb)->flooded);
 
+  free (rc_order);
   free (bb_order);
   delete worklist;
   delete pending;
@@ -7283,7 +7367,7 @@ dump_var (variable *var)
 static void
 dump_vars (variable_table_type *vars)
 {
-  if (vars->elements () > 0)
+  if (!vars->is_empty ())
     {
       fprintf (dump_file, "Variables:\n");
       vars->traverse <void *, dump_var_tracking_slot> (NULL);
@@ -8012,8 +8096,9 @@ delete_variable_part (dataflow_set *set, rtx loc, decl_or_value dv,
 
 /* Structure for passing some other parameters to function
    vt_expand_loc_callback.  */
-struct expand_loc_callback_data
+class expand_loc_callback_data
 {
+public:
   /* The variables and values active at this point.  */
   variable_table_type *vars;
 
@@ -8059,7 +8144,7 @@ loc_exp_dep_alloc (variable *var, int count)
     return;
 
   allocsize = offsetof (struct onepart_aux, deps)
-             + vec<loc_exp_dep, va_heap, vl_embed>::embedded_size (count);
+             + deps_vec::embedded_size (count);
 
   if (VAR_LOC_1PAUX (var))
     {
@@ -8279,8 +8364,8 @@ static inline rtx
 vt_expand_var_loc_chain (variable *var, bitmap regs, void *data,
                         bool *pendrecp)
 {
-  struct expand_loc_callback_data *elcd
-    = (struct expand_loc_callback_data *) data;
+  class expand_loc_callback_data *elcd
+    = (class expand_loc_callback_data *) data;
   location_chain *loc, *next;
   rtx result = NULL;
   int first_child, result_first_child, last_child;
@@ -8418,8 +8503,8 @@ vt_expand_loc_callback (rtx x, bitmap regs,
                        int max_depth ATTRIBUTE_UNUSED,
                        void *data)
 {
-  struct expand_loc_callback_data *elcd
-    = (struct expand_loc_callback_data *) data;
+  class expand_loc_callback_data *elcd
+    = (class expand_loc_callback_data *) data;
   decl_or_value dv;
   variable *var;
   rtx result, subreg;
@@ -8442,7 +8527,7 @@ vt_expand_loc_callback (rtx x, bitmap regs,
 
       /* Invalid SUBREGs are ok in debug info.  ??? We could try
         alternate expansions for the VALUE as well.  */
-      if (!result)
+      if (!result && GET_MODE (subreg) != VOIDmode)
        result = gen_rtx_raw_SUBREG (GET_MODE (x), subreg, SUBREG_BYTE (x));
 
       return result;
@@ -8576,10 +8661,10 @@ resolve_expansions_pending_recursion (vec<rtx, va_heap> *pending)
 static rtx
 vt_expand_loc (rtx loc, variable_table_type *vars)
 {
-  struct expand_loc_callback_data data;
+  class expand_loc_callback_data data;
   rtx result;
 
-  if (!MAY_HAVE_DEBUG_INSNS)
+  if (!MAY_HAVE_DEBUG_BIND_INSNS)
     return loc;
 
   INIT_ELCD (data, vars);
@@ -8598,7 +8683,7 @@ vt_expand_loc (rtx loc, variable_table_type *vars)
 static rtx
 vt_expand_1pvar (variable *var, variable_table_type *vars)
 {
-  struct expand_loc_callback_data data;
+  class expand_loc_callback_data data;
   rtx loc;
 
   gcc_checking_assert (var->onepart && var->n_var_parts == 1);
@@ -8634,7 +8719,6 @@ emit_note_insn_var_location (variable **varp, emit_note_data *data)
   bool complete;
   enum var_init_status initialized = VAR_INIT_STATUS_UNINITIALIZED;
   HOST_WIDE_INT last_limit;
-  tree type_size_unit;
   HOST_WIDE_INT offsets[MAX_VAR_PARTS];
   rtx loc[MAX_VAR_PARTS];
   tree decl;
@@ -8656,7 +8740,7 @@ emit_note_insn_var_location (variable **varp, emit_note_data *data)
     {
       machine_mode mode, wider_mode;
       rtx loc2;
-      HOST_WIDE_INT offset;
+      HOST_WIDE_INT offset, size, wider_size;
 
       if (i == 0 && var->onepart)
        {
@@ -8711,7 +8795,14 @@ emit_note_insn_var_location (variable **varp, emit_note_data *data)
       mode = GET_MODE (var->var_part[i].cur_loc);
       if (mode == VOIDmode && var->onepart)
        mode = DECL_MODE (decl);
-      last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
+      /* We ony track subparts of constant-sized objects, since at present
+        there's no representation for polynomial pieces.  */
+      if (!GET_MODE_SIZE (mode).is_constant (&size))
+       {
+         complete = false;
+         continue;
+       }
+      last_limit = offsets[n_var_parts] + size;
 
       /* Attempt to merge adjacent registers or memory.  */
       for (j = i + 1; j < var->n_var_parts; j++)
@@ -8719,6 +8810,7 @@ emit_note_insn_var_location (variable **varp, emit_note_data *data)
          break;
       if (j < var->n_var_parts
          && GET_MODE_WIDER_MODE (mode).exists (&wider_mode)
+         && GET_MODE_SIZE (wider_mode).is_constant (&wider_size)
          && var->var_part[j].cur_loc
          && mode == GET_MODE (var->var_part[j].cur_loc)
          && (REG_P (loc[n_var_parts]) || MEM_P (loc[n_var_parts]))
@@ -8727,6 +8819,7 @@ emit_note_insn_var_location (variable **varp, emit_note_data *data)
          && GET_CODE (loc[n_var_parts]) == GET_CODE (loc2))
        {
          rtx new_loc = NULL;
+         poly_int64 offset2;
 
          if (REG_P (loc[n_var_parts])
              && hard_regno_nregs (REGNO (loc[n_var_parts]), mode) * 2
@@ -8751,20 +8844,13 @@ emit_note_insn_var_location (variable **varp, emit_note_data *data)
          else if (MEM_P (loc[n_var_parts])
                   && GET_CODE (XEXP (loc2, 0)) == PLUS
                   && REG_P (XEXP (XEXP (loc2, 0), 0))
-                  && CONST_INT_P (XEXP (XEXP (loc2, 0), 1)))
+                  && poly_int_rtx_p (XEXP (XEXP (loc2, 0), 1), &offset2))
            {
-             if ((REG_P (XEXP (loc[n_var_parts], 0))
-                  && rtx_equal_p (XEXP (loc[n_var_parts], 0),
-                                  XEXP (XEXP (loc2, 0), 0))
-                  && INTVAL (XEXP (XEXP (loc2, 0), 1))
-                     == GET_MODE_SIZE (mode))
-                 || (GET_CODE (XEXP (loc[n_var_parts], 0)) == PLUS
-                     && CONST_INT_P (XEXP (XEXP (loc[n_var_parts], 0), 1))
-                     && rtx_equal_p (XEXP (XEXP (loc[n_var_parts], 0), 0),
-                                     XEXP (XEXP (loc2, 0), 0))
-                     && INTVAL (XEXP (XEXP (loc[n_var_parts], 0), 1))
-                        + GET_MODE_SIZE (mode)
-                        == INTVAL (XEXP (XEXP (loc2, 0), 1))))
+             poly_int64 end1 = size;
+             rtx base1 = strip_offset_and_add (XEXP (loc[n_var_parts], 0),
+                                               &end1);
+             if (rtx_equal_p (base1, XEXP (XEXP (loc2, 0), 0))
+                 && known_eq (end1, offset2))
                new_loc = adjust_address_nv (loc[n_var_parts],
                                             wider_mode, 0);
            }
@@ -8773,14 +8859,15 @@ emit_note_insn_var_location (variable **varp, emit_note_data *data)
            {
              loc[n_var_parts] = new_loc;
              mode = wider_mode;
-             last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
+             last_limit = offsets[n_var_parts] + wider_size;
              i = j;
            }
        }
       ++n_var_parts;
     }
-  type_size_unit = TYPE_SIZE_UNIT (TREE_TYPE (decl));
-  if ((unsigned HOST_WIDE_INT) last_limit < TREE_INT_CST_LOW (type_size_unit))
+  poly_uint64 type_size_unit
+    = tree_to_poly_uint64 (TYPE_SIZE_UNIT (TREE_TYPE (decl)));
+  if (maybe_lt (poly_uint64 (last_limit), type_size_unit))
     complete = false;
 
   if (! flag_var_tracking_uninit)
@@ -8825,14 +8912,12 @@ emit_note_insn_var_location (variable **varp, emit_note_data *data)
       /* Make sure that the call related notes come first.  */
       while (NEXT_INSN (insn)
             && NOTE_P (insn)
-            && ((NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION
-                 && NOTE_DURING_CALL_P (insn))
-                || NOTE_KIND (insn) == NOTE_INSN_CALL_ARG_LOCATION))
+            && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION
+            && NOTE_DURING_CALL_P (insn))
        insn = NEXT_INSN (insn);
       if (NOTE_P (insn)
-         && ((NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION
-              && NOTE_DURING_CALL_P (insn))
-             || NOTE_KIND (insn) == NOTE_INSN_CALL_ARG_LOCATION))
+         && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION
+         && NOTE_DURING_CALL_P (insn))
        note = emit_note_after (NOTE_INSN_VAR_LOCATION, insn);
       else
        note = emit_note_before (NOTE_INSN_VAR_LOCATION, insn);
@@ -9011,10 +9096,10 @@ emit_notes_for_changes (rtx_insn *insn, enum emit_note_where where,
   emit_note_data data;
   variable_table_type *htab = shared_hash_htab (vars);
 
-  if (!changed_variables->elements ())
+  if (changed_variables->is_empty ())
     return;
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     process_changed_values (htab);
 
   data.insn = insn;
@@ -9175,7 +9260,6 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
            emit_notes_for_changes (insn, EMIT_NOTE_AFTER_CALL_INSN, set->vars);
            {
              rtx arguments = mo->u.loc, *p = &arguments;
-             rtx_note *note;
              while (*p)
                {
                  XEXP (XEXP (*p, 0), 1)
@@ -9183,7 +9267,11 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
                                     shared_hash_htab (set->vars));
                  /* If expansion is successful, keep it in the list.  */
                  if (XEXP (XEXP (*p, 0), 1))
-                   p = &XEXP (*p, 1);
+                   {
+                     XEXP (XEXP (*p, 0), 1)
+                       = copy_rtx_if_shared (XEXP (XEXP (*p, 0), 1));
+                     p = &XEXP (*p, 1);
+                   }
                  /* Otherwise, if the following item is data_value for it,
                     drop it too too.  */
                  else if (XEXP (*p, 1)
@@ -9199,8 +9287,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
                  else
                    *p = XEXP (*p, 1);
                }
-             note = emit_note_after (NOTE_INSN_CALL_ARG_LOCATION, insn);
-             NOTE_VAR_LOCATION (note) = arguments;
+             add_reg_note (insn, REG_CALL_ARG_LOCATION, arguments);
            }
            break;
 
@@ -9487,7 +9574,7 @@ vt_emit_notes (void)
   basic_block bb;
   dataflow_set cur;
 
-  gcc_assert (!changed_variables->elements ());
+  gcc_assert (changed_variables->is_empty ());
 
   /* Free memory occupied by the out hash tables, as they aren't used
      anymore.  */
@@ -9498,10 +9585,8 @@ vt_emit_notes (void)
      delete_variable_part).  */
   emit_notes = true;
 
-  if (MAY_HAVE_DEBUG_INSNS)
-    {
-      dropped_values = new variable_table_type (cselib_get_next_uid () * 2);
-    }
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
+    dropped_values = new variable_table_type (cselib_get_next_uid () * 2);
 
   dataflow_set_init (&cur);
 
@@ -9511,13 +9596,13 @@ vt_emit_notes (void)
         subsequent basic blocks.  */
       emit_notes_for_differences (BB_HEAD (bb), &cur, &VTI (bb)->in);
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
        local_get_addr_cache = new hash_map<rtx, rtx>;
 
       /* Emit the notes for the changes in the basic block itself.  */
       emit_notes_in_bb (bb, &cur);
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
        delete local_get_addr_cache;
       local_get_addr_cache = NULL;
 
@@ -9533,7 +9618,7 @@ vt_emit_notes (void)
 
   dataflow_set_destroy (&cur);
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     delete dropped_values;
   dropped_values = NULL;
 
@@ -9544,7 +9629,7 @@ vt_emit_notes (void)
    assign declaration to *DECLP and offset to *OFFSETP, and return true.  */
 
 static bool
-vt_get_decl_and_offset (rtx rtl, tree *declp, HOST_WIDE_INT *offsetp)
+vt_get_decl_and_offset (rtx rtl, tree *declp, poly_int64 *offsetp)
 {
   if (REG_P (rtl))
     {
@@ -9570,8 +9655,10 @@ vt_get_decl_and_offset (rtx rtl, tree *declp, HOST_WIDE_INT *offsetp)
            decl = REG_EXPR (reg);
          if (REG_EXPR (reg) != decl)
            break;
-         if (REG_OFFSET (reg) < offset)
-           offset = REG_OFFSET (reg);
+         HOST_WIDE_INT this_offset;
+         if (!track_offset_p (REG_OFFSET (reg), &this_offset))
+           break;
+         offset = MIN (offset, this_offset);
        }
 
       if (i == len)
@@ -9615,9 +9702,10 @@ vt_add_function_parameter (tree parm)
   rtx incoming = DECL_INCOMING_RTL (parm);
   tree decl;
   machine_mode mode;
-  HOST_WIDE_INT offset;
+  poly_int64 offset;
   dataflow_set *out;
   decl_or_value dv;
+  bool incoming_ok = true;
 
   if (TREE_CODE (parm) != PARM_DECL)
     return;
@@ -9632,20 +9720,17 @@ vt_add_function_parameter (tree parm)
      rewrite the incoming location of parameters passed on the stack
      into MEMs based on the argument pointer, so that incoming doesn't
      depend on a pseudo.  */
+  poly_int64 incoming_offset = 0;
   if (MEM_P (incoming)
-      && (XEXP (incoming, 0) == crtl->args.internal_arg_pointer
-         || (GET_CODE (XEXP (incoming, 0)) == PLUS
-             && XEXP (XEXP (incoming, 0), 0)
-                == crtl->args.internal_arg_pointer
-             && CONST_INT_P (XEXP (XEXP (incoming, 0), 1)))))
+      && (strip_offset (XEXP (incoming, 0), &incoming_offset)
+         == crtl->args.internal_arg_pointer))
     {
       HOST_WIDE_INT off = -FIRST_PARM_OFFSET (current_function_decl);
-      if (GET_CODE (XEXP (incoming, 0)) == PLUS)
-       off += INTVAL (XEXP (XEXP (incoming, 0), 1));
       incoming
        = replace_equiv_address_nv (incoming,
                                    plus_constant (Pmode,
-                                                  arg_pointer_rtx, off));
+                                                  arg_pointer_rtx,
+                                                  off + incoming_offset));
     }
 
 #ifdef HAVE_window_save
@@ -9708,6 +9793,7 @@ vt_add_function_parameter (tree parm)
 
   if (!vt_get_decl_and_offset (incoming, &decl, &offset))
     {
+      incoming_ok = false;
       if (MEM_P (incoming))
        {
          /* This means argument is passed by invisible reference.  */
@@ -9738,7 +9824,8 @@ vt_add_function_parameter (tree parm)
       offset = 0;
     }
 
-  if (!track_loc_p (incoming, parm, offset, false, &mode, &offset))
+  HOST_WIDE_INT const_offset;
+  if (!track_loc_p (incoming, parm, offset, false, &mode, &const_offset))
     return;
 
   out = &VTI (ENTRY_BLOCK_PTR_FOR_FN (cfun))->out;
@@ -9759,7 +9846,7 @@ vt_add_function_parameter (tree parm)
         arguments passed by invisible reference aren't dealt with
         above: incoming-rtl will have Pmode rather than the
         expected mode for the type.  */
-      if (offset)
+      if (const_offset)
        return;
 
       lowpart = var_lowpart (mode, incoming);
@@ -9774,7 +9861,7 @@ vt_add_function_parameter (tree parm)
       if (val)
        {
          preserve_value (val);
-         set_variable_part (out, val->val_rtx, dv, offset,
+         set_variable_part (out, val->val_rtx, dv, const_offset,
                             VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
          dv = dv_from_value (val->val_rtx);
        }
@@ -9795,9 +9882,9 @@ vt_add_function_parameter (tree parm)
     {
       incoming = var_lowpart (mode, incoming);
       gcc_assert (REGNO (incoming) < FIRST_PSEUDO_REGISTER);
-      attrs_list_insert (&out->regs[REGNO (incoming)], dv, offset,
+      attrs_list_insert (&out->regs[REGNO (incoming)], dv, const_offset,
                         incoming);
-      set_variable_part (out, incoming, dv, offset,
+      set_variable_part (out, incoming, dv, const_offset,
                         VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
       if (dv_is_value_p (dv))
        {
@@ -9825,20 +9912,26 @@ vt_add_function_parameter (tree parm)
     {
       int i;
 
+      /* The following code relies on vt_get_decl_and_offset returning true for
+        incoming, which might not be always the case.  */
+      if (!incoming_ok)
+       return;
       for (i = 0; i < XVECLEN (incoming, 0); i++)
        {
          rtx reg = XEXP (XVECEXP (incoming, 0, i), 0);
-         offset = REG_OFFSET (reg);
+         /* vt_get_decl_and_offset has already checked that the offset
+            is a valid variable part.  */
+         const_offset = get_tracked_reg_offset (reg);
          gcc_assert (REGNO (reg) < FIRST_PSEUDO_REGISTER);
-         attrs_list_insert (&out->regs[REGNO (reg)], dv, offset, reg);
-         set_variable_part (out, reg, dv, offset,
+         attrs_list_insert (&out->regs[REGNO (reg)], dv, const_offset, reg);
+         set_variable_part (out, reg, dv, const_offset,
                             VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
        }
     }
   else if (MEM_P (incoming))
     {
       incoming = var_lowpart (mode, incoming);
-      set_variable_part (out, incoming, dv, offset,
+      set_variable_part (out, incoming, dv, const_offset,
                         VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
     }
 }
@@ -9852,8 +9945,7 @@ vt_add_function_parameters (void)
 
   for (parm = DECL_ARGUMENTS (current_function_decl);
        parm; parm = DECL_CHAIN (parm))
-    if (!POINTER_BOUNDS_P (parm))
-      vt_add_function_parameter (parm);
+    vt_add_function_parameter (parm);
 
   if (DECL_HAS_VALUE_EXPR_P (DECL_RESULT (current_function_decl)))
     {
@@ -9893,7 +9985,7 @@ vt_init_cfa_base (void)
       cfa_base_rtx = NULL_RTX;
       return;
     }
-  if (!MAY_HAVE_DEBUG_INSNS)
+  if (!MAY_HAVE_DEBUG_BIND_INSNS)
     return;
 
   /* Tell alias analysis that cfa_base_rtx should share
@@ -9909,6 +10001,35 @@ vt_init_cfa_base (void)
   cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));
 }
 
+/* Reemit INSN, a MARKER_DEBUG_INSN, as a note.  */
+
+static rtx_insn *
+reemit_marker_as_note (rtx_insn *insn)
+{
+  gcc_checking_assert (DEBUG_MARKER_INSN_P (insn));
+
+  enum insn_note kind = INSN_DEBUG_MARKER_KIND (insn);
+
+  switch (kind)
+    {
+    case NOTE_INSN_BEGIN_STMT:
+    case NOTE_INSN_INLINE_ENTRY:
+      {
+       rtx_insn *note = NULL;
+       if (cfun->debug_nonbind_markers)
+         {
+           note = emit_note_before (kind, insn);
+           NOTE_MARKER_LOCATION (note) = INSN_LOCATION (insn);
+         }
+       delete_insn (insn);
+       return note;
+      }
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Allocate and initialize the data structures for variable tracking
    and parse the RTL to get the micro operations.  */
 
@@ -9916,7 +10037,7 @@ static bool
 vt_initialize (void)
 {
   basic_block bb;
-  HOST_WIDE_INT fp_cfa_offset = -1;
+  poly_int64 fp_cfa_offset = -1;
 
   alloc_aux_for_blocks (sizeof (variable_tracking_info));
 
@@ -9935,7 +10056,7 @@ vt_initialize (void)
       VTI (bb)->permp = NULL;
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS);
       scratch_regs = BITMAP_ALLOC (NULL);
@@ -9948,7 +10069,7 @@ vt_initialize (void)
       global_get_addr_cache = NULL;
     }
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       rtx reg, expr;
       int ofst;
@@ -9969,19 +10090,25 @@ vt_initialize (void)
       preserve_value (val);
       if (reg != hard_frame_pointer_rtx && fixed_regs[REGNO (reg)])
        cselib_preserve_cfa_base_value (val, REGNO (reg));
-      expr = plus_constant (GET_MODE (stack_pointer_rtx),
-                           stack_pointer_rtx, -ofst);
-      cselib_add_permanent_equiv (val, expr, get_insns ());
-
       if (ofst)
        {
-         val = cselib_lookup_from_insn (stack_pointer_rtx,
-                                        GET_MODE (stack_pointer_rtx), 1,
-                                        VOIDmode, get_insns ());
-         preserve_value (val);
+         cselib_val *valsp
+           = cselib_lookup_from_insn (stack_pointer_rtx,
+                                      GET_MODE (stack_pointer_rtx), 1,
+                                      VOIDmode, get_insns ());
+         preserve_value (valsp);
          expr = plus_constant (GET_MODE (reg), reg, ofst);
-         cselib_add_permanent_equiv (val, expr, get_insns ());
+         /* This cselib_add_permanent_equiv call needs to be done before
+            the other cselib_add_permanent_equiv a few lines later,
+            because after that one is done, cselib_lookup on this expr
+            will due to the cselib SP_DERIVED_VALUE_P optimizations
+            return valsp and so no permanent equivalency will be added.  */
+         cselib_add_permanent_equiv (valsp, expr, get_insns ());
        }
+
+      expr = plus_constant (GET_MODE (stack_pointer_rtx),
+                           stack_pointer_rtx, -ofst);
+      cselib_add_permanent_equiv (val, expr, get_insns ());
     }
 
   /* In order to factor out the adjustments made to the stack pointer or to
@@ -10031,7 +10158,7 @@ vt_initialize (void)
        {
          if (GET_CODE (elim) == PLUS)
            {
-             fp_cfa_offset -= INTVAL (XEXP (elim, 1));
+             fp_cfa_offset -= rtx_to_poly_int64 (XEXP (elim, 1));
              elim = XEXP (elim, 0);
            }
          if (elim != hard_frame_pointer_rtx)
@@ -10072,13 +10199,13 @@ vt_initialize (void)
 
   vt_add_function_parameters ();
 
+  bool record_sp_value = false;
   FOR_EACH_BB_FN (bb, cfun)
     {
       rtx_insn *insn;
-      HOST_WIDE_INT pre, post = 0;
       basic_block first_bb, last_bb;
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
        {
          cselib_record_sets_hook = add_with_sets;
          if (dump_file && (dump_flags & TDF_DETAILS))
@@ -10086,6 +10213,15 @@ vt_initialize (void)
                     cselib_get_next_uid ());
        }
 
+      if (MAY_HAVE_DEBUG_BIND_INSNS
+         && cfa_base_rtx
+         && !frame_pointer_needed
+         && record_sp_value)
+       cselib_record_sp_cfa_base_equiv (-cfa_base_offset
+                                        - VTI (bb)->in.stack_adjust,
+                                        BB_HEAD (bb));
+      record_sp_value = true;
+
       first_bb = bb;
       for (;;)
        {
@@ -10105,11 +10241,14 @@ vt_initialize (void)
        {
          HOST_WIDE_INT offset = VTI (bb)->out.stack_adjust;
          VTI (bb)->out.stack_adjust = VTI (bb)->in.stack_adjust;
-         for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
-              insn = NEXT_INSN (insn))
+
+         rtx_insn *next;
+         FOR_BB_INSNS_SAFE (bb, insn, next)
            {
              if (INSN_P (insn))
                {
+                 HOST_WIDE_INT pre = 0, post = 0;
+
                  if (!frame_pointer_needed)
                    {
                      insn_stack_adjust_offset_pre_post (insn, &pre, &post);
@@ -10123,20 +10262,32 @@ vt_initialize (void)
                            log_op_type (PATTERN (insn), bb, insn,
                                         MO_ADJUST, dump_file);
                          VTI (bb)->mos.safe_push (mo);
-                         VTI (bb)->out.stack_adjust += pre;
                        }
                    }
 
                  cselib_hook_called = false;
                  adjust_insn (bb, insn);
-                 if (MAY_HAVE_DEBUG_INSNS)
+
+                 if (pre)
+                   VTI (bb)->out.stack_adjust += pre;
+
+                 if (DEBUG_MARKER_INSN_P (insn))
+                   {
+                     reemit_marker_as_note (insn);
+                     continue;
+                   }
+
+                 if (MAY_HAVE_DEBUG_BIND_INSNS)
                    {
                      if (CALL_P (insn))
                        prepare_call_arguments (bb, insn);
                      cselib_process_insn (insn);
                      if (dump_file && (dump_flags & TDF_DETAILS))
                        {
-                         print_rtl_single (dump_file, insn);
+                         if (dump_flags & TDF_SLIM)
+                           dump_insn_slim (dump_file, insn);
+                         else
+                           print_rtl_single (dump_file, insn);
                          dump_cselib_table (dump_file);
                        }
                    }
@@ -10144,7 +10295,7 @@ vt_initialize (void)
                    add_with_sets (insn, 0, 0);
                  cancel_changes (0);
 
-                 if (!frame_pointer_needed && post)
+                 if (post)
                    {
                      micro_operation mo;
                      mo.type = MO_ADJUST;
@@ -10157,14 +10308,14 @@ vt_initialize (void)
                      VTI (bb)->out.stack_adjust += post;
                    }
 
-                 if (fp_cfa_offset != -1
-                     && hard_frame_pointer_adjustment == -1
+                 if (maybe_ne (fp_cfa_offset, -1)
+                     && known_eq (hard_frame_pointer_adjustment, -1)
                      && fp_setter_insn (insn))
                    {
                      vt_init_cfa_base ();
                      hard_frame_pointer_adjustment = fp_cfa_offset;
                      /* Disassociate sp from fp now.  */
-                     if (MAY_HAVE_DEBUG_INSNS)
+                     if (MAY_HAVE_DEBUG_BIND_INSNS)
                        {
                          cselib_val *v;
                          cselib_invalidate_rtx (stack_pointer_rtx);
@@ -10184,7 +10335,7 @@ vt_initialize (void)
 
       bb = last_bb;
 
-      if (MAY_HAVE_DEBUG_INSNS)
+      if (MAY_HAVE_DEBUG_BIND_INSNS)
        {
          cselib_preserve_only_values ();
          cselib_reset_table (cselib_get_next_uid ());
@@ -10204,10 +10355,40 @@ vt_initialize (void)
 
 static int debug_label_num = 1;
 
-/* Get rid of all debug insns from the insn stream.  */
+/* Remove from the insn stream a single debug insn used for
+   variable tracking at assignments.  */
 
-static void
-delete_debug_insns (void)
+static inline void
+delete_vta_debug_insn (rtx_insn *insn)
+{
+  if (DEBUG_MARKER_INSN_P (insn))
+    {
+      reemit_marker_as_note (insn);
+      return;
+    }
+
+  tree decl = INSN_VAR_LOCATION_DECL (insn);
+  if (TREE_CODE (decl) == LABEL_DECL
+      && DECL_NAME (decl)
+      && !DECL_RTL_SET_P (decl))
+    {
+      PUT_CODE (insn, NOTE);
+      NOTE_KIND (insn) = NOTE_INSN_DELETED_DEBUG_LABEL;
+      NOTE_DELETED_LABEL_NAME (insn)
+       = IDENTIFIER_POINTER (DECL_NAME (decl));
+      SET_DECL_RTL (decl, insn);
+      CODE_LABEL_NUMBER (insn) = debug_label_num++;
+    }
+  else
+    delete_insn (insn);
+}
+
+/* Remove from the insn stream all debug insns used for variable
+   tracking at assignments.  USE_CFG should be false if the cfg is no
+   longer usable.  */
+
+void
+delete_vta_debug_insns (bool use_cfg)
 {
   basic_block bb;
   rtx_insn *insn, *next;
@@ -10215,27 +10396,20 @@ delete_debug_insns (void)
   if (!MAY_HAVE_DEBUG_INSNS)
     return;
 
-  FOR_EACH_BB_FN (bb, cfun)
-    {
-      FOR_BB_INSNS_SAFE (bb, insn, next)
+  if (use_cfg)
+    FOR_EACH_BB_FN (bb, cfun)
+      {
+       FOR_BB_INSNS_SAFE (bb, insn, next)
+         if (DEBUG_INSN_P (insn))
+           delete_vta_debug_insn (insn);
+      }
+  else
+    for (insn = get_insns (); insn; insn = next)
+      {
+       next = NEXT_INSN (insn);
        if (DEBUG_INSN_P (insn))
-         {
-           tree decl = INSN_VAR_LOCATION_DECL (insn);
-           if (TREE_CODE (decl) == LABEL_DECL
-               && DECL_NAME (decl)
-               && !DECL_RTL_SET_P (decl))
-             {
-               PUT_CODE (insn, NOTE);
-               NOTE_KIND (insn) = NOTE_INSN_DELETED_DEBUG_LABEL;
-               NOTE_DELETED_LABEL_NAME (insn)
-                 = IDENTIFIER_POINTER (DECL_NAME (decl));
-               SET_DECL_RTL (decl, insn);
-               CODE_LABEL_NUMBER (insn) = debug_label_num++;
-             }
-           else
-             delete_insn (insn);
-         }
-    }
+         delete_vta_debug_insn (insn);
+      }
 }
 
 /* Run a fast, BB-local only version of var tracking, to take care of
@@ -10248,7 +10422,7 @@ static void
 vt_debug_insns_local (bool skipped ATTRIBUTE_UNUSED)
 {
   /* ??? Just skip it all for now.  */
-  delete_debug_insns ();
+  delete_vta_debug_insns (true);
 }
 
 /* Free the data structures needed for variable tracking.  */
@@ -10283,7 +10457,7 @@ vt_finalize (void)
   location_chain_pool.release ();
   shared_hash_pool.release ();
 
-  if (MAY_HAVE_DEBUG_INSNS)
+  if (MAY_HAVE_DEBUG_BIND_INSNS)
     {
       if (global_get_addr_cache)
        delete global_get_addr_cache;
@@ -10313,23 +10487,28 @@ variable_tracking_main_1 (void)
 {
   bool success;
 
-  if (flag_var_tracking_assignments < 0
+  /* We won't be called as a separate pass if flag_var_tracking is not
+     set, but final may call us to turn debug markers into notes.  */
+  if ((!flag_var_tracking && MAY_HAVE_DEBUG_INSNS)
+      || flag_var_tracking_assignments < 0
       /* Var-tracking right now assumes the IR doesn't contain
         any pseudos at this point.  */
       || targetm.no_register_allocation)
     {
-      delete_debug_insns ();
+      delete_vta_debug_insns (true);
       return 0;
     }
 
-  if (n_basic_blocks_for_fn (cfun) > 500 &&
-      n_edges_for_fn (cfun) / n_basic_blocks_for_fn (cfun) >= 20)
+  if (!flag_var_tracking)
+    return 0;
+
+  if (n_basic_blocks_for_fn (cfun) > 500
+      && n_edges_for_fn (cfun) / n_basic_blocks_for_fn (cfun) >= 20)
     {
       vt_debug_insns_local (true);
       return 0;
     }
 
-  mark_dfs_back_edges ();
   if (!vt_initialize ())
     {
       vt_finalize ();
@@ -10343,7 +10522,7 @@ variable_tracking_main_1 (void)
     {
       vt_finalize ();
 
-      delete_debug_insns ();
+      delete_vta_debug_insns (true);
 
       /* This is later restored by our caller.  */
       flag_var_tracking_assignments = 0;