for gcc/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
PR debug/49310
* var-tracking.c (loc_exp_dep, onepart_aux): New structs.
(variable_part): Replace offset with union.
(onepart_enum, onepart_enum_t): New enum-like type.
(variable_def): Drop cur_loc_changed, add onepart.
(VAR_PART_OFFSET, VAR_LOC_1PAUX): New macros, with checking.
(VAR_LOC_DEP_LST, VAR_LOC_DEP_LSTP): New macros.
(VAR_LOC_FROM, VAR_LOC_DEPTH, VAR_LOC_DEP_VEC): Likewise.
(value_chain_pool, value_chains): Remove.
(vt_stack_adjustments): Don't record register arguments.
(dv_as_rtx): New.
(dv_onepart_p): Return a onepart_enum_t.
(onepart_pool): New.
(dv_pool): Remove.
(dv_from_rtx): New.
(variable_htab_free): Release onepart aux data.
(value_chain_htab_hash, value_chain_htab_eq): Remove.
(unshare_variable): Use onepart field. Propagate onepart aux
data or offset. Drop cur_loc_changed.
(val_store): Cope with NULL insn. Rephrase dump output.
(val_resolve): Record cselib locs explicitly in set.
(variable_union): Use onepart field, adjust access to offset.
(NO_LOC_P): New.
(VALUE_CHANGED, DECL_CHANGED): Update doc.
(set_dv_changed): Clear NO_LOC_P when changed.
(find_loc_in_1pdv): Use onepart field.
(intersect_loc_chains): Likewise.
(add_value_chain, add_value_chains): Remove.
(add_cselib_value_chains, remove_value_chain): Likewise.
(remove_value_chains, remove_cselib_value_chains): Likewise.
(canonicalize_loc_order_check): Use onepart. Drop cur_loc_changed.
(canonicalize_values_star, canonicalize_vars_star): Use onepart.
(variable_merge_over_cur): Likewise. Adjust access to offset.
Drop cur_loc_changed.
(variable_merge_over_src): Use onepart field.
(remove_duplicate_values): Likewise.
(variable_post_merge_new_vals): Likewise.
(find_mem_expr_in_1pdv): Likewise.
(dataflow_set_preserve_mem_locs): Likewise. Drop cur_loc_changed
and value chains.
(dataflow_set_remove_mem_locs): Likewise. Use VAR_LOC_FROM.
(variable_different_p): Use onepart field. Move onepart test out
of the loop.
(argument_reg_set): Drop.
(EXPR_DEPTH): Unlimit.
(EXPR_USE_DEPTH): Repurpose PARAM_MAX_VARTRACK_EXPR_DEPTH.
(add_stores): Use non-argument src exprs in dataflow set.
(prepare_call_arguments): Use DECL_RTL_IF_SET.
(dump_var): Adjust access to offset.
(variable_was_changed): Drop cur_loc_changed. Use onepart.
Preserve onepart aux.
(find_variable_location_part): Special-case onepart. Adjust
access to offset.
(set_slot_part): Use onepart. Drop cur_loc_changed. Adjust
access to offset. Initialize onepaux. Drop value chains.
(delete_slot_part): Drop value chains. Use VAR_LOC_FROM.
(VEC (variable, heap), VEC (rtx, stack)): Define.
(expand_loc_callback_data): Drop dummy, cur_loc_changed,
ignore_cur_loc. Add expanding, pending, first_child.
(loc_exp_dep_alloc, loc_exp_dep_clear): New.
(loc_exp_dep_insert, loc_exp_dep_set): New.
(notify_dependents_of_resolved_value): New.
(vt_expand_var_loc_chain): New.
(vt_expand_loc_callback): Revamped.
(resolve_expansions_pending_recursion): New.
(INIT_ELCD, FINI_ELCD): New.
(vt_expand_loc): Use the new macros above. Drop ignore_cur_loc
parameter, adjust all callers.
(vt_expand_loc_dummy): Drop.
(vt_expand_1pvar): New.
(emit_note_insn_var_location): Operate on non-debug decls only.
Revamp multi-part cur_loc recomputation and one-part expansion.
Drop cur_loc_changed. Adjust access to offset.
(VEC (variable, heap)): Drop.
(changed_variables_stack, changed_values_stack): Drop.
(check_changed_vars_0, check_changed_vars_1): Remove.
(check_changed_vars_2, check_changed_vars_3): Remove.
(values_to_stack, remove_value_from_changed_variables): New.
(notify_dependents_of_changed_value, process_changed_values): New.
(emit_notes_for_changes): Revamp onepart updates.
(emit_notes_for_differences_1): Use onepart. Drop cur_loc_changed
and value chains. Propagate onepaux.
(emit_notes_for_differences_2): Drop value chains.
(emit_notes_in_bb): Adjust.
(vt_emit_notes): Drop value chains, changed_variables_stack.
(create_entry_value): Revamp.
(vt_add_function_parameter): Use new interface.
(note_register_arguments): Remove.
(vt_initialize): Drop value chains and register arguments.
(vt_finalize): Drop value chains.
* rtl.h: Document various pass-local uses of RTL flags.
* doc/invoke.texi (param max-vartrack-expr-depth): Update
description and default.
===================================================================
@@ -301,6 +301,48 @@ typedef struct location_chain_def
enum var_init_status init;
} *location_chain;
+/* A vector of loc_exp_dep holds the active dependencies of a one-part
+ DV on VALUEs, i.e., the VALUEs expanded so as to form the current
+ location of DV. Each entry is also part of VALUE' s linked-list of
+ backlinks back to DV. */
+typedef struct loc_exp_dep_s
+{
+ /* The dependent DV. */
+ decl_or_value dv;
+ /* The dependency VALUE or DECL_DEBUG. */
+ rtx value;
+ /* The next entry in VALUE's backlinks list. */
+ struct loc_exp_dep_s *next;
+ /* A pointer to the pointer to this entry (head or prev's next) in
+ the doubly-linked list. */
+ struct loc_exp_dep_s **pprev;
+} loc_exp_dep;
+
+DEF_VEC_O (loc_exp_dep);
+
+/* This data structure is allocated for one-part variables at the time
+ of emitting notes. */
+struct onepart_aux
+{
+ /* Doubly-linked list of dependent DVs. These are DVs whose cur_loc
+ computation used the expansion of this variable, and that ought
+ to be notified should this variable change. If the DV's cur_loc
+ expanded to NULL, all components of the loc list are regarded as
+ active, so that any changes in them give us a chance to get a
+ location. Otherwise, only components of the loc that expanded to
+ non-NULL are regarded as active dependencies. */
+ loc_exp_dep *backlinks;
+ /* This holds the LOC that was expanded into cur_loc. We need only
+ mark a one-part variable as changed if the FROM loc is removed,
+ or if it has no known location and a loc is added, or if it gets
+ a change notification from any of its active dependencies. */
+ rtx from;
+ /* One plus the maximum depth among the active dependencies. */
+ int depth;
+ /* Dependencies actively used when expand FROM into cur_loc. */
+ VEC (loc_exp_dep, none) deps;
+};
+
/* Structure describing one part of variable. */
typedef struct variable_part_def
{
@@ -310,13 +352,38 @@ typedef struct variable_part_def
/* Location which was last emitted to location list. */
rtx cur_loc;
- /* The offset in the variable. */
- HOST_WIDE_INT offset;
+ union variable_aux
+ {
+ /* The offset in the variable, if !var->onepart. */
+ HOST_WIDE_INT offset;
+
+ /* Pointer to auxiliary data, if var->onepart and emit_notes. */
+ struct onepart_aux *onepaux;
+ } aux;
} variable_part;
/* Maximum number of location parts. */
#define MAX_VAR_PARTS 16
+/* Enumeration type used to discriminate various types of one-part
+ variables. */
+enum onepart_enum {
+ /* Not a one-part variable. */
+ NOT_ONEPART = 0,
+ /* A one-part DECL that is not a DEBUG_EXPR_DECL. */
+ ONEPART_VDECL = 1,
+ /* Some other kind of tree expression. */
+ ONEPART_OTHER = 2,
+ /* A DEBUG_EXPR_DECL. */
+ ONEPART_DEXPR = 3,
+ /* A VALUE. */
+ ONEPART_VALUE = 4
+};
+
+/* A narrower type used to hold a onepart_enum while saving
+ memory. */
+typedef char onepart_enum_t;
+
/* Structure describing where the variable is located. */
typedef struct variable_def
{
@@ -330,10 +397,8 @@ typedef struct variable_def
/* Number of variable 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;
+ /* What type of DV this is, according to enum onepart_enum. */
+ onepart_enum_t onepart;
/* True if this variable_def struct is currently in the
changed_variables hash table. */
@@ -367,6 +432,42 @@ typedef const struct value_chain_def *co
/* Macro to access MEM_OFFSET as an HOST_WIDE_INT. Evaluates MEM twice. */
#define INT_MEM_OFFSET(mem) (MEM_OFFSET_KNOWN_P (mem) ? MEM_OFFSET (mem) : 0)
+#if ENABLE_CHECKING && (GCC_VERSION >= 2007)
+
+/* Access VAR's Ith part's offset, checking that it's not a one-part
+ variable. */
+#define VAR_PART_OFFSET(var, i) __extension__ \
+(*({ variable const __v = (var); \
+ gcc_checking_assert (!__v->onepart); \
+ &__v->var_part[(i)].aux.offset; }))
+
+/* Access VAR's one-part auxiliary data, checking that it is a
+ one-part variable. */
+#define VAR_LOC_1PAUX(var) __extension__ \
+(*({ variable const __v = (var); \
+ gcc_checking_assert (__v->onepart); \
+ &__v->var_part[0].aux.onepaux; }))
+
+#else
+#define VAR_PART_OFFSET(var, i) ((var)->var_part[(i)].aux.offset)
+#define VAR_LOC_1PAUX(var) ((var)->var_part[0].aux.onepaux)
+#endif
+
+/* These are accessor macros for the one-part auxiliary data. When
+ convenient for users, they're guarded by tests that the data was
+ allocated. */
+#define VAR_LOC_DEP_LST(var) (VAR_LOC_1PAUX (var) \
+ ? VAR_LOC_1PAUX (var)->backlinks \
+ : NULL)
+#define VAR_LOC_DEP_LSTP(var) (VAR_LOC_1PAUX (var) \
+ ? &VAR_LOC_1PAUX (var)->backlinks \
+ : NULL)
+#define VAR_LOC_FROM(var) (VAR_LOC_1PAUX (var)->from)
+#define VAR_LOC_DEPTH(var) (VAR_LOC_1PAUX (var)->depth)
+#define VAR_LOC_DEP_VEC(var) (VAR_LOC_1PAUX (var) \
+ ? &VAR_LOC_1PAUX (var)->deps \
+ : NULL)
+
/* Alloc pool for struct attrs_def. */
static alloc_pool attrs_pool;
@@ -382,15 +483,9 @@ static alloc_pool loc_chain_pool;
/* Alloc pool for struct shared_hash_def. */
static alloc_pool shared_hash_pool;
-/* Alloc pool for struct value_chain_def. */
-static alloc_pool value_chain_pool;
-
/* Changed variables, notes will be emitted for them. */
static htab_t changed_variables;
-/* Links from VALUEs to DVs referencing them in their current loc_chains. */
-static htab_t value_chains;
-
/* Shall notes be emitted? */
static bool emit_notes;
@@ -420,7 +515,6 @@ static void stack_adjust_offset_pre_post
static void insn_stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
HOST_WIDE_INT *);
static bool vt_stack_adjustments (void);
-static void note_register_arguments (rtx);
static hashval_t variable_htab_hash (const void *);
static int variable_htab_eq (const void *, const void *);
static void variable_htab_free (void *);
@@ -672,15 +766,11 @@ vt_stack_adjustments (void)
for (insn = BB_HEAD (dest);
insn != NEXT_INSN (BB_END (dest));
insn = NEXT_INSN (insn))
- {
- if (INSN_P (insn))
- {
- insn_stack_adjust_offset_pre_post (insn, &pre, &post);
- offset += pre + post;
- }
- if (CALL_P (insn))
- note_register_arguments (insn);
- }
+ if (INSN_P (insn))
+ {
+ insn_stack_adjust_offset_pre_post (insn, &pre, &post);
+ offset += pre + post;
+ }
VTI (dest)->out.stack_adjust = offset;
@@ -1133,6 +1223,21 @@ dv_as_value (decl_or_value dv)
return (rtx)dv;
}
+/* Return the DEBUG_EXPR of a DEBUG_EXPR_DECL or the VALUE in DV. */
+static inline rtx
+dv_as_rtx (decl_or_value dv)
+{
+ tree decl;
+
+ if (dv_is_value_p (dv))
+ return dv_as_value (dv);
+
+ decl = dv_as_decl (dv);
+
+ gcc_checking_assert (TREE_CODE (decl) == DEBUG_EXPR_DECL);
+ return DECL_RTL_IF_SET (decl);
+}
+
/* Return the opaque pointer in the decl_or_value. */
static inline void *
dv_as_opaque (decl_or_value dv)
@@ -1140,36 +1245,39 @@ dv_as_opaque (decl_or_value dv)
return dv;
}
-/* Return true if a decl_or_value must not have more than one variable
- part. */
-static inline bool
+/* Return nonzero if a decl_or_value must not have more than one
+ variable part. The returned value discriminates among various
+ kinds of one-part DVs ccording to enum onepart_enum. */
+static inline onepart_enum_t
dv_onepart_p (decl_or_value dv)
{
tree decl;
if (!MAY_HAVE_DEBUG_INSNS)
- return false;
+ return NOT_ONEPART;
if (dv_is_value_p (dv))
- return true;
+ return ONEPART_VALUE;
decl = dv_as_decl (dv);
if (!decl)
- return true;
+ return ONEPART_OTHER;
if (TREE_CODE (decl) == DEBUG_EXPR_DECL)
- return true;
+ return ONEPART_DEXPR;
+
+ if (target_for_debug_bind (decl) != NULL_TREE)
+ return ONEPART_VDECL;
- return (target_for_debug_bind (decl) != NULL_TREE);
+ return NOT_ONEPART;
}
-/* Return the variable pool to be used for dv, depending on whether it
- can have multiple parts or not. */
+/* Return the variable pool to be used for a dv of type ONEPART. */
static inline alloc_pool
-dv_pool (decl_or_value dv)
+onepart_pool (onepart_enum_t onepart)
{
- return dv_onepart_p (dv) ? valvar_pool : var_pool;
+ return onepart ? valvar_pool : var_pool;
}
/* Build a decl_or_value out of a decl. */
@@ -1192,6 +1300,30 @@ dv_from_value (rtx value)
return dv;
}
+/* Return a value or the decl of a debug_expr as a decl_or_value. */
+static inline decl_or_value
+dv_from_rtx (rtx x)
+{
+ decl_or_value dv;
+
+ switch (GET_CODE (x))
+ {
+ case DEBUG_EXPR:
+ dv = dv_from_decl (DEBUG_EXPR_TREE_DECL (x));
+ gcc_checking_assert (DECL_RTL_IF_SET (DEBUG_EXPR_TREE_DECL (x)) == x);
+ break;
+
+ case VALUE:
+ dv = dv_from_value (x);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return dv;
+}
+
extern void debug_dv (decl_or_value dv);
DEBUG_FUNCTION void
@@ -1254,6 +1386,8 @@ variable_htab_eq (const void *x, const v
return (dv_as_opaque (v->dv) == dv_as_opaque (dv));
}
+static void loc_exp_dep_clear (variable var);
+
/* Free the element of VARIABLE_HTAB (its type is struct variable_def). */
static void
@@ -1278,29 +1412,14 @@ variable_htab_free (void *elem)
}
var->var_part[i].loc_chain = NULL;
}
- pool_free (dv_pool (var->dv), var);
-}
-
-/* The hash function for value_chains htab, computes the hash value
- from the VALUE. */
-
-static hashval_t
-value_chain_htab_hash (const void *x)
-{
- const_value_chain const v = (const_value_chain) x;
-
- return dv_htab_hash (v->dv);
-}
-
-/* Compare the VALUE X with VALUE Y. */
-
-static int
-value_chain_htab_eq (const void *x, const void *y)
-{
- const_value_chain const v = (const_value_chain) x;
- decl_or_value dv = CONST_CAST2 (decl_or_value, const void *, y);
-
- return dv_as_opaque (v->dv) == dv_as_opaque (dv);
+ if (var->onepart)
+ {
+ loc_exp_dep_clear (var);
+ if (VAR_LOC_DEP_LST (var))
+ VAR_LOC_DEP_LST (var)->pprev = NULL;
+ XDELETE (VAR_LOC_1PAUX (var));
+ }
+ pool_free (onepart_pool (var->onepart), var);
}
/* Initialize the set (array) SET of attrs to empty lists. */
@@ -1569,13 +1688,12 @@ unshare_variable (dataflow_set *set, voi
variable new_var;
int i;
- new_var = (variable) pool_alloc (dv_pool (var->dv));
+ new_var = (variable) pool_alloc (onepart_pool (var->onepart));
new_var->dv = var->dv;
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->onepart = var->onepart;
new_var->in_changed_variables = false;
if (! flag_var_tracking_uninit)
@@ -1586,7 +1704,18 @@ unshare_variable (dataflow_set *set, voi
location_chain node;
location_chain *nextp;
- new_var->var_part[i].offset = var->var_part[i].offset;
+ if (i == 0 && var->onepart)
+ {
+ /* One-part auxiliary data is only used while emitting
+ notes, so propagate it to the new variable in the active
+ dataflow set. If we're not emitting notes, this will be
+ a no-op. */
+ gcc_checking_assert (!VAR_LOC_1PAUX (var) || emit_notes);
+ VAR_LOC_1PAUX (new_var) = VAR_LOC_1PAUX (var);
+ VAR_LOC_1PAUX (var) = NULL;
+ }
+ else
+ VAR_PART_OFFSET (new_var, i) = VAR_PART_OFFSET (var, i);
nextp = &new_var->var_part[i].loc_chain;
for (node = var->var_part[i].loc_chain; node; node = node->next)
{
@@ -1904,10 +2033,10 @@ val_store (dataflow_set *set, rtx val, r
if (dump_file)
{
- fprintf (dump_file, "%i: ", INSN_UID (insn));
- print_inline_rtx (dump_file, val, 0);
- fprintf (dump_file, " stored in ");
+ fprintf (dump_file, "%i: ", insn ? INSN_UID (insn) : 0);
print_inline_rtx (dump_file, loc, 0);
+ fprintf (dump_file, " evaluates to ");
+ print_inline_rtx (dump_file, val, 0);
if (v->locs)
{
struct elt_loc_list *l;
@@ -2029,6 +2158,20 @@ val_resolve (dataflow_set *set, rtx val,
val_reset (set, dv);
+ if (insn)
+ {
+ cselib_val *v = CSELIB_VAL_PTR (val);
+ struct elt_loc_list *l;
+
+ /* Take all equivalent expressions recorded by cselib at this
+ insn, so that complete information is available in our
+ dataflow sets. The exception is the very expressions we were
+ asked to record, that gets special treatment below. */
+ for (l = v->locs; l; l = l->next)
+ if (l->setting_insn == insn && l->loc != loc)
+ val_store (set, val, l->loc, insn, false);
+ }
+
if (REG_P (loc))
{
attrs node, found = NULL;
@@ -2176,10 +2319,11 @@ variable_union (variable src, dataflow_s
dst = (variable) *dstp;
gcc_assert (src->n_var_parts);
+ gcc_checking_assert (src->onepart == dst->onepart);
/* We can combine one-part variables very efficiently, because their
entries are in canonical order. */
- if (dv_onepart_p (src->dv))
+ if (src->onepart)
{
location_chain *nodep, dnode, snode;
@@ -2233,16 +2377,18 @@ variable_union (variable src, dataflow_s
return 1;
}
+ gcc_checking_assert (!src->onepart);
+
/* Count the number of location parts, result is K. */
for (i = 0, j = 0, k = 0;
i < src->n_var_parts && j < dst->n_var_parts; k++)
{
- if (src->var_part[i].offset == dst->var_part[j].offset)
+ if (VAR_PART_OFFSET (src, i) == VAR_PART_OFFSET (dst, j))
{
i++;
j++;
}
- else if (src->var_part[i].offset < dst->var_part[j].offset)
+ else if (VAR_PART_OFFSET (src, i) < VAR_PART_OFFSET (dst, j))
i++;
else
j++;
@@ -2252,7 +2398,7 @@ variable_union (variable src, dataflow_s
/* We track only variables whose size is <= MAX_VAR_PARTS bytes
thus there are at most MAX_VAR_PARTS different offsets. */
- gcc_assert (dv_onepart_p (dst->dv) ? k == 1 : k <= MAX_VAR_PARTS);
+ gcc_checking_assert (dst->onepart ? k == 1 : k <= MAX_VAR_PARTS);
if (dst->n_var_parts != k && shared_var_p (dst, set->vars))
{
@@ -2269,7 +2415,7 @@ variable_union (variable src, dataflow_s
location_chain node, node2;
if (i >= 0 && j >= 0
- && src->var_part[i].offset == dst->var_part[j].offset)
+ && VAR_PART_OFFSET (src, i) == VAR_PART_OFFSET (dst, j))
{
/* Compute the "sorted" union of the chains, i.e. the locations which
are in both chains go first, they are sorted by the sum of
@@ -2317,7 +2463,7 @@ variable_union (variable src, dataflow_s
/* The most common case, much simpler, no qsort is needed. */
location_chain dstnode = dst->var_part[j].loc_chain;
dst->var_part[k].loc_chain = dstnode;
- dst->var_part[k].offset = dst->var_part[j].offset;
+ VAR_PART_OFFSET (dst, k) = VAR_PART_OFFSET(dst, j);
node2 = dstnode;
for (node = src->var_part[i].loc_chain; node; node = node->next)
if (!((REG_P (dstnode->loc)
@@ -2455,20 +2601,20 @@ variable_union (variable src, dataflow_s
dst->var_part[k].loc_chain = vui[0].lc;
}
- dst->var_part[k].offset = dst->var_part[j].offset;
+ VAR_PART_OFFSET (dst, k) = VAR_PART_OFFSET (dst, j);
}
i--;
j--;
}
else if ((i >= 0 && j >= 0
- && src->var_part[i].offset < dst->var_part[j].offset)
+ && VAR_PART_OFFSET (src, i) < VAR_PART_OFFSET (dst, j))
|| i < 0)
{
dst->var_part[k] = dst->var_part[j];
j--;
}
else if ((i >= 0 && j >= 0
- && src->var_part[i].offset > dst->var_part[j].offset)
+ && VAR_PART_OFFSET (src, i) > VAR_PART_OFFSET (dst, j))
|| j < 0)
{
location_chain *nextp;
@@ -2492,7 +2638,7 @@ variable_union (variable src, dataflow_s
nextp = &new_lc->next;
}
- dst->var_part[k].offset = src->var_part[i].offset;
+ VAR_PART_OFFSET (dst, k) = VAR_PART_OFFSET (src, i);
i--;
}
dst->var_part[k].cur_loc = NULL;
@@ -2543,25 +2689,46 @@ dataflow_set_union (dataflow_set *dst, d
/* Whether the value is currently being expanded. */
#define VALUE_RECURSED_INTO(x) \
(RTL_FLAG_CHECK2 ("VALUE_RECURSED_INTO", (x), VALUE, DEBUG_EXPR)->used)
-/* Whether the value is in changed_variables hash table. */
+
+/* Whether no expansion was found, saving useless lookups.
+ It must only be set when VALUE_CHANGED is clear. */
+#define NO_LOC_P(x) \
+ (RTL_FLAG_CHECK2 ("NO_LOC_P", (x), VALUE, DEBUG_EXPR)->return_val)
+
+/* Whether cur_loc in the value needs to be (re)computed. */
#define VALUE_CHANGED(x) \
(RTL_FLAG_CHECK1 ("VALUE_CHANGED", (x), VALUE)->frame_related)
-/* Whether the decl is in changed_variables hash table. */
+/* Whether cur_loc in the decl needs to be (re)computed. */
#define DECL_CHANGED(x) TREE_VISITED (x)
-/* Record that DV has been added into resp. removed from changed_variables
- hashtable. */
+/* Record (if NEWV) that DV needs to have its cur_loc recomputed. For
+ user DECLs, this means they're in changed_variables. Values and
+ debug exprs may be left with this flag set if no user variable
+ requires them to be evaluated. */
static inline void
set_dv_changed (decl_or_value dv, bool newv)
{
- if (dv_is_value_p (dv))
- VALUE_CHANGED (dv_as_value (dv)) = newv;
- else
- DECL_CHANGED (dv_as_decl (dv)) = newv;
+ switch (dv_onepart_p (dv))
+ {
+ case ONEPART_VALUE:
+ if (newv)
+ NO_LOC_P (dv_as_value (dv)) = false;
+ VALUE_CHANGED (dv_as_value (dv)) = newv;
+ break;
+
+ case ONEPART_DEXPR:
+ if (newv)
+ NO_LOC_P (DECL_RTL_IF_SET (dv_as_decl (dv))) = false;
+ /* Fall through... */
+
+ default:
+ DECL_CHANGED (dv_as_decl (dv)) = newv;
+ break;
+ }
}
-/* Return true if DV is present in changed_variables hash table. */
+/* Return true if DV needs to have its cur_loc recomputed. */
static inline bool
dv_changed_p (decl_or_value dv)
@@ -2585,12 +2752,11 @@ find_loc_in_1pdv (rtx loc, variable var,
if (!var)
return NULL;
- gcc_checking_assert (dv_onepart_p (var->dv));
+ gcc_checking_assert (var->onepart);
if (!var->n_var_parts)
return NULL;
- gcc_checking_assert (var->var_part[0].offset == 0);
gcc_checking_assert (loc != dv_as_opaque (var->dv));
loc_code = GET_CODE (loc);
@@ -2700,11 +2866,10 @@ intersect_loc_chains (rtx val, location_
{
location_chain s2node;
- gcc_checking_assert (dv_onepart_p (s2var->dv));
+ gcc_checking_assert (s2var->onepart);
if (s2var->n_var_parts)
{
- gcc_checking_assert (s2var->var_part[0].offset == 0);
s2node = s2var->var_part[0].loc_chain;
for (; s1node && s2node;
@@ -2933,186 +3098,23 @@ loc_cmp (rtx x, rtx y)
return 0;
}
-/* If decl or value DVP refers to VALUE from *LOC, add backlinks
- from VALUE to DVP. */
-
-static int
-add_value_chain (rtx *loc, void *dvp)
-{
- decl_or_value dv, ldv;
- value_chain vc, nvc;
- void **slot;
-
- if (GET_CODE (*loc) == VALUE)
- ldv = dv_from_value (*loc);
- else if (GET_CODE (*loc) == DEBUG_EXPR)
- ldv = dv_from_decl (DEBUG_EXPR_TREE_DECL (*loc));
- else
- return 0;
-
- if (dv_as_opaque (ldv) == dvp)
- return 0;
-
- dv = (decl_or_value) dvp;
- slot = htab_find_slot_with_hash (value_chains, ldv, dv_htab_hash (ldv),
- INSERT);
- if (!*slot)
- {
- vc = (value_chain) pool_alloc (value_chain_pool);
- vc->dv = ldv;
- vc->next = NULL;
- vc->refcount = 0;
- *slot = (void *) vc;
- }
- else
- {
- for (vc = ((value_chain) *slot)->next; vc; vc = vc->next)
- if (dv_as_opaque (vc->dv) == dv_as_opaque (dv))
- break;
- if (vc)
- {
- vc->refcount++;
- return 0;
- }
- }
- vc = (value_chain) *slot;
- nvc = (value_chain) pool_alloc (value_chain_pool);
- nvc->dv = dv;
- nvc->next = vc->next;
- nvc->refcount = 1;
- vc->next = nvc;
- return 0;
-}
-
-/* If decl or value DVP refers to VALUEs from within LOC, add backlinks
- from those VALUEs to DVP. */
-
-static void
-add_value_chains (decl_or_value dv, rtx loc)
-{
- if (GET_CODE (loc) == VALUE || GET_CODE (loc) == DEBUG_EXPR)
- {
- add_value_chain (&loc, dv_as_opaque (dv));
- return;
- }
- if (REG_P (loc))
- return;
- if (MEM_P (loc))
- loc = XEXP (loc, 0);
- for_each_rtx (&loc, add_value_chain, dv_as_opaque (dv));
-}
-
-/* If CSELIB_VAL_PTR of value DV refer to VALUEs, add backlinks from those
- VALUEs to DV. Add the same time get rid of ASM_OPERANDS from locs list,
- that is something we never can express in .debug_info and can prevent
- reverse ops from being used. */
-
-static void
-add_cselib_value_chains (decl_or_value dv)
-{
- struct elt_loc_list **l;
-
- for (l = &CSELIB_VAL_PTR (dv_as_value (dv))->locs; *l;)
- if (GET_CODE ((*l)->loc) == ASM_OPERANDS)
- *l = (*l)->next;
- else
- {
- for_each_rtx (&(*l)->loc, add_value_chain, dv_as_opaque (dv));
- l = &(*l)->next;
- }
-}
-
-/* If decl or value DVP refers to VALUE from *LOC, remove backlinks
- from VALUE to DVP. */
-
-static int
-remove_value_chain (rtx *loc, void *dvp)
-{
- decl_or_value dv, ldv;
- value_chain vc;
- void **slot;
-
- if (GET_CODE (*loc) == VALUE)
- ldv = dv_from_value (*loc);
- else if (GET_CODE (*loc) == DEBUG_EXPR)
- ldv = dv_from_decl (DEBUG_EXPR_TREE_DECL (*loc));
- else
- return 0;
-
- if (dv_as_opaque (ldv) == dvp)
- return 0;
-
- dv = (decl_or_value) dvp;
- slot = htab_find_slot_with_hash (value_chains, ldv, dv_htab_hash (ldv),
- NO_INSERT);
- for (vc = (value_chain) *slot; vc->next; vc = vc->next)
- if (dv_as_opaque (vc->next->dv) == dv_as_opaque (dv))
- {
- value_chain dvc = vc->next;
- gcc_assert (dvc->refcount > 0);
- if (--dvc->refcount == 0)
- {
- vc->next = dvc->next;
- pool_free (value_chain_pool, dvc);
- if (vc->next == NULL && vc == (value_chain) *slot)
- {
- pool_free (value_chain_pool, vc);
- htab_clear_slot (value_chains, slot);
- }
- }
- return 0;
- }
- gcc_unreachable ();
-}
-
-/* If decl or value DVP refers to VALUEs from within LOC, remove backlinks
- from those VALUEs to DVP. */
-
-static void
-remove_value_chains (decl_or_value dv, rtx loc)
-{
- if (GET_CODE (loc) == VALUE || GET_CODE (loc) == DEBUG_EXPR)
- {
- remove_value_chain (&loc, dv_as_opaque (dv));
- return;
- }
- if (REG_P (loc))
- return;
- if (MEM_P (loc))
- loc = XEXP (loc, 0);
- for_each_rtx (&loc, remove_value_chain, dv_as_opaque (dv));
-}
-
#if ENABLE_CHECKING
-/* If CSELIB_VAL_PTR of value DV refer to VALUEs, remove backlinks from those
- VALUEs to DV. */
-
-static void
-remove_cselib_value_chains (decl_or_value dv)
-{
- struct elt_loc_list *l;
-
- for (l = CSELIB_VAL_PTR (dv_as_value (dv))->locs; l; l = l->next)
- for_each_rtx (&l->loc, remove_value_chain, dv_as_opaque (dv));
-}
-
/* Check the order of entries in one-part variables. */
static int
canonicalize_loc_order_check (void **slot, void *data ATTRIBUTE_UNUSED)
{
variable var = (variable) *slot;
- 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);
+ gcc_assert (!var->in_changed_variables);
#endif
- if (!dv_onepart_p (dv))
+ if (!var->onepart)
return 1;
gcc_assert (var->n_var_parts == 1);
@@ -3186,7 +3188,7 @@ canonicalize_values_star (void **slot, v
bool has_value;
bool has_marks;
- if (!dv_onepart_p (dv))
+ if (!var->onepart)
return 1;
gcc_checking_assert (var->n_var_parts == 1);
@@ -3408,7 +3410,7 @@ canonicalize_vars_star (void **slot, voi
variable cvar;
location_chain cnode;
- if (!dv_onepart_p (dv) || dv_is_value_p (dv))
+ if (!var->onepart || var->onepart == ONEPART_VALUE)
return 1;
gcc_assert (var->n_var_parts == 1);
@@ -3461,7 +3463,7 @@ variable_merge_over_cur (variable s1var,
void **dstslot;
variable s2var, dvar = NULL;
decl_or_value dv = s1var->dv;
- bool onepart = dv_onepart_p (dv);
+ onepart_enum_t onepart = s1var->onepart;
rtx val;
hashval_t dvhash;
location_chain node, *nodep;
@@ -3475,8 +3477,7 @@ variable_merge_over_cur (variable s1var,
if (!onepart)
return variable_union (s1var, dst);
- gcc_checking_assert (s1var->n_var_parts == 1
- && s1var->var_part[0].offset == 0);
+ gcc_checking_assert (s1var->n_var_parts == 1);
dvhash = dv_htab_hash (dv);
if (dv_is_value_p (dv))
@@ -3493,16 +3494,16 @@ variable_merge_over_cur (variable s1var,
dsm->src_onepart_cnt--;
gcc_assert (s2var->var_part[0].loc_chain
- && s2var->n_var_parts == 1
- && s2var->var_part[0].offset == 0);
+ && s2var->onepart == onepart
+ && s2var->n_var_parts == 1);
dstslot = shared_hash_find_slot_noinsert_1 (dst->vars, dv, dvhash);
if (dstslot)
{
dvar = (variable)*dstslot;
gcc_assert (dvar->refcount == 1
- && dvar->n_var_parts == 1
- && dvar->var_part[0].offset == 0);
+ && dvar->onepart == onepart
+ && dvar->n_var_parts == 1);
nodep = &dvar->var_part[0].loc_chain;
}
else
@@ -3529,15 +3530,18 @@ variable_merge_over_cur (variable s1var,
{
if (node)
{
- dvar = (variable) pool_alloc (dv_pool (dv));
+ dvar = (variable) pool_alloc (onepart_pool (onepart));
dvar->dv = dv;
dvar->refcount = 1;
dvar->n_var_parts = 1;
- dvar->cur_loc_changed = false;
+ dvar->onepart = onepart;
dvar->in_changed_variables = false;
- dvar->var_part[0].offset = 0;
dvar->var_part[0].loc_chain = node;
dvar->var_part[0].cur_loc = NULL;
+ if (onepart)
+ VAR_LOC_1PAUX (dvar) = NULL;
+ else
+ VAR_PART_OFFSET (dvar, 0) = 0;
dstslot
= shared_hash_find_slot_unshare_1 (&dst->vars, dv, dvhash,
@@ -3662,15 +3666,16 @@ variable_merge_over_cur (variable s1var,
INSERT);
if (!*slot)
{
- variable var = (variable) pool_alloc (dv_pool (dv));
+ variable var = (variable) pool_alloc (onepart_pool
+ (ONEPART_VALUE));
var->dv = dv;
var->refcount = 1;
var->n_var_parts = 1;
- var->cur_loc_changed = false;
+ var->onepart = ONEPART_VALUE;
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;
+ VAR_LOC_1PAUX (var) = NULL;
*slot = var;
}
@@ -3717,9 +3722,8 @@ variable_merge_over_src (variable s2var,
{
dataflow_set *dst = dsm->dst;
decl_or_value dv = s2var->dv;
- bool onepart = dv_onepart_p (dv);
- if (!onepart)
+ if (!s2var->onepart)
{
void **dstp = shared_hash_find_slot (dst->vars, dv);
*dstp = s2var;
@@ -3864,7 +3868,7 @@ remove_duplicate_values (variable var)
{
location_chain node, *nodep;
- gcc_assert (dv_onepart_p (var->dv));
+ gcc_assert (var->onepart);
gcc_assert (var->n_var_parts == 1);
gcc_assert (var->refcount == 1);
@@ -3915,7 +3919,7 @@ variable_post_merge_new_vals (void **slo
variable var = (variable)*slot;
location_chain node;
- if (!dv_onepart_p (var->dv) || !var->n_var_parts)
+ if (!var->onepart || !var->n_var_parts)
return 1;
gcc_assert (var->n_var_parts == 1);
@@ -4146,13 +4150,11 @@ find_mem_expr_in_1pdv (tree expr, rtx va
if (!var)
return NULL;
- gcc_assert (dv_onepart_p (var->dv));
+ gcc_assert (var->onepart);
if (!var->n_var_parts)
return NULL;
- gcc_assert (var->var_part[0].offset == 0);
-
VALUE_RECURSED_INTO (val) = true;
for (node = var->var_part[0].loc_chain; node; node = node->next)
@@ -4206,7 +4208,7 @@ dataflow_set_preserve_mem_locs (void **s
dataflow_set *set = (dataflow_set *) data;
variable var = (variable) *slot;
- if (dv_is_decl_p (var->dv) && dv_onepart_p (var->dv))
+ if (var->onepart == ONEPART_VDECL || var->onepart == ONEPART_DEXPR)
{
tree decl = dv_as_decl (var->dv);
location_chain loc, *locp;
@@ -4277,10 +4279,7 @@ dataflow_set_preserve_mem_locs (void **s
{
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);
}
locp = &loc->next;
continue;
@@ -4288,12 +4287,10 @@ dataflow_set_preserve_mem_locs (void **s
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;
@@ -4321,10 +4318,11 @@ dataflow_set_remove_mem_locs (void **slo
dataflow_set *set = (dataflow_set *) data;
variable var = (variable) *slot;
- if (dv_is_value_p (var->dv))
+ if (var->onepart == ONEPART_VALUE)
{
location_chain loc, *locp;
bool changed = false;
+ rtx cur_loc;
gcc_assert (var->n_var_parts == 1);
@@ -4343,6 +4341,11 @@ dataflow_set_remove_mem_locs (void **slo
gcc_assert (var->n_var_parts == 1);
}
+ if (VAR_LOC_1PAUX (var))
+ cur_loc = VAR_LOC_FROM (var);
+ else
+ cur_loc = var->var_part[0].cur_loc;
+
for (locp = &var->var_part[0].loc_chain, loc = *locp;
loc; loc = *locp)
{
@@ -4353,17 +4356,16 @@ dataflow_set_remove_mem_locs (void **slo
continue;
}
- if (emit_notes)
- remove_value_chains (var->dv, loc->loc);
*locp = loc->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[0].cur_loc == loc->loc)
+ if (cur_loc == loc->loc)
{
changed = true;
var->var_part[0].cur_loc = NULL;
- var->cur_loc_changed = true;
+ if (VAR_LOC_1PAUX (var))
+ VAR_LOC_FROM (var) = NULL;
}
pool_free (loc_chain_pool, loc);
}
@@ -4467,20 +4469,24 @@ variable_different_p (variable var1, var
if (var1 == var2)
return false;
+ if (var1->onepart != var2->onepart)
+ return true;
+
if (var1->n_var_parts != var2->n_var_parts)
return true;
+ if (var1->onepart && var1->n_var_parts)
+ {
+ gcc_checking_assert (dv_as_opaque (var1->dv) == dv_as_opaque (var2->dv)
+ && var1->n_var_parts == 1);
+ /* One-part values have locations in a canonical order. */
+ return onepart_variable_different_p (var1, var2);
+ }
+
for (i = 0; i < var1->n_var_parts; i++)
{
- if (var1->var_part[i].offset != var2->var_part[i].offset)
+ if (VAR_PART_OFFSET (var1, i) != VAR_PART_OFFSET (var2, i))
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))
- {
- gcc_assert (var1->n_var_parts == 1
- && dv_as_opaque (var1->dv) == dv_as_opaque (var2->dv));
- return onepart_variable_different_p (var1, var2);
- }
if (variable_part_different_p (&var1->var_part[i], &var2->var_part[i]))
return true;
if (variable_part_different_p (&var2->var_part[i], &var1->var_part[i]))
@@ -5020,9 +5026,6 @@ log_op_type (rtx x, basic_block bb, rtx
/* All preserved VALUEs. */
static VEC (rtx, heap) *preserved_values;
-/* Registers used in the current function for passing parameters. */
-static HARD_REG_SET argument_reg_set;
-
/* Ensure VAL is preserved and remember it in a vector for vt_emit_notes. */
static void
@@ -5255,7 +5258,18 @@ add_uses_1 (rtx *x, void *cui)
for_each_rtx (x, add_uses, cui);
}
-#define EXPR_DEPTH (PARAM_VALUE (PARAM_MAX_VARTRACK_EXPR_DEPTH))
+/* This is the value used during expansion of locations. We want it
+ to be unbounded, so that variables expanded deep in a recursion
+ nest are fully evaluated, so that their values are cached
+ correctly. We avoid recursion cycles through other means, and we
+ don't unshare RTL, so excess complexity is not a problem. */
+#define EXPR_DEPTH (INT_MAX)
+/* We use this to keep too-complex expressions from being emitted as
+ location notes, and then to debug information. Users can trade
+ compile time for ridiculously complex expressions, although they're
+ seldom useful, and they may often have to be discarded as not
+ representable anyway. */
+#define EXPR_USE_DEPTH (PARAM_VALUE (PARAM_MAX_VARTRACK_EXPR_DEPTH))
/* Attempt to reverse the EXPR operation in the debug info. Say for
reg1 = reg2 + 6 even when reg2 is no longer live we
@@ -5382,8 +5396,6 @@ add_stores (rtx loc, const_rtx expr, voi
mo.u.loc = loc;
if (GET_CODE (expr) == SET
&& SET_DEST (expr) == loc
- && REGNO (loc) < FIRST_PSEUDO_REGISTER
- && TEST_HARD_REG_BIT (argument_reg_set, REGNO (loc))
&& find_use_val (loc, mode, cui)
&& GET_CODE (SET_SRC (expr)) != ASM_OPERANDS)
{
@@ -5893,7 +5905,7 @@ prepare_call_arguments (basic_block bb,
tree dtemp = VEC_index (tree, *debug_args, ix + 1);
enum machine_mode mode = DECL_MODE (dtemp);
item = gen_rtx_DEBUG_PARAMETER_REF (mode, param);
- item = gen_rtx_CONCAT (mode, item, DECL_RTL (dtemp));
+ item = gen_rtx_CONCAT (mode, item, DECL_RTL_IF_SET (dtemp));
call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item,
call_arguments);
}
@@ -6705,7 +6717,7 @@ dump_var (variable var)
for (i = 0; i < var->n_var_parts; i++)
{
fprintf (dump_file, " offset %ld\n",
- (long) var->var_part[i].offset);
+ (long)(var->onepart ? 0 : VAR_PART_OFFSET (var, i)));
for (node = var->var_part[i].loc_chain; node; node = node->next)
{
fprintf (dump_file, " ");
@@ -6777,7 +6789,6 @@ 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);
@@ -6791,30 +6802,43 @@ variable_was_changed (variable var, data
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;
+ if (var != old_var && var->onepart)
+ {
+ /* Restore the auxiliary info from an empty variable
+ previously created for changed_variables, so it is
+ not lost. */
+ gcc_checking_assert (!VAR_LOC_1PAUX (var));
+ VAR_LOC_1PAUX (var) = VAR_LOC_1PAUX (old_var);
+ VAR_LOC_1PAUX (old_var) = NULL;
+ }
variable_htab_free (*slot);
}
if (set && var->n_var_parts == 0)
{
variable empty_var;
+ onepart_enum_t onepart = var->onepart;
- empty_var = (variable) pool_alloc (dv_pool (var->dv));
+ empty_var = (variable) pool_alloc (onepart_pool (onepart));
empty_var->dv = var->dv;
empty_var->refcount = 1;
empty_var->n_var_parts = 0;
- empty_var->cur_loc_changed = true;
+ empty_var->onepart = onepart;
empty_var->in_changed_variables = true;
*slot = empty_var;
+ /* ??? It might be wise to retain onepart values that have
+ active backlinks, lest they get bound to expressions but
+ fail to notify dependent variables. */
+ if (onepart)
+ {
+ VAR_LOC_1PAUX (empty_var) = VAR_LOC_1PAUX (var);
+ VAR_LOC_1PAUX (var) = NULL;
+ }
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;
}
}
@@ -6849,13 +6873,24 @@ find_variable_location_part (variable va
{
int pos, low, high;
+ if (var->onepart)
+ {
+ if (offset != 0)
+ return -1;
+
+ if (insertion_point)
+ *insertion_point = 0;
+
+ return var->n_var_parts - 1;
+ }
+
/* Find the location part. */
low = 0;
high = var->n_var_parts;
while (low != high)
{
pos = (low + high) / 2;
- if (var->var_part[pos].offset < offset)
+ if (VAR_PART_OFFSET (var, pos) < offset)
low = pos + 1;
else
high = pos;
@@ -6865,7 +6900,7 @@ find_variable_location_part (variable va
if (insertion_point)
*insertion_point = pos;
- if (pos < var->n_var_parts && var->var_part[pos].offset == offset)
+ if (pos < var->n_var_parts && VAR_PART_OFFSET (var, pos) == offset)
return pos;
return -1;
@@ -6880,26 +6915,34 @@ set_slot_part (dataflow_set *set, rtx lo
location_chain node, next;
location_chain *nextp;
variable var;
- bool onepart = dv_onepart_p (dv);
-
- gcc_assert (offset == 0 || !onepart);
- gcc_assert (loc != dv_as_opaque (dv));
+ onepart_enum_t onepart;
var = (variable) *slot;
+ if (var)
+ onepart = var->onepart;
+ else
+ onepart = dv_onepart_p (dv);
+
+ gcc_checking_assert (offset == 0 || !onepart);
+ gcc_assert (loc != dv_as_opaque (dv));
+
if (! flag_var_tracking_uninit)
initialized = VAR_INIT_STATUS_INITIALIZED;
if (!var)
{
/* Create new variable information. */
- var = (variable) pool_alloc (dv_pool (dv));
+ var = (variable) pool_alloc (onepart_pool (onepart));
var->dv = dv;
var->refcount = 1;
var->n_var_parts = 1;
- var->cur_loc_changed = false;
+ var->onepart = onepart;
var->in_changed_variables = false;
- var->var_part[0].offset = offset;
+ if (var->onepart)
+ VAR_LOC_1PAUX (var) = NULL;
+ else
+ VAR_PART_OFFSET (var, 0) = offset;
var->var_part[0].loc_chain = NULL;
var->var_part[0].cur_loc = NULL;
*slot = var;
@@ -7054,7 +7097,7 @@ set_slot_part (dataflow_set *set, rtx lo
/* We track only variables whose size is <= MAX_VAR_PARTS bytes
thus there are at most MAX_VAR_PARTS different offsets. */
gcc_assert (var->n_var_parts < MAX_VAR_PARTS
- && (!var->n_var_parts || !dv_onepart_p (var->dv)));
+ && (!var->n_var_parts || !onepart));
/* We have to move the elements of array starting at index
inspos to the next position. */
@@ -7062,7 +7105,8 @@ set_slot_part (dataflow_set *set, rtx lo
var->var_part[pos] = var->var_part[pos - 1];
var->n_var_parts++;
- var->var_part[pos].offset = offset;
+ gcc_checking_assert (!onepart);
+ VAR_PART_OFFSET (var, pos) = offset;
var->var_part[pos].loc_chain = NULL;
var->var_part[pos].cur_loc = NULL;
}
@@ -7083,10 +7127,7 @@ set_slot_part (dataflow_set *set, rtx lo
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;
- }
+ var->var_part[pos].cur_loc = NULL;
pool_free (loc_chain_pool, node);
*nextp = next;
break;
@@ -7106,9 +7147,6 @@ set_slot_part (dataflow_set *set, rtx lo
node->next = *nextp;
*nextp = node;
- if (onepart && emit_notes)
- add_value_chains (var->dv, loc);
-
/* If no location was emitted do so. */
if (var->var_part[pos].cur_loc == NULL)
variable_was_changed (var, set);
@@ -7238,6 +7276,7 @@ delete_slot_part (dataflow_set *set, rtx
location_chain node, next;
location_chain *nextp;
bool changed;
+ rtx cur_loc;
if (shared_var_p (var, set->vars))
{
@@ -7258,6 +7297,11 @@ delete_slot_part (dataflow_set *set, rtx
}
}
+ if (pos == 0 && var->onepart && VAR_LOC_1PAUX (var))
+ cur_loc = VAR_LOC_FROM (var);
+ else
+ cur_loc = var->var_part[pos].cur_loc;
+
/* Delete the location part. */
changed = false;
nextp = &var->var_part[pos].loc_chain;
@@ -7268,16 +7312,15 @@ delete_slot_part (dataflow_set *set, rtx
&& REGNO (node->loc) == REGNO (loc))
|| rtx_equal_p (node->loc, loc))
{
- 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)
+ if (cur_loc == node->loc)
{
changed = true;
var->var_part[pos].cur_loc = NULL;
- var->cur_loc_changed = true;
+ if (pos == 0 && var->onepart && VAR_LOC_1PAUX (var))
+ VAR_LOC_FROM (var) = NULL;
}
pool_free (loc_chain_pool, node);
*nextp = next;
@@ -7291,8 +7334,6 @@ delete_slot_part (dataflow_set *set, rtx
{
changed = true;
var->n_var_parts--;
- if (emit_notes)
- var->cur_loc_changed = true;
while (pos < var->n_var_parts)
{
var->var_part[pos] = var->var_part[pos + 1];
@@ -7321,6 +7362,12 @@ delete_variable_part (dataflow_set *set,
delete_slot_part (set, loc, slot, offset);
}
+DEF_VEC_P (variable);
+DEF_VEC_ALLOC_P (variable, heap);
+
+DEF_VEC_ALLOC_P_STACK (rtx);
+#define VEC_rtx_stack_alloc(alloc) VEC_stack_alloc (rtx, alloc)
+
/* Structure for passing some other parameters to function
vt_expand_loc_callback. */
struct expand_loc_callback_data
@@ -7328,215 +7375,492 @@ 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;
-
- /* True if cur_loc should be ignored and any possible location
- returned. */
- bool ignore_cur_loc;
+ /* Stack of values and debug_exprs under expansion, and their
+ children. */
+ VEC (rtx, stack) *expanding;
+
+ /* Stack of values and debug_exprs whose expansion hit recursion
+ cycles. They will have VALUE_RECURSED_INTO marked when added to
+ this list. This flag will be cleared if any of its dependencies
+ resolves to a valid location. So, if the flag remains set at the
+ end of the search, we know no valid location for this one can
+ possibly exist. */
+ VEC (rtx, stack) *pending;
+
+ /* Index of the first child of the uppermost recursed-into value in
+ EXPANDING. */
+ int first_child;
};
-/* 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. */
+/* Allocate the one-part auxiliary data structure for VAR, with enough
+ room for COUNT dependencies. */
-static rtx
-vt_expand_loc_callback (rtx x, bitmap regs, int max_depth, void *data)
+static void
+loc_exp_dep_alloc (variable var, int count)
{
- struct expand_loc_callback_data *elcd
- = (struct expand_loc_callback_data *) data;
- bool dummy = elcd->dummy;
- bool cur_loc_changed = elcd->cur_loc_changed;
- rtx cur_loc;
- decl_or_value dv;
- variable var;
- location_chain loc;
- rtx result, subreg, xret;
-
- switch (GET_CODE (x))
- {
- case SUBREG:
- if (dummy)
- {
- if (cselib_dummy_expand_value_rtx_cb (SUBREG_REG (x), regs,
- max_depth - 1,
- vt_expand_loc_callback, data))
- return pc_rtx;
- else
- return NULL;
- }
+ size_t allocsize;
- subreg = cselib_expand_value_rtx_cb (SUBREG_REG (x), regs,
- max_depth - 1,
- vt_expand_loc_callback, data);
+ gcc_checking_assert (var->onepart);
- if (!subreg)
- return NULL;
+ /* We can be called with COUNT == 0 to allocate the data structure
+ without any dependencies, e.g. for the backlinks only. However,
+ if we are specifying a COUNT, then the dependency list must have
+ been emptied before. It would be possible to adjust pointers or
+ force it empty here, but this is better done at an earlier point
+ in the algorithm, so we instead leave an assertion to catch
+ errors. */
+ gcc_checking_assert (!count
+ || VEC_empty (loc_exp_dep, VAR_LOC_DEP_VEC (var)));
- result = simplify_gen_subreg (GET_MODE (x), subreg,
- GET_MODE (SUBREG_REG (x)),
- SUBREG_BYTE (x));
+ if (VAR_LOC_1PAUX (var)
+ && VEC_space (loc_exp_dep, VAR_LOC_DEP_VEC (var), count))
+ return;
- /* Invalid SUBREGs are ok in debug info. ??? We could try
- alternate expansions for the VALUE as well. */
- if (!result)
- result = gen_rtx_raw_SUBREG (GET_MODE (x), subreg, SUBREG_BYTE (x));
+ allocsize = offsetof (struct onepart_aux, deps)
+ + VEC_embedded_size (loc_exp_dep, count);
- return result;
+ if (VAR_LOC_1PAUX (var))
+ {
+ VAR_LOC_1PAUX (var) = XRESIZEVAR (struct onepart_aux,
+ VAR_LOC_1PAUX (var), allocsize);
+ /* If the reallocation moves the onepaux structure, the
+ back-pointer to BACKLINKS in the first list member will still
+ point to its old location. Adjust it. */
+ if (VAR_LOC_DEP_LST (var))
+ VAR_LOC_DEP_LST (var)->pprev = VAR_LOC_DEP_LSTP (var);
+ }
+ else
+ {
+ VAR_LOC_1PAUX (var) = XNEWVAR (struct onepart_aux, allocsize);
+ *VAR_LOC_DEP_LSTP (var) = NULL;
+ VAR_LOC_FROM (var) = NULL;
+ VAR_LOC_DEPTH (var) = 0;
+ }
+ VEC_embedded_init (loc_exp_dep, VAR_LOC_DEP_VEC (var), count);
+}
- case DEBUG_EXPR:
- dv = dv_from_decl (DEBUG_EXPR_TREE_DECL (x));
- xret = NULL;
- break;
+/* Remove all entries from the vector of active dependencies of VAR,
+ removing them from the back-links lists too. */
+
+static void
+loc_exp_dep_clear (variable var)
+{
+ while (!VEC_empty (loc_exp_dep, VAR_LOC_DEP_VEC (var)))
+ {
+ loc_exp_dep *led = VEC_last (loc_exp_dep, VAR_LOC_DEP_VEC (var));
+ if (led->next)
+ led->next->pprev = led->pprev;
+ if (led->pprev)
+ *led->pprev = led->next;
+ VEC_pop (loc_exp_dep, VAR_LOC_DEP_VEC (var));
+ }
+}
+
+/* Insert an active dependency from VAR on X to the vector of
+ dependencies, and add the corresponding back-link to X's list of
+ back-links in VARS. Return the depth of the expression. */
+
+static int
+loc_exp_insert_dep (variable var, rtx x, htab_t vars)
+{
+ decl_or_value dv;
+ variable xvar;
+ loc_exp_dep *led;
+
+ dv = dv_from_rtx (x);
+
+ /* ??? Build a vector of variables parallel to EXPANDING, to avoid
+ an additional look up? */
+ xvar = (variable) htab_find_with_hash (vars, dv, dv_htab_hash (dv));
+
+ if (!xvar)
+ return 0;
+
+ /* No point in adding the same backlink more than once. This may
+ arise if say the same value appears in two complex expressions in
+ the same loc_list, or even more than once in a single
+ expression. */
+ if (VAR_LOC_DEP_LST (xvar) && VAR_LOC_DEP_LST (xvar)->dv == var->dv)
+ return VAR_LOC_DEPTH (xvar);
+
+ VEC_quick_push (loc_exp_dep, VAR_LOC_DEP_VEC (var), NULL);
+ led = VEC_last (loc_exp_dep, VAR_LOC_DEP_VEC (var));
+ led->dv = var->dv;
+ led->value = x;
+
+ loc_exp_dep_alloc (xvar, 0);
+ led->pprev = VAR_LOC_DEP_LSTP (xvar);
+ led->next = *led->pprev;
+ if (led->next)
+ led->next->pprev = &led->next;
+ *led->pprev = led;
+
+ return VAR_LOC_DEPTH (xvar);
+}
+
+/* Create active dependencies of VAR on COUNT values starting at
+ VALUE, and corresponding back-links to the entries in VARS. Return
+ true if we found any pending-recursion results. */
+
+static bool
+loc_exp_dep_set (variable var, rtx result, rtx *value, int count, htab_t vars)
+{
+ bool pending_recursion = false;
+ int depth = result ? 1 : 0;
+
+ gcc_checking_assert (VEC_empty (loc_exp_dep, VAR_LOC_DEP_VEC (var)));
+
+ /* Set up all dependencies from last_child (as set up at the end of
+ the loop above) to the end. */
+ loc_exp_dep_alloc (var, count);
+
+ while (count--)
+ {
+ rtx x = *value++;
+ int xdepth;
+
+ if (!pending_recursion)
+ pending_recursion = !result && VALUE_RECURSED_INTO (x);
+
+ xdepth = loc_exp_insert_dep (var, x, vars);
+ if (xdepth >= depth && xdepth && result)
+ depth = xdepth + 1;
+ }
+
+ VAR_LOC_DEPTH (var) = depth;
+
+ return pending_recursion;
+}
+
+/* Notify the back-links of IVAR that are pending recursion that we
+ have found a non-NIL value for it, so they are cleared for another
+ attempt to compute a current location. */
+
+static void
+notify_dependents_of_resolved_value (variable ivar, htab_t vars)
+{
+ loc_exp_dep *led, *next;
+
+ for (led = VAR_LOC_DEP_LST (ivar); led; led = next)
+ {
+ decl_or_value dv = led->dv;
+ variable var;
+
+ next = led->next;
+
+ if (dv_is_value_p (dv))
+ {
+ rtx value = dv_as_value (dv);
+
+ /* If we have already resolved it, leave it alone. */
+ if (!VALUE_RECURSED_INTO (value))
+ continue;
+
+ /* Check that VALUE_RECURSED_INTO, true from the test above,
+ implies NO_LOC_P. */
+ gcc_checking_assert (NO_LOC_P (value));
+
+ /* We won't notify variables that are being expanded,
+ because their dependency list is cleared before
+ recursing. */
+ VALUE_RECURSED_INTO (value) = false;
+
+ gcc_checking_assert (dv_changed_p (dv));
+ }
+ else if (!dv_changed_p (dv))
+ continue;
+
+ var = (variable) htab_find_with_hash (vars, dv, dv_htab_hash (dv));
+
+ if (var)
+ notify_dependents_of_resolved_value (var, vars);
+
+ if (next)
+ next->pprev = led->pprev;
+ if (led->pprev)
+ *led->pprev = next;
+ led->next = NULL;
+ led->pprev = NULL;
+ }
+}
+
+static rtx vt_expand_loc_callback (rtx x, bitmap regs,
+ int max_depth, void *data);
+
+/* Expand VAR to a location RTX, updating its cur_loc. Use REGS and
+ DATA for cselib expand callback. If PENDRECP is given, indicate in
+ it whether any sub-expression couldn't be fully evaluated because
+ it is pending recursion resolution. */
+
+static inline rtx
+vt_expand_var_loc_chain (variable var, bitmap regs, void *data, bool *pendrecp)
+{
+ struct expand_loc_callback_data *elcd
+ = (struct expand_loc_callback_data *) data;
+ location_chain loc;
+ rtx result = NULL;
+ int first_child, last_child;
+ bool pending_recursion;
+
+ /* Clear all backlinks pointing at this, so that we're not notified
+ while we're active. */
+ loc_exp_dep_clear (var);
+
+ first_child = last_child = elcd->first_child
+ = VEC_length (rtx, elcd->expanding);
+
+ /* Attempt to expand each available location in turn. */
+ for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
+ {
+ result = cselib_expand_value_rtx_cb (loc->loc, regs, EXPR_DEPTH,
+ vt_expand_loc_callback, data);
+ if (result)
+ break;
+ else if (loc->next)
+ /* Set it for the next iteration. */
+ last_child = VEC_length (rtx, elcd->expanding);
+ else
+ /* The search is over and we couldn't find anything, prepare
+ to use the dependencies from all loc nodes. */
+ last_child = first_child;
+ }
+
+ /* Register all encountered dependencies as active. */
+ pending_recursion = loc_exp_dep_set
+ (var, result,
+ VEC_address (rtx, elcd->expanding) + last_child,
+ VEC_length (rtx, elcd->expanding) - last_child,
+ elcd->vars);
+ VEC_truncate (rtx, elcd->expanding, first_child);
+
+ /* Record where the expansion came from. */
+ if (loc)
+ {
+ VAR_LOC_FROM (var) = loc->loc;
+ gcc_checking_assert (!pending_recursion);
+ }
+ else
+ VAR_LOC_FROM (var) = NULL;
+
+ /* Indicate whether any of the dependencies are pending recursion
+ resolution. */
+ if (pendrecp)
+ *pendrecp = pending_recursion;
+ if (!pendrecp || !pending_recursion)
+ var->var_part[0].cur_loc = result;
+
+ return result;
+}
+
+/* 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. */
+
+static rtx
+vt_expand_loc_callback (rtx x, bitmap regs,
+ int max_depth ATTRIBUTE_UNUSED,
+ void *data)
+{
+ struct expand_loc_callback_data *elcd
+ = (struct expand_loc_callback_data *) data;
+ decl_or_value dv;
+ variable var;
+ rtx result, subreg;
+ bool pending_recursion = false;
+
+ switch (GET_CODE (x))
+ {
+ case SUBREG:
+ subreg = cselib_expand_value_rtx_cb (SUBREG_REG (x), regs,
+ EXPR_DEPTH,
+ vt_expand_loc_callback, data);
+
+ if (!subreg)
+ return NULL;
+
+ 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)
+ result = gen_rtx_raw_SUBREG (GET_MODE (x), subreg, SUBREG_BYTE (x));
+
+ return result;
+
+ case DEBUG_EXPR:
case VALUE:
- dv = dv_from_value (x);
- xret = x;
+ dv = dv_from_rtx (x);
break;
default:
return x;
}
- if (VALUE_RECURSED_INTO (x))
+ VEC_safe_push (rtx, stack, elcd->expanding, x);
+
+ /* Check that VALUE_RECURSED_INTO implies NO_LOC_P. */
+ gcc_checking_assert (!VALUE_RECURSED_INTO (x) || NO_LOC_P (x));
+
+ if (NO_LOC_P (x))
return NULL;
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;
+ NO_LOC_P (x) = true;
+ set_dv_changed (dv, false);
+ return NULL;
}
- if (var->n_var_parts == 0)
+ if (!dv_changed_p (dv))
{
- if (dummy)
- elcd->cur_loc_changed = true;
- return xret;
+ gcc_checking_assert (NO_LOC_P (x) == !var->var_part[0].cur_loc);
+ return var->var_part[0].cur_loc;
}
- gcc_assert (var->n_var_parts == 1);
-
VALUE_RECURSED_INTO (x) = true;
- result = NULL;
+ /* This is tentative, but it makes some tests simpler. */
+ NO_LOC_P (x) = true;
- if (var->var_part[0].cur_loc && !elcd->ignore_cur_loc)
+ if (var)
{
- 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);
- cur_loc = var->var_part[0].cur_loc;
+ gcc_checking_assert (var->n_var_parts == 1);
+
+ result = vt_expand_var_loc_chain (var, regs, data, &pending_recursion);
}
else
- cur_loc = NULL_RTX;
- if (!result && (dv_changed_p (dv) || elcd->ignore_cur_loc))
{
- if (!elcd->ignore_cur_loc)
- set_dv_changed (dv, false);
- for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
- if (loc->loc == 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;
- if (!elcd->ignore_cur_loc)
- 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)
- return result;
+ pending_recursion = false;
+ result = NULL;
+ }
+
+ if (pending_recursion)
+ {
+ gcc_checking_assert (!result);
+ VEC_safe_push (rtx, stack, elcd->pending, x);
+ }
else
- return xret;
+ {
+ NO_LOC_P (x) = !result;
+ VALUE_RECURSED_INTO (x) = false;
+ set_dv_changed (dv, false);
+
+ if (result)
+ notify_dependents_of_resolved_value (var, elcd->vars);
+ }
+
+ return result;
+}
+
+/* While expanding variables, we may encounter recursion cycles
+ because of mutual (possibly indirect) dependencies between two
+ particular variables (or values), say A and B. If we're trying to
+ expand A when we get to B, which in turn attempts to expand A, if
+ we can't find any other expansion for B, we'll add B to this
+ pending-recursion stack, and tentatively return NULL for its
+ location. This tentative value will be used for any other
+ occurrences of B, unless A gets some other location, in which case
+ it will notify B that it is worth another try at computing a
+ location for it, and it will use the location computed for A then.
+ At the end of the expansion, the tentative NULL locations become
+ final for all members of PENDING that didn't get a notification.
+ This function performs this finalization of NULL locations. */
+
+static void
+resolve_expansions_pending_recursion (VEC (rtx, stack) *pending)
+{
+ while (!VEC_empty (rtx, pending))
+ {
+ rtx x = VEC_pop (rtx, pending);
+ decl_or_value dv;
+
+ if (!VALUE_RECURSED_INTO (x))
+ continue;
+
+ gcc_checking_assert (NO_LOC_P (x));
+ VALUE_RECURSED_INTO (x) = false;
+ dv = dv_from_rtx (x);
+ gcc_checking_assert (dv_changed_p (dv));
+ set_dv_changed (dv, false);
+ }
}
-/* Expand VALUEs in LOC, using VARS as well as cselib's equivalence
- tables. */
+/* Initialize expand_loc_callback_data D with variable hash table V.
+ It must be a macro because of alloca (VEC stack). */
+#define INIT_ELCD(d, v) \
+ do \
+ { \
+ (d).vars = (v); \
+ (d).expanding = VEC_alloc (rtx, stack, 4); \
+ (d).pending = VEC_alloc (rtx, stack, 4); \
+ (d).first_child = 0; \
+ } \
+ while (0)
+/* Finalize expand_loc_callback_data D, resolved to location L. */
+#define FINI_ELCD(d, l) \
+ do \
+ { \
+ resolve_expansions_pending_recursion ((d).pending); \
+ VEC_free (rtx, stack, (d).pending); \
+ VEC_free (rtx, stack, (d).expanding); \
+ \
+ if ((l) && MEM_P (l)) \
+ (l) = targetm.delegitimize_address (l); \
+ } \
+ while (0)
+
+/* Expand VALUEs and DEBUG_EXPRs in LOC to a location, using the
+ equivalences in VARS, updating their CUR_LOCs in the process. */
static rtx
-vt_expand_loc (rtx loc, htab_t vars, bool ignore_cur_loc)
+vt_expand_loc (rtx loc, htab_t vars)
{
struct expand_loc_callback_data data;
+ rtx result;
if (!MAY_HAVE_DEBUG_INSNS)
return loc;
- data.vars = vars;
- data.dummy = false;
- data.cur_loc_changed = false;
- data.ignore_cur_loc = ignore_cur_loc;
- loc = cselib_expand_value_rtx_cb (loc, scratch_regs, EXPR_DEPTH,
- vt_expand_loc_callback, &data);
+ INIT_ELCD (data, vars);
- if (loc && MEM_P (loc))
- loc = targetm.delegitimize_address (loc);
- return loc;
+ result = cselib_expand_value_rtx_cb (loc, scratch_regs, EXPR_DEPTH,
+ vt_expand_loc_callback, &data);
+
+ FINI_ELCD (data, result);
+
+ return result;
}
-/* Like vt_expand_loc, but only return true/false (whether vt_expand_loc
- would succeed or not, without actually allocating new rtxes. */
+/* Expand the one-part VARiable to a location, using the equivalences
+ in VARS, updating their CUR_LOCs in the process. */
-static bool
-vt_expand_loc_dummy (rtx loc, htab_t vars, bool *pcur_loc_changed)
+static rtx
+vt_expand_1pvar (variable var, htab_t vars)
{
struct expand_loc_callback_data data;
- bool ret;
+ rtx loc;
- gcc_assert (MAY_HAVE_DEBUG_INSNS);
- data.vars = vars;
- data.dummy = true;
- data.cur_loc_changed = false;
- data.ignore_cur_loc = false;
- ret = cselib_dummy_expand_value_rtx_cb (loc, scratch_regs, EXPR_DEPTH,
- vt_expand_loc_callback, &data);
- *pcur_loc_changed = data.cur_loc_changed;
- return ret;
+ gcc_checking_assert (var->onepart && var->n_var_parts == 1);
+
+ if (!dv_changed_p (var->dv))
+ return var->var_part[0].cur_loc;
+
+ INIT_ELCD (data, vars);
+
+ loc = vt_expand_var_loc_chain (var, scratch_regs, &data, NULL);
+
+ if (VAR_LOC_DEPTH (var) > EXPR_USE_DEPTH)
+ loc = NULL;
+
+ gcc_checking_assert (VEC_empty (rtx, data.expanding));
+
+ FINI_ELCD (data, loc);
+
+ return loc;
}
/* Emit the NOTE_INSN_VAR_LOCATION for variable *VARP. DATA contains
@@ -7561,49 +7885,57 @@ emit_note_insn_var_location (void **varp
tree decl;
location_chain lc;
- if (dv_is_value_p (var->dv))
- goto value_or_debug_decl;
+ gcc_checking_assert (var->onepart == NOT_ONEPART
+ || var->onepart == ONEPART_VDECL);
decl = dv_as_decl (var->dv);
- if (TREE_CODE (decl) == DEBUG_EXPR_DECL)
- goto value_or_debug_decl;
-
complete = true;
last_limit = 0;
n_var_parts = 0;
- if (!MAY_HAVE_DEBUG_INSNS)
- {
- 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;
- }
- if (!var->cur_loc_changed)
- goto clear;
+ if (!var->onepart)
+ 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;
for (i = 0; i < var->n_var_parts; i++)
{
enum machine_mode mode, wider_mode;
rtx loc2;
+ HOST_WIDE_INT offset;
- if (last_limit < var->var_part[i].offset)
+ if (i == 0 && var->onepart)
{
- complete = false;
- break;
+ gcc_checking_assert (var->n_var_parts == 1);
+ offset = 0;
+ initialized = VAR_INIT_STATUS_INITIALIZED;
+ loc2 = vt_expand_1pvar (var, vars);
}
- else if (last_limit > var->var_part[i].offset)
- continue;
- offsets[n_var_parts] = var->var_part[i].offset;
- if (!var->var_part[i].cur_loc)
+ else
{
- complete = false;
- continue;
+ if (last_limit < VAR_PART_OFFSET (var, i))
+ {
+ complete = false;
+ break;
+ }
+ else if (last_limit > VAR_PART_OFFSET (var, i))
+ continue;
+ offset = VAR_PART_OFFSET (var, i);
+ if (!var->var_part[i].cur_loc)
+ {
+ complete = false;
+ continue;
+ }
+ 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);
+ loc2 = var->var_part[i].cur_loc;
}
- loc2 = vt_expand_loc (var->var_part[i].cur_loc, vars, false);
+
+ offsets[n_var_parts] = offset;
if (!loc2)
{
complete = false;
@@ -7611,29 +7943,22 @@ emit_note_insn_var_location (void **varp
}
loc[n_var_parts] = loc2;
mode = GET_MODE (var->var_part[i].cur_loc);
- if (mode == VOIDmode && dv_onepart_p (var->dv))
+ if (mode == VOIDmode && var->onepart)
mode = DECL_MODE (decl);
- 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. */
wider_mode = GET_MODE_WIDER_MODE (mode);
for (j = i + 1; j < var->n_var_parts; j++)
- if (last_limit <= var->var_part[j].offset)
+ if (last_limit <= VAR_PART_OFFSET (var, j))
break;
if (j < var->n_var_parts
&& wider_mode != VOIDmode
&& 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]))
- && last_limit == var->var_part[j].offset
- && (loc2 = vt_expand_loc (var->var_part[j].cur_loc, vars, false))
+ && last_limit == (var->onepart ? 0 : VAR_PART_OFFSET (var, j))
+ && (loc2 = vt_expand_loc (var->var_part[j].cur_loc, vars))
&& GET_CODE (loc[n_var_parts]) == GET_CODE (loc2))
{
rtx new_loc = NULL;
@@ -7746,152 +8071,149 @@ emit_note_insn_var_location (void **varp
}
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);
-DEF_VEC_ALLOC_P (variable, heap);
-
-/* Stack of variable_def pointers that need processing with
- check_changed_vars_2. */
-
-static VEC (variable, heap) *changed_variables_stack;
+/* While traversing changed_variables, push onto DATA (a stack of RTX
+ values) entries that aren't user variables. */
-/* VALUEs with no variables that need set_dv_changed (val, false)
- called before check_changed_vars_3. */
+static int
+values_to_stack (void **slot, void *data)
+{
+ VEC (rtx, stack) **changed_values_stack = (VEC (rtx, stack) **)data;
+ variable var = (variable) *slot;
-static VEC (rtx, heap) *changed_values_stack;
+ if (var->onepart == ONEPART_VALUE)
+ VEC_safe_push (rtx, stack, *changed_values_stack, dv_as_value (var->dv));
+ else if (var->onepart == ONEPART_DEXPR)
+ VEC_safe_push (rtx, stack, *changed_values_stack,
+ DECL_RTL_IF_SET (dv_as_decl (var->dv)));
-/* Helper function for check_changed_vars_1 and check_changed_vars_2. */
+ return 1;
+}
+/* Remove from changed_variables the entry whose DV corresponds to
+ value or debug_expr VAL. */
static void
-check_changed_vars_0 (decl_or_value dv, htab_t htab)
+remove_value_from_changed_variables (rtx val)
{
- value_chain vc
- = (value_chain) htab_find_with_hash (value_chains, dv, dv_htab_hash (dv));
+ decl_or_value dv = dv_from_rtx (val);
+ void **slot;
+ variable var;
- if (vc == NULL)
- return;
- for (vc = vc->next; vc; vc = vc->next)
- if (!dv_changed_p (vc->dv))
- {
- variable vcvar
- = (variable) htab_find_with_hash (htab, vc->dv,
- dv_htab_hash (vc->dv));
- if (vcvar)
- {
- set_dv_changed (vc->dv, true);
- VEC_safe_push (variable, heap, changed_variables_stack, vcvar);
- }
- else if (dv_is_value_p (vc->dv))
- {
- set_dv_changed (vc->dv, true);
- VEC_safe_push (rtx, heap, changed_values_stack,
- dv_as_value (vc->dv));
- check_changed_vars_0 (vc->dv, htab);
- }
- }
+ slot = htab_find_slot_with_hash (changed_variables,
+ dv, dv_htab_hash (dv), NO_INSERT);
+ var = (variable) *slot;
+ var->in_changed_variables = false;
+ htab_clear_slot (changed_variables, slot);
}
-/* Populate changed_variables_stack with variable_def pointers
- that need variable_was_changed called on them. */
+/* If VAL (a value or debug_expr) has backlinks to variables actively
+ dependent on it in HTAB or in CHANGED_VARIABLES, mark them as
+ changed, adding to CHANGED_VALUES_STACK any dependencies that may
+ have dependencies of their own to notify. */
-static int
-check_changed_vars_1 (void **slot, void *data)
+static void
+notify_dependents_of_changed_value (rtx val, htab_t htab,
+ VEC (rtx, stack) **changed_values_stack)
{
- variable var = (variable) *slot;
- htab_t htab = (htab_t) data;
+ void **slot;
+ variable var;
+ loc_exp_dep *led;
+ decl_or_value dv = dv_from_rtx (val);
- if (dv_is_value_p (var->dv)
- || TREE_CODE (dv_as_decl (var->dv)) == DEBUG_EXPR_DECL)
- check_changed_vars_0 (var->dv, htab);
- return 1;
-}
+ slot = htab_find_slot_with_hash (changed_variables,
+ dv, dv_htab_hash (dv), NO_INSERT);
+ if (!slot)
+ slot = htab_find_slot_with_hash (htab,
+ dv, dv_htab_hash (dv), NO_INSERT);
+ var = (variable) *slot;
-/* Add VAR to changed_variables and also for VALUEs add recursively
- all DVs that aren't in changed_variables yet but reference the
- VALUE from its loc_chain. */
+ while ((led = VAR_LOC_DEP_LST (var)))
+ {
+ decl_or_value ldv = led->dv;
+ void **islot;
+ variable ivar;
+
+ /* Deactivate and remove the backlink, as it was “used up”. It
+ makes no sense to attempt to notify the same entity again:
+ either it will be recomputed and re-register an active
+ dependency, or it will still have the changed mark. */
+ if (led->next)
+ led->next->pprev = led->pprev;
+ if (led->pprev)
+ *led->pprev = led->next;
+ led->next = NULL;
+ led->pprev = NULL;
-static void
-check_changed_vars_2 (variable var, htab_t htab)
-{
- variable_was_changed (var, NULL);
- if (dv_is_value_p (var->dv)
- || TREE_CODE (dv_as_decl (var->dv)) == DEBUG_EXPR_DECL)
- check_changed_vars_0 (var->dv, htab);
+ if (dv_changed_p (ldv))
+ continue;
+
+ switch (dv_onepart_p (ldv))
+ {
+ case ONEPART_VALUE:
+ case ONEPART_DEXPR:
+ set_dv_changed (ldv, true);
+ VEC_safe_push (rtx, stack, *changed_values_stack, dv_as_rtx (ldv));
+ break;
+
+ default:
+ islot = htab_find_slot_with_hash (htab, ldv, dv_htab_hash (ldv),
+ NO_INSERT);
+ ivar = (variable) *islot;
+ gcc_checking_assert (!VAR_LOC_DEP_LST (ivar));
+ variable_was_changed (ivar, NULL);
+ break;
+ }
+ }
}
-/* 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. */
+/* Take out of changed_variables any entries that don't refer to use
+ variables. Back-propagate change notifications from values and
+ debug_exprs to their active dependencies in HTAB or in
+ CHANGED_VARIABLES. */
-static int
-check_changed_vars_3 (void **slot, void *data)
+static void
+process_changed_values (htab_t htab)
{
- variable var = (variable) *slot;
- htab_t vars = (htab_t) data;
- int i;
- location_chain lc;
- bool cur_loc_changed;
+ int i, n;
+ rtx val;
+ VEC (rtx, stack) *changed_values_stack = VEC_alloc (rtx, stack, 20);
- if (dv_is_value_p (var->dv)
- || TREE_CODE (dv_as_decl (var->dv)) == DEBUG_EXPR_DECL)
- return 1;
+ /* Move values from changed_variables to changed_values_stack. */
+ htab_traverse (changed_variables, values_to_stack, &changed_values_stack);
- for (i = 0; i < var->n_var_parts; i++)
+ /* Back-propagate change notifications in values while popping
+ them from the stack. */
+ for (n = i = VEC_length (rtx, changed_values_stack);
+ i > 0; i = VEC_length (rtx, changed_values_stack))
{
- if (var->var_part[i].cur_loc
- && vt_expand_loc_dummy (var->var_part[i].cur_loc, vars,
- &cur_loc_changed))
+ val = VEC_pop (rtx, changed_values_stack);
+ notify_dependents_of_changed_value (val, htab, &changed_values_stack);
+
+ /* This condition will hold when visiting each of the entries
+ originally in changed_variables. We can't remove them
+ earlier because this could drop the backlinks before we got a
+ chance to use them. */
+ if (i == n)
{
- if (cur_loc_changed)
- var->cur_loc_changed = true;
- continue;
+ remove_value_from_changed_variables (val);
+ n--;
}
- 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;
+
+ VEC_free (rtx, stack, changed_values_stack);
}
/* 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. */
+ CHANGED_VARIABLES and delete this chain. WHERE specifies whether
+ the notes shall be emitted before of after instruction INSN. */
static void
emit_notes_for_changes (rtx insn, enum emit_note_where where,
@@ -7904,19 +8226,7 @@ emit_notes_for_changes (rtx insn, enum e
return;
if (MAY_HAVE_DEBUG_INSNS)
- {
- /* Unfortunately this has to be done in two steps, because
- we can't traverse a hashtab into which we are inserting
- through variable_was_changed. */
- htab_traverse (changed_variables, check_changed_vars_1, htab);
- while (VEC_length (variable, changed_variables_stack) > 0)
- check_changed_vars_2 (VEC_pop (variable, changed_variables_stack),
- htab);
- while (VEC_length (rtx, changed_values_stack) > 0)
- set_dv_changed (dv_from_value (VEC_pop (rtx, changed_values_stack)),
- false);
- htab_traverse (changed_variables, check_changed_vars_3, htab);
- }
+ process_changed_values (htab);
data.insn = insn;
data.where = where;
@@ -7943,76 +8253,34 @@ emit_notes_for_differences_1 (void **slo
/* Variable has disappeared. */
variable empty_var;
- empty_var = (variable) pool_alloc (dv_pool (old_var->dv));
+ empty_var = (variable) pool_alloc (onepart_pool (old_var->onepart));
empty_var->dv = old_var->dv;
empty_var->refcount = 0;
empty_var->n_var_parts = 0;
- empty_var->cur_loc_changed = false;
+ empty_var->onepart = old_var->onepart;
empty_var->in_changed_variables = false;
- if (dv_onepart_p (old_var->dv))
+ if (empty_var->onepart)
{
- location_chain lc;
-
- gcc_assert (old_var->n_var_parts == 1);
- for (lc = old_var->var_part[0].loc_chain; lc; lc = lc->next)
- remove_value_chains (old_var->dv, lc->loc);
+ /* Propagate the auxiliary data to (ultimately)
+ changed_variables. */
+ VAR_LOC_1PAUX (empty_var) = VAR_LOC_1PAUX (old_var);
+ VAR_LOC_1PAUX (old_var) = NULL;
}
variable_was_changed (empty_var, NULL);
/* Continue traversing the hash table. */
return 1;
}
- if (variable_different_p (old_var, new_var))
- {
- if (dv_onepart_p (old_var->dv))
- {
- location_chain lc1, lc2;
-
- gcc_assert (old_var->n_var_parts == 1
- && new_var->n_var_parts == 1);
- lc1 = old_var->var_part[0].loc_chain;
- lc2 = new_var->var_part[0].loc_chain;
- while (lc1
- && lc2
- && ((REG_P (lc1->loc) && REG_P (lc2->loc))
- || rtx_equal_p (lc1->loc, lc2->loc)))
- {
- lc1 = lc1->next;
- lc2 = lc2->next;
- }
- for (; lc2; lc2 = lc2->next)
- add_value_chains (old_var->dv, lc2->loc);
- for (; lc1; lc1 = lc1->next)
- remove_value_chains (old_var->dv, lc1->loc);
- }
- 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;
- }
- }
+ /* Update cur_loc and one-part auxiliary data, before new_var goes
+ through variable_was_changed. */
+ if (old_var != new_var && new_var->onepart)
+ {
+ gcc_checking_assert (VAR_LOC_1PAUX (new_var) == NULL);
+ VAR_LOC_1PAUX (new_var) = VAR_LOC_1PAUX (old_var);
+ VAR_LOC_1PAUX (old_var) = NULL;
+ new_var->var_part[0].cur_loc = old_var->var_part[0].cur_loc;
}
+ if (variable_different_p (old_var, new_var))
+ variable_was_changed (new_var, NULL);
/* Continue traversing the hash table. */
return 1;
@@ -8033,15 +8301,6 @@ emit_notes_for_differences_2 (void **slo
if (!old_var)
{
int i;
- /* Variable has appeared. */
- if (dv_onepart_p (new_var->dv))
- {
- location_chain lc;
-
- gcc_assert (new_var->n_var_parts == 1);
- for (lc = new_var->var_part[0].loc_chain; lc; lc = lc->next)
- add_value_chains (new_var->dv, lc->loc);
- }
for (i = 0; i < new_var->n_var_parts; i++)
new_var->var_part[i].cur_loc = NULL;
variable_was_changed (new_var, NULL);
@@ -8111,7 +8370,7 @@ emit_notes_in_bb (basic_block bb, datafl
{
XEXP (XEXP (*p, 0), 1)
= vt_expand_loc (XEXP (XEXP (*p, 0), 1),
- shared_hash_htab (set->vars), true);
+ shared_hash_htab (set->vars));
/* If expansion is successful, keep it in the list. */
if (XEXP (XEXP (*p, 0), 1))
p = &XEXP (*p, 1);
@@ -8411,17 +8670,6 @@ vt_emit_notes (void)
delete_variable_part). */
emit_notes = true;
- if (MAY_HAVE_DEBUG_INSNS)
- {
- unsigned int i;
- rtx val;
-
- FOR_EACH_VEC_ELT (rtx, preserved_values, i, val)
- add_cselib_value_chains (dv_from_value (val));
- changed_variables_stack = VEC_alloc (variable, heap, 40);
- changed_values_stack = VEC_alloc (rtx, heap, 40);
- }
-
dataflow_set_init (&cur);
FOR_EACH_BB (bb)
@@ -8441,24 +8689,9 @@ vt_emit_notes (void)
htab_traverse (shared_hash_htab (cur.vars),
emit_notes_for_differences_1,
shared_hash_htab (empty_shared_hash));
- if (MAY_HAVE_DEBUG_INSNS)
- {
- unsigned int i;
- rtx val;
-
- FOR_EACH_VEC_ELT (rtx, preserved_values, i, val)
- remove_cselib_value_chains (dv_from_value (val));
- gcc_assert (htab_elements (value_chains) == 0);
- }
#endif
dataflow_set_destroy (&cur);
- if (MAY_HAVE_DEBUG_INSNS)
- {
- VEC_free (variable, heap, changed_variables_stack);
- VEC_free (rtx, heap, changed_values_stack);
- }
-
emit_notes = false;
}
@@ -8489,37 +8722,28 @@ vt_get_decl_and_offset (rtx rtl, tree *d
return false;
}
-/* Helper function for vt_add_function_parameter. RTL is
- the expression and VAL corresponding cselib_val pointer
- for which ENTRY_VALUE should be created. */
-
-static void
-create_entry_value (rtx rtl, cselib_val *val)
-{
- cselib_val *val2;
- struct elt_loc_list *el;
- el = (struct elt_loc_list *) ggc_alloc_cleared_atomic (sizeof (*el));
- el->loc = gen_rtx_ENTRY_VALUE (GET_MODE (rtl));
- ENTRY_VALUE_EXP (el->loc) = rtl;
- val2 = cselib_lookup_from_insn (el->loc, GET_MODE (rtl), true,
- VOIDmode, get_insns ());
- el->next = val->locs;
- el->setting_insn = get_insns ();
- val->locs = el;
- if (val2
- && val2 != val
- && val2->locs
- && rtx_equal_p (val2->locs->loc, el->loc))
- {
- struct elt_loc_list *el2;
-
- preserve_value (val2);
- el2 = (struct elt_loc_list *) ggc_alloc_cleared_atomic (sizeof (*el2));
- el2->next = val2->locs;
- el2->loc = val->val_rtx;
- el2->setting_insn = get_insns ();
- val2->locs = el2;
+/* Mark the value for the ENTRY_VALUE of RTL as equivalent to EQVAL in
+ OUT. */
+
+static void
+create_entry_value (dataflow_set *out, rtx eqval, rtx rtl)
+{
+ rtx ev = gen_rtx_ENTRY_VALUE (GET_MODE (rtl));
+ cselib_val *val;
+
+ ENTRY_VALUE_EXP (ev) = rtl;
+
+ val = cselib_lookup_from_insn (ev, GET_MODE (ev), true,
+ VOIDmode, get_insns ());
+
+ if (val->val_rtx != eqval)
+ {
+ preserve_value (val);
+ val_store (out, val->val_rtx, eqval, NULL, false);
+ val_store (out, eqval, val->val_rtx, NULL, false);
}
+
+ val_store (out, eqval, ev, NULL, false);
}
/* Insert function parameter PARM in IN and OUT sets of ENTRY_BLOCK. */
@@ -8678,20 +8902,22 @@ vt_add_function_parameter (tree parm)
VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
if (dv_is_value_p (dv))
{
- cselib_val *val = CSELIB_VAL_PTR (dv_as_value (dv));
- create_entry_value (incoming, val);
+ create_entry_value (out, dv_as_value (dv), incoming);
if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (parm))))
{
enum machine_mode indmode
= TYPE_MODE (TREE_TYPE (TREE_TYPE (parm)));
rtx mem = gen_rtx_MEM (indmode, incoming);
- val = cselib_lookup_from_insn (mem, indmode, true,
- VOIDmode, get_insns ());
+ cselib_val *val = cselib_lookup_from_insn (mem, indmode, true,
+ VOIDmode,
+ get_insns ());
if (val)
{
preserve_value (val);
- create_entry_value (mem, val);
+ set_variable_part (out, mem, dv_from_value (val->val_rtx), 0,
+ VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
+ create_entry_value (out, val->val_rtx, mem);
}
}
}
@@ -8755,23 +8981,6 @@ fp_setter (rtx insn)
return false;
}
-/* Gather all registers used for passing arguments to other functions
- called from the current routine. */
-
-static void
-note_register_arguments (rtx insn)
-{
- rtx link, x;
-
- for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
- if (GET_CODE (XEXP (link, 0)) == USE)
- {
- x = XEXP (XEXP (link, 0), 0);
- if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
- SET_HARD_REG_BIT (argument_reg_set, REGNO (x));
- }
-}
-
/* Initialize cfa_base_rtx, create a preserved VALUE for it and
ensure it isn't flushed during cselib_reset_table.
Can be called only if frame_pointer_rtx resp. arg_pointer_rtx
@@ -8843,14 +9052,6 @@ vt_initialize (void)
variable_htab_free);
changed_variables = htab_create (10, variable_htab_hash, variable_htab_eq,
variable_htab_free);
- if (MAY_HAVE_DEBUG_INSNS)
- {
- value_chain_pool = create_alloc_pool ("value_chain_def pool",
- sizeof (struct value_chain_def),
- 1024);
- value_chains = htab_create (32, value_chain_htab_hash,
- value_chain_htab_eq, NULL);
- }
/* Init the IN and OUT sets. */
FOR_ALL_BB (bb)
@@ -8876,8 +9077,6 @@ vt_initialize (void)
valvar_pool = NULL;
}
- CLEAR_HARD_REG_SET (argument_reg_set);
-
/* In order to factor out the adjustments made to the stack pointer or to
the hard frame pointer and thus be able to use DW_OP_fbreg operations
instead of individual location lists, we're going to rewrite MEMs based
@@ -8962,14 +9161,6 @@ vt_initialize (void)
}
}
- if (frame_pointer_needed)
- {
- rtx insn;
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- if (CALL_P (insn))
- note_register_arguments (insn);
- }
-
hard_frame_pointer_adjustment = -1;
vt_add_function_parameters ();
@@ -9155,8 +9346,6 @@ vt_finalize (void)
if (MAY_HAVE_DEBUG_INSNS)
{
- htab_delete (value_chains);
- free_alloc_pool (value_chain_pool);
free_alloc_pool (valvar_pool);
VEC_free (rtx, heap, preserved_values);
cselib_finish ();
===================================================================
@@ -265,7 +265,8 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"
when we access a component.
1 in a CALL_INSN if it is a sibling call.
1 in a SET that is for a return.
- In a CODE_LABEL, part of the two-bit alternate entry field. */
+ In a CODE_LABEL, part of the two-bit alternate entry field.
+ 1 in a CONCAT is VAL_EXPR_IS_COPIED in var-tracking.c. */
unsigned int jump : 1;
/* In a CODE_LABEL, part of the two-bit alternate entry field.
1 in a MEM if it cannot trap.
@@ -278,7 +279,9 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"
constants pool.
1 in a CALL_INSN logically equivalent to ECF_CONST and TREE_READONLY.
1 in a NOTE, or EXPR_LIST for a const call.
- 1 in a JUMP_INSN of an annulling branch. */
+ 1 in a JUMP_INSN of an annulling branch.
+ 1 in a CONCAT is VAL_EXPR_IS_CLOBBERED in var-tracking.c.
+ 1 in a preserved VALUE is PRESERVED_VALUE_P in cselib.c. */
unsigned int unchanging : 1;
/* 1 in a MEM or ASM_OPERANDS expression if the memory reference is volatile.
1 in an INSN, CALL_INSN, JUMP_INSN, CODE_LABEL, BARRIER, or NOTE
@@ -290,7 +293,8 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"
non-local label.
In a SYMBOL_REF, this flag is used for machine-specific purposes.
In a PREFETCH, this flag indicates that it should be considered a scheduling
- barrier. */
+ barrier.
+ 1 in a CONCAT is VAL_NEEDS_RESOLUTION in var-tracking.c. */
unsigned int volatil : 1;
/* 1 in a MEM referring to a field of an aggregate.
0 if the MEM was a variable or the result of a * operator in C;
@@ -311,19 +315,24 @@ struct GTY((chain_next ("RTX_NEXT (&%h)"
In a REG, this is not needed for that purpose, and used instead
in `leaf_renumber_regs_insn'.
1 in a SYMBOL_REF, means that emit_library_call
- has used it as the function. */
+ has used it as the function.
+ 1 in a CONCAT is VAL_HOLDS_TRACK_EXPR in var-tracking.c.
+ 1 in a VALUE or DEBUG_EXPR is VALUE_RECURSED_INTO in var-tracking.c. */
unsigned int used : 1;
/* 1 in an INSN or a SET if this rtx is related to the call frame,
either changing how we compute the frame address or saving and
restoring registers in the prologue and epilogue.
1 in a REG or MEM if it is a pointer.
1 in a SYMBOL_REF if it addresses something in the per-function
- constant string pool. */
+ constant string pool.
+ 1 in a VALUE is VALUE_CHANGED in var-tracking.c. */
unsigned frame_related : 1;
/* 1 in a REG or PARALLEL that is the current function's return value.
1 in a MEM if it refers to a scalar.
1 in a SYMBOL_REF for a weak symbol.
- 1 in a CALL_INSN logically equivalent to ECF_PURE and DECL_PURE_P. */
+ 1 in a CALL_INSN logically equivalent to ECF_PURE and DECL_PURE_P.
+ 1 in a CONCAT is VAL_EXPR_HAS_REVERSE in var-tracking.c.
+ 1 in a VALUE or DEBUG_EXPR is NO_LOC_P in var-tracking.c. */
unsigned return_val : 1;
/* The first element of the operands of this rtx.
===================================================================
@@ -9013,8 +9013,7 @@ compile time for more complete debug inf
low, value expressions that are available and could be represented in
debug information may end up not being used; setting this higher may
enable the compiler to find more complex debug expressions, but compile
-time may grow exponentially, and even then, it may fail to find more
-usable expressions. The default is 10.
+time and memory use may grow. The default is 12.
@item min-nondebug-insn-uid
Use uids starting at this parameter for nondebug insns. The range below