OSDN Git Service

Add ability to track uninitialized variables, and mark uninitialized
authorctice <ctice@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 13 Jul 2007 23:11:15 +0000 (23:11 +0000)
committerctice <ctice@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 13 Jul 2007 23:11:15 +0000 (23:11 +0000)
variables in the Dwarf debug info.  Controlled by compile option
-fvar-tracking-uninit

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@126630 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/common.opt
gcc/config/darwin.c
gcc/dwarf2.h
gcc/dwarf2out.c
gcc/print-rtl.c
gcc/rtl.def
gcc/rtl.h
gcc/toplev.c
gcc/var-tracking.c

index 6aeca7e..01c0bdb 100644 (file)
@@ -1,3 +1,102 @@
+2007-07-13  Caroline Tice  <ctice@apple.com>
+       
+       * toplev.c (process_options): Turn flag_var_tracking_uninit off when
+       flag_var_tracking is explicitly turned off (i.e. when variable
+       tracking is not feasible); otherwise, turn flag_var_tracking on when
+       flag_var_tracking_uninit is on.
+       * rtl.def (VAR_LOCATION): Add a new integer subfield to VAR_LOCATION
+       note definitions, to allow recording of initialization status in the
+       notes.
+       * dwarf2out.c (dwarf_stack_op_name): Add case for DW_OP_GNU_uninit.
+       (add_var_loc_to_decl): Add comparison of NOTE_VAR_LOCATION_STATUS to
+       determine if two note locations are equal.
+       (output_loc_list): Don't output list entries whose start & end labels
+       are the same.
+       (reg_loc_descriptor): Add parameter for initialization status; pass it
+       to other loc descriptor functions.
+       (one_reg_loc_descriptor): Add parameter for initialization status;
+       check its value and add DW_OP_GNU_uninit to returned loc descr if
+       appropriate.
+       (multiple_reg_loc_descriptor): Add parameter for initialization
+       status;
+       pass init status argument to other loc descriptor functions; check
+       value of intialization parameter and add DW_OP_GNU_uninit to returned
+       loc descr if appropriate.
+       (based_loc_descr): Add parameter for initialization status; add new
+       variable for return value; check value of initialization parameter and
+       add DW_OP_GNU_uninit to returned loc descr if appropriate.
+       (concatn_mem_loc_descriptor): Add parameter for initialization status;
+       pass init status argument to other loc descriptor functions; check
+       value of intialization parameter and add DW_OP_GNU_uninit to returned
+       loc descr if appropriate.
+       (mem_loc_descriptor): Likewise.
+       (concat_loc_descriptor): Likewise.
+       (concatn_loc_descriptor): Likewise.
+       (loc_descriptor): Add parameter for initialization status; pass it as
+       argument to other loc descriptor function calls.
+       (loc_descriptor_from_tree_1): Add appropriate initialization status
+       to loc descriptor function calls.
+       (add_location_or_const_value_attribute): Get initialization status
+       from VAR_LOCATION note; add initialization status to loc descriptor
+       function calls.
+       * dwarf2.h (enum dwarf_location_atom): New op, DW_OP_GNU_uninit.
+       * print-rtl.c (print_rtx): When printing a VAR_LOCATION note, if
+       status is uninitialized, add "[uninint]" to output.
+       * common.opt (fvar-tracking-uninit): New option, similar to
+       fvar-tracking, to turn on tracking of uninitialized variables; creates
+       a new global flag, flag_var_tracking_uninit.
+       * rtl.h (NOTE_VAR_LOCATION_STATUS): New macro for accessing new field.
+       (enum var_init_status): New type, for var initialization status field.
+       * var-tracking.c (struct location_chain_def): Two new fields, init,
+       for initialization status, and set_src for the assignment value expr.
+       (unshare_variable): New parameter for initialization status;
+       initialize new init and set_src fields.
+       (var_reg_set): New parameters for initialization status and value;
+       pass them to set_variable_part.
+       (var_mem_set): Likewise.
+       (get_init_value): New function.
+       (var_reg_delete_and_set): New initialization status & value
+       parameters; add call to get_init_value if status is unknown; pass new
+       parameters to clobber_variable_part and var_reg_set.
+       (var_mem_delete_and_set): Likewise.
+       (var_reg_delete): Pass null set_src value to clobber_variable_part.
+       (var_mem_delete): Likewise.
+       (variable_union): Pass status to unshare_variable; initialize new init
+       and set_src fields. If flag_var_tracking_uninit is not set, force
+       status to initialized.
+       (add_stores): Store insn, rather than NEXT_INSN(insn), so it can be
+       used later to get the set_src value.
+       (find_src_status): New function.
+       (find_src_set_src): New function.
+       (compute_bb_dataflow): Pass init status to calls to var_reg_set,
+       var_mem_set, var_reg_delete_and_set and var_mem_delete_and_set; for
+       MO_SET, get set_src value and pass it to var_reg_delete_and_set
+       and var_mem_delete_and_set.
+       (dump_variable): Print out "[uninit]" if appropriate.
+       (set_variable_part): Add new initialization and set_src parameters;
+       pass status to unshare_variable; set node->init and node- >set_src
+       fields and modify slot in hash table appropriately; save the init and
+       set_src values if appropriate and assign to the new node.
+       (clobber_variable_part): New set_src parameter; if two nodes have
+       same variable and same location but different set_src (assignment)
+       values, clobber old node.
+       (delete_variable_part): Pass init status to unshare_variable.
+       (emit_note_insn_var_location): Add initialized var; assign var's init
+       status to new 'initialized'; pass new init status field to calls to
+       gen_rtx_VAR_LOCATION. If flag_var_tracking_uninit is not set, force
+       status to initialized.
+       (emit_notes_in_bb): Pass initialization status to calls to
+       var_reg_set, var_mem_set, var_reg_delete_and_set and
+       var_mem_delete_and_set; for MO_SET, get set_src value and pass it to
+       var_reg_delete_and_set and var_mem_delete_and_set; call
+       emit_notes_for_changes on NEXT_INSN(insn) rather than on insn, to
+       make up for change in add_stores.
+       (vt_add_function_parameters): Add status to calls to
+       set_variable_part.
+       * config/darwin.c (darwin_override_options): Turn on uninitialized
+       tracking automatically, if var_tracking is on and the system is
+       10.5 or higher.
+       
 2007-07-13  Sa Liu  <saliu@de.ibm.com>
 
        * config.gcc: Add options for arch and tune on SPU.
index dfbbf92..a37d3fc 100644 (file)
@@ -1130,6 +1130,10 @@ fvar-tracking
 Common Report Var(flag_var_tracking) VarExists Optimization
 Perform variable tracking
 
+fvar-tracking-uninit
+Common Report Var(flag_var_tracking_uninit) Optimization
+Perform variable tracking and also tag variables that are uninitialized
+
 ftree-vectorize
 Common Report Var(flag_tree_vectorize) Optimization
 Enable loop vectorization on trees
index 9d703da..0673915 100644 (file)
@@ -1728,6 +1728,9 @@ darwin_override_options (void)
       /* No -fnon-call-exceptions data in kexts.  */
       flag_non_call_exceptions = 0;
     }
+  if (flag_var_tracking
+      && strverscmp (darwin_macosx_version_min, "10.5") >= 0)
+    flag_var_tracking_uninit = 1;
 }
 
 #include "gt-darwin.h"
index 3118837..ac0b3ba 100644 (file)
@@ -540,6 +540,8 @@ enum dwarf_location_atom
     DW_OP_bit_piece = 0x9d,
     /* GNU extensions.  */
     DW_OP_GNU_push_tls_address = 0xe0,
+    /* The following is for marking variables that are uninitialized.  */
+    DW_OP_GNU_uninit     = 0xf0,
     /* HP extensions.  */
     DW_OP_HP_unknown     = 0xe0, /* Ouch, the same as GNU_push_tls_address.  */
     DW_OP_HP_is_value    = 0xe1,
index a54e517..974419f 100644 (file)
@@ -3125,6 +3125,8 @@ dwarf_stack_op_name (unsigned int op)
       return "DW_OP_call_ref";
     case DW_OP_GNU_push_tls_address:
       return "DW_OP_GNU_push_tls_address";
+    case DW_OP_GNU_uninit:
+      return "DW_OP_GNU_uninit";
     default:
       return "OP_<unknown>";
     }
@@ -4193,15 +4195,20 @@ static dw_die_ref modified_type_die (tree, int, int, dw_die_ref);
 static int type_is_enum (tree);
 static unsigned int dbx_reg_number (rtx);
 static void add_loc_descr_op_piece (dw_loc_descr_ref *, int);
-static dw_loc_descr_ref reg_loc_descriptor (rtx);
-static dw_loc_descr_ref one_reg_loc_descriptor (unsigned int);
-static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx);
+static dw_loc_descr_ref reg_loc_descriptor (rtx, enum var_init_status);
+static dw_loc_descr_ref one_reg_loc_descriptor (unsigned int, 
+                                               enum var_init_status);
+static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx,
+                                                    enum var_init_status);
 static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT);
-static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT);
+static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT,
+                                        enum var_init_status);
 static int is_based_loc (rtx);
-static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode);
-static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx);
-static dw_loc_descr_ref loc_descriptor (rtx);
+static dw_loc_descr_ref mem_loc_descriptor (rtx, enum machine_mode mode,
+                                           enum var_init_status);
+static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx,
+                                              enum var_init_status);
+static dw_loc_descr_ref loc_descriptor (rtx, enum var_init_status);
 static dw_loc_descr_ref loc_descriptor_from_tree_1 (tree, int);
 static dw_loc_descr_ref loc_descriptor_from_tree (tree);
 static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
@@ -5757,9 +5764,16 @@ add_var_loc_to_decl (tree decl, struct var_loc_node *loc)
   if (temp->last)
     {
       /* If the current location is the same as the end of the list,
+        and either both or neither of the locations is uninitialized,
         we have nothing to do.  */
-      if (!rtx_equal_p (NOTE_VAR_LOCATION_LOC (temp->last->var_loc_note),
-                       NOTE_VAR_LOCATION_LOC (loc->var_loc_note)))
+      if ((!rtx_equal_p (NOTE_VAR_LOCATION_LOC (temp->last->var_loc_note),
+                        NOTE_VAR_LOCATION_LOC (loc->var_loc_note)))
+         || ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note)
+              != NOTE_VAR_LOCATION_STATUS (loc->var_loc_note))
+             && ((NOTE_VAR_LOCATION_STATUS (temp->last->var_loc_note)
+                  == VAR_INIT_STATUS_UNINITIALIZED)
+                 || (NOTE_VAR_LOCATION_STATUS (loc->var_loc_note)
+                     == VAR_INIT_STATUS_UNINITIALIZED))))
        {
          /* Add LOC to the end of list and update LAST.  */
          temp->last->next = loc;
@@ -7069,6 +7083,9 @@ output_loc_list (dw_loc_list_ref list_head)
   for (curr = list_head; curr != NULL; curr = curr->dw_loc_next)
     {
       unsigned long size;
+      /* Don't output an entry that starts and ends at the same address.  */
+      if (strcmp (curr->begin, curr->end) == 0)
+       continue;
       if (!have_multiple_function_sections)
        {
          dw2_asm_output_delta (DWARF2_ADDR_SIZE, curr->begin, curr->section,
@@ -8747,7 +8764,7 @@ add_loc_descr_op_piece (dw_loc_descr_ref *list_head, int size)
    zero if there is none.  */
 
 static dw_loc_descr_ref
-reg_loc_descriptor (rtx rtl)
+reg_loc_descriptor (rtx rtl, enum var_init_status initialized)
 {
   rtx regs;
 
@@ -8757,28 +8774,35 @@ reg_loc_descriptor (rtx rtl)
   regs = targetm.dwarf_register_span (rtl);
 
   if (hard_regno_nregs[REGNO (rtl)][GET_MODE (rtl)] > 1 || regs)
-    return multiple_reg_loc_descriptor (rtl, regs);
+    return multiple_reg_loc_descriptor (rtl, regs, initialized);
   else
-    return one_reg_loc_descriptor (dbx_reg_number (rtl));
+    return one_reg_loc_descriptor (dbx_reg_number (rtl), initialized);
 }
 
 /* Return a location descriptor that designates a machine register for
    a given hard register number.  */
 
 static dw_loc_descr_ref
-one_reg_loc_descriptor (unsigned int regno)
+one_reg_loc_descriptor (unsigned int regno, enum var_init_status initialized)
 {
+  dw_loc_descr_ref reg_loc_descr;
   if (regno <= 31)
-    return new_loc_descr (DW_OP_reg0 + regno, 0, 0);
+    reg_loc_descr = new_loc_descr (DW_OP_reg0 + regno, 0, 0);
   else
-    return new_loc_descr (DW_OP_regx, regno, 0);
+    reg_loc_descr = new_loc_descr (DW_OP_regx, regno, 0);
+
+  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&reg_loc_descr, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
+  return reg_loc_descr;
 }
 
 /* Given an RTL of a register, return a location descriptor that
    designates a value that spans more than one register.  */
 
 static dw_loc_descr_ref
-multiple_reg_loc_descriptor (rtx rtl, rtx regs)
+multiple_reg_loc_descriptor (rtx rtl, rtx regs, 
+                            enum var_init_status initialized)
 {
   int nregs, size, i;
   unsigned reg;
@@ -8806,7 +8830,8 @@ multiple_reg_loc_descriptor (rtx rtl, rtx regs)
        {
          dw_loc_descr_ref t;
 
-         t = one_reg_loc_descriptor (DBX_REGISTER_NUMBER (reg));
+         t = one_reg_loc_descriptor (DBX_REGISTER_NUMBER (reg),
+                                     VAR_INIT_STATUS_INITIALIZED);
          add_loc_descr (&loc_result, t);
          add_loc_descr_op_piece (&loc_result, size);
          ++reg;
@@ -8825,11 +8850,15 @@ multiple_reg_loc_descriptor (rtx rtl, rtx regs)
     {
       dw_loc_descr_ref t;
 
-      t = one_reg_loc_descriptor (REGNO (XVECEXP (regs, 0, i)));
+      t = one_reg_loc_descriptor (REGNO (XVECEXP (regs, 0, i)),
+                                 VAR_INIT_STATUS_INITIALIZED);
       add_loc_descr (&loc_result, t);
       size = GET_MODE_SIZE (GET_MODE (XVECEXP (regs, 0, 0)));
       add_loc_descr_op_piece (&loc_result, size);
     }
+
+  if (loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
   return loc_result;
 }
 
@@ -8875,9 +8904,11 @@ int_loc_descriptor (HOST_WIDE_INT i)
 /* Return a location descriptor that designates a base+offset location.  */
 
 static dw_loc_descr_ref
-based_loc_descr (rtx reg, HOST_WIDE_INT offset)
+based_loc_descr (rtx reg, HOST_WIDE_INT offset,
+                enum var_init_status initialized)
 {
   unsigned int regno;
+  dw_loc_descr_ref result;
 
   /* We only use "frame base" when we're sure we're talking about the
      post-prologue local stack frame.  We do this by *not* running
@@ -8904,9 +8935,14 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset)
 
   regno = dbx_reg_number (reg);
   if (regno <= 31)
-    return new_loc_descr (DW_OP_breg0 + regno, offset, 0);
+    result = new_loc_descr (DW_OP_breg0 + regno, offset, 0);
   else
-    return new_loc_descr (DW_OP_bregx, regno, offset);
+    result = new_loc_descr (DW_OP_bregx, regno, offset);
+
+  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
+  return result;
 }
 
 /* Return true if this RTL expression describes a base+offset calculation.  */
@@ -8924,7 +8960,8 @@ is_based_loc (rtx rtl)
    used to form the address of a memory location.  */
 
 static dw_loc_descr_ref
-concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode)
+concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode,
+                           enum var_init_status initialized)
 {
   unsigned int i;
   dw_loc_descr_ref cc_loc_result = NULL;
@@ -8935,7 +8972,7 @@ concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode)
       dw_loc_descr_ref ref;
       rtx x = XVECEXP (concatn, 0, i);
 
-      ref = mem_loc_descriptor (x, mode);
+      ref = mem_loc_descriptor (x, mode, VAR_INIT_STATUS_INITIALIZED);
       if (ref == NULL)
        return NULL;
 
@@ -8943,6 +8980,9 @@ concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode)
       add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x)));
     }
 
+  if (cc_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
   return cc_loc_result;
 }
 
@@ -8965,7 +9005,8 @@ concatn_mem_loc_descriptor (rtx concatn, enum machine_mode mode)
    Return 0 if we can't represent the location.  */
 
 static dw_loc_descr_ref
-mem_loc_descriptor (rtx rtl, enum machine_mode mode)
+mem_loc_descriptor (rtx rtl, enum machine_mode mode,
+                   enum var_init_status initialized)
 {
   dw_loc_descr_ref mem_loc_result = NULL;
   enum dwarf_location_atom op;
@@ -9012,11 +9053,12 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode)
         memory) so DWARF consumers need to be aware of the subtle
         distinction between OP_REG and OP_BASEREG.  */
       if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
-       mem_loc_result = based_loc_descr (rtl, 0);
+       mem_loc_result = based_loc_descr (rtl, 0, VAR_INIT_STATUS_INITIALIZED);
       break;
 
     case MEM:
-      mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
+      mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
+                                          VAR_INIT_STATUS_INITIALIZED);
       if (mem_loc_result != 0)
        add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
       break;
@@ -9083,10 +9125,12 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode)
     plus:
       if (is_based_loc (rtl))
        mem_loc_result = based_loc_descr (XEXP (rtl, 0),
-                                         INTVAL (XEXP (rtl, 1)));
+                                         INTVAL (XEXP (rtl, 1)),
+                                         VAR_INIT_STATUS_INITIALIZED);
       else
        {
-         mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode);
+         mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                                              VAR_INIT_STATUS_INITIALIZED);
          if (mem_loc_result == 0)
            break;
 
@@ -9098,7 +9142,8 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode)
          else
            {
              add_loc_descr (&mem_loc_result,
-                            mem_loc_descriptor (XEXP (rtl, 1), mode));
+                            mem_loc_descriptor (XEXP (rtl, 1), mode,
+                                                VAR_INIT_STATUS_INITIALIZED));
              add_loc_descr (&mem_loc_result,
                             new_loc_descr (DW_OP_plus, 0, 0));
            }
@@ -9125,8 +9170,10 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode)
 
     do_binop:
       {
-       dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode);
-       dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode);
+       dw_loc_descr_ref op0 = mem_loc_descriptor (XEXP (rtl, 0), mode,
+                                                  VAR_INIT_STATUS_INITIALIZED);
+       dw_loc_descr_ref op1 = mem_loc_descriptor (XEXP (rtl, 1), mode,
+                                                  VAR_INIT_STATUS_INITIALIZED);
 
        if (op0 == 0 || op1 == 0)
          break;
@@ -9142,13 +9189,17 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode)
       break;
 
     case CONCATN:
-      mem_loc_result = concatn_mem_loc_descriptor (rtl, mode);
+      mem_loc_result = concatn_mem_loc_descriptor (rtl, mode, 
+                                                  VAR_INIT_STATUS_INITIALIZED);
       break;
 
     default:
       gcc_unreachable ();
     }
 
+  if (mem_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
   return mem_loc_result;
 }
 
@@ -9156,11 +9207,11 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode)
    This is typically a complex variable.  */
 
 static dw_loc_descr_ref
-concat_loc_descriptor (rtx x0, rtx x1)
+concat_loc_descriptor (rtx x0, rtx x1, enum var_init_status initialized)
 {
   dw_loc_descr_ref cc_loc_result = NULL;
-  dw_loc_descr_ref x0_ref = loc_descriptor (x0);
-  dw_loc_descr_ref x1_ref = loc_descriptor (x1);
+  dw_loc_descr_ref x0_ref = loc_descriptor (x0, VAR_INIT_STATUS_INITIALIZED);
+  dw_loc_descr_ref x1_ref = loc_descriptor (x1, VAR_INIT_STATUS_INITIALIZED);
 
   if (x0_ref == 0 || x1_ref == 0)
     return 0;
@@ -9171,6 +9222,9 @@ concat_loc_descriptor (rtx x0, rtx x1)
   add_loc_descr (&cc_loc_result, x1_ref);
   add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x1)));
 
+  if (initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
   return cc_loc_result;
 }
 
@@ -9178,7 +9232,7 @@ concat_loc_descriptor (rtx x0, rtx x1)
    locations.  */
 
 static dw_loc_descr_ref
-concatn_loc_descriptor (rtx concatn)
+concatn_loc_descriptor (rtx concatn, enum var_init_status initialized)
 {
   unsigned int i;
   dw_loc_descr_ref cc_loc_result = NULL;
@@ -9189,7 +9243,7 @@ concatn_loc_descriptor (rtx concatn)
       dw_loc_descr_ref ref;
       rtx x = XVECEXP (concatn, 0, i);
 
-      ref = loc_descriptor (x);
+      ref = loc_descriptor (x, VAR_INIT_STATUS_INITIALIZED);
       if (ref == NULL)
        return NULL;
 
@@ -9197,6 +9251,9 @@ concatn_loc_descriptor (rtx concatn)
       add_loc_descr_op_piece (&cc_loc_result, GET_MODE_SIZE (GET_MODE (x)));
     }
 
+  if (cc_loc_result && initialized == VAR_INIT_STATUS_UNINITIALIZED)
+    add_loc_descr (&cc_loc_result, new_loc_descr (DW_OP_GNU_uninit, 0, 0));
+
   return cc_loc_result;
 }
 
@@ -9209,7 +9266,7 @@ concatn_loc_descriptor (rtx concatn)
    If we don't know how to describe it, return 0.  */
 
 static dw_loc_descr_ref
-loc_descriptor (rtx rtl)
+loc_descriptor (rtx rtl, enum var_init_status initialized)
 {
   dw_loc_descr_ref loc_result = NULL;
 
@@ -9226,26 +9283,28 @@ loc_descriptor (rtx rtl)
       /* ... fall through ...  */
 
     case REG:
-      loc_result = reg_loc_descriptor (rtl);
+      loc_result = reg_loc_descriptor (rtl, initialized);
       break;
 
     case MEM:
-      loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl));
+      loc_result = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
+                                      initialized);
       break;
 
     case CONCAT:
-      loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1));
+      loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1),
+                                         initialized);
       break;
 
     case CONCATN:
-      loc_result = concatn_loc_descriptor (rtl);
+      loc_result = concatn_loc_descriptor (rtl, initialized);
       break;
 
     case VAR_LOCATION:
       /* Single part.  */
       if (GET_CODE (XEXP (rtl, 1)) != PARALLEL)
        {
-         loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0));
+         loc_result = loc_descriptor (XEXP (XEXP (rtl, 1), 0), initialized);
          break;
        }
 
@@ -9260,14 +9319,16 @@ loc_descriptor (rtx rtl)
        int i;
 
        /* Create the first one, so we have something to add to.  */
-       loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0));
+       loc_result = loc_descriptor (XEXP (RTVEC_ELT (par_elems, 0), 0),
+                                    initialized);
        mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, 0), 0));
        add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
        for (i = 1; i < num_elem; i++)
          {
            dw_loc_descr_ref temp;
 
-           temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0));
+           temp = loc_descriptor (XEXP (RTVEC_ELT (par_elems, i), 0),
+                                  initialized);
            add_loc_descr (&loc_result, temp);
            mode = GET_MODE (XEXP (RTVEC_ELT (par_elems, i), 0));
            add_loc_descr_op_piece (&loc_result, GET_MODE_SIZE (mode));
@@ -9399,7 +9460,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
 
            /* Certain constructs can only be represented at top-level.  */
            if (want_address == 2)
-             return loc_descriptor (rtl);
+             return loc_descriptor (rtl, VAR_INIT_STATUS_INITIALIZED);
 
            mode = GET_MODE (rtl);
            if (MEM_P (rtl))
@@ -9407,7 +9468,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
                rtl = XEXP (rtl, 0);
                have_address = 1;
              }
-           ret = mem_loc_descriptor (rtl, mode);
+           ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
          }
       }
       break;
@@ -9488,7 +9549,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address)
          return 0;
        mode = GET_MODE (rtl);
        rtl = XEXP (rtl, 0);
-       ret = mem_loc_descriptor (rtl, mode);
+       ret = mem_loc_descriptor (rtl, mode, VAR_INIT_STATUS_INITIALIZED);
        have_address = 1;
        break;
       }
@@ -10575,6 +10636,7 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
       const char *endname, *secname;
       dw_loc_list_ref list;
       rtx varloc;
+      enum var_init_status initialized;
 
       /* Now that we know what section we are using for a base,
         actually construct the list of locations.
@@ -10591,7 +10653,12 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
       varloc = NOTE_VAR_LOCATION (node->var_loc_note);
       secname = secname_for_decl (decl);
 
-      list = new_loc_list (loc_descriptor (varloc),
+      if (NOTE_VAR_LOCATION_LOC (node->var_loc_note))
+       initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
+      else
+       initialized = VAR_INIT_STATUS_INITIALIZED;
+
+      list = new_loc_list (loc_descriptor (varloc, initialized),
                           node->label, node->next->label, secname, 1);
       node = node->next;
 
@@ -10600,8 +10667,11 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
          {
            /* The variable has a location between NODE->LABEL and
               NODE->NEXT->LABEL.  */
+           enum var_init_status initialized =
+             NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
            varloc = NOTE_VAR_LOCATION (node->var_loc_note);
-           add_loc_descr_to_loc_list (&list, loc_descriptor (varloc),
+           add_loc_descr_to_loc_list (&list, 
+                                      loc_descriptor (varloc, initialized),
                                       node->label, node->next->label, secname);
          }
 
@@ -10610,6 +10680,8 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
       if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
        {
          char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
+         enum var_init_status initialized =
+           NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
 
          varloc = NOTE_VAR_LOCATION (node->var_loc_note);
          if (!current_function_decl)
@@ -10620,7 +10692,8 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
                                           current_function_funcdef_no);
              endname = ggc_strdup (label_id);
            }
-         add_loc_descr_to_loc_list (&list, loc_descriptor (varloc),
+         add_loc_descr_to_loc_list (&list, 
+                                    loc_descriptor (varloc, initialized),
                                     node->label, endname, secname);
        }
 
@@ -10644,8 +10717,10 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
      location list, try generating a location from that.  */
   if (loc_list && loc_list->first)
     {
+      enum var_init_status status;
       node = loc_list->first;
-      descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note));
+      status = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
+      descr = loc_descriptor (NOTE_VAR_LOCATION (node->var_loc_note), status);
       if (descr)
        {
          add_AT_location_description (die, attr, descr);
index a47a02b..52b5c65 100644 (file)
@@ -325,6 +325,9 @@ print_rtx (rtx in_rtx)
                print_mem_expr (outfile, NOTE_VAR_LOCATION_DECL (in_rtx));
                fprintf (outfile, " ");
                print_rtx (NOTE_VAR_LOCATION_LOC (in_rtx));
+               if (NOTE_VAR_LOCATION_STATUS (in_rtx) == 
+                                                VAR_INIT_STATUS_UNINITIALIZED)
+                 fprintf (outfile, " [uninit]");
                fprintf (outfile, ")");
 #endif
                break;
index c82fa7e..1326202 100644 (file)
@@ -680,7 +680,9 @@ DEF_RTL_EXPR(SS_TRUNCATE, "ss_truncate", "e", RTX_UNARY)
 DEF_RTL_EXPR(US_TRUNCATE, "us_truncate", "e", RTX_UNARY)
 
 /* Information about the variable and its location.  */
-DEF_RTL_EXPR(VAR_LOCATION, "var_location", "te", RTX_EXTRA)
+/* Changed 'te' to 'tei'; the 'i' field is for recording
+   initialization status of variables.  */
+DEF_RTL_EXPR(VAR_LOCATION, "var_location", "tei", RTX_EXTRA)
 
 /* All expressions from this point forward appear only in machine
    descriptions.  */
index 124f528..63f6573 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -847,6 +847,22 @@ extern const char * const reg_note_name[];
 #define NOTE_VAR_LOCATION_LOC(INSN)    (XCEXP (XCEXP (INSN, 4, NOTE),  \
                                                1, VAR_LOCATION))
 
+/* Initialization status of the variable in the location.  Status
+   can be unknown, uninitialized or initialized.  See enumeration
+   type below.  */
+#define NOTE_VAR_LOCATION_STATUS(INSN)  (XCINT (XCEXP (INSN, 4, NOTE), \
+                                               2, VAR_LOCATION))
+
+/* Possible initialization status of a variable.   When requested
+   by the user, this information is tracked and recorded in the DWARF
+   debug information, along with the variable's location.  */
+enum var_init_status
+{
+  VAR_INIT_STATUS_UNKNOWN,
+  VAR_INIT_STATUS_UNINITIALIZED,
+  VAR_INIT_STATUS_INITIALIZED
+};
+
 /* Codes that appear in the NOTE_KIND field for kinds of notes
    that are not line numbers.  These codes are all negative.
    
index ff0d8a3..de86b38 100644 (file)
@@ -1874,7 +1874,8 @@ process_options (void)
   if (debug_info_level < DINFO_LEVEL_NORMAL
       || debug_hooks->var_location == do_nothing_debug_hooks.var_location)
     {
-      if (flag_var_tracking == 1)
+      if (flag_var_tracking == 1
+         || flag_var_tracking_uninit == 1)
         {
          if (debug_info_level < DINFO_LEVEL_NORMAL)
            warning (0, "variable tracking requested, but useless unless "
@@ -1884,6 +1885,7 @@ process_options (void)
                     "by this debug format");
        }
       flag_var_tracking = 0;
+      flag_var_tracking_uninit = 0;
     }
 
   if (flag_rename_registers == AUTODETECT_VALUE)
@@ -1893,6 +1895,12 @@ process_options (void)
   if (flag_var_tracking == AUTODETECT_VALUE)
     flag_var_tracking = optimize >= 1;
 
+  /* If the user specifically requested variable tracking with tagging
+     uninitialized variables, we need to turn on variable tracking.
+     (We already determined above that variable tracking is feasible.)  */
+  if (flag_var_tracking_uninit)
+    flag_var_tracking = 1;
+
   /* If auxiliary info generation is desired, open the output file.
      This goes in the same directory as the source file--unlike
      all the other output files.  */
index 94a025a..56dcc19 100644 (file)
@@ -219,6 +219,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.  */
@@ -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);
@@ -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);
@@ -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;
 }
@@ -1679,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)
@@ -1700,10 +1798,99 @@ 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;
+  tree decl = NULL_TREE;
+  enum var_init_status status = VAR_INIT_STATUS_UNINITIALIZED;
+
+  if (! flag_var_tracking_uninit)
+    status = VAR_INIT_STATUS_INITIALIZED;
+
+  if (GET_CODE (PATTERN (insn)) == SET)
+    src = SET_SRC (PATTERN (insn));
+  else if (GET_CODE (PATTERN (insn)) == PARALLEL
+          || GET_CODE (PATTERN (insn)) == SEQUENCE)
+    {
+      int i;
+      for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+       if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET
+           && SET_DEST (XVECEXP (PATTERN (insn), 0, i)) == loc)
+         src = SET_SRC (XVECEXP (PATTERN (insn), 0, i));
+    }
+
+  if (REG_P (src))
+    decl = var_debug_decl (REG_EXPR (src));
+  else if (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".      */
+  void **slot;
+  variable var;
+  location_chain nextp;
+  int i;
+  bool found;
+
+  if (GET_CODE (PATTERN (insn)) == SET)
+    src = SET_SRC (PATTERN (insn));
+  else if (GET_CODE (PATTERN (insn)) == PARALLEL
+          || GET_CODE (PATTERN (insn)) == SEQUENCE)
+    {
+      for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
+       if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET
+           && SET_DEST (XVECEXP (PATTERN (insn), 0, i)) == loc)
+         src = SET_SRC (XVECEXP (PATTERN (insn), 0, i));
+    }
+
+  if (REG_P (src))
+    decl = var_debug_decl (REG_EXPR (src));
+  else if (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
@@ -1733,33 +1920,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;
 
@@ -1932,6 +2151,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);
        }
     }
@@ -2077,7 +2298,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;
@@ -2119,13 +2341,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
@@ -2134,7 +2362,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.  */
@@ -2161,6 +2389,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;
@@ -2172,6 +2406,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;
 
@@ -2190,7 +2426,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;
 
@@ -2213,7 +2449,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))
                    {
@@ -2278,7 +2518,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;
                    }
                }
@@ -2345,6 +2588,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];
@@ -2352,6 +2596,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;
@@ -2369,6 +2616,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.  */
@@ -2447,10 +2695,13 @@ emit_note_insn_var_location (void **varp, void *data)
   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)
     {
@@ -2458,7 +2709,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)
     {
@@ -2471,7 +2723,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);
@@ -2602,11 +2855,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);
            }
@@ -2615,26 +2871,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;
 
@@ -2660,7 +2936,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;
 
@@ -2776,10 +3052,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);
     }
 }