OSDN Git Service

2010-12-06 Jerry DeLisle <jvdelisle@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / var-tracking.c
index ece7790..35ca1cb 100644 (file)
@@ -92,6 +92,7 @@
 #include "tm.h"
 #include "rtl.h"
 #include "tree.h"
+#include "tm_p.h"
 #include "hard-reg-set.h"
 #include "basic-block.h"
 #include "flags.h"
 #include "tree-flow.h"
 #include "cselib.h"
 #include "target.h"
-#include "toplev.h"
 #include "params.h"
 #include "diagnostic.h"
+#include "tree-pretty-print.h"
 #include "pointer-set.h"
+#include "recog.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.
@@ -169,6 +171,13 @@ typedef struct micro_operation_def
   /* Type of micro operation.  */
   enum micro_operation_type type;
 
+  /* The instruction which the micro operation is in, for MO_USE,
+     MO_USE_NO_VAR, MO_CALL and MO_ADJUST, or the subsequent
+     instruction or note in the original flow (before any var-tracking
+     notes are inserted, to simplify emission of notes), for MO_SET
+     and MO_CLOBBER.  */
+  rtx insn;
+
   union {
     /* Location.  For MO_SET and MO_COPY, this is the SET that
        performs the assignment, if known, otherwise it is the target
@@ -181,15 +190,11 @@ typedef struct micro_operation_def
     /* Stack adjustment.  */
     HOST_WIDE_INT adjust;
   } u;
-
-  /* The instruction which the micro operation is in, for MO_USE,
-     MO_USE_NO_VAR, MO_CALL and MO_ADJUST, or the subsequent
-     instruction or note in the original flow (before any var-tracking
-     notes are inserted, to simplify emission of notes), for MO_SET
-     and MO_CLOBBER.  */
-  rtx insn;
 } micro_operation;
 
+DEF_VEC_O(micro_operation);
+DEF_VEC_ALLOC_O(micro_operation,heap);
+
 /* A declaration of a variable, or an RTL value being handled like a
    declaration.  */
 typedef void *decl_or_value;
@@ -258,11 +263,8 @@ typedef struct dataflow_set_def
    needed for variable tracking.  */
 typedef struct variable_tracking_info_def
 {
-  /* Number of micro operations stored in the MOS array.  */
-  int n_mos;
-
-  /* The array of micro operations.  */
-  micro_operation *mos;
+  /* The vector of micro operations.  */
+  VEC(micro_operation, heap) *mos;
 
   /* The IN and OUT set for dataflow analysis.  */
   dataflow_set in;
@@ -405,9 +407,7 @@ static void stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
                                          HOST_WIDE_INT *);
 static void insn_stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
                                               HOST_WIDE_INT *);
-static void bb_stack_adjust_offset (basic_block);
 static bool vt_stack_adjustments (void);
-static rtx adjust_stack_reference (rtx, HOST_WIDE_INT);
 static hashval_t variable_htab_hash (const void *);
 static int variable_htab_eq (const void *, const void *);
 static void variable_htab_free (void *);
@@ -421,7 +421,6 @@ static void attrs_list_union (attrs *, attrs);
 
 static void **unshare_variable (dataflow_set *set, void **slot, variable var,
                                enum var_init_status);
-static int vars_copy_1 (void **, void *);
 static void vars_copy (htab_t, htab_t);
 static tree var_debug_decl (tree);
 static void var_reg_set (dataflow_set *, rtx, enum var_init_status, rtx);
@@ -438,7 +437,6 @@ static void dataflow_set_init (dataflow_set *);
 static void dataflow_set_clear (dataflow_set *);
 static void dataflow_set_copy (dataflow_set *, dataflow_set *);
 static int variable_union_info_cmp_pos (const void *, const void *);
-static int variable_union (void **, void *);
 static void dataflow_set_union (dataflow_set *, dataflow_set *);
 static location_chain find_loc_in_1pdv (rtx, variable, htab_t);
 static bool canon_value_cmp (rtx, rtx);
@@ -446,16 +444,12 @@ static int loc_cmp (rtx, rtx);
 static bool variable_part_different_p (variable_part *, variable_part *);
 static bool onepart_variable_different_p (variable, variable);
 static bool variable_different_p (variable, variable);
-static int dataflow_set_different_1 (void **, void *);
 static bool dataflow_set_different (dataflow_set *, dataflow_set *);
 static void dataflow_set_destroy (dataflow_set *);
 
 static bool contains_symbol_ref (rtx);
 static bool track_expr_p (tree, bool);
 static bool same_variable_part_p (rtx, tree, HOST_WIDE_INT);
-static int count_uses (rtx *, void *);
-static void count_uses_1 (rtx *, void *);
-static void count_stores (rtx, const_rtx, void *);
 static int add_uses (rtx *, void *);
 static void add_uses_1 (rtx *, void *);
 static void add_stores (rtx, const_rtx, void *);
@@ -493,7 +487,7 @@ 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 void vt_initialize (void);
+static bool vt_initialize (void);
 static void vt_finalize (void);
 
 /* Given a SET, calculate the amount of stack adjustment it contains
@@ -620,31 +614,6 @@ insn_stack_adjust_offset_pre_post (rtx insn, HOST_WIDE_INT *pre,
     }
 }
 
-/* Compute stack adjustment in basic block BB.  */
-
-static void
-bb_stack_adjust_offset (basic_block bb)
-{
-  HOST_WIDE_INT offset;
-  int i;
-
-  offset = VTI (bb)->in.stack_adjust;
-  for (i = 0; i < VTI (bb)->n_mos; i++)
-    {
-      if (VTI (bb)->mos[i].type == MO_ADJUST)
-       offset += VTI (bb)->mos[i].u.adjust;
-      else if (VTI (bb)->mos[i].type != MO_CALL)
-       {
-         if (MEM_P (VTI (bb)->mos[i].u.loc))
-           {
-             VTI (bb)->mos[i].u.loc
-               = adjust_stack_reference (VTI (bb)->mos[i].u.loc, -offset);
-           }
-       }
-    }
-  VTI (bb)->out.stack_adjust = offset;
-}
-
 /* Compute stack adjustments for all blocks by traversing DFS tree.
    Return true when the adjustments on all incoming edges are consistent.
    Heavily borrowed from pre_and_rev_post_order_compute.  */
@@ -657,6 +626,7 @@ vt_stack_adjustments (void)
 
   /* Initialize entry block.  */
   VTI (ENTRY_BLOCK_PTR)->visited = true;
+  VTI (ENTRY_BLOCK_PTR)->in.stack_adjust = INCOMING_FRAME_SP_OFFSET;
   VTI (ENTRY_BLOCK_PTR)->out.stack_adjust = INCOMING_FRAME_SP_OFFSET;
 
   /* Allocate stack for back-tracking up CFG.  */
@@ -680,9 +650,22 @@ vt_stack_adjustments (void)
       /* Check if the edge destination has been visited yet.  */
       if (!VTI (dest)->visited)
        {
+         rtx insn;
+         HOST_WIDE_INT pre, post, offset;
          VTI (dest)->visited = true;
-         VTI (dest)->in.stack_adjust = VTI (src)->out.stack_adjust;
-         bb_stack_adjust_offset (dest);
+         VTI (dest)->in.stack_adjust = offset = VTI (src)->out.stack_adjust;
+
+         if (dest != EXIT_BLOCK_PTR)
+           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;
+               }
+
+         VTI (dest)->out.stack_adjust = offset;
 
          if (EDGE_COUNT (dest->succs) > 0)
            /* Since the DEST node has been visited for the first
@@ -711,28 +694,363 @@ vt_stack_adjustments (void)
   return true;
 }
 
-/* Adjust stack reference MEM by ADJUSTMENT bytes and make it relative
-   to the argument pointer.  Return the new rtx.  */
+/* arg_pointer_rtx resp. frame_pointer_rtx if stack_pointer_rtx or
+   hard_frame_pointer_rtx is being mapped to it and offset for it.  */
+static rtx cfa_base_rtx;
+static HOST_WIDE_INT cfa_base_offset;
+
+/* Compute a CFA-based value for the stack pointer.  */
+
+static inline rtx
+compute_cfa_pointer (HOST_WIDE_INT adjustment)
+{
+  return plus_constant (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;
+
+/* Data for adjust_mems callback.  */
+
+struct adjust_mem_data
+{
+  bool store;
+  enum machine_mode mem_mode;
+  HOST_WIDE_INT stack_adjust;
+  rtx side_effects;
+};
+
+/* Helper for adjust_mems.  Return 1 if *loc is unsuitable for
+   transformation of wider mode arithmetics to narrower mode,
+   -1 if it is suitable and subexpressions shouldn't be
+   traversed and 0 if it is suitable and subexpressions should
+   be traversed.  Called through for_each_rtx.  */
+
+static int
+use_narrower_mode_test (rtx *loc, void *data)
+{
+  rtx subreg = (rtx) data;
+
+  if (CONSTANT_P (*loc))
+    return -1;
+  switch (GET_CODE (*loc))
+    {
+    case REG:
+      if (cselib_lookup (*loc, GET_MODE (SUBREG_REG (subreg)), 0))
+       return 1;
+      return -1;
+    case PLUS:
+    case MINUS:
+    case MULT:
+      return 0;
+    case ASHIFT:
+      if (for_each_rtx (&XEXP (*loc, 0), use_narrower_mode_test, data))
+       return 1;
+      else
+       return -1;
+    default:
+      return 1;
+    }
+}
+
+/* Transform X into narrower mode MODE from wider mode WMODE.  */
 
 static rtx
-adjust_stack_reference (rtx mem, HOST_WIDE_INT adjustment)
+use_narrower_mode (rtx x, enum machine_mode mode, enum machine_mode wmode)
 {
-  rtx addr, cfa, tmp;
+  rtx op0, op1;
+  if (CONSTANT_P (x))
+    return lowpart_subreg (mode, x, wmode);
+  switch (GET_CODE (x))
+    {
+    case REG:
+      return lowpart_subreg (mode, x, wmode);
+    case PLUS:
+    case MINUS:
+    case MULT:
+      op0 = use_narrower_mode (XEXP (x, 0), mode, wmode);
+      op1 = use_narrower_mode (XEXP (x, 1), mode, wmode);
+      return simplify_gen_binary (GET_CODE (x), mode, op0, op1);
+    case ASHIFT:
+      op0 = use_narrower_mode (XEXP (x, 0), mode, wmode);
+      return simplify_gen_binary (ASHIFT, mode, op0, XEXP (x, 1));
+    default:
+      gcc_unreachable ();
+    }
+}
 
-#ifdef FRAME_POINTER_CFA_OFFSET
-  adjustment -= FRAME_POINTER_CFA_OFFSET (current_function_decl);
-  cfa = plus_constant (frame_pointer_rtx, adjustment);
-#else
-  adjustment -= ARG_POINTER_CFA_OFFSET (current_function_decl);
-  cfa = plus_constant (arg_pointer_rtx, adjustment);
-#endif
+/* Helper function for adjusting used MEMs.  */
+
+static rtx
+adjust_mems (rtx loc, const_rtx old_rtx, void *data)
+{
+  struct adjust_mem_data *amd = (struct adjust_mem_data *) data;
+  rtx mem, addr = loc, tem;
+  enum machine_mode mem_mode_save;
+  bool store_save;
+  switch (GET_CODE (loc))
+    {
+    case REG:
+      /* Don't do any sp or fp replacements outside of MEM addresses
+         on the LHS.  */
+      if (amd->mem_mode == VOIDmode && amd->store)
+       return loc;
+      if (loc == stack_pointer_rtx
+         && !frame_pointer_needed
+         && cfa_base_rtx)
+       return compute_cfa_pointer (amd->stack_adjust);
+      else if (loc == hard_frame_pointer_rtx
+              && frame_pointer_needed
+              && hard_frame_pointer_adjustment != -1
+              && cfa_base_rtx)
+       return compute_cfa_pointer (hard_frame_pointer_adjustment);
+      return loc;
+    case MEM:
+      mem = loc;
+      if (!amd->store)
+       {
+         mem = targetm.delegitimize_address (mem);
+         if (mem != loc && !MEM_P (mem))
+           return simplify_replace_fn_rtx (mem, old_rtx, adjust_mems, data);
+       }
+
+      addr = XEXP (mem, 0);
+      mem_mode_save = amd->mem_mode;
+      amd->mem_mode = GET_MODE (mem);
+      store_save = amd->store;
+      amd->store = false;
+      addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
+      amd->store = store_save;
+      amd->mem_mode = mem_mode_save;
+      if (mem == loc)
+       addr = targetm.delegitimize_address (addr);
+      if (addr != XEXP (mem, 0))
+       mem = replace_equiv_address_nv (mem, addr);
+      if (!amd->store)
+       mem = avoid_constant_pool_reference (mem);
+      return mem;
+    case PRE_INC:
+    case PRE_DEC:
+      addr = gen_rtx_PLUS (GET_MODE (loc), XEXP (loc, 0),
+                          GEN_INT (GET_CODE (loc) == PRE_INC
+                                   ? GET_MODE_SIZE (amd->mem_mode)
+                                   : -GET_MODE_SIZE (amd->mem_mode)));
+    case POST_INC:
+    case POST_DEC:
+      if (addr == loc)
+       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 ((GET_CODE (loc) == PRE_INC
+                                    || GET_CODE (loc) == POST_INC)
+                                   ? GET_MODE_SIZE (amd->mem_mode)
+                                   : -GET_MODE_SIZE (amd->mem_mode)));
+      amd->side_effects = alloc_EXPR_LIST (0,
+                                          gen_rtx_SET (VOIDmode,
+                                                       XEXP (loc, 0),
+                                                       tem),
+                                          amd->side_effects);
+      return addr;
+    case PRE_MODIFY:
+      addr = XEXP (loc, 1);
+    case POST_MODIFY:
+      if (addr == loc)
+       addr = XEXP (loc, 0);
+      gcc_assert (amd->mem_mode != VOIDmode);
+      addr = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
+      amd->side_effects = alloc_EXPR_LIST (0,
+                                          gen_rtx_SET (VOIDmode,
+                                                       XEXP (loc, 0),
+                                                       XEXP (loc, 1)),
+                                          amd->side_effects);
+      return addr;
+    case SUBREG:
+      /* First try without delegitimization of whole MEMs and
+        avoid_constant_pool_reference, which is more likely to succeed.  */
+      store_save = amd->store;
+      amd->store = true;
+      addr = simplify_replace_fn_rtx (SUBREG_REG (loc), old_rtx, adjust_mems,
+                                     data);
+      amd->store = store_save;
+      mem = simplify_replace_fn_rtx (addr, old_rtx, adjust_mems, data);
+      if (mem == SUBREG_REG (loc))
+       {
+         tem = loc;
+         goto finish_subreg;
+       }
+      tem = simplify_gen_subreg (GET_MODE (loc), mem,
+                                GET_MODE (SUBREG_REG (loc)),
+                                SUBREG_BYTE (loc));
+      if (tem)
+       goto finish_subreg;
+      tem = simplify_gen_subreg (GET_MODE (loc), addr,
+                                GET_MODE (SUBREG_REG (loc)),
+                                SUBREG_BYTE (loc));
+      if (tem == NULL_RTX)
+       tem = gen_rtx_raw_SUBREG (GET_MODE (loc), addr, SUBREG_BYTE (loc));
+    finish_subreg:
+      if (MAY_HAVE_DEBUG_INSNS
+         && GET_CODE (tem) == SUBREG
+         && (GET_CODE (SUBREG_REG (tem)) == PLUS
+             || GET_CODE (SUBREG_REG (tem)) == MINUS
+             || GET_CODE (SUBREG_REG (tem)) == MULT
+             || GET_CODE (SUBREG_REG (tem)) == ASHIFT)
+         && GET_MODE_CLASS (GET_MODE (tem)) == MODE_INT
+         && GET_MODE_CLASS (GET_MODE (SUBREG_REG (tem))) == MODE_INT
+         && GET_MODE_SIZE (GET_MODE (tem))
+            < GET_MODE_SIZE (GET_MODE (SUBREG_REG (tem)))
+         && subreg_lowpart_p (tem)
+         && !for_each_rtx (&SUBREG_REG (tem), use_narrower_mode_test, tem))
+       return use_narrower_mode (SUBREG_REG (tem), GET_MODE (tem),
+                                 GET_MODE (SUBREG_REG (tem)));
+      return tem;
+    case ASM_OPERANDS:
+      /* Don't do any replacements in second and following
+        ASM_OPERANDS of inline-asm with multiple sets.
+        ASM_OPERANDS_INPUT_VEC, ASM_OPERANDS_INPUT_CONSTRAINT_VEC
+        and ASM_OPERANDS_LABEL_VEC need to be equal between
+        all the ASM_OPERANDs in the insn and adjust_insn will
+        fix this up.  */
+      if (ASM_OPERANDS_OUTPUT_IDX (loc) != 0)
+       return loc;
+      break;
+    default:
+      break;
+    }
+  return NULL_RTX;
+}
+
+/* Helper function for replacement of uses.  */
+
+static void
+adjust_mem_uses (rtx *x, void *data)
+{
+  rtx new_x = simplify_replace_fn_rtx (*x, NULL_RTX, adjust_mems, data);
+  if (new_x != *x)
+    validate_change (NULL_RTX, x, new_x, true);
+}
+
+/* Helper function for replacement of stores.  */
 
-  addr = replace_rtx (copy_rtx (XEXP (mem, 0)), stack_pointer_rtx, cfa);
-  tmp = simplify_rtx (addr);
-  if (tmp)
-    addr = tmp;
+static void
+adjust_mem_stores (rtx loc, const_rtx expr, void *data)
+{
+  if (MEM_P (loc))
+    {
+      rtx new_dest = simplify_replace_fn_rtx (SET_DEST (expr), NULL_RTX,
+                                             adjust_mems, data);
+      if (new_dest != SET_DEST (expr))
+       {
+         rtx xexpr = CONST_CAST_RTX (expr);
+         validate_change (NULL_RTX, &SET_DEST (xexpr), new_dest, true);
+       }
+    }
+}
+
+/* Simplify INSN.  Remove all {PRE,POST}_{INC,DEC,MODIFY} rtxes,
+   replace them with their value in the insn and add the side-effects
+   as other sets to the insn.  */
+
+static void
+adjust_insn (basic_block bb, rtx insn)
+{
+  struct adjust_mem_data amd;
+  rtx set;
+  amd.mem_mode = VOIDmode;
+  amd.stack_adjust = -VTI (bb)->out.stack_adjust;
+  amd.side_effects = NULL_RTX;
+
+  amd.store = true;
+  note_stores (PATTERN (insn), adjust_mem_stores, &amd);
+
+  amd.store = false;
+  if (GET_CODE (PATTERN (insn)) == PARALLEL
+      && asm_noperands (PATTERN (insn)) > 0
+      && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
+    {
+      rtx body, set0;
+      int i;
+
+      /* inline-asm with multiple sets is tiny bit more complicated,
+        because the 3 vectors in ASM_OPERANDS need to be shared between
+        all ASM_OPERANDS in the instruction.  adjust_mems will
+        not touch ASM_OPERANDS other than the first one, asm_noperands
+        test above needs to be called before that (otherwise it would fail)
+        and afterwards this code fixes it up.  */
+      note_uses (&PATTERN (insn), adjust_mem_uses, &amd);
+      body = PATTERN (insn);
+      set0 = XVECEXP (body, 0, 0);
+      gcc_checking_assert (GET_CODE (set0) == SET
+                          && GET_CODE (SET_SRC (set0)) == ASM_OPERANDS
+                          && ASM_OPERANDS_OUTPUT_IDX (SET_SRC (set0)) == 0);
+      for (i = 1; i < XVECLEN (body, 0); i++)
+       if (GET_CODE (XVECEXP (body, 0, i)) != SET)
+         break;
+       else
+         {
+           set = XVECEXP (body, 0, i);
+           gcc_checking_assert (GET_CODE (SET_SRC (set)) == ASM_OPERANDS
+                                && ASM_OPERANDS_OUTPUT_IDX (SET_SRC (set))
+                                   == i);
+           if (ASM_OPERANDS_INPUT_VEC (SET_SRC (set))
+               != ASM_OPERANDS_INPUT_VEC (SET_SRC (set0))
+               || ASM_OPERANDS_INPUT_CONSTRAINT_VEC (SET_SRC (set))
+                  != ASM_OPERANDS_INPUT_CONSTRAINT_VEC (SET_SRC (set0))
+               || ASM_OPERANDS_LABEL_VEC (SET_SRC (set))
+                  != ASM_OPERANDS_LABEL_VEC (SET_SRC (set0)))
+             {
+               rtx newsrc = shallow_copy_rtx (SET_SRC (set));
+               ASM_OPERANDS_INPUT_VEC (newsrc)
+                 = ASM_OPERANDS_INPUT_VEC (SET_SRC (set0));
+               ASM_OPERANDS_INPUT_CONSTRAINT_VEC (newsrc)
+                 = ASM_OPERANDS_INPUT_CONSTRAINT_VEC (SET_SRC (set0));
+               ASM_OPERANDS_LABEL_VEC (newsrc)
+                 = ASM_OPERANDS_LABEL_VEC (SET_SRC (set0));
+               validate_change (NULL_RTX, &SET_SRC (set), newsrc, true);
+             }
+         }
+    }
+  else
+    note_uses (&PATTERN (insn), adjust_mem_uses, &amd);
+
+  /* For read-only MEMs containing some constant, prefer those
+     constants.  */
+  set = single_set (insn);
+  if (set && MEM_P (SET_SRC (set)) && MEM_READONLY_P (SET_SRC (set)))
+    {
+      rtx note = find_reg_equal_equiv_note (insn);
+
+      if (note && CONSTANT_P (XEXP (note, 0)))
+       validate_change (NULL_RTX, &SET_SRC (set), XEXP (note, 0), true);
+    }
+
+  if (amd.side_effects)
+    {
+      rtx *pat, new_pat, s;
+      int i, oldn, newn;
 
-  return replace_equiv_address_nv (mem, addr);
+      pat = &PATTERN (insn);
+      if (GET_CODE (*pat) == COND_EXEC)
+       pat = &COND_EXEC_CODE (*pat);
+      if (GET_CODE (*pat) == PARALLEL)
+       oldn = XVECLEN (*pat, 0);
+      else
+       oldn = 1;
+      for (s = amd.side_effects, newn = 0; s; newn++)
+       s = XEXP (s, 1);
+      new_pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (oldn + newn));
+      if (GET_CODE (*pat) == PARALLEL)
+       for (i = 0; i < oldn; i++)
+         XVECEXP (new_pat, 0, i) = XVECEXP (*pat, 0, i);
+      else
+       XVECEXP (new_pat, 0, 0) = *pat;
+      for (s = amd.side_effects, i = oldn; i < oldn + newn; i++, s = XEXP (s, 1))
+       XVECEXP (new_pat, 0, i) = XEXP (s, 0);
+      free_EXPR_LIST_list (&amd.side_effects);
+      validate_change (NULL_RTX, pat, new_pat, true);
+    }
 }
 
 /* Return true if a decl_or_value DV is a DECL or NULL.  */
@@ -753,9 +1071,7 @@ dv_is_value_p (decl_or_value dv)
 static inline tree
 dv_as_decl (decl_or_value dv)
 {
-#ifdef ENABLE_CHECKING
-  gcc_assert (dv_is_decl_p (dv));
-#endif
+  gcc_checking_assert (dv_is_decl_p (dv));
   return (tree) dv;
 }
 
@@ -763,9 +1079,7 @@ dv_as_decl (decl_or_value dv)
 static inline rtx
 dv_as_value (decl_or_value dv)
 {
-#ifdef ENABLE_CHECKING
-  gcc_assert (dv_is_value_p (dv));
-#endif
+  gcc_checking_assert (dv_is_value_p (dv));
   return (rtx)dv;
 }
 
@@ -814,9 +1128,7 @@ dv_from_decl (tree decl)
 {
   decl_or_value dv;
   dv = decl;
-#ifdef ENABLE_CHECKING
-  gcc_assert (dv_is_decl_p (dv));
-#endif
+  gcc_checking_assert (dv_is_decl_p (dv));
   return dv;
 }
 
@@ -826,15 +1138,13 @@ dv_from_value (rtx value)
 {
   decl_or_value dv;
   dv = value;
-#ifdef ENABLE_CHECKING
-  gcc_assert (dv_is_value_p (dv));
-#endif
+  gcc_checking_assert (dv_is_value_p (dv));
   return dv;
 }
 
 extern void debug_dv (decl_or_value dv);
 
-void
+DEBUG_FUNCTION void
 debug_dv (decl_or_value dv)
 {
   if (dv_is_value_p (dv))
@@ -903,7 +1213,7 @@ variable_htab_free (void *elem)
   variable var = (variable) elem;
   location_chain node, next;
 
-  gcc_assert (var->refcount > 0);
+  gcc_checking_assert (var->refcount > 0);
 
   var->refcount--;
   if (var->refcount > 0)
@@ -1106,7 +1416,7 @@ shared_hash_copy (shared_hash vars)
 static void
 shared_hash_destroy (shared_hash vars)
 {
-  gcc_assert (vars->refcount > 0);
+  gcc_checking_assert (vars->refcount > 0);
   if (--vars->refcount == 0)
     {
       htab_delete (vars->htab);
@@ -1271,34 +1581,23 @@ unshare_variable (dataflow_set *set, void **slot, variable var,
   return slot;
 }
 
-/* Add a variable from *SLOT to hash table DATA and increase its reference
-   count.  */
-
-static int
-vars_copy_1 (void **slot, void *data)
-{
-  htab_t dst = (htab_t) data;
-  variable src;
-  void **dstp;
-
-  src = (variable) *slot;
-  src->refcount++;
-
-  dstp = htab_find_slot_with_hash (dst, src->dv,
-                                  dv_htab_hash (src->dv),
-                                  INSERT);
-  *dstp = src;
-
-  /* Continue traversing the hash table.  */
-  return 1;
-}
-
 /* Copy all variables from hash table SRC to hash table DST.  */
 
 static void
 vars_copy (htab_t dst, htab_t src)
 {
-  htab_traverse_noresize (src, vars_copy_1, dst);
+  htab_iterator hi;
+  variable var;
+
+  FOR_EACH_HTAB_ELEMENT (src, var, variable, hi)
+    {
+      void **dstp;
+      var->refcount++;
+      dstp = htab_find_slot_with_hash (dst, var->dv,
+                                      dv_htab_hash (var->dv),
+                                      INSERT);
+      *dstp = var;
+    }
 }
 
 /* Map a decl to its main debug decl.  */
@@ -1307,9 +1606,12 @@ static inline tree
 var_debug_decl (tree decl)
 {
   if (decl && DECL_P (decl)
-      && DECL_DEBUG_EXPR_IS_FROM (decl) && DECL_DEBUG_EXPR (decl)
-      && DECL_P (DECL_DEBUG_EXPR (decl)))
-    decl = DECL_DEBUG_EXPR (decl);
+      && DECL_DEBUG_EXPR_IS_FROM (decl))
+    {
+      tree debugdecl = DECL_DEBUG_EXPR (decl);
+      if (debugdecl && DECL_P (debugdecl))
+       decl = debugdecl;
+    }
 
   return decl;
 }
@@ -1800,14 +2102,12 @@ variable_union_info_cmp_pos (const void *n1, const void *n2)
    we keep the newest locations in the beginning.  */
 
 static int
-variable_union (void **slot, void *data)
+variable_union (variable src, dataflow_set *set)
 {
-  variable src, dst;
+  variable dst;
   void **dstp;
-  dataflow_set *set = (dataflow_set *) data;
   int i, j, k;
 
-  src = (variable) *slot;
   dstp = shared_hash_find_slot (set->vars, src->dv);
   if (!dstp || !*dstp)
     {
@@ -1833,8 +2133,8 @@ variable_union (void **slot, void *data)
     {
       location_chain *nodep, dnode, snode;
 
-      gcc_assert (src->n_var_parts == 1);
-      gcc_assert (dst->n_var_parts == 1);
+      gcc_assert (src->n_var_parts == 1
+                 && dst->n_var_parts == 1);
 
       snode = src->var_part[0].loc_chain;
       gcc_assert (snode);
@@ -1870,10 +2170,8 @@ variable_union (void **slot, void *data)
              nnode->next = dnode;
              dnode = nnode;
            }
-#ifdef ENABLE_CHECKING
          else if (r == 0)
-           gcc_assert (rtx_equal_p (dnode->loc, snode->loc));
-#endif
+           gcc_checking_assert (rtx_equal_p (dnode->loc, snode->loc));
 
          if (r >= 0)
            snode = snode->next;
@@ -2183,7 +2481,13 @@ dataflow_set_union (dataflow_set *dst, dataflow_set *src)
       dst->vars = shared_hash_copy (src->vars);
     }
   else
-    htab_traverse (shared_hash_htab (src->vars), variable_union, dst);
+    {
+      htab_iterator hi;
+      variable var;
+
+      FOR_EACH_HTAB_ELEMENT (shared_hash_htab (src->vars), var, variable, hi)
+       variable_union (var, dst);
+    }
 }
 
 /* Whether the value is currently being expanded.  */
@@ -2219,45 +2523,71 @@ dv_changed_p (decl_or_value dv)
 
 /* Return a location list node whose loc is rtx_equal to LOC, in the
    location list of a one-part variable or value VAR, or in that of
-   any values recursively mentioned in the location lists.  */
+   any values recursively mentioned in the location lists.  VARS must
+   be in star-canonical form.  */
 
 static location_chain
 find_loc_in_1pdv (rtx loc, variable var, htab_t vars)
 {
   location_chain node;
+  enum rtx_code loc_code;
 
   if (!var)
     return NULL;
 
-  gcc_assert (dv_onepart_p (var->dv));
+  gcc_checking_assert (dv_onepart_p (var->dv));
 
   if (!var->n_var_parts)
     return NULL;
 
-  gcc_assert (var->var_part[0].offset == 0);
+  gcc_checking_assert (var->var_part[0].offset == 0);
+  gcc_checking_assert (loc != dv_as_opaque (var->dv));
 
+  loc_code = GET_CODE (loc);
   for (node = var->var_part[0].loc_chain; node; node = node->next)
-    if (rtx_equal_p (loc, node->loc))
-      return node;
-    else if (GET_CODE (node->loc) == VALUE
-            && !VALUE_RECURSED_INTO (node->loc))
-      {
-       decl_or_value dv = dv_from_value (node->loc);
-       variable var = (variable)
-                      htab_find_with_hash (vars, dv, dv_htab_hash (dv));
+    {
+      decl_or_value dv;
+      variable rvar;
 
-       if (var)
-         {
-           location_chain where;
-           VALUE_RECURSED_INTO (node->loc) = true;
-           if ((where = find_loc_in_1pdv (loc, var, vars)))
-             {
-               VALUE_RECURSED_INTO (node->loc) = false;
-               return where;
-             }
-           VALUE_RECURSED_INTO (node->loc) = false;
-         }
-      }
+      if (GET_CODE (node->loc) != loc_code)
+       {
+         if (GET_CODE (node->loc) != VALUE)
+           continue;
+       }
+      else if (loc == node->loc)
+       return node;
+      else if (loc_code != VALUE)
+       {
+         if (rtx_equal_p (loc, node->loc))
+           return node;
+         continue;
+       }
+
+      /* Since we're in star-canonical form, we don't need to visit
+        non-canonical nodes: one-part variables and non-canonical
+        values would only point back to the canonical node.  */
+      if (dv_is_value_p (var->dv)
+         && !canon_value_cmp (node->loc, dv_as_value (var->dv)))
+       {
+         /* Skip all subsequent VALUEs.  */
+         while (node->next && GET_CODE (node->next->loc) == VALUE)
+           {
+             node = node->next;
+             gcc_checking_assert (!canon_value_cmp (node->loc,
+                                                    dv_as_value (var->dv)));
+             if (loc == node->loc)
+               return node;
+           }
+         continue;
+       }
+
+      gcc_checking_assert (node == var->var_part[0].loc_chain);
+      gcc_checking_assert (!node->next);
+
+      dv = dv_from_value (node->loc);
+      rvar = (variable) htab_find_with_hash (vars, dv, dv_htab_hash (dv));
+      return find_loc_in_1pdv (loc, rvar, vars);
+    }
 
   return NULL;
 }
@@ -2316,6 +2646,29 @@ intersect_loc_chains (rtx val, location_chain *dest, struct dfset_merge *dsm,
   dataflow_set *s2set = dsm->src;
   location_chain found;
 
+  if (s2var)
+    {
+      location_chain s2node;
+
+      gcc_checking_assert (dv_onepart_p (s2var->dv));
+
+      if (s2var->n_var_parts)
+       {
+         gcc_checking_assert (s2var->var_part[0].offset == 0);
+         s2node = s2var->var_part[0].loc_chain;
+
+         for (; s1node && s2node;
+              s1node = s1node->next, s2node = s2node->next)
+           if (s1node->loc != s2node->loc)
+             break;
+           else if (s1node->loc == val)
+             continue;
+           else
+             insert_into_intersection (dest, s1node->loc,
+                                       MIN (s1node->init, s2node->init));
+       }
+    }
+
   for (; s1node; s1node = s1node->next)
     {
       if (s1node->loc == val)
@@ -2450,10 +2803,8 @@ loc_cmp (rtx x, rtx y)
       if (DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x))
          < DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (y)))
        return -1;
-#ifdef ENABLE_CHECKING
-      gcc_assert (DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x))
-                 > DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (y)));
-#endif
+      gcc_checking_assert (DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x))
+                          > DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (y)));
       return 1;
     }
 
@@ -2602,15 +2953,23 @@ add_value_chains (decl_or_value dv, rtx loc)
 }
 
 /* If CSELIB_VAL_PTR of value DV refer to VALUEs, add backlinks from those
-   VALUEs to DV.  */
+   VALUEs to DV.  Add the same time get rid of ASM_OPERANDS from locs list,
+   that is something we never can express in .debug_info and can prevent
+   reverse ops from being used.  */
 
 static void
 add_cselib_value_chains (decl_or_value dv)
 {
-  struct elt_loc_list *l;
+  struct elt_loc_list **l;
 
-  for (l = CSELIB_VAL_PTR (dv_as_value (dv))->locs; l; l = l->next)
-    for_each_rtx (&l->loc, add_value_chain, dv_as_opaque (dv));
+  for (l = &CSELIB_VAL_PTR (dv_as_value (dv))->locs; *l;)
+    if (GET_CODE ((*l)->loc) == ASM_OPERANDS)
+      *l = (*l)->next;
+    else
+      {
+       for_each_rtx (&(*l)->loc, add_value_chain, dv_as_opaque (dv));
+       l = &(*l)->next;
+      }
 }
 
 /* If decl or value DVP refers to VALUE from *LOC, remove backlinks
@@ -2737,7 +3096,7 @@ canonicalize_values_mark (void **slot, void *data)
   if (!dv_is_value_p (dv))
     return 1;
 
-  gcc_assert (var->n_var_parts == 1);
+  gcc_checking_assert (var->n_var_parts == 1);
 
   val = dv_as_value (dv);
 
@@ -2780,7 +3139,7 @@ canonicalize_values_star (void **slot, void *data)
   if (!dv_onepart_p (dv))
     return 1;
 
-  gcc_assert (var->n_var_parts == 1);
+  gcc_checking_assert (var->n_var_parts == 1);
 
   if (dv_is_value_p (dv))
     {
@@ -2970,8 +3329,8 @@ canonicalize_values_star (void **slot, void *data)
 
   /* Variable may have been unshared.  */
   var = (variable)*slot;
-  gcc_assert (var->n_var_parts && var->var_part[0].loc_chain->loc == cval
-             && var->var_part[0].loc_chain->next == NULL);
+  gcc_checking_assert (var->n_var_parts && var->var_part[0].loc_chain->loc == cval
+                      && var->var_part[0].loc_chain->next == NULL);
 
   if (VALUE_RECURSED_INTO (cval))
     goto restart_with_cval;
@@ -2979,18 +3338,77 @@ canonicalize_values_star (void **slot, void *data)
   return 1;
 }
 
+/* Bind one-part variables to the canonical value in an equivalence
+   set.  Not doing this causes dataflow convergence failure in rare
+   circumstances, see PR42873.  Unfortunately we can't do this
+   efficiently as part of canonicalize_values_star, since we may not
+   have determined or even seen the canonical value of a set when we
+   get to a variable that references another member of the set.  */
+
+static int
+canonicalize_vars_star (void **slot, void *data)
+{
+  dataflow_set *set = (dataflow_set *)data;
+  variable var = (variable) *slot;
+  decl_or_value dv = var->dv;
+  location_chain node;
+  rtx cval;
+  decl_or_value cdv;
+  void **cslot;
+  variable cvar;
+  location_chain cnode;
+
+  if (!dv_onepart_p (dv) || dv_is_value_p (dv))
+    return 1;
+
+  gcc_assert (var->n_var_parts == 1);
+
+  node = var->var_part[0].loc_chain;
+
+  if (GET_CODE (node->loc) != VALUE)
+    return 1;
+
+  gcc_assert (!node->next);
+  cval = node->loc;
+
+  /* Push values to the canonical one.  */
+  cdv = dv_from_value (cval);
+  cslot = shared_hash_find_slot_noinsert (set->vars, cdv);
+  if (!cslot)
+    return 1;
+  cvar = (variable)*cslot;
+  gcc_assert (cvar->n_var_parts == 1);
+
+  cnode = cvar->var_part[0].loc_chain;
+
+  /* CVAL is canonical if its value list contains non-VALUEs or VALUEs
+     that are not “more canonical” than it.  */
+  if (GET_CODE (cnode->loc) != VALUE
+      || !canon_value_cmp (cnode->loc, cval))
+    return 1;
+
+  /* CVAL was found to be non-canonical.  Change the variable to point
+     to the canonical VALUE.  */
+  gcc_assert (!cnode->next);
+  cval = cnode->loc;
+
+  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);
+
+  return 1;
+}
+
 /* Combine variable or value in *S1SLOT (in DSM->cur) with the
    corresponding entry in DSM->src.  Multi-part variables are combined
    with variable_union, whereas onepart dvs are combined with
    intersection.  */
 
 static int
-variable_merge_over_cur (void **s1slot, void *data)
+variable_merge_over_cur (variable s1var, struct dfset_merge *dsm)
 {
-  struct dfset_merge *dsm = (struct dfset_merge *)data;
   dataflow_set *dst = dsm->dst;
   void **dstslot;
-  variable s1var = (variable) *s1slot;
   variable s2var, dvar = NULL;
   decl_or_value dv = s1var->dv;
   bool onepart = dv_onepart_p (dv);
@@ -3001,14 +3419,14 @@ variable_merge_over_cur (void **s1slot, void *data)
   /* If the incoming onepart variable has an empty location list, then
      the intersection will be just as empty.  For other variables,
      it's always union.  */
-  gcc_assert (s1var->n_var_parts);
-  gcc_assert (s1var->var_part[0].loc_chain);
+  gcc_checking_assert (s1var->n_var_parts
+                      && s1var->var_part[0].loc_chain);
 
   if (!onepart)
-    return variable_union (s1slot, dst);
+    return variable_union (s1var, dst);
 
-  gcc_assert (s1var->n_var_parts == 1);
-  gcc_assert (s1var->var_part[0].offset == 0);
+  gcc_checking_assert (s1var->n_var_parts == 1
+                      && s1var->var_part[0].offset == 0);
 
   dvhash = dv_htab_hash (dv);
   if (dv_is_value_p (dv))
@@ -3024,17 +3442,17 @@ variable_merge_over_cur (void **s1slot, void *data)
     }
 
   dsm->src_onepart_cnt--;
-  gcc_assert (s2var->var_part[0].loc_chain);
-  gcc_assert (s2var->n_var_parts == 1);
-  gcc_assert (s2var->var_part[0].offset == 0);
+  gcc_assert (s2var->var_part[0].loc_chain
+             && s2var->n_var_parts == 1
+             && s2var->var_part[0].offset == 0);
 
   dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash);
   if (dstslot)
     {
       dvar = (variable)*dstslot;
-      gcc_assert (dvar->refcount == 1);
-      gcc_assert (dvar->n_var_parts == 1);
-      gcc_assert (dvar->var_part[0].offset == 0);
+      gcc_assert (dvar->refcount == 1
+                 && dvar->n_var_parts == 1
+                 && dvar->var_part[0].offset == 0);
       nodep = &dvar->var_part[0].loc_chain;
     }
   else
@@ -3146,10 +3564,9 @@ variable_merge_over_cur (void **s1slot, void *data)
       dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash);
       gcc_assert (*dstslot == dvar);
       canonicalize_values_star (dstslot, dst);
-#ifdef ENABLE_CHECKING
-      gcc_assert (dstslot
-                 == shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash));
-#endif
+      gcc_checking_assert (dstslot
+                          == shared_hash_find_slot_noinsert_1 (dst->vars,
+                                                               dv, dvhash));
       dvar = (variable)*dstslot;
     }
   else
@@ -3214,11 +3631,9 @@ variable_merge_over_cur (void **s1slot, void *data)
          dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash);
          gcc_assert (*dstslot == dvar);
          canonicalize_values_star (dstslot, dst);
-#ifdef ENABLE_CHECKING
-         gcc_assert (dstslot
-                     == shared_hash_find_slot_noinsert_1 (dst->vars,
-                                                          dv, dvhash));
-#endif
+         gcc_checking_assert (dstslot
+                              == shared_hash_find_slot_noinsert_1 (dst->vars,
+                                                                   dv, dvhash));
          dvar = (variable)*dstslot;
        }
     }
@@ -3248,11 +3663,9 @@ variable_merge_over_cur (void **s1slot, void *data)
    variable_merge_over_cur().  */
 
 static int
-variable_merge_over_src (void **s2slot, void *data)
+variable_merge_over_src (variable s2var, struct dfset_merge *dsm)
 {
-  struct dfset_merge *dsm = (struct dfset_merge *)data;
   dataflow_set *dst = dsm->dst;
-  variable s2var = (variable) *s2slot;
   decl_or_value dv = s2var->dv;
   bool onepart = dv_onepart_p (dv);
 
@@ -3279,6 +3692,8 @@ dataflow_set_merge (dataflow_set *dst, dataflow_set *src2)
   struct dfset_merge dsm;
   int i;
   size_t src1_elems, src2_elems;
+  htab_iterator hi;
+  variable var;
 
   src1_elems = htab_elements (shared_hash_htab (src1->vars));
   src2_elems = htab_elements (shared_hash_htab (src2->vars));
@@ -3299,10 +3714,10 @@ dataflow_set_merge (dataflow_set *dst, dataflow_set *src2)
   dsm.cur = src1;
   dsm.src_onepart_cnt = 0;
 
-  htab_traverse (shared_hash_htab (dsm.src->vars), variable_merge_over_src,
-                &dsm);
-  htab_traverse (shared_hash_htab (dsm.cur->vars), variable_merge_over_cur,
-                &dsm);
+  FOR_EACH_HTAB_ELEMENT (shared_hash_htab (dsm.src->vars), var, variable, hi)
+    variable_merge_over_src (var, &dsm);
+  FOR_EACH_HTAB_ELEMENT (shared_hash_htab (dsm.cur->vars), var, variable, hi)
+    variable_merge_over_cur (var, &dsm);
 
   if (dsm.src_onepart_cnt)
     dst_can_be_shared = false;
@@ -3322,6 +3737,11 @@ dataflow_set_equiv_regs (dataflow_set *set)
     {
       rtx canon[NUM_MACHINE_MODES];
 
+      /* If the list is empty or one entry, no need to canonicalize
+        anything.  */
+      if (set->regs[i] == NULL || set->regs[i]->next == NULL)
+       continue;
+
       memset (canon, 0, sizeof (canon));
 
       for (list = set->regs[i]; list; list = list->next)
@@ -3515,8 +3935,8 @@ variable_post_merge_new_vals (void **slot, void *info)
                       att; att = att->next)
                    if (GET_MODE (att->loc) == GET_MODE (node->loc))
                      {
-                       gcc_assert (att->offset == 0);
-                       gcc_assert (dv_is_value_p (att->dv));
+                       gcc_assert (att->offset == 0
+                                   && dv_is_value_p (att->dv));
                        val_reset (set, att->dv);
                        break;
                      }
@@ -3582,18 +4002,24 @@ variable_post_merge_perm_vals (void **pslot, void *info)
   decl_or_value dv;
   attrs att;
 
-  gcc_assert (dv_is_value_p (pvar->dv));
-  gcc_assert (pvar->n_var_parts == 1);
+  gcc_assert (dv_is_value_p (pvar->dv)
+             && pvar->n_var_parts == 1);
   pnode = pvar->var_part[0].loc_chain;
-  gcc_assert (pnode);
-  gcc_assert (!pnode->next);
-  gcc_assert (REG_P (pnode->loc));
+  gcc_assert (pnode
+             && !pnode->next
+             && REG_P (pnode->loc));
 
   dv = pvar->dv;
 
   var = shared_hash_find (set->vars, dv);
   if (var)
     {
+      /* Although variable_post_merge_new_vals may have made decls
+        non-star-canonical, values that pre-existed in canonical form
+        remain canonical, and newly-created values reference a single
+        REG, so they are canonical as well.  Since VAR has the
+        location list for a VALUE, using find_loc_in_1pdv for it is
+        fine, since VALUEs don't map back to DECLs.  */
       if (find_loc_in_1pdv (pnode->loc, var, shared_hash_htab (set->vars)))
        return 1;
       val_reset (set, dv);
@@ -3618,7 +4044,7 @@ variable_post_merge_perm_vals (void **pslot, void *info)
     {
       attrs_list_insert (&set->regs[REGNO (pnode->loc)],
                         dv, 0, pnode->loc);
-      variable_union (pslot, set);
+      variable_union (pvar, set);
     }
 
   return 1;
@@ -3641,6 +4067,7 @@ dataflow_post_merge_adjust (dataflow_set *set, dataflow_set **permp)
     htab_traverse (shared_hash_htab ((*permp)->vars),
                   variable_post_merge_perm_vals, &dfpm);
   htab_traverse (shared_hash_htab (set->vars), canonicalize_values_star, set);
+  htab_traverse (shared_hash_htab (set->vars), canonicalize_vars_star, set);
 }
 
 /* Return a node whose loc is a MEM that refers to EXPR in the
@@ -3658,9 +4085,8 @@ find_mem_expr_in_1pdv (tree expr, rtx val, htab_t vars)
   if (!val)
     return NULL;
 
-  gcc_assert (GET_CODE (val) == VALUE);
-
-  gcc_assert (!VALUE_RECURSED_INTO (val));
+  gcc_assert (GET_CODE (val) == VALUE
+             && !VALUE_RECURSED_INTO (val));
 
   dv = dv_from_value (val);
   var = (variable) htab_find_with_hash (vars, dv, dv_htab_hash (dv));
@@ -3911,7 +4337,7 @@ dataflow_set_clear_at_call (dataflow_set *set)
   int r;
 
   for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
-    if (TEST_HARD_REG_BIT (call_used_reg_set, r))
+    if (TEST_HARD_REG_BIT (regs_invalidated_by_call, r))
       var_regno_delete (set, r);
 
   if (MAY_HAVE_DEBUG_INSNS)
@@ -3926,10 +4352,6 @@ dataflow_set_clear_at_call (dataflow_set *set)
     }
 }
 
-/* Flag whether two dataflow sets being compared contain different data.  */
-static bool
-dataflow_set_different_value;
-
 static bool
 variable_part_different_p (variable_part *vp1, variable_part *vp2)
 {
@@ -3964,14 +4386,13 @@ onepart_variable_different_p (variable var1, variable var2)
   if (var1 == var2)
     return false;
 
-  gcc_assert (var1->n_var_parts == 1);
-  gcc_assert (var2->n_var_parts == 1);
+  gcc_assert (var1->n_var_parts == 1
+             && var2->n_var_parts == 1);
 
   lc1 = var1->var_part[0].loc_chain;
   lc2 = var2->var_part[0].loc_chain;
 
-  gcc_assert (lc1);
-  gcc_assert (lc2);
+  gcc_assert (lc1 && lc2);
 
   while (lc1 && lc2)
     {
@@ -4004,8 +4425,8 @@ variable_different_p (variable var1, variable var2)
       /* One-part values have locations in a canonical order.  */
       if (i == 0 && var1->var_part[i].offset == 0 && dv_onepart_p (var1->dv))
        {
-         gcc_assert (var1->n_var_parts == 1);
-         gcc_assert (dv_as_opaque (var1->dv) == dv_as_opaque (var2->dv));
+         gcc_assert (var1->n_var_parts == 1
+                     && dv_as_opaque (var1->dv) == dv_as_opaque (var2->dv));
          return onepart_variable_different_p (var1, var2);
        }
       if (variable_part_different_p (&var1->var_part[i], &var2->var_part[i]))
@@ -4016,56 +4437,14 @@ variable_different_p (variable var1, variable var2)
   return false;
 }
 
-/* Compare variable *SLOT with the same variable in hash table DATA
-   and set DATAFLOW_SET_DIFFERENT_VALUE if they are different.  */
-
-static int
-dataflow_set_different_1 (void **slot, void *data)
-{
-  htab_t htab = (htab_t) data;
-  variable var1, var2;
-
-  var1 = (variable) *slot;
-  var2 = (variable) htab_find_with_hash (htab, var1->dv,
-                                        dv_htab_hash (var1->dv));
-  if (!var2)
-    {
-      dataflow_set_different_value = true;
-
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       {
-         fprintf (dump_file, "dataflow difference found: removal of:\n");
-         dump_var (var1);
-       }
-
-      /* Stop traversing the hash table.  */
-      return 0;
-    }
-
-  if (variable_different_p (var1, var2))
-    {
-      dataflow_set_different_value = true;
-
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       {
-         fprintf (dump_file, "dataflow difference found: old and new follow:\n");
-         dump_var (var1);
-         dump_var (var2);
-       }
-
-      /* Stop traversing the hash table.  */
-      return 0;
-    }
-
-  /* Continue traversing the hash table.  */
-  return 1;
-}
-
-/* Return true if dataflow sets OLD_SET and NEW_SET differ.  */
+/* Return true if dataflow sets OLD_SET and NEW_SET differ.  */
 
 static bool
 dataflow_set_different (dataflow_set *old_set, dataflow_set *new_set)
 {
+  htab_iterator hi;
+  variable var1;
+
   if (old_set->vars == new_set->vars)
     return false;
 
@@ -4073,14 +4452,38 @@ dataflow_set_different (dataflow_set *old_set, dataflow_set *new_set)
       != htab_elements (shared_hash_htab (new_set->vars)))
     return true;
 
-  dataflow_set_different_value = false;
+  FOR_EACH_HTAB_ELEMENT (shared_hash_htab (old_set->vars), var1, variable, hi)
+    {
+      htab_t htab = shared_hash_htab (new_set->vars);
+      variable var2 = (variable) htab_find_with_hash (htab, var1->dv,
+                                                     dv_htab_hash (var1->dv));
+      if (!var2)
+       {
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           {
+             fprintf (dump_file, "dataflow difference found: removal of:\n");
+             dump_var (var1);
+           }
+         return true;
+       }
+
+      if (variable_different_p (var1, var2))
+       {
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           {
+             fprintf (dump_file, "dataflow difference found: "
+                      "old and new follow:\n");
+             dump_var (var1);
+             dump_var (var2);
+           }
+         return true;
+       }
+    }
 
-  htab_traverse (shared_hash_htab (old_set->vars), dataflow_set_different_1,
-                shared_hash_htab (new_set->vars));
   /* No need to traverse the second hashtab, if both have the same number
      of elements and the second one had all entries found in the first one,
      then it can't have any extra entries.  */
-  return dataflow_set_different_value;
+  return false;
 }
 
 /* Free the contents of dataflow set SET.  */
@@ -4161,13 +4564,32 @@ track_expr_p (tree expr, bool need_rtl)
      don't need to track this expression if the ultimate declaration is
      ignored.  */
   realdecl = expr;
-  if (DECL_DEBUG_EXPR_IS_FROM (realdecl) && DECL_DEBUG_EXPR (realdecl))
+  if (DECL_DEBUG_EXPR_IS_FROM (realdecl))
     {
       realdecl = DECL_DEBUG_EXPR (realdecl);
-      /* ??? We don't yet know how to emit DW_OP_piece for variable
-        that has been SRA'ed.  */
-      if (!DECL_P (realdecl))
-       return 0;
+      if (realdecl == NULL_TREE)
+       realdecl = expr;
+      else if (!DECL_P (realdecl))
+       {
+         if (handled_component_p (realdecl))
+           {
+             HOST_WIDE_INT bitsize, bitpos, maxsize;
+             tree innerdecl
+               = get_ref_base_and_extent (realdecl, &bitpos, &bitsize,
+                                          &maxsize);
+             if (!DECL_P (innerdecl)
+                 || DECL_IGNORED_P (innerdecl)
+                 || TREE_STATIC (innerdecl)
+                 || bitsize <= 0
+                 || bitpos + bitsize > 256
+                 || bitsize != maxsize)
+               return 0;
+             else
+               realdecl = expr;
+           }
+         else
+           return 0;
+       }
     }
 
   /* Do not track EXPR if REALDECL it should be ignored for debugging
@@ -4376,6 +4798,17 @@ find_use_val (rtx x, enum machine_mode mode, struct count_use_info *cui)
   return NULL;
 }
 
+/* Helper function to get mode of MEM's address.  */
+
+static inline enum machine_mode
+get_address_mode (rtx mem)
+{
+  enum machine_mode mode = GET_MODE (XEXP (mem, 0));
+  if (mode != VOIDmode)
+    return mode;
+  return targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem));
+}
+
 /* Replace all registers and addresses in an expression with VALUE
    expressions that map back to them, unless the expression is a
    register.  If no mapping is or can be performed, returns NULL.  */
@@ -4387,9 +4820,8 @@ replace_expr_with_values (rtx loc)
     return NULL;
   else if (MEM_P (loc))
     {
-      enum machine_mode address_mode
-       = targetm.addr_space.address_mode (MEM_ADDR_SPACE (loc));
-      cselib_val *addr = cselib_lookup (XEXP (loc, 0), address_mode, 0);
+      cselib_val *addr = cselib_lookup (XEXP (loc, 0),
+                                       get_address_mode (loc), 0);
       if (addr)
        return replace_equiv_address_nv (loc, addr->val_rtx);
       else
@@ -4414,12 +4846,15 @@ use_type (rtx loc, struct count_use_info *cui, enum machine_mode *modep)
          if (track_expr_p (PAT_VAR_LOCATION_DECL (loc), false))
            {
              rtx ploc = PAT_VAR_LOCATION_LOC (loc);
-             cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1);
+             if (! VAR_LOC_UNKNOWN_P (ploc))
+               {
+                 cselib_val *val = cselib_lookup (ploc, GET_MODE (loc), 1);
 
-             /* ??? flag_float_store and volatile mems are never
-                given values, but we could in theory use them for
-                locations.  */
-             gcc_assert (val || 1);
+                 /* ??? flag_float_store and volatile mems are never
+                    given values, but we could in theory use them for
+                    locations.  */
+                 gcc_assert (val || 1);
+               }
              return MO_VAL_LOC;
            }
          else
@@ -4434,7 +4869,8 @@ use_type (rtx loc, struct count_use_info *cui, enum machine_mode *modep)
            {
              if (REG_P (loc)
                  || (find_use_val (loc, GET_MODE (loc), cui)
-                     && cselib_lookup (XEXP (loc, 0), GET_MODE (loc), 0)))
+                     && cselib_lookup (XEXP (loc, 0),
+                                       get_address_mode (loc), 0)))
                return MO_VAL_SET;
            }
          else
@@ -4451,6 +4887,8 @@ use_type (rtx loc, struct count_use_info *cui, enum machine_mode *modep)
     {
       gcc_assert (REGNO (loc) < FIRST_PSEUDO_REGISTER);
 
+      if (loc == cfa_base_rtx)
+       return MO_CLOBBER;
       expr = REG_EXPR (loc);
 
       if (!expr)
@@ -4489,171 +4927,12 @@ log_op_type (rtx x, basic_block bb, rtx insn,
             enum micro_operation_type mopt, FILE *out)
 {
   fprintf (out, "bb %i op %i insn %i %s ",
-          bb->index, VTI (bb)->n_mos - 1,
+          bb->index, VEC_length (micro_operation, VTI (bb)->mos),
           INSN_UID (insn), micro_operation_type_name[mopt]);
   print_inline_rtx (out, x, 2);
   fputc ('\n', out);
 }
 
-/* Count uses (register and memory references) LOC which will be tracked.
-   INSN is instruction which the LOC is part of.  */
-
-static int
-count_uses (rtx *ploc, void *cuip)
-{
-  rtx loc = *ploc;
-  struct count_use_info *cui = (struct count_use_info *) cuip;
-  enum micro_operation_type mopt = use_type (loc, cui, NULL);
-
-  if (mopt != MO_CLOBBER)
-    {
-      cselib_val *val;
-      enum machine_mode mode = GET_MODE (loc);
-
-      switch (mopt)
-       {
-       case MO_VAL_LOC:
-         loc = PAT_VAR_LOCATION_LOC (loc);
-         if (VAR_LOC_UNKNOWN_P (loc))
-           break;
-         /* Fall through.  */
-
-       case MO_VAL_USE:
-       case MO_VAL_SET:
-         if (MEM_P (loc)
-             && !REG_P (XEXP (loc, 0)) && !MEM_P (XEXP (loc, 0)))
-           {
-             enum machine_mode address_mode
-               = targetm.addr_space.address_mode (MEM_ADDR_SPACE (loc));
-             val = cselib_lookup (XEXP (loc, 0), address_mode, 0);
-
-             if (val && !cselib_preserved_value_p (val))
-               {
-                 VTI (cui->bb)->n_mos++;
-                 cselib_preserve_value (val);
-                 if (dump_file && (dump_flags & TDF_DETAILS))
-                   log_op_type (XEXP (loc, 0), cui->bb, cui->insn,
-                                MO_VAL_USE, dump_file);
-               }
-           }
-
-         val = find_use_val (loc, mode, cui);
-         if (val)
-           {
-             if (mopt == MO_VAL_SET
-                 && GET_CODE (PATTERN (cui->insn)) == COND_EXEC
-                 && (REG_P (loc)
-                     || (MEM_P (loc)
-                         && (use_type (loc, NULL, NULL) == MO_USE
-                             || cui->sets))))
-               {
-                 cselib_val *oval = cselib_lookup (loc, GET_MODE (loc), 0);
-
-                 gcc_assert (oval != val);
-                 gcc_assert (REG_P (loc) || MEM_P (loc));
-
-                 if (!cselib_preserved_value_p (oval))
-                   {
-                     VTI (cui->bb)->n_mos++;
-                     cselib_preserve_value (oval);
-                     if (dump_file && (dump_flags & TDF_DETAILS))
-                       log_op_type (loc, cui->bb, cui->insn,
-                                    MO_VAL_USE, dump_file);
-                   }
-               }
-
-             cselib_preserve_value (val);
-           }
-         else
-           gcc_assert (mopt == MO_VAL_LOC
-                       || (mopt == MO_VAL_SET && cui->store_p));
-
-         break;
-
-       default:
-         break;
-       }
-
-      VTI (cui->bb)->n_mos++;
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       log_op_type (loc, cui->bb, cui->insn, mopt, dump_file);
-    }
-
-  return 0;
-}
-
-/* Helper function for finding all uses of REG/MEM in X in CUI's
-   insn.  */
-
-static void
-count_uses_1 (rtx *x, void *cui)
-{
-  for_each_rtx (x, count_uses, cui);
-}
-
-/* Count stores (register and memory references) LOC which will be
-   tracked.  CUI is a count_use_info object containing the instruction
-   which the LOC is part of.  */
-
-static void
-count_stores (rtx loc, const_rtx expr ATTRIBUTE_UNUSED, void *cui)
-{
-  count_uses (&loc, cui);
-}
-
-/* Adjust sets if needed.  Currently this optimizes read-only MEM loads
-   if REG_EQUAL/REG_EQUIV note is present.  */
-
-static void
-adjust_sets (rtx insn, struct cselib_set *sets, int n_sets)
-{
-  if (n_sets == 1 && MEM_P (sets[0].src) && MEM_READONLY_P (sets[0].src))
-    {
-      /* For read-only MEMs containing some constant, prefer those
-        constants.  */
-      rtx note = find_reg_equal_equiv_note (insn), src;
-
-      if (note && CONSTANT_P (XEXP (note, 0)))
-       {
-         sets[0].src = src = XEXP (note, 0);
-         if (GET_CODE (PATTERN (insn)) == COND_EXEC)
-           src = gen_rtx_IF_THEN_ELSE (GET_MODE (sets[0].dest),
-                                       COND_EXEC_TEST (PATTERN (insn)),
-                                       src, sets[0].dest);
-         sets[0].src_elt = cselib_lookup (src, GET_MODE (sets[0].dest), 1);
-       }
-    }
-}
-
-/* Callback for cselib_record_sets_hook, that counts how many micro
-   operations it takes for uses and stores in an insn after
-   cselib_record_sets has analyzed the sets in an insn, but before it
-   modifies the stored values in the internal tables, unless
-   cselib_record_sets doesn't call it directly (perhaps because we're
-   not doing cselib in the first place, in which case sets and n_sets
-   will be 0).  */
-
-static void
-count_with_sets (rtx insn, struct cselib_set *sets, int n_sets)
-{
-  basic_block bb = BLOCK_FOR_INSN (insn);
-  struct count_use_info cui;
-
-  cselib_hook_called = true;
-
-  adjust_sets (insn, sets, n_sets);
-
-  cui.insn = insn;
-  cui.bb = bb;
-  cui.sets = sets;
-  cui.n_sets = n_sets;
-
-  cui.store_p = false;
-  note_uses (&PATTERN (insn), count_uses_1, &cui);
-  cui.store_p = true;
-  note_stores (PATTERN (insn), count_stores, &cui);
-}
-
 /* Tell whether the CONCAT used to holds a VALUE and its location
    needs value resolution, i.e., an attempt of mapping the location
    back to other incoming values.  */
@@ -4679,9 +4958,7 @@ count_with_sets (rtx insn, struct cselib_set *sets, int n_sets)
 /* All preserved VALUEs.  */
 static VEC (rtx, heap) *preserved_values;
 
-/* Ensure VAL is preserved and remember it in a vector for vt_emit_notes.
-   This must be only called when cselib_preserve_only_values will be called
-   with true, the counting phase must use cselib_preserve_value.  */
+/* Ensure VAL is preserved and remember it in a vector for vt_emit_notes.  */
 
 static void
 preserve_value (cselib_val *val)
@@ -4690,6 +4967,33 @@ preserve_value (cselib_val *val)
   VEC_safe_push (rtx, heap, preserved_values, val->val_rtx);
 }
 
+/* Helper function for MO_VAL_LOC handling.  Return non-zero if
+   any rtxes not suitable for CONST use not replaced by VALUEs
+   are discovered.  */
+
+static int
+non_suitable_const (rtx *x, void *data ATTRIBUTE_UNUSED)
+{
+  if (*x == NULL_RTX)
+    return 0;
+
+  switch (GET_CODE (*x))
+    {
+    case REG:
+    case DEBUG_EXPR:
+    case PC:
+    case SCRATCH:
+    case CC0:
+    case ASM_INPUT:
+    case ASM_OPERANDS:
+      return 1;
+    case MEM:
+      return !MEM_READONLY_P (*x);
+    default:
+      return 0;
+    }
+}
+
 /* Add uses (register and memory references) LOC which will be tracked
    to VTI (bb)->mos.  INSN is instruction which the LOC is part of.  */
 
@@ -4704,11 +5008,11 @@ add_uses (rtx *ploc, void *data)
   if (type != MO_CLOBBER)
     {
       basic_block bb = cui->bb;
-      micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
+      micro_operation mo;
 
-      mo->type = type;
-      mo->u.loc = type == MO_USE ? var_lowpart (mode, loc) : loc;
-      mo->insn = cui->insn;
+      mo.type = type;
+      mo.u.loc = type == MO_USE ? var_lowpart (mode, loc) : loc;
+      mo.insn = cui->insn;
 
       if (type == MO_VAL_LOC)
        {
@@ -4719,34 +5023,39 @@ add_uses (rtx *ploc, void *data)
          gcc_assert (cui->sets);
 
          if (MEM_P (vloc)
-             && !REG_P (XEXP (vloc, 0)) && !MEM_P (XEXP (vloc, 0)))
+             && !REG_P (XEXP (vloc, 0))
+             && !MEM_P (XEXP (vloc, 0))
+             && (GET_CODE (XEXP (vloc, 0)) != PLUS
+                 || XEXP (XEXP (vloc, 0), 0) != cfa_base_rtx
+                 || !CONST_INT_P (XEXP (XEXP (vloc, 0), 1))))
            {
              rtx mloc = vloc;
-             enum machine_mode address_mode
-               = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mloc));
+             enum machine_mode address_mode = get_address_mode (mloc);
              cselib_val *val
                = cselib_lookup (XEXP (mloc, 0), address_mode, 0);
 
              if (val && !cselib_preserved_value_p (val))
                {
-                 micro_operation *mon = VTI (bb)->mos + VTI (bb)->n_mos++;
-                 mon->type = mo->type;
-                 mon->u.loc = mo->u.loc;
-                 mon->insn = mo->insn;
+                 micro_operation moa;
                  preserve_value (val);
-                 mo->type = MO_VAL_USE;
                  mloc = cselib_subst_to_values (XEXP (mloc, 0));
-                 mo->u.loc = gen_rtx_CONCAT (address_mode,
+                 moa.type = MO_VAL_USE;
+                 moa.insn = cui->insn;
+                 moa.u.loc = gen_rtx_CONCAT (address_mode,
                                              val->val_rtx, mloc);
                  if (dump_file && (dump_flags & TDF_DETAILS))
-                   log_op_type (mo->u.loc, cui->bb, cui->insn,
-                                mo->type, dump_file);
-                 mo = mon;
+                   log_op_type (moa.u.loc, cui->bb, cui->insn,
+                                moa.type, dump_file);
+                 VEC_safe_push (micro_operation, heap, VTI (bb)->mos, &moa);
                }
            }
 
-         if (!VAR_LOC_UNKNOWN_P (vloc)
-             && (val = find_use_val (vloc, GET_MODE (oloc), cui)))
+         if (CONSTANT_P (vloc)
+             && (GET_CODE (vloc) != CONST
+                 || for_each_rtx (&vloc, non_suitable_const, NULL)))
+           /* For constants don't look up any value.  */;
+         else if (!VAR_LOC_UNKNOWN_P (vloc)
+                  && (val = find_use_val (vloc, GET_MODE (oloc), cui)))
            {
              enum machine_mode mode2;
              enum micro_operation_type type2;
@@ -4778,7 +5087,7 @@ add_uses (rtx *ploc, void *data)
              PAT_VAR_LOCATION_LOC (oloc) = gen_rtx_UNKNOWN_VAR_LOC ();
            }
 
-         mo->u.loc = oloc;
+         mo.u.loc = oloc;
        }
       else if (type == MO_VAL_USE)
        {
@@ -4790,30 +5099,30 @@ add_uses (rtx *ploc, void *data)
          gcc_assert (cui->sets);
 
          if (MEM_P (oloc)
-             && !REG_P (XEXP (oloc, 0)) && !MEM_P (XEXP (oloc, 0)))
+             && !REG_P (XEXP (oloc, 0))
+             && !MEM_P (XEXP (oloc, 0))
+             && (GET_CODE (XEXP (oloc, 0)) != PLUS
+                 || XEXP (XEXP (oloc, 0), 0) != cfa_base_rtx
+                 || !CONST_INT_P (XEXP (XEXP (oloc, 0), 1))))
            {
              rtx mloc = oloc;
-             enum machine_mode address_mode
-               = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mloc));
+             enum machine_mode address_mode = get_address_mode (mloc);
              cselib_val *val
                = cselib_lookup (XEXP (mloc, 0), address_mode, 0);
 
              if (val && !cselib_preserved_value_p (val))
                {
-                 micro_operation *mon = VTI (bb)->mos + VTI (bb)->n_mos++;
-                 mon->type = mo->type;
-                 mon->u.loc = mo->u.loc;
-                 mon->insn = mo->insn;
+                 micro_operation moa;
                  preserve_value (val);
-                 mo->type = MO_VAL_USE;
                  mloc = cselib_subst_to_values (XEXP (mloc, 0));
-                 mo->u.loc = gen_rtx_CONCAT (address_mode,
+                 moa.type = MO_VAL_USE;
+                 moa.insn = cui->insn;
+                 moa.u.loc = gen_rtx_CONCAT (address_mode,
                                              val->val_rtx, mloc);
-                 mo->insn = cui->insn;
                  if (dump_file && (dump_flags & TDF_DETAILS))
-                   log_op_type (mo->u.loc, cui->bb, cui->insn,
-                                mo->type, dump_file);
-                 mo = mon;
+                   log_op_type (moa.u.loc, cui->bb, cui->insn,
+                                moa.type, dump_file);
+                 VEC_safe_push (micro_operation, heap, VTI (bb)->mos, &moa);
                }
            }
 
@@ -4846,13 +5155,13 @@ add_uses (rtx *ploc, void *data)
          else
            oloc = val->val_rtx;
 
-         mo->u.loc = gen_rtx_CONCAT (mode, oloc, nloc);
+         mo.u.loc = gen_rtx_CONCAT (mode, oloc, nloc);
 
          if (type2 == MO_USE)
-           VAL_HOLDS_TRACK_EXPR (mo->u.loc) = 1;
+           VAL_HOLDS_TRACK_EXPR (mo.u.loc) = 1;
          if (!cselib_preserved_value_p (val))
            {
-             VAL_NEEDS_RESOLUTION (mo->u.loc) = 1;
+             VAL_NEEDS_RESOLUTION (mo.u.loc) = 1;
              preserve_value (val);
            }
        }
@@ -4860,7 +5169,8 @@ add_uses (rtx *ploc, void *data)
        gcc_assert (type == MO_USE || type == MO_USE_NO_VAR);
 
       if (dump_file && (dump_flags & TDF_DETAILS))
-       log_op_type (mo->u.loc, cui->bb, cui->insn, mo->type, dump_file);
+       log_op_type (mo.u.loc, cui->bb, cui->insn, mo.type, dump_file);
+      VEC_safe_push (micro_operation, heap, VTI (bb)->mos, &mo);
     }
 
   return 0;
@@ -4899,14 +5209,19 @@ reverse_op (rtx val, const_rtx expr)
     case XOR:
     case NOT:
     case NEG:
+      if (!REG_P (XEXP (src, 0)))
+       return NULL_RTX;
+      break;
     case SIGN_EXTEND:
     case ZERO_EXTEND:
+      if (!REG_P (XEXP (src, 0)) && !MEM_P (XEXP (src, 0)))
+       return NULL_RTX;
       break;
     default:
       return NULL_RTX;
     }
 
-  if (!REG_P (XEXP (src, 0)) || !SCALAR_INT_MODE_P (GET_MODE (src)))
+  if (!SCALAR_INT_MODE_P (GET_MODE (src)) || XEXP (src, 0) == cfa_base_rtx)
     return NULL_RTX;
 
   v = cselib_lookup (XEXP (src, 0), GET_MODE (XEXP (src, 0)), 0);
@@ -4960,21 +5275,6 @@ reverse_op (rtx val, const_rtx expr)
   return gen_rtx_CONCAT (GET_MODE (v->val_rtx), v->val_rtx, ret);
 }
 
-/* Return SRC, or, if it is a read-only MEM for which adjust_sets
-   replated it with a constant from REG_EQUIV/REG_EQUAL note,
-   that constant.  */
-
-static inline rtx
-get_adjusted_src (struct count_use_info *cui, rtx src)
-{
-  if (cui->n_sets == 1
-      && MEM_P (src)
-      && MEM_READONLY_P (src)
-      && CONSTANT_P (cui->sets[0].src))
-    return cui->sets[0].src;
-  return src;
-}
-
 /* Add stores (register and memory references) LOC which will be tracked
    to VTI (bb)->mos.  EXPR is the RTL expression containing the store.
    CUIP->insn is instruction which the LOC is part of.  */
@@ -4985,7 +5285,7 @@ add_stores (rtx loc, const_rtx expr, void *cuip)
   enum machine_mode mode = VOIDmode, mode2;
   struct count_use_info *cui = (struct count_use_info *)cuip;
   basic_block bb = cui->bb;
-  micro_operation *mo;
+  micro_operation mo;
   rtx oloc = loc, nloc, src = NULL;
   enum micro_operation_type type = use_type (loc, cui, &mode);
   bool track_p = false;
@@ -5000,107 +5300,96 @@ add_stores (rtx loc, const_rtx expr, void *cuip)
 
   if (REG_P (loc))
     {
-      mo = VTI (bb)->mos + VTI (bb)->n_mos++;
-
+      gcc_assert (loc != cfa_base_rtx);
       if ((GET_CODE (expr) == CLOBBER && type != MO_VAL_SET)
          || !(track_p = use_type (loc, NULL, &mode2) == MO_USE)
          || GET_CODE (expr) == CLOBBER)
        {
-         mo->type = MO_CLOBBER;
-         mo->u.loc = loc;
+         mo.type = MO_CLOBBER;
+         mo.u.loc = loc;
        }
       else
        {
          if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
-           {
-             src = get_adjusted_src (cui, SET_SRC (expr));
-             src = var_lowpart (mode2, src);
-           }
+           src = var_lowpart (mode2, SET_SRC (expr));
          loc = var_lowpart (mode2, loc);
 
          if (src == NULL)
            {
-             mo->type = MO_SET;
-             mo->u.loc = loc;
+             mo.type = MO_SET;
+             mo.u.loc = loc;
            }
          else
            {
-             rtx xexpr = CONST_CAST_RTX (expr);
-
-             if (SET_SRC (expr) != src)
-               xexpr = gen_rtx_SET (VOIDmode, loc, src);
+             rtx xexpr = gen_rtx_SET (VOIDmode, loc, src);
              if (same_variable_part_p (src, REG_EXPR (loc), REG_OFFSET (loc)))
-               mo->type = MO_COPY;
+               mo.type = MO_COPY;
              else
-               mo->type = MO_SET;
-             mo->u.loc = xexpr;
+               mo.type = MO_SET;
+             mo.u.loc = xexpr;
            }
        }
-      mo->insn = cui->insn;
+      mo.insn = cui->insn;
     }
   else if (MEM_P (loc)
           && ((track_p = use_type (loc, NULL, &mode2) == MO_USE)
               || cui->sets))
     {
-      mo = VTI (bb)->mos + VTI (bb)->n_mos++;
-
       if (MEM_P (loc) && type == MO_VAL_SET
-         && !REG_P (XEXP (loc, 0)) && !MEM_P (XEXP (loc, 0)))
+         && !REG_P (XEXP (loc, 0))
+         && !MEM_P (XEXP (loc, 0))
+         && (GET_CODE (XEXP (loc, 0)) != PLUS
+             || XEXP (XEXP (loc, 0), 0) != cfa_base_rtx
+             || !CONST_INT_P (XEXP (XEXP (loc, 0), 1))))
        {
          rtx mloc = loc;
-         enum machine_mode address_mode
-           = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mloc));
-         cselib_val *val = cselib_lookup (XEXP (mloc, 0), address_mode, 0);
+         enum machine_mode address_mode = get_address_mode (mloc);
+         cselib_val *val = cselib_lookup (XEXP (mloc, 0),
+                                          address_mode, 0);
 
          if (val && !cselib_preserved_value_p (val))
            {
              preserve_value (val);
-             mo->type = MO_VAL_USE;
+             mo.type = MO_VAL_USE;
              mloc = cselib_subst_to_values (XEXP (mloc, 0));
-             mo->u.loc = gen_rtx_CONCAT (address_mode, val->val_rtx, mloc);
-             mo->insn = cui->insn;
+             mo.u.loc = gen_rtx_CONCAT (address_mode, val->val_rtx, mloc);
+             mo.insn = cui->insn;
              if (dump_file && (dump_flags & TDF_DETAILS))
-               log_op_type (mo->u.loc, cui->bb, cui->insn,
-                            mo->type, dump_file);
-             mo = VTI (bb)->mos + VTI (bb)->n_mos++;
+               log_op_type (mo.u.loc, cui->bb, cui->insn,
+                            mo.type, dump_file);
+             VEC_safe_push (micro_operation, heap, VTI (bb)->mos, &mo);
            }
        }
 
       if (GET_CODE (expr) == CLOBBER || !track_p)
        {
-         mo->type = MO_CLOBBER;
-         mo->u.loc = track_p ? var_lowpart (mode2, loc) : loc;
+         mo.type = MO_CLOBBER;
+         mo.u.loc = track_p ? var_lowpart (mode2, loc) : loc;
        }
       else
        {
          if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
-           {
-             src = get_adjusted_src (cui, SET_SRC (expr));
-             src = var_lowpart (mode2, src);
-           }
+           src = var_lowpart (mode2, SET_SRC (expr));
          loc = var_lowpart (mode2, loc);
 
          if (src == NULL)
            {
-             mo->type = MO_SET;
-             mo->u.loc = loc;
+             mo.type = MO_SET;
+             mo.u.loc = loc;
            }
          else
            {
-             rtx xexpr = CONST_CAST_RTX (expr);
-
-             if (SET_SRC (expr) != src)
-               xexpr = gen_rtx_SET (VOIDmode, loc, src);
+             rtx xexpr = gen_rtx_SET (VOIDmode, loc, src);
              if (same_variable_part_p (SET_SRC (xexpr),
                                        MEM_EXPR (loc),
                                        INT_MEM_OFFSET (loc)))
-               mo->type = MO_COPY;
+               mo.type = MO_COPY;
              else
-               mo->type = MO_SET;
-             mo->u.loc = xexpr;
+               mo.type = MO_SET;
+             mo.u.loc = xexpr;
            }
        }
-      mo->insn = cui->insn;
+      mo.insn = cui->insn;
     }
   else
     return;
@@ -5128,59 +5417,59 @@ add_stores (rtx loc, const_rtx expr, void *cuip)
 
       if (!cselib_preserved_value_p (oval))
        {
-         micro_operation *nmo = VTI (bb)->mos + VTI (bb)->n_mos++;
+         micro_operation moa;
 
          preserve_value (oval);
 
-         nmo->type = MO_VAL_USE;
-         nmo->u.loc = gen_rtx_CONCAT (mode, oval->val_rtx, oloc);
-         VAL_NEEDS_RESOLUTION (nmo->u.loc) = 1;
-         nmo->insn = mo->insn;
+         moa.type = MO_VAL_USE;
+         moa.u.loc = gen_rtx_CONCAT (mode, oval->val_rtx, oloc);
+         VAL_NEEDS_RESOLUTION (moa.u.loc) = 1;
+         moa.insn = cui->insn;
 
          if (dump_file && (dump_flags & TDF_DETAILS))
-           log_op_type (nmo->u.loc, cui->bb, cui->insn,
-                        nmo->type, dump_file);
+           log_op_type (moa.u.loc, cui->bb, cui->insn,
+                        moa.type, dump_file);
+         VEC_safe_push (micro_operation, heap, VTI (bb)->mos, &moa);
        }
 
       resolve = false;
     }
-  else if (resolve && GET_CODE (mo->u.loc) == SET)
+  else if (resolve && GET_CODE (mo.u.loc) == SET)
     {
-      src = get_adjusted_src (cui, SET_SRC (expr));
-      nloc = replace_expr_with_values (src);
+      nloc = replace_expr_with_values (SET_SRC (expr));
 
       /* Avoid the mode mismatch between oexpr and expr.  */
       if (!nloc && mode != mode2)
        {
-         nloc = src;
+         nloc = SET_SRC (expr);
          gcc_assert (oloc == SET_DEST (expr));
        }
 
       if (nloc)
-       oloc = gen_rtx_SET (GET_MODE (mo->u.loc), oloc, nloc);
+       oloc = gen_rtx_SET (GET_MODE (mo.u.loc), oloc, nloc);
       else
        {
-         if (oloc == SET_DEST (mo->u.loc))
+         if (oloc == SET_DEST (mo.u.loc))
            /* No point in duplicating.  */
-           oloc = mo->u.loc;
-         if (!REG_P (SET_SRC (mo->u.loc)))
+           oloc = mo.u.loc;
+         if (!REG_P (SET_SRC (mo.u.loc)))
            resolve = false;
        }
     }
   else if (!resolve)
     {
-      if (GET_CODE (mo->u.loc) == SET
-         && oloc == SET_DEST (mo->u.loc))
+      if (GET_CODE (mo.u.loc) == SET
+         && oloc == SET_DEST (mo.u.loc))
        /* No point in duplicating.  */
-       oloc = mo->u.loc;
+       oloc = mo.u.loc;
     }
   else
     resolve = false;
 
   loc = gen_rtx_CONCAT (mode, v->val_rtx, oloc);
 
-  if (mo->u.loc != oloc)
-    loc = gen_rtx_CONCAT (GET_MODE (mo->u.loc), loc, mo->u.loc);
+  if (mo.u.loc != oloc)
+    loc = gen_rtx_CONCAT (GET_MODE (mo.u.loc), loc, mo.u.loc);
 
   /* The loc of a MO_VAL_SET may have various forms:
 
@@ -5207,12 +5496,12 @@ add_stores (rtx loc, const_rtx expr, void *cuip)
       reverse = reverse_op (v->val_rtx, expr);
       if (reverse)
        {
-         loc = gen_rtx_CONCAT (GET_MODE (mo->u.loc), loc, reverse);
+         loc = gen_rtx_CONCAT (GET_MODE (mo.u.loc), loc, reverse);
          VAL_EXPR_HAS_REVERSE (loc) = 1;
        }
     }
 
-  mo->u.loc = loc;
+  mo.u.loc = loc;
 
   if (track_p)
     VAL_HOLDS_TRACK_EXPR (loc) = 1;
@@ -5221,16 +5510,17 @@ add_stores (rtx loc, const_rtx expr, void *cuip)
       VAL_NEEDS_RESOLUTION (loc) = resolve;
       preserve_value (v);
     }
-  if (mo->type == MO_CLOBBER)
+  if (mo.type == MO_CLOBBER)
     VAL_EXPR_IS_CLOBBERED (loc) = 1;
-  if (mo->type == MO_COPY)
+  if (mo.type == MO_COPY)
     VAL_EXPR_IS_COPIED (loc) = 1;
 
-  mo->type = MO_VAL_SET;
+  mo.type = MO_VAL_SET;
 
  log_and_return:
   if (dump_file && (dump_flags & TDF_DETAILS))
-    log_op_type (mo->u.loc, cui->bb, cui->insn, mo->type, dump_file);
+    log_op_type (mo.u.loc, cui->bb, cui->insn, mo.type, dump_file);
+  VEC_safe_push (micro_operation, heap, VTI (bb)->mos, &mo);
 }
 
 /* Callback for cselib_record_sets_hook, that records as micro
@@ -5246,90 +5536,111 @@ add_with_sets (rtx insn, struct cselib_set *sets, int n_sets)
   basic_block bb = BLOCK_FOR_INSN (insn);
   int n1, n2;
   struct count_use_info cui;
+  micro_operation *mos;
 
   cselib_hook_called = true;
 
-  adjust_sets (insn, sets, n_sets);
-
   cui.insn = insn;
   cui.bb = bb;
   cui.sets = sets;
   cui.n_sets = n_sets;
 
-  n1 = VTI (bb)->n_mos;
+  n1 = VEC_length (micro_operation, VTI (bb)->mos);
   cui.store_p = false;
   note_uses (&PATTERN (insn), add_uses_1, &cui);
-  n2 = VTI (bb)->n_mos - 1;
+  n2 = VEC_length (micro_operation, VTI (bb)->mos) - 1;
+  mos = VEC_address (micro_operation, VTI (bb)->mos);
 
   /* Order the MO_USEs to be before MO_USE_NO_VARs and MO_VAL_USE, and
      MO_VAL_LOC last.  */
   while (n1 < n2)
     {
-      while (n1 < n2 && VTI (bb)->mos[n1].type == MO_USE)
+      while (n1 < n2 && mos[n1].type == MO_USE)
        n1++;
-      while (n1 < n2 && VTI (bb)->mos[n2].type != MO_USE)
+      while (n1 < n2 && mos[n2].type != MO_USE)
        n2--;
       if (n1 < n2)
        {
          micro_operation sw;
 
-         sw = VTI (bb)->mos[n1];
-         VTI (bb)->mos[n1] = VTI (bb)->mos[n2];
-         VTI (bb)->mos[n2] = sw;
+         sw = mos[n1];
+         mos[n1] = mos[n2];
+         mos[n2] = sw;
        }
     }
 
-  n2 = VTI (bb)->n_mos - 1;
-
+  n2 = VEC_length (micro_operation, VTI (bb)->mos) - 1;
   while (n1 < n2)
     {
-      while (n1 < n2 && VTI (bb)->mos[n1].type != MO_VAL_LOC)
+      while (n1 < n2 && mos[n1].type != MO_VAL_LOC)
        n1++;
-      while (n1 < n2 && VTI (bb)->mos[n2].type == MO_VAL_LOC)
+      while (n1 < n2 && mos[n2].type == MO_VAL_LOC)
        n2--;
       if (n1 < n2)
        {
          micro_operation sw;
 
-         sw = VTI (bb)->mos[n1];
-         VTI (bb)->mos[n1] = VTI (bb)->mos[n2];
-         VTI (bb)->mos[n2] = sw;
+         sw = mos[n1];
+         mos[n1] = mos[n2];
+         mos[n2] = sw;
        }
     }
 
   if (CALL_P (insn))
     {
-      micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
+      micro_operation mo;
 
-      mo->type = MO_CALL;
-      mo->insn = insn;
+      mo.type = MO_CALL;
+      mo.insn = insn;
+      mo.u.loc = NULL_RTX;
 
       if (dump_file && (dump_flags & TDF_DETAILS))
-       log_op_type (PATTERN (insn), bb, insn, mo->type, dump_file);
+       log_op_type (PATTERN (insn), bb, insn, mo.type, dump_file);
+      VEC_safe_push (micro_operation, heap, VTI (bb)->mos, &mo);
     }
 
-  n1 = VTI (bb)->n_mos;
+  n1 = VEC_length (micro_operation, VTI (bb)->mos);
   /* This will record NEXT_INSN (insn), such that we can
      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);
-  n2 = VTI (bb)->n_mos - 1;
+  n2 = VEC_length (micro_operation, VTI (bb)->mos) - 1;
+  mos = VEC_address (micro_operation, VTI (bb)->mos);
 
-  /* Order the MO_CLOBBERs to be before MO_SETs.  */
+  /* Order the MO_VAL_USEs first (note_stores does nothing
+     on DEBUG_INSNs, so there are no MO_VAL_LOCs from this
+     insn), then MO_CLOBBERs, then MO_SET/MO_COPY/MO_VAL_SET.  */
   while (n1 < n2)
     {
-      while (n1 < n2 && VTI (bb)->mos[n1].type == MO_CLOBBER)
+      while (n1 < n2 && mos[n1].type == MO_VAL_USE)
        n1++;
-      while (n1 < n2 && VTI (bb)->mos[n2].type != MO_CLOBBER)
+      while (n1 < n2 && mos[n2].type != MO_VAL_USE)
        n2--;
       if (n1 < n2)
        {
          micro_operation sw;
 
-         sw = VTI (bb)->mos[n1];
-         VTI (bb)->mos[n1] = VTI (bb)->mos[n2];
-         VTI (bb)->mos[n2] = sw;
+         sw = mos[n1];
+         mos[n1] = mos[n2];
+         mos[n2] = sw;
+       }
+    }
+
+  n2 = VEC_length (micro_operation, VTI (bb)->mos) - 1;
+  while (n1 < n2)
+    {
+      while (n1 < n2 && mos[n1].type == MO_CLOBBER)
+       n1++;
+      while (n1 < n2 && mos[n2].type != MO_CLOBBER)
+       n2--;
+      if (n1 < n2)
+       {
+         micro_operation sw;
+
+         sw = mos[n1];
+         mos[n1] = mos[n2];
+         mos[n2] = sw;
        }
     }
 }
@@ -5401,7 +5712,8 @@ find_src_set_src (dataflow_set *set, rtx src)
 static bool
 compute_bb_dataflow (basic_block bb)
 {
-  int i, n;
+  unsigned int i;
+  micro_operation *mo;
   bool changed;
   dataflow_set old_out;
   dataflow_set *in = &VTI (bb)->in;
@@ -5411,12 +5723,11 @@ compute_bb_dataflow (basic_block bb)
   dataflow_set_copy (&old_out, out);
   dataflow_set_copy (out, in);
 
-  n = VTI (bb)->n_mos;
-  for (i = 0; i < n; i++)
+  FOR_EACH_VEC_ELT (micro_operation, VTI (bb)->mos, i, mo)
     {
-      rtx insn = VTI (bb)->mos[i].insn;
+      rtx insn = mo->insn;
 
-      switch (VTI (bb)->mos[i].type)
+      switch (mo->type)
        {
          case MO_CALL:
            dataflow_set_clear_at_call (out);
@@ -5424,7 +5735,7 @@ compute_bb_dataflow (basic_block bb)
 
          case MO_USE:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
 
              if (REG_P (loc))
                var_reg_set (out, loc, VAR_INIT_STATUS_UNINITIALIZED, NULL);
@@ -5435,7 +5746,7 @@ compute_bb_dataflow (basic_block bb)
 
          case MO_VAL_LOC:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
              rtx val, vloc;
              tree var;
 
@@ -5462,12 +5773,17 @@ compute_bb_dataflow (basic_block bb)
                                     VAR_INIT_STATUS_INITIALIZED, NULL_RTX,
                                     INSERT);
                }
+             else if (!VAR_LOC_UNKNOWN_P (PAT_VAR_LOCATION_LOC (vloc)))
+               set_variable_part (out, PAT_VAR_LOCATION_LOC (vloc),
+                                  dv_from_decl (var), 0,
+                                  VAR_INIT_STATUS_INITIALIZED, NULL_RTX,
+                                  INSERT);
            }
            break;
 
          case MO_VAL_USE:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
              rtx val, vloc, uloc;
 
              vloc = uloc = XEXP (loc, 1);
@@ -5498,7 +5814,7 @@ compute_bb_dataflow (basic_block bb)
 
          case MO_VAL_SET:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
              rtx val, vloc, uloc, reverse = NULL_RTX;
 
              vloc = loc;
@@ -5591,7 +5907,7 @@ compute_bb_dataflow (basic_block bb)
 
          case MO_SET:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
              rtx set_src = NULL;
 
              if (GET_CODE (loc) == SET)
@@ -5611,7 +5927,7 @@ compute_bb_dataflow (basic_block bb)
 
          case MO_COPY:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
              enum var_init_status src_status;
              rtx set_src = NULL;
 
@@ -5642,7 +5958,7 @@ compute_bb_dataflow (basic_block bb)
 
          case MO_USE_NO_VAR:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
 
              if (REG_P (loc))
                var_reg_delete (out, loc, false);
@@ -5653,7 +5969,7 @@ compute_bb_dataflow (basic_block bb)
 
          case MO_CLOBBER:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
 
              if (REG_P (loc))
                var_reg_delete (out, loc, true);
@@ -5663,7 +5979,7 @@ compute_bb_dataflow (basic_block bb)
            break;
 
          case MO_ADJUST:
-           out->stack_adjust += VTI (bb)->mos[i].u.adjust;
+           out->stack_adjust += mo->u.adjust;
            break;
        }
     }
@@ -5701,6 +6017,7 @@ vt_find_locations (void)
   int htabmax = PARAM_VALUE (PARAM_MAX_VARTRACK_SIZE);
   bool success = true;
 
+  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 - NUM_FIXED_BLOCKS);
@@ -5736,6 +6053,7 @@ vt_find_locations (void)
        {
          bb = (basic_block) fibheap_extract_min (worklist);
          RESET_BIT (in_worklist, bb->index);
+         gcc_assert (!TEST_BIT (visited, bb->index));
          if (!TEST_BIT (visited, bb->index))
            {
              bool changed;
@@ -5888,6 +6206,7 @@ vt_find_locations (void)
   sbitmap_free (in_worklist);
   sbitmap_free (in_pending);
 
+  timevar_pop (TV_VAR_TRACKING_DATAFLOW);
   return success;
 }
 
@@ -6708,14 +7027,13 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
                result = pc_rtx;
                break;
              }
-           else
-             {
-               result = cselib_expand_value_rtx_cb (loc->loc, regs, max_depth,
-                                                    vt_expand_loc_callback,
-                                                    data);
-               if (result)
-                 break;
-             }
+         }
+       else
+         {
+           result = cselib_expand_value_rtx_cb (loc->loc, regs, max_depth,
+                                                vt_expand_loc_callback, data);
+           if (result)
+             break;
          }
       if (dummy && (result || var->var_part[0].cur_loc))
        var->cur_loc_changed = true;
@@ -6750,7 +7068,7 @@ 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, 5,
+  loc = cselib_expand_value_rtx_cb (loc, scratch_regs, 8,
                                    vt_expand_loc_callback, &data);
 
   if (loc && MEM_P (loc))
@@ -6771,7 +7089,7 @@ 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, 5,
+  ret = cselib_dummy_expand_value_rtx_cb (loc, scratch_regs, 8,
                                          vt_expand_loc_callback, &data);
   *pcur_loc_changed = data.cur_loc_changed;
   return ret;
@@ -6780,6 +7098,19 @@ vt_expand_loc_dummy (rtx loc, htab_t vars, bool *pcur_loc_changed)
 #ifdef ENABLE_RTL_CHECKING
 /* Used to verify that cur_loc_changed updating is safe.  */
 static struct pointer_map_t *emitted_notes;
+
+/* Strip REG_POINTER from REGs and MEM_POINTER from MEMs in order to
+   avoid differences in commutative operand simplification.  */
+static rtx
+strip_pointer_flags (rtx x, const_rtx old_rtx ATTRIBUTE_UNUSED,
+                    void *data ATTRIBUTE_UNUSED)
+{
+  if (REG_P (x) && REG_POINTER (x))
+    return gen_rtx_REG (GET_MODE (x), REGNO (x));
+  if (MEM_P (x) && MEM_POINTER (x))
+    return gen_rtx_MEM (GET_MODE (x), XEXP (x, 0));
+  return NULL_RTX;
+}
 #endif
 
 /* Emit the NOTE_INSN_VAR_LOCATION for variable *VARP.  DATA contains
@@ -6815,7 +7146,7 @@ emit_note_insn_var_location (void **varp, void *data)
   complete = true;
   last_limit = 0;
   n_var_parts = 0;
-  if (!MAY_HAVE_DEBUG_STMTS)
+  if (!MAY_HAVE_DEBUG_INSNS)
     {
       for (i = 0; i < var->n_var_parts; i++)
        if (var->var_part[i].cur_loc == NULL && var->var_part[i].loc_chain)
@@ -6856,6 +7187,8 @@ emit_note_insn_var_location (void **varp, void *data)
        }
       loc[n_var_parts] = loc2;
       mode = GET_MODE (var->var_part[i].cur_loc);
+      if (mode == VOIDmode && dv_onepart_p (var->dv))
+       mode = DECL_MODE (decl);
       for (lc = var->var_part[i].loc_chain; lc; lc = lc->next)
        if (var->var_part[i].cur_loc == lc->loc)
          {
@@ -6945,8 +7278,12 @@ emit_note_insn_var_location (void **varp, void *data)
                                    (int) initialized);
   else if (n_var_parts == 1)
     {
-      rtx expr_list
-       = gen_rtx_EXPR_LIST (VOIDmode, loc[0], GEN_INT (offsets[0]));
+      rtx expr_list;
+
+      if (offsets[0] || GET_CODE (loc[0]) == PARALLEL)
+       expr_list = gen_rtx_EXPR_LIST (VOIDmode, loc[0], GEN_INT (offsets[0]));
+      else
+       expr_list = loc[0];
 
       note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl, expr_list,
                                      (int) initialized);
@@ -6972,9 +7309,22 @@ emit_note_insn_var_location (void **varp, void *data)
       rtx pnote = (rtx) *note_slot;
       if (!var->cur_loc_changed && (pnote || PAT_VAR_LOCATION_LOC (note_vl)))
        {
+         rtx old_vl, new_vl;
          gcc_assert (pnote);
-         gcc_assert (rtx_equal_p (PAT_VAR_LOCATION_LOC (pnote),
-                                  PAT_VAR_LOCATION_LOC (note_vl)));
+         old_vl = PAT_VAR_LOCATION_LOC (pnote);
+         new_vl = PAT_VAR_LOCATION_LOC (note_vl);
+         if (!rtx_equal_p (old_vl, new_vl))
+           {
+             /* There might be differences caused by REG_POINTER
+                differences.  REG_POINTER affects
+                swap_commutative_operands_p.  */
+             old_vl = simplify_replace_fn_rtx (old_vl, NULL_RTX,
+                                               strip_pointer_flags, NULL);
+             new_vl = simplify_replace_fn_rtx (new_vl, NULL_RTX,
+                                               strip_pointer_flags, NULL);
+             gcc_assert (rtx_equal_p (old_vl, new_vl));
+             PAT_VAR_LOCATION_LOC (note_vl) = new_vl;
+           }
        }
       *note_slot = (void *) note_vl;
     }
@@ -6989,7 +7339,17 @@ emit_note_insn_var_location (void **varp, void *data)
        NOTE_DURING_CALL_P (note) = true;
     }
   else
-    note = emit_note_before (NOTE_INSN_VAR_LOCATION, insn);
+    {
+      /* Make sure that the call related notes come first.  */
+      while (NEXT_INSN (insn)
+            && NOTE_P (insn)
+            && NOTE_DURING_CALL_P (insn))
+       insn = NEXT_INSN (insn);
+      if (NOTE_P (insn) && NOTE_DURING_CALL_P (insn))
+       note = emit_note_after (NOTE_INSN_VAR_LOCATION, insn);
+      else
+       note = emit_note_before (NOTE_INSN_VAR_LOCATION, insn);
+    }
   NOTE_VAR_LOCATION (note) = note_vl;
 
  clear:
@@ -7213,8 +7573,8 @@ emit_notes_for_differences_1 (void **slot, void *data)
        {
          location_chain lc1, lc2;
 
-         gcc_assert (old_var->n_var_parts == 1);
-         gcc_assert (new_var->n_var_parts == 1);
+         gcc_assert (old_var->n_var_parts == 1
+                     && new_var->n_var_parts == 1);
          lc1 = old_var->var_part[0].loc_chain;
          lc2 = new_var->var_part[0].loc_chain;
          while (lc1
@@ -7318,16 +7678,17 @@ emit_notes_for_differences (rtx insn, dataflow_set *old_set,
 static void
 emit_notes_in_bb (basic_block bb, dataflow_set *set)
 {
-  int i;
+  unsigned int i;
+  micro_operation *mo;
 
   dataflow_set_clear (set);
   dataflow_set_copy (set, &VTI (bb)->in);
 
-  for (i = 0; i < VTI (bb)->n_mos; i++)
+  FOR_EACH_VEC_ELT (micro_operation, VTI (bb)->mos, i, mo)
     {
-      rtx insn = VTI (bb)->mos[i].insn;
+      rtx insn = mo->insn;
 
-      switch (VTI (bb)->mos[i].type)
+      switch (mo->type)
        {
          case MO_CALL:
            dataflow_set_clear_at_call (set);
@@ -7336,7 +7697,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
 
          case MO_USE:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
 
              if (REG_P (loc))
                var_reg_set (set, loc, VAR_INIT_STATUS_UNINITIALIZED, NULL);
@@ -7349,7 +7710,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
 
          case MO_VAL_LOC:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
              rtx val, vloc;
              tree var;
 
@@ -7376,6 +7737,11 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
                                     VAR_INIT_STATUS_INITIALIZED, NULL_RTX,
                                     INSERT);
                }
+             else if (!VAR_LOC_UNKNOWN_P (PAT_VAR_LOCATION_LOC (vloc)))
+               set_variable_part (set, PAT_VAR_LOCATION_LOC (vloc),
+                                  dv_from_decl (var), 0,
+                                  VAR_INIT_STATUS_INITIALIZED, NULL_RTX,
+                                  INSERT);
 
              emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN, set->vars);
            }
@@ -7383,7 +7749,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
 
          case MO_VAL_USE:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
              rtx val, vloc, uloc;
 
              vloc = uloc = XEXP (loc, 1);
@@ -7416,7 +7782,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
 
          case MO_VAL_SET:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
              rtx val, vloc, uloc, reverse = NULL_RTX;
 
              vloc = loc;
@@ -7506,7 +7872,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
 
          case MO_SET:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
              rtx set_src = NULL;
 
              if (GET_CODE (loc) == SET)
@@ -7529,7 +7895,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
 
          case MO_COPY:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
              enum var_init_status src_status;
              rtx set_src = NULL;
 
@@ -7554,7 +7920,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
 
          case MO_USE_NO_VAR:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
 
              if (REG_P (loc))
                var_reg_delete (set, loc, false);
@@ -7567,7 +7933,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
 
          case MO_CLOBBER:
            {
-             rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx loc = mo->u.loc;
 
              if (REG_P (loc))
                var_reg_delete (set, loc, true);
@@ -7580,7 +7946,7 @@ emit_notes_in_bb (basic_block bb, dataflow_set *set)
            break;
 
          case MO_ADJUST:
-           set->stack_adjust += VTI (bb)->mos[i].u.adjust;
+           set->stack_adjust += mo->u.adjust;
            break;
        }
     }
@@ -7613,7 +7979,7 @@ vt_emit_notes (void)
       unsigned int i;
       rtx val;
 
-      for (i = 0; VEC_iterate (rtx, preserved_values, i, val); i++)
+      FOR_EACH_VEC_ELT (rtx, preserved_values, i, val)
        add_cselib_value_chains (dv_from_value (val));
       changed_variables_stack = VEC_alloc (variable, heap, 40);
       changed_values_stack = VEC_alloc (rtx, heap, 40);
@@ -7643,7 +8009,7 @@ vt_emit_notes (void)
       unsigned int i;
       rtx val;
 
-      for (i = 0; VEC_iterate (rtx, preserved_values, i, val); i++)
+      FOR_EACH_VEC_ELT (rtx, preserved_values, i, val)
        remove_cselib_value_chains (dv_from_value (val));
       gcc_assert (htab_elements (value_chains) == 0);
     }
@@ -7697,7 +8063,7 @@ vt_add_function_parameters (void)
   tree parm;
 
   for (parm = DECL_ARGUMENTS (current_function_decl);
-       parm; parm = TREE_CHAIN (parm))
+       parm; parm = DECL_CHAIN (parm))
     {
       rtx decl_rtl = DECL_RTL_IF_SET (parm);
       rtx incoming = DECL_INCOMING_RTL (parm);
@@ -7806,25 +8172,128 @@ vt_add_function_parameters (void)
 
   if (MAY_HAVE_DEBUG_INSNS)
     {
-      cselib_preserve_only_values (true);
+      cselib_preserve_only_values ();
       cselib_reset_table (cselib_get_next_uid ());
     }
 
 }
 
+/* Return true if INSN in the prologue initializes hard_frame_pointer_rtx.  */
+
+static bool
+fp_setter (rtx insn)
+{
+  rtx pat = PATTERN (insn);
+  if (RTX_FRAME_RELATED_P (insn))
+    {
+      rtx expr = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
+      if (expr)
+       pat = XEXP (expr, 0);
+    }
+  if (GET_CODE (pat) == SET)
+    return SET_DEST (pat) == hard_frame_pointer_rtx;
+  else if (GET_CODE (pat) == PARALLEL)
+    {
+      int i;
+      for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)
+       if (GET_CODE (XVECEXP (pat, 0, i)) == SET
+           && SET_DEST (XVECEXP (pat, 0, i)) == hard_frame_pointer_rtx)
+         return true;
+    }
+  return false;
+}
+
+/* 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
+   has been eliminated.  */
+
+static void
+vt_init_cfa_base (void)
+{
+  cselib_val *val;
+
+#ifdef FRAME_POINTER_CFA_OFFSET
+  cfa_base_rtx = frame_pointer_rtx;
+  cfa_base_offset = -FRAME_POINTER_CFA_OFFSET (current_function_decl);
+#else
+  cfa_base_rtx = arg_pointer_rtx;
+  cfa_base_offset = -ARG_POINTER_CFA_OFFSET (current_function_decl);
+#endif
+  if (cfa_base_rtx == hard_frame_pointer_rtx
+      || !fixed_regs[REGNO (cfa_base_rtx)])
+    {
+      cfa_base_rtx = NULL_RTX;
+      return;
+    }
+  if (!MAY_HAVE_DEBUG_INSNS)
+    return;
+
+  /* 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);
+  val = cselib_lookup_from_insn (cfa_base_rtx, GET_MODE (cfa_base_rtx), 1,
+                                get_insns ());
+  preserve_value (val);
+  cselib_preserve_cfa_base_value (val, REGNO (cfa_base_rtx));
+  var_reg_decl_set (&VTI (ENTRY_BLOCK_PTR)->out, cfa_base_rtx,
+                   VAR_INIT_STATUS_INITIALIZED, dv_from_value (val->val_rtx),
+                   0, NULL_RTX, INSERT);
+}
+
 /* Allocate and initialize the data structures for variable tracking
    and parse the RTL to get the micro operations.  */
 
-static void
+static bool
 vt_initialize (void)
 {
-  basic_block bb;
+  basic_block bb, prologue_bb = NULL;
+  HOST_WIDE_INT fp_cfa_offset = -1;
 
   alloc_aux_for_blocks (sizeof (struct variable_tracking_info_def));
 
+  attrs_pool = create_alloc_pool ("attrs_def pool",
+                                 sizeof (struct attrs_def), 1024);
+  var_pool = create_alloc_pool ("variable_def pool",
+                               sizeof (struct variable_def)
+                               + (MAX_VAR_PARTS - 1)
+                               * sizeof (((variable)NULL)->var_part[0]), 64);
+  loc_chain_pool = create_alloc_pool ("location_chain_def pool",
+                                     sizeof (struct location_chain_def),
+                                     1024);
+  shared_hash_pool = create_alloc_pool ("shared_hash_def pool",
+                                       sizeof (struct shared_hash_def), 256);
+  empty_shared_hash = (shared_hash) pool_alloc (shared_hash_pool);
+  empty_shared_hash->refcount = 1;
+  empty_shared_hash->htab
+    = htab_create (1, variable_htab_hash, variable_htab_eq,
+                  variable_htab_free);
+  changed_variables = htab_create (10, variable_htab_hash, variable_htab_eq,
+                                  variable_htab_free);
+  if (MAY_HAVE_DEBUG_INSNS)
+    {
+      value_chain_pool = create_alloc_pool ("value_chain_def pool",
+                                           sizeof (struct value_chain_def),
+                                           1024);
+      value_chains = htab_create (32, value_chain_htab_hash,
+                                 value_chain_htab_eq, NULL);
+    }
+
+  /* Init the IN and OUT sets.  */
+  FOR_ALL_BB (bb)
+    {
+      VTI (bb)->visited = false;
+      VTI (bb)->flooded = false;
+      dataflow_set_init (&VTI (bb)->in);
+      dataflow_set_init (&VTI (bb)->out);
+      VTI (bb)->permp = NULL;
+    }
+
   if (MAY_HAVE_DEBUG_INSNS)
     {
-      cselib_init (true);
+      cselib_init (CSELIB_RECORD_MEMORY | CSELIB_PRESERVE_CONSTANTS);
       scratch_regs = BITMAP_ALLOC (NULL);
       valvar_pool = create_alloc_pool ("small variable_def pool",
                                       sizeof (struct variable_def), 256);
@@ -7836,17 +8305,64 @@ vt_initialize (void)
       valvar_pool = NULL;
     }
 
+  if (!frame_pointer_needed)
+    {
+      rtx reg, elim;
+
+      if (!vt_stack_adjustments ())
+       return false;
+
+#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 == stack_pointer_rtx)
+           vt_init_cfa_base ();
+       }
+    }
+  else if (!crtl->stack_realign_tried)
+    {
+      rtx reg, elim;
+
+#ifdef FRAME_POINTER_CFA_OFFSET
+      reg = frame_pointer_rtx;
+      fp_cfa_offset = FRAME_POINTER_CFA_OFFSET (current_function_decl);
+#else
+      reg = arg_pointer_rtx;
+      fp_cfa_offset = ARG_POINTER_CFA_OFFSET (current_function_decl);
+#endif
+      elim = eliminate_regs (reg, VOIDmode, NULL_RTX);
+      if (elim != reg)
+       {
+         if (GET_CODE (elim) == PLUS)
+           {
+             fp_cfa_offset -= INTVAL (XEXP (elim, 1));
+             elim = XEXP (elim, 0);
+           }
+         if (elim != hard_frame_pointer_rtx)
+           fp_cfa_offset = -1;
+         else
+           prologue_bb = single_succ (ENTRY_BLOCK_PTR);
+       }
+    }
+
+  hard_frame_pointer_adjustment = -1;
+
   FOR_EACH_BB (bb)
     {
       rtx insn;
       HOST_WIDE_INT pre, post = 0;
-      unsigned int next_uid_before = cselib_get_next_uid ();
-      unsigned int next_uid_after = next_uid_before;
       basic_block first_bb, last_bb;
 
       if (MAY_HAVE_DEBUG_INSNS)
        {
-         cselib_record_sets_hook = count_with_sets;
+         cselib_record_sets_hook = add_with_sets;
          if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "first value: %i\n",
                     cselib_get_next_uid ());
@@ -7866,10 +8382,11 @@ vt_initialize (void)
        }
       last_bb = bb;
 
-      /* Count the number of micro operations.  */
+      /* Add the micro-operations to the vector.  */
       FOR_BB_BETWEEN (bb, first_bb, last_bb->next_bb, next_bb)
        {
-         VTI (bb)->n_mos = 0;
+         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))
            {
@@ -7880,83 +8397,21 @@ vt_initialize (void)
                      insn_stack_adjust_offset_pre_post (insn, &pre, &post);
                      if (pre)
                        {
-                         VTI (bb)->n_mos++;
-                         if (dump_file && (dump_flags & TDF_DETAILS))
-                           log_op_type (GEN_INT (pre), bb, insn,
-                                        MO_ADJUST, dump_file);
-                       }
-                     if (post)
-                       {
-                         VTI (bb)->n_mos++;
-                         if (dump_file && (dump_flags & TDF_DETAILS))
-                           log_op_type (GEN_INT (post), bb, insn,
-                                        MO_ADJUST, dump_file);
-                       }
-                   }
-                 cselib_hook_called = false;
-                 if (MAY_HAVE_DEBUG_INSNS)
-                   {
-                     cselib_process_insn (insn);
-                     if (dump_file && (dump_flags & TDF_DETAILS))
-                       {
-                         print_rtl_single (dump_file, insn);
-                         dump_cselib_table (dump_file);
-                       }
-                   }
-                 if (!cselib_hook_called)
-                   count_with_sets (insn, 0, 0);
-                 if (CALL_P (insn))
-                   {
-                     VTI (bb)->n_mos++;
-                     if (dump_file && (dump_flags & TDF_DETAILS))
-                       log_op_type (PATTERN (insn), bb, insn,
-                                    MO_CALL, dump_file);
-                   }
-               }
-           }
-       }
-
-      if (MAY_HAVE_DEBUG_INSNS)
-       {
-         cselib_preserve_only_values (false);
-         next_uid_after = cselib_get_next_uid ();
-         cselib_reset_table (next_uid_before);
-         cselib_record_sets_hook = add_with_sets;
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           fprintf (dump_file, "first value: %i\n",
-                    cselib_get_next_uid ());
-       }
-
-      /* Add the micro-operations to the array.  */
-      FOR_BB_BETWEEN (bb, first_bb, last_bb->next_bb, next_bb)
-       {
-         int count = VTI (bb)->n_mos;
-         VTI (bb)->mos = XNEWVEC (micro_operation, count);
-         VTI (bb)->n_mos = 0;
-         for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
-              insn = NEXT_INSN (insn))
-           {
-             if (INSN_P (insn))
-               {
-                 if (!frame_pointer_needed)
-                   {
-                     insn_stack_adjust_offset_pre_post (insn, &pre, &post);
-                     if (pre)
-                       {
-                         micro_operation *mo
-                           = VTI (bb)->mos + VTI (bb)->n_mos++;
-
-                         mo->type = MO_ADJUST;
-                         mo->u.adjust = pre;
-                         mo->insn = insn;
-
+                         micro_operation mo;
+                         mo.type = MO_ADJUST;
+                         mo.u.adjust = pre;
+                         mo.insn = insn;
                          if (dump_file && (dump_flags & TDF_DETAILS))
                            log_op_type (PATTERN (insn), bb, insn,
                                         MO_ADJUST, dump_file);
+                         VEC_safe_push (micro_operation, heap, VTI (bb)->mos,
+                                        &mo);
+                         VTI (bb)->out.stack_adjust += pre;
                        }
                    }
 
                  cselib_hook_called = false;
+                 adjust_insn (bb, insn);
                  if (MAY_HAVE_DEBUG_INSNS)
                    {
                      cselib_process_insn (insn);
@@ -7968,74 +8423,50 @@ vt_initialize (void)
                    }
                  if (!cselib_hook_called)
                    add_with_sets (insn, 0, 0);
+                 cancel_changes (0);
 
                  if (!frame_pointer_needed && post)
                    {
-                     micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
-
-                     mo->type = MO_ADJUST;
-                     mo->u.adjust = post;
-                     mo->insn = insn;
-
+                     micro_operation mo;
+                     mo.type = MO_ADJUST;
+                     mo.u.adjust = post;
+                     mo.insn = insn;
                      if (dump_file && (dump_flags & TDF_DETAILS))
                        log_op_type (PATTERN (insn), bb, insn,
                                     MO_ADJUST, dump_file);
+                     VEC_safe_push (micro_operation, heap, VTI (bb)->mos,
+                                    &mo);
+                     VTI (bb)->out.stack_adjust += post;
+                   }
+
+                 if (bb == prologue_bb
+                     && hard_frame_pointer_adjustment == -1
+                     && RTX_FRAME_RELATED_P (insn)
+                     && fp_setter (insn))
+                   {
+                     vt_init_cfa_base ();
+                     hard_frame_pointer_adjustment = fp_cfa_offset;
                    }
                }
            }
-         gcc_assert (count == VTI (bb)->n_mos);
+         gcc_assert (offset == VTI (bb)->out.stack_adjust);
        }
 
       bb = last_bb;
 
       if (MAY_HAVE_DEBUG_INSNS)
        {
-         cselib_preserve_only_values (true);
-         gcc_assert (next_uid_after == cselib_get_next_uid ());
-         cselib_reset_table (next_uid_after);
+         cselib_preserve_only_values ();
+         cselib_reset_table (cselib_get_next_uid ());
          cselib_record_sets_hook = NULL;
        }
     }
 
-  attrs_pool = create_alloc_pool ("attrs_def pool",
-                                 sizeof (struct attrs_def), 1024);
-  var_pool = create_alloc_pool ("variable_def pool",
-                               sizeof (struct variable_def)
-                               + (MAX_VAR_PARTS - 1)
-                               * sizeof (((variable)NULL)->var_part[0]), 64);
-  loc_chain_pool = create_alloc_pool ("location_chain_def pool",
-                                     sizeof (struct location_chain_def),
-                                     1024);
-  shared_hash_pool = create_alloc_pool ("shared_hash_def pool",
-                                       sizeof (struct shared_hash_def), 256);
-  empty_shared_hash = (shared_hash) pool_alloc (shared_hash_pool);
-  empty_shared_hash->refcount = 1;
-  empty_shared_hash->htab
-    = htab_create (1, variable_htab_hash, variable_htab_eq,
-                  variable_htab_free);
-  changed_variables = htab_create (10, variable_htab_hash, variable_htab_eq,
-                                  variable_htab_free);
-  if (MAY_HAVE_DEBUG_INSNS)
-    {
-      value_chain_pool = create_alloc_pool ("value_chain_def pool",
-                                           sizeof (struct value_chain_def),
-                                           1024);
-      value_chains = htab_create (32, value_chain_htab_hash,
-                                 value_chain_htab_eq, NULL);
-    }
-
-  /* Init the IN and OUT sets.  */
-  FOR_ALL_BB (bb)
-    {
-      VTI (bb)->visited = false;
-      VTI (bb)->flooded = false;
-      dataflow_set_init (&VTI (bb)->in);
-      dataflow_set_init (&VTI (bb)->out);
-      VTI (bb)->permp = NULL;
-    }
-
+  hard_frame_pointer_adjustment = -1;
   VTI (ENTRY_BLOCK_PTR)->flooded = true;
   vt_add_function_parameters ();
+  cfa_base_rtx = NULL_RTX;
+  return true;
 }
 
 /* Get rid of all debug insns from the insn stream.  */
@@ -8079,7 +8510,7 @@ vt_finalize (void)
 
   FOR_EACH_BB (bb)
     {
-      free (VTI (bb)->mos);
+      VEC_free (micro_operation, heap, VTI (bb)->mos);
     }
 
   FOR_ALL_BB (bb)
@@ -8137,15 +8568,11 @@ variable_tracking_main_1 (void)
     }
 
   mark_dfs_back_edges ();
-  vt_initialize ();
-  if (!frame_pointer_needed)
+  if (!vt_initialize ())
     {
-      if (!vt_stack_adjustments ())
-       {
-         vt_finalize ();
-         vt_debug_insns_local (true);
-         return 0;
-       }
+      vt_finalize ();
+      vt_debug_insns_local (true);
+      return 0;
     }
 
   success = vt_find_locations ();
@@ -8159,10 +8586,8 @@ variable_tracking_main_1 (void)
       /* This is later restored by our caller.  */
       flag_var_tracking_assignments = 0;
 
-      vt_initialize ();
-
-      if (!frame_pointer_needed && !vt_stack_adjustments ())
-       gcc_unreachable ();
+      success = vt_initialize ();
+      gcc_assert (success);
 
       success = vt_find_locations ();
     }
@@ -8180,7 +8605,9 @@ variable_tracking_main_1 (void)
       dump_flow_info (dump_file, dump_flags);
     }
 
+  timevar_push (TV_VAR_TRACKING_EMIT);
   vt_emit_notes ();
+  timevar_pop (TV_VAR_TRACKING_EMIT);
 
   vt_finalize ();
   vt_debug_insns_local (false);