Commit 864ddef7 by Jakub Jelinek Committed by Jakub Jelinek

re PR debug/43176 (var-tracking fails to notice a value change)

	PR debug/43176
	* Makefile.in (var-tracking.o): Depend on pointer-set.h.
	* cselib.c (struct expand_value_data): Add dummy field.
	(cselib_expand_value_rtx, cselib_expand_value_rtx_cb): Initialize
	dummy to false.
	(cselib_dummy_expand_value_rtx_cb): New function.
	(cselib_expand_value_rtx_1): If evd->dummy is true, don't allocate
	any rtl.
	* cselib.h (cselib_dummy_expand_value_rtx_cb): New prototype.
	* var-tracking.c: Include pointer-set.h.
	(variable): Change n_var_parts to char from int.  Add
	cur_loc_changed and in_changed_variables fields.
	(variable_canonicalize): Remove.
	(shared_var_p): New inline function.
	(unshare_variable): Maintain cur_loc_changed and
	in_changed_variables fields.  If var was in changed_variables,
	replace it there with new_var.  Just copy cur_loc instead of
	resetting it to something else.
	(variable_union): Don't recompute cur_loc.  Use shared_var_p.
	(dataflow_set_union): Don't call variable_canonicalize.
	(loc_cmp): If both x and y are DEBUG_EXPRs, compare uids
	of their DEBUG_EXPR_TREE_DECLs.
	(canonicalize_loc_order_check): Verify that cur_loc is NULL
	and in_changed_variables and cur_loc_changed is false.
	(variable_merge_over_cur): Clear cur_loc, in_changed_variables
	and cur_loc_changed.  Don't update cur_loc here.
	(variable_merge_over_src): Don't call variable_canonicalize.
	(dataflow_set_preserve_mem_locs): Use shared_var_p.  When
	removing loc that is equal to cur_loc, clear cur_loc,
	set cur_loc_changed and ensure variable_was_changed is called.
	(dataflow_set_remove_mem_locs): Use shared_var_p.  Only
	compare pointers in cur_loc check, if it is equal to loc,
	clear cur_loc and set cur_loc_changed.  Don't recompute cur_loc here.
	(variable_different_p): Remove compare_current_location argument,
	don't compare cur_loc.
	(dataflow_set_different_1): Adjust variable_different_p caller.
	(variable_was_changed): If dv had some var in changed_variables
	already, reset in_changed_variables flag for it and propagate
	cur_loc_changed over to the new variable.  On empty var
	always set cur_loc_changed.  Set in_changed_variables on whatever
	var is added to changed_variables.
	(set_slot_part): Clear cur_loc_changed and in_changed_variables.
	Use shared_var_p.  When removing loc that is equal to cur_loc,
	clear cur_loc and set cur_loc_changed.  If cur_loc is NULL at the
	end, don't set it to something else, just call variable_was_changed.
	(delete_slot_part): Use shared_var_p.  When cur_loc equals to
	loc being removed, clear cur_loc and set cur_loc_changed.
	Set cur_loc_changed if all locations have been removed.
	(struct expand_loc_callback_data): New type.
	(vt_expand_loc_callback): Add dummy mode in which no rtxes are
	allocated.  Always create SUBREGs if simplify_subreg failed.
	Prefer to use cur_loc, when that fails and still in
	changed_variables (and seen first time) recompute it.  Set
	cur_loc_changed of variables which had to change cur_loc and
	compute elcd->cur_loc_changed if any of the subexpressions used
	had to change cur_loc.
	(vt_expand_loc): Adjust to pass arguments in
	expand_loc_callback_data structure.
	(vt_expand_loc_dummy): New function.
	(emitted_notes): New variable.
	(emit_note_insn_var_location): For VALUEs and DEBUG_EXPR_DECLs
	that weren't used for any other decl in current
	emit_notes_for_changes call call vt_expand_loc_dummy to update
	cur_loc.  For -fno-var-tracking-assignments, set cur_loc to
	first loc_chain location if NULL before.  Always use just
	cur_loc instead of first loc_chain location.  When cur_loc_changed
	is false, when not --enable-checking=rtl just don't emit any note.
	When rtl checking, compute the note and assert it is the same
	as previous note.  Clear cur_loc_changed and in_changed_variables
	at the end before removing from changed_variables.
	(check_changed_vars_3): New function.
	(emit_notes_for_changes): Traverse changed_vars to call
	check_changed_vars_3 on each changed var.
	(emit_notes_for_differences_1): Clear cur_loc_changed and
	in_changed_variables.  Recompute cur_loc of new_var.
	(emit_notes_for_differences_2): Clear cur_loc if new variable
	appears.
	(vt_emit_notes): Initialize and destroy emitted_notes.

From-SVN: r157264
parent c4137918
2010-03-07 Jakub Jelinek <jakub@redhat.com>
PR debug/43176
* Makefile.in (var-tracking.o): Depend on pointer-set.h.
* cselib.c (struct expand_value_data): Add dummy field.
(cselib_expand_value_rtx, cselib_expand_value_rtx_cb): Initialize
dummy to false.
(cselib_dummy_expand_value_rtx_cb): New function.
(cselib_expand_value_rtx_1): If evd->dummy is true, don't allocate
any rtl.
* cselib.h (cselib_dummy_expand_value_rtx_cb): New prototype.
* var-tracking.c: Include pointer-set.h.
(variable): Change n_var_parts to char from int. Add
cur_loc_changed and in_changed_variables fields.
(variable_canonicalize): Remove.
(shared_var_p): New inline function.
(unshare_variable): Maintain cur_loc_changed and
in_changed_variables fields. If var was in changed_variables,
replace it there with new_var. Just copy cur_loc instead of
resetting it to something else.
(variable_union): Don't recompute cur_loc. Use shared_var_p.
(dataflow_set_union): Don't call variable_canonicalize.
(loc_cmp): If both x and y are DEBUG_EXPRs, compare uids
of their DEBUG_EXPR_TREE_DECLs.
(canonicalize_loc_order_check): Verify that cur_loc is NULL
and in_changed_variables and cur_loc_changed is false.
(variable_merge_over_cur): Clear cur_loc, in_changed_variables
and cur_loc_changed. Don't update cur_loc here.
(variable_merge_over_src): Don't call variable_canonicalize.
(dataflow_set_preserve_mem_locs): Use shared_var_p. When
removing loc that is equal to cur_loc, clear cur_loc,
set cur_loc_changed and ensure variable_was_changed is called.
(dataflow_set_remove_mem_locs): Use shared_var_p. Only
compare pointers in cur_loc check, if it is equal to loc,
clear cur_loc and set cur_loc_changed. Don't recompute cur_loc here.
(variable_different_p): Remove compare_current_location argument,
don't compare cur_loc.
(dataflow_set_different_1): Adjust variable_different_p caller.
(variable_was_changed): If dv had some var in changed_variables
already, reset in_changed_variables flag for it and propagate
cur_loc_changed over to the new variable. On empty var
always set cur_loc_changed. Set in_changed_variables on whatever
var is added to changed_variables.
(set_slot_part): Clear cur_loc_changed and in_changed_variables.
Use shared_var_p. When removing loc that is equal to cur_loc,
clear cur_loc and set cur_loc_changed. If cur_loc is NULL at the
end, don't set it to something else, just call variable_was_changed.
(delete_slot_part): Use shared_var_p. When cur_loc equals to
loc being removed, clear cur_loc and set cur_loc_changed.
Set cur_loc_changed if all locations have been removed.
(struct expand_loc_callback_data): New type.
(vt_expand_loc_callback): Add dummy mode in which no rtxes are
allocated. Always create SUBREGs if simplify_subreg failed.
Prefer to use cur_loc, when that fails and still in
changed_variables (and seen first time) recompute it. Set
cur_loc_changed of variables which had to change cur_loc and
compute elcd->cur_loc_changed if any of the subexpressions used
had to change cur_loc.
(vt_expand_loc): Adjust to pass arguments in
expand_loc_callback_data structure.
(vt_expand_loc_dummy): New function.
(emitted_notes): New variable.
(emit_note_insn_var_location): For VALUEs and DEBUG_EXPR_DECLs
that weren't used for any other decl in current
emit_notes_for_changes call call vt_expand_loc_dummy to update
cur_loc. For -fno-var-tracking-assignments, set cur_loc to
first loc_chain location if NULL before. Always use just
cur_loc instead of first loc_chain location. When cur_loc_changed
is false, when not --enable-checking=rtl just don't emit any note.
When rtl checking, compute the note and assert it is the same
as previous note. Clear cur_loc_changed and in_changed_variables
at the end before removing from changed_variables.
(check_changed_vars_3): New function.
(emit_notes_for_changes): Traverse changed_vars to call
check_changed_vars_3 on each changed var.
(emit_notes_for_differences_1): Clear cur_loc_changed and
in_changed_variables. Recompute cur_loc of new_var.
(emit_notes_for_differences_2): Clear cur_loc if new variable
appears.
(vt_emit_notes): Initialize and destroy emitted_notes.
2010-03-07 Bernd Schmidt <bernd.schmidt@analog.com>
PR rtl-optimization/42220
......
......@@ -3031,7 +3031,7 @@ var-tracking.o : var-tracking.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(RTL_H) $(TREE_H) hard-reg-set.h insn-config.h reload.h $(FLAGS_H) \
$(BASIC_BLOCK_H) output.h sbitmap.h alloc-pool.h $(FIBHEAP_H) $(HASHTAB_H) \
$(REGS_H) $(EXPR_H) $(TIMEVAR_H) $(TREE_PASS_H) $(TREE_FLOW_H) \
cselib.h $(TARGET_H) $(TOPLEV_H) $(PARAMS_H) $(DIAGNOSTIC_H)
cselib.h $(TARGET_H) $(TOPLEV_H) $(PARAMS_H) $(DIAGNOSTIC_H) pointer-set.h
profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(TREE_H) $(FLAGS_H) output.h $(REGS_H) $(EXPR_H) $(FUNCTION_H) \
$(TOPLEV_H) $(COVERAGE_H) $(TREE_FLOW_H) value-prof.h cfghooks.h \
......
......@@ -69,6 +69,7 @@ struct expand_value_data
bitmap regs_active;
cselib_expand_callback callback;
void *callback_arg;
bool dummy;
};
static rtx cselib_expand_value_rtx_1 (rtx, struct expand_value_data *, int);
......@@ -1069,6 +1070,7 @@ cselib_expand_value_rtx (rtx orig, bitmap regs_active, int max_depth)
evd.regs_active = regs_active;
evd.callback = NULL;
evd.callback_arg = NULL;
evd.dummy = false;
return cselib_expand_value_rtx_1 (orig, &evd, max_depth);
}
......@@ -1088,10 +1090,29 @@ cselib_expand_value_rtx_cb (rtx orig, bitmap regs_active, int max_depth,
evd.regs_active = regs_active;
evd.callback = cb;
evd.callback_arg = data;
evd.dummy = false;
return cselib_expand_value_rtx_1 (orig, &evd, max_depth);
}
/* Similar to cselib_expand_value_rtx_cb, but no rtxs are actually copied
or simplified. Useful to find out whether cselib_expand_value_rtx_cb
would return NULL or non-NULL, without allocating new rtx. */
bool
cselib_dummy_expand_value_rtx_cb (rtx orig, bitmap regs_active, int max_depth,
cselib_expand_callback cb, void *data)
{
struct expand_value_data evd;
evd.regs_active = regs_active;
evd.callback = cb;
evd.callback_arg = data;
evd.dummy = true;
return cselib_expand_value_rtx_1 (orig, &evd, max_depth) != NULL;
}
/* Internal implementation of cselib_expand_value_rtx and
cselib_expand_value_rtx_cb. */
......@@ -1249,6 +1270,9 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd,
that all fields need copying, and then clear the fields that should
not be copied. That is the sensible default behavior, and forces
us to explicitly document why we are *not* copying a flag. */
if (evd->dummy)
copy = NULL;
else
copy = shallow_copy_rtx (orig);
format_ptr = GET_RTX_FORMAT (code);
......@@ -1263,6 +1287,7 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd,
max_depth - 1);
if (!result)
return NULL;
if (copy)
XEXP (copy, i) = result;
}
break;
......@@ -1271,13 +1296,15 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd,
case 'V':
if (XVEC (orig, i) != NULL)
{
if (copy)
XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
for (j = 0; j < XVECLEN (copy, i); j++)
for (j = 0; j < XVECLEN (orig, i); j++)
{
rtx result = cselib_expand_value_rtx_1 (XVECEXP (orig, i, j),
evd, max_depth - 1);
if (!result)
return NULL;
if (copy)
XVECEXP (copy, i, j) = result;
}
}
......@@ -1299,6 +1326,9 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd,
gcc_unreachable ();
}
if (evd->dummy)
return orig;
mode = GET_MODE (copy);
/* If an operand has been simplified into CONST_INT, which doesn't
have a mode and the mode isn't derivable from whole rtx's mode,
......
......@@ -81,7 +81,9 @@ extern int references_value_p (const_rtx, int);
extern rtx cselib_expand_value_rtx (rtx, bitmap, int);
typedef rtx (*cselib_expand_callback)(rtx, bitmap, int, void *);
extern rtx cselib_expand_value_rtx_cb (rtx, bitmap, int,
cselib_expand_callback, void*);
cselib_expand_callback, void *);
extern bool cselib_dummy_expand_value_rtx_cb (rtx, bitmap, int,
cselib_expand_callback, void *);
extern rtx cselib_subst_to_values (rtx);
extern void cselib_invalidate_rtx (rtx);
......
......@@ -112,6 +112,7 @@
#include "toplev.h"
#include "params.h"
#include "diagnostic.h"
#include "pointer-set.h"
/* var-tracking.c assumes that tree code with the same value as VALUE rtx code
has no chance to appear in REG_EXPR/MEM_EXPRs and isn't a decl.
......@@ -324,7 +325,16 @@ typedef struct variable_def
int refcount;
/* Number of variable parts. */
int n_var_parts;
char n_var_parts;
/* True if this variable changed (any of its) cur_loc fields
during the current emit_notes_for_changes resp.
emit_notes_for_differences call. */
bool cur_loc_changed;
/* True if this variable_def struct is currently in the
changed_variables hash table. */
bool in_changed_variables;
/* The variable parts. */
variable_part var_part[1];
......@@ -429,14 +439,13 @@ static void dataflow_set_clear (dataflow_set *);
static void dataflow_set_copy (dataflow_set *, dataflow_set *);
static int variable_union_info_cmp_pos (const void *, const void *);
static int variable_union (void **, void *);
static int variable_canonicalize (void **, void *);
static void dataflow_set_union (dataflow_set *, dataflow_set *);
static location_chain find_loc_in_1pdv (rtx, variable, htab_t);
static bool canon_value_cmp (rtx, rtx);
static int loc_cmp (rtx, rtx);
static bool variable_part_different_p (variable_part *, variable_part *);
static bool onepart_variable_different_p (variable, variable);
static bool variable_different_p (variable, variable, bool);
static bool variable_different_p (variable, variable);
static int dataflow_set_different_1 (void **, void *);
static bool dataflow_set_different (dataflow_set *, dataflow_set *);
static void dataflow_set_destroy (dataflow_set *);
......@@ -1056,6 +1065,16 @@ shared_hash_htab (shared_hash vars)
return vars->htab;
}
/* Return true if VAR is shared, or maybe because VARS is shared. */
static inline bool
shared_var_p (variable var, shared_hash vars)
{
/* Don't count an entry in the changed_variables table as a duplicate. */
return ((var->refcount > 1 + (int) var->in_changed_variables)
|| shared_hash_shared (vars));
}
/* Copy variables into a new hash table. */
static shared_hash
......@@ -1195,6 +1214,9 @@ unshare_variable (dataflow_set *set, void **slot, variable var,
new_var->refcount = 1;
var->refcount--;
new_var->n_var_parts = var->n_var_parts;
new_var->cur_loc_changed = var->cur_loc_changed;
var->cur_loc_changed = false;
new_var->in_changed_variables = false;
if (! flag_var_tracking_uninit)
initialized = VAR_INIT_STATUS_INITIALIZED;
......@@ -1226,12 +1248,7 @@ unshare_variable (dataflow_set *set, void **slot, variable var,
nextp = &new_lc->next;
}
/* We are at the basic block boundary when copying variable description
so set the CUR_LOC to be the first element of the chain. */
if (new_var->var_part[i].loc_chain)
new_var->var_part[i].cur_loc = new_var->var_part[i].loc_chain->loc;
else
new_var->var_part[i].cur_loc = NULL;
new_var->var_part[i].cur_loc = var->var_part[i].cur_loc;
}
dst_can_be_shared = false;
......@@ -1240,6 +1257,17 @@ unshare_variable (dataflow_set *set, void **slot, variable var,
else if (set->traversed_vars && set->vars != set->traversed_vars)
slot = shared_hash_find_slot_noinsert (set->vars, var->dv);
*slot = new_var;
if (var->in_changed_variables)
{
void **cslot
= htab_find_slot_with_hash (changed_variables, var->dv,
dv_htab_hash (var->dv), NO_INSERT);
gcc_assert (*cslot == (void *) var);
var->in_changed_variables = false;
variable_htab_free (var);
*cslot = new_var;
new_var->in_changed_variables = true;
}
return slot;
}
......@@ -1791,23 +1819,6 @@ variable_union (void **slot, void *data)
*dstp = src;
/* If CUR_LOC of some variable part is not the first element of
the location chain we are going to change it so we have to make
a copy of the variable. */
for (k = 0; k < src->n_var_parts; k++)
{
gcc_assert (!src->var_part[k].loc_chain
== !src->var_part[k].cur_loc);
if (src->var_part[k].loc_chain)
{
gcc_assert (src->var_part[k].cur_loc);
if (src->var_part[k].cur_loc != src->var_part[k].loc_chain->loc)
break;
}
}
if (k < src->n_var_parts)
dstp = unshare_variable (set, dstp, src, VAR_INIT_STATUS_UNKNOWN);
/* Continue traversing the hash table. */
return 1;
}
......@@ -1841,7 +1852,7 @@ variable_union (void **slot, void *data)
{
location_chain nnode;
if (dst->refcount != 1 || shared_hash_shared (set->vars))
if (shared_var_p (dst, set->vars))
{
dstp = unshare_variable (set, dstp, dst,
VAR_INIT_STATUS_INITIALIZED);
......@@ -1871,8 +1882,6 @@ variable_union (void **slot, void *data)
dnode = *nodep;
}
dst->var_part[0].cur_loc = dst->var_part[0].loc_chain->loc;
return 1;
}
......@@ -1897,8 +1906,7 @@ variable_union (void **slot, void *data)
thus there are at most MAX_VAR_PARTS different offsets. */
gcc_assert (dv_onepart_p (dst->dv) ? k == 1 : k <= MAX_VAR_PARTS);
if ((dst->refcount > 1 || shared_hash_shared (set->vars))
&& dst->n_var_parts != k)
if (dst->n_var_parts != k && shared_var_p (dst, set->vars))
{
dstp = unshare_variable (set, dstp, dst, VAR_INIT_STATUS_UNKNOWN);
dst = (variable)*dstp;
......@@ -1925,7 +1933,7 @@ variable_union (void **slot, void *data)
/* If DST is shared compare the location chains.
If they are different we will modify the chain in DST with
high probability so make a copy of DST. */
if (dst->refcount > 1 || shared_hash_shared (set->vars))
if (shared_var_p (dst, set->vars))
{
for (node = src->var_part[i].loc_chain,
node2 = dst->var_part[j].loc_chain; node && node2;
......@@ -2139,12 +2147,6 @@ variable_union (void **slot, void *data)
dst->var_part[k].offset = src->var_part[i].offset;
i--;
}
/* We are at the basic block boundary when computing union
so set the CUR_LOC to be the first element of the chain. */
if (dst->var_part[k].loc_chain)
dst->var_part[k].cur_loc = dst->var_part[k].loc_chain->loc;
else
dst->var_part[k].cur_loc = NULL;
}
......@@ -2165,39 +2167,6 @@ variable_union (void **slot, void *data)
return 1;
}
/* Like variable_union, but only used when doing dataflow_set_union
into an empty hashtab. To allow sharing, dst is initially shared
with src (so all variables are "copied" from src to dst hashtab),
so only unshare_variable for variables that need canonicalization
are needed. */
static int
variable_canonicalize (void **slot, void *data)
{
variable src;
dataflow_set *set = (dataflow_set *) data;
int k;
src = *(variable *) slot;
/* If CUR_LOC of some variable part is not the first element of
the location chain we are going to change it so we have to make
a copy of the variable. */
for (k = 0; k < src->n_var_parts; k++)
{
gcc_assert (!src->var_part[k].loc_chain == !src->var_part[k].cur_loc);
if (src->var_part[k].loc_chain)
{
gcc_assert (src->var_part[k].cur_loc);
if (src->var_part[k].cur_loc != src->var_part[k].loc_chain->loc)
break;
}
}
if (k < src->n_var_parts)
slot = unshare_variable (set, slot, src, VAR_INIT_STATUS_UNKNOWN);
return 1;
}
/* Compute union of dataflow sets SRC and DST and store it to DST. */
static void
......@@ -2212,9 +2181,6 @@ dataflow_set_union (dataflow_set *dst, dataflow_set *src)
{
shared_hash_destroy (dst->vars);
dst->vars = shared_hash_copy (src->vars);
dst->traversed_vars = dst->vars;
htab_traverse (shared_hash_htab (dst->vars), variable_canonicalize, dst);
dst->traversed_vars = NULL;
}
else
htab_traverse (shared_hash_htab (src->vars), variable_union, dst);
......@@ -2479,6 +2445,18 @@ loc_cmp (rtx x, rtx y)
gcc_assert (GET_MODE (x) == GET_MODE (y));
if (GET_CODE (x) == DEBUG_EXPR)
{
if (DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x))
< DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (y)))
return -1;
#ifdef ENABLE_CHECKING
gcc_assert (DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x))
> DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (y)));
#endif
return 1;
}
fmt = GET_RTX_FORMAT (code);
for (i = 0; i < GET_RTX_LENGTH (code); i++)
switch (fmt[i])
......@@ -2718,6 +2696,13 @@ canonicalize_loc_order_check (void **slot, void *data ATTRIBUTE_UNUSED)
decl_or_value dv = var->dv;
location_chain node, next;
#ifdef ENABLE_RTL_CHECKING
int i;
for (i = 0; i < var->n_var_parts; i++)
gcc_assert (var->var_part[0].cur_loc == NULL);
gcc_assert (!var->cur_loc_changed && !var->in_changed_variables);
#endif
if (!dv_onepart_p (dv))
return 1;
......@@ -3080,9 +3065,11 @@ variable_merge_over_cur (void **s1slot, void *data)
dvar->dv = dv;
dvar->refcount = 1;
dvar->n_var_parts = 1;
dvar->cur_loc_changed = false;
dvar->in_changed_variables = false;
dvar->var_part[0].offset = 0;
dvar->var_part[0].loc_chain = node;
dvar->var_part[0].cur_loc = node->loc;
dvar->var_part[0].cur_loc = NULL;
dstslot
= shared_hash_find_slot_unshare_1 (&dst->vars, dv, dvhash,
......@@ -3212,6 +3199,8 @@ variable_merge_over_cur (void **s1slot, void *data)
var->dv = dv;
var->refcount = 1;
var->n_var_parts = 1;
var->cur_loc_changed = false;
var->in_changed_variables = false;
var->var_part[0].offset = 0;
var->var_part[0].loc_chain = NULL;
var->var_part[0].cur_loc = NULL;
......@@ -3248,11 +3237,7 @@ variable_merge_over_cur (void **s1slot, void *data)
dst_can_be_shared = false;
}
else
{
if (dvar->refcount == 1)
dvar->var_part[0].cur_loc = dvar->var_part[0].loc_chain->loc;
dst_can_be_shared = false;
}
return 1;
}
......@@ -3276,7 +3261,7 @@ variable_merge_over_src (void **s2slot, void *data)
void **dstp = shared_hash_find_slot (dst->vars, dv);
*dstp = s2var;
s2var->refcount++;
return variable_canonicalize (dstp, dst);
return 1;
}
dsm->src_onepart_cnt++;
......@@ -3746,13 +3731,14 @@ dataflow_set_preserve_mem_locs (void **slot, void *data)
{
tree decl = dv_as_decl (var->dv);
location_chain loc, *locp;
bool changed = false;
if (!var->n_var_parts)
return 1;
gcc_assert (var->n_var_parts == 1);
if (var->refcount > 1 || shared_hash_shared (set->vars))
if (shared_var_p (var, set->vars))
{
for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
{
......@@ -3809,6 +3795,12 @@ dataflow_set_preserve_mem_locs (void **slot, void *data)
{
if (old_loc != loc->loc && emit_notes)
{
if (old_loc == var->var_part[0].cur_loc)
{
changed = true;
var->var_part[0].cur_loc = NULL;
var->cur_loc_changed = true;
}
add_value_chains (var->dv, loc->loc);
remove_value_chains (var->dv, old_loc);
}
......@@ -3817,7 +3809,15 @@ dataflow_set_preserve_mem_locs (void **slot, void *data)
}
if (emit_notes)
{
remove_value_chains (var->dv, old_loc);
if (old_loc == var->var_part[0].cur_loc)
{
changed = true;
var->var_part[0].cur_loc = NULL;
var->cur_loc_changed = true;
}
}
*locp = loc->next;
pool_free (loc_chain_pool, loc);
}
......@@ -3827,8 +3827,10 @@ dataflow_set_preserve_mem_locs (void **slot, void *data)
var->n_var_parts--;
if (emit_notes && dv_is_value_p (var->dv))
remove_cselib_value_chains (var->dv);
variable_was_changed (var, set);
changed = true;
}
if (changed)
variable_was_changed (var, set);
}
return 1;
......@@ -3850,7 +3852,7 @@ dataflow_set_remove_mem_locs (void **slot, void *data)
gcc_assert (var->n_var_parts == 1);
if (var->refcount > 1 || shared_hash_shared (set->vars))
if (shared_var_p (var, set->vars))
{
for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
if (GET_CODE (loc->loc) == MEM
......@@ -3881,9 +3883,12 @@ dataflow_set_remove_mem_locs (void **slot, void *data)
/* If we have deleted the location which was last emitted
we have to emit new location so add the variable to set
of changed variables. */
if (var->var_part[0].cur_loc
&& rtx_equal_p (loc->loc, var->var_part[0].cur_loc))
if (var->var_part[0].cur_loc == loc->loc)
{
changed = true;
var->var_part[0].cur_loc = NULL;
var->cur_loc_changed = true;
}
pool_free (loc_chain_pool, loc);
}
......@@ -3892,15 +3897,11 @@ dataflow_set_remove_mem_locs (void **slot, void *data)
var->n_var_parts--;
if (emit_notes && dv_is_value_p (var->dv))
remove_cselib_value_chains (var->dv);
gcc_assert (changed);
changed = true;
}
if (changed)
{
if (var->n_var_parts && var->var_part[0].loc_chain)
var->var_part[0].cur_loc = var->var_part[0].loc_chain->loc;
variable_was_changed (var, set);
}
}
return 1;
}
......@@ -3987,13 +3988,10 @@ onepart_variable_different_p (variable var1, variable var2)
return lc1 != lc2;
}
/* Return true if variables VAR1 and VAR2 are different.
If COMPARE_CURRENT_LOCATION is true compare also the cur_loc of each
variable part. */
/* Return true if variables VAR1 and VAR2 are different. */
static bool
variable_different_p (variable var1, variable var2,
bool compare_current_location)
variable_different_p (variable var1, variable var2)
{
int i;
......@@ -4007,16 +4005,6 @@ variable_different_p (variable var1, variable var2,
{
if (var1->var_part[i].offset != var2->var_part[i].offset)
return true;
if (compare_current_location)
{
if (!((REG_P (var1->var_part[i].cur_loc)
&& REG_P (var2->var_part[i].cur_loc)
&& (REGNO (var1->var_part[i].cur_loc)
== REGNO (var2->var_part[i].cur_loc)))
|| rtx_equal_p (var1->var_part[i].cur_loc,
var2->var_part[i].cur_loc)))
return true;
}
/* One-part values have locations in a canonical order. */
if (i == 0 && var1->var_part[i].offset == 0 && dv_onepart_p (var1->dv))
{
......@@ -4058,7 +4046,7 @@ dataflow_set_different_1 (void **slot, void *data)
return 0;
}
if (variable_different_p (var1, var2, false))
if (variable_different_p (var1, var2))
{
dataflow_set_different_value = true;
......@@ -5978,6 +5966,7 @@ variable_was_changed (variable var, dataflow_set *set)
if (emit_notes)
{
void **slot;
bool old_cur_loc_changed = false;
/* Remember this decl or VALUE has been added to changed_variables. */
set_dv_changed (var->dv, true);
......@@ -5986,6 +5975,14 @@ variable_was_changed (variable var, dataflow_set *set)
var->dv,
hash, INSERT);
if (*slot)
{
variable old_var = (variable) *slot;
gcc_assert (old_var->in_changed_variables);
old_var->in_changed_variables = false;
old_cur_loc_changed = old_var->cur_loc_changed;
variable_htab_free (*slot);
}
if (set && var->n_var_parts == 0)
{
variable empty_var;
......@@ -5994,12 +5991,19 @@ variable_was_changed (variable var, dataflow_set *set)
empty_var->dv = var->dv;
empty_var->refcount = 1;
empty_var->n_var_parts = 0;
empty_var->cur_loc_changed = true;
empty_var->in_changed_variables = true;
*slot = empty_var;
goto drop_var;
}
else
{
var->refcount++;
var->in_changed_variables = true;
/* If within processing one uop a variable is deleted
and then readded, we need to assume it has changed. */
if (old_cur_loc_changed)
var->cur_loc_changed = true;
*slot = var;
}
}
......@@ -6082,6 +6086,8 @@ set_slot_part (dataflow_set *set, rtx loc, void **slot,
var->dv = dv;
var->refcount = 1;
var->n_var_parts = 1;
var->cur_loc_changed = false;
var->in_changed_variables = false;
var->var_part[0].offset = offset;
var->var_part[0].loc_chain = NULL;
var->var_part[0].cur_loc = NULL;
......@@ -6179,7 +6185,7 @@ set_slot_part (dataflow_set *set, rtx loc, void **slot,
if (r == 0)
return slot;
if (var->refcount > 1 || shared_hash_shared (set->vars))
if (shared_var_p (var, set->vars))
{
slot = unshare_variable (set, slot, var, initialized);
var = (variable)*slot;
......@@ -6218,7 +6224,7 @@ set_slot_part (dataflow_set *set, rtx loc, void **slot,
else
{
/* We have to make a copy of a shared variable. */
if (var->refcount > 1 || shared_hash_shared (set->vars))
if (shared_var_p (var, set->vars))
{
slot = unshare_variable (set, slot, var, initialized);
var = (variable)*slot;
......@@ -6230,7 +6236,7 @@ set_slot_part (dataflow_set *set, rtx loc, void **slot,
/* We have not found the location part, new one will be created. */
/* We have to make a copy of the shared variable. */
if (var->refcount > 1 || shared_hash_shared (set->vars))
if (shared_var_p (var, set->vars))
{
slot = unshare_variable (set, slot, var, initialized);
var = (variable)*slot;
......@@ -6267,6 +6273,11 @@ set_slot_part (dataflow_set *set, rtx loc, void **slot,
initialized = node->init;
if (node->set_src != NULL && set_src == NULL)
set_src = node->set_src;
if (var->var_part[pos].cur_loc == node->loc)
{
var->var_part[pos].cur_loc = NULL;
var->cur_loc_changed = true;
}
pool_free (loc_chain_pool, node);
*nextp = next;
break;
......@@ -6291,10 +6302,7 @@ set_slot_part (dataflow_set *set, rtx loc, void **slot,
/* If no location was emitted do so. */
if (var->var_part[pos].cur_loc == NULL)
{
var->var_part[pos].cur_loc = loc;
variable_was_changed (var, set);
}
return slot;
}
......@@ -6422,7 +6430,7 @@ delete_slot_part (dataflow_set *set, rtx loc, void **slot,
location_chain *nextp;
bool changed;
if (var->refcount > 1 || shared_hash_shared (set->vars))
if (shared_var_p (var, set->vars))
{
/* If the variable contains the location part we have to
make a copy of the variable. */
......@@ -6442,6 +6450,7 @@ delete_slot_part (dataflow_set *set, rtx loc, void **slot,
}
/* Delete the location part. */
changed = false;
nextp = &var->var_part[pos].loc_chain;
for (node = *nextp; node; node = next)
{
......@@ -6452,36 +6461,33 @@ delete_slot_part (dataflow_set *set, rtx loc, void **slot,
{
if (emit_notes && pos == 0 && dv_onepart_p (var->dv))
remove_value_chains (var->dv, node->loc);
pool_free (loc_chain_pool, node);
*nextp = next;
break;
}
else
nextp = &node->next;
}
/* If we have deleted the location which was last emitted
we have to emit new location so add the variable to set
of changed variables. */
if (var->var_part[pos].cur_loc
&& ((REG_P (loc)
&& REG_P (var->var_part[pos].cur_loc)
&& REGNO (loc) == REGNO (var->var_part[pos].cur_loc))
|| rtx_equal_p (loc, var->var_part[pos].cur_loc)))
if (var->var_part[pos].cur_loc == node->loc)
{
changed = true;
if (var->var_part[pos].loc_chain)
var->var_part[pos].cur_loc = var->var_part[pos].loc_chain->loc;
var->var_part[pos].cur_loc = NULL;
var->cur_loc_changed = true;
}
pool_free (loc_chain_pool, node);
*nextp = next;
break;
}
else
changed = false;
nextp = &node->next;
}
if (var->var_part[pos].loc_chain == NULL)
{
gcc_assert (changed);
changed = true;
var->n_var_parts--;
if (emit_notes && var->n_var_parts == 0 && dv_is_value_p (var->dv))
if (emit_notes)
{
var->cur_loc_changed = true;
if (var->n_var_parts == 0 && dv_is_value_p (var->dv))
remove_cselib_value_chains (var->dv);
}
while (pos < var->n_var_parts)
{
var->var_part[pos] = var->var_part[pos + 1];
......@@ -6510,6 +6516,27 @@ delete_variable_part (dataflow_set *set, rtx loc, decl_or_value dv,
slot = delete_slot_part (set, loc, slot, offset);
}
/* Structure for passing some other parameters to function
vt_expand_loc_callback. */
struct expand_loc_callback_data
{
/* The variables and values active at this point. */
htab_t vars;
/* True in vt_expand_loc_dummy calls, no rtl should be allocated.
Non-NULL should be returned if vt_expand_loc would return
non-NULL in that case, NULL otherwise. cur_loc_changed should be
computed and cur_loc recomputed when possible (but just once
per emit_notes_for_changes call). */
bool dummy;
/* True if expansion of subexpressions had to recompute some
VALUE/DEBUG_EXPR_DECL's cur_loc or used a VALUE/DEBUG_EXPR_DECL
whose cur_loc has been already recomputed during current
emit_notes_for_changes call. */
bool cur_loc_changed;
};
/* Callback for cselib_expand_value, that looks for expressions
holding the value in the var-tracking hash tables. Return X for
standard processing, anything else is to be used as-is. */
......@@ -6517,7 +6544,10 @@ delete_variable_part (dataflow_set *set, rtx loc, decl_or_value dv,
static rtx
vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
{
htab_t vars = (htab_t)data;
struct expand_loc_callback_data *elcd
= (struct expand_loc_callback_data *) data;
bool dummy = elcd->dummy;
bool cur_loc_changed = elcd->cur_loc_changed;
decl_or_value dv;
variable var;
location_chain loc;
......@@ -6526,11 +6556,6 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
switch (GET_CODE (x))
{
case SUBREG:
subreg = SUBREG_REG (x);
if (GET_CODE (SUBREG_REG (x)) != VALUE)
return x;
subreg = cselib_expand_value_rtx_cb (SUBREG_REG (x), regs,
max_depth - 1,
vt_expand_loc_callback, data);
......@@ -6538,13 +6563,16 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
if (!subreg)
return NULL;
if (dummy)
return pc_rtx;
result = simplify_gen_subreg (GET_MODE (x), subreg,
GET_MODE (SUBREG_REG (x)),
SUBREG_BYTE (x));
/* Invalid SUBREGs are ok in debug info. ??? We could try
alternate expansions for the VALUE as well. */
if (!result && (REG_P (subreg) || MEM_P (subreg)))
if (!result)
result = gen_rtx_raw_SUBREG (GET_MODE (x), subreg, SUBREG_BYTE (x));
return result;
......@@ -6566,26 +6594,79 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
if (VALUE_RECURSED_INTO (x))
return NULL;
var = (variable) htab_find_with_hash (vars, dv, dv_htab_hash (dv));
var = (variable) htab_find_with_hash (elcd->vars, dv, dv_htab_hash (dv));
if (!var)
{
if (dummy && dv_changed_p (dv))
elcd->cur_loc_changed = true;
return xret;
}
if (var->n_var_parts == 0)
{
if (dummy)
elcd->cur_loc_changed = true;
return xret;
}
gcc_assert (var->n_var_parts == 1);
VALUE_RECURSED_INTO (x) = true;
result = NULL;
if (var->var_part[0].cur_loc)
{
if (dummy)
{
if (cselib_dummy_expand_value_rtx_cb (var->var_part[0].cur_loc, regs,
max_depth,
vt_expand_loc_callback, data))
result = pc_rtx;
}
else
result = cselib_expand_value_rtx_cb (var->var_part[0].cur_loc, regs,
max_depth,
vt_expand_loc_callback, data);
if (result)
set_dv_changed (dv, false);
}
if (!result && dv_changed_p (dv))
{
set_dv_changed (dv, false);
for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
if (loc->loc == var->var_part[0].cur_loc)
continue;
else if (dummy)
{
elcd->cur_loc_changed = cur_loc_changed;
if (cselib_dummy_expand_value_rtx_cb (loc->loc, regs, max_depth,
vt_expand_loc_callback,
data))
{
result = pc_rtx;
break;
}
else
{
result = cselib_expand_value_rtx_cb (loc->loc, regs, max_depth,
vt_expand_loc_callback, vars);
vt_expand_loc_callback,
data);
if (result)
break;
}
}
if (dummy && (result || var->var_part[0].cur_loc))
var->cur_loc_changed = true;
var->var_part[0].cur_loc = loc ? loc->loc : NULL_RTX;
}
if (dummy)
{
if (var->cur_loc_changed)
elcd->cur_loc_changed = true;
else if (!result && var->var_part[0].cur_loc == NULL_RTX)
elcd->cur_loc_changed = cur_loc_changed;
}
VALUE_RECURSED_INTO (x) = false;
if (result)
......@@ -6600,18 +6681,46 @@ vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
static rtx
vt_expand_loc (rtx loc, htab_t vars)
{
struct expand_loc_callback_data data;
if (!MAY_HAVE_DEBUG_INSNS)
return loc;
data.vars = vars;
data.dummy = false;
data.cur_loc_changed = false;
loc = cselib_expand_value_rtx_cb (loc, scratch_regs, 5,
vt_expand_loc_callback, vars);
vt_expand_loc_callback, &data);
if (loc && MEM_P (loc))
loc = targetm.delegitimize_address (loc);
return loc;
}
/* Like vt_expand_loc, but only return true/false (whether vt_expand_loc
would succeed or not, without actually allocating new rtxes. */
static bool
vt_expand_loc_dummy (rtx loc, htab_t vars, bool *pcur_loc_changed)
{
struct expand_loc_callback_data data;
bool ret;
gcc_assert (MAY_HAVE_DEBUG_INSNS);
data.vars = vars;
data.dummy = true;
data.cur_loc_changed = false;
ret = cselib_dummy_expand_value_rtx_cb (loc, scratch_regs, 5,
vt_expand_loc_callback, &data);
*pcur_loc_changed = data.cur_loc_changed;
return ret;
}
#ifdef ENABLE_RTL_CHECKING
/* Used to verify that cur_loc_changed updating is safe. */
static struct pointer_map_t *emitted_notes;
#endif
/* Emit the NOTE_INSN_VAR_LOCATION for variable *VARP. DATA contains
additional parameters: WHERE specifies whether the note shall be emitted
before or after instruction INSN. */
......@@ -6623,7 +6732,7 @@ emit_note_insn_var_location (void **varp, void *data)
rtx insn = ((emit_note_data *)data)->insn;
enum emit_note_where where = ((emit_note_data *)data)->where;
htab_t vars = ((emit_note_data *)data)->vars;
rtx note;
rtx note, note_vl;
int i, j, n_var_parts;
bool complete;
enum var_init_status initialized = VAR_INIT_STATUS_UNINITIALIZED;
......@@ -6632,20 +6741,34 @@ emit_note_insn_var_location (void **varp, void *data)
HOST_WIDE_INT offsets[MAX_VAR_PARTS];
rtx loc[MAX_VAR_PARTS];
tree decl;
location_chain lc;
if (dv_is_value_p (var->dv))
goto clear;
goto value_or_debug_decl;
decl = dv_as_decl (var->dv);
if (TREE_CODE (decl) == DEBUG_EXPR_DECL)
goto clear;
gcc_assert (decl);
goto value_or_debug_decl;
complete = true;
last_limit = 0;
n_var_parts = 0;
if (!MAY_HAVE_DEBUG_STMTS)
{
for (i = 0; i < var->n_var_parts; i++)
if (var->var_part[i].cur_loc == NULL && var->var_part[i].loc_chain)
{
var->var_part[i].cur_loc = var->var_part[i].loc_chain->loc;
var->cur_loc_changed = true;
}
if (var->n_var_parts == 0)
var->cur_loc_changed = true;
}
#ifndef ENABLE_RTL_CHECKING
if (!var->cur_loc_changed)
goto clear;
#endif
for (i = 0; i < var->n_var_parts; i++)
{
enum machine_mode mode, wider_mode;
......@@ -6659,15 +6782,26 @@ emit_note_insn_var_location (void **varp, void *data)
else if (last_limit > var->var_part[i].offset)
continue;
offsets[n_var_parts] = var->var_part[i].offset;
loc2 = vt_expand_loc (var->var_part[i].loc_chain->loc, vars);
if (!var->var_part[i].cur_loc)
{
complete = false;
continue;
}
loc2 = vt_expand_loc (var->var_part[i].cur_loc, vars);
if (!loc2)
{
complete = false;
continue;
}
loc[n_var_parts] = loc2;
mode = GET_MODE (var->var_part[i].loc_chain->loc);
initialized = var->var_part[i].loc_chain->init;
mode = GET_MODE (var->var_part[i].cur_loc);
for (lc = var->var_part[i].loc_chain; lc; lc = lc->next)
if (var->var_part[i].cur_loc == lc->loc)
{
initialized = lc->init;
break;
}
gcc_assert (lc);
last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
/* Attempt to merge adjacent registers or memory. */
......@@ -6677,11 +6811,12 @@ emit_note_insn_var_location (void **varp, void *data)
break;
if (j < var->n_var_parts
&& wider_mode != VOIDmode
&& mode == GET_MODE (var->var_part[j].loc_chain->loc)
&& var->var_part[j].cur_loc
&& mode == GET_MODE (var->var_part[j].cur_loc)
&& (REG_P (loc[n_var_parts]) || MEM_P (loc[n_var_parts]))
&& (loc2 = vt_expand_loc (var->var_part[j].loc_chain->loc, vars))
&& GET_CODE (loc[n_var_parts]) == GET_CODE (loc2)
&& last_limit == var->var_part[j].offset)
&& last_limit == var->var_part[j].offset
&& (loc2 = vt_expand_loc (var->var_part[j].cur_loc, vars))
&& GET_CODE (loc[n_var_parts]) == GET_CODE (loc2))
{
rtx new_loc = NULL;
......@@ -6740,30 +6875,19 @@ emit_note_insn_var_location (void **varp, void *data)
if ((unsigned HOST_WIDE_INT) last_limit < TREE_INT_CST_LOW (type_size_unit))
complete = false;
if (where != EMIT_NOTE_BEFORE_INSN)
{
note = emit_note_after (NOTE_INSN_VAR_LOCATION, insn);
if (where == EMIT_NOTE_AFTER_CALL_INSN)
NOTE_DURING_CALL_P (note) = true;
}
else
note = emit_note_before (NOTE_INSN_VAR_LOCATION, insn);
if (! flag_var_tracking_uninit)
initialized = VAR_INIT_STATUS_INITIALIZED;
note_vl = NULL_RTX;
if (!complete)
{
NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, decl,
NULL_RTX, (int) initialized);
}
note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl, NULL_RTX,
(int) initialized);
else if (n_var_parts == 1)
{
rtx expr_list
= gen_rtx_EXPR_LIST (VOIDmode, loc[0], GEN_INT (offsets[0]));
NOTE_VAR_LOCATION (note) = gen_rtx_VAR_LOCATION (VOIDmode, decl,
expr_list,
note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl, expr_list,
(int) initialized);
}
else if (n_var_parts)
......@@ -6776,17 +6900,64 @@ 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, decl,
parallel,
(int) initialized);
note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl,
parallel, (int) initialized);
}
#ifdef ENABLE_RTL_CHECKING
if (note_vl)
{
void **note_slot = pointer_map_insert (emitted_notes, decl);
rtx pnote = (rtx) *note_slot;
if (!var->cur_loc_changed && (pnote || PAT_VAR_LOCATION_LOC (note_vl)))
{
gcc_assert (pnote);
gcc_assert (rtx_equal_p (PAT_VAR_LOCATION_LOC (pnote),
PAT_VAR_LOCATION_LOC (note_vl)));
}
*note_slot = (void *) note_vl;
}
if (!var->cur_loc_changed)
goto clear;
#endif
if (where != EMIT_NOTE_BEFORE_INSN)
{
note = emit_note_after (NOTE_INSN_VAR_LOCATION, insn);
if (where == EMIT_NOTE_AFTER_CALL_INSN)
NOTE_DURING_CALL_P (note) = true;
}
else
note = emit_note_before (NOTE_INSN_VAR_LOCATION, insn);
NOTE_VAR_LOCATION (note) = note_vl;
clear:
set_dv_changed (var->dv, false);
var->cur_loc_changed = false;
gcc_assert (var->in_changed_variables);
var->in_changed_variables = false;
htab_clear_slot (changed_variables, varp);
/* Continue traversing the hash table. */
return 1;
value_or_debug_decl:
if (dv_changed_p (var->dv) && var->n_var_parts)
{
location_chain lc;
bool cur_loc_changed;
if (var->var_part[0].cur_loc
&& vt_expand_loc_dummy (var->var_part[0].cur_loc, vars,
&cur_loc_changed))
goto clear;
for (lc = var->var_part[0].loc_chain; lc; lc = lc->next)
if (lc->loc != var->var_part[0].cur_loc
&& vt_expand_loc_dummy (lc->loc, vars, &cur_loc_changed))
break;
var->var_part[0].cur_loc = lc ? lc->loc : NULL_RTX;
}
goto clear;
}
DEF_VEC_P (variable);
......@@ -6858,6 +7029,48 @@ check_changed_vars_2 (variable var, htab_t htab)
}
}
/* For each changed decl (except DEBUG_EXPR_DECLs) recompute
cur_loc if needed (and cur_loc of all VALUEs and DEBUG_EXPR_DECLs
it needs and are also in changed variables) and track whether
cur_loc (or anything it uses to compute location) had to change
during the current emit_notes_for_changes call. */
static int
check_changed_vars_3 (void **slot, void *data)
{
variable var = (variable) *slot;
htab_t vars = (htab_t) data;
int i;
location_chain lc;
bool cur_loc_changed;
if (dv_is_value_p (var->dv)
|| TREE_CODE (dv_as_decl (var->dv)) == DEBUG_EXPR_DECL)
return 1;
for (i = 0; i < var->n_var_parts; i++)
{
if (var->var_part[i].cur_loc
&& vt_expand_loc_dummy (var->var_part[i].cur_loc, vars,
&cur_loc_changed))
{
if (cur_loc_changed)
var->cur_loc_changed = true;
continue;
}
for (lc = var->var_part[i].loc_chain; lc; lc = lc->next)
if (lc->loc != var->var_part[i].cur_loc
&& vt_expand_loc_dummy (lc->loc, vars, &cur_loc_changed))
break;
if (lc || var->var_part[i].cur_loc)
var->cur_loc_changed = true;
var->var_part[i].cur_loc = lc ? lc->loc : NULL_RTX;
}
if (var->n_var_parts == 0)
var->cur_loc_changed = true;
return 1;
}
/* Emit NOTE_INSN_VAR_LOCATION note for each variable from a chain
CHANGED_VARIABLES and delete this chain. WHERE specifies whether the notes
shall be emitted before of after instruction INSN. */
......@@ -6881,6 +7094,7 @@ emit_notes_for_changes (rtx insn, enum emit_note_where where,
while (VEC_length (variable, changed_variables_stack) > 0)
check_changed_vars_2 (VEC_pop (variable, changed_variables_stack),
htab);
htab_traverse (changed_variables, check_changed_vars_3, htab);
}
data.insn = insn;
......@@ -6912,6 +7126,8 @@ emit_notes_for_differences_1 (void **slot, void *data)
empty_var->dv = old_var->dv;
empty_var->refcount = 0;
empty_var->n_var_parts = 0;
empty_var->cur_loc_changed = false;
empty_var->in_changed_variables = false;
if (dv_onepart_p (old_var->dv))
{
location_chain lc;
......@@ -6923,8 +7139,10 @@ emit_notes_for_differences_1 (void **slot, void *data)
remove_cselib_value_chains (old_var->dv);
}
variable_was_changed (empty_var, NULL);
/* Continue traversing the hash table. */
return 1;
}
else if (variable_different_p (old_var, new_var, true))
if (variable_different_p (old_var, new_var))
{
if (dv_onepart_p (old_var->dv))
{
......@@ -6949,6 +7167,33 @@ emit_notes_for_differences_1 (void **slot, void *data)
}
variable_was_changed (new_var, NULL);
}
/* Update cur_loc. */
if (old_var != new_var)
{
int i;
for (i = 0; i < new_var->n_var_parts; i++)
{
new_var->var_part[i].cur_loc = NULL;
if (old_var->n_var_parts != new_var->n_var_parts
|| old_var->var_part[i].offset != new_var->var_part[i].offset)
new_var->cur_loc_changed = true;
else if (old_var->var_part[i].cur_loc != NULL)
{
location_chain lc;
rtx cur_loc = old_var->var_part[i].cur_loc;
for (lc = new_var->var_part[i].loc_chain; lc; lc = lc->next)
if (lc->loc == cur_loc
|| rtx_equal_p (cur_loc, lc->loc))
{
new_var->var_part[i].cur_loc = lc->loc;
break;
}
if (lc == NULL)
new_var->cur_loc_changed = true;
}
}
}
/* Continue traversing the hash table. */
return 1;
......@@ -6968,6 +7213,7 @@ emit_notes_for_differences_2 (void **slot, void *data)
dv_htab_hash (new_var->dv));
if (!old_var)
{
int i;
/* Variable has appeared. */
if (dv_onepart_p (new_var->dv))
{
......@@ -6979,6 +7225,8 @@ emit_notes_for_differences_2 (void **slot, void *data)
if (dv_is_value_p (new_var->dv))
add_cselib_value_chains (new_var->dv);
}
for (i = 0; i < new_var->n_var_parts; i++)
new_var->var_part[i].cur_loc = NULL;
variable_was_changed (new_var, NULL);
}
......@@ -7283,6 +7531,9 @@ vt_emit_notes (void)
basic_block bb;
dataflow_set cur;
#ifdef ENABLE_RTL_CHECKING
emitted_notes = pointer_map_create ();
#endif
gcc_assert (!htab_elements (changed_variables));
/* Free memory occupied by the out hash tables, as they aren't used
......@@ -7324,6 +7575,9 @@ vt_emit_notes (void)
if (MAY_HAVE_DEBUG_INSNS)
VEC_free (variable, heap, changed_variables_stack);
#ifdef ENABLE_RTL_CHECKING
pointer_map_destroy (emitted_notes);
#endif
emit_notes = false;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment