Add ability to track uninitialized variables, and mark uninitialized variables in the Dwarf debug info.

Add ability to track uninitialized variables, and mark uninitialized
variables in the Dwarf debug info.  Controlled by compile option
-fvar-tracking-uninit

From-SVN: r126630
This commit is contained in:
Caroline Tice 2007-07-13 23:11:15 +00:00 committed by Caroline Tice
parent f861f54dd7
commit 62760ffd15
10 changed files with 596 additions and 106 deletions

View 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.

View 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

View 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"

View 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,

View 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);

View 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;

View 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. */

View File

@ -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.

View 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. */

View 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);
}
}