OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / var-tracking.c
index 815faca..ab4d93c 100644 (file)
@@ -1,11 +1,11 @@
 /* Variable tracking routines for the GNU compiler.
 /* 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
 
    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
    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
    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
 
 /* This file contains the variable tracking pass.  It computes where
    variables are located (which registers or where in memory) at each position
@@ -135,7 +134,9 @@ typedef struct micro_operation_def
   enum micro_operation_type type;
 
   union {
   enum micro_operation_type type;
 
   union {
-    /* Location.  */
+    /* Location.  For MO_SET and MO_COPY, this is the SET that performs
+       the assignment, if known, otherwise it is the target of the
+       assignment.  */
     rtx loc;
 
     /* Stack adjustment.  */
     rtx loc;
 
     /* Stack adjustment.  */
@@ -219,6 +220,12 @@ typedef struct location_chain_def
 
   /* The location (REG or MEM).  */
   rtx loc;
 
   /* 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.  */
 } *location_chain;
 
 /* Structure describing one part of variable.  */
@@ -252,6 +259,7 @@ typedef struct variable_def
   /* The variable parts.  */
   variable_part var_part[MAX_VAR_PARTS];
 } *variable;
   /* 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))
 
 /* Hash function for DECL for VARIABLE_HTAB.  */
 #define VARIABLE_HASH_VAL(decl) (DECL_UID (decl))
@@ -259,6 +267,9 @@ typedef struct variable_def
 /* Pointer to the BB's information specific to variable tracking pass.  */
 #define VTI(BB) ((variable_tracking_info) (BB)->aux)
 
 /* Pointer to the BB's information specific to variable tracking pass.  */
 #define VTI(BB) ((variable_tracking_info) (BB)->aux)
 
+/* Macro to access MEM_OFFSET as an HOST_WIDE_INT.  Evaluates MEM twice.  */
+#define INT_MEM_OFFSET(mem) (MEM_OFFSET (mem) ? INTVAL (MEM_OFFSET (mem)) : 0)
+
 /* Alloc pool for struct attrs_def.  */
 static alloc_pool attrs_pool;
 
 /* Alloc pool for struct attrs_def.  */
 static alloc_pool attrs_pool;
 
@@ -294,16 +305,19 @@ static void attrs_list_copy (attrs *, attrs);
 static void attrs_list_union (attrs *, attrs);
 
 static void vars_clear (htab_t);
 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 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_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);
 static void var_mem_delete (dataflow_set *, rtx, bool);
 
 static void dataflow_set_init (dataflow_set *, int);
@@ -324,10 +338,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 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 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);
 
 static bool compute_bb_dataflow (basic_block);
 static void vt_find_locations (void);
 
@@ -338,8 +352,10 @@ static void dump_dataflow_set (dataflow_set *);
 static void dump_dataflow_sets (void);
 
 static void variable_was_changed (variable, htab_t);
 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);
 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 +606,7 @@ adjust_stack_reference (rtx mem, HOST_WIDE_INT adjustment)
 static hashval_t
 variable_htab_hash (const void *x)
 {
 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));
 }
 
   return (VARIABLE_HASH_VAL (v->decl));
 }
@@ -600,8 +616,8 @@ variable_htab_hash (const void *x)
 static int
 variable_htab_eq (const void *x, const void *y)
 {
 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));
 }
 
   return (VARIABLE_HASH_VAL (v->decl) == VARIABLE_HASH_VAL (decl));
 }
@@ -677,7 +693,7 @@ attrs_list_insert (attrs *listp, tree decl, HOST_WIDE_INT offset, rtx loc)
 {
   attrs list;
 
 {
   attrs list;
 
-  list = pool_alloc (attrs_pool);
+  list = (attrs) pool_alloc (attrs_pool);
   list->loc = loc;
   list->decl = decl;
   list->offset = offset;
   list->loc = loc;
   list->decl = decl;
   list->offset = offset;
@@ -695,7 +711,7 @@ attrs_list_copy (attrs *dstp, attrs src)
   attrs_list_clear (dstp);
   for (; src; src = src->next)
     {
   attrs_list_clear (dstp);
   for (; src; src = src->next)
     {
-      n = pool_alloc (attrs_pool);
+      n = (attrs) pool_alloc (attrs_pool);
       n->loc = src->loc;
       n->decl = src->decl;
       n->offset = src->offset;
       n->loc = src->loc;
       n->decl = src->decl;
       n->offset = src->offset;
@@ -727,13 +743,14 @@ vars_clear (htab_t vars)
 /* Return a copy of a variable VAR and insert it to dataflow set SET.  */
 
 static variable
 /* 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;
   int i;
 
 {
   void **slot;
   variable new_var;
   int i;
 
-  new_var = pool_alloc (var_pool);
+  new_var = (variable) pool_alloc (var_pool);
   new_var->decl = var->decl;
   new_var->refcount = 1;
   var->refcount--;
   new_var->decl = var->decl;
   new_var->refcount = 1;
   var->refcount--;
@@ -750,8 +767,16 @@ unshare_variable (dataflow_set *set, variable var)
        {
          location_chain new_lc;
 
        {
          location_chain new_lc;
 
-         new_lc = pool_alloc (loc_chain_pool);
+         new_lc = (location_chain) pool_alloc (loc_chain_pool);
          new_lc->next = NULL;
          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;
          new_lc->loc = node->loc;
 
          *nextp = new_lc;
@@ -819,7 +844,8 @@ var_debug_decl (tree decl)
 /* Set the register to contain REG_EXPR (LOC), REG_OFFSET (LOC).  */
 
 static void
 /* 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);
 {
   tree decl = REG_EXPR (loc);
   HOST_WIDE_INT offset = REG_OFFSET (loc);
@@ -832,7 +858,38 @@ var_reg_set (dataflow_set *set, rtx loc)
       break;
   if (!node)
     attrs_list_insert (&set->regs[REGNO (loc)], decl, offset, 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
 }
 
 /* Delete current content of register LOC in dataflow set SET and set
@@ -843,7 +900,8 @@ var_reg_set (dataflow_set *set, rtx loc)
    part.  */
 
 static void
    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);
 {
   tree decl = REG_EXPR (loc);
   HOST_WIDE_INT offset = REG_OFFSET (loc);
@@ -852,6 +910,9 @@ var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify)
 
   decl = var_debug_decl (decl);
 
 
   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)
     {
   nextp = &set->regs[REGNO (loc)];
   for (node = *nextp; node; node = next)
     {
@@ -869,8 +930,8 @@ var_reg_delete_and_set (dataflow_set *set, rtx loc, bool modify)
        }
     }
   if (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
 }
 
 /* Delete current content of register LOC in dataflow set SET.  If
@@ -890,7 +951,7 @@ var_reg_delete (dataflow_set *set, rtx loc, bool clobber)
 
       decl = var_debug_decl (decl);
 
 
       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)
     }
 
   for (node = *reg; node; node = next)
@@ -924,14 +985,15 @@ var_regno_delete (dataflow_set *set, int regno)
    Adjust the address first if it is stack pointer based.  */
 
 static void
    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);
 {
   tree decl = MEM_EXPR (loc);
-  HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
+  HOST_WIDE_INT offset = INT_MEM_OFFSET (loc);
 
   decl = var_debug_decl (decl);
 
 
   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
 }
 
 /* Delete and set the location part of variable MEM_EXPR (LOC) in
@@ -942,16 +1004,20 @@ var_mem_set (dataflow_set *set, rtx loc)
    Adjust the address first if it is stack pointer based.  */
 
 static void
    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);
 {
   tree decl = MEM_EXPR (loc);
-  HOST_WIDE_INT offset = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
+  HOST_WIDE_INT offset = INT_MEM_OFFSET (loc);
 
   decl = var_debug_decl (decl);
 
 
   decl = var_debug_decl (decl);
 
+  if (initialized == VAR_INIT_STATUS_UNKNOWN)
+    initialized = get_init_value (set, loc, decl);
+
   if (modify)
   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
 }
 
 /* Delete the location part LOC from dataflow set SET.  If CLOBBER is
@@ -962,11 +1028,11 @@ static void
 var_mem_delete (dataflow_set *set, rtx loc, bool clobber)
 {
   tree decl = MEM_EXPR (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;
+  HOST_WIDE_INT offset = INT_MEM_OFFSET (loc);
 
   decl = var_debug_decl (decl);
   if (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);
 }
 
   delete_variable_part (set, loc, decl, offset);
 }
 
@@ -1029,8 +1095,10 @@ struct variable_union_info
 static int
 variable_union_info_cmp_pos (const void *n1, const void *n2)
 {
 static int
 variable_union_info_cmp_pos (const void *n1, const void *n2)
 {
-  const struct variable_union_info *i1 = n1;
-  const struct variable_union_info *i2 = n2;
+  const struct variable_union_info *const i1 =
+    (const struct variable_union_info *) n1;
+  const struct variable_union_info *const i2 =
+    ( const struct variable_union_info *) n2;
 
   if (i1->pos != i2->pos)
     return i1->pos - i2->pos;
 
   if (i1->pos != i2->pos)
     return i1->pos - i2->pos;
@@ -1078,7 +1146,14 @@ variable_union (void **slot, void *data)
            }
        }
       if (k < src->n_var_parts)
            }
        }
       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;
 
       else
        *dstp = src;
 
@@ -1112,7 +1187,13 @@ variable_union (void **slot, void *data)
   gcc_assert (k <= MAX_VAR_PARTS);
 
   if (dst->refcount > 1 && dst->n_var_parts != k)
   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;
 
   i = src->n_var_parts - 1;
   j = dst->n_var_parts - 1;
@@ -1145,10 +1226,14 @@ variable_union (void **slot, void *data)
                         && REG_P (node->loc)
                         && REGNO (node2->loc) == REGNO (node->loc))
                        || rtx_equal_p (node2->loc, node->loc)))
                         && REG_P (node->loc)
                         && REGNO (node2->loc) == REGNO (node->loc))
                        || rtx_equal_p (node2->loc, node->loc)))
-                   break;
+                   {
+                     if (node2->init < node->init)
+                       node2->init = node->init;
+                     break;
+                   }
                }
              if (node || node2)
                }
              if (node || node2)
-               dst = unshare_variable (set, dst);
+               dst = unshare_variable (set, dst, VAR_INIT_STATUS_UNKNOWN);
            }
 
          src_l = 0;
            }
 
          src_l = 0;
@@ -1192,8 +1277,13 @@ variable_union (void **slot, void *data)
                  location_chain new_node;
 
                  /* Copy the location from SRC.  */
                  location_chain new_node;
 
                  /* Copy the location from SRC.  */
-                 new_node = pool_alloc (loc_chain_pool);
+                 new_node = (location_chain) pool_alloc (loc_chain_pool);
                  new_node->loc = node->loc;
                  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;
                  vui[n].lc = new_node;
                  vui[n].pos_src = ii;
                  vui[n].pos_dst = src_l + dst_l;
@@ -1238,8 +1328,13 @@ variable_union (void **slot, void *data)
            {
              location_chain new_lc;
 
            {
              location_chain new_lc;
 
-             new_lc = pool_alloc (loc_chain_pool);
+             new_lc = (location_chain) pool_alloc (loc_chain_pool);
              new_lc->next = NULL;
              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;
              new_lc->loc = node->loc;
 
              *nextp = new_lc;
@@ -1258,6 +1353,18 @@ variable_union (void **slot, void *data)
        dst->var_part[k].cur_loc = NULL;
     }
 
        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;
 }
   /* Continue traversing the hash table.  */
   return 1;
 }
@@ -1350,7 +1457,7 @@ dataflow_set_different_1 (void **slot, void *data)
   variable var1, var2;
 
   var1 = *(variable *) slot;
   variable var1, var2;
 
   var1 = *(variable *) slot;
-  var2 = htab_find_with_hash (htab, var1->decl,
+  var2 = (variable) htab_find_with_hash (htab, var1->decl,
                              VARIABLE_HASH_VAL (var1->decl));
   if (!var2)
     {
                              VARIABLE_HASH_VAL (var1->decl));
   if (!var2)
     {
@@ -1382,7 +1489,7 @@ dataflow_set_different_2 (void **slot, void *data)
   variable var1, var2;
 
   var1 = *(variable *) slot;
   variable var1, var2;
 
   var1 = *(variable *) slot;
-  var2 = htab_find_with_hash (htab, var1->decl,
+  var2 = (variable) htab_find_with_hash (htab, var1->decl,
                              VARIABLE_HASH_VAL (var1->decl));
   if (!var2)
     {
                              VARIABLE_HASH_VAL (var1->decl));
   if (!var2)
     {
@@ -1529,7 +1636,8 @@ track_expr_p (tree expr)
   if (MEM_P (decl_rtl))
     {
       /* Do not track structures and arrays.  */
   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)
        return 0;
       if (MEM_SIZE (decl_rtl)
          && INTVAL (MEM_SIZE (decl_rtl)) > MAX_VAR_PARTS)
@@ -1559,7 +1667,7 @@ same_variable_part_p (rtx loc, tree expr, HOST_WIDE_INT offset)
   else if (MEM_P (loc))
     {
       expr2 = MEM_EXPR (loc);
   else if (MEM_P (loc))
     {
       expr2 = MEM_EXPR (loc);
-      offset2 = MEM_OFFSET (loc) ? INTVAL (MEM_OFFSET (loc)) : 0;
+      offset2 = INT_MEM_OFFSET (loc);
     }
   else
     return false;
     }
   else
     return false;
@@ -1573,6 +1681,92 @@ same_variable_part_p (rtx loc, tree expr, HOST_WIDE_INT offset)
   return (expr == expr2 && offset == offset2);
 }
 
   return (expr == expr2 && offset == offset2);
 }
 
+/* LOC is a REG or MEM that we would like to track if possible.
+   If EXPR is null, we don't know what expression LOC refers to,
+   otherwise it refers to EXPR + OFFSET.  STORE_REG_P is true if
+   LOC is an lvalue register.
+
+   Return true if EXPR is nonnull and if LOC, or some lowpart of it,
+   is something we can track.  When returning true, store the mode of
+   the lowpart we can track in *MODE_OUT (if nonnull) and its offset
+   from EXPR in *OFFSET_OUT (if nonnull).  */
+
+static bool
+track_loc_p (rtx loc, tree expr, HOST_WIDE_INT offset, bool store_reg_p,
+            enum machine_mode *mode_out, HOST_WIDE_INT *offset_out)
+{
+  enum machine_mode mode;
+
+  if (expr == NULL || !track_expr_p (expr))
+    return false;
+
+  /* If REG was a paradoxical subreg, its REG_ATTRS will describe the
+     whole subreg, but only the old inner part is really relevant.  */
+  mode = GET_MODE (loc);
+  if (REG_P (loc) && !HARD_REGISTER_NUM_P (ORIGINAL_REGNO (loc)))
+    {
+      enum machine_mode pseudo_mode;
+
+      pseudo_mode = PSEUDO_REGNO_MODE (ORIGINAL_REGNO (loc));
+      if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (pseudo_mode))
+       {
+         offset += byte_lowpart_offset (pseudo_mode, mode);
+         mode = pseudo_mode;
+       }
+    }
+
+  /* If LOC is a paradoxical lowpart of EXPR, refer to EXPR itself.
+     Do the same if we are storing to a register and EXPR occupies
+     the whole of register LOC; in that case, the whole of EXPR is
+     being changed.  We exclude complex modes from the second case
+     because the real and imaginary parts are represented as separate
+     pseudo registers, even if the whole complex value fits into one
+     hard register.  */
+  if ((GET_MODE_SIZE (mode) > GET_MODE_SIZE (DECL_MODE (expr))
+       || (store_reg_p
+          && !COMPLEX_MODE_P (DECL_MODE (expr))
+          && hard_regno_nregs[REGNO (loc)][DECL_MODE (expr)] == 1))
+      && offset + byte_lowpart_offset (DECL_MODE (expr), mode) == 0)
+    {
+      mode = DECL_MODE (expr);
+      offset = 0;
+    }
+
+  if (offset < 0 || offset >= MAX_VAR_PARTS)
+    return false;
+
+  if (mode_out)
+    *mode_out = mode;
+  if (offset_out)
+    *offset_out = offset;
+  return true;
+}
+
+/* Return the MODE lowpart of LOC, or null if LOC is not something we
+   want to track.  When returning nonnull, make sure that the attributes
+   on the returned value are updated.  */
+
+static rtx
+var_lowpart (enum machine_mode mode, rtx loc)
+{
+  unsigned int offset, reg_offset, regno;
+
+  if (!REG_P (loc) && !MEM_P (loc))
+    return NULL;
+
+  if (GET_MODE (loc) == mode)
+    return loc;
+
+  offset = byte_lowpart_offset (mode, GET_MODE (loc));
+
+  if (MEM_P (loc))
+    return adjust_address_nv (loc, mode, offset);
+
+  reg_offset = subreg_lowpart_offset (mode, GET_MODE (loc));
+  regno = REGNO (loc) + subreg_regno_offset (REGNO (loc), GET_MODE (loc),
+                                            reg_offset, mode);
+  return gen_rtx_REG_offset (loc, mode, regno, offset);
+}
 
 /* Count uses (register and memory references) LOC which will be tracked.
    INSN is instruction which the LOC is part of.  */
 
 /* Count uses (register and memory references) LOC which will be tracked.
    INSN is instruction which the LOC is part of.  */
@@ -1588,8 +1782,8 @@ count_uses (rtx *loc, void *insn)
       VTI (bb)->n_mos++;
     }
   else if (MEM_P (*loc)
       VTI (bb)->n_mos++;
     }
   else if (MEM_P (*loc)
-          && MEM_EXPR (*loc)
-          && track_expr_p (MEM_EXPR (*loc)))
+          && track_loc_p (*loc, MEM_EXPR (*loc), INT_MEM_OFFSET (*loc),
+                          false, NULL, NULL))
     {
       VTI (bb)->n_mos++;
     }
     {
       VTI (bb)->n_mos++;
     }
@@ -1609,7 +1803,7 @@ count_uses_1 (rtx *x, void *insn)
    INSN is instruction which the LOC is part of.  */
 
 static void
    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);
 }
 {
   count_uses (&loc, insn);
 }
@@ -1620,25 +1814,35 @@ count_stores (rtx loc, rtx expr ATTRIBUTE_UNUSED, void *insn)
 static int
 add_uses (rtx *loc, void *insn)
 {
 static int
 add_uses (rtx *loc, void *insn)
 {
+  enum machine_mode mode;
+
   if (REG_P (*loc))
     {
       basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
       micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
 
   if (REG_P (*loc))
     {
       basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
       micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
 
-      mo->type = ((REG_EXPR (*loc) && track_expr_p (REG_EXPR (*loc)))
-                 ? MO_USE : MO_USE_NO_VAR);
-      mo->u.loc = *loc;
+      if (track_loc_p (*loc, REG_EXPR (*loc), REG_OFFSET (*loc),
+                      false, &mode, NULL))
+       {
+         mo->type = MO_USE;
+         mo->u.loc = var_lowpart (mode, *loc);
+       }
+      else
+       {
+         mo->type = MO_USE_NO_VAR;
+         mo->u.loc = *loc;
+       }
       mo->insn = (rtx) insn;
     }
   else if (MEM_P (*loc)
       mo->insn = (rtx) insn;
     }
   else if (MEM_P (*loc)
-          && MEM_EXPR (*loc)
-          && track_expr_p (MEM_EXPR (*loc)))
+          && track_loc_p (*loc, MEM_EXPR (*loc), INT_MEM_OFFSET (*loc),
+                          false, &mode, NULL))
     {
       basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
       micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
 
       mo->type = MO_USE;
     {
       basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
       micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
 
       mo->type = MO_USE;
-      mo->u.loc = *loc;
+      mo->u.loc = var_lowpart (mode, *loc);
       mo->insn = (rtx) insn;
     }
 
       mo->insn = (rtx) insn;
     }
 
@@ -1658,51 +1862,154 @@ add_uses_1 (rtx *x, void *insn)
    INSN is instruction which the LOC is part of.  */
 
 static void
    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)
 {
 {
+  enum machine_mode mode;
+
   if (REG_P (loc))
     {
       basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
       micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
 
       if (GET_CODE (expr) == CLOBBER
   if (REG_P (loc))
     {
       basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
       micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
 
       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;
+         || !track_loc_p (loc, REG_EXPR (loc), REG_OFFSET (loc),
+                          true, &mode, NULL))
+       {
+         mo->type = MO_CLOBBER;
+         mo->u.loc = loc;
+       }
       else
       else
-       mo->type = MO_SET;
-      mo->u.loc = loc;
-      mo->insn = NEXT_INSN ((rtx) insn);
+       {
+         rtx src = NULL;
+
+         if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
+           src = var_lowpart (mode, SET_SRC (expr));
+         loc = var_lowpart (mode, loc);
+
+         if (src == NULL)
+           {
+             mo->type = MO_SET;
+             mo->u.loc = loc;
+           }
+         else
+           {
+             if (SET_SRC (expr) != src)
+               expr = gen_rtx_SET (VOIDmode, loc, src);
+             if (same_variable_part_p (src, REG_EXPR (loc), REG_OFFSET (loc)))
+               mo->type = MO_COPY;
+             else
+               mo->type = MO_SET;
+             mo->u.loc = CONST_CAST_RTX (expr);
+           }
+       }
+      mo->insn = (rtx) insn;
     }
   else if (MEM_P (loc)
     }
   else if (MEM_P (loc)
-          && MEM_EXPR (loc)
-          && track_expr_p (MEM_EXPR (loc)))
+          && track_loc_p (loc, MEM_EXPR (loc), INT_MEM_OFFSET (loc),
+                          false, &mode, NULL))
     {
       basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
       micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
 
       if (GET_CODE (expr) == CLOBBER)
     {
       basic_block bb = BLOCK_FOR_INSN ((rtx) insn);
       micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++;
 
       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;
+       {
+         mo->type = MO_CLOBBER;
+         mo->u.loc = var_lowpart (mode, loc);
+       }
       else
       else
-       mo->type = MO_SET;
-      mo->u.loc = loc;
-      mo->insn = NEXT_INSN ((rtx) insn);
+       {
+         rtx src = NULL;
+
+         if (GET_CODE (expr) == SET && SET_DEST (expr) == loc)
+           src = var_lowpart (mode, SET_SRC (expr));
+         loc = var_lowpart (mode, loc);
+
+         if (src == NULL)
+           {
+             mo->type = MO_SET;
+             mo->u.loc = loc;
+           }
+         else
+           {
+             if (SET_SRC (expr) != src)
+               expr = gen_rtx_SET (VOIDmode, loc, src);
+             if (same_variable_part_p (SET_SRC (expr),
+                                       MEM_EXPR (loc),
+                                       INT_MEM_OFFSET (loc)))
+               mo->type = MO_COPY;
+             else
+               mo->type = MO_SET;
+             mo->u.loc = CONST_CAST_RTX (expr);
+           }
+       }
+      mo->insn = (rtx) insn;
     }
 }
 
     }
 }
 
+static enum var_init_status
+find_src_status (dataflow_set *in, rtx src)
+{
+  tree decl = NULL_TREE;
+  enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED;
+
+  if (! flag_var_tracking_uninit)
+    status = VAR_INIT_STATUS_INITIALIZED;
+
+  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;
+}
+
+/* SRC is the source of an assignment.  Use SET to try to find what
+   was ultimately assigned to SRC.  Return that value if known,
+   otherwise return SRC itself.  */
+
+static rtx
+find_src_set_src (dataflow_set *set, rtx src)
+{
+  tree decl = NULL_TREE;   /* The variable being copied around.          */
+  rtx set_src = NULL_RTX;  /* The value for "decl" stored in "src".      */
+  void **slot;
+  variable var;
+  location_chain nextp;
+  int i;
+  bool found;
+
+  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
 /* Compute the changes of variable locations in the basic block BB.  */
 
 static bool
@@ -1732,33 +2039,64 @@ compute_bb_dataflow (basic_block bb)
          case MO_USE:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
          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)
 
              if (GET_CODE (loc) == REG)
-               var_reg_set (out, loc);
+               var_reg_set (out, loc, status, NULL);
              else if (GET_CODE (loc) == MEM)
              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;
            }
            break;
 
          case MO_SET:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx set_src = NULL;
+
+             if (GET_CODE (loc) == SET)
+               {
+                 set_src = SET_SRC (loc);
+                 loc = SET_DEST (loc);
+               }
 
              if (REG_P (loc))
 
              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))
              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;
            }
            break;
 
          case MO_COPY:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
+             enum var_init_status src_status;
+             rtx set_src = NULL;
+
+             if (GET_CODE (loc) == SET)
+               {
+                 set_src = SET_SRC (loc);
+                 loc = SET_DEST (loc);
+               }
+
+             if (! flag_var_tracking_uninit)
+               src_status = VAR_INIT_STATUS_INITIALIZED;
+             else
+               src_status = find_src_status (in, set_src);
+
+             if (src_status == VAR_INIT_STATUS_UNKNOWN)
+               src_status = find_src_status (out, set_src);
+
+             set_src = find_src_set_src (in, set_src);
 
              if (REG_P (loc))
 
              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))
              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;
 
            }
            break;
 
@@ -1841,7 +2179,7 @@ vt_find_locations (void)
 
       while (!fibheap_empty (worklist))
        {
 
       while (!fibheap_empty (worklist))
        {
-         bb = fibheap_extract_min (worklist);
+         bb = (basic_block) fibheap_extract_min (worklist);
          RESET_BIT (in_worklist, bb->index);
          if (!TEST_BIT (visited, bb->index))
            {
          RESET_BIT (in_worklist, bb->index);
          if (!TEST_BIT (visited, bb->index))
            {
@@ -1922,8 +2260,13 @@ dump_variable (void **slot, void *data ATTRIBUTE_UNUSED)
   int i;
   location_chain node;
 
   int i;
   location_chain node;
 
-  fprintf (dump_file, "  name: %s\n",
+  fprintf (dump_file, "  name: %s",
           IDENTIFIER_POINTER (DECL_NAME (var->decl)));
           IDENTIFIER_POINTER (DECL_NAME (var->decl)));
+  if (dump_flags & TDF_UID)
+    fprintf (dump_file, " D.%u\n", DECL_UID (var->decl));
+  else
+    fprintf (dump_file, "\n");
+
   for (i = 0; i < var->n_var_parts; i++)
     {
       fprintf (dump_file, "    offset %ld\n",
   for (i = 0; i < var->n_var_parts; i++)
     {
       fprintf (dump_file, "    offset %ld\n",
@@ -1931,6 +2274,8 @@ dump_variable (void **slot, void *data ATTRIBUTE_UNUSED)
       for (node = var->var_part[i].loc_chain; node; node = node->next)
        {
          fprintf (dump_file, "      ");
       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);
        }
     }
          print_rtl_single (dump_file, node->loc);
        }
     }
@@ -2009,7 +2354,7 @@ variable_was_changed (variable var, htab_t htab)
          variable empty_var;
          void **old;
 
          variable empty_var;
          void **old;
 
-         empty_var = pool_alloc (var_pool);
+         empty_var = (variable) pool_alloc (var_pool);
          empty_var->decl = var->decl;
          empty_var->refcount = 1;
          empty_var->n_var_parts = 0;
          empty_var->decl = var->decl;
          empty_var->refcount = 1;
          empty_var->n_var_parts = 0;
@@ -2076,7 +2421,8 @@ find_variable_location_part (variable var, HOST_WIDE_INT offset,
    part's location by LOC.  */
 
 static void
    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;
 {
   int pos;
   location_chain node, next;
@@ -2089,7 +2435,7 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
   if (!*slot)
     {
       /* Create new variable information.  */
   if (!*slot)
     {
       /* Create new variable information.  */
-      var = pool_alloc (var_pool);
+      var = (variable) pool_alloc (var_pool);
       var->decl = decl;
       var->refcount = 1;
       var->n_var_parts = 1;
       var->decl = decl;
       var->refcount = 1;
       var->n_var_parts = 1;
@@ -2118,13 +2464,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.  */
            {
              /* 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)
              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
            }
        }
       else
@@ -2133,7 +2485,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)
 
          /* 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.  */
 
          /* We track only variables whose size is <= MAX_VAR_PARTS bytes
             thus there are at most MAX_VAR_PARTS different offsets.  */
@@ -2160,6 +2512,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))
        {
           && 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;
          pool_free (loc_chain_pool, node);
          *nextp = next;
          break;
@@ -2169,8 +2527,10 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset)
     }
 
   /* Add the location to the beginning.  */
     }
 
   /* Add the location to the beginning.  */
-  node = pool_alloc (loc_chain_pool);
+  node = (location_chain) pool_alloc (loc_chain_pool);
   node->loc = loc;
   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;
 
   node->next = var->var_part[pos].loc_chain;
   var->var_part[pos].loc_chain = node;
 
@@ -2189,7 +2549,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,
 
 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;
 
 {
   void **slot;
 
@@ -2212,7 +2572,11 @@ clobber_variable_part (dataflow_set *set, rtx loc, tree decl,
          for (node = next; node; node = next)
            {
              next = node->next;
          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))
                    {
                {
                  if (REG_P (node->loc))
                    {
@@ -2233,6 +2597,8 @@ clobber_variable_part (dataflow_set *set, rtx loc, tree decl,
                              pool_free (attrs_pool, anode);
                              *anextp = anext;
                            }
                              pool_free (attrs_pool, anode);
                              *anextp = anext;
                            }
+                         else
+                           anextp = &anode->next;
                        }
                    }
 
                        }
                    }
 
@@ -2277,7 +2643,10 @@ delete_variable_part (dataflow_set *set, rtx loc, tree decl,
                       && REGNO (node->loc) == REGNO (loc))
                      || rtx_equal_p (node->loc, loc))
                    {
                       && 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;
                    }
                }
                      break;
                    }
                }
@@ -2344,6 +2713,7 @@ emit_note_insn_var_location (void **varp, void *data)
   rtx note;
   int i, j, n_var_parts;
   bool complete;
   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];
   HOST_WIDE_INT last_limit;
   tree type_size_unit;
   HOST_WIDE_INT offsets[MAX_VAR_PARTS];
@@ -2351,6 +2721,9 @@ emit_note_insn_var_location (void **varp, void *data)
 
   gcc_assert (var->decl);
 
 
   gcc_assert (var->decl);
 
+  if (! flag_var_tracking_uninit)
+    initialized = VAR_INIT_STATUS_INITIALIZED;
+
   complete = true;
   last_limit = 0;
   n_var_parts = 0;
   complete = true;
   last_limit = 0;
   n_var_parts = 0;
@@ -2368,6 +2741,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]);
       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.  */
       last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
 
       /* Attempt to merge adjacent registers or memory.  */
@@ -2388,8 +2762,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]
          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)
                 == REGNO (loc2))
            {
              if (! WORDS_BIG_ENDIAN && ! BYTES_BIG_ENDIAN)
@@ -2447,10 +2820,13 @@ emit_note_insn_var_location (void **varp, void *data)
   else
     note = emit_note_before (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,
   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)
     {
     }
   else if (n_var_parts == 1)
     {
@@ -2458,7 +2834,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,
        = 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)
     {
     }
   else if (n_var_parts)
     {
@@ -2471,7 +2848,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 = 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);
     }
 
   htab_clear_slot (changed_variables, varp);
@@ -2512,7 +2890,7 @@ emit_notes_for_differences_1 (void **slot, void *data)
   variable old_var, new_var;
 
   old_var = *(variable *) slot;
   variable old_var, new_var;
 
   old_var = *(variable *) slot;
-  new_var = htab_find_with_hash (new_vars, old_var->decl,
+  new_var = (variable) htab_find_with_hash (new_vars, old_var->decl,
                                 VARIABLE_HASH_VAL (old_var->decl));
 
   if (!new_var)
                                 VARIABLE_HASH_VAL (old_var->decl));
 
   if (!new_var)
@@ -2520,7 +2898,7 @@ emit_notes_for_differences_1 (void **slot, void *data)
       /* Variable has disappeared.  */
       variable empty_var;
 
       /* Variable has disappeared.  */
       variable empty_var;
 
-      empty_var = pool_alloc (var_pool);
+      empty_var = (variable) pool_alloc (var_pool);
       empty_var->decl = old_var->decl;
       empty_var->refcount = 1;
       empty_var->n_var_parts = 0;
       empty_var->decl = old_var->decl;
       empty_var->refcount = 1;
       empty_var->n_var_parts = 0;
@@ -2545,7 +2923,7 @@ emit_notes_for_differences_2 (void **slot, void *data)
   variable old_var, new_var;
 
   new_var = *(variable *) slot;
   variable old_var, new_var;
 
   new_var = *(variable *) slot;
-  old_var = htab_find_with_hash (old_vars, new_var->decl,
+  old_var = (variable) htab_find_with_hash (old_vars, new_var->decl,
                                 VARIABLE_HASH_VAL (new_var->decl));
   if (!old_var)
     {
                                 VARIABLE_HASH_VAL (new_var->decl));
   if (!old_var)
     {
@@ -2602,11 +2980,14 @@ emit_notes_in_bb (basic_block bb)
          case MO_USE:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
          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)
              if (GET_CODE (loc) == REG)
-               var_reg_set (&set, loc);
+               var_reg_set (&set, loc, status, NULL);
              else
              else
-               var_mem_set (&set, loc);
+               var_mem_set (&set, loc, status, NULL);
 
              emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
            }
 
              emit_notes_for_changes (insn, EMIT_NOTE_AFTER_INSN);
            }
@@ -2615,26 +2996,46 @@ emit_notes_in_bb (basic_block bb)
          case MO_SET:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
          case MO_SET:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
+             rtx set_src = NULL;
+
+             if (GET_CODE (loc) == SET)
+               {
+                 set_src = SET_SRC (loc);
+                 loc = SET_DEST (loc);
+               }
 
              if (REG_P (loc))
 
              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
              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;
            }
            break;
 
          case MO_COPY:
            {
              rtx loc = VTI (bb)->mos[i].u.loc;
+             enum var_init_status src_status;
+             rtx set_src = NULL;
+
+             if (GET_CODE (loc) == SET)
+               {
+                 set_src = SET_SRC (loc);
+                 loc = SET_DEST (loc);
+               }
+
+             src_status = find_src_status (&set, set_src);
+             set_src = find_src_set_src (&set, set_src);
 
              if (REG_P (loc))
 
              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
              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;
 
            }
            break;
 
@@ -2660,7 +3061,7 @@ emit_notes_in_bb (basic_block bb)
              else
                var_mem_delete (&set, loc, true);
 
              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;
 
            }
            break;
 
@@ -2725,7 +3126,7 @@ vt_get_decl_and_offset (rtx rtl, tree *declp, HOST_WIDE_INT *offsetp)
       if (MEM_ATTRS (rtl))
        {
          *declp = MEM_EXPR (rtl);
       if (MEM_ATTRS (rtl))
        {
          *declp = MEM_EXPR (rtl);
-         *offsetp = MEM_OFFSET (rtl) ? INTVAL (MEM_OFFSET (rtl)) : 0;
+         *offsetp = INT_MEM_OFFSET (rtl);
          return true;
        }
     }
          return true;
        }
     }
@@ -2745,6 +3146,7 @@ vt_add_function_parameters (void)
       rtx decl_rtl = DECL_RTL_IF_SET (parm);
       rtx incoming = DECL_INCOMING_RTL (parm);
       tree decl;
       rtx decl_rtl = DECL_RTL_IF_SET (parm);
       rtx incoming = DECL_INCOMING_RTL (parm);
       tree decl;
+      enum machine_mode mode;
       HOST_WIDE_INT offset;
       dataflow_set *out;
 
       HOST_WIDE_INT offset;
       dataflow_set *out;
 
@@ -2761,25 +3163,38 @@ vt_add_function_parameters (void)
        continue;
 
       if (!vt_get_decl_and_offset (incoming, &decl, &offset))
        continue;
 
       if (!vt_get_decl_and_offset (incoming, &decl, &offset))
-       if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset))
-         continue;
+       {
+         if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset))
+           continue;
+         offset += byte_lowpart_offset (GET_MODE (incoming),
+                                        GET_MODE (decl_rtl));
+       }
 
       if (!decl)
        continue;
 
       gcc_assert (parm == decl);
 
 
       if (!decl)
        continue;
 
       gcc_assert (parm == decl);
 
+      if (!track_loc_p (incoming, parm, offset, false, &mode, &offset))
+       continue;
+
       out = &VTI (ENTRY_BLOCK_PTR)->out;
 
       if (REG_P (incoming))
        {
       out = &VTI (ENTRY_BLOCK_PTR)->out;
 
       if (REG_P (incoming))
        {
+         incoming = var_lowpart (mode, incoming);
          gcc_assert (REGNO (incoming) < FIRST_PSEUDO_REGISTER);
          attrs_list_insert (&out->regs[REGNO (incoming)],
                             parm, offset, incoming);
          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))
        }
       else if (MEM_P (incoming))
-       set_variable_part (out, incoming, parm, offset);
+       {
+         incoming = var_lowpart (mode, incoming);
+         set_variable_part (out, incoming, parm, offset,
+                            VAR_INIT_STATUS_INITIALIZED, NULL);
+       }
     }
 }
 
     }
 }
 
@@ -2993,8 +3408,10 @@ gate_handle_var_tracking (void)
 
 
 
 
 
 
-struct tree_opt_pass pass_variable_tracking =
+struct rtl_opt_pass pass_variable_tracking =
 {
 {
+ {
+  RTL_PASS,
   "vartrack",                           /* name */
   gate_handle_var_tracking,             /* gate */
   variable_tracking_main,               /* execute */
   "vartrack",                           /* name */
   gate_handle_var_tracking,             /* gate */
   variable_tracking_main,               /* execute */
@@ -3006,7 +3423,7 @@ struct tree_opt_pass pass_variable_tracking =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_dump_func,                       /* todo_flags_finish */
-  'V'                                   /* letter */
+  TODO_dump_func | TODO_verify_rtl_sharing/* todo_flags_finish */
+ }
 };
 
 };