re PR middle-end/42450 (another GCC 4.5 ICE on C++ templated code)
authorMartin Jambor <mjambor@suse.cz>
Thu, 18 Mar 2010 20:07:13 +0000 (21:07 +0100)
committerMartin Jambor <jamborm@gcc.gnu.org>
Thu, 18 Mar 2010 20:07:13 +0000 (21:07 +0100)
2010-03-18  Martin Jambor  <mjambor@suse.cz>

PR middle-end/42450
* cgraph.h (cgraph_redirect_edge_call_stmt_to_callee): Declare.
* cgraphunit.c (cgraph_materialize_all_clones): Update calls in
all non-clones.  Moved call redirection...
(cgraph_redirect_edge_call_stmt_to_callee): ...to this new
function.
(cgraph_materialize_all_clones): Dispose of all
combined_args_to_skip bitmaps.
(verify_cgraph_node): Do not check for edges pointing to wrong
nodes in inline clones.
* tree-inline.c (copy_bb): Call
cgraph_redirect_edge_call_stmt_to_callee.
* ipa.c (cgraph_remove_unreachable_nodes): Call
cgraph_node_remove_callees even when there are used clones.

* testsuite/g++.dg/torture/pr42450.C: New test.

From-SVN: r157546

gcc/ChangeLog
gcc/cgraph.h
gcc/cgraphunit.c
gcc/ipa.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/torture/pr42450.C [new file with mode: 0644]
gcc/tree-inline.c

index 04ef3ca..9b5211c 100644 (file)
@@ -1,3 +1,20 @@
+2010-03-18  Martin Jambor  <mjambor@suse.cz>
+
+       PR middle-end/42450
+       * cgraph.h (cgraph_redirect_edge_call_stmt_to_callee): Declare.
+       * cgraphunit.c (cgraph_materialize_all_clones): Update calls in
+       all non-clones.  Moved call redirection...
+       (cgraph_redirect_edge_call_stmt_to_callee): ...to this new
+       function.
+       (cgraph_materialize_all_clones): Dispose of all
+       combined_args_to_skip bitmaps.
+       (verify_cgraph_node): Do not check for edges pointing to wrong
+       nodes in inline clones.
+       * tree-inline.c (copy_bb): Call
+       cgraph_redirect_edge_call_stmt_to_callee.
+       * ipa.c (cgraph_remove_unreachable_nodes): Call
+       cgraph_node_remove_callees even when there are used clones.
+
 2010-03-18  H.J. Lu  <hongjiu.lu@intel.com>
 
        * config/i386/libgcc-glibc.ver: Make GCC_4.5.0 inherit GCC_4.4.0.
index f8d52eb..4f0c333 100644 (file)
@@ -534,7 +534,7 @@ void cgraph_remove_edge_duplication_hook (struct cgraph_2edge_hook_list *);
 struct cgraph_2node_hook_list *cgraph_add_node_duplication_hook (cgraph_2node_hook, void *);
 void cgraph_remove_node_duplication_hook (struct cgraph_2node_hook_list *);
 void cgraph_materialize_all_clones (void);
-
+gimple cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *);
 /* In cgraphbuild.c  */
 unsigned int rebuild_cgraph_edges (void);
 void reset_inline_failed (struct cgraph_node *);
index f4580ad..c41477b 100644 (file)
@@ -751,8 +751,9 @@ verify_cgraph_node (struct cgraph_node *node)
                            debug_tree (e->callee->decl);
                            error_found = true;
                          }
-                       else if (!clone_of_p (cgraph_node (decl), e->callee)
-                                && !e->callee->global.inlined_to)
+                       else if (!node->global.inlined_to
+                                && !e->callee->global.inlined_to
+                                && !clone_of_p (cgraph_node (decl), e->callee))
                          {
                            error ("edge points to wrong declaration:");
                            debug_tree (e->callee->decl);
@@ -2222,11 +2223,60 @@ cgraph_materialize_clone (struct cgraph_node *node)
   bitmap_obstack_release (NULL);
 }
 
+/* If necessary, change the function declaration in the call statement
+   associated with E so that it corresponds to the edge callee.  */
+
+gimple
+cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e)
+{
+  tree decl = gimple_call_fndecl (e->call_stmt);
+  gimple new_stmt;
+  gimple_stmt_iterator gsi;
+
+  if (!decl || decl == e->callee->decl
+      /* Don't update call from same body alias to the real function.  */
+      || cgraph_get_node (decl) == cgraph_get_node (e->callee->decl))
+    return e->call_stmt;
+
+  if (cgraph_dump_file)
+    {
+      fprintf (cgraph_dump_file, "updating call of %s/%i -> %s/%i: ",
+              cgraph_node_name (e->caller), e->caller->uid,
+              cgraph_node_name (e->callee), e->callee->uid);
+      print_gimple_stmt (cgraph_dump_file, e->call_stmt, 0, dump_flags);
+    }
+
+  if (e->callee->clone.combined_args_to_skip)
+    new_stmt = gimple_call_copy_skip_args (e->call_stmt,
+                                      e->callee->clone.combined_args_to_skip);
+  else
+    new_stmt = e->call_stmt;
+  if (gimple_vdef (new_stmt)
+      && TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME)
+    SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
+  gimple_call_set_fndecl (new_stmt, e->callee->decl);
+
+  gsi = gsi_for_stmt (e->call_stmt);
+  gsi_replace (&gsi, new_stmt, true);
+
+  /* Update EH information too, just in case.  */
+  maybe_clean_or_replace_eh_stmt (e->call_stmt, new_stmt);
+
+  cgraph_set_call_stmt_including_clones (e->caller, e->call_stmt, new_stmt);
+
+  if (cgraph_dump_file)
+    {
+      fprintf (cgraph_dump_file, "  updated to:");
+      print_gimple_stmt (cgraph_dump_file, e->call_stmt, 0, dump_flags);
+    }
+  return new_stmt;
+}
+
 /* Once all functions from compilation unit are in memory, produce all clones
-   and update all calls.
-   We might also do this on demand if we don't want to bring all functions to
-   memory prior compilation, but current WHOPR implementation does that and it is
-   is bit easier to keep everything right in this order.  */
+   and update all calls.  We might also do this on demand if we don't want to
+   bring all functions to memory prior compilation, but current WHOPR
+   implementation does that and it is is bit easier to keep everything right in
+   this order.  */
 void
 cgraph_materialize_all_clones (void)
 {
@@ -2302,69 +2352,28 @@ cgraph_materialize_all_clones (void)
   if (cgraph_dump_file)
     fprintf (cgraph_dump_file, "Updating call sites\n");
   for (node = cgraph_nodes; node; node = node->next)
-    if (node->analyzed && gimple_has_body_p (node->decl)
-        && (!node->clone_of || node->clone_of->decl != node->decl))
+    if (node->analyzed && !node->clone_of
+       && gimple_has_body_p (node->decl))
       {
         struct cgraph_edge *e;
 
        current_function_decl = node->decl;
         push_cfun (DECL_STRUCT_FUNCTION (node->decl));
        for (e = node->callees; e; e = e->next_callee)
-         {
-           tree decl = gimple_call_fndecl (e->call_stmt);
-           /* When function gets inlined, indirect inlining might've invented
-              new edge for orginally indirect stmt.  Since we are not
-              preserving clones in the original form, we must not update here
-              since other inline clones don't need to contain call to the same
-              call.  Inliner will do the substitution for us later.  */
-           if (decl && decl != e->callee->decl)
-             {
-               gimple new_stmt;
-               gimple_stmt_iterator gsi;
-
-               if (cgraph_get_node (decl) == cgraph_get_node (e->callee->decl))
-                 /* Don't update call from same body alias to the real function.  */
-                 continue;
-
-               if (cgraph_dump_file)
-                 {
-                   fprintf (cgraph_dump_file, "updating call of %s in %s:",
-                            cgraph_node_name (node),
-                            cgraph_node_name (e->callee));
-                   print_gimple_stmt (cgraph_dump_file, e->call_stmt, 0, dump_flags);
-                 }
-
-               if (e->callee->clone.combined_args_to_skip)
-                 new_stmt = gimple_call_copy_skip_args (e->call_stmt,
-                                                        e->callee->clone.combined_args_to_skip);
-               else
-                 new_stmt = e->call_stmt;
-               if (gimple_vdef (new_stmt)
-                   && TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME)
-                 SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
-                gimple_call_set_fndecl (new_stmt, e->callee->decl);
-
-               gsi = gsi_for_stmt (e->call_stmt);
-               gsi_replace (&gsi, new_stmt, true);
-
-               /* Update EH information too, just in case.  */
-               maybe_clean_or_replace_eh_stmt (e->call_stmt, new_stmt);
-
-               cgraph_set_call_stmt_including_clones (node, e->call_stmt, new_stmt);
-
-               if (cgraph_dump_file)
-                 {
-                   fprintf (cgraph_dump_file, "  updated to:");
-                   print_gimple_stmt (cgraph_dump_file, e->call_stmt, 0, dump_flags);
-                 }
-             }
-         }
+         cgraph_redirect_edge_call_stmt_to_callee (e);
        pop_cfun ();
        current_function_decl = NULL;
 #ifdef ENABLE_CHECKING
         verify_cgraph_node (node);
 #endif
       }
+  if (cgraph_dump_file)
+    fprintf (cgraph_dump_file, "Materialization Call site updates done.\n");
+  /* All changes to parameters have been performed.  In order not to
+     incorrectly repeat them, we simply dispose of the bitmaps that drive the
+     changes. */
+  for (node = cgraph_nodes; node; node = node->next)
+    node->clone.combined_args_to_skip = NULL;
 #ifdef ENABLE_CHECKING
   verify_cgraph ();
 #endif
index f81d41a..c789a29 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -262,10 +262,10 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
                  if (!clone)
                    {
                      cgraph_release_function_body (node);
-                     cgraph_node_remove_callees (node);
                      node->analyzed = false;
                      node->local.inlinable = false;
                    }
+                 cgraph_node_remove_callees (node);
                  if (node->prev_sibling_clone)
                    node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
                  else if (node->clone_of)
index 4a0ef16..8d678f9 100644 (file)
@@ -1,3 +1,8 @@
+2010-03-18  Martin Jambor  <mjambor@suse.cz>
+
+       PR middle-end/42450
+       * g++.dg/torture/pr42450.C: New test.
+
 2010-03-18  Michael Matz  <matz@suse.de>
 
        PR middle-end/43419
diff --git a/gcc/testsuite/g++.dg/torture/pr42450.C b/gcc/testsuite/g++.dg/torture/pr42450.C
new file mode 100644 (file)
index 0000000..f630fa2
--- /dev/null
@@ -0,0 +1,112 @@
+/* { dg-do compile } */
+
+template < typename > class basic_stringstream;
+
+struct basic_string {
+  basic_string();
+};
+
+struct ios_base {
+  virtual ~ios_base();
+};
+
+class ostream:ios_base {};
+class istream:virtual ios_base {};
+
+template < typename > struct basic_iostream:public istream, ostream {
+  ~basic_iostream () {}
+};
+extern template class basic_iostream < char >;
+
+template < typename > struct basic_stringstream:public basic_iostream < char > {
+    basic_string _M_stringbuf;
+    ~basic_stringstream () {}
+};
+extern template class basic_stringstream < char >;
+
+template < typename > struct AnyMatrixBase;
+template < typename, int _Rows, int _Cols, int = _Rows, int = _Cols > class Matrix;
+template < typename > class CwiseNullaryOp;
+
+template < typename Derived > struct MatrixBase:public AnyMatrixBase < Derived > {
+  typedef CwiseNullaryOp < Derived > ConstantReturnType;
+  ConstantReturnType Constant ();
+  template < typename > Derived cast ();
+  static CwiseNullaryOp < Derived > Random (int);
+};
+
+template < typename Derived > struct AnyMatrixBase {
+  Derived derived () {}
+  Derived & derived () const {}
+};
+
+template < typename, int > struct ei_matrix_storage {};
+
+template < typename _Scalar, int, int, int _MaxRows, int _MaxCols > struct Matrix:MatrixBase < Matrix < _Scalar, _MaxRows, _MaxCols > > {
+  typedef MatrixBase < Matrix > Base;
+  ei_matrix_storage < int, _MaxCols > m_storage;
+  Matrix operator= (const Matrix other) {
+    _resize_to_match (other);
+    lazyAssign (other.derived ());
+  }
+  template < typename OtherDerived > Matrix lazyAssign (MatrixBase < OtherDerived > other) {
+    _resize_to_match (other);
+    return Base (other.derived ());
+  }
+  Matrix ();
+  template < typename OtherDerived > Matrix (const MatrixBase < OtherDerived > &other) {
+    *this = other;
+  }
+  template < typename OtherDerived > void _resize_to_match (const MatrixBase < OtherDerived > &) {
+    throw 1;
+  }
+};
+
+template < typename MatrixType > class CwiseNullaryOp:
+public MatrixBase < CwiseNullaryOp < MatrixType > > {};
+
+int f()
+{
+  bool align_cols;
+  if (align_cols) {
+    basic_stringstream<char> sstr;
+    f();
+  }
+}
+
+template < typename > struct AutoDiffScalar;
+template < typename Functor > struct AutoDiffJacobian:Functor {
+  AutoDiffJacobian (Functor);
+  typedef typename Functor::InputType InputType;
+  typedef typename Functor::ValueType ValueType;
+  typedef Matrix < int, Functor::InputsAtCompileTime, 1 > DerivativeType;
+  typedef AutoDiffScalar < DerivativeType > ActiveScalar;
+  typedef Matrix < ActiveScalar, Functor::InputsAtCompileTime, 1 > ActiveInput;
+  void operator () (InputType x, ValueType *) {
+    ActiveInput ax = x.template cast < ActiveScalar > ();
+  }
+};
+
+template < int NX, int NY > struct TestFunc1 {
+  enum  {
+    InputsAtCompileTime = NX
+  };
+  typedef Matrix < float, NX, 1 > InputType;
+  typedef Matrix < float, NY, 1 > ValueType;
+  typedef Matrix < float, NY, NX > JacobianType;
+  int inputs ();
+};
+
+template < typename Func > void forward_jacobian (Func f) {
+  typename Func::InputType x = Func::InputType::Random (f.inputs ());
+  typename Func::ValueType y;
+  typename Func::JacobianType jref = jref.Constant ();
+  AutoDiffJacobian < Func > autoj (f);
+  autoj (x, &y);
+}
+
+void test_autodiff_scalar ()
+{
+  forward_jacobian (TestFunc1 < 2, 2 > ());
+  forward_jacobian (TestFunc1 < 3, 2 > ());
+}
index f3c4204..e0928b9 100644 (file)
@@ -1650,6 +1650,7 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
                                   bb->frequency,
                                   copy_basic_block->frequency);
                        }
+                     stmt = cgraph_redirect_edge_call_stmt_to_callee (edge);
                    }
                  break;