OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / var-tracking.c
index a9efcb1..214f58a 100644 (file)
@@ -34,7 +34,7 @@
    operations.
    The micro operations of one instruction are ordered so that
    pre-modifying stack adjustment < use < use with no var < call insn <
-     < set < clobber < post-modifying stack adjustment
+     < clobber < set < post-modifying stack adjustment
 
    Then, a forward dataflow analysis is performed to find out how locations
    of variables change through code and to propagate the variable locations
 #include "tree-pretty-print.h"
 #include "pointer-set.h"
 #include "recog.h"
+#include "tm_p.h"
 
 /* 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.
@@ -364,7 +365,7 @@ typedef const struct value_chain_def *const_value_chain;
 #define VTI(BB) ((variable_tracking_info) (BB)->aux)
 
 /* Macro to access MEM_OFFSET as an HOST_WIDE_INT.  Evaluates MEM twice.  */
-#define INT_MEM_OFFSET(mem) (MEM_OFFSET (mem) ? INTVAL (MEM_OFFSET (mem)) : 0)
+#define INT_MEM_OFFSET(mem) (MEM_OFFSET_KNOWN_P (mem) ? MEM_OFFSET (mem) : 0)
 
 /* Alloc pool for struct attrs_def.  */
 static alloc_pool attrs_pool;
@@ -399,6 +400,17 @@ static shared_hash empty_shared_hash;
 /* Scratch register bitmap used by cselib_expand_value_rtx.  */
 static bitmap scratch_regs = NULL;
 
+typedef struct GTY(()) parm_reg {
+  rtx outgoing;
+  rtx incoming;
+} parm_reg_t;
+
+DEF_VEC_O(parm_reg_t);
+DEF_VEC_ALLOC_O(parm_reg_t, gc);
+
+/* Vector of windowed parameter registers, if any.  */
+static VEC(parm_reg_t, gc) *windowed_parm_regs = NULL;
+
 /* Variable used to tell whether cselib_process_insn called our hook.  */
 static bool cselib_hook_called;
 
@@ -408,6 +420,7 @@ static void stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
 static void insn_stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
                                               HOST_WIDE_INT *);
 static bool vt_stack_adjustments (void);
+static void note_register_arguments (rtx);
 static hashval_t variable_htab_hash (const void *);
 static int variable_htab_eq (const void *, const void *);
 static void variable_htab_free (void *);
@@ -659,11 +672,15 @@ vt_stack_adjustments (void)
            for (insn = BB_HEAD (dest);
                 insn != NEXT_INSN (BB_END (dest));
                 insn = NEXT_INSN (insn))
-             if (INSN_P (insn))
-               {
-                 insn_stack_adjust_offset_pre_post (insn, &pre, &post);
-                 offset += pre + post;
-               }
+             {
+               if (INSN_P (insn))
+                 {
+                   insn_stack_adjust_offset_pre_post (insn, &pre, &post);
+                   offset += pre + post;
+                 }
+               if (CALL_P (insn))
+                 note_register_arguments (insn);
+             }
 
          VTI (dest)->out.stack_adjust = offset;
 
@@ -699,7 +716,8 @@ vt_stack_adjustments (void)
 static rtx cfa_base_rtx;
 static HOST_WIDE_INT cfa_base_offset;
 
-/* Compute a CFA-based value for the stack pointer.  */
+/* Compute a CFA-based value for an ADJUSTMENT made to stack_pointer_rtx
+   or hard_frame_pointer_rtx.  */
 
 static inline rtx
 compute_cfa_pointer (HOST_WIDE_INT adjustment)
@@ -739,6 +757,10 @@ use_narrower_mode_test (rtx *loc, void *data)
     case REG:
       if (cselib_lookup (*loc, GET_MODE (SUBREG_REG (subreg)), 0, VOIDmode))
        return 1;
+      if (!validate_subreg (GET_MODE (subreg), GET_MODE (*loc),
+                           *loc, subreg_lowpart_offset (GET_MODE (subreg),
+                                                        GET_MODE (*loc))))
+       return 1;
       return -1;
     case PLUS:
     case MINUS:
@@ -959,6 +981,33 @@ adjust_insn (basic_block bb, rtx insn)
 {
   struct adjust_mem_data amd;
   rtx set;
+
+#ifdef HAVE_window_save
+  /* If the target machine has an explicit window save instruction, the
+     transformation OUTGOING_REGNO -> INCOMING_REGNO is done there.  */
+  if (RTX_FRAME_RELATED_P (insn)
+      && find_reg_note (insn, REG_CFA_WINDOW_SAVE, NULL_RTX))
+    {
+      unsigned int i, nregs = VEC_length(parm_reg_t, windowed_parm_regs);
+      rtx rtl = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nregs * 2));
+      parm_reg_t *p;
+
+      FOR_EACH_VEC_ELT (parm_reg_t, windowed_parm_regs, i, p)
+       {
+         XVECEXP (rtl, 0, i * 2)
+           = gen_rtx_SET (VOIDmode, p->incoming, p->outgoing);
+         /* Do not clobber the attached DECL, but only the REG.  */
+         XVECEXP (rtl, 0, i * 2 + 1)
+           = gen_rtx_CLOBBER (GET_MODE (p->outgoing),
+                              gen_raw_REG (GET_MODE (p->outgoing),
+                                           REGNO (p->outgoing)));
+       }
+
+      validate_change (NULL_RTX, &PATTERN (insn), rtl, true);
+      return;
+    }
+#endif
+
   amd.mem_mode = VOIDmode;
   amd.stack_adjust = -VTI (bb)->out.stack_adjust;
   amd.side_effects = NULL_RTX;
@@ -3111,8 +3160,8 @@ canonicalize_values_mark (void **slot, void *data)
            decl_or_value odv = dv_from_value (node->loc);
            void **oslot = shared_hash_find_slot_noinsert (set->vars, odv);
 
-           oslot = set_slot_part (set, val, oslot, odv, 0,
-                                  node->init, NULL_RTX);
+           set_slot_part (set, val, oslot, odv, 0,
+                          node->init, NULL_RTX);
 
            VALUE_RECURSED_INTO (node->loc) = true;
          }
@@ -3323,8 +3372,8 @@ canonicalize_values_star (void **slot, void *data)
       }
 
   if (val)
-    cslot = set_slot_part (set, val, cslot, cdv, 0,
-                          VAR_INIT_STATUS_INITIALIZED, NULL_RTX);
+    set_slot_part (set, val, cslot, cdv, 0,
+                  VAR_INIT_STATUS_INITIALIZED, NULL_RTX);
 
   slot = clobber_slot_part (set, cval, slot, 0, NULL);
 
@@ -3395,7 +3444,7 @@ canonicalize_vars_star (void **slot, void *data)
 
   slot = set_slot_part (set, cval, slot, dv, 0,
                        node->init, node->set_src);
-  slot = clobber_slot_part (set, cval, slot, 0, node->set_src);
+  clobber_slot_part (set, cval, slot, 0, node->set_src);
 
   return 1;
 }
@@ -4107,8 +4156,9 @@ find_mem_expr_in_1pdv (tree expr, rtx val, htab_t vars)
   VALUE_RECURSED_INTO (val) = true;
 
   for (node = var->var_part[0].loc_chain; node; node = node->next)
-    if (MEM_P (node->loc) && MEM_EXPR (node->loc) == expr
-       && MEM_OFFSET (node->loc) == 0)
+    if (MEM_P (node->loc)
+       && MEM_EXPR (node->loc) == expr
+       && INT_MEM_OFFSET (node->loc) == 0)
       {
        where = node;
        break;
@@ -4171,11 +4221,10 @@ dataflow_set_preserve_mem_locs (void **slot, void *data)
        {
          for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
            {
-             /* We want to remove dying MEMs that doesn't refer to
-                DECL.  */
+             /* We want to remove dying MEMs that doesn't refer to DECL.  */
              if (GET_CODE (loc->loc) == MEM
                  && (MEM_EXPR (loc->loc) != decl
-                     || MEM_OFFSET (loc->loc))
+                     || INT_MEM_OFFSET (loc->loc) != 0)
                  && !mem_dies_at_call (loc->loc))
                break;
              /* We want to move here MEMs that do refer to DECL.  */
@@ -4219,7 +4268,7 @@ dataflow_set_preserve_mem_locs (void **slot, void *data)
 
          if (GET_CODE (loc->loc) != MEM
              || (MEM_EXPR (loc->loc) == decl
-                 && MEM_OFFSET (loc->loc) == 0)
+                 && INT_MEM_OFFSET (loc->loc) == 0)
              || !mem_dies_at_call (loc->loc))
            {
              if (old_loc != loc->loc && emit_notes)
@@ -4625,8 +4674,8 @@ track_expr_p (tree expr, bool need_rtl)
       if (GET_MODE (decl_rtl) == BLKmode
          || AGGREGATE_TYPE_P (TREE_TYPE (realdecl)))
        return 0;
-      if (MEM_SIZE (decl_rtl)
-         && INTVAL (MEM_SIZE (decl_rtl)) > MAX_VAR_PARTS)
+      if (MEM_SIZE_KNOWN_P (decl_rtl)
+         && MEM_SIZE (decl_rtl) > MAX_VAR_PARTS)
        return 0;
     }
 
@@ -4826,7 +4875,7 @@ get_address_mode (rtx mem)
 static rtx
 replace_expr_with_values (rtx loc)
 {
-  if (REG_P (loc))
+  if (REG_P (loc) || GET_CODE (loc) == ENTRY_VALUE)
     return NULL;
   else if (MEM_P (loc))
     {
@@ -4971,6 +5020,9 @@ log_op_type (rtx x, basic_block bb, rtx insn,
 /* All preserved VALUEs.  */
 static VEC (rtx, heap) *preserved_values;
 
+/* Registers used in the current function for passing parameters.  */
+static HARD_REG_SET argument_reg_set;
+
 /* Ensure VAL is preserved and remember it in a vector for vt_emit_notes.  */
 
 static void
@@ -5038,6 +5090,7 @@ add_uses (rtx *ploc, void *data)
          if (MEM_P (vloc)
              && !REG_P (XEXP (vloc, 0))
              && !MEM_P (XEXP (vloc, 0))
+             && GET_CODE (XEXP (vloc, 0)) != ENTRY_VALUE
              && (GET_CODE (XEXP (vloc, 0)) != PLUS
                  || XEXP (XEXP (vloc, 0), 0) != cfa_base_rtx
                  || !CONST_INT_P (XEXP (XEXP (vloc, 0), 1))))
@@ -5116,6 +5169,7 @@ add_uses (rtx *ploc, void *data)
          if (MEM_P (oloc)
              && !REG_P (XEXP (oloc, 0))
              && !MEM_P (XEXP (oloc, 0))
+             && GET_CODE (XEXP (oloc, 0)) != ENTRY_VALUE
              && (GET_CODE (XEXP (oloc, 0)) != PLUS
                  || XEXP (XEXP (oloc, 0), 0) != cfa_base_rtx
                  || !CONST_INT_P (XEXP (XEXP (oloc, 0), 1))))
@@ -5201,6 +5255,8 @@ add_uses_1 (rtx *x, void *cui)
   for_each_rtx (x, add_uses, cui);
 }
 
+#define EXPR_DEPTH (PARAM_VALUE (PARAM_MAX_VARTRACK_EXPR_DEPTH))
+
 /* Attempt to reverse the EXPR operation in the debug info.  Say for
    reg1 = reg2 + 6 even when reg2 is no longer live we
    can express its value as VAL - 6.  */
@@ -5324,10 +5380,22 @@ 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
+             && REGNO (loc) < FIRST_PSEUDO_REGISTER
+             && TEST_HARD_REG_BIT (argument_reg_set, REGNO (loc))
+             && find_use_val (loc, mode, cui)
+             && GET_CODE (SET_SRC (expr)) != ASM_OPERANDS)
+           {
+             gcc_checking_assert (type == MO_VAL_SET);
+             mo.u.loc = gen_rtx_SET (VOIDmode, loc, SET_SRC (expr));
+           }
        }
       else
        {
-         if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
+         if (GET_CODE (expr) == SET
+             && SET_DEST (expr) == loc
+             && GET_CODE (SET_SRC (expr)) != ASM_OPERANDS)
            src = var_lowpart (mode2, SET_SRC (expr));
          loc = var_lowpart (mode2, loc);
 
@@ -5355,6 +5423,7 @@ add_stores (rtx loc, const_rtx expr, void *cuip)
       if (MEM_P (loc) && type == MO_VAL_SET
          && !REG_P (XEXP (loc, 0))
          && !MEM_P (XEXP (loc, 0))
+         && GET_CODE (XEXP (loc, 0)) != ENTRY_VALUE
          && (GET_CODE (XEXP (loc, 0)) != PLUS
              || XEXP (XEXP (loc, 0), 0) != cfa_base_rtx
              || !CONST_INT_P (XEXP (XEXP (loc, 0), 1))))
@@ -5387,7 +5456,9 @@ add_stores (rtx loc, const_rtx expr, void *cuip)
        }
       else
        {
-         if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
+         if (GET_CODE (expr) == SET
+             && SET_DEST (expr) == loc
+             && GET_CODE (SET_SRC (expr)) != ASM_OPERANDS)
            src = var_lowpart (mode2, SET_SRC (expr));
          loc = var_lowpart (mode2, loc);
 
@@ -5542,6 +5613,347 @@ add_stores (rtx loc, const_rtx expr, void *cuip)
   VEC_safe_push (micro_operation, heap, VTI (bb)->mos, &mo);
 }
 
+/* Arguments to the call.  */
+static rtx call_arguments;
+
+/* Compute call_arguments.  */
+
+static void
+prepare_call_arguments (basic_block bb, rtx insn)
+{
+  rtx link, x;
+  rtx prev, cur, next;
+  rtx call = PATTERN (insn);
+  rtx this_arg = NULL_RTX;
+  tree type = NULL_TREE, t, fndecl = NULL_TREE;
+  tree obj_type_ref = NULL_TREE;
+  CUMULATIVE_ARGS args_so_far_v;
+  cumulative_args_t args_so_far;
+
+  memset (&args_so_far_v, 0, sizeof (args_so_far_v));
+  args_so_far = pack_cumulative_args (&args_so_far_v);
+  if (GET_CODE (call) == PARALLEL)
+    call = XVECEXP (call, 0, 0);
+  if (GET_CODE (call) == SET)
+    call = SET_SRC (call);
+  if (GET_CODE (call) == CALL && MEM_P (XEXP (call, 0)))
+    {
+      if (GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
+       {
+         rtx symbol = XEXP (XEXP (call, 0), 0);
+         if (SYMBOL_REF_DECL (symbol))
+           fndecl = SYMBOL_REF_DECL (symbol);
+       }
+      if (fndecl == NULL_TREE)
+       fndecl = MEM_EXPR (XEXP (call, 0));
+      if (fndecl
+         && TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE
+         && TREE_CODE (TREE_TYPE (fndecl)) != METHOD_TYPE)
+       fndecl = NULL_TREE;
+      if (fndecl && TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
+       type = TREE_TYPE (fndecl);
+      if (fndecl && TREE_CODE (fndecl) != FUNCTION_DECL)
+       {
+         if (TREE_CODE (fndecl) == INDIRECT_REF
+             && TREE_CODE (TREE_OPERAND (fndecl, 0)) == OBJ_TYPE_REF)
+           obj_type_ref = TREE_OPERAND (fndecl, 0);
+         fndecl = NULL_TREE;
+       }
+      if (type)
+       {
+         for (t = TYPE_ARG_TYPES (type); t && t != void_list_node;
+              t = TREE_CHAIN (t))
+           if (TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
+               && INTEGRAL_TYPE_P (TREE_TYPE (TREE_VALUE (t))))
+             break;
+         if ((t == NULL || t == void_list_node) && obj_type_ref == NULL_TREE)
+           type = NULL;
+         else
+           {
+             int nargs ATTRIBUTE_UNUSED = list_length (TYPE_ARG_TYPES (type));
+             link = CALL_INSN_FUNCTION_USAGE (insn);
+#ifndef PCC_STATIC_STRUCT_RETURN
+             if (aggregate_value_p (TREE_TYPE (type), type)
+                 && targetm.calls.struct_value_rtx (type, 0) == 0)
+               {
+                 tree struct_addr = build_pointer_type (TREE_TYPE (type));
+                 enum machine_mode mode = TYPE_MODE (struct_addr);
+                 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);
+                 if (reg == NULL_RTX)
+                   {
+                     for (; link; link = XEXP (link, 1))
+                       if (GET_CODE (XEXP (link, 0)) == USE
+                           && MEM_P (XEXP (XEXP (link, 0), 0)))
+                         {
+                           link = XEXP (link, 1);
+                           break;
+                         }
+                   }
+               }
+             else
+#endif
+               INIT_CUMULATIVE_ARGS (args_so_far_v, type, NULL_RTX, fndecl,
+                                     nargs);
+             if (obj_type_ref && TYPE_ARG_TYPES (type) != void_list_node)
+               {
+                 enum 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);
+                 if (this_arg && !REG_P (this_arg))
+                   this_arg = NULL_RTX;
+                 else if (this_arg == NULL_RTX)
+                   {
+                     for (; link; link = XEXP (link, 1))
+                       if (GET_CODE (XEXP (link, 0)) == USE
+                           && MEM_P (XEXP (XEXP (link, 0), 0)))
+                         {
+                           this_arg = XEXP (XEXP (link, 0), 0);
+                           break;
+                         }
+                   }
+               }
+           }
+       }
+    }
+  t = type ? TYPE_ARG_TYPES (type) : NULL_TREE;
+
+  for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
+    if (GET_CODE (XEXP (link, 0)) == USE)
+      {
+       rtx item = NULL_RTX;
+       x = XEXP (XEXP (link, 0), 0);
+       if (GET_MODE (link) == VOIDmode
+           || GET_MODE (link) == BLKmode
+           || (GET_MODE (link) != GET_MODE (x)
+               && (GET_MODE_CLASS (GET_MODE (link)) != MODE_INT
+                   || GET_MODE_CLASS (GET_MODE (x)) != MODE_INT)))
+         /* Can't do anything for these, if the original type mode
+            isn't known or can't be converted.  */;
+       else if (REG_P (x))
+         {
+           cselib_val *val = cselib_lookup (x, GET_MODE (x), 0, VOIDmode);
+           if (val && cselib_preserved_value_p (val))
+             item = val->val_rtx;
+           else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
+             {
+               enum machine_mode mode = GET_MODE (x);
+
+               while ((mode = GET_MODE_WIDER_MODE (mode)) != VOIDmode
+                      && GET_MODE_BITSIZE (mode) <= BITS_PER_WORD)
+                 {
+                   rtx reg = simplify_subreg (mode, x, GET_MODE (x), 0);
+
+                   if (reg == NULL_RTX || !REG_P (reg))
+                     continue;
+                   val = cselib_lookup (reg, mode, 0, VOIDmode);
+                   if (val && cselib_preserved_value_p (val))
+                     {
+                       item = val->val_rtx;
+                       break;
+                     }
+                 }
+             }
+         }
+       else if (MEM_P (x))
+         {
+           rtx mem = x;
+           cselib_val *val;
+
+           if (!frame_pointer_needed)
+             {
+               struct adjust_mem_data amd;
+               amd.mem_mode = VOIDmode;
+               amd.stack_adjust = -VTI (bb)->out.stack_adjust;
+               amd.side_effects = NULL_RTX;
+               amd.store = true;
+               mem = simplify_replace_fn_rtx (mem, NULL_RTX, adjust_mems,
+                                              &amd);
+               gcc_assert (amd.side_effects == NULL_RTX);
+             }
+           val = cselib_lookup (mem, GET_MODE (mem), 0, VOIDmode);
+           if (val && cselib_preserved_value_p (val))
+             item = val->val_rtx;
+           else if (GET_MODE_CLASS (GET_MODE (mem)) != MODE_INT)
+             {
+               /* For non-integer stack argument see also if they weren't
+                  initialized by integers.  */
+               enum machine_mode imode = int_mode_for_mode (GET_MODE (mem));
+               if (imode != GET_MODE (mem) && imode != BLKmode)
+                 {
+                   val = cselib_lookup (adjust_address_nv (mem, imode, 0),
+                                        imode, 0, VOIDmode);
+                   if (val && cselib_preserved_value_p (val))
+                     item = lowpart_subreg (GET_MODE (x), val->val_rtx,
+                                            imode);
+                 }
+             }
+         }
+       if (item)
+         {
+           rtx x2 = x;
+           if (GET_MODE (item) != GET_MODE (link))
+             item = lowpart_subreg (GET_MODE (link), item, GET_MODE (item));
+           if (GET_MODE (x2) != GET_MODE (link))
+             x2 = lowpart_subreg (GET_MODE (link), x2, GET_MODE (x2));
+           item = gen_rtx_CONCAT (GET_MODE (link), x2, item);
+           call_arguments
+             = gen_rtx_EXPR_LIST (VOIDmode, item, call_arguments);
+         }
+       if (t && t != void_list_node)
+         {
+           tree argtype = TREE_VALUE (t);
+           enum 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))
+               && reg
+               && REG_P (reg)
+               && GET_MODE (reg) == mode
+               && GET_MODE_CLASS (mode) == MODE_INT
+               && REG_P (x)
+               && REGNO (x) == REGNO (reg)
+               && GET_MODE (x) == mode
+               && item)
+             {
+               enum machine_mode indmode
+                 = TYPE_MODE (TREE_TYPE (argtype));
+               rtx mem = gen_rtx_MEM (indmode, x);
+               cselib_val *val = cselib_lookup (mem, indmode, 0, VOIDmode);
+               if (val && cselib_preserved_value_p (val))
+                 {
+                   item = gen_rtx_CONCAT (indmode, mem, val->val_rtx);
+                   call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item,
+                                                       call_arguments);
+                 }
+               else
+                 {
+                   struct elt_loc_list *l;
+                   tree initial;
+
+                   /* Try harder, when passing address of a constant
+                      pool integer it can be easily read back.  */
+                   item = XEXP (item, 1);
+                   if (GET_CODE (item) == SUBREG)
+                     item = SUBREG_REG (item);
+                   gcc_assert (GET_CODE (item) == VALUE);
+                   val = CSELIB_VAL_PTR (item);
+                   for (l = val->locs; l; l = l->next)
+                     if (GET_CODE (l->loc) == SYMBOL_REF
+                         && TREE_CONSTANT_POOL_ADDRESS_P (l->loc)
+                         && SYMBOL_REF_DECL (l->loc)
+                         && DECL_INITIAL (SYMBOL_REF_DECL (l->loc)))
+                       {
+                         initial = DECL_INITIAL (SYMBOL_REF_DECL (l->loc));
+                         if (host_integerp (initial, 0))
+                           {
+                             item = GEN_INT (tree_low_cst (initial, 0));
+                             item = gen_rtx_CONCAT (indmode, mem, item);
+                             call_arguments
+                               = gen_rtx_EXPR_LIST (VOIDmode, item,
+                                                    call_arguments);
+                           }
+                         break;
+                       }
+                 }
+             }
+           targetm.calls.function_arg_advance (args_so_far, mode,
+                                               argtype, true);
+           t = TREE_CHAIN (t);
+         }
+      }
+
+  /* Add debug arguments.  */
+  if (fndecl
+      && TREE_CODE (fndecl) == FUNCTION_DECL
+      && DECL_HAS_DEBUG_ARGS_P (fndecl))
+    {
+      VEC(tree, gc) **debug_args = decl_debug_args_lookup (fndecl);
+      if (debug_args)
+       {
+         unsigned int ix;
+         tree param;
+         for (ix = 0; VEC_iterate (tree, *debug_args, ix, param); ix += 2)
+           {
+             rtx item;
+             tree dtemp = VEC_index (tree, *debug_args, ix + 1);
+             enum machine_mode mode = DECL_MODE (dtemp);
+             item = gen_rtx_DEBUG_PARAMETER_REF (mode, param);
+             item = gen_rtx_CONCAT (mode, item, DECL_RTL (dtemp));
+             call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item,
+                                                 call_arguments);
+           }
+       }
+    }
+
+  /* Reverse call_arguments chain.  */
+  prev = NULL_RTX;
+  for (cur = call_arguments; cur; cur = next)
+    {
+      next = XEXP (cur, 1);
+      XEXP (cur, 1) = prev;
+      prev = cur;
+    }
+  call_arguments = prev;
+
+  x = PATTERN (insn);
+  if (GET_CODE (x) == PARALLEL)
+    x = XVECEXP (x, 0, 0);
+  if (GET_CODE (x) == SET)
+    x = SET_SRC (x);
+  if (GET_CODE (x) == CALL && MEM_P (XEXP (x, 0)))
+    {
+      x = XEXP (XEXP (x, 0), 0);
+      if (GET_CODE (x) == SYMBOL_REF)
+       /* Don't record anything.  */;
+      else if (CONSTANT_P (x))
+       {
+         x = gen_rtx_CONCAT (GET_MODE (x) == VOIDmode ? Pmode : GET_MODE (x),
+                             pc_rtx, x);
+         call_arguments
+           = gen_rtx_EXPR_LIST (VOIDmode, x, call_arguments);
+       }
+      else
+       {
+         cselib_val *val = cselib_lookup (x, GET_MODE (x), 0, VOIDmode);
+         if (val && cselib_preserved_value_p (val))
+           {
+             x = gen_rtx_CONCAT (GET_MODE (x), pc_rtx, val->val_rtx);
+             call_arguments
+               = gen_rtx_EXPR_LIST (VOIDmode, x, call_arguments);
+           }
+       }
+    }
+  if (this_arg)
+    {
+      enum machine_mode mode
+       = TYPE_MODE (TREE_TYPE (OBJ_TYPE_REF_EXPR (obj_type_ref)));
+      rtx clobbered = gen_rtx_MEM (mode, this_arg);
+      HOST_WIDE_INT token
+       = tree_low_cst (OBJ_TYPE_REF_TOKEN (obj_type_ref), 0);
+      if (token)
+       clobbered = plus_constant (clobbered, token * GET_MODE_SIZE (mode));
+      clobbered = gen_rtx_MEM (mode, clobbered);
+      x = gen_rtx_CONCAT (mode, gen_rtx_CLOBBER (VOIDmode, pc_rtx), clobbered);
+      call_arguments
+       = gen_rtx_EXPR_LIST (VOIDmode, x, call_arguments);
+    }
+}
+
 /* Callback for cselib_record_sets_hook, that records as micro
    operations uses and stores in an insn after cselib_record_sets has
    analyzed the sets in an insn, but before it modifies the stored
@@ -5611,7 +6023,8 @@ add_with_sets (rtx insn, struct cselib_set *sets, int n_sets)
 
       mo.type = MO_CALL;
       mo.insn = insn;
-      mo.u.loc = NULL_RTX;
+      mo.u.loc = call_arguments;
+      call_arguments = NULL_RTX;
 
       if (dump_file && (dump_flags & TDF_DETAILS))
        log_op_type (PATTERN (insn), bb, insn, mo.type, dump_file);
@@ -6725,7 +7138,7 @@ set_variable_part (dataflow_set *set, rtx loc,
       if (!slot)
        slot = shared_hash_find_slot_unshare (&set->vars, dv, iopt);
     }
-  slot = set_slot_part (set, loc, slot, dv, offset, initialized, set_src);
+  set_slot_part (set, loc, slot, dv, offset, initialized, set_src);
 }
 
 /* Remove all recorded register locations for the given variable part
@@ -6806,7 +7219,7 @@ clobber_variable_part (dataflow_set *set, rtx loc, decl_or_value dv,
   if (!slot)
     return;
 
-  slot = clobber_slot_part (set, loc, slot, offset, set_src);
+  clobber_slot_part (set, loc, slot, offset, set_src);
 }
 
 /* Delete the part of variable's location from dataflow set SET.  The
@@ -6905,7 +7318,7 @@ delete_variable_part (dataflow_set *set, rtx loc, decl_or_value dv,
   if (!slot)
     return;
 
-  slot = delete_slot_part (set, loc, slot, offset);
+  delete_slot_part (set, loc, slot, offset);
 }
 
 /* Structure for passing some other parameters to function
@@ -6927,6 +7340,10 @@ struct expand_loc_callback_data
      whose cur_loc has been already recomputed during current
      emit_notes_for_changes call.  */
   bool cur_loc_changed;
+
+  /* True if cur_loc should be ignored and any possible location
+     returned.  */
+  bool ignore_cur_loc;
 };
 
 /* Callback for cselib_expand_value, that looks for expressions
@@ -6940,6 +7357,7 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
     = (struct expand_loc_callback_data *) data;
   bool dummy = elcd->dummy;
   bool cur_loc_changed = elcd->cur_loc_changed;
+  rtx cur_loc;
   decl_or_value dv;
   variable var;
   location_chain loc;
@@ -7014,7 +7432,7 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
   VALUE_RECURSED_INTO (x) = true;
   result = NULL;
 
-  if (var->var_part[0].cur_loc)
+  if (var->var_part[0].cur_loc && !elcd->ignore_cur_loc)
     {
       if (dummy)
        {
@@ -7029,12 +7447,16 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
                                             vt_expand_loc_callback, data);
       if (result)
        set_dv_changed (dv, false);
+      cur_loc = var->var_part[0].cur_loc;
     }
-  if (!result && dv_changed_p (dv))
+  else
+    cur_loc = NULL_RTX;
+  if (!result && (dv_changed_p (dv) || elcd->ignore_cur_loc))
     {
-      set_dv_changed (dv, false);
+      if (!elcd->ignore_cur_loc)
+       set_dv_changed (dv, false);
       for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
-       if (loc->loc == var->var_part[0].cur_loc)
+       if (loc->loc == cur_loc)
          continue;
        else if (dummy)
          {
@@ -7056,7 +7478,8 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
          }
       if (dummy && (result || var->var_part[0].cur_loc))
        var->cur_loc_changed = true;
-      var->var_part[0].cur_loc = loc ? loc->loc : NULL_RTX;
+      if (!elcd->ignore_cur_loc)
+       var->var_part[0].cur_loc = loc ? loc->loc : NULL_RTX;
     }
   if (dummy)
     {
@@ -7077,7 +7500,7 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
    tables.  */
 
 static rtx
-vt_expand_loc (rtx loc, htab_t vars)
+vt_expand_loc (rtx loc, htab_t vars, bool ignore_cur_loc)
 {
   struct expand_loc_callback_data data;
 
@@ -7087,7 +7510,8 @@ vt_expand_loc (rtx loc, htab_t vars)
   data.vars = vars;
   data.dummy = false;
   data.cur_loc_changed = false;
-  loc = cselib_expand_value_rtx_cb (loc, scratch_regs, 8,
+  data.ignore_cur_loc = ignore_cur_loc;
+  loc = cselib_expand_value_rtx_cb (loc, scratch_regs, EXPR_DEPTH,
                                    vt_expand_loc_callback, &data);
 
   if (loc && MEM_P (loc))
@@ -7108,7 +7532,8 @@ vt_expand_loc_dummy (rtx loc, htab_t vars, bool *pcur_loc_changed)
   data.vars = vars;
   data.dummy = true;
   data.cur_loc_changed = false;
-  ret = cselib_dummy_expand_value_rtx_cb (loc, scratch_regs, 8,
+  data.ignore_cur_loc = false;
+  ret = cselib_dummy_expand_value_rtx_cb (loc, scratch_regs, EXPR_DEPTH,
                                          vt_expand_loc_callback, &data);
   *pcur_loc_changed = data.cur_loc_changed;
   return ret;
@@ -7178,7 +7603,7 @@ emit_note_insn_var_location (void **varp, void *data)
          complete = false;
          continue;
        }
-      loc2 = vt_expand_loc (var->var_part[i].cur_loc, vars);
+      loc2 = vt_expand_loc (var->var_part[i].cur_loc, vars, false);
       if (!loc2)
        {
          complete = false;
@@ -7208,7 +7633,7 @@ emit_note_insn_var_location (void **varp, void *data)
          && mode == GET_MODE (var->var_part[j].cur_loc)
          && (REG_P (loc[n_var_parts]) || MEM_P (loc[n_var_parts]))
          && last_limit == var->var_part[j].offset
-         && (loc2 = vt_expand_loc (var->var_part[j].cur_loc, vars))
+         && (loc2 = vt_expand_loc (var->var_part[j].cur_loc, vars, false))
          && GET_CODE (loc[n_var_parts]) == GET_CODE (loc2))
        {
          rtx new_loc = NULL;
@@ -7642,6 +8067,23 @@ emit_notes_for_differences (rtx insn, dataflow_set *old_set,
   emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN, new_set->vars);
 }
 
+/* Return the next insn after INSN that is not a NOTE_INSN_VAR_LOCATION.  */
+
+static rtx
+next_non_note_insn_var_location (rtx insn)
+{
+  while (insn)
+    {
+      insn = NEXT_INSN (insn);
+      if (insn == 0
+         || !NOTE_P (insn)
+         || NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION)
+       break;
+    }
+
+  return insn;
+}
+
 /* Emit the notes for changes of location parts in the basic block BB.  */
 
 static void
@@ -7656,12 +8098,41 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
   FOR_EACH_VEC_ELT (micro_operation, VTI (bb)->mos, i, mo)
     {
       rtx insn = mo->insn;
+      rtx next_insn = next_non_note_insn_var_location (insn);
 
       switch (mo->type)
        {
          case MO_CALL:
            dataflow_set_clear_at_call (set);
            emit_notes_for_changes (insn, EMIT_NOTE_AFTER_CALL_INSN, set->vars);
+           {
+             rtx arguments = mo->u.loc, *p = &arguments, note;
+             while (*p)
+               {
+                 XEXP (XEXP (*p, 0), 1)
+                   = vt_expand_loc (XEXP (XEXP (*p, 0), 1),
+                                    shared_hash_htab (set->vars), true);
+                 /* If expansion is successful, keep it in the list.  */
+                 if (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)
+                          && REG_P (XEXP (XEXP (*p, 0), 0))
+                          && MEM_P (XEXP (XEXP (XEXP (*p, 1), 0), 0))
+                          && REG_P (XEXP (XEXP (XEXP (XEXP (*p, 1), 0), 0),
+                                          0))
+                          && REGNO (XEXP (XEXP (*p, 0), 0))
+                             == REGNO (XEXP (XEXP (XEXP (XEXP (*p, 1), 0),
+                                                   0), 0)))
+                   *p = XEXP (XEXP (*p, 1), 1);
+                 /* Just drop this item.  */
+                 else
+                   *p = XEXP (*p, 1);
+               }
+             note = emit_note_after (NOTE_INSN_CALL_ARG_LOCATION, insn);
+             NOTE_VAR_LOCATION (note) = arguments;
+           }
            break;
 
          case MO_USE:
@@ -7834,7 +8305,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
                val_store (set, XEXP (reverse, 0), XEXP (reverse, 1),
                           insn, false);
 
-             emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN,
+             emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
                                      set->vars);
            }
            break;
@@ -7857,7 +8328,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
                var_mem_delete_and_set (set, loc, true, VAR_INIT_STATUS_INITIALIZED,
                                        set_src);
 
-             emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN,
+             emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
                                      set->vars);
            }
            break;
@@ -7882,7 +8353,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
              else
                var_mem_delete_and_set (set, loc, false, src_status, set_src);
 
-             emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN,
+             emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
                                      set->vars);
            }
            break;
@@ -7909,7 +8380,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
              else
                var_mem_delete (set, loc, true);
 
-             emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN,
+             emit_notes_for_changes (next_insn, EMIT_NOTE_BEFORE_INSN,
                                      set->vars);
            }
            break;
@@ -8018,6 +8489,39 @@ vt_get_decl_and_offset (rtx rtl, tree *declp, HOST_WIDE_INT *offsetp)
   return false;
 }
 
+/* Helper function for vt_add_function_parameter.  RTL is
+   the expression and VAL corresponding cselib_val pointer
+   for which ENTRY_VALUE should be created.  */
+
+static void
+create_entry_value (rtx rtl, cselib_val *val)
+{
+  cselib_val *val2;
+  struct elt_loc_list *el;
+  el = (struct elt_loc_list *) ggc_alloc_cleared_atomic (sizeof (*el));
+  el->loc = gen_rtx_ENTRY_VALUE (GET_MODE (rtl));
+  ENTRY_VALUE_EXP (el->loc) = rtl;
+  val2 = cselib_lookup_from_insn (el->loc, GET_MODE (rtl), true,
+                                 VOIDmode, get_insns ());
+  el->next = val->locs;
+  el->setting_insn = get_insns ();
+  val->locs = el;
+  if (val2
+      && val2 != val
+      && val2->locs
+      && rtx_equal_p (val2->locs->loc, el->loc))
+    {
+      struct elt_loc_list *el2;
+
+      preserve_value (val2);
+      el2 = (struct elt_loc_list *) ggc_alloc_cleared_atomic (sizeof (*el2));
+      el2->next = val2->locs;
+      el2->loc = val->val_rtx;
+      el2->setting_insn = get_insns ();
+      val2->locs = el2;
+    }
+}
+
 /* Insert function parameter PARM in IN and OUT sets of ENTRY_BLOCK.  */
 
 static void
@@ -8040,6 +8544,61 @@ vt_add_function_parameter (tree parm)
   if (GET_MODE (decl_rtl) == BLKmode || GET_MODE (incoming) == BLKmode)
     return;
 
+  /* If there is a DRAP register, rewrite the incoming location of parameters
+     passed on the stack into MEMs based on the argument pointer, as the DRAP
+     register can be reused for other purposes and we do not track locations
+     based on generic registers.  But the prerequisite is that this argument
+     pointer be also the virtual CFA pointer, see vt_initialize.  */
+  if (MEM_P (incoming)
+      && stack_realign_drap
+      && arg_pointer_rtx == cfa_base_rtx
+      && (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)))))
+    {
+      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 (arg_pointer_rtx, off));
+    }
+
+#ifdef HAVE_window_save
+  /* DECL_INCOMING_RTL uses the INCOMING_REGNO of parameter registers.
+     If the target machine has an explicit window save instruction, the
+     actual entry value is the corresponding OUTGOING_REGNO instead.  */
+  if (REG_P (incoming)
+      && HARD_REGISTER_P (incoming)
+      && OUTGOING_REGNO (REGNO (incoming)) != REGNO (incoming))
+    {
+      parm_reg_t *p
+       = VEC_safe_push (parm_reg_t, gc, windowed_parm_regs, NULL);
+      p->incoming = incoming;
+      incoming
+       = gen_rtx_REG_offset (incoming, GET_MODE (incoming),
+                             OUTGOING_REGNO (REGNO (incoming)), 0);
+      p->outgoing = incoming;
+    }
+  else if (MEM_P (incoming)
+          && REG_P (XEXP (incoming, 0))
+          && HARD_REGISTER_P (XEXP (incoming, 0)))
+    {
+      rtx reg = XEXP (incoming, 0);
+      if (OUTGOING_REGNO (REGNO (reg)) != REGNO (reg))
+       {
+         parm_reg_t *p
+           = VEC_safe_push (parm_reg_t, gc, windowed_parm_regs, NULL);
+         p->incoming = reg;
+         reg = gen_raw_REG (GET_MODE (reg), OUTGOING_REGNO (REGNO (reg)));
+         p->outgoing = reg;
+         incoming = replace_equiv_address_nv (incoming, reg);
+       }
+    }
+#endif
+
   if (!vt_get_decl_and_offset (incoming, &decl, &offset))
     {
       if (REG_P (incoming) || MEM_P (incoming))
@@ -8095,8 +8654,8 @@ vt_add_function_parameter (tree parm)
       if (offset)
        return;
 
-      val = cselib_lookup (var_lowpart (mode, incoming), mode, true,
-                          VOIDmode);
+      val = cselib_lookup_from_insn (var_lowpart (mode, incoming), mode, true,
+                                    VOIDmode, get_insns ());
 
       /* ??? Float-typed values in memory are not handled by
         cselib.  */
@@ -8117,6 +8676,25 @@ vt_add_function_parameter (tree parm)
                         incoming);
       set_variable_part (out, incoming, dv, offset,
                         VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
+      if (dv_is_value_p (dv))
+       {
+         cselib_val *val = CSELIB_VAL_PTR (dv_as_value (dv));
+         create_entry_value (incoming, val);
+         if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE
+             && INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (parm))))
+           {
+             enum machine_mode indmode
+               = TYPE_MODE (TREE_TYPE (TREE_TYPE (parm)));
+             rtx mem = gen_rtx_MEM (indmode, incoming);
+             val = cselib_lookup_from_insn (mem, indmode, true,
+                                            VOIDmode, get_insns ());
+             if (val)
+               {
+                 preserve_value (val);
+                 create_entry_value (mem, val);
+               }
+           }
+       }
     }
   else if (MEM_P (incoming))
     {
@@ -8150,13 +8728,6 @@ vt_add_function_parameters (void)
          && DECL_NAMELESS (vexpr))
        vt_add_function_parameter (vexpr);
     }
-
-  if (MAY_HAVE_DEBUG_INSNS)
-    {
-      cselib_preserve_only_values ();
-      cselib_reset_table (cselib_get_next_uid ());
-    }
-
 }
 
 /* Return true if INSN in the prologue initializes hard_frame_pointer_rtx.  */
@@ -8184,6 +8755,23 @@ fp_setter (rtx insn)
   return false;
 }
 
+/* Gather all registers used for passing arguments to other functions
+   called from the current routine.  */
+
+static void
+note_register_arguments (rtx insn)
+{
+  rtx link, x;
+
+  for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
+    if (GET_CODE (XEXP (link, 0)) == USE)
+      {
+       x = XEXP (XEXP (link, 0), 0);
+       if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
+         SET_HARD_REG_BIT (argument_reg_set, REGNO (x));
+      }
+}
+
 /* Initialize cfa_base_rtx, create a preserved VALUE for it and
    ensure it isn't flushed during cselib_reset_table.
    Can be called only if frame_pointer_rtx resp. arg_pointer_rtx
@@ -8212,9 +8800,11 @@ vt_init_cfa_base (void)
 
   /* Tell alias analysis that cfa_base_rtx should share
      find_base_term value with stack pointer or hard frame pointer.  */
-  vt_equate_reg_base_value (cfa_base_rtx,
-                           frame_pointer_needed
-                           ? hard_frame_pointer_rtx : stack_pointer_rtx);
+  if (!frame_pointer_needed)
+    vt_equate_reg_base_value (cfa_base_rtx, stack_pointer_rtx);
+  else if (!crtl->stack_realign_tried)
+    vt_equate_reg_base_value (cfa_base_rtx, hard_frame_pointer_rtx);
+
   val = cselib_lookup_from_insn (cfa_base_rtx, GET_MODE (cfa_base_rtx), 1,
                                 VOIDmode, get_insns ());
   preserve_value (val);
@@ -8230,7 +8820,7 @@ vt_init_cfa_base (void)
 static bool
 vt_initialize (void)
 {
-  basic_block bb, prologue_bb = NULL;
+  basic_block bb, prologue_bb = single_succ (ENTRY_BLOCK_PTR);
   HOST_WIDE_INT fp_cfa_offset = -1;
 
   alloc_aux_for_blocks (sizeof (struct variable_tracking_info_def));
@@ -8286,6 +8876,18 @@ vt_initialize (void)
       valvar_pool = NULL;
     }
 
+  CLEAR_HARD_REG_SET (argument_reg_set);
+
+  /* In order to factor out the adjustments made to the stack pointer or to
+     the hard frame pointer and thus be able to use DW_OP_fbreg operations
+     instead of individual location lists, we're going to rewrite MEMs based
+     on them into MEMs based on the CFA by de-eliminating stack_pointer_rtx
+     or hard_frame_pointer_rtx to the virtual CFA pointer frame_pointer_rtx
+     resp. arg_pointer_rtx.  We can do this either when there is no frame
+     pointer in the function and stack adjustments are consistent for all
+     basic blocks or when there is a frame pointer and no stack realignment.
+     But we first have to check that frame_pointer_rtx resp. arg_pointer_rtx
+     has been eliminated.  */
   if (!frame_pointer_needed)
     {
       rtx reg, elim;
@@ -8328,13 +8930,50 @@ vt_initialize (void)
            }
          if (elim != hard_frame_pointer_rtx)
            fp_cfa_offset = -1;
-         else
-           prologue_bb = single_succ (ENTRY_BLOCK_PTR);
        }
+      else
+       fp_cfa_offset = -1;
+    }
+
+  /* If the stack is realigned and a DRAP register is used, we're going to
+     rewrite MEMs based on it representing incoming locations of parameters
+     passed on the stack into MEMs based on the argument pointer.  Although
+     we aren't going to rewrite other MEMs, we still need to initialize the
+     virtual CFA pointer in order to ensure that the argument pointer will
+     be seen as a constant throughout the function.
+
+     ??? This doesn't work if FRAME_POINTER_CFA_OFFSET is defined.  */
+  else if (stack_realign_drap)
+    {
+      rtx reg, elim;
+
+#ifdef FRAME_POINTER_CFA_OFFSET
+      reg = frame_pointer_rtx;
+#else
+      reg = arg_pointer_rtx;
+#endif
+      elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+      if (elim != reg)
+       {
+         if (GET_CODE (elim) == PLUS)
+           elim = XEXP (elim, 0);
+         if (elim == hard_frame_pointer_rtx)
+           vt_init_cfa_base ();
+       }
+    }
+
+  if (frame_pointer_needed)
+    {
+      rtx insn;
+      for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+       if (CALL_P (insn))
+         note_register_arguments (insn);
     }
 
   hard_frame_pointer_adjustment = -1;
 
+  vt_add_function_parameters ();
+
   FOR_EACH_BB (bb)
     {
       rtx insn;
@@ -8395,6 +9034,8 @@ vt_initialize (void)
                  adjust_insn (bb, insn);
                  if (MAY_HAVE_DEBUG_INSNS)
                    {
+                     if (CALL_P (insn))
+                       prepare_call_arguments (bb, insn);
                      cselib_process_insn (insn);
                      if (dump_file && (dump_flags & TDF_DETAILS))
                        {
@@ -8421,6 +9062,7 @@ vt_initialize (void)
                    }
 
                  if (bb == prologue_bb
+                     && fp_cfa_offset != -1
                      && hard_frame_pointer_adjustment == -1
                      && RTX_FRAME_RELATED_P (insn)
                      && fp_setter (insn))
@@ -8445,7 +9087,6 @@ vt_initialize (void)
 
   hard_frame_pointer_adjustment = -1;
   VTI (ENTRY_BLOCK_PTR)->flooded = true;
-  vt_add_function_parameters ();
   cfa_base_rtx = NULL_RTX;
   return true;
 }
@@ -8523,6 +9164,8 @@ vt_finalize (void)
       scratch_regs = NULL;
     }
 
+  VEC_free (parm_reg_t, gc, windowed_parm_regs);
+
   if (vui_vec)
     XDELETEVEC (vui_vec);
   vui_vec = NULL;
@@ -8611,7 +9254,7 @@ variable_tracking_main (void)
 static bool
 gate_handle_var_tracking (void)
 {
-  return (flag_var_tracking);
+  return (flag_var_tracking && !targetm.delay_vartrack);
 }
 
 
@@ -8631,6 +9274,6 @@ struct rtl_opt_pass pass_variable_tracking =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_dump_func | TODO_verify_rtl_sharing/* todo_flags_finish */
+  TODO_verify_rtl_sharing               /* todo_flags_finish */
  }
 };