This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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 ----


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]