From d24686d79d57c495c0bc30fdfd862584ae7cc453 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sun, 21 Jun 2009 11:38:34 +0200 Subject: [PATCH] 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 --- gcc/ChangeLog | 59 ++++++++ gcc/var-tracking.c | 370 ++++++++++++++++++++++++++++++++------------- 2 files changed, 328 insertions(+), 101 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 50f17b78fa1..4478145e380 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,62 @@ +2009-06-21 Jakub Jelinek + + * 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 * config/moxie/sfp-machine.h (__gcc_CMPtype, CMPtype): Define. diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index c4c3f3ec316..56e50c2c36d 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -182,6 +182,17 @@ typedef struct attrs_def HOST_WIDE_INT offset; } *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. */ typedef struct dataflow_set_def { @@ -192,7 +203,7 @@ typedef struct dataflow_set_def attrs regs[FIRST_PSEUDO_REGISTER]; /* Variable locations. */ - htab_t vars; + shared_hash vars; } dataflow_set; /* 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. */ 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. */ static htab_t changed_variables; /* Shall notes be emitted? */ static bool emit_notes; +/* Empty shared hashtable. */ +static shared_hash empty_shared_hash; + /* Local function prototypes. */ static void stack_adjust_offset_pre_post (rtx, 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_union (attrs *, attrs); -static void vars_clear (htab_t); static variable unshare_variable (dataflow_set *set, variable var, enum var_init_status); 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); 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_copy (dataflow_set *, dataflow_set *); static int variable_union_info_cmp_pos (const void *, const void *); static int variable_union (void **, void *); +static int variable_canonicalize (void **, void *); static void dataflow_set_union (dataflow_set *, dataflow_set *); static bool variable_part_different_p (variable_part *, variable_part *); 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_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, enum var_init_status, rtx); 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 -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. */ @@ -801,9 +913,7 @@ unshare_variable (dataflow_set *set, variable var, 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 = shared_hash_find_slot_unshare (&set->vars, new_var->decl, INSERT); *slot = new_var; return new_var; } @@ -834,8 +944,7 @@ vars_copy_1 (void **slot, void *data) static void vars_copy (htab_t dst, htab_t src) { - vars_clear (dst); - htab_traverse (src, vars_copy_1, dst); + htab_traverse_noresize (src, vars_copy_1, dst); } /* 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 get_init_value (dataflow_set *set, rtx loc, tree decl) { - void **slot; variable var; int i; 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) return VAR_INIT_STATUS_INITIALIZED; - slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl), - NO_INSERT); - if (slot) + var = shared_hash_find (set->vars, decl); + if (var) { - var = * (variable *) slot; for (i = 0; i < var->n_var_parts && ret_val == VAR_INIT_STATUS_UNKNOWN; i++) { 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. */ static void -dataflow_set_init (dataflow_set *set, int vars_size) +dataflow_set_init (dataflow_set *set) { init_attrs_list_set (set->regs); - set->vars = htab_create (vars_size, variable_htab_hash, variable_htab_eq, - variable_htab_free); + set->vars = shared_hash_copy (empty_shared_hash); set->stack_adjust = 0; } @@ -1068,7 +1173,8 @@ dataflow_set_clear (dataflow_set *set) for (i = 0; i < FIRST_PSEUDO_REGISTER; 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. */ @@ -1081,7 +1187,8 @@ dataflow_set_copy (dataflow_set *dst, dataflow_set *src) for (i = 0; i < FIRST_PSEUDO_REGISTER; 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; } @@ -1129,15 +1236,14 @@ variable_union_info_cmp_pos (const void *n1, const void *n2) static int variable_union (void **slot, void *data) { - variable src, dst, *dstp; + variable src, dst; + void **dstp; dataflow_set *set = (dataflow_set *) data; int i, j, k; src = *(variable *) slot; - dstp = (variable *) htab_find_slot_with_hash (set->vars, src->decl, - VARIABLE_HASH_VAL (src->decl), - INSERT); - if (!*dstp) + dstp = shared_hash_find_slot (set->vars, src->decl); + if (!dstp || !*dstp) { src->refcount++; @@ -1162,16 +1268,23 @@ variable_union (void **slot, void *data) if (! flag_var_tracking_uninit) status = VAR_INIT_STATUS_INITIALIZED; + if (dstp) + *dstp = (void *) src; unshare_variable (set, src, status); } else - *dstp = src; + { + if (!dstp) + dstp = shared_hash_find_slot_unshare (&set->vars, src->decl, + INSERT); + *dstp = (void *) src; + } /* Continue traversing the hash table. */ return 1; } else - dst = *dstp; + dst = (variable) *dstp; 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. */ 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; @@ -1226,7 +1340,7 @@ variable_union (void **slot, void *data) /* If DST is shared compare the location chains. If they are different we will modify the chain in DST with high probability so make a copy of DST. */ - if (dst->refcount > 1) + if (dst->refcount > 1 || shared_hash_shared (set->vars)) { for (node = src->var_part[i].loc_chain, node2 = dst->var_part[j].loc_chain; node && node2; @@ -1379,6 +1493,46 @@ variable_union (void **slot, void *data) return 1; } +/* Like variable_union, but only used when doing dataflow_set_union + into an empty hashtab. To allow sharing, dst is initially shared + with src (so all variables are "copied" from src to dst hashtab), + so only unshare_variable for variables that need canonicalization + are needed. */ + +static int +variable_canonicalize (void **slot, void *data) +{ + variable src; + dataflow_set *set = (dataflow_set *) data; + int k; + + src = *(variable *) slot; + + /* If CUR_LOC of some variable part is not the first element of + the location chain we are going to change it so we have to make + a copy of the variable. */ + for (k = 0; k < src->n_var_parts; k++) + { + gcc_assert (!src->var_part[k].loc_chain == !src->var_part[k].cur_loc); + if (src->var_part[k].loc_chain) + { + gcc_assert (src->var_part[k].cur_loc); + if (src->var_part[k].cur_loc != src->var_part[k].loc_chain->loc) + break; + } + } + if (k < src->n_var_parts) + { + 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. */ static void @@ -1389,7 +1543,14 @@ dataflow_set_union (dataflow_set *dst, dataflow_set *src) for (i = 0; i < FIRST_PSEUDO_REGISTER; 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. */ @@ -1522,15 +1683,24 @@ dataflow_set_different_2 (void **slot, void *data) static bool 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; - 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) { /* We have compared the variables which are in both hash tables so now only check whether there are some variables in NEW_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; } @@ -1545,7 +1715,7 @@ dataflow_set_destroy (dataflow_set *set) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) attrs_list_clear (&set->regs[i]); - htab_delete (set->vars); + shared_hash_destroy (set->vars); 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. */ rtx set_src = NULL_RTX; /* The value for "decl" stored in "src". */ - void **slot; variable var; location_chain nextp; int i; @@ -1998,12 +2167,9 @@ find_src_set_src (dataflow_set *set, rtx src) if (src && decl) { - slot = htab_find_slot_with_hash (set->vars, decl, - VARIABLE_HASH_VAL (decl), NO_INSERT); - - if (slot) + var = shared_hash_find (set->vars, decl); + if (var) { - var = *(variable *) slot; found = false; for (i = 0; i < var->n_var_parts && !found; i++) 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 *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 (out, in); @@ -2323,7 +2489,7 @@ dump_dataflow_set (dataflow_set *set) dump_attrs_list (set->regs[i]); } } - dump_vars (set->vars); + dump_vars (shared_hash_htab (set->vars)); fprintf (dump_file, "\n"); } @@ -2345,10 +2511,10 @@ dump_dataflow_sets (void) } /* 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 -variable_was_changed (variable var, htab_t htab) +variable_was_changed (variable var, dataflow_set *set) { 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, var->decl, hash, INSERT); - if (htab && var->n_var_parts == 0) + if (set && var->n_var_parts == 0) { variable empty_var; - void **old; empty_var = (variable) pool_alloc (var_pool); empty_var->decl = var->decl; empty_var->refcount = 1; empty_var->n_var_parts = 0; *slot = empty_var; - - old = htab_find_slot_with_hash (htab, var->decl, hash, - NO_INSERT); - if (old) - htab_clear_slot (htab, old); + goto drop_var; } else { + var->refcount++; *slot = var; } } else { - gcc_assert (htab); + gcc_assert (set); if (var->n_var_parts == 0) { - void **slot = htab_find_slot_with_hash (htab, var->decl, hash, - NO_INSERT); + void **slot; + + drop_var: + slot = shared_hash_find_slot_noinsert (set->vars, var->decl); 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 *nextp; variable var; - void **slot; - - slot = htab_find_slot_with_hash (set->vars, decl, - VARIABLE_HASH_VAL (decl), INSERT); - if (!*slot) + void **slot = shared_hash_find_slot (set->vars, decl); + + if (!slot || !*slot) { + if (!slot) + slot = shared_hash_find_slot_unshare (&set->vars, decl, INSERT); /* Create new variable information. */ var = (variable) pool_alloc (var_pool); 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) node->set_src = set_src; - *slot = var; return; } else { /* 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); } } @@ -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 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); /* 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) { 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, HOST_WIDE_INT offset, rtx set_src) { - void **slot; + variable var; if (! decl || ! DECL_P (decl)) return; - slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl), - NO_INSERT); - if (slot) + var = shared_hash_find (set->vars, decl); + if (var) { - variable var = (variable) *slot; int pos = find_variable_location_part (var, offset, NULL); if (pos >= 0) @@ -2627,13 +2793,9 @@ static void delete_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset) { - void **slot; - - slot = htab_find_slot_with_hash (set->vars, decl, VARIABLE_HASH_VAL (decl), - NO_INSERT); - if (slot) + variable var = shared_hash_find (set->vars, decl);; + if (var) { - variable var = (variable) *slot; int pos = find_variable_location_part (var, offset, NULL); if (pos >= 0) @@ -2642,7 +2804,7 @@ delete_variable_part (dataflow_set *set, rtx loc, tree decl, location_chain *nextp; 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 make a copy of the variable. */ @@ -2705,7 +2867,7 @@ delete_variable_part (dataflow_set *set, rtx loc, tree decl, } } 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); - /* 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. */ return 1; } @@ -2910,7 +3064,7 @@ emit_notes_for_differences_1 (void **slot, void *data) empty_var = (variable) pool_alloc (var_pool); empty_var->decl = old_var->decl; - empty_var->refcount = 1; + empty_var->refcount = 0; empty_var->n_var_parts = 0; variable_was_changed (empty_var, NULL); } @@ -2952,8 +3106,12 @@ static void emit_notes_for_differences (rtx insn, dataflow_set *old_set, dataflow_set *new_set) { - htab_traverse (old_set->vars, emit_notes_for_differences_1, new_set->vars); - htab_traverse (new_set->vars, emit_notes_for_differences_2, old_set->vars); + htab_traverse (shared_hash_htab (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); } @@ -2965,7 +3123,7 @@ emit_notes_in_bb (basic_block bb) int i; 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); for (i = 0; i < VTI (bb)->n_mos; i++) @@ -3098,7 +3256,7 @@ vt_emit_notes (void) delete_variable_part). */ emit_notes = true; - dataflow_set_init (&empty, 7); + dataflow_set_init (&empty); last_out = ∅ 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", sizeof (struct attrs_def), 1024); 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", sizeof (struct location_chain_def), 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, - 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 (); } @@ -3381,10 +3547,12 @@ vt_finalize (void) dataflow_set_destroy (&VTI (bb)->out); } free_aux_for_blocks (); + htab_delete (empty_shared_hash->htab); + htab_delete (changed_variables); free_alloc_pool (attrs_pool); free_alloc_pool (var_pool); free_alloc_pool (loc_chain_pool); - htab_delete (changed_variables); + free_alloc_pool (shared_hash_pool); } /* The entry point to variable tracking pass. */