]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR ipa/60315 (template constructor switch optimization)
authorJan Hubicka <hubicka@ucw.cz>
Wed, 26 Mar 2014 02:11:57 +0000 (03:11 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Wed, 26 Mar 2014 02:11:57 +0000 (02:11 +0000)
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
gcc/cgraph.c
gcc/cgraphclones.c
gcc/cif-code.def
gcc/ipa-cp.c
gcc/ipa-inline-analysis.c
gcc/ipa-inline.c
gcc/ipa-inline.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/torture/pr60315.C [new file with mode: 0644]

index bc74777659b538310f177e963850423e2d44133f..64ef5c059f85d4242c57bda26f5982ae71d97e53 100644 (file)
@@ -1,3 +1,23 @@
+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):
index abfd63c9955c2cf064caacad47f75eea4b17a573..586ef797abae40069827e7d9f2f0afb3a9986a21 100644 (file)
@@ -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
index ca69033ddde402c3aa5bcc6911802b6d69d31ed6..b2eb8ab5ce9aff3ec004839eb09de716292b9a19 100644 (file)
@@ -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);
     }
 
 
index 71f3e39a6da6fba00c89d1b0680eeddc79970a59..ce64d96b6900fee023c4c6f5562d681dde08a6c5 100644 (file)
@@ -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"))
index 74042adb5a1deab24341a9b29593897f4a4ac689..05de8572492c066dd8b708f5b72b3c04525c4784 100644 (file)
@@ -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;
index 98f42ef1e55e7ea94c817491d9bdaed55fac75ce..ebc46a90cbf5f67f392f228fae1ed7e0d54637e5 100644 (file)
@@ -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;
+           }
        }
     }
 
index f6f97f87ebe417af459a45778bc65688926280d5..da83c4014e42721a0c4c770641a46df3e09be435 100644 (file)
@@ -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.  
index 0a5960899a3fb5a147dae8702dfddb9854ef305f..48136d22b52cabb5489b8a7bdf8f099a10dd78fe 100644 (file)
@@ -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);
index da8d6437047238271a1474596dbfab32304f286d..9c745e10834c52115437acdc994e0f2ad340018a 100644 (file)
@@ -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 (file)
index 0000000..7f12260
--- /dev/null
@@ -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))();
+}