[PATCH] Fix var-tracking cur_loc handling (PR debug/43176)
Richard Guenther
rguenther@suse.de
Sun Mar 7 15:50:00 GMT 2010
On Sat, 6 Mar 2010, Jakub Jelinek wrote:
> Hi!
>
> The problem in this PR is that var-tracking uses cur_loc field (of variable
> parts) to decide if a variable (or VALUE/DEBUG_EXPR_DECL some variable uses
> in computing its actual value) has changed (== a new location note needs to
> be emitted for it and the location of the variable recomputed), but what
> actually is emitted into the location might be very different from that.
> E.g. in vla-1.c (f2) on x86_64 the emitted note uses r12 register to compute
> array bound, but cur_loc says rdi register. At that point rdi and r12 hold
> the same value, but when a few insns later r12 is changed, and thus the
> expression is no longer correct, var-tracking doesn't notice, as it thinks
> the location is based on rdi register instead. When rdi finally is
> clobbered, a new location note is emitted.
>
> The following patch rewrites the cur_loc handling. cur_loc is now supposed
> to be always NULL before vt_emit_notes (mainly during vt_find_locations),
> is maintained only in the current variable set, set to location chain entry
> that was actually used to compute the location emitted into notes and at bb
> boundary is propagated to the variables in the new set (if the old cur_loc
> is in the new bb's in variables location chain, it is set to the new
> location chain's loc, otherwise it is reset).
> To avoid creating GC garbage, there is a new special variant of
> cselib_expand_value_rtx_cb that calls the callback with the same values as
> the normal routine would do, but doesn't actually create any new rtxs and
> attempt to simplify them, it only returns true whether normal
> cselib_expand_value_rtx_cb would return non-NULL and false if it would
> return NULL. This routine is used to decide which among the set of
> changed_variables in the current emit_notes_for_changes call need to
> actually change cur_loc. emit_note_insn_var_location then just uses the
> computed cur_loc location.
>
> The patch should decrease GC memory allocation during vt_emit_notes, because
> it won't emit notes for variables whose location didn't actually change.
>
> There are several bugfixes I've discovered when testing the patch, e.g.
> loc_cmp returned 0 (the same value) for (debug_expr D#1) and (debug_expr
> D#2), so at bb boundaries var-tracking failed to notice a change.
> Or handling of changes to variables for which variable_was_changed had been
> already called.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux
> (--enable-checking=yes,rtl, also --enable-checking=yes and
> --enable-checking=yes,rtl with a hack to disable -fvar-tracking-assignments
> by default). A backport of this patch (identical except trainling
> whitespace changes) to redhat/gcc-4_4-branch has been bootstrapped/regtested
> with --enable-checking=yes,rtl on {x86_64,i686,ppc,ppc64,s390,s390x}-linux.
>
> Ok for trunk?
Ok.
Thanks,
Richard.
> 2010-03-06 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.
>
> --- gcc/Makefile.in.jj 2010-03-05 17:13:54.000000000 +0100
> +++ gcc/Makefile.in 2010-03-05 17:14:02.000000000 +0100
> @@ -3025,7 +3025,7 @@ var-tracking.o : var-tracking.c $(CONFIG
> $(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 \
> --- gcc/cselib.c.jj 2010-03-05 13:03:03.000000000 +0100
> +++ gcc/cselib.c 2010-03-05 13:04:54.000000000 +0100
> @@ -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, bitma
> 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, bi
> 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,7 +1270,10 @@ cselib_expand_value_rtx_1 (rtx orig, str
> 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. */
> - copy = shallow_copy_rtx (orig);
> + if (evd->dummy)
> + copy = NULL;
> + else
> + copy = shallow_copy_rtx (orig);
>
> format_ptr = GET_RTX_FORMAT (code);
>
> @@ -1263,7 +1287,8 @@ cselib_expand_value_rtx_1 (rtx orig, str
> max_depth - 1);
> if (!result)
> return NULL;
> - XEXP (copy, i) = result;
> + if (copy)
> + XEXP (copy, i) = result;
> }
> break;
>
> @@ -1271,14 +1296,16 @@ cselib_expand_value_rtx_1 (rtx orig, str
> case 'V':
> if (XVEC (orig, i) != NULL)
> {
> - XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
> - for (j = 0; j < XVECLEN (copy, i); j++)
> + if (copy)
> + XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
> + 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;
> - XVECEXP (copy, i, j) = result;
> + if (copy)
> + XVECEXP (copy, i, j) = result;
> }
> }
> break;
> @@ -1299,6 +1326,9 @@ cselib_expand_value_rtx_1 (rtx orig, str
> 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,
> --- gcc/cselib.h.jj 2010-03-05 13:03:03.000000000 +0100
> +++ gcc/cselib.h 2010-03-05 13:04:54.000000000 +0100
> @@ -81,7 +81,9 @@ extern int references_value_p (const_rtx
> 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);
>
> --- gcc/var-tracking.c.jj 2010-03-05 13:03:03.000000000 +0100
> +++ gcc/var-tracking.c 2010-03-05 17:13:05.000000000 +0100
> @@ -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
> 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, voi
> 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, voi
> 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, voi
> 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,13 +2147,7 @@ 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;
> + dst->var_part[k].cur_loc = NULL;
> }
>
> if (flag_var_tracking_uninit)
> @@ -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, d
> {
> 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);
> @@ -2500,6 +2466,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])
> @@ -2739,6 +2717,13 @@ canonicalize_loc_order_check (void **slo
> 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;
>
> @@ -3101,9 +3086,11 @@ variable_merge_over_cur (void **s1slot,
> 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,
> @@ -3233,6 +3220,8 @@ variable_merge_over_cur (void **s1slot,
> 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;
> @@ -3269,11 +3258,7 @@ variable_merge_over_cur (void **s1slot,
> 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;
> - }
> + dst_can_be_shared = false;
>
> return 1;
> }
> @@ -3297,7 +3282,7 @@ variable_merge_over_src (void **s2slot,
> void **dstp = shared_hash_find_slot (dst->vars, dv);
> *dstp = s2var;
> s2var->refcount++;
> - return variable_canonicalize (dstp, dst);
> + return 1;
> }
>
> dsm->src_onepart_cnt++;
> @@ -3766,13 +3751,14 @@ dataflow_set_preserve_mem_locs (void **s
> {
> 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)
> {
> @@ -3829,6 +3815,12 @@ dataflow_set_preserve_mem_locs (void **s
> {
> 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);
> }
> @@ -3837,7 +3829,15 @@ dataflow_set_preserve_mem_locs (void **s
> }
>
> if (emit_notes)
> - remove_value_chains (var->dv, old_loc);
> + {
> + 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);
> }
> @@ -3847,8 +3847,10 @@ dataflow_set_preserve_mem_locs (void **s
> 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;
> @@ -3870,7 +3872,7 @@ dataflow_set_remove_mem_locs (void **slo
>
> 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
> @@ -3901,9 +3903,12 @@ dataflow_set_remove_mem_locs (void **slo
> /* 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))
> - changed = true;
> + 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);
> }
>
> @@ -3912,14 +3917,10 @@ dataflow_set_remove_mem_locs (void **slo
> 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);
> - }
> + variable_was_changed (var, set);
> }
>
> return 1;
> @@ -4007,13 +4008,10 @@ onepart_variable_different_p (variable v
> 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;
>
> @@ -4027,16 +4025,6 @@ variable_different_p (variable var1, var
> {
> 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))
> {
> @@ -4078,7 +4066,7 @@ dataflow_set_different_1 (void **slot, v
> return 0;
> }
>
> - if (variable_different_p (var1, var2, false))
> + if (variable_different_p (var1, var2))
> {
> dataflow_set_different_value = true;
>
> @@ -5999,6 +5987,7 @@ variable_was_changed (variable var, data
> 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);
> @@ -6007,6 +5996,14 @@ variable_was_changed (variable var, data
> 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;
> @@ -6015,12 +6012,19 @@ variable_was_changed (variable var, data
> 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;
> }
> }
> @@ -6103,6 +6107,8 @@ set_slot_part (dataflow_set *set, rtx lo
> 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;
> @@ -6200,7 +6206,7 @@ set_slot_part (dataflow_set *set, rtx lo
> 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;
> @@ -6239,7 +6245,7 @@ set_slot_part (dataflow_set *set, rtx lo
> 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;
> @@ -6251,7 +6257,7 @@ set_slot_part (dataflow_set *set, rtx lo
> /* 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;
> @@ -6288,6 +6294,11 @@ set_slot_part (dataflow_set *set, rtx lo
> 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;
> @@ -6312,10 +6323,7 @@ set_slot_part (dataflow_set *set, rtx lo
>
> /* 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);
> - }
> + variable_was_changed (var, set);
>
> return slot;
> }
> @@ -6443,7 +6451,7 @@ delete_slot_part (dataflow_set *set, rtx
> 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. */
> @@ -6463,6 +6471,7 @@ delete_slot_part (dataflow_set *set, rtx
> }
>
> /* Delete the location part. */
> + changed = false;
> nextp = &var->var_part[pos].loc_chain;
> for (node = *nextp; node; node = next)
> {
> @@ -6473,6 +6482,15 @@ delete_slot_part (dataflow_set *set, rtx
> {
> if (emit_notes && pos == 0 && dv_onepart_p (var->dv))
> remove_value_chains (var->dv, node->loc);
> + /* 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 == node->loc)
> + {
> + changed = true;
> + var->var_part[pos].cur_loc = NULL;
> + var->cur_loc_changed = true;
> + }
> pool_free (loc_chain_pool, node);
> *nextp = next;
> break;
> @@ -6481,28 +6499,16 @@ delete_slot_part (dataflow_set *set, rtx
> 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)))
> - {
> - changed = true;
> - if (var->var_part[pos].loc_chain)
> - var->var_part[pos].cur_loc = var->var_part[pos].loc_chain->loc;
> - }
> - else
> - changed = false;
> -
> 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))
> - remove_cselib_value_chains (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];
> @@ -6531,6 +6537,27 @@ delete_variable_part (dataflow_set *set,
> 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. */
> @@ -6538,7 +6565,10 @@ delete_variable_part (dataflow_set *set,
> 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;
> @@ -6547,11 +6577,6 @@ vt_expand_loc_callback (rtx x, bitmap re
> 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);
> @@ -6559,13 +6584,16 @@ vt_expand_loc_callback (rtx x, bitmap re
> 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;
> @@ -6587,25 +6615,78 @@ vt_expand_loc_callback (rtx x, bitmap re
> 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)
> - return xret;
> + {
> + if (dummy && dv_changed_p (dv))
> + elcd->cur_loc_changed = true;
> + return xret;
> + }
>
> if (var->n_var_parts == 0)
> - return xret;
> + {
> + if (dummy)
> + elcd->cur_loc_changed = true;
> + return xret;
> + }
>
> gcc_assert (var->n_var_parts == 1);
>
> VALUE_RECURSED_INTO (x) = true;
> result = NULL;
>
> - for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
> + if (var->var_part[0].cur_loc)
> {
> - result = cselib_expand_value_rtx_cb (loc->loc, regs, max_depth,
> - vt_expand_loc_callback, vars);
> + 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)
> - break;
> + 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,
> + 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;
> @@ -6621,18 +6702,46 @@ vt_expand_loc_callback (rtx x, bitmap re
> 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. */
> @@ -6644,7 +6753,7 @@ emit_note_insn_var_location (void **varp
> 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;
> @@ -6653,20 +6762,34 @@ emit_note_insn_var_location (void **varp
> 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;
> @@ -6680,15 +6803,26 @@ emit_note_insn_var_location (void **varp
> 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. */
> @@ -6698,11 +6832,12 @@ emit_note_insn_var_location (void **varp
> 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;
>
> @@ -6761,31 +6896,20 @@ emit_note_insn_var_location (void **varp
> 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,
> - (int) initialized);
> + note_vl = gen_rtx_VAR_LOCATION (VOIDmode, decl, expr_list,
> + (int) initialized);
> }
> else if (n_var_parts)
> {
> @@ -6797,17 +6921,64 @@ emit_note_insn_var_location (void **varp
>
> 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);
> @@ -6879,6 +7050,48 @@ check_changed_vars_2 (variable var, 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. */
> @@ -6902,6 +7115,7 @@ emit_notes_for_changes (rtx insn, enum e
> 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;
> @@ -6933,6 +7147,8 @@ emit_notes_for_differences_1 (void **slo
> 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;
> @@ -6944,8 +7160,10 @@ emit_notes_for_differences_1 (void **slo
> 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))
> {
> @@ -6970,6 +7188,33 @@ emit_notes_for_differences_1 (void **slo
> }
> 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;
> @@ -6989,6 +7234,7 @@ emit_notes_for_differences_2 (void **slo
> dv_htab_hash (new_var->dv));
> if (!old_var)
> {
> + int i;
> /* Variable has appeared. */
> if (dv_onepart_p (new_var->dv))
> {
> @@ -7000,6 +7246,8 @@ emit_notes_for_differences_2 (void **slo
> 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);
> }
>
> @@ -7304,6 +7552,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
> @@ -7345,6 +7596,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;
> }
>
>
> Jakub
>
>
--
Richard Guenther <rguenther@suse.de>
Novell / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746 - GF: Markus Rex
More information about the Gcc-patches
mailing list