The following fixes part of PR61034 - we are hindered by false clobbering during FRE/PRE on paths we try to look through by means of the alias walker. The following makes us also consider lattice-based disambiguation there and in particular also try harder to disambiguate against builtins.
Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2014-05-07 Richard Biener <rguent...@suse.de> PR tree-optimization/61034 * tree-ssa-alias.c (call_may_clobber_ref_p_1): Export. (maybe_skip_until): Use translate to take into account lattices when trying to do disambiguations. (get_continuation_for_phi_1): Likewise. (get_continuation_for_phi): Adjust for added translate arguments. (walk_non_aliased_vuses): Likewise. * tree-ssa-alias.h (get_continuation_for_phi): Adjust prototype. (walk_non_aliased_vuses): Likewise. (call_may_clobber_ref_p_1): Declare. * tree-ssa-sccvn.c (vn_reference_lookup_3): Also disambiguate against calls. Stop early if we are only supposed to disambiguate. * tree-ssa-pre.c (translate_vuse_through_block): Adjust. * g++.dg/tree-ssa/pr61034.C: New testcase. Index: gcc/tree-ssa-alias.c =================================================================== *** gcc/tree-ssa-alias.c.orig 2014-05-07 13:53:47.015599960 +0200 --- gcc/tree-ssa-alias.c 2014-05-07 14:07:09.087544738 +0200 *************** ref_maybe_used_by_stmt_p (gimple stmt, t *** 1835,1841 **** /* If the call in statement CALL may clobber the memory reference REF return true, otherwise return false. */ ! static bool call_may_clobber_ref_p_1 (gimple call, ao_ref *ref) { tree base; --- 1835,1841 ---- /* If the call in statement CALL may clobber the memory reference REF return true, otherwise return false. */ ! bool call_may_clobber_ref_p_1 (gimple call, ao_ref *ref) { tree base; *************** stmt_kills_ref_p (gimple stmt, tree ref) *** 2318,2324 **** static bool maybe_skip_until (gimple phi, tree target, ao_ref *ref, tree vuse, unsigned int *cnt, bitmap *visited, ! bool abort_on_visited) { basic_block bb = gimple_bb (phi); --- 2318,2326 ---- static bool maybe_skip_until (gimple phi, tree target, ao_ref *ref, tree vuse, unsigned int *cnt, bitmap *visited, ! bool abort_on_visited, ! void *(*translate)(ao_ref *, tree, void *, bool), ! void *data) { basic_block bb = gimple_bb (phi); *************** maybe_skip_until (gimple phi, tree targe *** 2338,2344 **** if (bitmap_bit_p (*visited, SSA_NAME_VERSION (PHI_RESULT (def_stmt)))) return !abort_on_visited; vuse = get_continuation_for_phi (def_stmt, ref, cnt, ! visited, abort_on_visited); if (!vuse) return false; continue; --- 2340,2347 ---- if (bitmap_bit_p (*visited, SSA_NAME_VERSION (PHI_RESULT (def_stmt)))) return !abort_on_visited; vuse = get_continuation_for_phi (def_stmt, ref, cnt, ! visited, abort_on_visited, ! translate, data); if (!vuse) return false; continue; *************** maybe_skip_until (gimple phi, tree targe *** 2350,2356 **** /* A clobbering statement or the end of the IL ends it failing. */ ++*cnt; if (stmt_may_clobber_ref_p_1 (def_stmt, ref)) ! return false; } /* If we reach a new basic-block see if we already skipped it in a previous walk that ended successfully. */ --- 2353,2365 ---- /* A clobbering statement or the end of the IL ends it failing. */ ++*cnt; if (stmt_may_clobber_ref_p_1 (def_stmt, ref)) ! { ! if (translate ! && (*translate) (ref, vuse, data, true) == NULL) ! ; ! else ! return false; ! } } /* If we reach a new basic-block see if we already skipped it in a previous walk that ended successfully. */ *************** maybe_skip_until (gimple phi, tree targe *** 2372,2378 **** static tree get_continuation_for_phi_1 (gimple phi, tree arg0, tree arg1, ao_ref *ref, unsigned int *cnt, ! bitmap *visited, bool abort_on_visited) { gimple def0 = SSA_NAME_DEF_STMT (arg0); gimple def1 = SSA_NAME_DEF_STMT (arg1); --- 2381,2389 ---- static tree get_continuation_for_phi_1 (gimple phi, tree arg0, tree arg1, ao_ref *ref, unsigned int *cnt, ! bitmap *visited, bool abort_on_visited, ! void *(*translate)(ao_ref *, tree, void *, bool), ! void *data) { gimple def0 = SSA_NAME_DEF_STMT (arg0); gimple def1 = SSA_NAME_DEF_STMT (arg1); *************** get_continuation_for_phi_1 (gimple phi, *** 2386,2392 **** gimple_bb (def1), gimple_bb (def0)))) { if (maybe_skip_until (phi, arg0, ref, arg1, cnt, ! visited, abort_on_visited)) return arg0; } else if (gimple_nop_p (def1) --- 2397,2403 ---- gimple_bb (def1), gimple_bb (def0)))) { if (maybe_skip_until (phi, arg0, ref, arg1, cnt, ! visited, abort_on_visited, translate, data)) return arg0; } else if (gimple_nop_p (def1) *************** get_continuation_for_phi_1 (gimple phi, *** 2394,2400 **** gimple_bb (def0), gimple_bb (def1))) { if (maybe_skip_until (phi, arg1, ref, arg0, cnt, ! visited, abort_on_visited)) return arg1; } /* Special case of a diamond: --- 2405,2411 ---- gimple_bb (def0), gimple_bb (def1))) { if (maybe_skip_until (phi, arg1, ref, arg0, cnt, ! visited, abort_on_visited, translate, data)) return arg1; } /* Special case of a diamond: *************** get_continuation_for_phi_1 (gimple phi, *** 2414,2421 **** && common_vuse == gimple_vuse (def1)) { *cnt += 2; ! if (!stmt_may_clobber_ref_p_1 (def0, ref) ! && !stmt_may_clobber_ref_p_1 (def1, ref)) return common_vuse; } --- 2425,2436 ---- && common_vuse == gimple_vuse (def1)) { *cnt += 2; ! if ((!stmt_may_clobber_ref_p_1 (def0, ref) ! || (translate ! && (*translate) (ref, arg0, data, true) == NULL)) ! && (!stmt_may_clobber_ref_p_1 (def1, ref) ! || (translate ! && (*translate) (ref, arg1, data, true) == NULL))) return common_vuse; } *************** get_continuation_for_phi_1 (gimple phi, *** 2432,2438 **** tree get_continuation_for_phi (gimple phi, ao_ref *ref, unsigned int *cnt, bitmap *visited, ! bool abort_on_visited) { unsigned nargs = gimple_phi_num_args (phi); --- 2447,2455 ---- tree get_continuation_for_phi (gimple phi, ao_ref *ref, unsigned int *cnt, bitmap *visited, ! bool abort_on_visited, ! void *(*translate)(ao_ref *, tree, void *, bool), ! void *data) { unsigned nargs = gimple_phi_num_args (phi); *************** get_continuation_for_phi (gimple phi, ao *** 2470,2476 **** { arg1 = PHI_ARG_DEF (phi, i); arg0 = get_continuation_for_phi_1 (phi, arg0, arg1, ref, ! cnt, visited, abort_on_visited); if (!arg0) return NULL_TREE; } --- 2487,2494 ---- { arg1 = PHI_ARG_DEF (phi, i); arg0 = get_continuation_for_phi_1 (phi, arg0, arg1, ref, ! cnt, visited, abort_on_visited, ! translate, data); if (!arg0) return NULL_TREE; } *************** get_continuation_for_phi (gimple phi, ao *** 2502,2508 **** void * walk_non_aliased_vuses (ao_ref *ref, tree vuse, void *(*walker)(ao_ref *, tree, unsigned int, void *), ! void *(*translate)(ao_ref *, tree, void *), void *data) { bitmap visited = NULL; void *res; --- 2520,2527 ---- void * walk_non_aliased_vuses (ao_ref *ref, tree vuse, void *(*walker)(ao_ref *, tree, unsigned int, void *), ! void *(*translate)(ao_ref *, tree, void *, bool), ! void *data) { bitmap visited = NULL; void *res; *************** walk_non_aliased_vuses (ao_ref *ref, tre *** 2532,2538 **** break; else if (gimple_code (def_stmt) == GIMPLE_PHI) vuse = get_continuation_for_phi (def_stmt, ref, &cnt, ! &visited, translated); else { cnt++; --- 2551,2557 ---- break; else if (gimple_code (def_stmt) == GIMPLE_PHI) vuse = get_continuation_for_phi (def_stmt, ref, &cnt, ! &visited, translated, translate, data); else { cnt++; *************** walk_non_aliased_vuses (ao_ref *ref, tre *** 2540,2546 **** { if (!translate) break; ! res = (*translate) (ref, vuse, data); /* Failed lookup and translation. */ if (res == (void *)-1) { --- 2559,2565 ---- { if (!translate) break; ! res = (*translate) (ref, vuse, data, false); /* Failed lookup and translation. */ if (res == (void *)-1) { Index: gcc/tree-ssa-alias.h =================================================================== *** gcc/tree-ssa-alias.h.orig 2014-05-07 13:53:47.015599960 +0200 --- gcc/tree-ssa-alias.h 2014-05-07 14:07:09.088544738 +0200 *************** extern bool stmt_may_clobber_global_p (g *** 110,122 **** extern bool stmt_may_clobber_ref_p (gimple, tree); extern bool stmt_may_clobber_ref_p_1 (gimple, ao_ref *); extern bool call_may_clobber_ref_p (gimple, tree); extern bool stmt_kills_ref_p (gimple, tree); extern tree get_continuation_for_phi (gimple, ao_ref *, ! unsigned int *, bitmap *, bool); extern void *walk_non_aliased_vuses (ao_ref *, tree, void *(*)(ao_ref *, tree, unsigned int, void *), ! void *(*)(ao_ref *, tree, void *), void *); extern unsigned int walk_aliased_vdefs (ao_ref *, tree, bool (*)(ao_ref *, tree, void *), void *, bitmap *); --- 110,126 ---- extern bool stmt_may_clobber_ref_p (gimple, tree); extern bool stmt_may_clobber_ref_p_1 (gimple, ao_ref *); extern bool call_may_clobber_ref_p (gimple, tree); + extern bool call_may_clobber_ref_p_1 (gimple, ao_ref *); extern bool stmt_kills_ref_p (gimple, tree); extern tree get_continuation_for_phi (gimple, ao_ref *, ! unsigned int *, bitmap *, bool, ! void *(*)(ao_ref *, tree, void *, bool), ! void *); extern void *walk_non_aliased_vuses (ao_ref *, tree, void *(*)(ao_ref *, tree, unsigned int, void *), ! void *(*)(ao_ref *, tree, void *, bool), ! void *); extern unsigned int walk_aliased_vdefs (ao_ref *, tree, bool (*)(ao_ref *, tree, void *), void *, bitmap *); Index: gcc/tree-ssa-sccvn.c =================================================================== *** gcc/tree-ssa-sccvn.c.orig 2014-05-07 13:53:47.015599960 +0200 --- gcc/tree-ssa-sccvn.c 2014-05-07 14:07:27.320543483 +0200 *************** vn_reference_lookup_or_insert_for_pieces *** 1542,1548 **** of VUSE. */ static void * ! vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_) { vn_reference_t vr = (vn_reference_t)vr_; gimple def_stmt = SSA_NAME_DEF_STMT (vuse); --- 1542,1549 ---- of VUSE. */ static void * ! vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_, ! bool disambiguate_only) { vn_reference_t vr = (vn_reference_t)vr_; gimple def_stmt = SSA_NAME_DEF_STMT (vuse); *************** vn_reference_lookup_3 (ao_ref *ref, tree *** 1580,1585 **** --- 1581,1619 ---- lhs_ref_ok = true; } } + else if (gimple_call_builtin_p (def_stmt, BUILT_IN_NORMAL) + && gimple_call_num_args (def_stmt) <= 4) + { + /* For builtin calls valueize its arguments and call the + alias oracle again. Valueization may improve points-to + info of pointers and constify size and position arguments. + Originally this was motivated by PR61034 which has + conditional calls to free falsely clobbering ref because + of imprecise points-to info of the argument. */ + tree oldargs[4]; + bool valueized_anything; + for (unsigned i = 0; i < gimple_call_num_args (def_stmt); ++i) + { + oldargs[i] = gimple_call_arg (def_stmt, i); + if (TREE_CODE (oldargs[i]) == SSA_NAME + && VN_INFO (oldargs[i])->valnum != oldargs[i]) + { + gimple_call_set_arg (def_stmt, i, VN_INFO (oldargs[i])->valnum); + valueized_anything = true; + } + } + if (valueized_anything) + { + bool res = call_may_clobber_ref_p_1 (def_stmt, ref); + for (unsigned i = 0; i < gimple_call_num_args (def_stmt); ++i) + gimple_call_set_arg (def_stmt, i, oldargs[i]); + if (!res) + return NULL; + } + } + + if (disambiguate_only) + return (void *)-1; base = ao_ref_base (ref); offset = ref->offset; Index: gcc/tree-ssa-pre.c =================================================================== *** gcc/tree-ssa-pre.c.orig 2014-05-07 13:53:47.015599960 +0200 --- gcc/tree-ssa-pre.c 2014-05-07 14:07:09.091544738 +0200 *************** translate_vuse_through_block (vec<vn_ref *** 1308,1314 **** unsigned int cnt; /* Try to find a vuse that dominates this phi node by skipping non-clobbering statements. */ ! vuse = get_continuation_for_phi (phi, &ref, &cnt, &visited, false); if (visited) BITMAP_FREE (visited); } --- 1308,1315 ---- unsigned int cnt; /* Try to find a vuse that dominates this phi node by skipping non-clobbering statements. */ ! vuse = get_continuation_for_phi (phi, &ref, &cnt, &visited, false, ! NULL, NULL); if (visited) BITMAP_FREE (visited); } Index: gcc/testsuite/g++.dg/tree-ssa/pr61034.C =================================================================== *** /dev/null 1970-01-01 00:00:00.000000000 +0000 --- gcc/testsuite/g++.dg/tree-ssa/pr61034.C 2014-05-07 14:07:09.091544738 +0200 *************** *** 0 **** --- 1,45 ---- + // { dg-do compile } + // { dg-options "-O3 -fdump-tree-fre2" } + + #define assume(x) if(!(x))__builtin_unreachable() + + inline void* operator new(__SIZE_TYPE__ n){ return __builtin_malloc(n); } + inline void operator delete(void *p) { __builtin_free(p); } + struct O { + double num; + int count; + }; + struct I { + O *o; + I(double d = 0) : o (new O) { o->num = d; o->count = 1; } + I(I const&i) { assume(i.o->count >= 1); o = i.o; ++o->count; } + I& operator=(I const&i) { I(i).swap(*this); return *this; } + ~I() { if (--o->count == 0) delete o; } + void swap(I& i) { O *tmp = o; o = i.o; i.o = tmp; } + I& operator*= (I const&i) { + if (o->count > 1) *this = I(o->num); + o->num *= i.o->num; + return *this; + } + I& operator-= (I const&i) { + if (o->count > 1) *this = I(o->num); + o->num -= i.o->num; + return *this; + } + }; + inline I operator* (I a, I const&b) { return a *= b; } + inline I operator- (I a, I const&b) { return a -= b; } + inline bool operator< (I const&a, I const&b) { return a.o->num < b.o->num; } + + bool f(I a, I b, I c, I d) { + return (a * d - b * c) * (a * b - c * d) < 42; + } + + // We should be able to CSE most references to count and thus remove + // a bunch of conditional free()s and unreachable()s. + // This works only if everything is inlined into 'f'. + + // { dg-final { scan-tree-dump-times ";; Function" 1 "fre2" } } + // { dg-final { scan-tree-dump-times "free" 19 "fre2" } } + // { dg-final { scan-tree-dump-times "unreachable" 11 "fre2" } } + // { dg-final { cleanup-tree-dump "fre2" } }