aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMartin Jambor <mjambor@suse.cz>2010-03-18 21:07:13 +0100
committerMartin Jambor <jamborm@gcc.gnu.org>2010-03-18 21:07:13 +0100
commit8132a837da9fb586a5fd2596528178f9ea6f97a2 (patch)
treeb3c65fe0aa2410f77c557a506bd3f0cf02737f6e /gcc
parent7893d7acfe277b4d46f5b4f012f7f76971c33b63 (diff)
downloadgcc-8132a837da9fb586a5fd2596528178f9ea6f97a2.zip
gcc-8132a837da9fb586a5fd2596528178f9ea6f97a2.tar.gz
gcc-8132a837da9fb586a5fd2596528178f9ea6f97a2.tar.bz2
re PR middle-end/42450 (another GCC 4.5 ICE on C++ templated code)
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/cgraph.h2
-rw-r--r--gcc/cgraphunit.c123
-rw-r--r--gcc/ipa.c2
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/torture/pr42450.C112
-rw-r--r--gcc/tree-inline.c1
7 files changed, 203 insertions, 59 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 04ef3ca..9b5211c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index f8d52eb..4f0c333 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -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 *);
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index f4580ad..c41477b 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -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
diff --git a/gcc/ipa.c b/gcc/ipa.c
index f81d41a..c789a29 100644
--- 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)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4a0ef16..8d678f9 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..f630fa2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr42450.C
@@ -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 > ());
+}
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index f3c4204..e0928b9 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -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;