[tree-ssa] dead const/pure/alloca call removal

Jan Hubicka jh@suse.cz
Sat Nov 8 21:21:00 GMT 2003


> > > On Sat, 08 Nov 2003 10:55:16 -0800, "Zack Weinberg" <zack@codesourcery.com> wrote:
> > > 
> > > > Falk Hueffner <falk.hueffner@student.uni-tuebingen.de> writes:
> > > >
> > > >> Jan Hubicka <jh@suse.cz> writes:
> > > >>
> > > >>> + /* Return false when CALL can be removed when it's return value is dead.
> > > >>               ^ true?
> > > >>
> > > >> I would formulate it like this:
> > > >>
> > > >> Return true if CALL can be removed in case its return value is dead.
> > > >
> > > > Still better English, given your explanation of the return value:
> > > >
> > > >   Return true if CALL cannot be removed even if its return value
> > > >   is dead (i.e. CALL must be assumed to have side effects).
> > > 
> > > We have a flag for this: TREE_SIDE_EFFECTS, which is cleared in
> > > gimplify_call_expr for const functions.  If it should also be cleared for
> > > pure and alloca calls, please make the change there rather than introduce a
> > > new function.
> > 
> > OK, I will update the pure functions and ask for TREE_SIDE_EFFECTS.
> > Are you really sure we want to clear alloca too?  It has side effect.
> > Only I know that given the semantic of alloca the side effect is useless
> > when return value is thrown away.
> 
> This has a problem.  We first gimplify functions, then analyze them and
> mark as CONST/PURE and then optimize.  So we lose the information.
> 
> Wehre do you think this flag should be updated?
> (remove_useless* looks like one candidate)
Hi,
here is updated patch that use TREE_SIDE_EFFECTS for const and pure
functions, adds code to update the flag to remove_useless* and still use
separate test for alloca.  I added test that ensures that automatically
recognized pure functions are optimized.
It also updates spelling isses pointed out by Zack.  Thanks for all the comments :)
Bootstrap still in progress (stage3 now).  OK assuming it passes?

/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-dce" } */

int t() __attribute__ ((const));
q()
{
  int i = t();
  if (!i)
    i = t();
}
/* There should be no IF conditionals.  */
/* { dg-final { scan-tree-dump-times "if " 0 "dce"} } */

/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-dce" } */

int t() __attribute__ ((const));
q()
{
  alloca ();
}
/* There should be no alloca conditionals.  */
/* { dg-final { scan-tree-dump-times "alloca" 0 "dce"} } */

/* { dg-do compile } */
/* { dg-options "-O1 -fdump-tree-dce" } */

__attribute__ ((noinline))
static int t(int a)
{
	return a;
}
q()
{
  int i = t(1);
  if (!i)
    i = t(1);
}
/* We should notice that t is pure and we should delete IF conditional.  */
/* { dg-final { scan-tree-dump-times "Deleted.*if " 0 "dce"} } */

	* tree-ssa-dce.c (call_useful_p): New function.
	(stmt_useful_p):  Use it.
	* gimplify.c (gimplify_call_expr): Clear side effect flags for pure
	functions.
	* tree-cfg.c (remove_useless_stmts_and_vars_1): Clear side effect flags
	for pure and const functions.
Index: gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/gimplify.c,v
retrieving revision 1.1.2.106
diff -c -3 -p -r1.1.2.106 gimplify.c
*** gimplify.c	5 Nov 2003 13:39:23 -0000	1.1.2.106
--- gimplify.c	8 Nov 2003 21:11:02 -0000
*************** gimplify_call_expr (tree *expr_p, tree *
*** 1709,1719 ****
  	}
      }
  
!   /* If the function is "const", then clear TREE_SIDE_EFFECTS on its
       decl.  This allows us to eliminate redundant or useless
       calls to "const" functions.  */
    if (TREE_CODE (*expr_p) == CALL_EXPR
!       && (call_expr_flags (*expr_p) & ECF_CONST))
      TREE_SIDE_EFFECTS (*expr_p) = 0;
  
    return ret;
--- 1709,1719 ----
  	}
      }
  
!   /* If the function is "const" or "pure", then clear TREE_SIDE_EFFECTS on its
       decl.  This allows us to eliminate redundant or useless
       calls to "const" functions.  */
    if (TREE_CODE (*expr_p) == CALL_EXPR
!       && (call_expr_flags (*expr_p) & (ECF_CONST | ECF_PURE)))
      TREE_SIDE_EFFECTS (*expr_p) = 0;
  
    return ret;
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.199
diff -c -3 -p -r1.1.4.199 tree-cfg.c
*** tree-cfg.c	8 Nov 2003 09:49:19 -0000	1.1.4.199
--- tree-cfg.c	8 Nov 2003 21:11:02 -0000
*************** remove_useless_stmts_and_vars_1 (tree *f
*** 1233,1240 ****
  	case RETURN_EXPR:
  	  data->may_branch = true;
  	  break;
- 	case MODIFY_EXPR:
  	case CALL_EXPR:
  	  if (tree_could_throw_p (*stmt_p))
  	    data->may_throw = true;
  	  break;
--- 1233,1256 ----
  	case RETURN_EXPR:
  	  data->may_branch = true;
  	  break;
  	case CALL_EXPR:
+ 	  /* If the function is "const" or "pure", then clear TREE_SIDE_EFFECTS on its
+ 	     decl.  This allows us to eliminate redundant or useless
+ 	     calls to "const" functions. 
+ 
+ 	     Gimplifier already does the same operation, but we may notice functions
+ 	     being const and pure once their calls has been gimplified, so we need
+ 	     to update the flag.  */
+           if (call_expr_flags (*stmt_p) & (ECF_CONST | ECF_PURE))
+ 	    TREE_SIDE_EFFECTS (*stmt_p) = 0;
+ 	  if (tree_could_throw_p (*stmt_p))
+ 	    data->may_throw = true;
+ 	  break;
+ 	case MODIFY_EXPR:
+           if (TREE_CODE (TREE_OPERAND (*stmt_p, 1)) == CALL_EXPR
+ 	      && (call_expr_flags (TREE_OPERAND (*stmt_p, 1))
+ 		  & (ECF_CONST | ECF_PURE)))
+ 	    TREE_SIDE_EFFECTS (TREE_OPERAND (*stmt_p, 1)) = 0;
  	  if (tree_could_throw_p (*stmt_p))
  	    data->may_throw = true;
  	  break;
Index: tree-ssa-dce.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-dce.c,v
retrieving revision 1.1.2.64
diff -c -3 -p -r1.1.2.64 tree-ssa-dce.c
*** tree-ssa-dce.c	5 Nov 2003 13:39:23 -0000	1.1.2.64
--- tree-ssa-dce.c	8 Nov 2003 21:11:02 -0000
*************** find_useful_stmts (void)
*** 236,241 ****
--- 236,259 ----
      }
  }
  
+ /* Return true if CALL cannot be removed even if its return value
+    is dead (i.e. CALL must be assumed to have side effects).
+    In addition to const and pure functions we may elliminate alloca 
+    builtin too.  */
+ 
+ static bool
+ call_useful_p (tree call)
+ {
+   tree decl;
+ 
+   if (!TREE_SIDE_EFFECTS (call))
+     return false;
+   decl = get_callee_fndecl (call);
+   if (decl && DECL_BUILT_IN (decl)
+       && DECL_FUNCTION_CODE (decl) == BUILT_IN_ALLOCA)
+     return false;
+   return true;
+ }
  
  /* Return true if STMT is necessary.  */
  
*************** stmt_useful_p (tree stmt)
*** 258,269 ****
      case CASE_LABEL_EXPR:
      case LABEL_EXPR:
      case BIND_EXPR:
-     case CALL_EXPR:
      case RESX_EXPR:
        return true;
  
      case MODIFY_EXPR:
!       if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)
  	return true;
  
        /* These values are mildly magic bits of the EH runtime.  We can't
--- 276,289 ----
      case CASE_LABEL_EXPR:
      case LABEL_EXPR:
      case BIND_EXPR:
      case RESX_EXPR:
        return true;
+     case CALL_EXPR:
+       return call_useful_p (stmt);
  
      case MODIFY_EXPR:
!       if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR
! 	  && call_useful_p (TREE_OPERAND (stmt, 1)))
  	return true;
  
        /* These values are mildly magic bits of the EH runtime.  We can't



More information about the Gcc-patches mailing list