This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH][RFC] Another approach to fixing "bad" inlining
- From: Richard Guenther <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 10 Jul 2007 12:40:11 +0200 (CEST)
- Subject: [PATCH][RFC] Another approach to fixing "bad" inlining
This reverts (parts of) the earlier patch that got rid of the
langhook convert_parm_for_inlining. With this patch we no longer try
to avoid inlining functions with mismatched parameters, instead we
try to deal with it after the fact (the same we did with the langhook,
but instead of relying on the frontend to define convertibleness we
use the new fold_convertible predicate and instead of issuing an
error if conversion is not possible we simply leave the parameters
or return variables uninitialized).
Instead of leaving things uninitialized we could also emit
VIEW_CONVERT_EXPRs and hope for the best (that rtl expansion won't
ICE on us, or that by luck we make more code "work" even if it is
undefined).
Bootstrapped and tested on x86_64-unknown-linux-gnu.
Of course we again don't have many testcases that exercise these
code paths, but this approach looks saner than the previous one.
Still, there may be better suggestions?
(the interesting parts of the patch are in tree-inline.c)
Thanks,
Richard.
2007-07-10 Richard Guenther <rguenther@suse.de>
Revert
2007-06-23 Richard Guenther <rguenther@suse.de>
* tree.h (CALL_CANNOT_INLINE_P): New macro to access static_flag
for CALL_EXPRs.
* cgraphbuild.c (initialize_inline_failed): Set inline failed
reason for mismatched types.
* gimplify.c (gimplify_call_expr): Verify the call expression
arguments match the called function type signature. Otherwise
mark the call expression to be not considered for inlining
using CALL_CANNOT_INLINE_P flag.
* ipa-inline.c (cgraph_mark_inline): Honor CALL_CANNOT_INLINE_P on the
edges call expression.
(cgraph_decide_inlining_of_small_function): Likewise.
(cgraph_decide_inlining): Likewise.
* tree-inline.c (setup_one_parameter): Leave non-convertible
parameters uninitialized.
(declare_return_variable): Leave non-convertible return
variables uninitialized.
Index: gcc/gimplify.c
===================================================================
*** gcc.orig/gimplify.c 2007-07-10 11:47:26.000000000 +0200
--- gcc/gimplify.c 2007-07-10 11:52:08.000000000 +0200
*************** gimplify_arg (tree *expr_p, tree *pre_p)
*** 2058,2064 ****
static enum gimplify_status
gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
{
! tree decl, parms, p;
enum gimplify_status ret;
int i, nargs;
--- 2058,2064 ----
static enum gimplify_status
gimplify_call_expr (tree *expr_p, tree *pre_p, bool want_value)
{
! tree decl;
enum gimplify_status ret;
int i, nargs;
*************** gimplify_call_expr (tree *expr_p, tree *
*** 2124,2183 ****
nargs = call_expr_nargs (*expr_p);
- /* Get argument types for verification. */
- decl = get_callee_fndecl (*expr_p);
- parms = NULL_TREE;
- if (decl)
- parms = TYPE_ARG_TYPES (TREE_TYPE (decl));
- 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 (decl && DECL_ARGUMENTS (decl))
- {
- for (i = 0, p = DECL_ARGUMENTS (decl); 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;
- }
- }
- }
- 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;
- }
- }
- }
- else if (nargs != 0)
- CALL_CANNOT_INLINE_P (*expr_p) = 1;
-
- /* Finally, gimplify the function arguments. */
for (i = (PUSH_ARGS_REVERSED ? nargs - 1 : 0);
PUSH_ARGS_REVERSED ? i >= 0 : i < nargs;
PUSH_ARGS_REVERSED ? i-- : i++)
--- 2124,2129 ----
Index: gcc/tree-inline.c
===================================================================
*** gcc.orig/tree-inline.c 2007-07-10 11:47:13.000000000 +0200
--- gcc/tree-inline.c 2007-07-10 11:55:34.000000000 +0200
*************** setup_one_parameter (copy_body_data *id,
*** 1278,1291 ****
tree init_stmt;
tree var;
tree var_sub;
! tree rhs = value;
tree def = (gimple_in_ssa_p (cfun)
? gimple_default_def (id->src_cfun, p) : NULL);
if (value
! && value != error_mark_node
! && !useless_type_conversion_p (TREE_TYPE (p), TREE_TYPE (value)))
! rhs = fold_build1 (NOP_EXPR, TREE_TYPE (p), value);
/* If the parameter is never assigned to, has no SSA_NAMEs created,
we may not need to create a new variable here at all. Instead, we may
--- 1278,1303 ----
tree init_stmt;
tree var;
tree var_sub;
! tree rhs;
tree def = (gimple_in_ssa_p (cfun)
? gimple_default_def (id->src_cfun, p) : NULL);
if (value
! && value != error_mark_node)
! {
! if (useless_type_conversion_p (TREE_TYPE (p), TREE_TYPE (value)))
! rhs = value;
! else if (fold_convertible_p (TREE_TYPE (p), value))
! rhs = fold_build1 (NOP_EXPR, TREE_TYPE (p), value);
! else
! {
! /* As last resort we could use a VIEW_CONVERT_EXPR, though leaving
! the parameter uninitialized is another valid option. */
! rhs = NULL_TREE;
! }
! }
! else
! rhs = value;
/* If the parameter is never assigned to, has no SSA_NAMEs created,
we may not need to create a new variable here at all. Instead, we may
*************** setup_one_parameter (copy_body_data *id,
*** 1386,1392 ****
/* Initialize this VAR_DECL from the equivalent argument. Convert
the argument to the proper type in case it was promoted. */
! if (value)
{
block_stmt_iterator bsi = bsi_last (bb);
--- 1398,1404 ----
/* Initialize this VAR_DECL from the equivalent argument. Convert
the argument to the proper type in case it was promoted. */
! if (rhs)
{
block_stmt_iterator bsi = bsi_last (bb);
*************** declare_return_variable (copy_body_data
*** 1643,1651 ****
/* Build the use expr. If the return type of the function was
promoted, convert it back to the expected type. */
use = var;
! if (!useless_type_conversion_p (caller_type, TREE_TYPE (var)))
use = fold_convert (caller_type, var);
!
STRIP_USELESS_TYPE_CONVERSION (use);
if (DECL_BY_REFERENCE (result))
--- 1655,1673 ----
/* Build the use expr. If the return type of the function was
promoted, convert it back to the expected type. */
use = var;
! if (useless_type_conversion_p (caller_type, TREE_TYPE (var)))
! ;
! else if (fold_convertible_p (caller_type, var))
use = fold_convert (caller_type, var);
! else
! {
! /* As last resort we could use a VIEW_CONVERT_EXPR, though leaving the
! result variable uninitialized is another valid option. */
! id->retvar = var;
! *use_p = NULL_TREE;
! return var;
! }
!
STRIP_USELESS_TYPE_CONVERSION (use);
if (DECL_BY_REFERENCE (result))
Index: gcc/cgraphbuild.c
===================================================================
*** gcc.orig/cgraphbuild.c 2007-06-23 20:25:29.000000000 +0200
--- gcc/cgraphbuild.c 2007-07-10 11:56:57.000000000 +0200
*************** initialize_inline_failed (struct cgraph_
*** 99,106 ****
"considered for inlining");
else if (!node->local.inlinable)
e->inline_failed = N_("function not inlinable");
- else if (CALL_CANNOT_INLINE_P (e->call_stmt))
- e->inline_failed = N_("mismatched arguments");
else
e->inline_failed = N_("function not considered for inlining");
}
--- 99,104 ----
Index: gcc/ipa-inline.c
===================================================================
*** gcc.orig/ipa-inline.c 2007-07-02 13:59:20.000000000 +0200
--- gcc/ipa-inline.c 2007-07-10 11:57:43.000000000 +0200
*************** cgraph_mark_inline (struct cgraph_edge *
*** 289,295 ****
struct cgraph_node *what = edge->callee;
struct cgraph_edge *e, *next;
- gcc_assert (!CALL_CANNOT_INLINE_P (edge->call_stmt));
/* Look for all calls, mark them inline and clone recursively
all inlined functions. */
for (e = what->callers; e; e = next)
--- 289,294 ----
*************** cgraph_decide_inlining_of_small_function
*** 952,960 ****
else
{
struct cgraph_node *callee;
! if (CALL_CANNOT_INLINE_P (edge->call_stmt)
! || !cgraph_check_inline_limits (edge->caller, edge->callee,
! &edge->inline_failed, true))
{
if (dump_file)
fprintf (dump_file, " Not inlining into %s:%s.\n",
--- 951,958 ----
else
{
struct cgraph_node *callee;
! if (!cgraph_check_inline_limits (edge->caller, edge->callee,
! &edge->inline_failed, true))
{
if (dump_file)
fprintf (dump_file, " Not inlining into %s:%s.\n",
*************** cgraph_decide_inlining (void)
*** 1078,1084 ****
for (e = node->callers; e; e = next)
{
next = e->next_caller;
! if (!e->inline_failed || CALL_CANNOT_INLINE_P (e->call_stmt))
continue;
if (cgraph_recursive_inlining_p (e->caller, e->callee,
&e->inline_failed))
--- 1076,1082 ----
for (e = node->callers; e; e = next)
{
next = e->next_caller;
! if (!e->inline_failed)
continue;
if (cgraph_recursive_inlining_p (e->caller, e->callee,
&e->inline_failed))
*************** cgraph_decide_inlining (void)
*** 1119,1125 ****
if (node->callers && !node->callers->next_caller && !node->needed
&& node->local.inlinable && node->callers->inline_failed
- && !CALL_CANNOT_INLINE_P (node->callers->call_stmt)
&& !DECL_EXTERNAL (node->decl) && !DECL_COMDAT (node->decl))
{
if (dump_file)
--- 1117,1122 ----
*************** cgraph_decide_inlining_incrementally (st
*** 1282,1289 ****
if (!e->callee->local.disregard_inline_limits
&& (mode != INLINE_ALL || !e->callee->local.inlinable))
continue;
- if (CALL_CANNOT_INLINE_P (e->call_stmt))
- continue;
/* When the edge is already inlined, we just need to recurse into
it in order to fully flatten the leaves. */
if (!e->inline_failed && mode == INLINE_ALL)
--- 1279,1284 ----
*************** cgraph_decide_inlining_incrementally (st
*** 1381,1388 ****
continue;
}
if (!cgraph_check_inline_limits (node, e->callee, &e->inline_failed,
! false)
! || CALL_CANNOT_INLINE_P (e->call_stmt))
{
if (dump_file)
{
--- 1376,1382 ----
continue;
}
if (!cgraph_check_inline_limits (node, e->callee, &e->inline_failed,
! false))
{
if (dump_file)
{
Index: gcc/tree.h
===================================================================
*** gcc.orig/tree.h 2007-07-04 10:25:04.000000000 +0200
--- gcc/tree.h 2007-07-10 11:56:45.000000000 +0200
*************** struct gimple_stmt GTY(())
*** 451,458 ****
GIMPLE_MODIFY_STMT
CASE_HIGH_SEEN in
CASE_LABEL_EXPR
- CALL_CANNOT_INLINE_P in
- CALL_EXPR
public_flag:
--- 451,456 ----
*************** extern void omp_clause_range_check_faile
*** 1147,1155 ****
#define CASE_HIGH_SEEN(NODE) \
(CASE_LABEL_EXPR_CHECK (NODE)->base.static_flag)
- /* Used to mark a CALL_EXPR as not suitable for inlining. */
- #define CALL_CANNOT_INLINE_P(NODE) ((NODE)->base.static_flag)
-
/* In an expr node (usually a conversion) this means the node was made
implicitly and should not lead to any sort of warning. In a decl node,
warnings concerning the decl should be suppressed. This is used at
--- 1145,1150 ----