OSDN Git Service

2006-09-11 Alexandre Oliva <aoliva@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / var-tracking.c
index c036baa..815faca 100644 (file)
@@ -1,5 +1,5 @@
 /* Variable tracking routines for the GNU compiler.
-   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -15,8 +15,8 @@
 
    You should have received a copy of the GNU General Public License
    along with GCC; see the file COPYING.  If not, write to the Free
-   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.  */
 
 /* This file contains the variable tracking pass.  It computes where
    variables are located (which registers or where in memory) at each position
 #include "alloc-pool.h"
 #include "fibheap.h"
 #include "hashtab.h"
+#include "regs.h"
+#include "expr.h"
+#include "timevar.h"
+#include "tree-pass.h"
 
 /* Type of micro operation.  */
 enum micro_operation_type
@@ -110,6 +114,8 @@ enum micro_operation_type
   MO_USE_NO_VAR,/* Use location which is not associated with a variable
                   or the variable is not trackable.  */
   MO_SET,      /* Set location.  */
+  MO_COPY,     /* Copy the same portion of a variable from one
+                  location to another.  */
   MO_CLOBBER,  /* Clobber location.  */
   MO_CALL,     /* Call insn.  */
   MO_ADJUST    /* Adjust stack pointer.  */
@@ -136,7 +142,11 @@ typedef struct micro_operation_def
     HOST_WIDE_INT adjust;
   } u;
 
-  /* The instruction which the micro operation is in.  */
+  /* 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;
 
@@ -244,7 +254,7 @@ typedef struct variable_def
 } *variable;
 
 /* Hash function for DECL for VARIABLE_HTAB.  */
-#define VARIABLE_HASH_VAL(decl) ((size_t) (decl))
+#define VARIABLE_HASH_VAL(decl) (DECL_UID (decl))
 
 /* Pointer to the BB's information specific to variable tracking pass.  */
 #define VTI(BB) ((variable_tracking_info) (BB)->aux)
@@ -264,16 +274,12 @@ static htab_t changed_variables;
 /* Shall notes be emitted?  */
 static bool emit_notes;
 
-/* Fake variable for stack pointer.  */
-tree frame_base_decl;
-
 /* Local function prototypes.  */
 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 HOST_WIDE_INT prologue_stack_adjust (void);
 static bool vt_stack_adjustments (void);
 static rtx adjust_stack_reference (rtx, HOST_WIDE_INT);
 static hashval_t variable_htab_hash (const void *);
@@ -291,11 +297,14 @@ static void vars_clear (htab_t);
 static variable unshare_variable (dataflow_set *set, variable var);
 static int vars_copy_1 (void **, void *);
 static void vars_copy (htab_t, htab_t);
-static void var_reg_delete_and_set (dataflow_set *, rtx);
-static void var_reg_delete (dataflow_set *, rtx);
+static tree var_debug_decl (tree);
+static void var_reg_set (dataflow_set *, rtx);
+static void var_reg_delete_and_set (dataflow_set *, rtx, bool);
+static void var_reg_delete (dataflow_set *, rtx, bool);
 static void var_regno_delete (dataflow_set *, int);
-static void var_mem_delete_and_set (dataflow_set *, rtx);
-static void var_mem_delete (dataflow_set *, rtx);
+static void var_mem_set (dataflow_set *, rtx);
+static void var_mem_delete_and_set (dataflow_set *, rtx, bool);
+static void var_mem_delete (dataflow_set *, rtx, bool);
 
 static void dataflow_set_init (dataflow_set *, int);
 static void dataflow_set_clear (dataflow_set *);
@@ -312,6 +321,7 @@ static void dataflow_set_destroy (dataflow_set *);
 
 static bool contains_symbol_ref (rtx);
 static bool track_expr_p (tree);
+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, rtx, void *);
@@ -328,8 +338,8 @@ static void dump_dataflow_set (dataflow_set *);
 static void dump_dataflow_sets (void);
 
 static void variable_was_changed (variable, htab_t);
-static void set_frame_base_location (dataflow_set *, rtx);
 static void set_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT);
+static void clobber_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT);
 static void delete_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT);
 static int emit_note_insn_var_location (void **, void *);
 static void emit_notes_for_changes (rtx, enum emit_note_where);
@@ -370,7 +380,7 @@ stack_adjust_offset_pre_post (rtx pattern, HOST_WIDE_INT *pre,
       else
        *post -= INTVAL (XEXP (src, 1));
     }
-  else if (GET_CODE (dest) == MEM)
+  else if (MEM_P (dest))
     {
       /* (set (mem (pre_dec (reg sp))) (foo)) */
       src = XEXP (dest, 0);
@@ -384,9 +394,9 @@ stack_adjust_offset_pre_post (rtx pattern, HOST_WIDE_INT *pre,
            {
              rtx val = XEXP (XEXP (src, 1), 1);
              /* We handle only adjustments by constant amount.  */
-             if (GET_CODE (XEXP (src, 1)) != PLUS ||
-                 GET_CODE (val) != CONST_INT)
-               abort ();
+             gcc_assert (GET_CODE (XEXP (src, 1)) == PLUS &&
+                         GET_CODE (val) == CONST_INT);
+             
              if (code == PRE_MODIFY)
                *pre -= INTVAL (val);
              else
@@ -474,7 +484,7 @@ bb_stack_adjust_offset (basic_block bb)
        offset += VTI (bb)->mos[i].u.adjust;
       else if (VTI (bb)->mos[i].type != MO_CALL)
        {
-         if (GET_CODE (VTI (bb)->mos[i].u.loc) == MEM)
+         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);
@@ -484,69 +494,37 @@ bb_stack_adjust_offset (basic_block bb)
   VTI (bb)->out.stack_adjust = offset;
 }
 
-/* Compute stack adjustment caused by function prolog.  */
-
-static HOST_WIDE_INT
-prologue_stack_adjust (void)
-{
-  HOST_WIDE_INT offset = 0;
-  basic_block bb = ENTRY_BLOCK_PTR->next_bb;
-  rtx insn;
-  rtx end;
-
-  if (!BB_END (bb))
-    return 0;
-
-  end = NEXT_INSN (BB_END (bb));
-  for (insn = BB_HEAD (bb); insn != end; insn = NEXT_INSN (insn))
-    {
-      if (GET_CODE (insn) == NOTE
-         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
-       break;
-
-      if (INSN_P (insn))
-       {
-         HOST_WIDE_INT tmp;
-
-         insn_stack_adjust_offset_pre_post (insn, &tmp, &tmp);
-         offset += tmp;
-       }
-    }
-
-  return 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 flow_depth_first_order_compute.  */
+   Heavily borrowed from pre_and_rev_post_order_compute.  */
 
 static bool
 vt_stack_adjustments (void)
 {
-  edge *stack;
+  edge_iterator *stack;
   int sp;
 
   /* Initialize entry block.  */
   VTI (ENTRY_BLOCK_PTR)->visited = true;
-  VTI (ENTRY_BLOCK_PTR)->out.stack_adjust = 0;
+  VTI (ENTRY_BLOCK_PTR)->out.stack_adjust = INCOMING_FRAME_SP_OFFSET;
 
   /* Allocate stack for back-tracking up CFG.  */
-  stack = xmalloc ((n_basic_blocks + 1) * sizeof (edge));
+  stack = XNEWVEC (edge_iterator, n_basic_blocks + 1);
   sp = 0;
 
   /* Push the first edge on to the stack.  */
-  stack[sp++] = ENTRY_BLOCK_PTR->succ;
+  stack[sp++] = ei_start (ENTRY_BLOCK_PTR->succs);
 
   while (sp)
     {
-      edge e;
+      edge_iterator ei;
       basic_block src;
       basic_block dest;
 
       /* Look at the edge on the top of the stack.  */
-      e = stack[sp - 1];
-      src = e->src;
-      dest = e->dest;
+      ei = stack[sp - 1];
+      src = ei_edge (ei)->src;
+      dest = ei_edge (ei)->dest;
 
       /* Check if the edge destination has been visited yet.  */
       if (!VTI (dest)->visited)
@@ -555,10 +533,10 @@ vt_stack_adjustments (void)
          VTI (dest)->in.stack_adjust = VTI (src)->out.stack_adjust;
          bb_stack_adjust_offset (dest);
 
-         if (dest->succ)
+         if (EDGE_COUNT (dest->succs) > 0)
            /* Since the DEST node has been visited for the first
               time, check its successors.  */
-           stack[sp++] = dest->succ;
+           stack[sp++] = ei_start (dest->succs);
        }
       else
        {
@@ -569,9 +547,9 @@ vt_stack_adjustments (void)
              return false;
            }
 
-         if (e->succ_next)
+         if (! ei_one_before_end_p (ei))
            /* Go to the next edge.  */
-           stack[sp - 1] = e->succ_next;
+           ei_next (&stack[sp - 1]);
          else
            /* Return to previous level if there are no more edges.  */
            sp--;
@@ -582,24 +560,28 @@ vt_stack_adjustments (void)
   return true;
 }
 
-/* Adjust stack reference MEM by ADJUSTMENT bytes and return the new rtx.  */
+/* Adjust stack reference MEM by ADJUSTMENT bytes and make it relative
+   to the argument pointer.  Return the new rtx.  */
 
 static rtx
 adjust_stack_reference (rtx mem, HOST_WIDE_INT adjustment)
 {
-  rtx adjusted_mem;
-  rtx tmp;
+  rtx addr, cfa, tmp;
 
-  adjusted_mem = copy_rtx (mem);
-  XEXP (adjusted_mem, 0) = replace_rtx (XEXP (adjusted_mem, 0),
-                                       stack_pointer_rtx,
-                                       gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-                                                     GEN_INT (adjustment)));
-  tmp = simplify_rtx (XEXP (adjusted_mem, 0));
+#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
+
+  addr = replace_rtx (copy_rtx (XEXP (mem, 0)), stack_pointer_rtx, cfa);
+  tmp = simplify_rtx (addr);
   if (tmp)
-    XEXP (adjusted_mem, 0) = tmp;
+    addr = tmp;
 
-  return adjusted_mem;
+  return replace_equiv_address_nv (mem, addr);
 }
 
 /* The hash function for variable_htab, computes the hash value
@@ -633,10 +615,7 @@ variable_htab_free (void *elem)
   variable var = (variable) elem;
   location_chain node, next;
 
-#ifdef ENABLE_CHECKING
-  if (var->refcount <= 0)
-    abort ();
-#endif
+  gcc_assert (var->refcount > 0);
 
   var->refcount--;
   if (var->refcount > 0)
@@ -824,17 +803,55 @@ vars_copy (htab_t dst, htab_t src)
   htab_traverse (src, vars_copy_1, dst);
 }
 
-/* Delete current content of register LOC in dataflow set SET
-   and set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  */
+/* Map a decl to its main debug decl.  */
+
+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);
+
+  return decl;
+}
+
+/* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  */
+
+static void
+var_reg_set (dataflow_set *set, rtx loc)
+{
+  tree decl = REG_EXPR (loc);
+  HOST_WIDE_INT offset = REG_OFFSET (loc);
+  attrs node;
+
+  decl = var_debug_decl (decl);
+
+  for (node = set->regs[REGNO (loc)]; node; node = node->next)
+    if (node->decl == decl && node->offset == offset)
+      break;
+  if (!node)
+    attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, loc);
+  set_variable_part (set, loc, decl, offset);
+}
+
+/* Delete current content of register LOC in dataflow set SET and set
+   the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  If
+   MODIFY is true, any other live copies of the same variable part are
+   also deleted from the dataflow set, otherwise the variable part is
+   assumed to be copied from another location holding the same
+   part.  */
 
 static void
-var_reg_delete_and_set (dataflow_set *set, rtx loc)
+var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify)
 {
   tree decl = REG_EXPR (loc);
   HOST_WIDE_INT offset = REG_OFFSET (loc);
   attrs node, next;
   attrs *nextp;
 
+  decl = var_debug_decl (decl);
+
   nextp = &set->regs[REGNO (loc)];
   for (node = *nextp; node; node = next)
     {
@@ -851,19 +868,31 @@ var_reg_delete_and_set (dataflow_set *set, rtx loc)
          nextp = &node->next;
        }
     }
-  if (set->regs[REGNO (loc)] == NULL)
-    attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, loc);
-  set_variable_part (set, loc, decl, offset);
+  if (modify)
+    clobber_variable_part (set, loc, decl, offset);
+  var_reg_set (set, loc);
 }
 
-/* Delete current content of register LOC in dataflow set SET.  */
+/* Delete current content of register LOC in dataflow set SET.  If
+   CLOBBER is true, also delete any other live copies of the same
+   variable part.  */
 
 static void
-var_reg_delete (dataflow_set *set, rtx loc)
+var_reg_delete (dataflow_set *set, rtx loc, bool clobber)
 {
   attrs *reg = &set->regs[REGNO (loc)];
   attrs node, next;
 
+  if (clobber)
+    {
+      tree decl = REG_EXPR (loc);
+      HOST_WIDE_INT offset = REG_OFFSET (loc);
+
+      decl = var_debug_decl (decl);
+
+      clobber_variable_part (set, NULL, decl, offset);
+    }
+
   for (node = *reg; node; node = next)
     {
       next = node->next;
@@ -890,28 +919,54 @@ var_regno_delete (dataflow_set *set, int regno)
   *reg = NULL;
 }
 
-/* Delete and set the location part of variable MEM_EXPR (LOC)
-   in dataflow set SET to LOC.
+/* Set the location part of variable MEM_EXPR (LOC) in dataflow set
+   SET to LOC.
    Adjust the address first if it is stack pointer based.  */
 
 static void
-var_mem_delete_and_set (dataflow_set *set, rtx loc)
+var_mem_set (dataflow_set *set, rtx loc)
 {
   tree decl = MEM_EXPR (loc);
   HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
 
+  decl = var_debug_decl (decl);
+
   set_variable_part (set, loc, decl, offset);
 }
 
-/* Delete the location part LOC from dataflow set SET.
+/* Delete and set the location part of variable MEM_EXPR (LOC) in
+   dataflow set SET to LOC.  If MODIFY is true, any other live copies
+   of the same variable part are also deleted from the dataflow set,
+   otherwise the variable part is assumed to be copied from another
+   location holding the same part.
+   Adjust the address first if it is stack pointer based.  */
+
+static void
+var_mem_delete_and_set (dataflow_set *set, rtx loc, bool modify)
+{
+  tree decl = MEM_EXPR (loc);
+  HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
+
+  decl = var_debug_decl (decl);
+
+  if (modify)
+    clobber_variable_part (set, NULL, decl, offset);
+  var_mem_set (set, loc);
+}
+
+/* Delete the location part LOC from dataflow set SET.  If CLOBBER is
+   true, also delete any other live copies of the same variable part.
    Adjust the address first if it is stack pointer based.  */
 
 static void
-var_mem_delete (dataflow_set *set, rtx loc)
+var_mem_delete (dataflow_set *set, rtx loc, bool clobber)
 {
   tree decl = MEM_EXPR (loc);
   HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
 
+  decl = var_debug_decl (decl);
+  if (clobber)
+    clobber_variable_part (set, NULL, decl, offset);
   delete_variable_part (set, loc, decl, offset);
 }
 
@@ -1013,22 +1068,14 @@ variable_union (void **slot, void *data)
         a copy of the variable.  */
       for (k = 0; k < src->n_var_parts; k++)
        {
+         gcc_assert (!src->var_part[k].loc_chain
+                     == !src->var_part[k].cur_loc);
          if (src->var_part[k].loc_chain)
            {
-#ifdef ENABLE_CHECKING
-             if (src->var_part[k].cur_loc == NULL)
-               abort ();
-#endif
+             gcc_assert (src->var_part[k].cur_loc);
              if (src->var_part[k].cur_loc != src->var_part[k].loc_chain->loc)
                break;
            }
-#ifdef ENABLE_CHECKING
-         else
-           {
-             if (src->var_part[k].cur_loc != NULL)
-               abort ();
-           }
-#endif
        }
       if (k < src->n_var_parts)
        unshare_variable (set, src);
@@ -1041,10 +1088,7 @@ variable_union (void **slot, void *data)
   else
     dst = *dstp;
 
-#ifdef ENABLE_CHECKING
-  if (src->n_var_parts == 0)
-    abort ();
-#endif
+  gcc_assert (src->n_var_parts);
 
   /* Count the number of location parts, result is K.  */
   for (i = 0, j = 0, k = 0;
@@ -1062,12 +1106,10 @@ variable_union (void **slot, void *data)
     }
   k += src->n_var_parts - i;
   k += dst->n_var_parts - j;
-#ifdef ENABLE_CHECKING
+
   /* We track only variables whose size is <= MAX_VAR_PARTS bytes
      thus there are at most MAX_VAR_PARTS different offsets.  */
-  if (k > MAX_VAR_PARTS)
-    abort ();
-#endif
+  gcc_assert (k <= MAX_VAR_PARTS);
 
   if (dst->refcount > 1 && dst->n_var_parts != k)
     dst = unshare_variable (set, dst);
@@ -1115,7 +1157,7 @@ variable_union (void **slot, void *data)
          dst_l = 0;
          for (node = dst->var_part[j].loc_chain; node; node = node->next)
            dst_l++;
-         vui = xcalloc (src_l + dst_l, sizeof (struct variable_union_info));
+         vui = XCNEWVEC (struct variable_union_info, src_l + dst_l);
 
          /* Fill in the locations from DST.  */
          for (node = dst->var_part[j].loc_chain, jj = 0; node;
@@ -1350,12 +1392,9 @@ dataflow_set_different_2 (void **slot, void *data)
       return 0;
     }
 
-#ifdef ENABLE_CHECKING
   /* If both variables are defined they have been already checked for
      equivalence.  */
-  if (variable_different_p (var1, var2, false))
-    abort ();
-#endif
+  gcc_assert (!variable_different_p (var1, var2, false));
 
   /* Continue traversing the hash table.  */
   return 1;
@@ -1435,6 +1474,7 @@ static bool
 track_expr_p (tree expr)
 {
   rtx decl_rtl;
+  tree realdecl;
 
   /* If EXPR is not a parameter or a variable do not track it.  */
   if (TREE_CODE (expr) != VAR_DECL && TREE_CODE (expr) != PARM_DECL)
@@ -1448,14 +1488,28 @@ track_expr_p (tree expr)
   decl_rtl = DECL_RTL_IF_SET (expr);
   if (!decl_rtl)
     return 0;
+  
+  /* If this expression is really a debug alias of some other declaration, we 
+     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))
+    {
+      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;
+    }
 
-  /* Do not track EXPR if it should be ignored for debugging purposes.  */
-  if (DECL_IGNORED_P (expr))
+  /* Do not track EXPR if REALDECL it should be ignored for debugging
+     purposes.  */ 
+  if (DECL_IGNORED_P (realdecl))
     return 0;
 
   /* Do not track global variables until we are able to emit correct location
      list for them.  */
-  if (TREE_STATIC (expr))
+  if (TREE_STATIC (realdecl))
     return 0;
 
   /* When the EXPR is a DECL for alias of some variable (see example)
@@ -1466,13 +1520,13 @@ track_expr_p (tree expr)
      extern char **_dl_argv_internal __attribute__ ((alias ("_dl_argv")));
      char **_dl_argv;
   */
-  if (GET_CODE (decl_rtl) == MEM
+  if (MEM_P (decl_rtl)
       && contains_symbol_ref (XEXP (decl_rtl, 0)))
     return 0;
 
   /* If RTX is a memory it should not be very large (because it would be
      an array or struct).  */
-  if (GET_CODE (decl_rtl) == MEM)
+  if (MEM_P (decl_rtl))
     {
       /* Do not track structures and arrays.  */
       if (GET_MODE (decl_rtl) == BLKmode)
@@ -1485,6 +1539,41 @@ track_expr_p (tree expr)
   return 1;
 }
 
+/* Determine whether a given LOC refers to the same variable part as
+   EXPR+OFFSET.  */
+
+static bool
+same_variable_part_p (rtx loc, tree expr, HOST_WIDE_INT offset)
+{
+  tree expr2;
+  HOST_WIDE_INT offset2;
+
+  if (! DECL_P (expr))
+    return false;
+
+  if (REG_P (loc))
+    {
+      expr2 = REG_EXPR (loc);
+      offset2 = REG_OFFSET (loc);
+    }
+  else if (MEM_P (loc))
+    {
+      expr2 = MEM_EXPR (loc);
+      offset2 = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
+    }
+  else
+    return false;
+
+  if (! expr2 || ! DECL_P (expr2))
+    return false;
+
+  expr = var_debug_decl (expr);
+  expr2 = var_debug_decl (expr2);
+
+  return (expr == expr2 && offset == offset2);
+}
+
+
 /* Count uses (register and memory references) LOC which will be tracked.
    INSN is instruction which the LOC is part of.  */
 
@@ -1495,17 +1584,14 @@ count_uses (rtx *loc, void *insn)
 
   if (REG_P (*loc))
     {
-#ifdef ENABLE_CHECKING
-       if (REGNO (*loc) >= FIRST_PSEUDO_REGISTER)
-         abort ();
-#endif
-       VTI (bb)->n_mos++;
+      gcc_assert (REGNO (*loc) < FIRST_PSEUDO_REGISTER);
+      VTI (bb)->n_mos++;
     }
-  else if (GET_CODE (*loc) == MEM
+  else if (MEM_P (*loc)
           && MEM_EXPR (*loc)
           && track_expr_p (MEM_EXPR (*loc)))
     {
-         VTI (bb)->n_mos++;
+      VTI (bb)->n_mos++;
     }
 
   return 0;
@@ -1544,7 +1630,7 @@ add_uses (rtx *loc, void *insn)
       mo->u.loc = *loc;
       mo->insn = (rtx) insn;
     }
-  else if (GET_CODE (*loc) == MEM
+  else if (MEM_P (*loc)
           && MEM_EXPR (*loc)
           && track_expr_p (MEM_EXPR (*loc)))
     {
@@ -1579,22 +1665,41 @@ add_stores (rtx loc, rtx expr, void *insn)
       basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
       micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
 
-      mo->type = ((GET_CODE (expr) != CLOBBER && REG_EXPR (loc)
-                  && track_expr_p (REG_EXPR (loc)))
-                 ? MO_SET : MO_CLOBBER);
+      if (GET_CODE (expr) == CLOBBER
+         || ! REG_EXPR (loc)
+         || ! track_expr_p (REG_EXPR (loc)))
+       mo->type = MO_CLOBBER;
+      else if (GET_CODE (expr) == SET
+              && SET_DEST (expr) == loc
+              && same_variable_part_p (SET_SRC (expr),
+                                       REG_EXPR (loc),
+                                       REG_OFFSET (loc)))
+       mo->type = MO_COPY;
+      else
+       mo->type = MO_SET;
       mo->u.loc = loc;
-      mo->insn = (rtx) insn;
+      mo->insn = NEXT_INSN ((rtx) insn);
     }
-  else if (GET_CODE (loc) == MEM
+  else if (MEM_P (loc)
           && MEM_EXPR (loc)
           && track_expr_p (MEM_EXPR (loc)))
     {
       basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
       micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
 
-      mo->type = GET_CODE (expr) == CLOBBER ? MO_CLOBBER : MO_SET;
+      if (GET_CODE (expr) == CLOBBER)
+       mo->type = MO_CLOBBER;
+      else if (GET_CODE (expr) == SET
+              && SET_DEST (expr) == loc
+              && same_variable_part_p (SET_SRC (expr),
+                                       MEM_EXPR (loc),
+                                       MEM_OFFSET (loc)
+                                       ? INTVAL (MEM_OFFSET (loc)) : 0))
+       mo->type = MO_COPY;
+      else
+       mo->type = MO_SET;
       mo->u.loc = loc;
-      mo->insn = (rtx) insn;
+      mo->insn = NEXT_INSN ((rtx) insn);
     }
 }
 
@@ -1625,40 +1730,63 @@ compute_bb_dataflow (basic_block bb)
            break;
 
          case MO_USE:
+           {
+             rtx loc = VTI (bb)->mos[i].u.loc;
+
+             if (GET_CODE (loc) == REG)
+               var_reg_set (out, loc);
+             else if (GET_CODE (loc) == MEM)
+               var_mem_set (out, loc);
+           }
+           break;
+
          case MO_SET:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
 
              if (REG_P (loc))
-               var_reg_delete_and_set (out, loc);
-             else if (GET_CODE (loc) == MEM)
-               var_mem_delete_and_set (out, loc);
+               var_reg_delete_and_set (out, loc, true);
+             else if (MEM_P (loc))
+               var_mem_delete_and_set (out, loc, true);
+           }
+           break;
+
+         case MO_COPY:
+           {
+             rtx loc = VTI (bb)->mos[i].u.loc;
+
+             if (REG_P (loc))
+               var_reg_delete_and_set (out, loc, false);
+             else if (MEM_P (loc))
+               var_mem_delete_and_set (out, loc, false);
            }
            break;
 
          case MO_USE_NO_VAR:
-         case MO_CLOBBER:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
 
              if (REG_P (loc))
-               var_reg_delete (out, loc);
-             else if (GET_CODE (loc) == MEM)
-               var_mem_delete (out, loc);
+               var_reg_delete (out, loc, false);
+             else if (MEM_P (loc))
+               var_mem_delete (out, loc, false);
            }
            break;
 
-         case MO_ADJUST:
+         case MO_CLOBBER:
            {
-             rtx base;
+             rtx loc = VTI (bb)->mos[i].u.loc;
 
-             out->stack_adjust += VTI (bb)->mos[i].u.adjust;
-             base = gen_rtx_MEM (Pmode,
-                                 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-                                               GEN_INT (out->stack_adjust)));
-             set_frame_base_location (out, base);
+             if (REG_P (loc))
+               var_reg_delete (out, loc, true);
+             else if (MEM_P (loc))
+               var_mem_delete (out, loc, true);
            }
            break;
+
+         case MO_ADJUST:
+           out->stack_adjust += VTI (bb)->mos[i].u.adjust;
+           break;
        }
     }
 
@@ -1682,10 +1810,10 @@ vt_find_locations (void)
 
   /* Compute reverse completion order of depth first search of the CFG
      so that the data-flow runs faster.  */
-  rc_order = xmalloc (n_basic_blocks * sizeof (int));
-  bb_order = xmalloc (last_basic_block * sizeof (int));
-  flow_depth_first_order_compute (NULL, rc_order);
-  for (i = 0; i < n_basic_blocks; i++)
+  rc_order = XNEWVEC (int, n_basic_blocks - NUM_FIXED_BLOCKS);
+  bb_order = XNEWVEC (int, last_basic_block);
+  pre_and_rev_post_order_compute (NULL, rc_order, false);
+  for (i = 0; i < n_basic_blocks - NUM_FIXED_BLOCKS; i++)
     bb_order[rc_order[i]] = i;
   free (rc_order);
 
@@ -1695,13 +1823,10 @@ vt_find_locations (void)
   in_worklist = sbitmap_alloc (last_basic_block);
   in_pending = sbitmap_alloc (last_basic_block);
   sbitmap_zero (in_worklist);
-  sbitmap_zero (in_pending);
 
   FOR_EACH_BB (bb)
-    {
-      fibheap_insert (pending, bb_order[bb->index], bb);
-      SET_BIT (in_pending, bb->index);
-    }
+    fibheap_insert (pending, bb_order[bb->index], bb);
+  sbitmap_ones (in_pending);
 
   while (!fibheap_empty (pending))
     {
@@ -1721,12 +1846,13 @@ vt_find_locations (void)
          if (!TEST_BIT (visited, bb->index))
            {
              bool changed;
+             edge_iterator ei;
 
              SET_BIT (visited, bb->index);
 
              /* Calculate the IN set as union of predecessor OUT sets.  */
              dataflow_set_clear (&VTI (bb)->in);
-             for (e = bb->pred; e; e = e->pred_next)
+             FOR_EACH_EDGE (e, ei, bb->preds)
                {
                  dataflow_set_union (&VTI (bb)->in, &VTI (e->src)->out);
                }
@@ -1734,7 +1860,7 @@ vt_find_locations (void)
              changed = compute_bb_dataflow (bb);
              if (changed)
                {
-                 for (e = bb->succ; e; e = e->succ_next)
+                 FOR_EACH_EDGE (e, ei, bb->succs)
                    {
                      if (e->dest == EXIT_BLOCK_PTR)
                        continue;
@@ -1782,8 +1908,7 @@ dump_attrs_list (attrs list)
   for (; list; list = list->next)
     {
       print_mem_expr (dump_file, list->decl);
-      fprintf (dump_file, "+");
-      fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC, list->offset);
+      fprintf (dump_file, "+" HOST_WIDE_INT_PRINT_DEC, list->offset);
     }
   fprintf (dump_file, "\n");
 }
@@ -1833,10 +1958,9 @@ dump_dataflow_set (dataflow_set *set)
 {
   int i;
 
-  fprintf (dump_file, "Stack adjustment: ");
-  fprintf (dump_file, HOST_WIDE_INT_PRINT_DEC, set->stack_adjust);
-  fprintf (dump_file, "\n");
-  for (i = 1; i < FIRST_PSEUDO_REGISTER; i++)
+  fprintf (dump_file, "Stack adjustment: " HOST_WIDE_INT_PRINT_DEC "\n",
+          set->stack_adjust);
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
       if (set->regs[i])
        {
@@ -1903,10 +2027,7 @@ variable_was_changed (variable var, htab_t htab)
     }
   else
     {
-#ifdef ENABLE_CHECKING
-      if (!htab)
-       abort ();
-#endif
+      gcc_assert (htab);
       if (var->n_var_parts == 0)
        {
          void **slot = htab_find_slot_with_hash (htab, var->decl, hash,
@@ -1917,36 +2038,37 @@ variable_was_changed (variable var, htab_t htab)
     }
 }
 
-/* Set the location of frame_base_decl to LOC in dataflow set SET.  This
-   function expects that
-   frame_base_decl has already one location for offset 0 in the variable table.
- */
+/* Look for the index in VAR->var_part corresponding to OFFSET.
+   Return -1 if not found.  If INSERTION_POINT is non-NULL, the
+   referenced int will be set to the index that the part has or should
  have, if it should be inserted.  */
 
-static void
-set_frame_base_location (dataflow_set *set, rtx loc)
+static inline int
+find_variable_location_part (variable var, HOST_WIDE_INT offset,
+                            int *insertion_point)
 {
-  variable var;
-  
-  var = htab_find_with_hash (set->vars, frame_base_decl,
-                            VARIABLE_HASH_VAL (frame_base_decl));
-#ifdef ENABLE_CHECKING
-  if (!var)
-    abort ();
-  if (var->n_var_parts != 1)
-    abort ();
-  if (var->var_part[0].offset != 0)
-    abort ();
-  if (!var->var_part[0].loc_chain)
-    abort ();
-#endif
+  int pos, low, high;
 
-  /* If frame_base_decl is shared unshare it first.  */
-  if (var->refcount > 1)
-    var = unshare_variable (set, var);
+  /* Find the location part.  */
+  low = 0;
+  high = var->n_var_parts;
+  while (low != high)
+    {
+      pos = (low + high) / 2;
+      if (var->var_part[pos].offset < offset)
+       low = pos + 1;
+      else
+       high = pos;
+    }
+  pos = low;
+
+  if (insertion_point)
+    *insertion_point = pos;
 
-  var->var_part[0].loc_chain->loc = loc;
-  var->var_part[0].cur_loc = loc;
-  variable_was_changed (var, set->vars);
+  if (pos < var->n_var_parts && var->var_part[pos].offset == offset)
+    return pos;
+
+  return -1;
 }
 
 /* Set the part of variable's location in the dataflow set SET.  The variable
@@ -1956,7 +2078,7 @@ set_frame_base_location (dataflow_set *set, rtx loc)
 static void
 set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
 {
-  int pos, low, high;
+  int pos;
   location_chain node, next;
   location_chain *nextp;
   variable var;
@@ -1979,22 +2101,13 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
     }
   else
     {
+      int inspos = 0;
+
       var = (variable) *slot;
 
-      /* Find the location part.  */
-      low = 0;
-      high = var->n_var_parts;
-      while (low != high)
-       {
-         pos = (low + high) / 2;
-         if (var->var_part[pos].offset < offset)
-           low = pos + 1;
-         else
-           high = pos;
-       }
-      pos = low;
+      pos = find_variable_location_part (var, offset, &inspos);
 
-      if (pos < var->n_var_parts && var->var_part[pos].offset == offset)
+      if (pos >= 0)
        {
          node = var->var_part[pos].loc_chain;
 
@@ -2022,17 +2135,14 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
          if (var->refcount > 1)
            var = unshare_variable (set, var);
 
-#ifdef ENABLE_CHECKING
          /* We track only variables whose size is <= MAX_VAR_PARTS bytes
             thus there are at most MAX_VAR_PARTS different offsets.  */
-         if (var->n_var_parts >= MAX_VAR_PARTS)
-           abort ();
-#endif
+         gcc_assert (var->n_var_parts < MAX_VAR_PARTS);
 
-         /* We have to move the elements of array starting at index low to the
-            next position.  */
-         for (high = var->n_var_parts; high > low; high--)
-           var->var_part[high] = var->var_part[high - 1];
+         /* We have to move the elements of array starting at index
+            inspos to the next position.  */
+         for (pos = var->n_var_parts; pos > inspos; pos--)
+           var->var_part[pos] = var->var_part[pos - 1];
 
          var->n_var_parts++;
          var->var_part[pos].offset = offset;
@@ -2072,6 +2182,67 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
     }
 }
 
+/* Remove all recorded register locations for the given variable part
+   from dataflow set SET, except for those that are identical to loc.
+   The variable part is specified by variable's declaration DECL and
+   offset OFFSET.  */
+
+static void
+clobber_variable_part (dataflow_set *set, rtx loc, tree decl,
+                     HOST_WIDE_INT offset)
+{
+  void **slot;
+
+  if (! decl || ! DECL_P (decl))
+    return;
+
+  slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl),
+                                  NO_INSERT);
+  if (slot)
+    {
+      variable var = (variable) *slot;
+      int pos = find_variable_location_part (var, offset, NULL);
+
+      if (pos >= 0)
+       {
+         location_chain node, next;
+
+         /* Remove the register locations from the dataflow set.  */
+         next = var->var_part[pos].loc_chain;
+         for (node = next; node; node = next)
+           {
+             next = node->next;
+             if (node->loc != loc)
+               {
+                 if (REG_P (node->loc))
+                   {
+                     attrs anode, anext;
+                     attrs *anextp;
+
+                     /* Remove the variable part from the register's
+                        list, but preserve any other variable parts
+                        that might be regarded as live in that same
+                        register.  */
+                     anextp = &set->regs[REGNO (node->loc)];
+                     for (anode = *anextp; anode; anode = anext)
+                       {
+                         anext = anode->next;
+                         if (anode->decl == decl
+                             && anode->offset == offset)
+                           {
+                             pool_free (attrs_pool, anode);
+                             *anextp = anext;
+                           }
+                       }
+                   }
+
+                 delete_variable_part (set, node->loc, decl, offset);
+               }
+           }
+       }
+    }
+}
+
 /* Delete the part of variable's location from dataflow set SET.  The variable
    part is specified by variable's declaration DECL and offset OFFSET and the
    part's location by LOC.  */
@@ -2080,7 +2251,6 @@ static void
 delete_variable_part (dataflow_set *set, rtx loc, tree decl,
                      HOST_WIDE_INT offset)
 {
-  int pos, low, high;
   void **slot;
     
   slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl),
@@ -2088,21 +2258,9 @@ delete_variable_part (dataflow_set *set, rtx loc, tree decl,
   if (slot)
     {
       variable var = (variable) *slot;
+      int pos = find_variable_location_part (var, offset, NULL);
 
-      /* Find the location part.  */
-      low = 0;
-      high = var->n_var_parts;
-      while (low != high)
-       {
-         pos = (low + high) / 2;
-         if (var->var_part[pos].offset < offset)
-           low = pos + 1;
-         else
-           high = pos;
-       }
-      pos = low;
-
-      if (pos < var->n_var_parts && var->var_part[pos].offset == offset)
+      if (pos >= 0)
        {
          location_chain node, next;
          location_chain *nextp;
@@ -2168,7 +2326,7 @@ delete_variable_part (dataflow_set *set, rtx loc, tree decl,
                }
            }
          if (changed)
-             variable_was_changed (var, set->vars);
+           variable_was_changed (var, set->vars);
        }
     }
 }
@@ -2184,28 +2342,101 @@ emit_note_insn_var_location (void **varp, void *data)
   rtx insn = ((emit_note_data *)data)->insn;
   enum emit_note_where where = ((emit_note_data *)data)->where;
   rtx note;
-  int i;
+  int i, j, n_var_parts;
   bool complete;
   HOST_WIDE_INT last_limit;
   tree type_size_unit;
+  HOST_WIDE_INT offsets[MAX_VAR_PARTS];
+  rtx loc[MAX_VAR_PARTS];
 
-#ifdef ENABLE_CHECKING
-  if (!var->decl)
-    abort ();
-#endif
+  gcc_assert (var->decl);
 
   complete = true;
   last_limit = 0;
+  n_var_parts = 0;
   for (i = 0; i < var->n_var_parts; i++)
     {
+      enum machine_mode mode, wider_mode;
+
       if (last_limit < var->var_part[i].offset)
        {
          complete = false;
          break;
        }
-      last_limit
-       = (var->var_part[i].offset
-          + GET_MODE_SIZE (GET_MODE (var->var_part[i].loc_chain->loc)));
+      else if (last_limit > var->var_part[i].offset)
+       continue;
+      offsets[n_var_parts] = var->var_part[i].offset;
+      loc[n_var_parts] = var->var_part[i].loc_chain->loc;
+      mode = GET_MODE (loc[n_var_parts]);
+      last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
+
+      /* Attempt to merge adjacent registers or memory.  */
+      wider_mode = GET_MODE_WIDER_MODE (mode);
+      for (j = i + 1; j < var->n_var_parts; j++)
+       if (last_limit <= var->var_part[j].offset)
+         break;
+      if (j < var->n_var_parts
+         && wider_mode != VOIDmode
+         && GET_CODE (loc[n_var_parts])
+            == GET_CODE (var->var_part[j].loc_chain->loc)
+         && mode == GET_MODE (var->var_part[j].loc_chain->loc)
+         && last_limit == var->var_part[j].offset)
+       {
+         rtx new_loc = NULL;
+         rtx loc2 = var->var_part[j].loc_chain->loc;
+
+         if (REG_P (loc[n_var_parts])
+             && hard_regno_nregs[REGNO (loc[n_var_parts])][mode] * 2
+                == hard_regno_nregs[REGNO (loc[n_var_parts])][wider_mode]
+             && REGNO (loc[n_var_parts])
+                + hard_regno_nregs[REGNO (loc[n_var_parts])][mode]
+                == REGNO (loc2))
+           {
+             if (! WORDS_BIG_ENDIAN && ! BYTES_BIG_ENDIAN)
+               new_loc = simplify_subreg (wider_mode, loc[n_var_parts],
+                                          mode, 0);
+             else if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
+               new_loc = simplify_subreg (wider_mode, loc2, mode, 0);
+             if (new_loc)
+               {
+                 if (!REG_P (new_loc)
+                     || REGNO (new_loc) != REGNO (loc[n_var_parts]))
+                   new_loc = NULL;
+                 else
+                   REG_ATTRS (new_loc) = REG_ATTRS (loc[n_var_parts]);
+               }
+           }
+         else if (MEM_P (loc[n_var_parts])
+                  && GET_CODE (XEXP (loc2, 0)) == PLUS
+                  && GET_CODE (XEXP (XEXP (loc2, 0), 0)) == REG
+                  && GET_CODE (XEXP (XEXP (loc2, 0), 1)) == CONST_INT)
+           {
+             if ((GET_CODE (XEXP (loc[n_var_parts], 0)) == REG
+                  && rtx_equal_p (XEXP (loc[n_var_parts], 0),
+                                  XEXP (XEXP (loc2, 0), 0))
+                  && INTVAL (XEXP (XEXP (loc2, 0), 1))
+                     == GET_MODE_SIZE (mode))
+                 || (GET_CODE (XEXP (loc[n_var_parts], 0)) == PLUS
+                     && GET_CODE (XEXP (XEXP (loc[n_var_parts], 0), 1))
+                        == CONST_INT
+                     && rtx_equal_p (XEXP (XEXP (loc[n_var_parts], 0), 0),
+                                     XEXP (XEXP (loc2, 0), 0))
+                     && INTVAL (XEXP (XEXP (loc[n_var_parts], 0), 1))
+                        + GET_MODE_SIZE (mode)
+                        == INTVAL (XEXP (XEXP (loc2, 0), 1))))
+               new_loc = adjust_address_nv (loc[n_var_parts],
+                                            wider_mode, 0);
+           }
+
+         if (new_loc)
+           {
+             loc[n_var_parts] = new_loc;
+             mode = wider_mode;
+             last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
+             i = j;
+           }
+       }
+      ++n_var_parts;
     }
   type_size_unit = TYPE_SIZE_UNIT (TREE_TYPE (var->decl));
   if ((unsigned HOST_WIDE_INT) last_limit < TREE_INT_CST_LOW (type_size_unit))
@@ -2221,26 +2452,24 @@ emit_note_insn_var_location (void **varp, void *data)
       NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
                                                       NULL_RTX);
     }
-  else if (var->n_var_parts == 1)
+  else if (n_var_parts == 1)
     {
       rtx expr_list
-       = gen_rtx_EXPR_LIST (VOIDmode,
-                            var->var_part[0].loc_chain->loc,
-                            GEN_INT (var->var_part[0].offset));
+       = gen_rtx_EXPR_LIST (VOIDmode, loc[0], GEN_INT (offsets[0]));
 
       NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
                                                       expr_list);
     }
-  else if (var->n_var_parts)
+  else if (n_var_parts)
     {
-      rtx argp[MAX_VAR_PARTS];
       rtx parallel;
 
-      for (i = 0; i < var->n_var_parts; i++)
-       argp[i] = gen_rtx_EXPR_LIST (VOIDmode, var->var_part[i].loc_chain->loc,
-                                    GEN_INT (var->var_part[i].offset));
+      for (i = 0; i < n_var_parts; i++)
+       loc[i]
+         = gen_rtx_EXPR_LIST (VOIDmode, loc[i], GEN_INT (offsets[i]));
+
       parallel = gen_rtx_PARALLEL (VOIDmode,
-                                  gen_rtvec_v (var->n_var_parts, argp));
+                                  gen_rtvec_v (n_var_parts, loc));
       NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
                                                       parallel);
     }
@@ -2371,51 +2600,73 @@ emit_notes_in_bb (basic_block bb)
            break;
 
          case MO_USE:
+           {
+             rtx loc = VTI (bb)->mos[i].u.loc;
+
+             if (GET_CODE (loc) == REG)
+               var_reg_set (&set, loc);
+             else
+               var_mem_set (&set, loc);
+
+             emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+           }
+           break;
+
          case MO_SET:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
 
              if (REG_P (loc))
-               var_reg_delete_and_set (&set, loc);
+               var_reg_delete_and_set (&set, loc, true);
              else
-               var_mem_delete_and_set (&set, loc);
+               var_mem_delete_and_set (&set, loc, true);
+
+             emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
+           }
+           break;
+
+         case MO_COPY:
+           {
+             rtx loc = VTI (bb)->mos[i].u.loc;
 
-             if (VTI (bb)->mos[i].type == MO_USE)
-               emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
+             if (REG_P (loc))
+               var_reg_delete_and_set (&set, loc, false);
              else
-               emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+               var_mem_delete_and_set (&set, loc, false);
+
+             emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
            }
            break;
 
          case MO_USE_NO_VAR:
-         case MO_CLOBBER:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
 
              if (REG_P (loc))
-               var_reg_delete (&set, loc);
+               var_reg_delete (&set, loc, false);
              else
-               var_mem_delete (&set, loc);
+               var_mem_delete (&set, loc, false);
 
-             if (VTI (bb)->mos[i].type == MO_USE_NO_VAR)
-               emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
-             else
-               emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+             emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
            }
            break;
 
-         case MO_ADJUST:
+         case MO_CLOBBER:
            {
-             rtx base;
+             rtx loc = VTI (bb)->mos[i].u.loc;
 
-             set.stack_adjust += VTI (bb)->mos[i].u.adjust;
-             base = gen_rtx_MEM (Pmode,
-                                 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-                                               GEN_INT (set.stack_adjust)));
-             set_frame_base_location (&set, base);
-             emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
+             if (REG_P (loc))
+               var_reg_delete (&set, loc, true);
+             else
+               var_mem_delete (&set, loc, true);
+
+             emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
            }
            break;
+
+         case MO_ADJUST:
+           set.stack_adjust += VTI (bb)->mos[i].u.adjust;
+           break;
        }
     }
   dataflow_set_destroy (&set);
@@ -2430,10 +2681,7 @@ vt_emit_notes (void)
   dataflow_set *last_out;
   dataflow_set empty;
 
-#ifdef ENABLE_CHECKING
-  if (htab_elements (changed_variables))
-    abort ();
-#endif
+  gcc_assert (!htab_elements (changed_variables));
 
   /* Enable emitting notes by functions (mainly by set_variable_part and
      delete_variable_part).  */
@@ -2472,7 +2720,7 @@ vt_get_decl_and_offset (rtx rtl, tree *declp, HOST_WIDE_INT *offsetp)
          return true;
        }
     }
-  else if (GET_CODE (rtl) == MEM)
+  else if (MEM_P (rtl))
     {
       if (MEM_ATTRS (rtl))
        {
@@ -2490,11 +2738,7 @@ static void
 vt_add_function_parameters (void)
 {
   tree parm;
-  HOST_WIDE_INT stack_adjust = 0;
   
-  if (!frame_pointer_needed)
-    stack_adjust = prologue_stack_adjust ();
-
   for (parm = DECL_ARGUMENTS (current_function_decl);
        parm; parm = TREE_CHAIN (parm))
     {
@@ -2523,30 +2767,19 @@ vt_add_function_parameters (void)
       if (!decl)
        continue;
 
-#ifdef ENABLE_CHECKING
-      if (parm != decl)
-       abort ();
-#endif
+      gcc_assert (parm == decl);
 
-      incoming = eliminate_regs (incoming, 0, NULL_RTX);
-      if (!frame_pointer_needed && GET_CODE (incoming) == MEM)
-       incoming = adjust_stack_reference (incoming, -stack_adjust);
       out = &VTI (ENTRY_BLOCK_PTR)->out;
 
       if (REG_P (incoming))
        {
-#ifdef ENABLE_CHECKING
-         if (REGNO (incoming) >= FIRST_PSEUDO_REGISTER)
-           abort ();
-#endif
+         gcc_assert (REGNO (incoming) < FIRST_PSEUDO_REGISTER);
          attrs_list_insert (&out->regs[REGNO (incoming)],
                             parm, offset, incoming);
          set_variable_part (out, incoming, parm, offset);
        }
-      else if (GET_CODE (incoming) == MEM)
-       {
-         set_variable_part (out, incoming, parm, offset);
-       }
+      else if (MEM_P (incoming))
+       set_variable_part (out, incoming, parm, offset);
     }
 }
 
@@ -2563,7 +2796,7 @@ vt_initialize (void)
   FOR_EACH_BB (bb)
     {
       rtx insn;
-      HOST_WIDE_INT pre, post;
+      HOST_WIDE_INT pre, post = 0;
 
       /* Count the number of micro operations.  */
       VTI (bb)->n_mos = 0;
@@ -2582,14 +2815,13 @@ vt_initialize (void)
                }
              note_uses (&PATTERN (insn), count_uses_1, insn);
              note_stores (PATTERN (insn), count_stores, insn);
-             if (GET_CODE (insn) == CALL_INSN)
+             if (CALL_P (insn))
                VTI (bb)->n_mos++;
            }
        }
 
       /* Add the micro-operations to the array.  */
-      VTI (bb)->mos = xmalloc (VTI (bb)->n_mos
-                              * sizeof (struct micro_operation_def));
+      VTI (bb)->mos = XNEWVEC (micro_operation, VTI (bb)->n_mos);
       VTI (bb)->n_mos = 0;
       for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
           insn = NEXT_INSN (insn))
@@ -2632,7 +2864,7 @@ vt_initialize (void)
                    }
                }
 
-             if (GET_CODE (insn) == CALL_INSN)
+             if (CALL_P (insn))
                {
                  micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
 
@@ -2641,15 +2873,19 @@ vt_initialize (void)
                }
 
              n1 = VTI (bb)->n_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.  */
              note_stores (PATTERN (insn), add_stores, insn);
              n2 = VTI (bb)->n_mos - 1;
 
-             /* Order the MO_SETs to be before MO_CLOBBERs.  */
+             /* Order the MO_CLOBBERs to be before MO_SETs.  */
              while (n1 < n2)
                {
-                 while (n1 < n2 && VTI (bb)->mos[n1].type == MO_SET)
+                 while (n1 < n2 && VTI (bb)->mos[n1].type == MO_CLOBBER)
                    n1++;
-                 while (n1 < n2 && VTI (bb)->mos[n2].type == MO_CLOBBER)
+                 while (n1 < n2 && (VTI (bb)->mos[n2].type == MO_SET
+                                    || VTI (bb)->mos[n2].type == MO_COPY))
                    n2--;
                  if (n1 < n2)
                    {
@@ -2691,25 +2927,6 @@ vt_initialize (void)
   changed_variables = htab_create (10, variable_htab_hash, variable_htab_eq,
                                   NULL);
   vt_add_function_parameters ();
-
-  if (!frame_pointer_needed)
-    {
-      rtx base;
-
-      /* Create fake variable for tracking stack pointer changes.  */
-      frame_base_decl = make_node (VAR_DECL);
-      DECL_NAME (frame_base_decl) = get_identifier ("___frame_base_decl");
-      TREE_TYPE (frame_base_decl) = char_type_node;
-      DECL_ARTIFICIAL (frame_base_decl) = 1;
-
-      /* Set its initial "location".  */
-      base = gen_rtx_MEM (Pmode, stack_pointer_rtx);
-      set_variable_part (&VTI (ENTRY_BLOCK_PTR)->out, base, frame_base_decl, 0);
-    }
-  else
-    {
-      frame_base_decl = NULL;
-    }
 }
 
 /* Free the data structures needed for variable tracking.  */
@@ -2738,11 +2955,11 @@ vt_finalize (void)
 
 /* The entry point to variable tracking pass.  */
 
-void
+unsigned int
 variable_tracking_main (void)
 {
   if (n_basic_blocks > 500 && n_edges / n_basic_blocks >= 20)
-    return;
+    return 0;
 
   mark_dfs_back_edges ();
   vt_initialize ();
@@ -2751,18 +2968,45 @@ variable_tracking_main (void)
       if (!vt_stack_adjustments ())
        {
          vt_finalize ();
-         return;
+         return 0;
        }
     }
 
   vt_find_locations ();
   vt_emit_notes ();
 
-  if (dump_file)
+  if (dump_file && (dump_flags & TDF_DETAILS))
     {
       dump_dataflow_sets ();
-      dump_flow_info (dump_file);
+      dump_flow_info (dump_file, dump_flags);
     }
 
   vt_finalize ();
+  return 0;
 }
+\f
+static bool
+gate_handle_var_tracking (void)
+{
+  return (flag_var_tracking);
+}
+
+
+
+struct tree_opt_pass pass_variable_tracking =
+{
+  "vartrack",                           /* name */
+  gate_handle_var_tracking,             /* gate */
+  variable_tracking_main,               /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_VAR_TRACKING,                      /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func,                       /* todo_flags_finish */
+  'V'                                   /* letter */
+};
+