var-tracking.c (struct shared_hash_def, [...]): New types.

* var-tracking.c (struct shared_hash_def, shared_hash): New types.
	(dataflow_set): Change vars type from htab_t to shared_hash.
	(shared_hash_pool, empty_shared_hash): New variables.
	(vars_clear): Removed.
	(shared_hash_shared, shared_hash_htab, shared_hash_copy,
	shared_hash_find_slot_unshare, shared_hash_find_slot,
	shared_hash_find_slot_noinsert, shared_hash_find): New
	static inlines.
	(shared_hash_unshare, shared_hash_destroy): New functions.
	(unshare_variable): Unshare set->vars if shared, use
	shared_hash_htab.
	(vars_copy): Use htab_traverse_noresize instead of htab_traverse.
	(get_init_value, find_src_set_src, dump_dataflow_set,
	clobber_variable_part, emit_notes_for_differences): Use
	shared_hash_htab.
	(dataflow_set_init): Remove second argument, set vars to
	empty_shared_hash instead of creating a new htab.
	(dataflow_set_clear): Call shared_hash_destroy and set vars
	to empty_shared_hash instead of calling vars_clear.
	(dataflow_set_copy): Don't call vars_copy, instead just share
	the src htab with dst.
	(variable_union): Use shared_hash_*, use initially NO_INSERT
	lookup if set->vars is shared.  Don't keep slot cleared before
	calling unshare_variable.  Unshare set->vars if needed.
	Even ->refcount == 1 vars must be unshared if set->vars is shared
	and var needs to be modified.
	(variable_canonicalize): New function.
	(dataflow_set_union): If dst->vars is empty, just share src->vars
	with dst->vars and traverse with variable_canonicalize to canonicalize
	and unshare what is needed.
	(dataflow_set_different): If old_set and new_set use the same shared
	htab, they aren't different.  If number of htab elements is different,
	htabs are different.  Use shared_hash_*.
	(dataflow_set_destroy): Call shared_hash_destroy instead of
	htab_delete.
	(compute_bb_dataflow, emit_notes_in_bb, vt_emit_notes): Don't pass
	second argument to dataflow_set_init.
	(vt_initialize): Likewise.  Initialize shared_hash_pool and
	empty_shared_hash, move bb in/out initialization afterwards.
	Use variable_htab_free instead of NULL as changed_variables del hook.
	(variable_was_changed): Change type of second argument to pointer to
	dataflow_set.  When inserting var into changed_variables, bump
	refcount.  Unshare set->vars if set is shared htab and slot needs to
	be cleared.
	(set_variable_part): Use shared_hash_*, use initially NO_INSERT
	lookup if set->vars is shared.  Unshare set->vars if needed.
	Even ->refcount == 1 vars must be unshared if set->vars is shared
	and var needs to be modified.  Adjust variable_was_changed caller.
	(delete_variable_part): Use shared_hash_*.  Even ->refcount == 1
	vars must be unshared if set->vars is shared and var needs to be
	modified.  Adjust variable_was_changed caller.
	(emit_note_insn_var_location): Don't pool_free var.
	(emit_notes_for_differences_1): Initialize empty_var->refcount to 0
	instead of 1.
	(vt_finalize): Call htab_delete on empty_shared_hash->htab and
	free_alloc_pool on shared_hash_pool.

From-SVN: r148760
This commit is contained in:
Jakub Jelinek 2009-06-21 11:38:34 +02:00 committed by Jakub Jelinek
parent a46f975bee
commit d24686d79d
2 changed files with 328 additions and 101 deletions

View File

@ -1,3 +1,62 @@
2009-06-21 Jakub Jelinek <jakub@redhat.com>
* var-tracking.c (struct shared_hash_def, shared_hash): New types.
(dataflow_set): Change vars type from htab_t to shared_hash.
(shared_hash_pool, empty_shared_hash): New variables.
(vars_clear): Removed.
(shared_hash_shared, shared_hash_htab, shared_hash_copy,
shared_hash_find_slot_unshare, shared_hash_find_slot,
shared_hash_find_slot_noinsert, shared_hash_find): New
static inlines.
(shared_hash_unshare, shared_hash_destroy): New functions.
(unshare_variable): Unshare set->vars if shared, use
shared_hash_htab.
(vars_copy): Use htab_traverse_noresize instead of htab_traverse.
(get_init_value, find_src_set_src, dump_dataflow_set,
clobber_variable_part, emit_notes_for_differences): Use
shared_hash_htab.
(dataflow_set_init): Remove second argument, set vars to
empty_shared_hash instead of creating a new htab.
(dataflow_set_clear): Call shared_hash_destroy and set vars
to empty_shared_hash instead of calling vars_clear.
(dataflow_set_copy): Don't call vars_copy, instead just share
the src htab with dst.
(variable_union): Use shared_hash_*, use initially NO_INSERT
lookup if set->vars is shared. Don't keep slot cleared before
calling unshare_variable. Unshare set->vars if needed.
Even ->refcount == 1 vars must be unshared if set->vars is shared
and var needs to be modified.
(variable_canonicalize): New function.
(dataflow_set_union): If dst->vars is empty, just share src->vars
with dst->vars and traverse with variable_canonicalize to canonicalize
and unshare what is needed.
(dataflow_set_different): If old_set and new_set use the same shared
htab, they aren't different. If number of htab elements is different,
htabs are different. Use shared_hash_*.
(dataflow_set_destroy): Call shared_hash_destroy instead of
htab_delete.
(compute_bb_dataflow, emit_notes_in_bb, vt_emit_notes): Don't pass
second argument to dataflow_set_init.
(vt_initialize): Likewise. Initialize shared_hash_pool and
empty_shared_hash, move bb in/out initialization afterwards.
Use variable_htab_free instead of NULL as changed_variables del hook.
(variable_was_changed): Change type of second argument to pointer to
dataflow_set. When inserting var into changed_variables, bump
refcount. Unshare set->vars if set is shared htab and slot needs to
be cleared.
(set_variable_part): Use shared_hash_*, use initially NO_INSERT
lookup if set->vars is shared. Unshare set->vars if needed.
Even ->refcount == 1 vars must be unshared if set->vars is shared
and var needs to be modified. Adjust variable_was_changed caller.
(delete_variable_part): Use shared_hash_*. Even ->refcount == 1
vars must be unshared if set->vars is shared and var needs to be
modified. Adjust variable_was_changed caller.
(emit_note_insn_var_location): Don't pool_free var.
(emit_notes_for_differences_1): Initialize empty_var->refcount to 0
instead of 1.
(vt_finalize): Call htab_delete on empty_shared_hash->htab and
free_alloc_pool on shared_hash_pool.
2009-06-20 Anthony Green <green@moxielogic.com> 2009-06-20 Anthony Green <green@moxielogic.com>
* config/moxie/sfp-machine.h (__gcc_CMPtype, CMPtype): Define. * config/moxie/sfp-machine.h (__gcc_CMPtype, CMPtype): Define.

View File

@ -182,6 +182,17 @@ typedef struct attrs_def
HOST_WIDE_INT offset; HOST_WIDE_INT offset;
} *attrs; } *attrs;
/* Structure holding a refcounted hash table. If refcount > 1,
it must be first unshared before modified. */
typedef struct shared_hash_def
{
/* Reference count. */
int refcount;
/* Actual hash table. */
htab_t htab;
} *shared_hash;
/* Structure holding the IN or OUT set for a basic block. */ /* Structure holding the IN or OUT set for a basic block. */
typedef struct dataflow_set_def typedef struct dataflow_set_def
{ {
@ -192,7 +203,7 @@ typedef struct dataflow_set_def
attrs regs[FIRST_PSEUDO_REGISTER]; attrs regs[FIRST_PSEUDO_REGISTER];
/* Variable locations. */ /* Variable locations. */
htab_t vars; shared_hash vars;
} dataflow_set; } dataflow_set;
/* The structure (one for each basic block) containing the information /* The structure (one for each basic block) containing the information
@ -280,12 +291,18 @@ static alloc_pool var_pool;
/* Alloc pool for struct location_chain_def. */ /* Alloc pool for struct location_chain_def. */
static alloc_pool loc_chain_pool; static alloc_pool loc_chain_pool;
/* Alloc pool for struct shared_hash_def. */
static alloc_pool shared_hash_pool;
/* Changed variables, notes will be emitted for them. */ /* Changed variables, notes will be emitted for them. */
static htab_t changed_variables; static htab_t changed_variables;
/* Shall notes be emitted? */ /* Shall notes be emitted? */
static bool emit_notes; static bool emit_notes;
/* Empty shared hashtable. */
static shared_hash empty_shared_hash;
/* Local function prototypes. */ /* Local function prototypes. */
static void stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *, static void stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
HOST_WIDE_INT *); HOST_WIDE_INT *);
@ -305,7 +322,6 @@ static void attrs_list_insert (attrs *, tree, HOST_WIDE_INT, rtx);
static void attrs_list_copy (attrs *, attrs); static void attrs_list_copy (attrs *, attrs);
static void attrs_list_union (attrs *, attrs); static void attrs_list_union (attrs *, attrs);
static void vars_clear (htab_t);
static variable unshare_variable (dataflow_set *set, variable var, static variable unshare_variable (dataflow_set *set, variable var,
enum var_init_status); enum var_init_status);
static int vars_copy_1 (void **, void *); static int vars_copy_1 (void **, void *);
@ -321,11 +337,12 @@ static void var_mem_delete_and_set (dataflow_set *, rtx, bool,
enum var_init_status, rtx); enum var_init_status, rtx);
static void var_mem_delete (dataflow_set *, rtx, bool); static void var_mem_delete (dataflow_set *, rtx, bool);
static void dataflow_set_init (dataflow_set *, int); static void dataflow_set_init (dataflow_set *);
static void dataflow_set_clear (dataflow_set *); static void dataflow_set_clear (dataflow_set *);
static void dataflow_set_copy (dataflow_set *, dataflow_set *); static void dataflow_set_copy (dataflow_set *, dataflow_set *);
static int variable_union_info_cmp_pos (const void *, const void *); static int variable_union_info_cmp_pos (const void *, const void *);
static int variable_union (void **, void *); static int variable_union (void **, void *);
static int variable_canonicalize (void **, void *);
static void dataflow_set_union (dataflow_set *, dataflow_set *); static void dataflow_set_union (dataflow_set *, dataflow_set *);
static bool variable_part_different_p (variable_part *, variable_part *); static bool variable_part_different_p (variable_part *, variable_part *);
static bool variable_different_p (variable, variable, bool); static bool variable_different_p (variable, variable, bool);
@ -352,7 +369,7 @@ static void dump_vars (htab_t);
static void dump_dataflow_set (dataflow_set *); static void dump_dataflow_set (dataflow_set *);
static void dump_dataflow_sets (void); static void dump_dataflow_sets (void);
static void variable_was_changed (variable, htab_t); static void variable_was_changed (variable, dataflow_set *);
static void set_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT, static void set_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT,
enum var_init_status, rtx); enum var_init_status, rtx);
static void clobber_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT, static void clobber_variable_part (dataflow_set *, rtx, tree, HOST_WIDE_INT,
@ -742,12 +759,107 @@ attrs_list_union (attrs *dstp, attrs src)
} }
} }
/* Delete all variables from hash table VARS. */ /* Shared hashtable support. */
/* Return true if VARS is shared. */
static inline bool
shared_hash_shared (shared_hash vars)
{
return vars->refcount > 1;
}
/* Return the hash table for VARS. */
static inline htab_t
shared_hash_htab (shared_hash vars)
{
return vars->htab;
}
/* Copy variables into a new hash table. */
static shared_hash
shared_hash_unshare (shared_hash vars)
{
shared_hash new_vars = (shared_hash) pool_alloc (shared_hash_pool);
gcc_assert (vars->refcount > 1);
new_vars->refcount = 1;
new_vars->htab
= htab_create (htab_elements (vars->htab) + 3, variable_htab_hash,
variable_htab_eq, variable_htab_free);
vars_copy (new_vars->htab, vars->htab);
vars->refcount--;
return new_vars;
}
/* Increment reference counter on VARS and return it. */
static inline shared_hash
shared_hash_copy (shared_hash vars)
{
vars->refcount++;
return vars;
}
/* Decrement reference counter and destroy hash table if not shared
anymore. */
static void static void
vars_clear (htab_t vars) shared_hash_destroy (shared_hash vars)
{ {
htab_empty (vars); gcc_assert (vars->refcount > 0);
if (--vars->refcount == 0)
{
htab_delete (vars->htab);
pool_free (shared_hash_pool, vars);
}
}
/* Unshare *PVARS if shared and return slot for DECL. If INS is
INSERT, insert it if not already present. */
static inline void **
shared_hash_find_slot_unshare (shared_hash *pvars, tree decl,
enum insert_option ins)
{
if (shared_hash_shared (*pvars))
*pvars = shared_hash_unshare (*pvars);
return htab_find_slot_with_hash (shared_hash_htab (*pvars), decl,
VARIABLE_HASH_VAL (decl), ins);
}
/* Return slot for DECL, if it is already present in the hash table.
If it is not present, insert it only VARS is not shared, otherwise
return NULL. */
static inline void **
shared_hash_find_slot (shared_hash vars, tree decl)
{
return htab_find_slot_with_hash (shared_hash_htab (vars), decl,
VARIABLE_HASH_VAL (decl),
shared_hash_shared (vars)
? NO_INSERT : INSERT);
}
/* Return slot for DECL only if it is already present in the hash table. */
static inline void **
shared_hash_find_slot_noinsert (shared_hash vars, tree decl)
{
return htab_find_slot_with_hash (shared_hash_htab (vars), decl,
VARIABLE_HASH_VAL (decl), NO_INSERT);
}
/* Return variable for DECL or NULL if not already present in the hash
table. */
static inline variable
shared_hash_find (shared_hash vars, tree decl)
{
return (variable)
htab_find_with_hash (shared_hash_htab (vars), decl,
VARIABLE_HASH_VAL (decl));
} }
/* Return a copy of a variable VAR and insert it to dataflow set SET. */ /* Return a copy of a variable VAR and insert it to dataflow set SET. */
@ -801,9 +913,7 @@ unshare_variable (dataflow_set *set, variable var,
new_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, slot = shared_hash_find_slot_unshare (&set->vars, new_var->decl, INSERT);
VARIABLE_HASH_VAL (new_var->decl),
INSERT);
*slot = new_var; *slot = new_var;
return new_var; return new_var;
} }
@ -834,8 +944,7 @@ vars_copy_1 (void **slot, void *data)
static void static void
vars_copy (htab_t dst, htab_t src) vars_copy (htab_t dst, htab_t src)
{ {
vars_clear (dst); htab_traverse_noresize (src, vars_copy_1, dst);
htab_traverse (src, vars_copy_1, dst);
} }
/* Map a decl to its main debug decl. */ /* Map a decl to its main debug decl. */
@ -874,7 +983,6 @@ var_reg_set (dataflow_set *set, rtx loc, enum var_init_status initialized,
static enum var_init_status static enum var_init_status
get_init_value (dataflow_set *set, rtx loc, tree decl) get_init_value (dataflow_set *set, rtx loc, tree decl)
{ {
void **slot;
variable var; variable var;
int i; int i;
enum var_init_status ret_val = VAR_INIT_STATUS_UNKNOWN; enum var_init_status ret_val = VAR_INIT_STATUS_UNKNOWN;
@ -882,11 +990,9 @@ get_init_value (dataflow_set *set, rtx loc, tree decl)
if (! flag_var_tracking_uninit) if (! flag_var_tracking_uninit)
return VAR_INIT_STATUS_INITIALIZED; return VAR_INIT_STATUS_INITIALIZED;
slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl), var = shared_hash_find (set->vars, decl);
NO_INSERT); if (var)
if (slot)
{ {
var = * (variable *) slot;
for (i = 0; i < var->n_var_parts && ret_val == VAR_INIT_STATUS_UNKNOWN; i++) for (i = 0; i < var->n_var_parts && ret_val == VAR_INIT_STATUS_UNKNOWN; i++)
{ {
location_chain nextp; location_chain nextp;
@ -1050,11 +1156,10 @@ var_mem_delete (dataflow_set *set, rtx loc, bool clobber)
VARS_SIZE is the initial size of hash table VARS. */ VARS_SIZE is the initial size of hash table VARS. */
static void static void
dataflow_set_init (dataflow_set *set, int vars_size) dataflow_set_init (dataflow_set *set)
{ {
init_attrs_list_set (set->regs); init_attrs_list_set (set->regs);
set->vars = htab_create (vars_size, variable_htab_hash, variable_htab_eq, set->vars = shared_hash_copy (empty_shared_hash);
variable_htab_free);
set->stack_adjust = 0; set->stack_adjust = 0;
} }
@ -1068,7 +1173,8 @@ dataflow_set_clear (dataflow_set *set)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
attrs_list_clear (&set->regs[i]); attrs_list_clear (&set->regs[i]);
vars_clear (set->vars); shared_hash_destroy (set->vars);
set->vars = shared_hash_copy (empty_shared_hash);
} }
/* Copy the contents of dataflow set SRC to DST. */ /* Copy the contents of dataflow set SRC to DST. */
@ -1081,7 +1187,8 @@ dataflow_set_copy (dataflow_set *dst, dataflow_set *src)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
attrs_list_copy (&dst->regs[i], src->regs[i]); attrs_list_copy (&dst->regs[i], src->regs[i]);
vars_copy (dst->vars, src->vars); shared_hash_destroy (dst->vars);
dst->vars = shared_hash_copy (src->vars);
dst->stack_adjust = src->stack_adjust; dst->stack_adjust = src->stack_adjust;
} }
@ -1129,15 +1236,14 @@ variable_union_info_cmp_pos (const void *n1, const void *n2)
static int static int
variable_union (void **slot, void *data) variable_union (void **slot, void *data)
{ {
variable src, dst, *dstp; variable src, dst;
void **dstp;
dataflow_set *set = (dataflow_set *) data; dataflow_set *set = (dataflow_set *) data;
int i, j, k; int i, j, k;
src = *(variable *) slot; src = *(variable *) slot;
dstp = (variable *) htab_find_slot_with_hash (set->vars, src->decl, dstp = shared_hash_find_slot (set->vars, src->decl);
VARIABLE_HASH_VAL (src->decl), if (!dstp || !*dstp)
INSERT);
if (!*dstp)
{ {
src->refcount++; src->refcount++;
@ -1162,16 +1268,23 @@ variable_union (void **slot, void *data)
if (! flag_var_tracking_uninit) if (! flag_var_tracking_uninit)
status = VAR_INIT_STATUS_INITIALIZED; status = VAR_INIT_STATUS_INITIALIZED;
if (dstp)
*dstp = (void *) src;
unshare_variable (set, src, status); unshare_variable (set, src, status);
} }
else else
*dstp = src; {
if (!dstp)
dstp = shared_hash_find_slot_unshare (&set->vars, src->decl,
INSERT);
*dstp = (void *) src;
}
/* Continue traversing the hash table. */ /* Continue traversing the hash table. */
return 1; return 1;
} }
else else
dst = *dstp; dst = (variable) *dstp;
gcc_assert (src->n_var_parts); gcc_assert (src->n_var_parts);
@ -1196,7 +1309,8 @@ variable_union (void **slot, void *data)
thus there are at most MAX_VAR_PARTS different offsets. */ thus there are at most MAX_VAR_PARTS different offsets. */
gcc_assert (k <= MAX_VAR_PARTS); gcc_assert (k <= MAX_VAR_PARTS);
if (dst->refcount > 1 && dst->n_var_parts != k) if ((dst->refcount > 1 || shared_hash_shared (set->vars))
&& dst->n_var_parts != k)
{ {
enum var_init_status status = VAR_INIT_STATUS_UNKNOWN; enum var_init_status status = VAR_INIT_STATUS_UNKNOWN;
@ -1226,7 +1340,7 @@ variable_union (void **slot, void *data)
/* If DST is shared compare the location chains. /* If DST is shared compare the location chains.
If they are different we will modify the chain in DST with If they are different we will modify the chain in DST with
high probability so make a copy of DST. */ high probability so make a copy of DST. */
if (dst->refcount > 1) if (dst->refcount > 1 || shared_hash_shared (set->vars))
{ {
for (node = src->var_part[i].loc_chain, for (node = src->var_part[i].loc_chain,
node2 = dst->var_part[j].loc_chain; node && node2; node2 = dst->var_part[j].loc_chain; node && node2;
@ -1379,6 +1493,46 @@ variable_union (void **slot, void *data)
return 1; return 1;
} }
/* Like variable_union, but only used when doing dataflow_set_union
into an empty hashtab. To allow sharing, dst is initially shared
with src (so all variables are "copied" from src to dst hashtab),
so only unshare_variable for variables that need canonicalization
are needed. */
static int
variable_canonicalize (void **slot, void *data)
{
variable src;
dataflow_set *set = (dataflow_set *) data;
int k;
src = *(variable *) slot;
/* If CUR_LOC of some variable part is not the first element of
the location chain we are going to change it so we have to make
a copy of the variable. */
for (k = 0; k < src->n_var_parts; k++)
{
gcc_assert (!src->var_part[k].loc_chain == !src->var_part[k].cur_loc);
if (src->var_part[k].loc_chain)
{
gcc_assert (src->var_part[k].cur_loc);
if (src->var_part[k].cur_loc != src->var_part[k].loc_chain->loc)
break;
}
}
if (k < src->n_var_parts)
{
enum var_init_status status = VAR_INIT_STATUS_UNKNOWN;
if (! flag_var_tracking_uninit)
status = VAR_INIT_STATUS_INITIALIZED;
unshare_variable (set, src, status);
}
return 1;
}
/* Compute union of dataflow sets SRC and DST and store it to DST. */ /* Compute union of dataflow sets SRC and DST and store it to DST. */
static void static void
@ -1389,7 +1543,14 @@ dataflow_set_union (dataflow_set *dst, dataflow_set *src)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
attrs_list_union (&dst->regs[i], src->regs[i]); attrs_list_union (&dst->regs[i], src->regs[i]);
htab_traverse (src->vars, variable_union, dst); if (dst->vars == empty_shared_hash)
{
shared_hash_destroy (dst->vars);
dst->vars = shared_hash_copy (src->vars);
htab_traverse (shared_hash_htab (src->vars), variable_canonicalize, dst);
}
else
htab_traverse (shared_hash_htab (src->vars), variable_union, dst);
} }
/* Flag whether two dataflow sets being compared contain different data. */ /* Flag whether two dataflow sets being compared contain different data. */
@ -1522,15 +1683,24 @@ dataflow_set_different_2 (void **slot, void *data)
static bool static bool
dataflow_set_different (dataflow_set *old_set, dataflow_set *new_set) dataflow_set_different (dataflow_set *old_set, dataflow_set *new_set)
{ {
if (old_set->vars == new_set->vars)
return false;
if (htab_elements (shared_hash_htab (old_set->vars))
!= htab_elements (shared_hash_htab (new_set->vars)))
return true;
dataflow_set_different_value = false; dataflow_set_different_value = false;
htab_traverse (old_set->vars, dataflow_set_different_1, new_set->vars); htab_traverse (shared_hash_htab (old_set->vars), dataflow_set_different_1,
shared_hash_htab (new_set->vars));
if (!dataflow_set_different_value) if (!dataflow_set_different_value)
{ {
/* We have compared the variables which are in both hash tables /* We have compared the variables which are in both hash tables
so now only check whether there are some variables in NEW_SET->VARS so now only check whether there are some variables in NEW_SET->VARS
which are not in OLD_SET->VARS. */ which are not in OLD_SET->VARS. */
htab_traverse (new_set->vars, dataflow_set_different_2, old_set->vars); htab_traverse (shared_hash_htab (new_set->vars), dataflow_set_different_2,
shared_hash_htab (old_set->vars));
} }
return dataflow_set_different_value; return dataflow_set_different_value;
} }
@ -1545,7 +1715,7 @@ dataflow_set_destroy (dataflow_set *set)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
attrs_list_clear (&set->regs[i]); attrs_list_clear (&set->regs[i]);
htab_delete (set->vars); shared_hash_destroy (set->vars);
set->vars = NULL; set->vars = NULL;
} }
@ -1985,7 +2155,6 @@ find_src_set_src (dataflow_set *set, rtx src)
{ {
tree decl = NULL_TREE; /* The variable being copied around. */ tree decl = NULL_TREE; /* The variable being copied around. */
rtx set_src = NULL_RTX; /* The value for "decl" stored in "src". */ rtx set_src = NULL_RTX; /* The value for "decl" stored in "src". */
void **slot;
variable var; variable var;
location_chain nextp; location_chain nextp;
int i; int i;
@ -1998,12 +2167,9 @@ find_src_set_src (dataflow_set *set, rtx src)
if (src && decl) if (src && decl)
{ {
slot = htab_find_slot_with_hash (set->vars, decl, var = shared_hash_find (set->vars, decl);
VARIABLE_HASH_VAL (decl), NO_INSERT); if (var)
if (slot)
{ {
var = *(variable *) slot;
found = false; found = false;
for (i = 0; i < var->n_var_parts && !found; i++) for (i = 0; i < var->n_var_parts && !found; i++)
for (nextp = var->var_part[i].loc_chain; nextp && !found; for (nextp = var->var_part[i].loc_chain; nextp && !found;
@ -2031,7 +2197,7 @@ compute_bb_dataflow (basic_block bb)
dataflow_set *in = &VTI (bb)->in; dataflow_set *in = &VTI (bb)->in;
dataflow_set *out = &VTI (bb)->out; dataflow_set *out = &VTI (bb)->out;
dataflow_set_init (&old_out, htab_elements (VTI (bb)->out.vars) + 3); dataflow_set_init (&old_out);
dataflow_set_copy (&old_out, out); dataflow_set_copy (&old_out, out);
dataflow_set_copy (out, in); dataflow_set_copy (out, in);
@ -2323,7 +2489,7 @@ dump_dataflow_set (dataflow_set *set)
dump_attrs_list (set->regs[i]); dump_attrs_list (set->regs[i]);
} }
} }
dump_vars (set->vars); dump_vars (shared_hash_htab (set->vars));
fprintf (dump_file, "\n"); fprintf (dump_file, "\n");
} }
@ -2345,10 +2511,10 @@ dump_dataflow_sets (void)
} }
/* Add variable VAR to the hash table of changed variables and /* Add variable VAR to the hash table of changed variables and
if it has no locations delete it from hash table HTAB. */ if it has no locations delete it from SET's hash table. */
static void static void
variable_was_changed (variable var, htab_t htab) variable_was_changed (variable var, dataflow_set *set)
{ {
hashval_t hash = VARIABLE_HASH_VAL (var->decl); hashval_t hash = VARIABLE_HASH_VAL (var->decl);
@ -2359,36 +2525,39 @@ variable_was_changed (variable var, htab_t htab)
slot = (variable *) htab_find_slot_with_hash (changed_variables, slot = (variable *) htab_find_slot_with_hash (changed_variables,
var->decl, hash, INSERT); var->decl, hash, INSERT);
if (htab && var->n_var_parts == 0) if (set && var->n_var_parts == 0)
{ {
variable empty_var; variable empty_var;
void **old;
empty_var = (variable) pool_alloc (var_pool); empty_var = (variable) pool_alloc (var_pool);
empty_var->decl = var->decl; empty_var->decl = var->decl;
empty_var->refcount = 1; empty_var->refcount = 1;
empty_var->n_var_parts = 0; empty_var->n_var_parts = 0;
*slot = empty_var; *slot = empty_var;
goto drop_var;
old = htab_find_slot_with_hash (htab, var->decl, hash,
NO_INSERT);
if (old)
htab_clear_slot (htab, old);
} }
else else
{ {
var->refcount++;
*slot = var; *slot = var;
} }
} }
else else
{ {
gcc_assert (htab); gcc_assert (set);
if (var->n_var_parts == 0) if (var->n_var_parts == 0)
{ {
void **slot = htab_find_slot_with_hash (htab, var->decl, hash, void **slot;
NO_INSERT);
drop_var:
slot = shared_hash_find_slot_noinsert (set->vars, var->decl);
if (slot) if (slot)
htab_clear_slot (htab, slot); {
if (shared_hash_shared (set->vars))
slot = shared_hash_find_slot_unshare (&set->vars, var->decl,
NO_INSERT);
htab_clear_slot (shared_hash_htab (set->vars), slot);
}
} }
} }
} }
@ -2438,12 +2607,12 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset,
location_chain node, next; location_chain node, next;
location_chain *nextp; location_chain *nextp;
variable var; variable var;
void **slot; void **slot = shared_hash_find_slot (set->vars, decl);
slot = htab_find_slot_with_hash (set->vars, decl, if (!slot || !*slot)
VARIABLE_HASH_VAL (decl), INSERT);
if (!*slot)
{ {
if (!slot)
slot = shared_hash_find_slot_unshare (&set->vars, decl, INSERT);
/* Create new variable information. */ /* Create new variable information. */
var = (variable) pool_alloc (var_pool); var = (variable) pool_alloc (var_pool);
var->decl = decl; var->decl = decl;
@ -2479,13 +2648,12 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset,
if (set_src != NULL) if (set_src != NULL)
node->set_src = set_src; node->set_src = set_src;
*slot = var;
return; return;
} }
else else
{ {
/* We have to make a copy of a shared variable. */ /* We have to make a copy of a shared variable. */
if (var->refcount > 1) if (var->refcount > 1 || shared_hash_shared (set->vars))
var = unshare_variable (set, var, initialized); var = unshare_variable (set, var, initialized);
} }
} }
@ -2494,7 +2662,7 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset,
/* We have not found the location part, new one will be created. */ /* We have not found the location part, new one will be created. */
/* We have to make a copy of the shared variable. */ /* We have to make a copy of the shared variable. */
if (var->refcount > 1) if (var->refcount > 1 || shared_hash_shared (set->vars))
var = unshare_variable (set, var, initialized); var = unshare_variable (set, var, initialized);
/* We track only variables whose size is <= MAX_VAR_PARTS bytes /* We track only variables whose size is <= MAX_VAR_PARTS bytes
@ -2548,7 +2716,7 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset,
if (var->var_part[pos].cur_loc == NULL) if (var->var_part[pos].cur_loc == NULL)
{ {
var->var_part[pos].cur_loc = loc; var->var_part[pos].cur_loc = loc;
variable_was_changed (var, set->vars); variable_was_changed (var, set);
} }
} }
@ -2561,16 +2729,14 @@ static void
clobber_variable_part (dataflow_set *set, rtx loc, tree decl, clobber_variable_part (dataflow_set *set, rtx loc, tree decl,
HOST_WIDE_INT offset, rtx set_src) HOST_WIDE_INT offset, rtx set_src)
{ {
void **slot; variable var;
if (! decl || ! DECL_P (decl)) if (! decl || ! DECL_P (decl))
return; return;
slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl), var = shared_hash_find (set->vars, decl);
NO_INSERT); if (var)
if (slot)
{ {
variable var = (variable) *slot;
int pos = find_variable_location_part (var, offset, NULL); int pos = find_variable_location_part (var, offset, NULL);
if (pos >= 0) if (pos >= 0)
@ -2627,13 +2793,9 @@ static void
delete_variable_part (dataflow_set *set, rtx loc, tree decl, delete_variable_part (dataflow_set *set, rtx loc, tree decl,
HOST_WIDE_INT offset) HOST_WIDE_INT offset)
{ {
void **slot; variable var = shared_hash_find (set->vars, decl);;
if (var)
slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl),
NO_INSERT);
if (slot)
{ {
variable var = (variable) *slot;
int pos = find_variable_location_part (var, offset, NULL); int pos = find_variable_location_part (var, offset, NULL);
if (pos >= 0) if (pos >= 0)
@ -2642,7 +2804,7 @@ delete_variable_part (dataflow_set *set, rtx loc, tree decl,
location_chain *nextp; location_chain *nextp;
bool changed; bool changed;
if (var->refcount > 1) if (var->refcount > 1 || shared_hash_shared (set->vars))
{ {
/* If the variable contains the location part we have to /* If the variable contains the location part we have to
make a copy of the variable. */ make a copy of the variable. */
@ -2705,7 +2867,7 @@ delete_variable_part (dataflow_set *set, rtx loc, tree decl,
} }
} }
if (changed) if (changed)
variable_was_changed (var, set->vars); variable_was_changed (var, set);
} }
} }
} }
@ -2864,14 +3026,6 @@ emit_note_insn_var_location (void **varp, void *data)
htab_clear_slot (changed_variables, varp); htab_clear_slot (changed_variables, varp);
/* When there are no location parts the variable has been already
removed from hash table and a new empty variable was created.
Free the empty variable. */
if (var->n_var_parts == 0)
{
pool_free (var_pool, var);
}
/* Continue traversing the hash table. */ /* Continue traversing the hash table. */
return 1; return 1;
} }
@ -2910,7 +3064,7 @@ emit_notes_for_differences_1 (void **slot, void *data)
empty_var = (variable) pool_alloc (var_pool); empty_var = (variable) pool_alloc (var_pool);
empty_var->decl = old_var->decl; empty_var->decl = old_var->decl;
empty_var->refcount = 1; empty_var->refcount = 0;
empty_var->n_var_parts = 0; empty_var->n_var_parts = 0;
variable_was_changed (empty_var, NULL); variable_was_changed (empty_var, NULL);
} }
@ -2952,8 +3106,12 @@ static void
emit_notes_for_differences (rtx insn, dataflow_set *old_set, emit_notes_for_differences (rtx insn, dataflow_set *old_set,
dataflow_set *new_set) dataflow_set *new_set)
{ {
htab_traverse (old_set->vars, emit_notes_for_differences_1, new_set->vars); htab_traverse (shared_hash_htab (old_set->vars),
htab_traverse (new_set->vars, emit_notes_for_differences_2, old_set->vars); emit_notes_for_differences_1,
shared_hash_htab (new_set->vars));
htab_traverse (shared_hash_htab (new_set->vars),
emit_notes_for_differences_2,
shared_hash_htab (old_set->vars));
emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN); emit_notes_for_changes (insn, EMIT_NOTE_BEFORE_INSN);
} }
@ -2965,7 +3123,7 @@ emit_notes_in_bb (basic_block bb)
int i; int i;
dataflow_set set; dataflow_set set;
dataflow_set_init (&set, htab_elements (VTI (bb)->in.vars) + 3); dataflow_set_init (&set);
dataflow_set_copy (&set, &VTI (bb)->in); dataflow_set_copy (&set, &VTI (bb)->in);
for (i = 0; i < VTI (bb)->n_mos; i++) for (i = 0; i < VTI (bb)->n_mos; i++)
@ -3098,7 +3256,7 @@ vt_emit_notes (void)
delete_variable_part). */ delete_variable_part). */
emit_notes = true; emit_notes = true;
dataflow_set_init (&empty, 7); dataflow_set_init (&empty);
last_out = &empty; last_out = &empty;
FOR_EACH_BB (bb) FOR_EACH_BB (bb)
@ -3343,14 +3501,6 @@ vt_initialize (void)
} }
} }
/* Init the IN and OUT sets. */
FOR_ALL_BB (bb)
{
VTI (bb)->visited = false;
dataflow_set_init (&VTI (bb)->in, 7);
dataflow_set_init (&VTI (bb)->out, 7);
}
attrs_pool = create_alloc_pool ("attrs_def pool", attrs_pool = create_alloc_pool ("attrs_def pool",
sizeof (struct attrs_def), 1024); sizeof (struct attrs_def), 1024);
var_pool = create_alloc_pool ("variable_def pool", var_pool = create_alloc_pool ("variable_def pool",
@ -3358,8 +3508,24 @@ vt_initialize (void)
loc_chain_pool = create_alloc_pool ("location_chain_def pool", loc_chain_pool = create_alloc_pool ("location_chain_def pool",
sizeof (struct location_chain_def), sizeof (struct location_chain_def),
1024); 1024);
shared_hash_pool = create_alloc_pool ("shared_hash_def pool",
sizeof (struct shared_hash_def), 256);
empty_shared_hash = (shared_hash) pool_alloc (shared_hash_pool);
empty_shared_hash->refcount = 1;
empty_shared_hash->htab
= htab_create (1, variable_htab_hash, variable_htab_eq,
variable_htab_free);
changed_variables = htab_create (10, variable_htab_hash, variable_htab_eq, changed_variables = htab_create (10, variable_htab_hash, variable_htab_eq,
NULL); variable_htab_free);
/* Init the IN and OUT sets. */
FOR_ALL_BB (bb)
{
VTI (bb)->visited = false;
dataflow_set_init (&VTI (bb)->in);
dataflow_set_init (&VTI (bb)->out);
}
vt_add_function_parameters (); vt_add_function_parameters ();
} }
@ -3381,10 +3547,12 @@ vt_finalize (void)
dataflow_set_destroy (&VTI (bb)->out); dataflow_set_destroy (&VTI (bb)->out);
} }
free_aux_for_blocks (); free_aux_for_blocks ();
htab_delete (empty_shared_hash->htab);
htab_delete (changed_variables);
free_alloc_pool (attrs_pool); free_alloc_pool (attrs_pool);
free_alloc_pool (var_pool); free_alloc_pool (var_pool);
free_alloc_pool (loc_chain_pool); free_alloc_pool (loc_chain_pool);
htab_delete (changed_variables); free_alloc_pool (shared_hash_pool);
} }
/* The entry point to variable tracking pass. */ /* The entry point to variable tracking pass. */