diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc index 389faec260c..5ae374df3a2 100644 --- a/gcc/gimple-range-path.cc +++ b/gcc/gimple-range-path.cc @@ -276,8 +276,6 @@ void path_range_query::ssa_range_in_phi (vrange &r, gphi *phi) { tree name = gimple_phi_result (phi); - basic_block bb = gimple_bb (phi); - unsigned nargs = gimple_phi_num_args (phi); if (at_entry ()) { @@ -287,6 +285,7 @@ path_range_query::ssa_range_in_phi (vrange &r, gphi *phi) // Try to fold the phi exclusively with global or cached values. // This will get things like PHI <5(99), 6(88)>. We do this by // calling range_of_expr with no context. + unsigned nargs = gimple_phi_num_args (phi); Value_Range arg_range (TREE_TYPE (name)); r.set_undefined (); for (size_t i = 0; i < nargs; ++i) @@ -303,36 +302,31 @@ path_range_query::ssa_range_in_phi (vrange &r, gphi *phi) return; } + basic_block bb = gimple_bb (phi); basic_block prev = prev_bb (); edge e_in = find_edge (prev, bb); - - for (size_t i = 0; i < nargs; ++i) - if (e_in == gimple_phi_arg_edge (phi, i)) - { - tree arg = gimple_phi_arg_def (phi, i); - // Avoid using the cache for ARGs defined in this block, as - // that could create an ordering problem. - if (ssa_defined_in_bb (arg, bb) || !get_cache (r, arg)) - { - if (m_resolve) - { - Value_Range tmp (TREE_TYPE (name)); - // Using both the range on entry to the path, and the - // range on this edge yields significantly better - // results. - if (defined_outside_path (arg)) - range_on_path_entry (r, arg); - else - r.set_varying (TREE_TYPE (name)); - m_ranger->range_on_edge (tmp, e_in, arg); - r.intersect (tmp); - return; - } + tree arg = PHI_ARG_DEF_FROM_EDGE (phi, e_in); + // Avoid using the cache for ARGs defined in this block, as + // that could create an ordering problem. + if (ssa_defined_in_bb (arg, bb) || !get_cache (r, arg)) + { + if (m_resolve) + { + Value_Range tmp (TREE_TYPE (name)); + // Using both the range on entry to the path, and the + // range on this edge yields significantly better + // results. + if (TREE_CODE (arg) == SSA_NAME + && defined_outside_path (arg)) + range_on_path_entry (r, arg); + else r.set_varying (TREE_TYPE (name)); - } - return; - } - gcc_unreachable (); + m_ranger->range_on_edge (tmp, e_in, arg); + r.intersect (tmp); + return; + } + r.set_varying (TREE_TYPE (name)); + } } // If NAME is defined in BB, set R to the range of NAME, and return diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-19.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-19.c index 58a872b8d25..62912f372de 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-19.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-19.c @@ -30,4 +30,4 @@ int foo (struct S *chain, _Bool is_ctor, _Bool is_dtor) /* We want to thread both paths from A with NULL chain to C, the one through B and one around it. ??? Ideally we'd thread one "path" containing the half-diamond with B. */ -/* { dg-final { scan-tree-dump "Jumps threaded: 2" "threadfull1" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump "Jumps threaded: 2" "threadfull1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-20.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-20.c new file mode 100644 index 00000000000..c6529659021 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-thread-20.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-ethread-stats" } */ + +struct S { int base; }; +void foo (struct S *p) +{ + if (p) + { + int *q = &p->base; + if (q) + __builtin_puts ("x"); + } +} + +/* { dg-final { scan-tree-dump "Jumps threaded: 1" "ethread" } } */ diff --git a/gcc/tree-ssa-threadbackward.cc b/gcc/tree-ssa-threadbackward.cc index 6585a30551d..546a776bd91 100644 --- a/gcc/tree-ssa-threadbackward.cc +++ b/gcc/tree-ssa-threadbackward.cc @@ -362,32 +362,85 @@ back_threader::find_paths_to_names (basic_block bb, bitmap interesting, { // For further greedy searching we want to remove interesting // names defined in BB but add ones on the PHI edges for the - // respective edges. We do this by starting with all names + // respective edges and adding imports from those stmts. + // We do this by starting with all names // not defined in BB as interesting, collecting a list of // interesting PHIs in BB on the fly. Then we iterate over // predecessor edges, adding interesting PHI edge defs to // the set of interesting names to consider when processing it. auto_bitmap new_interesting; + auto_vec new_imports; auto_vec interesting_phis; bitmap_iterator bi; unsigned i; + auto_vec worklist; EXECUTE_IF_SET_IN_BITMAP (interesting, 0, i, bi) { tree name = ssa_name (i); gimple *def_stmt = SSA_NAME_DEF_STMT (name); + /* Imports remain interesting. */ if (gimple_bb (def_stmt) != bb) - bitmap_set_bit (new_interesting, i); - else if (gphi *phi = dyn_cast (def_stmt)) { - tree res = gimple_phi_result (phi); - if (!SSA_NAME_OCCURS_IN_ABNORMAL_PHI (res)) - interesting_phis.safe_push (phi); + bitmap_set_bit (new_interesting, i); + continue; + } + worklist.quick_push (name); + while (!worklist.is_empty ()) + { + tree name = worklist.pop (); + gimple *def_stmt = SSA_NAME_DEF_STMT (name); + /* Newly discovered imports are interesting. */ + if (gimple_bb (def_stmt) != bb) + { + bitmap_set_bit (new_interesting, SSA_NAME_VERSION (name)); + continue; + } + /* Local PHIs participate in renaming below. */ + if (gphi *phi = dyn_cast (def_stmt)) + { + tree res = gimple_phi_result (phi); + if (!SSA_NAME_OCCURS_IN_ABNORMAL_PHI (res)) + interesting_phis.safe_push (phi); + } + /* For other local defs process their uses, amending + imports on the way. */ + else if (gassign *ass = dyn_cast (def_stmt)) + { + tree ssa[3]; + if (range_op_handler (ass)) + { + ssa[0] = gimple_range_ssa_p (gimple_range_operand1 (ass)); + ssa[1] = gimple_range_ssa_p (gimple_range_operand2 (ass)); + ssa[2] = NULL_TREE; + } + else if (gimple_assign_rhs_code (ass) == COND_EXPR) + { + ssa[0] = gimple_range_ssa_p (gimple_assign_rhs1 (ass)); + ssa[1] = gimple_range_ssa_p (gimple_assign_rhs2 (ass)); + ssa[2] = gimple_range_ssa_p (gimple_assign_rhs3 (ass)); + } + else + continue; + for (unsigned j = 0; j < 3; ++j) + { + tree rhs = ssa[j]; + if (rhs + && TREE_CODE (rhs) == SSA_NAME + && bitmap_set_bit (m_imports, + SSA_NAME_VERSION (rhs))) + { + new_imports.safe_push (SSA_NAME_VERSION (rhs)); + worklist.safe_push (rhs); + } + } + } } } if (!bitmap_empty_p (new_interesting) || !interesting_phis.is_empty ()) { - auto_vec unwind (interesting_phis.length ()); + auto_vec unwind (interesting_phis.length ()); + auto_vec imports_unwind (interesting_phis.length ()); edge_iterator iter; edge e; FOR_EACH_EDGE (e, iter, bb->preds) @@ -405,22 +458,31 @@ back_threader::find_paths_to_names (basic_block bb, bitmap interesting, { tree def = PHI_ARG_DEF_FROM_EDGE (phi, e); if (TREE_CODE (def) == SSA_NAME) - if (bitmap_set_bit (new_interesting, - SSA_NAME_VERSION (def))) - { - bitmap_set_bit (m_imports, SSA_NAME_VERSION (def)); - unwind.quick_push (def); - } + { + int ver = SSA_NAME_VERSION (def); + if (bitmap_set_bit (new_interesting, ver)) + { + if (bitmap_set_bit (m_imports, ver)) + imports_unwind.quick_push (ver); + unwind.quick_push (ver); + } + } } find_paths_to_names (e->src, new_interesting, overall_paths); - // Restore new_interesting. We leave m_imports alone since - // we do not prune defs in BB from it and separately keeping - // track of which bits to unwind isn't worth the trouble. - for (tree def : unwind) - bitmap_clear_bit (new_interesting, SSA_NAME_VERSION (def)); + // Restore new_interesting. + for (int def : unwind) + bitmap_clear_bit (new_interesting, def); unwind.truncate (0); + // Restore and m_imports. + for (int def : imports_unwind) + bitmap_clear_bit (m_imports, def); + imports_unwind.truncate (0); } } + /* m_imports tracks all interesting names on the path, so when + backtracking we have to restore it. */ + for (int j : new_imports) + bitmap_clear_bit (m_imports, j); } else if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " FAIL: Search space limit %d reached.\n", @@ -444,17 +506,24 @@ back_threader::find_paths (basic_block bb, tree name) && gimple_code (stmt) != GIMPLE_SWITCH)) return; - if (EDGE_COUNT (bb->succs) > 1 - || single_succ_to_potentially_threadable_block (bb)) + if (EDGE_COUNT (bb->succs) > 1) { m_last_stmt = stmt; m_visited_bbs.empty (); m_path.truncate (0); m_name = name; - m_path.safe_push (bb); - m_solver->compute_imports (m_imports, m_path); - m_path.pop (); + // We compute imports of the path during discovery starting + // just with names used in the conditional. + bitmap_clear (m_imports); + ssa_op_iter iter; + FOR_EACH_SSA_TREE_OPERAND (name, stmt, iter, SSA_OP_USE) + bitmap_set_bit (m_imports, SSA_NAME_VERSION (name)); + + // Interesting is the set of imports we still not have see + // the definition of. So while imports only grow, the + // set of interesting defs dwindles and once empty we can + // stop searching. auto_bitmap interesting; bitmap_copy (interesting, m_imports); find_paths_to_names (bb, interesting, 1);