diff options
author | zlomek <zlomek@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-03-11 08:05:14 +0000 |
---|---|---|
committer | zlomek <zlomek@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-03-11 08:05:14 +0000 |
commit | 85bbdb3f23b548c1b3d911646b528afe5c885b57 (patch) | |
tree | 8ce1eecafee1cf882113fbad7789e4dd621695cf /gcc/var-tracking.c | |
parent | 6175885e8a1e9e972eac8b32b93f3ea9b236092d (diff) | |
download | gcc-85bbdb3f23b548c1b3d911646b528afe5c885b57.tar.gz |
PR/14362
* var-tracking.c (struct variable_def): Added field refcount.
(variable_htab_free): Decrease the refcount and delete variable
only if there are no more references.
(unshare_variable): New function.
(vars_copy_1): Increase refcount instead of copying the variable.
(variable_union): Share the variables where possible, unshare
the variables if needed.
(variable_different_p): Return false if var1 and var2 are
the same structure.
(variable_was_changed): Init the refcount of new variable.
(set_frame_base_location): Unshare variable if needed.
(set_variable_part): Init the refcount of new variable.
Unshare the variables if needed.
(delete_variable_part): Unshare the variables if needed.
(emit_notes_for_differences_1): Init the refcount of new variable.
(vt_add_function_parameters): Do not add function parameters to
IN set of ENTRY_BLOCK_PTR because it is unused anyway.
(vt_initialize): Do not add frame_base_decl to IN set of
ENTRY_BLOCK_PTR because it is unused anyway.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@79307 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/var-tracking.c')
-rw-r--r-- | gcc/var-tracking.c | 204 |
1 files changed, 166 insertions, 38 deletions
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index 5b586bc55aa..5da23768366 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -233,6 +233,9 @@ typedef struct variable_def /* The declaration of the variable. */ tree decl; + /* Reference count. */ + int refcount; + /* Number of variable parts. */ int n_var_parts; @@ -285,6 +288,7 @@ 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); 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); @@ -629,6 +633,15 @@ variable_htab_free (void *elem) 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) @@ -732,32 +745,29 @@ vars_clear (htab_t vars) 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; @@ -771,12 +781,36 @@ vars_copy_1 (void **slot, void *data) /* 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; } @@ -972,9 +1006,37 @@ variable_union (void **slot, void *data) 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; @@ -998,10 +1060,8 @@ variable_union (void **slot, void *data) 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. */ @@ -1009,13 +1069,16 @@ variable_union (void **slot, void *data) 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) @@ -1026,7 +1089,26 @@ variable_union (void **slot, void *data) 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++; @@ -1187,6 +1269,9 @@ variable_different_p (variable var1, variable var2) { int i; + if (var1 == var2) + return false; + if (var1->n_var_parts != var2->n_var_parts) return true; @@ -1791,6 +1876,7 @@ variable_was_changed (variable var, htab_t htab) empty_var = pool_alloc (var_pool); empty_var->decl = var->decl; + empty_var->refcount = 1; empty_var->n_var_parts = 0; *slot = empty_var; @@ -1843,7 +1929,12 @@ set_frame_base_location (dataflow_set *set, rtx loc) 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); } @@ -1867,6 +1958,7 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset) /* 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; @@ -1891,9 +1983,33 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset) } 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 @@ -1914,7 +2030,7 @@ set_variable_part (dataflow_set *set, rtx loc, tree decl, HOST_WIDE_INT offset) } } - /* 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) { @@ -1981,6 +2097,23 @@ delete_variable_part (dataflow_set *set, rtx loc, tree decl, 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) @@ -2149,6 +2282,7 @@ emit_notes_for_differences_1 (void **slot, void *data) 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); } @@ -2357,7 +2491,7 @@ vt_add_function_parameters (void) 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; @@ -2386,7 +2520,6 @@ vt_add_function_parameters (void) 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) @@ -2395,16 +2528,12 @@ vt_add_function_parameters (void) 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); } } @@ -2564,7 +2693,6 @@ vt_initialize (void) /* 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 |