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
This commit is contained in:
Martin Jambor 2010-03-18 21:07:13 +01:00 committed by Martin Jambor
parent 7893d7acfe
commit 8132a837da
7 changed files with 203 additions and 59 deletions

View 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.

View 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 *);

View 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

View File

@ -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)

View 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

View File

@ -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 > ());
}

View 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;