summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2014-03-26 02:11:57 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2014-03-26 02:11:57 +0000
commit5a7ad25306b167d5b9a494a776aef7df1ec2412c (patch)
tree58c27722a6391d91e8bbfcb902c1edc28e754d14 /gcc
parentce2d198d93cf01609d4d18ce934efacc0cf21b5b (diff)
downloadgcc-5a7ad25306b167d5b9a494a776aef7df1ec2412c.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@208831 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog20
-rw-r--r--gcc/cgraph.c6
-rw-r--r--gcc/cgraphclones.c8
-rw-r--r--gcc/cif-code.def4
-rw-r--r--gcc/ipa-cp.c4
-rw-r--r--gcc/ipa-inline-analysis.c34
-rw-r--r--gcc/ipa-inline.c2
-rw-r--r--gcc/ipa-inline.h3
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/torture/pr60315.C32
10 files changed, 105 insertions, 13 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index bc74777659b..64ef5c059f8 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,25 @@
2014-03-25 Jan Hubicka <hubicka@ucw.cz>
+ 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 <hubicka@ucw.cz>
+
* ipa-pure-const.c (propagate_pure_const, propagate_nothrow):
Do not modify inline clones.
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 <hubicka@ucw.cz>
+
+ PR ipa/60315
+ * testsuite/g++.dg/torture/pr60315.C: New testcase.
+
2014-03-25 Martin Jambor <mjambor@suse.cz>
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<Derived*>(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<Derived*>(b)->*(&Derived::f))();
+}