Commit f9487002 by Jakub Jelinek Committed by Jakub Jelinek

re PR c++/36631 (attribute always_inline -> sorry, unimplemented: recursive inlining)

	PR c++/36631
	* gimplify.c (gimplify_call_expr): Defer most of the cannot inline
	checking until GIMPLE lowering.
	* gimple-low.c (check_call_args): New function.
	(lower_stmt) <case GIMPLE_CALL>: Call it.

	* g++.dg/template/call5.C: New test.

From-SVN: r142033
parent 10432013
2008-11-20 Jakub Jelinek <jakub@redhat.com>
PR c++/36631
* gimplify.c (gimplify_call_expr): Defer most of the cannot inline
checking until GIMPLE lowering.
* gimple-low.c (check_call_args): New function.
(lower_stmt) <case GIMPLE_CALL>: Call it.
2008-11-19 Adam Nemet <anemet@caviumnetworks.com>
* config/mips/mips.c (mips_gimplify_va_arg_expr): Use -rsize
......
/* GIMPLE lowering pass. Converts High GIMPLE into Low GIMPLE.
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GCC.
......@@ -218,6 +219,80 @@ struct gimple_opt_pass pass_lower_cf =
};
/* Verify if the type of the argument matches that of the function
declaration. If we cannot verify this or there is a mismatch,
mark the call expression so it doesn't get inlined later. */
static void
check_call_args (gimple stmt)
{
tree fndecl, parms, p;
unsigned int i, nargs;
if (gimple_call_cannot_inline_p (stmt))
return;
nargs = gimple_call_num_args (stmt);
/* Get argument types for verification. */
fndecl = gimple_call_fndecl (stmt);
parms = NULL_TREE;
if (fndecl)
parms = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
else if (POINTER_TYPE_P (TREE_TYPE (gimple_call_fn (stmt))))
parms = TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (gimple_call_fn (stmt))));
/* Verify if the type of the argument matches that of the function
declaration. If we cannot verify this or there is a mismatch,
mark the call expression so it doesn't get inlined later. */
if (fndecl && DECL_ARGUMENTS (fndecl))
{
for (i = 0, p = DECL_ARGUMENTS (fndecl);
i < nargs;
i++, p = TREE_CHAIN (p))
{
/* We cannot distinguish a varargs function from the case
of excess parameters, still deferring the inlining decision
to the callee is possible. */
if (!p)
break;
if (p == error_mark_node
|| gimple_call_arg (stmt, i) == error_mark_node
|| !fold_convertible_p (DECL_ARG_TYPE (p),
gimple_call_arg (stmt, i)))
{
gimple_call_set_cannot_inline (stmt, true);
break;
}
}
}
else if (parms)
{
for (i = 0, p = parms; i < nargs; i++, p = TREE_CHAIN (p))
{
/* If this is a varargs function defer inlining decision
to callee. */
if (!p)
break;
if (TREE_VALUE (p) == error_mark_node
|| gimple_call_arg (stmt, i) == error_mark_node
|| TREE_CODE (TREE_VALUE (p)) == VOID_TYPE
|| !fold_convertible_p (TREE_VALUE (p),
gimple_call_arg (stmt, i)))
{
gimple_call_set_cannot_inline (stmt, true);
break;
}
}
}
else
{
if (nargs != 0)
gimple_call_set_cannot_inline (stmt, true);
}
}
/* Lower sequence SEQ. Unlike gimplification the statements are not relowered
when they are changed -- if this has to be done, the lowering routine must
do it explicitly. DATA is passed through the recursion. */
......@@ -320,6 +395,7 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
lower_builtin_setjmp (gsi);
return;
}
check_call_args (stmt);
}
break;
......
......@@ -2352,56 +2352,18 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
else if (POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_FN (*expr_p))))
parms = TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (*expr_p))));
/* Verify if the type of the argument matches that of the function
declaration. If we cannot verify this or there is a mismatch,
mark the call expression so it doesn't get inlined later. */
if (fndecl && DECL_ARGUMENTS (fndecl))
{
for (i = 0, p = DECL_ARGUMENTS (fndecl);
i < nargs;
i++, p = TREE_CHAIN (p))
{
/* We cannot distinguish a varargs function from the case
of excess parameters, still deferring the inlining decision
to the callee is possible. */
if (!p)
break;
if (p == error_mark_node
|| CALL_EXPR_ARG (*expr_p, i) == error_mark_node
|| !fold_convertible_p (DECL_ARG_TYPE (p),
CALL_EXPR_ARG (*expr_p, i)))
{
CALL_CANNOT_INLINE_P (*expr_p) = 1;
break;
}
}
}
p = DECL_ARGUMENTS (fndecl);
else if (parms)
{
for (i = 0, p = parms; i < nargs; i++, p = TREE_CHAIN (p))
{
/* If this is a varargs function defer inlining decision
to callee. */
if (!p)
break;
if (TREE_VALUE (p) == error_mark_node
|| CALL_EXPR_ARG (*expr_p, i) == error_mark_node
|| TREE_CODE (TREE_VALUE (p)) == VOID_TYPE
|| !fold_convertible_p (TREE_VALUE (p),
CALL_EXPR_ARG (*expr_p, i)))
{
CALL_CANNOT_INLINE_P (*expr_p) = 1;
break;
}
}
}
p = parms;
else
{
if (nargs != 0)
CALL_CANNOT_INLINE_P (*expr_p) = 1;
i = 0;
p = NULL_TREE;
}
for (i = 0; i < nargs && p; i++, p = TREE_CHAIN (p))
;
/* If the last argument is __builtin_va_arg_pack () and it is not
passed as a named argument, decrease the number of CALL_EXPR
......
2008-11-20 Jakub Jelinek <jakub@redhat.com>
PR c++/36631
* g++.dg/template/call5.C: New test.
2008-11-19 Adam Nemet <anemet@caviumnetworks.com>
* gcc.c-torture/compile/20081119-1.c: New test.
......
// PR c++/36631
// { dg-options "-O0" }
template <typename T> struct B
{
struct C
{
__attribute__ ((always_inline)) C (C const &c) {}
};
void __attribute__ ((always_inline)) g (C c) {}
};
void
trigger (B <int> b, B <int>::C c)
{
b.g (c);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment