summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorctice <ctice@138bc75d-0d04-0410-961f-82ee72b054a4>2007-07-13 23:11:15 +0000
committerctice <ctice@138bc75d-0d04-0410-961f-82ee72b054a4>2007-07-13 23:11:15 +0000
commitd53bb22673261b227d5045c435bd2acd4c87c236 (patch)
treeb87516d5c9ea7c2c70b26f837f1dada3f4c4d0f0
parentaa9311a1b831d7e2f0575a09def64eff0dac9f6a (diff)
downloadgcc-d53bb22673261b227d5045c435bd2acd4c87c236.tar.gz
Add ability to track uninitialized variables, and mark uninitialized
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
-rw-r--r--gcc/ChangeLog99
-rw-r--r--gcc/common.opt4
-rw-r--r--gcc/config/darwin.c3
-rw-r--r--gcc/dwarf2.h2
-rw-r--r--gcc/dwarf2out.c179
-rw-r--r--gcc/print-rtl.c3
-rw-r--r--gcc/rtl.def4
-rw-r--r--gcc/rtl.h16
-rw-r--r--gcc/toplev.c10
-rw-r--r--gcc/var-tracking.c382
10 files changed, 596 insertions, 106 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6aeca7e06b9..01c0bdb3353 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/common.opt b/gcc/common.opt
index dfbbf92f10a..a37d3fcdd1d 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -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
diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c
index 9d703da70a1..0673915200f 100644
--- a/gcc/config/darwin.c
+++ b/gcc/config/darwin.c
@@ -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"
diff --git a/gcc/dwarf2.h b/gcc/dwarf2.h
index 31188372787..ac0b3ba1a97 100644
--- a/gcc/dwarf2.h
+++ b/gcc/dwarf2.h
@@ -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,
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index a54e517dc21..974419ffa75 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -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);
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index a47a02b87fe..52b5c658168 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -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;
diff --git a/gcc/rtl.def b/gcc/rtl.def
index c82fa7e86ed..1326202cc88 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -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. */
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 124f5280950..63f65730d10 100644
--- 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.
diff --git a/gcc/toplev.c b/gcc/toplev.c
index ff0d8a3ea7d..de86b38ae16 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -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. */
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index 94a025a002b..56dcc198d7d 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -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);
}
}