/* The declaration of the variable. */
tree decl;
+ /* Reference count. */
+ int refcount;
+
/* Number of variable parts. */
int n_var_parts;
static void attrs_list_union (attrs *, attrs);
static void vars_clear (htab_t);
+static variable unshare_variable (dataflow_set *set, variable var);
static int vars_copy_1 (void **, void *);
static void vars_copy (htab_t, htab_t);
static void var_reg_delete_and_set (dataflow_set *, rtx);
variable var = (variable) elem;
location_chain node, next;
+#ifdef ENABLE_CHECKING
+ if (var->refcount <= 0)
+ abort ();
+#endif
+
+ var->refcount--;
+ if (var->refcount > 0)
+ return;
+
for (i = 0; i < var->n_var_parts; i++)
{
for (node = var->var_part[i].loc_chain; node; node = next)
htab_empty (vars);
}
-/* Copy one variable from *SLOT to hash table DATA. */
+/* Return a copy of a variable VAR and insert it to dataflow set SET. */
-static int
-vars_copy_1 (void **slot, void *data)
+static variable
+unshare_variable (dataflow_set *set, variable var)
{
- htab_t dst = (htab_t) data;
- variable src, *dstp, var;
+ void **slot;
+ variable new_var;
int i;
- src = *(variable *) slot;
- dstp = (variable *) htab_find_slot_with_hash (dst, src->decl,
- VARIABLE_HASH_VAL (src->decl),
- INSERT);
- var = pool_alloc (var_pool);
- var->decl = src->decl;
- var->n_var_parts = src->n_var_parts;
- *dstp = (void *) var;
+ new_var = pool_alloc (var_pool);
+ new_var->decl = var->decl;
+ new_var->refcount = 1;
+ var->refcount--;
+ new_var->n_var_parts = var->n_var_parts;
for (i = 0; i < var->n_var_parts; i++)
{
location_chain node;
location_chain *nextp;
- var->var_part[i].offset = src->var_part[i].offset;
- nextp = &var->var_part[i].loc_chain;
- for (node = src->var_part[i].loc_chain; node; node = node->next)
+ new_var->var_part[i].offset = var->var_part[i].offset;
+ nextp = &new_var->var_part[i].loc_chain;
+ for (node = var->var_part[i].loc_chain; node; node = node->next)
{
location_chain new_lc;
/* 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 (var->var_part[i].loc_chain)
- var->var_part[i].cur_loc = var->var_part[i].loc_chain->loc;
+ if (new_var->var_part[i].loc_chain)
+ new_var->var_part[i].cur_loc = new_var->var_part[i].loc_chain->loc;
else
- var->var_part[i].cur_loc = NULL;
+ new_var->var_part[i].cur_loc = NULL;
}
+ slot = htab_find_slot_with_hash (set->vars, new_var->decl,
+ VARIABLE_HASH_VAL (new_var->decl),
+ INSERT);
+ *slot = new_var;
+ return new_var;
+}
+
+/* Add a variable from *SLOT to hash table DATA and increase its reference
+ count. */
+
+static int
+vars_copy_1 (void **slot, void *data)
+{
+ htab_t dst = (htab_t) data;
+ variable src, *dstp;
+
+ src = *(variable *) slot;
+ src->refcount++;
+
+ dstp = (variable *) htab_find_slot_with_hash (dst, src->decl,
+ VARIABLE_HASH_VAL (src->decl),
+ INSERT);
+ *dstp = src;
+
/* Continue traversing the hash table. */
return 1;
}
INSERT);
if (!*dstp)
{
- *dstp = dst = pool_alloc (var_pool);
- dst->decl = src->decl;
- dst->n_var_parts = 0;
+ src->refcount++;
+
+ /* 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++)
+ {
+ if (src->var_part[k].loc_chain)
+ {
+#ifdef ENABLE_CHECKING
+ if (src->var_part[k].cur_loc == NULL)
+ abort ();
+#endif
+ if (src->var_part[k].cur_loc != src->var_part[k].loc_chain->loc)
+ break;
+ }
+#ifdef ENABLE_CHECKING
+ else
+ {
+ if (src->var_part[k].cur_loc != NULL)
+ abort ();
+ }
+#endif
+ }
+ if (k < src->n_var_parts)
+ unshare_variable (set, src);
+ else
+ *dstp = src;
+
+ /* Continue traversing the hash table. */
+ return 1;
}
else
dst = *dstp;
else
j++;
}
- if (i < src->n_var_parts)
- k += src->n_var_parts - i;
- if (j < dst->n_var_parts)
- k += dst->n_var_parts - j;
+ k += src->n_var_parts - i;
+ k += dst->n_var_parts - j;
#ifdef ENABLE_CHECKING
/* We track only variables whose size is <= MAX_VAR_PARTS bytes
thus there are at most MAX_VAR_PARTS different offsets. */
abort ();
#endif
+ if (dst->refcount > 1 && dst->n_var_parts != k)
+ dst = unshare_variable (set, dst);
+
i = src->n_var_parts - 1;
j = dst->n_var_parts - 1;
dst->n_var_parts = k;
for (k--; k >= 0; k--)
{
- location_chain node;
+ location_chain node, node2;
if (i >= 0 && j >= 0
&& src->var_part[i].offset == dst->var_part[j].offset)
int dst_l, src_l;
int ii, jj, n;
struct variable_union_info *vui;
-
+
+ /* 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)
+ {
+ for (node = src->var_part[i].loc_chain,
+ node2 = dst->var_part[j].loc_chain; node && node2;
+ node = node->next, node2 = node2->next)
+ {
+ if (!((GET_CODE (node2->loc) == REG
+ && GET_CODE (node->loc) == REG
+ && REGNO (node2->loc) == REGNO (node->loc))
+ || rtx_equal_p (node2->loc, node->loc)))
+ break;
+ }
+ if (node || node2)
+ dst = unshare_variable (set, dst);
+ }
+
src_l = 0;
for (node = src->var_part[i].loc_chain; node; node = node->next)
src_l++;
{
int i;
+ if (var1 == var2)
+ return false;
+
if (var1->n_var_parts != var2->n_var_parts)
return true;
empty_var = pool_alloc (var_pool);
empty_var->decl = var->decl;
+ empty_var->refcount = 1;
empty_var->n_var_parts = 0;
*slot = empty_var;
abort ();
#endif
+ /* If frame_base_decl is shared unshare it first. */
+ if (var->refcount > 1)
+ var = unshare_variable (set, var);
+
var->var_part[0].loc_chain->loc = loc;
+ var->var_part[0].cur_loc = loc;
variable_was_changed (var, set->vars);
}
/* Create new variable information. */
var = pool_alloc (var_pool);
var->decl = decl;
+ var->refcount = 1;
var->n_var_parts = 1;
var->var_part[0].offset = offset;
var->var_part[0].loc_chain = NULL;
}
pos = low;
- if (pos == var->n_var_parts || var->var_part[pos].offset != offset)
+ if (pos < var->n_var_parts && var->var_part[pos].offset == offset)
{
- /* We have not find the location part, new one will be created. */
+ node = var->var_part[pos].loc_chain;
+
+ if (node
+ && ((GET_CODE (node->loc) == REG && GET_CODE (loc) == REG
+ && REGNO (node->loc) == REGNO (loc))
+ || rtx_equal_p (node->loc, loc)))
+ {
+ /* LOC is in the beginning of the chain so we have nothing
+ to do. */
+ return;
+ }
+ else
+ {
+ /* We have to make a copy of a shared variable. */
+ if (var->refcount > 1)
+ var = unshare_variable (set, var);
+ }
+ }
+ else
+ {
+ /* 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)
+ var = unshare_variable (set, var);
#ifdef ENABLE_CHECKING
/* We track only variables whose size is <= MAX_VAR_PARTS bytes
}
}
- /* Delete the location from list. */
+ /* Delete the location from the list. */
nextp = &var->var_part[pos].loc_chain;
for (node = var->var_part[pos].loc_chain; node; node = next)
{
location_chain *nextp;
bool changed;
+ if (var->refcount > 1)
+ {
+ /* If the variable contains the location part we have to
+ make a copy of the variable. */
+ for (node = var->var_part[pos].loc_chain; node;
+ node = node->next)
+ {
+ if ((GET_CODE (node->loc) == REG && GET_CODE (loc) == REG
+ && REGNO (node->loc) == REGNO (loc))
+ || rtx_equal_p (node->loc, loc))
+ {
+ var = unshare_variable (set, var);
+ break;
+ }
+ }
+ }
+
/* Delete the location part. */
nextp = &var->var_part[pos].loc_chain;
for (node = *nextp; node; node = next)
empty_var = pool_alloc (var_pool);
empty_var->decl = old_var->decl;
+ empty_var->refcount = 1;
empty_var->n_var_parts = 0;
variable_was_changed (empty_var, NULL);
}
rtx incoming = DECL_INCOMING_RTL (parm);
tree decl;
HOST_WIDE_INT offset;
- dataflow_set *in, *out;
+ dataflow_set *out;
if (TREE_CODE (parm) != PARM_DECL)
continue;
incoming = eliminate_regs (incoming, 0, NULL_RTX);
if (!frame_pointer_needed && GET_CODE (incoming) == MEM)
incoming = adjust_stack_reference (incoming, -stack_adjust);
- in = &VTI (ENTRY_BLOCK_PTR)->in;
out = &VTI (ENTRY_BLOCK_PTR)->out;
if (GET_CODE (incoming) == REG)
if (REGNO (incoming) >= FIRST_PSEUDO_REGISTER)
abort ();
#endif
- attrs_list_insert (&in->regs[REGNO (incoming)],
- parm, offset, incoming);
attrs_list_insert (&out->regs[REGNO (incoming)],
parm, offset, incoming);
- set_variable_part (in, incoming, parm, offset);
set_variable_part (out, incoming, parm, offset);
}
else if (GET_CODE (incoming) == MEM)
{
- set_variable_part (in, incoming, parm, offset);
set_variable_part (out, incoming, parm, offset);
}
}
/* Set its initial "location". */
base = gen_rtx_MEM (Pmode, stack_pointer_rtx);
- set_variable_part (&VTI (ENTRY_BLOCK_PTR)->in, base, frame_base_decl, 0);
set_variable_part (&VTI (ENTRY_BLOCK_PTR)->out, base, frame_base_decl, 0);
}
else