From 9de6f6c3eed463e8c41b95a28ad7f2186e379fff Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 26 Mar 2014 03:11:57 +0100 Subject: [PATCH] re PR ipa/60315 (template constructor switch optimization) PR ipa/60315 * cif-code.def (UNREACHABLE) New code. * ipa-inline.c (inline_small_functions): Skip edges to __builtlin_unreachable. (estimate_edge_growth): Allow edges to __builtlin_unreachable. * ipa-inline-analysis.c (edge_set_predicate): Redirect edges with false predicate to __bulitin_unreachable. (set_cond_stmt_execution_predicate): Fix issue when invert_tree_comparison returns ERROR_MARK. * ipa-pure-const.c (propagate_pure_const, propagate_nothrow): Do not propagate to inline clones. * cgraph.c (verify_edge_corresponds_to_fndecl): Allow redirection to unreachable. * ipa-cp.c (create_specialized_node): Be ready for new node to appear. * cgraphclones.c (cgraph_clone_node): If call destination is already ureachable, do not redirect it back. * tree-inline.c (fold_marked_statements): Hanlde calls becoming unreachable. From-SVN: r208831 --- gcc/ChangeLog | 20 +++++++++++++++ gcc/cgraph.c | 6 +++++ gcc/cgraphclones.c | 8 ++++-- gcc/cif-code.def | 4 +++ gcc/ipa-cp.c | 4 +-- gcc/ipa-inline-analysis.c | 34 +++++++++++++++++++++----- gcc/ipa-inline.c | 2 +- gcc/ipa-inline.h | 3 ++- gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/g++.dg/torture/pr60315.C | 32 ++++++++++++++++++++++++ 10 files changed, 105 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/g++.dg/torture/pr60315.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bc74777659b..64ef5c059f8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2014-03-25 Jan Hubicka + + PR ipa/60315 + * cif-code.def (UNREACHABLE) New code. + * ipa-inline.c (inline_small_functions): Skip edges to __builtlin_unreachable. + (estimate_edge_growth): Allow edges to __builtlin_unreachable. + * ipa-inline-analysis.c (edge_set_predicate): Redirect edges with false + predicate to __bulitin_unreachable. + (set_cond_stmt_execution_predicate): Fix issue when invert_tree_comparison + returns ERROR_MARK. + * ipa-pure-const.c (propagate_pure_const, propagate_nothrow): Do not + propagate to inline clones. + * cgraph.c (verify_edge_corresponds_to_fndecl): Allow redirection + to unreachable. + * ipa-cp.c (create_specialized_node): Be ready for new node to appear. + * cgraphclones.c (cgraph_clone_node): If call destination is already + ureachable, do not redirect it back. + * tree-inline.c (fold_marked_statements): Hanlde calls becoming + unreachable. + 2014-03-25 Jan Hubicka * ipa-pure-const.c (propagate_pure_const, propagate_nothrow): diff --git a/gcc/cgraph.c b/gcc/cgraph.c index abfd63c9955..586ef797aba 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -2612,6 +2612,12 @@ verify_edge_corresponds_to_fndecl (struct cgraph_edge *e, tree decl) || node->in_other_partition || e->callee->in_other_partition) return false; + + /* Optimizers can redirect unreachable calls or calls triggering undefined + behaviour to builtin_unreachable. */ + if (DECL_BUILT_IN_CLASS (e->callee->decl) == BUILT_IN_NORMAL + && DECL_FUNCTION_CODE (e->callee->decl) == BUILT_IN_UNREACHABLE) + return false; node = cgraph_function_or_thunk_node (node, NULL); if (e->callee->former_clone_of != node->decl diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c index ca69033ddde..b2eb8ab5ce9 100644 --- a/gcc/cgraphclones.c +++ b/gcc/cgraphclones.c @@ -238,8 +238,12 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq, FOR_EACH_VEC_ELT (redirect_callers, i, e) { /* Redirect calls to the old version node to point to its new - version. */ - cgraph_redirect_edge_callee (e, new_node); + version. The only exception is when the edge was proved to + be unreachable during the clonning procedure. */ + if (!e->callee + || DECL_BUILT_IN_CLASS (e->callee->decl) != BUILT_IN_NORMAL + || DECL_FUNCTION_CODE (e->callee->decl) != BUILT_IN_UNREACHABLE) + cgraph_redirect_edge_callee (e, new_node); } diff --git a/gcc/cif-code.def b/gcc/cif-code.def index 71f3e39a6da..ce64d96b690 100644 --- a/gcc/cif-code.def +++ b/gcc/cif-code.def @@ -127,3 +127,7 @@ DEFCIFCODE(USES_COMDAT_LOCAL, CIF_FINAL_NORMAL, /* We can't inline because of mismatched caller/callee attributes. */ DEFCIFCODE(ATTRIBUTE_MISMATCH, CIF_FINAL_NORMAL, N_("function attribute mismatch")) + +/* We proved that the call is unreachable. */ +DEFCIFCODE(UNREACHABLE, CIF_FINAL_NORMAL, + N_("unreachable")) diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index 74042adb5a1..05de8572492 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -2811,9 +2811,7 @@ create_specialized_node (struct cgraph_node *node, if (aggvals) ipa_dump_agg_replacement_values (dump_file, aggvals); } - gcc_checking_assert (ipa_node_params_vector.exists () - && (ipa_node_params_vector.length () - > (unsigned) cgraph_max_uid)); + ipa_check_create_node_params (); update_profiling_info (node, new_node); new_info = IPA_NODE_REF (new_node); new_info->ipcp_orig_node = node; diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c index 98f42ef1e55..ebc46a90cbf 100644 --- a/gcc/ipa-inline-analysis.c +++ b/gcc/ipa-inline-analysis.c @@ -746,6 +746,20 @@ static void edge_set_predicate (struct cgraph_edge *e, struct predicate *predicate) { struct inline_edge_summary *es = inline_edge_summary (e); + + /* If the edge is determined to be never executed, redirect it + to BUILTIN_UNREACHABLE to save inliner from inlining into it. */ + if (predicate && false_predicate_p (predicate) && e->callee) + { + struct cgraph_node *callee = !e->inline_failed ? e->callee : NULL; + + cgraph_redirect_edge_callee (e, + cgraph_get_create_node + (builtin_decl_implicit (BUILT_IN_UNREACHABLE))); + e->inline_failed = CIF_UNREACHABLE; + if (callee) + cgraph_remove_node_and_inline_clones (callee, NULL); + } if (predicate && !true_predicate_p (predicate)) { if (!es->predicate) @@ -1724,12 +1738,20 @@ set_cond_stmt_execution_predicate (struct ipa_node_params *info, FOR_EACH_EDGE (e, ei, bb->succs) { - struct predicate p = add_condition (summary, index, &aggpos, - e->flags & EDGE_TRUE_VALUE - ? code : inverted_code, - gimple_cond_rhs (last)); - e->aux = pool_alloc (edge_predicate_pool); - *(struct predicate *) e->aux = p; + enum tree_code this_code = (e->flags & EDGE_TRUE_VALUE + ? code : inverted_code); + /* invert_tree_comparison will return ERROR_MARK on FP + comparsions that are not EQ/NE instead of returning proper + unordered one. Be sure it is not confused with NON_CONSTANT. */ + if (this_code != ERROR_MARK) + { + struct predicate p = add_condition (summary, index, &aggpos, + e->flags & EDGE_TRUE_VALUE + ? code : inverted_code, + gimple_cond_rhs (last)); + e->aux = pool_alloc (edge_predicate_pool); + *(struct predicate *) e->aux = p; + } } } diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index f6f97f87ebe..da83c4014e4 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -1685,7 +1685,7 @@ inline_small_functions (void) edge = (struct cgraph_edge *) fibheap_extract_min (edge_heap); gcc_assert (edge->aux); edge->aux = NULL; - if (!edge->inline_failed) + if (!edge->inline_failed || !edge->callee->analyzed) continue; /* Be sure that caches are maintained consistent. diff --git a/gcc/ipa-inline.h b/gcc/ipa-inline.h index 0a5960899a3..48136d22b52 100644 --- a/gcc/ipa-inline.h +++ b/gcc/ipa-inline.h @@ -285,7 +285,8 @@ static inline int estimate_edge_growth (struct cgraph_edge *edge) { #ifdef ENABLE_CHECKING - gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size); + gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size + || !edge->callee->analyzed); #endif return (estimate_edge_size (edge) - inline_edge_summary (edge)->call_stmt_size); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index da8d6437047..9c745e10834 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2014-03-25 Jan Hubicka + + PR ipa/60315 + * testsuite/g++.dg/torture/pr60315.C: New testcase. + 2014-03-25 Martin Jambor PR ipa/60600 diff --git a/gcc/testsuite/g++.dg/torture/pr60315.C b/gcc/testsuite/g++.dg/torture/pr60315.C new file mode 100644 index 00000000000..7f122608504 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr60315.C @@ -0,0 +1,32 @@ +// { dg-do compile } +struct Base { + virtual int f() = 0; +}; + +struct Derived : public Base { + virtual int f() final override { + return 42; + } +}; + +extern Base* b; + +int main() { + return (static_cast(b)->*(&Derived::f))(); +} +// { dg-do compile } +struct Base { + virtual int f() = 0; +}; + +struct Derived : public Base { + virtual int f() final override { + return 42; + } +}; + +extern Base* b; + +int main() { + return (static_cast(b)->*(&Derived::f))(); +}