OSDN Git Service

* tree-sra.c (decide_block_copy): Decide if there are groups.
[pf3gnuchains/gcc-fork.git] / gcc / var-tracking.c
index c4bef66..97986b6 100644 (file)
@@ -1,11 +1,11 @@
 /* Variable tracking routines for the GNU compiler.
-   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
    GCC is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GCC is distributed in the hope that it will be useful, but WITHOUT
@@ -14,9 +14,8 @@
    License for more details.
 
    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, 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.  */
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
 
 /* This file contains the variable tracking pass.  It computes where
    variables are located (which registers or where in memory) at each position
@@ -219,6 +218,12 @@ typedef struct location_chain_def
 
   /* The location (REG or MEM).  */
   rtx loc;
+
+  /* The "value" stored in this location.  */
+  rtx set_src;
+
+  /* Initialized? */
+  enum var_init_status init;
 } *location_chain;
 
 /* Structure describing one part of variable.  */
@@ -252,6 +257,7 @@ typedef struct variable_def
   /* The variable parts.  */
   variable_part var_part[MAX_VAR_PARTS];
 } *variable;
+typedef const struct variable_def *const_variable;
 
 /* Hash function for DECL for VARIABLE_HTAB.  */
 #define VARIABLE_HASH_VAL(decl) (DECL_UID (decl))
@@ -294,16 +300,19 @@ static void attrs_list_copy (attrs *, attrs);
 static void attrs_list_union (attrs *, attrs);
 
 static void vars_clear (htab_t);
-static variable unshare_variable (dataflow_set *set, variable var);
+static variable unshare_variable (dataflow_set *set, 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);
-static void var_reg_delete_and_set (dataflow_set *, rtx, bool);
+static void var_reg_set (dataflow_set *, rtx, enum var_init_status, rtx);
+static void var_reg_delete_and_set (dataflow_set *, rtx, bool, 
+                                   enum var_init_status, rtx);
 static void var_reg_delete (dataflow_set *, rtx, bool);
 static void var_regno_delete (dataflow_set *, int);
-static void var_mem_set (dataflow_set *, rtx);
-static void var_mem_delete_and_set (dataflow_set *, rtx, bool);
+static void var_mem_set (dataflow_set *, rtx, enum var_init_status, rtx);
+static void var_mem_delete_and_set (dataflow_set *, rtx, bool, 
+                                   enum var_init_status, rtx);
 static void var_mem_delete (dataflow_set *, rtx, bool);
 
 static void dataflow_set_init (dataflow_set *, int);
@@ -324,10 +333,10 @@ 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 *);
+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, rtx, void *);
+static void add_stores (rtx, const_rtx, void *);
 static bool compute_bb_dataflow (basic_block);
 static void vt_find_locations (void);
 
@@ -338,8 +347,10 @@ static void dump_dataflow_set (dataflow_set *);
 static void dump_dataflow_sets (void);
 
 static void variable_was_changed (variable, htab_t);
-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 set_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT, 
+                              enum var_init_status, rtx);
+static void clobber_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT, 
+                                  rtx);
 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);
@@ -590,7 +601,7 @@ adjust_stack_reference (rtx mem, HOST_WIDE_INT adjustment)
 static hashval_t
 variable_htab_hash (const void *x)
 {
-  const variable v = (const variable) x;
+  const_variable const v = (const_variable) x;
 
   return (VARIABLE_HASH_VAL (v->decl));
 }
@@ -600,8 +611,8 @@ variable_htab_hash (const void *x)
 static int
 variable_htab_eq (const void *x, const void *y)
 {
-  const variable v = (const variable) x;
-  const tree decl = (const tree) y;
+  const_variable const v = (const_variable) x;
+  const_tree const decl = (const_tree) y;
 
   return (VARIABLE_HASH_VAL (v->decl) == VARIABLE_HASH_VAL (decl));
 }
@@ -727,7 +738,8 @@ vars_clear (htab_t vars)
 /* Return a copy of a variable VAR and insert it to dataflow set SET.  */
 
 static variable
-unshare_variable (dataflow_set *set, variable var)
+unshare_variable (dataflow_set *set, variable var, 
+                 enum var_init_status initialized)
 {
   void **slot;
   variable new_var;
@@ -752,6 +764,14 @@ unshare_variable (dataflow_set *set, variable var)
 
          new_lc = pool_alloc (loc_chain_pool);
          new_lc->next = NULL;
+         if (node->init > initialized)
+           new_lc->init = node->init;
+         else
+           new_lc->init = initialized;
+         if (node->set_src && !(MEM_P (node->set_src)))
+           new_lc->set_src = node->set_src;
+         else
+           new_lc->set_src = NULL;
          new_lc->loc = node->loc;
 
          *nextp = new_lc;
@@ -819,7 +839,8 @@ var_debug_decl (tree decl)
 /* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  */
 
 static void
-var_reg_set (dataflow_set *set, rtx loc)
+var_reg_set (dataflow_set *set, rtx loc, enum var_init_status initialized, 
+            rtx set_src)
 {
   tree decl = REG_EXPR (loc);
   HOST_WIDE_INT offset = REG_OFFSET (loc);
@@ -832,7 +853,38 @@ var_reg_set (dataflow_set *set, rtx loc)
       break;
   if (!node)
     attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, loc);
-  set_variable_part (set, loc, decl, offset);
+  set_variable_part (set, loc, decl, offset, initialized, set_src);
+}
+
+static int
+get_init_value (dataflow_set *set, rtx loc, tree decl)
+{
+  void **slot;
+  variable var;
+  int i;
+  int ret_val = VAR_INIT_STATUS_UNKNOWN;
+
+  if (! flag_var_tracking_uninit)
+    return VAR_INIT_STATUS_INITIALIZED;
+
+  slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl),
+                                  NO_INSERT);
+  if (slot)
+    {
+      var = * (variable *) slot;
+      for (i = 0; i < var->n_var_parts && ret_val == VAR_INIT_STATUS_UNKNOWN; i++)
+       {
+         location_chain nextp;
+         for (nextp = var->var_part[i].loc_chain; nextp; nextp = nextp->next)
+           if (rtx_equal_p (nextp->loc, loc))
+             {
+               ret_val = nextp->init;
+               break;
+             }
+       }
+    }
+
+  return ret_val;
 }
 
 /* Delete current content of register LOC in dataflow set SET and set
@@ -843,7 +895,8 @@ var_reg_set (dataflow_set *set, rtx loc)
    part.  */
 
 static void
-var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify)
+var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify, 
+                       enum var_init_status initialized, rtx set_src)
 {
   tree decl = REG_EXPR (loc);
   HOST_WIDE_INT offset = REG_OFFSET (loc);
@@ -852,6 +905,9 @@ var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify)
 
   decl = var_debug_decl (decl);
 
+  if (initialized == VAR_INIT_STATUS_UNKNOWN)
+    initialized = get_init_value (set, loc, decl);
+
   nextp = &set->regs[REGNO (loc)];
   for (node = *nextp; node; node = next)
     {
@@ -869,8 +925,8 @@ var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify)
        }
     }
   if (modify)
-    clobber_variable_part (set, loc, decl, offset);
-  var_reg_set (set, loc);
+    clobber_variable_part (set, loc, decl, offset, set_src);
+  var_reg_set (set, loc, initialized, set_src);
 }
 
 /* Delete current content of register LOC in dataflow set SET.  If
@@ -890,7 +946,7 @@ var_reg_delete (dataflow_set *set, rtx loc, bool clobber)
 
       decl = var_debug_decl (decl);
 
-      clobber_variable_part (set, NULL, decl, offset);
+      clobber_variable_part (set, NULL, decl, offset, NULL);
     }
 
   for (node = *reg; node; node = next)
@@ -924,14 +980,15 @@ var_regno_delete (dataflow_set *set, int regno)
    Adjust the address first if it is stack pointer based.  */
 
 static void
-var_mem_set (dataflow_set *set, rtx loc)
+var_mem_set (dataflow_set *set, rtx loc, enum var_init_status initialized, 
+            rtx set_src)
 {
   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);
+  set_variable_part (set, loc, decl, offset, initialized, set_src);
 }
 
 /* Delete and set the location part of variable MEM_EXPR (LOC) in
@@ -942,16 +999,20 @@ var_mem_set (dataflow_set *set, rtx loc)
    Adjust the address first if it is stack pointer based.  */
 
 static void
-var_mem_delete_and_set (dataflow_set *set, rtx loc, bool modify)
+var_mem_delete_and_set (dataflow_set *set, rtx loc, bool modify, 
+                       enum var_init_status initialized, rtx set_src)
 {
   tree decl = MEM_EXPR (loc);
   HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
 
   decl = var_debug_decl (decl);
 
+  if (initialized == VAR_INIT_STATUS_UNKNOWN)
+    initialized = get_init_value (set, loc, decl);
+
   if (modify)
-    clobber_variable_part (set, NULL, decl, offset);
-  var_mem_set (set, loc);
+    clobber_variable_part (set, NULL, decl, offset, set_src);
+  var_mem_set (set, loc, initialized, set_src);
 }
 
 /* Delete the location part LOC from dataflow set SET.  If CLOBBER is
@@ -966,7 +1027,7 @@ var_mem_delete (dataflow_set *set, rtx loc, bool clobber)
 
   decl = var_debug_decl (decl);
   if (clobber)
-    clobber_variable_part (set, NULL, decl, offset);
+    clobber_variable_part (set, NULL, decl, offset, NULL);
   delete_variable_part (set, loc, decl, offset);
 }
 
@@ -1078,7 +1139,14 @@ variable_union (void **slot, void *data)
            }
        }
       if (k < src->n_var_parts)
-       unshare_variable (set, src);
+       {
+         enum var_init_status status = VAR_INIT_STATUS_UNKNOWN;
+         
+         if (! flag_var_tracking_uninit)
+           status = VAR_INIT_STATUS_INITIALIZED;
+
+         unshare_variable (set, src, status);
+       }
       else
        *dstp = src;
 
@@ -1112,7 +1180,13 @@ variable_union (void **slot, void *data)
   gcc_assert (k <= MAX_VAR_PARTS);
 
   if (dst->refcount > 1 && dst->n_var_parts != k)
-    dst = unshare_variable (set, dst);
+    {
+      enum var_init_status status = VAR_INIT_STATUS_UNKNOWN;
+      
+      if (! flag_var_tracking_uninit)
+       status = VAR_INIT_STATUS_INITIALIZED;
+      dst = unshare_variable (set, dst, status);
+    }
 
   i = src->n_var_parts - 1;
   j = dst->n_var_parts - 1;
@@ -1145,10 +1219,12 @@ variable_union (void **slot, void *data)
                         && REG_P (node->loc)
                         && REGNO (node2->loc) == REGNO (node->loc))
                        || rtx_equal_p (node2->loc, node->loc)))
+                   if (node2->init < node->init)
+                     node2->init = node->init;
                    break;
                }
              if (node || node2)
-               dst = unshare_variable (set, dst);
+               dst = unshare_variable (set, dst, VAR_INIT_STATUS_UNKNOWN);
            }
 
          src_l = 0;
@@ -1194,6 +1270,11 @@ variable_union (void **slot, void *data)
                  /* Copy the location from SRC.  */
                  new_node = pool_alloc (loc_chain_pool);
                  new_node->loc = node->loc;
+                 new_node->init = node->init;
+                 if (!node->set_src || MEM_P (node->set_src))
+                   new_node->set_src = NULL;
+                 else
+                   new_node->set_src = node->set_src;
                  vui[n].lc = new_node;
                  vui[n].pos_src = ii;
                  vui[n].pos_dst = src_l + dst_l;
@@ -1240,6 +1321,11 @@ variable_union (void **slot, void *data)
 
              new_lc = pool_alloc (loc_chain_pool);
              new_lc->next = NULL;
+             new_lc->init = node->init;
+             if (!node->set_src || MEM_P (node->set_src))
+               new_lc->set_src = NULL;
+             else
+               new_lc->set_src = node->set_src;
              new_lc->loc = node->loc;
 
              *nextp = new_lc;
@@ -1258,6 +1344,18 @@ variable_union (void **slot, void *data)
        dst->var_part[k].cur_loc = NULL;
     }
 
+  for (i = 0; i < src->n_var_parts && i < dst->n_var_parts; i++)
+    {
+      location_chain node, node2;
+      for (node = src->var_part[i].loc_chain; node; node = node->next)
+       for (node2 = dst->var_part[i].loc_chain; node2; node2 = node2->next)
+         if (rtx_equal_p (node->loc, node2->loc))
+           {
+             if (node->init > node2->init)
+               node2->init = node->init;
+           }
+    }
+
   /* Continue traversing the hash table.  */
   return 1;
 }
@@ -1529,7 +1627,8 @@ track_expr_p (tree expr)
   if (MEM_P (decl_rtl))
     {
       /* Do not track structures and arrays.  */
-      if (GET_MODE (decl_rtl) == BLKmode)
+      if (GET_MODE (decl_rtl) == BLKmode
+         || AGGREGATE_TYPE_P (TREE_TYPE (realdecl)))
        return 0;
       if (MEM_SIZE (decl_rtl)
          && INTVAL (MEM_SIZE (decl_rtl)) > MAX_VAR_PARTS)
@@ -1609,7 +1708,7 @@ count_uses_1 (rtx *x, void *insn)
    INSN is instruction which the LOC is part of.  */
 
 static void
-count_stores (rtx loc, rtx expr ATTRIBUTE_UNUSED, void *insn)
+count_stores (rtx loc, const_rtx expr ATTRIBUTE_UNUSED, void *insn)
 {
   count_uses (&loc, insn);
 }
@@ -1658,7 +1757,7 @@ add_uses_1 (rtx *x, void *insn)
    INSN is instruction which the LOC is part of.  */
 
 static void
-add_stores (rtx loc, rtx expr, void *insn)
+add_stores (rtx loc, const_rtx expr, void *insn)
 {
   if (REG_P (loc))
     {
@@ -1678,7 +1777,7 @@ add_stores (rtx loc, rtx expr, void *insn)
       else
        mo->type = MO_SET;
       mo->u.loc = loc;
-      mo->insn = NEXT_INSN ((rtx) insn);
+      mo->insn = (rtx) insn;
     }
   else if (MEM_P (loc)
           && MEM_EXPR (loc)
@@ -1699,10 +1798,111 @@ add_stores (rtx loc, rtx expr, void *insn)
       else
        mo->type = MO_SET;
       mo->u.loc = loc;
-      mo->insn = NEXT_INSN ((rtx) insn);
+      mo->insn = (rtx) insn;
     }
 }
 
+static enum var_init_status
+find_src_status (dataflow_set *in, rtx loc, rtx insn)
+{
+  rtx src = NULL_RTX;
+  rtx pattern;
+  tree decl = NULL_TREE;
+  enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED;
+
+  if (! flag_var_tracking_uninit)
+    status = VAR_INIT_STATUS_INITIALIZED;
+
+  pattern = PATTERN (insn);
+
+  if (GET_CODE (pattern) == COND_EXEC)
+    pattern = COND_EXEC_CODE (pattern);
+
+  if (GET_CODE (pattern) == SET)
+    src = SET_SRC (pattern);
+  else if (GET_CODE (pattern) == PARALLEL
+          || GET_CODE (pattern) == SEQUENCE)
+    {
+      int i;
+      for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
+       if (GET_CODE (XVECEXP (pattern, 0, i)) == SET
+           && SET_DEST (XVECEXP (pattern, 0, i)) == loc)
+         src = SET_SRC (XVECEXP (pattern, 0, i));
+    }
+
+  if (src && REG_P (src))
+    decl = var_debug_decl (REG_EXPR (src));
+  else if (src && MEM_P (src))
+    decl = var_debug_decl (MEM_EXPR (src));
+
+  if (src && decl)
+    status = get_init_value (in, src, decl);
+
+  return status;
+}
+
+/* LOC is the destination the variable is being copied to.  INSN 
+   contains the copy instruction.  SET is the dataflow set containing
+   the variable in LOC.  */
+
+static rtx
+find_src_set_src (dataflow_set *set, rtx loc, rtx insn)
+{
+  tree decl = NULL_TREE;   /* The variable being copied around.          */
+  rtx src = NULL_RTX;      /* The location "decl" is being copied from.  */
+  rtx set_src = NULL_RTX;  /* The value for "decl" stored in "src".      */
+  rtx pattern;
+  void **slot;
+  variable var;
+  location_chain nextp;
+  int i;
+  bool found;
+
+
+  pattern = PATTERN (insn);
+  if (GET_CODE (pattern) == COND_EXEC)
+    pattern = COND_EXEC_CODE (pattern);
+
+  if (GET_CODE (pattern) == SET)
+    src = SET_SRC (pattern);
+  else if (GET_CODE (pattern) == PARALLEL
+          || GET_CODE (pattern) == SEQUENCE)
+    {
+      for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
+       if (GET_CODE (XVECEXP (pattern, 0, i)) == SET
+           && SET_DEST (XVECEXP (pattern, 0, i)) == loc)
+         src = SET_SRC (XVECEXP (pattern, 0, i));
+    }
+
+  if (src && REG_P (src))
+    decl = var_debug_decl (REG_EXPR (src));
+  else if (src && MEM_P (src))
+    decl = var_debug_decl (MEM_EXPR (src));
+
+  if (src && decl)
+    {
+      slot = htab_find_slot_with_hash (set->vars, decl, 
+                                      VARIABLE_HASH_VAL (decl), NO_INSERT);
+
+      if (slot)
+       {
+         var = *(variable *) slot;
+         found = false;
+         for (i = 0; i < var->n_var_parts && !found; i++)
+           for (nextp = var->var_part[i].loc_chain; nextp && !found; 
+                nextp = nextp->next)
+             if (rtx_equal_p (nextp->loc, src))
+               {
+                 set_src = nextp->set_src;
+                 found = true;
+               }
+             
+       }
+    }
+
+  return set_src;
+}
+
 /* Compute the changes of variable locations in the basic block BB.  */
 
 static bool
@@ -1732,33 +1932,65 @@ compute_bb_dataflow (basic_block bb)
          case MO_USE:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
+             enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED;
+
+             if (! flag_var_tracking_uninit)
+               status = VAR_INIT_STATUS_INITIALIZED;
 
              if (GET_CODE (loc) == REG)
-               var_reg_set (out, loc);
+               var_reg_set (out, loc, status, NULL);
              else if (GET_CODE (loc) == MEM)
-               var_mem_set (out, loc);
+               var_mem_set (out, loc, status, NULL);
            }
            break;
 
          case MO_SET:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx set_src =  NULL;
+             rtx insn = VTI (bb)->mos[i].insn;
+
+             if (GET_CODE (PATTERN (insn)) == SET)
+               set_src = SET_SRC (PATTERN (insn));
+             else if (GET_CODE (PATTERN (insn)) == PARALLEL
+                      || GET_CODE (PATTERN (insn)) == SEQUENCE)
+               {
+                 int j;
+                 for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
+                   if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET
+                       && SET_DEST (XVECEXP (PATTERN (insn), 0, j)) == loc)
+                     set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, j));
+               }
 
              if (REG_P (loc))
-               var_reg_delete_and_set (out, loc, true);
+               var_reg_delete_and_set (out, loc, true, VAR_INIT_STATUS_INITIALIZED,
+                                       set_src);
              else if (MEM_P (loc))
-               var_mem_delete_and_set (out, loc, true);
+               var_mem_delete_and_set (out, loc, true, VAR_INIT_STATUS_INITIALIZED,
+                                       set_src);
            }
            break;
 
          case MO_COPY:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
+             enum var_init_status src_status;
+             rtx set_src;
+
+             if (! flag_var_tracking_uninit)
+               src_status = VAR_INIT_STATUS_INITIALIZED;
+             else
+               src_status = find_src_status (in, loc, VTI (bb)->mos[i].insn);
+
+             if (src_status == VAR_INIT_STATUS_UNKNOWN)
+               src_status = find_src_status (out, loc, VTI (bb)->mos[i].insn);
+
+             set_src = find_src_set_src (in, loc, VTI (bb)->mos[i].insn);
 
              if (REG_P (loc))
-               var_reg_delete_and_set (out, loc, false);
+               var_reg_delete_and_set (out, loc, false, src_status, set_src);
              else if (MEM_P (loc))
-               var_mem_delete_and_set (out, loc, false);
+               var_mem_delete_and_set (out, loc, false, src_status, set_src);
            }
            break;
 
@@ -1931,6 +2163,8 @@ dump_variable (void **slot, void *data ATTRIBUTE_UNUSED)
       for (node = var->var_part[i].loc_chain; node; node = node->next)
        {
          fprintf (dump_file, "      ");
+         if (node->init == VAR_INIT_STATUS_UNINITIALIZED)
+           fprintf (dump_file, "[uninit]");
          print_rtl_single (dump_file, node->loc);
        }
     }
@@ -2076,7 +2310,8 @@ find_variable_location_part (variable var, HOST_WIDE_INT offset,
    part's location by LOC.  */
 
 static void
-set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
+set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset,
+                  enum var_init_status initialized, rtx set_src)
 {
   int pos;
   location_chain node, next;
@@ -2118,13 +2353,19 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
            {
              /* LOC is in the beginning of the chain so we have nothing
                 to do.  */
+             if (node->init < initialized)
+               node->init = initialized;
+             if (set_src != NULL)
+               node->set_src = set_src;
+
+             *slot = var;
              return;
            }
          else
            {
              /* We have to make a copy of a shared variable.  */
              if (var->refcount > 1)
-               var = unshare_variable (set, var);
+               var = unshare_variable (set, var, initialized);
            }
        }
       else
@@ -2133,7 +2374,7 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
 
          /* We have to make a copy of the shared variable.  */
          if (var->refcount > 1)
-           var = unshare_variable (set, var);
+           var = unshare_variable (set, var, initialized);
 
          /* We track only variables whose size is <= MAX_VAR_PARTS bytes
             thus there are at most MAX_VAR_PARTS different offsets.  */
@@ -2160,6 +2401,12 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
           && REGNO (node->loc) == REGNO (loc))
          || rtx_equal_p (node->loc, loc))
        {
+         /* Save these values, to assign to the new node, before
+            deleting this one.  */
+         if (node->init > initialized)
+           initialized = node->init;
+         if (node->set_src != NULL && set_src == NULL)
+           set_src = node->set_src;
          pool_free (loc_chain_pool, node);
          *nextp = next;
          break;
@@ -2171,6 +2418,8 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
   /* Add the location to the beginning.  */
   node = pool_alloc (loc_chain_pool);
   node->loc = loc;
+  node->init = initialized;
+  node->set_src = set_src;
   node->next = var->var_part[pos].loc_chain;
   var->var_part[pos].loc_chain = node;
 
@@ -2189,7 +2438,7 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
 
 static void
 clobber_variable_part (dataflow_set *set, rtx loc, tree decl,
-                     HOST_WIDE_INT offset)
+                      HOST_WIDE_INT offset, rtx set_src)
 {
   void **slot;
 
@@ -2212,7 +2461,11 @@ clobber_variable_part (dataflow_set *set, rtx loc, tree decl,
          for (node = next; node; node = next)
            {
              next = node->next;
-             if (node->loc != loc)
+             if (node->loc != loc 
+                 && (!flag_var_tracking_uninit
+                     || !set_src 
+                     || MEM_P (set_src)
+                     || !rtx_equal_p (set_src, node->set_src)))
                {
                  if (REG_P (node->loc))
                    {
@@ -2277,7 +2530,10 @@ delete_variable_part (dataflow_set *set, rtx loc, tree decl,
                       && REGNO (node->loc) == REGNO (loc))
                      || rtx_equal_p (node->loc, loc))
                    {
-                     var = unshare_variable (set, var);
+                     enum var_init_status status = VAR_INIT_STATUS_UNKNOWN;
+                     if (! flag_var_tracking_uninit)
+                       status = VAR_INIT_STATUS_INITIALIZED;
+                     var = unshare_variable (set, var, status);
                      break;
                    }
                }
@@ -2344,6 +2600,7 @@ emit_note_insn_var_location (void **varp, void *data)
   rtx note;
   int i, j, n_var_parts;
   bool complete;
+  enum var_init_status initialized = VAR_INIT_STATUS_UNINITIALIZED;
   HOST_WIDE_INT last_limit;
   tree type_size_unit;
   HOST_WIDE_INT offsets[MAX_VAR_PARTS];
@@ -2351,6 +2608,9 @@ emit_note_insn_var_location (void **varp, void *data)
 
   gcc_assert (var->decl);
 
+  if (! flag_var_tracking_uninit)
+    initialized = VAR_INIT_STATUS_INITIALIZED;
+
   complete = true;
   last_limit = 0;
   n_var_parts = 0;
@@ -2368,6 +2628,7 @@ emit_note_insn_var_location (void **varp, void *data)
       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]);
+      initialized = var->var_part[i].loc_chain->init;
       last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
 
       /* Attempt to merge adjacent registers or memory.  */
@@ -2388,8 +2649,7 @@ emit_note_insn_var_location (void **varp, void *data)
          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]
+             && end_hard_regno (mode, REGNO (loc[n_var_parts]))
                 == REGNO (loc2))
            {
              if (! WORDS_BIG_ENDIAN && ! BYTES_BIG_ENDIAN)
@@ -2443,16 +2703,17 @@ emit_note_insn_var_location (void **varp, void *data)
     complete = false;
 
   if (where == EMIT_NOTE_AFTER_INSN)
-    /* emit_note_after can insert a note after a flow-control insn in a basic
-       block.  That causes verify_flow_info failures.  */
-    note = emit_note_before (NOTE_INSN_VAR_LOCATION, NEXT_INSN (insn));
+    note = emit_note_after (NOTE_INSN_VAR_LOCATION, insn);
   else
     note = emit_note_before (NOTE_INSN_VAR_LOCATION, insn);
 
+  if (! flag_var_tracking_uninit)
+    initialized = VAR_INIT_STATUS_INITIALIZED;
+
   if (!complete)
     {
       NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
-                                                      NULL_RTX);
+                                                      NULL_RTX, (int) initialized);
     }
   else if (n_var_parts == 1)
     {
@@ -2460,7 +2721,8 @@ emit_note_insn_var_location (void **varp, void *data)
        = gen_rtx_EXPR_LIST (VOIDmode, loc[0], GEN_INT (offsets[0]));
 
       NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
-                                                      expr_list);
+                                                      expr_list, 
+                                                      (int) initialized);
     }
   else if (n_var_parts)
     {
@@ -2473,7 +2735,8 @@ emit_note_insn_var_location (void **varp, void *data)
       parallel = gen_rtx_PARALLEL (VOIDmode,
                                   gen_rtvec_v (n_var_parts, loc));
       NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, var->decl,
-                                                      parallel);
+                                                      parallel, 
+                                                      (int) initialized);
     }
 
   htab_clear_slot (changed_variables, varp);
@@ -2604,11 +2867,14 @@ emit_notes_in_bb (basic_block bb)
          case MO_USE:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
-
+      
+             enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED;
+             if (! flag_var_tracking_uninit)
+               status = VAR_INIT_STATUS_INITIALIZED;
              if (GET_CODE (loc) == REG)
-               var_reg_set (&set, loc);
+               var_reg_set (&set, loc, status, NULL);
              else
-               var_mem_set (&set, loc);
+               var_mem_set (&set, loc, status, NULL);
 
              emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
            }
@@ -2617,26 +2883,46 @@ emit_notes_in_bb (basic_block bb)
          case MO_SET:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx set_src =  NULL;
+
+             if (GET_CODE (PATTERN (insn)) == SET)
+               set_src = SET_SRC (PATTERN (insn));
+             else if (GET_CODE (PATTERN (insn)) == PARALLEL
+                      || GET_CODE (PATTERN (insn)) == SEQUENCE)
+               {
+                 int j;
+                 for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
+                   if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET
+                       && SET_DEST (XVECEXP (PATTERN (insn), 0, j)) == loc)
+                     set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, j));
+               }
 
              if (REG_P (loc))
-               var_reg_delete_and_set (&set, loc, true);
+               var_reg_delete_and_set (&set, loc, true, VAR_INIT_STATUS_INITIALIZED, 
+                                       set_src);
              else
-               var_mem_delete_and_set (&set, loc, true);
+               var_mem_delete_and_set (&set, loc, true, VAR_INIT_STATUS_INITIALIZED, 
+                                       set_src);
 
-             emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
+             emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN);
            }
            break;
 
          case MO_COPY:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
+             enum var_init_status src_status;
+             rtx set_src;
+
+             src_status = find_src_status (&set, loc, VTI (bb)->mos[i].insn);
+             set_src = find_src_set_src (&set, loc, VTI (bb)->mos[i].insn);
 
              if (REG_P (loc))
-               var_reg_delete_and_set (&set, loc, false);
+               var_reg_delete_and_set (&set, loc, false, src_status, set_src);
              else
-               var_mem_delete_and_set (&set, loc, false);
+               var_mem_delete_and_set (&set, loc, false, src_status, set_src);
 
-             emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
+             emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN);
            }
            break;
 
@@ -2662,7 +2948,7 @@ emit_notes_in_bb (basic_block bb)
              else
                var_mem_delete (&set, loc, true);
 
-             emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
+             emit_notes_for_changes (NEXT_INSN (insn), EMIT_NOTE_BEFORE_INSN);
            }
            break;
 
@@ -2778,10 +3064,12 @@ vt_add_function_parameters (void)
          gcc_assert (REGNO (incoming) < FIRST_PSEUDO_REGISTER);
          attrs_list_insert (&out->regs[REGNO (incoming)],
                             parm, offset, incoming);
-         set_variable_part (out, incoming, parm, offset);
+         set_variable_part (out, incoming, parm, offset, VAR_INIT_STATUS_INITIALIZED, 
+                            NULL);
        }
       else if (MEM_P (incoming))
-       set_variable_part (out, incoming, parm, offset);
+       set_variable_part (out, incoming, parm, offset, VAR_INIT_STATUS_INITIALIZED, 
+                          NULL);
     }
 }
 
@@ -3008,7 +3296,7 @@ struct tree_opt_pass pass_variable_tracking =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_dump_func,                       /* todo_flags_finish */
+  TODO_dump_func | TODO_verify_rtl_sharing,/* todo_flags_finish */
   'V'                                   /* letter */
 };