2010-02-17 Alexandre Oliva * var-tracking.c (dataflow_set_preserve_mem_locs): Update cur_loc. 2010-02-17 Jakub Jelinek PR debug/43051 * var-tracking.c (struct dfset_merge): Move definition earlier. (value_pair): New variable. (ignore_first_value_pair): New function. (find_loc_in_1pdv_1): Change last argument to struct dfset_merge *. If node->loc is VALUE, don't call rtx_equal_p at all, instead just compare pointers and then recurse. For other rtxes, call rtx_equal_p_cb instead of rtx_equal_p and ignore first VALUE pair during comparison, if some has been found, compare those VALUEs recursively. (find_loc_in_1pdv): Change last argument to struct dfset_merge *. (intersect_loc_chains, variable_post_merge_perm_vals): Adjust callers. * gcc.dg/guality/pr43051-1.c: New test. --- gcc/var-tracking.c.jj 2010-02-07 11:53:22.000000000 +0100 +++ gcc/var-tracking.c 2010-02-15 12:37:00.000000000 +0100 @@ -428,7 +428,8 @@ static int variable_union_info_cmp_pos ( static int variable_union (void **, void *); static int variable_canonicalize (void **, void *); static void dataflow_set_union (dataflow_set *, dataflow_set *); -static location_chain find_loc_in_1pdv (rtx, variable, htab_t); +struct dfset_merge; +static location_chain find_loc_in_1pdv (rtx, variable, struct dfset_merge *); static bool canon_value_cmp (rtx, rtx); static int loc_cmp (rtx, rtx); static bool variable_part_different_p (variable_part *, variable_part *); @@ -2234,6 +2235,53 @@ dv_changed_p (decl_or_value dv) : DECL_CHANGED (dv_as_decl (dv))); } +/* Hash table iteration argument passed to variable_merge. */ +struct dfset_merge +{ + /* The set in which the merge is to be inserted. */ + dataflow_set *dst; + /* The set that we're iterating in. */ + dataflow_set *cur; + /* The set that may contain the other dv we are to merge with. */ + dataflow_set *src; + /* Number of onepart dvs in src. */ + int src_onepart_cnt; +}; + +/* First encountered differing VALUE pair remembered by + ignore_first_value_pair hook. */ + +static rtx value_pair[2]; + +/* Helper for rtx_equal_p_cb. Pretend the first encountered VALUE pair + is the same and remember it. */ + +static int +ignore_first_value_pair (const_rtx *px, const_rtx *py, rtx *nx, rtx *ny) +{ + const_rtx x = *px, y; + + if (GET_CODE (x) != VALUE) + return 0; + y = *py; + if (GET_CODE (y) != VALUE) + return 0; + if (x == y) + return 0; + if (GET_MODE (x) != GET_MODE (y)) + return 0; + /* If this isn't the first encountered VALUE pair, fail. */ + if (value_pair[0]) + return 0; + /* Remember the first encountered VALUE pair and pretend the VALUEs are the + same. */ + value_pair[0] = CONST_CAST_RTX (x); + value_pair[1] = CONST_CAST_RTX (y); + *nx = CONST_CAST_RTX (x); + *ny = CONST_CAST_RTX (x); + return 1; +} + /* Vector of VALUEs that should have VALUE_RECURSED_INTO bit cleared at the end of find_loc_in_1pdv. Not a static variable in find_loc_in_1pdv to avoid constant allocation/freeing of it. */ @@ -2245,7 +2293,7 @@ static VEC(rtx, heap) *values_to_unmark; any values recursively mentioned in the location lists. */ static location_chain -find_loc_in_1pdv_1 (rtx loc, variable var, htab_t vars) +find_loc_in_1pdv_1 (rtx loc, variable var, struct dfset_merge *dsm) { location_chain node; @@ -2260,22 +2308,65 @@ find_loc_in_1pdv_1 (rtx loc, variable va gcc_assert (var->var_part[0].offset == 0); for (node = var->var_part[0].loc_chain; node; node = node->next) - if (rtx_equal_p (loc, node->loc)) - return node; - else if (GET_CODE (node->loc) == VALUE - && !VALUE_RECURSED_INTO (node->loc)) + if (GET_CODE (node->loc) == VALUE) { - decl_or_value dv = dv_from_value (node->loc); - variable var = (variable) - htab_find_with_hash (vars, dv, dv_htab_hash (dv)); + if (loc == node->loc) + return node; + if (!VALUE_RECURSED_INTO (node->loc)) + { + decl_or_value dv = dv_from_value (node->loc); + htab_t vars = shared_hash_htab (dsm->src->vars); + variable var + = (variable) htab_find_with_hash (vars, dv, dv_htab_hash (dv)); - if (var) + if (var) + { + location_chain where; + VALUE_RECURSED_INTO (node->loc) = true; + VEC_safe_push (rtx, heap, values_to_unmark, node->loc); + if ((where = find_loc_in_1pdv_1 (loc, var, dsm))) + return where; + } + } + } + else if (GET_CODE (node->loc) == GET_CODE (loc)) + { + rtx val1, val2; + if (!rtx_equal_p_cb (loc, node->loc, ignore_first_value_pair)) { - location_chain where; - VALUE_RECURSED_INTO (node->loc) = true; - VEC_safe_push (rtx, heap, values_to_unmark, node->loc); - if ((where = find_loc_in_1pdv_1 (loc, var, vars))) - return where; + value_pair[0] = NULL; + value_pair[1] = NULL; + continue; + } + if (!value_pair[0]) + return node; + val1 = value_pair[0]; + val2 = value_pair[1]; + value_pair[0] = NULL; + value_pair[1] = NULL; + if (dsm->cur) + { + decl_or_value dv; + htab_t vars; + variable var1, var2; + dv = dv_from_value (val1); + vars = shared_hash_htab (dsm->cur->vars); + var1 = (variable) htab_find_with_hash (vars, dv, + dv_htab_hash (dv)); + if (var1) + { + dv = dv_from_value (val2); + vars = shared_hash_htab (dsm->src->vars); + var2 = (variable) htab_find_with_hash (vars, dv, + dv_htab_hash (dv)); + if (var2) + { + location_chain s1node = var1->var_part[0].loc_chain; + for (; s1node; s1node = s1node->next) + if (find_loc_in_1pdv_1 (s1node->loc, var2, dsm)) + return node; + } + } } } @@ -2287,32 +2378,19 @@ find_loc_in_1pdv_1 (rtx loc, variable va any values recursively mentioned in the location lists. */ static location_chain -find_loc_in_1pdv (rtx loc, variable var, htab_t vars) +find_loc_in_1pdv (rtx loc, variable var, struct dfset_merge *dsm) { location_chain ret; unsigned int i; rtx value; - ret = find_loc_in_1pdv_1 (loc, var, vars); + ret = find_loc_in_1pdv_1 (loc, var, dsm); for (i = 0; VEC_iterate (rtx, values_to_unmark, i, value); i++) VALUE_RECURSED_INTO (value) = false; VEC_truncate (rtx, values_to_unmark, 0); return ret; } -/* Hash table iteration argument passed to variable_merge. */ -struct dfset_merge -{ - /* The set in which the merge is to be inserted. */ - dataflow_set *dst; - /* The set that we're iterating in. */ - dataflow_set *cur; - /* The set that may contain the other dv we are to merge with. */ - dataflow_set *src; - /* Number of onepart dvs in src. */ - int src_onepart_cnt; -}; - /* Insert LOC in *DNODE, if it's not there yet. The list must be in loc_cmp order, and it is maintained as such. */ @@ -2351,7 +2429,6 @@ intersect_loc_chains (rtx val, location_ location_chain s1node, variable s2var) { dataflow_set *s1set = dsm->cur; - dataflow_set *s2set = dsm->src; location_chain found; for (; s1node; s1node = s1node->next) @@ -2359,8 +2436,7 @@ intersect_loc_chains (rtx val, location_ if (s1node->loc == val) continue; - if ((found = find_loc_in_1pdv (s1node->loc, s2var, - shared_hash_htab (s2set->vars)))) + if ((found = find_loc_in_1pdv (s1node->loc, s2var, dsm))) { insert_into_intersection (dest, s1node->loc, MIN (s1node->init, found->init)); @@ -3592,7 +3668,10 @@ variable_post_merge_perm_vals (void **ps var = shared_hash_find (set->vars, dv); if (var) { - if (find_loc_in_1pdv (pnode->loc, var, shared_hash_htab (set->vars))) + struct dfset_merge dsm; + memset (&dsm, '\0', sizeof (dsm)); + dsm.src = set; + if (find_loc_in_1pdv (pnode->loc, var, &dsm)) return 1; val_reset (set, dv); } @@ -3808,6 +3808,7 @@ dataflow_set_preserve_mem_locs (void **s { tree decl = dv_as_decl (var->dv); location_chain loc, *locp; + bool changed = false; if (!var->n_var_parts) return 1; @@ -3881,6 +3882,9 @@ dataflow_set_preserve_mem_locs (void **s if (emit_notes) remove_value_chains (var->dv, old_loc); *locp = loc->next; + if (var->var_part[0].cur_loc + && rtx_equal_p (loc->loc, var->var_part[0].cur_loc)) + changed = true; pool_free (loc_chain_pool, loc); } @@ -3889,6 +3893,12 @@ dataflow_set_preserve_mem_locs (void **s var->n_var_parts--; if (emit_notes && dv_is_value_p (var->dv)) remove_cselib_value_chains (var->dv); + gcc_assert (changed); + } + if (changed) + { + if (var->n_var_parts && var->var_part[0].loc_chain) + var->var_part[0].cur_loc = var->var_part[0].loc_chain->loc; variable_was_changed (var, set); } } --- gcc/testsuite/gcc.dg/guality/pr43051-1.c.jj 2010-02-17 10:17:12.000000000 +0100 +++ gcc/testsuite/gcc.dg/guality/pr43051-1.c 2010-02-17 10:41:43.000000000 +0100 @@ -0,0 +1,57 @@ +/* PR debug/43051 */ +/* { dg-do run } */ +/* { dg-options "-g" } */ + +extern void abort (void); + +static void __attribute__ ((noinline)) +foo (const char *x, long long y, int z) +{ + asm volatile ("" : : "r" (x), "r" ((int) y), "r" (z) : "memory"); +} + +struct S +{ + struct S *n; + int v; +}; + +struct S a[10]; + +struct S * __attribute__ ((noinline)) +bar (struct S *c, int v, struct S *e) +{ +#ifdef __i386__ + register int si asm ("esi"), di asm ("edi"), bx +# if !defined (__pic__) && !defined (__APPLE__) + asm ("ebx") +# endif + ; + asm volatile ("" : "=r" (si), "=r" (di), "=r" (bx)); +#endif + while (c < e) + { + foo ("c", (unsigned long) c, 0); /* { dg-final { gdb-test 34 "c" "\&a\[0\]" } } */ + foo ("v", v, 1); /* { dg-final { gdb-test 35 "v" "1" } } */ + foo ("e", (unsigned long) e, 2); /* { dg-final { gdb-test 36 "e" "\&a\[1\]" } } */ + if (c->v == v) + return c; + foo ("c", (unsigned long) c, 3); /* { dg-final { gdb-test 39 "c" "\&a\[0\]" } } */ + foo ("v", v, 4); /* { dg-final { gdb-test 40 "v" "1" } } */ + foo ("e", (unsigned long) e, 5); /* { dg-final { gdb-test 41 "e" "\&a\[1\]" } } */ + c++; + } +#ifdef __i386__ + asm volatile ("" : : "r" (si), "r" (di), "r" (bx)); +#endif + return 0; +} + +int +main () +{ + asm volatile ("" : : "r" (&a[0]) : "memory"); + if (bar (&a[a[0].v], a[0].v + 1, &a[a[0].v + 1])) + abort (); + return 0; +}