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]

[tree-ssa] Gimple vs builtins



This patch fixes the tree-ssa branch so that gimplification doesn't muck
up recognition of opportunities to optimize/transform calls to builtin
functions into simpler forms.

At the root of the issue is the fact that gimple form places restrictions
on the form operands to a call can take.  Transforming the tree into
gimple form will cause some operands to be loaded into temporaries.
This is especially true for address arithmetic expressions.  That in turn
causes the expand_builtin_XXX routines to fail to recognize an opportunity
to transform/optimize a builtin function call (such as fputs -> fputc
transformations).

This patch allows the compiler to do _most_ of those optimizations when
gimplifying the tree. When we encounter a builtin function call, we go
ahead and try to perform the same transformations that expand_builtin_XXX
would perform.  And yes, the code was very factorizable, leading to
the ability to share code to perform these transformations between the
simplify_builtin_XXX and expand_builtin_XXX routines.

Anyway, this fixes 50+ failures in the GCC testsuite on the tree-ssa branch
related to not fully optimizing builtin function calls.  There are certain
some cases we do not currently handle -- most notably some of the
memcpy/memset cases which use store_by_pieces.  With work one could
probably hack up store_by_pieces enough to allow us to handle memcpy/memset
as well.

Bootstrapped and regression tested in the usual manner.


	* builtins.c: Fix minor comment typo.
	(expand_builtin_strcmp, expand_builtin_strncmp): Remove.
	(expand_builtin_strcat, expand_builtin_strncat): Likewise.
	(expand_builtin_strspn, expand_builtin_strcspn): Likewise.
	(expand_builtin_strcopy, expand_builtin_strstr): Likewise.
	(expand_builtin_strpbrk, expand_builtin_strchr): Likewise.
	(expand_builtin_strrchr, expand_builtin_fputs): Likewise.
	(simplify_builtin_memcmp, simplify_builtin_strcmp): New functions.
	(simplify_builtin_strpbrk, simplify_builtin_strstr): Likewise
	(simplify_builtin_strchr, simplify_builtin_strrchr): Likewise
	(simplify_builtin_strcpy, simplify_builtin_strncpy): Likewise
	(simplify_builtin_strncmp, simplify_builtin_strcat): Likewise
	(simplify_builtin_strncat, simplify_builtin_strspn): Likewise
	(simplify_builtin_strcspn, simplify_builtin_fputs): Likewise
	(expand_builtin_memcmp): Use simplify_builtin_memcmp.
	(simplify_builtin): New function
	(expand_builtin): Use simpify_builtin to collapse several common
	cases together.
	* gimplify.c (simplify_call_expr): Accept new argument.  All
	callers updated.  Call simplify_builtin to try and simplify builtin
	function calls before we simplify their arguments.
	* tree.h (simplify_builtin): Prototype.

	
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.152.2.18
diff -c -3 -p -r1.152.2.18 builtins.c
*** builtins.c	2 Mar 2003 19:58:44 -0000	1.152.2.18
--- builtins.c	12 Mar 2003 22:40:57 -0000
*************** const char *const built_in_names[(int) E
*** 76,82 ****
  tree built_in_decls[(int) END_BUILTINS];
  /* Declarations used when constructing the builtin implicitly in the compiler.
     It may be NULL_TREE when this is invalid (for instance runtime is not
!    required to implement the function call in all cases.  */
  tree implicit_built_in_decls[(int) END_BUILTINS];
  
  static int get_pointer_alignment	PARAMS ((tree, unsigned int));
--- 76,82 ----
  tree built_in_decls[(int) END_BUILTINS];
  /* Declarations used when constructing the builtin implicitly in the compiler.
     It may be NULL_TREE when this is invalid (for instance runtime is not
!    required to implement the function call in all cases).  */
  tree implicit_built_in_decls[(int) END_BUILTINS];
  
  static int get_pointer_alignment	PARAMS ((tree, unsigned int));
*************** static rtx expand_builtin_va_end	PARAMS 
*** 110,133 ****
  static rtx expand_builtin_va_copy	PARAMS ((tree));
  static rtx expand_builtin_memcmp	PARAMS ((tree, tree, rtx,
  						 enum machine_mode));
- static rtx expand_builtin_strcmp	PARAMS ((tree, rtx,
- 						 enum machine_mode));
- static rtx expand_builtin_strncmp	PARAMS ((tree, rtx,
- 						 enum machine_mode));
  static rtx builtin_memcpy_read_str	PARAMS ((PTR, HOST_WIDE_INT,
  						 enum machine_mode));
- static rtx expand_builtin_strcat	PARAMS ((tree, rtx,
- 						 enum machine_mode));
- static rtx expand_builtin_strncat	PARAMS ((tree, rtx,
- 						 enum machine_mode));
- static rtx expand_builtin_strspn	PARAMS ((tree, rtx,
- 						 enum machine_mode));
- static rtx expand_builtin_strcspn	PARAMS ((tree, rtx,
- 						 enum machine_mode));
  static rtx expand_builtin_memcpy	PARAMS ((tree, rtx,
  						 enum machine_mode));
- static rtx expand_builtin_strcpy	PARAMS ((tree, rtx,
- 						 enum machine_mode));
  static rtx builtin_strncpy_read_str	PARAMS ((PTR, HOST_WIDE_INT,
  						 enum machine_mode));
  static rtx expand_builtin_strncpy	PARAMS ((tree, rtx,
--- 110,119 ----
*************** static rtx expand_builtin_memset	PARAMS 
*** 140,157 ****
  						 enum machine_mode));
  static rtx expand_builtin_bzero		PARAMS ((tree));
  static rtx expand_builtin_strlen	PARAMS ((tree, rtx));
- static rtx expand_builtin_strstr	PARAMS ((tree, rtx,
- 						 enum machine_mode));
- static rtx expand_builtin_strpbrk	PARAMS ((tree, rtx,
- 						 enum machine_mode));
- static rtx expand_builtin_strchr	PARAMS ((tree, rtx,
- 						 enum machine_mode));
- static rtx expand_builtin_strrchr	PARAMS ((tree, rtx,
- 						 enum machine_mode));
  static rtx expand_builtin_alloca	PARAMS ((tree, rtx));
  static rtx expand_builtin_unop		PARAMS ((tree, rtx, rtx, optab));
  static rtx expand_builtin_frame_address	PARAMS ((tree));
- static rtx expand_builtin_fputs		PARAMS ((tree, int, int));
  static tree stabilize_va_list		PARAMS ((tree, int));
  static rtx expand_builtin_expect	PARAMS ((tree, rtx));
  static tree fold_builtin_constant_p	PARAMS ((tree));
--- 126,134 ----
*************** static tree fold_builtin_inf		PARAMS ((t
*** 160,165 ****
--- 137,156 ----
  static tree fold_builtin_nan		PARAMS ((tree, tree, int));
  static int validate_arglist		PARAMS ((tree, ...));
  static tree fold_trunc_transparent_mathfn PARAMS ((tree));
+ static tree simplify_builtin_memcmp	PARAMS ((tree));
+ static tree simplify_builtin_strcmp	PARAMS ((tree));
+ static tree simplify_builtin_strpbrk	PARAMS ((tree));
+ static tree simplify_builtin_strstr	PARAMS ((tree));
+ static tree simplify_builtin_strchr	PARAMS ((tree));
+ static tree simplify_builtin_strrchr	PARAMS ((tree));
+ static tree simplify_builtin_strcpy	PARAMS ((tree));
+ static tree simplify_builtin_strncpy	PARAMS ((tree));
+ static tree simplify_builtin_strncmp	PARAMS ((tree));
+ static tree simplify_builtin_strcat	PARAMS ((tree));
+ static tree simplify_builtin_strncat	PARAMS ((tree));
+ static tree simplify_builtin_strspn	PARAMS ((tree));
+ static tree simplify_builtin_strcspn	PARAMS ((tree));
+ static tree simplify_builtin_fputs	PARAMS ((tree, int, int));
  
  /* Return the alignment in bits of EXP, a pointer valued expression.
     But don't return more than MAX_ALIGN no matter what.
*************** expand_builtin_strlen (exp, target)
*** 2012,2026 ****
      }
  }
  
! /* Expand a call to the strstr builtin.  Return 0 if we failed the
!    caller should emit a normal call, otherwise try to get the result
!    in TARGET, if convenient (and in mode MODE if that's convenient).  */
  
! static rtx
! expand_builtin_strstr (arglist, target, mode)
       tree arglist;
-      rtx target;
-      enum machine_mode mode;
  {
    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      return 0;
--- 2003,2028 ----
      }
  }
  
! /* Simplify a call to the strstr builtin.
  
!    Return 0 if no simplification was possible, otherwise return the
!    simplified form of the call as a tree.
! 
!    The simplified form may be a constant or other expression which
!    computes the same value, but in a more efficient manner (including
!    calls to other builtin functions).
! 
!    The call may contain arguments which need to be evaluated, but
!    which are not useful to determine the result of the call.  In
!    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
!    COMPOUND_EXPR will be an argument which must be evaluated.
!    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
!    COMPOUND_EXPR in the chain will contain the tree for the simplified
!    form of the builtin function call.  */
! 
! static tree
! simplify_builtin_strstr (arglist)
       tree arglist;
  {
    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      return 0;
*************** expand_builtin_strstr (arglist, target, 
*** 2039,2055 ****
  	{
  	  const char *r = strstr (p1, p2);
  
- 	  if (r == NULL)
- 	    return const0_rtx;
- 
  	  /* Return an offset into the constant string argument.  */
! 	  return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
! 					   s1, ssize_int (r - p1))),
! 			      target, mode, EXPAND_NORMAL);
  	}
  
        if (p2[0] == '\0')
! 	return expand_expr (s1, target, mode, EXPAND_NORMAL);
  
        if (p2[1] != '\0')
  	return 0;
--- 2041,2056 ----
  	{
  	  const char *r = strstr (p1, p2);
  
  	  /* Return an offset into the constant string argument.  */
! 	  if (r == NULL)
! 	    return integer_zero_node;
! 	  else
! 	    return fold (build (PLUS_EXPR, TREE_TYPE (s1),
! 				s1, ssize_int (r - p1)));
  	}
  
        if (p2[0] == '\0')
! 	return s1;
  
        if (p2[1] != '\0')
  	return 0;
*************** expand_builtin_strstr (arglist, target, 
*** 2060,2082 ****
  
        /* New argument list transforming strstr(s1, s2) to
  	 strchr(s1, s2[0]).  */
!       arglist =
! 	build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
        arglist = tree_cons (NULL_TREE, s1, arglist);
!       return expand_expr (build_function_call_expr (fn, arglist),
! 			  target, mode, EXPAND_NORMAL);
      }
  }
  
! /* Expand a call to the strchr builtin.  Return 0 if we failed the
!    caller should emit a normal call, otherwise try to get the result
!    in TARGET, if convenient (and in mode MODE if that's convenient).  */
  
! static rtx
! expand_builtin_strchr (arglist, target, mode)
       tree arglist;
-      rtx target;
-      enum machine_mode mode;
  {
    if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      return 0;
--- 2061,2092 ----
  
        /* New argument list transforming strstr(s1, s2) to
  	 strchr(s1, s2[0]).  */
!       arglist = build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
        arglist = tree_cons (NULL_TREE, s1, arglist);
!       return build_function_call_expr (fn, arglist);
      }
  }
  
! /* Simplify a call to the strstr builtin.
  
!    Return 0 if no simplification was possible, otherwise return the
!    simplified form of the call as a tree.
! 
!    The simplified form may be a constant or other expression which
!    computes the same value, but in a more efficient manner (including
!    calls to other builtin functions).
! 
!    The call may contain arguments which need to be evaluated, but
!    which are not useful to determine the result of the call.  In
!    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
!    COMPOUND_EXPR will be an argument which must be evaluated.
!    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
!    COMPOUND_EXPR in the chain will contain the tree for the simplified
!    form of the builtin function call.  */
! 
! static tree
! simplify_builtin_strchr (arglist)
       tree arglist;
  {
    if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      return 0;
*************** expand_builtin_strchr (arglist, target, 
*** 2100,2111 ****
  	  r = strchr (p1, c);
  
  	  if (r == NULL)
! 	    return const0_rtx;
  
  	  /* Return an offset into the constant string argument.  */
! 	  return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
! 					   s1, ssize_int (r - p1))),
! 			      target, mode, EXPAND_NORMAL);
  	}
  
        /* FIXME: Should use here strchrM optab so that ports can optimize
--- 2110,2120 ----
  	  r = strchr (p1, c);
  
  	  if (r == NULL)
! 	    return integer_zero_node;
  
  	  /* Return an offset into the constant string argument.  */
! 	  return fold (build (PLUS_EXPR, TREE_TYPE (s1),
! 			      s1, ssize_int (r - p1)));
  	}
  
        /* FIXME: Should use here strchrM optab so that ports can optimize
*************** expand_builtin_strchr (arglist, target, 
*** 2114,2128 ****
      }
  }
  
! /* Expand a call to the strrchr builtin.  Return 0 if we failed the
!    caller should emit a normal call, otherwise try to get the result
!    in TARGET, if convenient (and in mode MODE if that's convenient).  */
  
! static rtx
! expand_builtin_strrchr (arglist, target, mode)
       tree arglist;
-      rtx target;
-      enum machine_mode mode;
  {
    if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      return 0;
--- 2123,2148 ----
      }
  }
  
! /* Simplify a call to the strrchr builtin.
  
!    Return 0 if no simplification was possible, otherwise return the
!    simplified form of the call as a tree.
! 
!    The simplified form may be a constant or other expression which
!    computes the same value, but in a more efficient manner (including
!    calls to other builtin functions).
! 
!    The call may contain arguments which need to be evaluated, but
!    which are not useful to determine the result of the call.  In
!    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
!    COMPOUND_EXPR will be an argument which must be evaluated.
!    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
!    COMPOUND_EXPR in the chain will contain the tree for the simplified
!    form of the builtin function call.  */
! 
! static tree
! simplify_builtin_strrchr (arglist)
       tree arglist;
  {
    if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      return 0;
*************** expand_builtin_strrchr (arglist, target,
*** 2147,2158 ****
  	  r = strrchr (p1, c);
  
  	  if (r == NULL)
! 	    return const0_rtx;
  
  	  /* Return an offset into the constant string argument.  */
! 	  return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
! 					   s1, ssize_int (r - p1))),
! 			      target, mode, EXPAND_NORMAL);
  	}
  
        if (! integer_zerop (s2))
--- 2167,2177 ----
  	  r = strrchr (p1, c);
  
  	  if (r == NULL)
! 	    return integer_zero_node;
  
  	  /* Return an offset into the constant string argument.  */
! 	  return fold (build (PLUS_EXPR, TREE_TYPE (s1),
! 			      s1, ssize_int (r - p1)));
  	}
  
        if (! integer_zerop (s2))
*************** expand_builtin_strrchr (arglist, target,
*** 2163,2182 ****
  	return 0;
  
        /* Transform strrchr(s1, '\0') to strchr(s1, '\0').  */
!       return expand_expr (build_function_call_expr (fn, arglist),
! 			  target, mode, EXPAND_NORMAL);
      }
  }
  
! /* Expand a call to the strpbrk builtin.  Return 0 if we failed the
!    caller should emit a normal call, otherwise try to get the result
!    in TARGET, if convenient (and in mode MODE if that's convenient).  */
  
! static rtx
! expand_builtin_strpbrk (arglist, target, mode)
       tree arglist;
-      rtx target;
-      enum machine_mode mode;
  {
    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      return 0;
--- 2182,2211 ----
  	return 0;
  
        /* Transform strrchr(s1, '\0') to strchr(s1, '\0').  */
!       return build_function_call_expr (fn, arglist);
      }
  }
  
! /* Simplify a call to the strpbrk builtin.
  
!    Return 0 if no simplification was possible, otherwise return the
!    simplified form of the call as a tree.
! 
!    The simplified form may be a constant or other expression which
!    computes the same value, but in a more efficient manner (including
!    calls to other builtin functions).
! 
!    The call may contain arguments which need to be evaluated, but
!    which are not useful to determine the result of the call.  In
!    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
!    COMPOUND_EXPR will be an argument which must be evaluated.
!    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
!    COMPOUND_EXPR in the chain will contain the tree for the simplified
!    form of the builtin function call.  */
! 
! static tree
! simplify_builtin_strpbrk (arglist)
       tree arglist;
  {
    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      return 0;
*************** expand_builtin_strpbrk (arglist, target,
*** 2196,2207 ****
  	  const char *r = strpbrk (p1, p2);
  
  	  if (r == NULL)
! 	    return const0_rtx;
  
  	  /* Return an offset into the constant string argument.  */
! 	  return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
! 					   s1, ssize_int (r - p1))),
! 			      target, mode, EXPAND_NORMAL);
  	}
  
        if (p2[0] == '\0')
--- 2225,2235 ----
  	  const char *r = strpbrk (p1, p2);
  
  	  if (r == NULL)
! 	    return integer_zero_node;
  
  	  /* Return an offset into the constant string argument.  */
! 	  return fold (build (PLUS_EXPR, TREE_TYPE (s1),
! 			      s1, ssize_int (r - p1)));
  	}
  
        if (p2[0] == '\0')
*************** expand_builtin_strpbrk (arglist, target,
*** 2209,2216 ****
  	  /* strpbrk(x, "") == NULL.
  	     Evaluate and ignore the arguments in case they had
  	     side-effects.  */
! 	  expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 	  return const0_rtx;
  	}
  
        if (p2[1] != '\0')
--- 2237,2243 ----
  	  /* strpbrk(x, "") == NULL.
  	     Evaluate and ignore the arguments in case they had
  	     side-effects.  */
! 	  return build (COMPOUND_EXPR, void_type_node, s1, integer_zero_node);
  	}
  
        if (p2[1] != '\0')
*************** expand_builtin_strpbrk (arglist, target,
*** 2225,2232 ****
        arglist =
  	build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
        arglist = tree_cons (NULL_TREE, s1, arglist);
!       return expand_expr (build_function_call_expr (fn, arglist),
! 			  target, mode, EXPAND_NORMAL);
      }
  }
  
--- 2252,2258 ----
        arglist =
  	build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
        arglist = tree_cons (NULL_TREE, s1, arglist);
!       return build_function_call_expr (fn, arglist);
      }
  }
  
*************** expand_builtin_memcpy (arglist, target, 
*** 2338,2355 ****
      }
  }
  
! /* Expand expression EXP, which is a call to the strcpy builtin.  Return 0
!    if we failed the caller should emit a normal call, otherwise try to get
!    the result in TARGET, if convenient (and in mode MODE if that's
!    convenient).  */
  
! static rtx
! expand_builtin_strcpy (exp, target, mode)
!      tree exp;
!      rtx target;
!      enum machine_mode mode;
  {
-   tree arglist = TREE_OPERAND (exp, 1);
    tree fn, len;
  
    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
--- 2364,2390 ----
      }
  }
  
! /* Simplify a call to the strcpy builtin.
  
!    Return 0 if no simplification was possible, otherwise return the
!    simplified form of the call as a tree.
! 
!    The simplified form may be a constant or other expression which
!    computes the same value, but in a more efficient manner (including
!    calls to other builtin functions).
! 
!    The call may contain arguments which need to be evaluated, but
!    which are not useful to determine the result of the call.  In
!    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
!    COMPOUND_EXPR will be an argument which must be evaluated.
!    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
!    COMPOUND_EXPR in the chain will contain the tree for the simplified
!    form of the builtin function call.  */
! 
! static tree
! simplify_builtin_strcpy (arglist)
!      tree arglist;
  {
    tree fn, len;
  
    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
*************** expand_builtin_strcpy (exp, target, mode
*** 2365,2372 ****
  
    len = size_binop (PLUS_EXPR, len, ssize_int (1));
    chainon (arglist, build_tree_list (NULL_TREE, len));
!   return expand_expr (build_function_call_expr (fn, arglist),
! 		      target, mode, EXPAND_NORMAL);
  }
  
  /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
--- 2400,2406 ----
  
    len = size_binop (PLUS_EXPR, len, ssize_int (1));
    chainon (arglist, build_tree_list (NULL_TREE, len));
!   return build_function_call_expr (fn, arglist);
  }
  
  /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
*************** builtin_strncpy_read_str (data, offset, 
*** 2387,2394 ****
    return c_readstr (str + offset, mode);
  }
  
! /* Expand expression EXP, which is a call to the strncpy builtin.  Return 0
!    if we failed the caller should emit a normal call.  */
  
  static rtx
  expand_builtin_strncpy (arglist, target, mode)
--- 2421,2488 ----
    return c_readstr (str + offset, mode);
  }
  
! /* Simplify a call to the strncpy builtin.
! 
!    Return 0 if no simplification was possible, otherwise return the
!    simplified form of the call as a tree.
! 
!    The simplified form may be a constant or other expression which
!    computes the same value, but in a more efficient manner (including
!    calls to other builtin functions).
! 
!    The call may contain arguments which need to be evaluated, but
!    which are not useful to determine the result of the call.  In
!    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
!    COMPOUND_EXPR will be an argument which must be evaluated.
!    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
!    COMPOUND_EXPR in the chain will contain the tree for the simplified
!    form of the builtin function call.  */
! 
! static tree
! simplify_builtin_strncpy (arglist)
!      tree arglist;
! {
!   if (!validate_arglist (arglist,
! 			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
!   else
!     {
!       tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
!       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
!       tree fn;
! 
!       /* We must be passed a constant len parameter.  */
!       if (TREE_CODE (len) != INTEGER_CST)
! 	return 0;
! 
!       /* If the len parameter is zero, return the dst parameter.  */
!       if (integer_zerop (len))
! 	{
! 	  /* Evaluate and ignore the src argument in case it has
! 	     side-effects and return the dst parameter.  */
! 	  return build (COMPOUND_EXPR, void_type_node,
! 			TREE_VALUE (TREE_CHAIN (arglist)),
! 			TREE_VALUE (arglist));
! 	}
! 
!       /* Now, we must be passed a constant src ptr parameter.  */
!       if (slen == 0 || TREE_CODE (slen) != INTEGER_CST)
! 	return 0;
! 
!       slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
! 
!       /* We do not support simplification of this case, though we do
!          support it when expanding trees into RTL.  */
!       if (tree_int_cst_lt (slen, len))
! 	return 0;
! 
!       /* OK transform into builtin memcpy.  */
!       fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
!       if (!fn)
! 	return 0;
!       return build_function_call_expr (fn, arglist);
!     }
! }
  
  static rtx
  expand_builtin_strncpy (arglist, target, mode)
*************** expand_builtin_bzero (exp)
*** 2664,2680 ****
    return result;
  }
  
! /* Expand expression EXP, which is a call to the memcmp or the strcmp builtin.
!    ARGLIST is the argument list for this call.  Return 0 if we failed and the
!    caller should emit a normal call, otherwise try to get the result in
!    TARGET, if convenient (and in mode MODE, if that's convenient).  */
  
! static rtx
! expand_builtin_memcmp (exp, arglist, target, mode)
!      tree exp ATTRIBUTE_UNUSED;
       tree arglist;
-      rtx target;
-      enum machine_mode mode;
  {
    tree arg1, arg2, len;
    const char *p1, *p2;
--- 2758,2783 ----
    return result;
  }
  
! /* Simplify a call to the memcmp builtin.
  
!    Return 0 if no simplification was possible, otherwise return the
!    simplified form of the call as a tree.
! 
!    The simplified form may be a constant or other expression which
!    computes the same value, but in a more efficient manner (including
!    calls to other builtin functions).
! 
!    The call may contain arguments which need to be evaluated, but
!    which are not useful to determine the result of the call.  In
!    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
!    COMPOUND_EXPR will be an argument which must be evaluated.
!    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
!    COMPOUND_EXPR in the chain will contain the tree for the simplified
!    form of the builtin function call.  */
! 
! static tree
! simplify_builtin_memcmp (arglist)
       tree arglist;
  {
    tree arg1, arg2, len;
    const char *p1, *p2;
*************** expand_builtin_memcmp (exp, arglist, tar
*** 2692,2700 ****
      {
        /* Evaluate and ignore arg1 and arg2 in case they have
           side-effects.  */
!       expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
!       expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
!       return const0_rtx;
      }
  
    p1 = c_getstr (arg1);
--- 2795,2803 ----
      {
        /* Evaluate and ignore arg1 and arg2 in case they have
           side-effects.  */
!       return build (COMPOUND_EXPR, void_type_node, arg1,
! 		    build (COMPOUND_EXPR, void_type_node,
! 			   arg2, integer_zero_node));
      }
  
    p1 = c_getstr (arg1);
*************** expand_builtin_memcmp (exp, arglist, tar
*** 2708,2714 ****
      {
        const int r = memcmp (p1, p2, tree_low_cst (len, 1));
  
!       return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
      }
  
    /* If len parameter is one, return an expression corresponding to
--- 2811,2819 ----
      {
        const int r = memcmp (p1, p2, tree_low_cst (len, 1));
  
!       return (r < 0
! 	      ? integer_minus_one_node
! 	      : (r > 0 ? integer_one_node : integer_zero_node));
      }
  
    /* If len parameter is one, return an expression corresponding to
*************** expand_builtin_memcmp (exp, arglist, tar
*** 2725,2733 ****
        fold (build1 (CONVERT_EXPR, integer_type_node,
  		    build1 (INDIRECT_REF, cst_uchar_node,
  			    build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
!       tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
!       return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
  
  #ifdef HAVE_cmpstrsi
    {
--- 2830,2882 ----
        fold (build1 (CONVERT_EXPR, integer_type_node,
  		    build1 (INDIRECT_REF, cst_uchar_node,
  			    build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
!       return fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
!     }
! 
!   return 0;
! }
! 
! /* Expand expression EXP, which is a call to the memcmp or the strcmp builtin.
!    ARGLIST is the argument list for this call.  Return 0 if we failed and the
!    caller should emit a normal call, otherwise try to get the result in
!    TARGET, if convenient (and in mode MODE, if that's convenient).  */
! 
! static rtx
! expand_builtin_memcmp (exp, arglist, target, mode)
!      tree exp ATTRIBUTE_UNUSED;
!      tree arglist;
!      rtx target;
!      enum machine_mode mode;
! {
!   tree arg1, arg2, len, new;
! 
!   new = simplify_builtin_memcmp (arglist);
!   if (new)
!     {
!       /* First deal with any arguments which need to be expanded
! 	 merely to deal with any side effects they may have.  */
!       while (TREE_CODE (new) == COMPOUND_EXPR)
! 	{
! 	  expand_expr (TREE_OPERAND (new, 0), const0_rtx,
! 		       VOIDmode, EXPAND_NORMAL);
! 	  new = TREE_OPERAND (new, 1);
! 	}
! 
!       /* At this point NEW contains either the result of the
! 	 builtin call (if it was a compile-time constant) or
! 	 a new CALL_EXPR to another builtin function.  Expand
! 	 it and return the RTX for the result.  */
!       return expand_expr (new, target, mode, EXPAND_NORMAL);
      }
+   else if (!validate_arglist (arglist,
+ 			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+     return 0;
+ 
+   /* If we were unable to simplify the builtin, there may be a target
+      insn which implements cmpstrsi that we can use.  */
+   arg1 = TREE_VALUE (arglist);
+   arg2 = TREE_VALUE (TREE_CHAIN (arglist));
+   len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
  
  #ifdef HAVE_cmpstrsi
    {
*************** expand_builtin_memcmp (exp, arglist, tar
*** 2790,2806 ****
    return 0;
  }
  
! /* Expand expression EXP, which is a call to the strcmp builtin.  Return 0
!    if we failed the caller should emit a normal call, otherwise try to get
!    the result in TARGET, if convenient.  */
  
! static rtx
! expand_builtin_strcmp (exp, target, mode)
!      tree exp;
!      rtx target;
!      enum machine_mode mode;
  {
-   tree arglist = TREE_OPERAND (exp, 1);
    tree arg1, arg2, len, len2, fn;
    const char *p1, *p2;
  
--- 2939,2965 ----
    return 0;
  }
  
! /* Simplify a call to the strcmp builtin.
  
!    Return 0 if no simplification was possible, otherwise return the
!    simplified form of the call as a tree.
! 
!    The simplified form may be a constant or other expression which
!    computes the same value, but in a more efficient manner (including
!    calls to other builtin functions).
! 
!    The call may contain arguments which need to be evaluated, but
!    which are not useful to determine the result of the call.  In
!    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
!    COMPOUND_EXPR will be an argument which must be evaluated.
!    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
!    COMPOUND_EXPR in the chain will contain the tree for the simplified
!    form of the builtin function call.  */
! 
! static tree
! simplify_builtin_strcmp (arglist)
!      tree arglist;
  {
    tree arg1, arg2, len, len2, fn;
    const char *p1, *p2;
  
*************** expand_builtin_strcmp (exp, target, mode
*** 2816,2822 ****
    if (p1 && p2)
      {
        const int i = strcmp (p1, p2);
!       return (i < 0 ? constm1_rtx : (i > 0 ? const1_rtx : const0_rtx));
      }
  
    /* If either arg is "", return an expression corresponding to
--- 2975,2983 ----
    if (p1 && p2)
      {
        const int i = strcmp (p1, p2);
!       return (i < 0
! 	      ? integer_minus_one_node
! 	      : (i > 0 ? integer_one_node : integer_zero_node));
      }
  
    /* If either arg is "", return an expression corresponding to
*************** expand_builtin_strcmp (exp, target, mode
*** 2833,2840 ****
  	fold (build1 (CONVERT_EXPR, integer_type_node,
  		      build1 (INDIRECT_REF, cst_uchar_node,
  			      build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
!       tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
!       return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
  
    len = c_strlen (arg1);
--- 2994,3000 ----
  	fold (build1 (CONVERT_EXPR, integer_type_node,
  		      build1 (INDIRECT_REF, cst_uchar_node,
  			      build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
!       return fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
      }
  
    len = c_strlen (arg1);
*************** expand_builtin_strcmp (exp, target, mode
*** 2878,2898 ****
      return 0;
  
    chainon (arglist, build_tree_list (NULL_TREE, len));
!   return expand_expr (build_function_call_expr (fn, arglist),
! 		      target, mode, EXPAND_NORMAL);
  }
  
! /* Expand expression EXP, which is a call to the strncmp builtin.  Return 0
!    if we failed the caller should emit a normal call, otherwise try to get
!    the result in TARGET, if convenient.  */
  
! static rtx
! expand_builtin_strncmp (exp, target, mode)
!      tree exp;
!      rtx target;
!      enum machine_mode mode;
  {
-   tree arglist = TREE_OPERAND (exp, 1);
    tree fn, newarglist, len = 0;
    tree arg1, arg2, arg3;
    const char *p1, *p2;
--- 3038,3067 ----
      return 0;
  
    chainon (arglist, build_tree_list (NULL_TREE, len));
!   return build_function_call_expr (fn, arglist);
  }
  
! /* Simplify a call to the strncmp builtin.
  
!    Return 0 if no simplification was possible, otherwise return the
!    simplified form of the call as a tree.
! 
!    The simplified form may be a constant or other expression which
!    computes the same value, but in a more efficient manner (including
!    calls to other builtin functions).
! 
!    The call may contain arguments which need to be evaluated, but
!    which are not useful to determine the result of the call.  In
!    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
!    COMPOUND_EXPR will be an argument which must be evaluated.
!    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
!    COMPOUND_EXPR in the chain will contain the tree for the simplified
!    form of the builtin function call.  */
! 
! static tree
! simplify_builtin_strncmp (arglist)
!      tree arglist;
  {
    tree fn, newarglist, len = 0;
    tree arg1, arg2, arg3;
    const char *p1, *p2;
*************** expand_builtin_strncmp (exp, target, mod
*** 2910,2918 ****
      {
        /* Evaluate and ignore arg1 and arg2 in case they have
  	 side-effects.  */
!       expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
!       expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
!       return const0_rtx;
      }
  
    p1 = c_getstr (arg1);
--- 3079,3087 ----
      {
        /* Evaluate and ignore arg1 and arg2 in case they have
  	 side-effects.  */
!       return build (COMPOUND_EXPR, void_type_node, arg1,
! 		    build (COMPOUND_EXPR, void_type_node,
! 			   arg2, integer_zero_node));
      }
  
    p1 = c_getstr (arg1);
*************** expand_builtin_strncmp (exp, target, mod
*** 2922,2928 ****
    if (host_integerp (arg3, 1) && p1 && p2)
      {
        const int r = strncmp (p1, p2, tree_low_cst (arg3, 1));
!       return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
      }
  
    /* If len == 1 or (either string parameter is "" and (len >= 1)),
--- 3091,3099 ----
    if (host_integerp (arg3, 1) && p1 && p2)
      {
        const int r = strncmp (p1, p2, tree_low_cst (arg3, 1));
!       return (r < 0
! 	      ? integer_minus_one_node
! 	      : (r > 0 ? integer_one_node : integer_zero_node));
      }
  
    /* If len == 1 or (either string parameter is "" and (len >= 1)),
*************** expand_builtin_strncmp (exp, target, mod
*** 2942,2949 ****
  	fold (build1 (CONVERT_EXPR, integer_type_node,
  		      build1 (INDIRECT_REF, cst_uchar_node,
  			      build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
!       tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
!       return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
  
    /* If c_strlen can determine an expression for one of the string
--- 3113,3119 ----
  	fold (build1 (CONVERT_EXPR, integer_type_node,
  		      build1 (INDIRECT_REF, cst_uchar_node,
  			      build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
!       return fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
      }
  
    /* If c_strlen can determine an expression for one of the string
*************** expand_builtin_strncmp (exp, target, mod
*** 2980,2998 ****
    newarglist = build_tree_list (NULL_TREE, len);
    newarglist = tree_cons (NULL_TREE, arg2, newarglist);
    newarglist = tree_cons (NULL_TREE, arg1, newarglist);
!   return expand_expr (build_function_call_expr (fn, newarglist),
! 		      target, mode, EXPAND_NORMAL);
  }
  
! /* Expand expression EXP, which is a call to the strcat builtin.
!    Return 0 if we failed the caller should emit a normal call,
!    otherwise try to get the result in TARGET, if convenient.  */
  
! static rtx
! expand_builtin_strcat (arglist, target, mode)
       tree arglist;
-      rtx target;
-      enum machine_mode mode;
  {
    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      return 0;
--- 3150,3178 ----
    newarglist = build_tree_list (NULL_TREE, len);
    newarglist = tree_cons (NULL_TREE, arg2, newarglist);
    newarglist = tree_cons (NULL_TREE, arg1, newarglist);
!   return build_function_call_expr (fn, newarglist);
  }
  
! /* Simplify a call to the strcat builtin.
  
!    Return 0 if no simplification was possible, otherwise return the
!    simplified form of the call as a tree.
! 
!    The simplified form may be a constant or other expression which
!    computes the same value, but in a more efficient manner (including
!    calls to other builtin functions).
! 
!    The call may contain arguments which need to be evaluated, but
!    which are not useful to determine the result of the call.  In
!    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
!    COMPOUND_EXPR will be an argument which must be evaluated.
!    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
!    COMPOUND_EXPR in the chain will contain the tree for the simplified
!    form of the builtin function call.  */
! 
! static tree
! simplify_builtin_strcat (arglist)
       tree arglist;
  {
    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      return 0;
*************** expand_builtin_strcat (arglist, target, 
*** 3004,3024 ****
  
        /* If the string length is zero, return the dst parameter.  */
        if (p && *p == '\0')
! 	return expand_expr (dst, target, mode, EXPAND_NORMAL);
  
        return 0;
      }
  }
  
! /* Expand expression EXP, which is a call to the strncat builtin.
!    Return 0 if we failed the caller should emit a normal call,
!    otherwise try to get the result in TARGET, if convenient.  */
  
! static rtx
! expand_builtin_strncat (arglist, target, mode)
       tree arglist;
-      rtx target;
-      enum machine_mode mode;
  {
    if (!validate_arglist (arglist,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
--- 3184,3215 ----
  
        /* If the string length is zero, return the dst parameter.  */
        if (p && *p == '\0')
! 	return dst;
  
        return 0;
      }
  }
  
! /* Simplify a call to the strncat builtin.
  
!    Return 0 if no simplification was possible, otherwise return the
!    simplified form of the call as a tree.
! 
!    The simplified form may be a constant or other expression which
!    computes the same value, but in a more efficient manner (including
!    calls to other builtin functions).
! 
!    The call may contain arguments which need to be evaluated, but
!    which are not useful to determine the result of the call.  In
!    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
!    COMPOUND_EXPR will be an argument which must be evaluated.
!    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
!    COMPOUND_EXPR in the chain will contain the tree for the simplified
!    form of the builtin function call.  */
! 
! static tree
! simplify_builtin_strncat (arglist)
       tree arglist;
  {
    if (!validate_arglist (arglist,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
*************** expand_builtin_strncat (arglist, target,
*** 3033,3045 ****
        /* If the requested length is zero, or the src parameter string
            length is zero, return the dst parameter.  */
        if (integer_zerop (len) || (p && *p == '\0'))
! 	{
! 	  /* Evaluate and ignore the src and len parameters in case
! 	     they have side-effects.  */
! 	  expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 	  expand_expr (len, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 	  return expand_expr (dst, target, mode, EXPAND_NORMAL);
! 	}
  
        /* If the requested len is greater than or equal to the string
           length, call strcat.  */
--- 3224,3231 ----
        /* If the requested length is zero, or the src parameter string
            length is zero, return the dst parameter.  */
        if (integer_zerop (len) || (p && *p == '\0'))
! 	return build (COMPOUND_EXPR, void_type_node, src,
! 		      build (COMPOUND_EXPR, void_type_node, len, dst));
  
        /* If the requested len is greater than or equal to the string
           length, call strcat.  */
*************** expand_builtin_strncat (arglist, target,
*** 3055,3076 ****
  	  if (!fn)
  	    return 0;
  
! 	  return expand_expr (build_function_call_expr (fn, newarglist),
! 			      target, mode, EXPAND_NORMAL);
  	}
        return 0;
      }
  }
  
! /* Expand expression EXP, which is a call to the strspn builtin.
!    Return 0 if we failed the caller should emit a normal call,
!    otherwise try to get the result in TARGET, if convenient.  */
  
! static rtx
! expand_builtin_strspn (arglist, target, mode)
       tree arglist;
-      rtx target;
-      enum machine_mode mode;
  {
    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      return 0;
--- 3241,3272 ----
  	  if (!fn)
  	    return 0;
  
! 	  return build_function_call_expr (fn, newarglist);
  	}
        return 0;
      }
  }
  
! /* Simplify a call to the strspn builtin.
  
!    Return 0 if no simplification was possible, otherwise return the
!    simplified form of the call as a tree.
! 
!    The simplified form may be a constant or other expression which
!    computes the same value, but in a more efficient manner (including
!    calls to other builtin functions).
! 
!    The call may contain arguments which need to be evaluated, but
!    which are not useful to determine the result of the call.  In
!    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
!    COMPOUND_EXPR will be an argument which must be evaluated.
!    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
!    COMPOUND_EXPR in the chain will contain the tree for the simplified
!    form of the builtin function call.  */
! 
! static tree
! simplify_builtin_strspn (arglist)
       tree arglist;
  {
    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      return 0;
*************** expand_builtin_strspn (arglist, target, 
*** 3083,3089 ****
        if (p1 && p2)
  	{
  	  const size_t r = strspn (p1, p2);
! 	  return expand_expr (size_int (r), target, mode, EXPAND_NORMAL);
  	}
  
        /* If either argument is "", return 0.  */
--- 3279,3285 ----
        if (p1 && p2)
  	{
  	  const size_t r = strspn (p1, p2);
! 	  return size_int (r);
  	}
  
        /* If either argument is "", return 0.  */
*************** expand_builtin_strspn (arglist, target, 
*** 3091,3113 ****
  	{
  	  /* Evaluate and ignore both arguments in case either one has
  	     side-effects.  */
! 	  expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 	  expand_expr (s2, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 	  return const0_rtx;
  	}
        return 0;
      }
  }
  
! /* Expand expression EXP, which is a call to the strcspn builtin.
!    Return 0 if we failed the caller should emit a normal call,
!    otherwise try to get the result in TARGET, if convenient.  */
  
! static rtx
! expand_builtin_strcspn (arglist, target, mode)
       tree arglist;
-      rtx target;
-      enum machine_mode mode;
  {
    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      return 0;
--- 3287,3320 ----
  	{
  	  /* Evaluate and ignore both arguments in case either one has
  	     side-effects.  */
! 	  return build (COMPOUND_EXPR, void_type_node, s1,
! 			build (COMPOUND_EXPR, void_type_node,
! 			       s2, integer_zero_node));
  	}
        return 0;
      }
  }
  
! /* Simplify a call to the strcspn builtin.
  
!    Return 0 if no simplification was possible, otherwise return the
!    simplified form of the call as a tree.
! 
!    The simplified form may be a constant or other expression which
!    computes the same value, but in a more efficient manner (including
!    calls to other builtin functions).
! 
!    The call may contain arguments which need to be evaluated, but
!    which are not useful to determine the result of the call.  In
!    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
!    COMPOUND_EXPR will be an argument which must be evaluated.
!    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
!    COMPOUND_EXPR in the chain will contain the tree for the simplified
!    form of the builtin function call.  */
! 
! static tree
! simplify_builtin_strcspn (arglist)
       tree arglist;
  {
    if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      return 0;
*************** expand_builtin_strcspn (arglist, target,
*** 3120,3126 ****
        if (p1 && p2)
  	{
  	  const size_t r = strcspn (p1, p2);
! 	  return expand_expr (size_int (r), target, mode, EXPAND_NORMAL);
  	}
  
        /* If the first argument is "", return 0.  */
--- 3327,3333 ----
        if (p1 && p2)
  	{
  	  const size_t r = strcspn (p1, p2);
! 	  return size_int (r);
  	}
  
        /* If the first argument is "", return 0.  */
*************** expand_builtin_strcspn (arglist, target,
*** 3128,3135 ****
  	{
  	  /* Evaluate and ignore argument s2 in case it has
  	     side-effects.  */
! 	  expand_expr (s2, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 	  return const0_rtx;
  	}
  
        /* If the second argument is "", return __builtin_strlen(s1).  */
--- 3335,3342 ----
  	{
  	  /* Evaluate and ignore argument s2 in case it has
  	     side-effects.  */
! 	  return build (COMPOUND_EXPR, void_type_node,
! 			s2, integer_zero_node);
  	}
  
        /* If the second argument is "", return __builtin_strlen(s1).  */
*************** expand_builtin_strcspn (arglist, target,
*** 3143,3150 ****
  	  if (!fn)
  	    return 0;
  
! 	  return expand_expr (build_function_call_expr (fn, newarglist),
! 			      target, mode, EXPAND_NORMAL);
  	}
        return 0;
      }
--- 3350,3356 ----
  	  if (!fn)
  	    return 0;
  
! 	  return build_function_call_expr (fn, newarglist);
  	}
        return 0;
      }
*************** expand_builtin_unop (arglist, target, su
*** 3740,3750 ****
    return target;
  }
  
! /* If the string passed to fputs is a constant and is one character
!    long, we attempt to transform this call into __builtin_fputc().  */
  
! static rtx
! expand_builtin_fputs (arglist, ignore, unlocked)
       tree arglist;
       int ignore;
       int unlocked;
--- 3946,3970 ----
    return target;
  }
  
! /* Simplify a call to the fputs builtin.
  
!    Return 0 if no simplification was possible, otherwise return the
!    simplified form of the call as a tree.
! 
!    The simplified form may be a constant or other expression which
!    computes the same value, but in a more efficient manner (including
!    calls to other builtin functions).
! 
!    The call may contain arguments which need to be evaluated, but
!    which are not useful to determine the result of the call.  In
!    this case we return a chain of COMPOUND_EXPRs.  The LHS of each
!    COMPOUND_EXPR will be an argument which must be evaluated.
!    COMPOUND_EXPRs are chained through their RHS.  The RHS of the last
!    COMPOUND_EXPR in the chain will contain the tree for the simplified
!    form of the builtin function call.  */
! 
! static tree
! simplify_builtin_fputs (arglist, ignore, unlocked)
       tree arglist;
       int ignore;
       int unlocked;
*************** expand_builtin_fputs (arglist, ignore, u
*** 3774,3784 ****
      {
      case -1: /* length is 0, delete the call entirely .  */
        {
! 	/* Evaluate and ignore the argument in case it has
!            side-effects.  */
! 	expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), const0_rtx,
! 		     VOIDmode, EXPAND_NORMAL);
! 	return const0_rtx;
        }
      case 0: /* length is 1, call fputc.  */
        {
--- 3994,4001 ----
      {
      case -1: /* length is 0, delete the call entirely .  */
        {
! 	return build (COMPOUND_EXPR, void_type_node,
! 		      TREE_VALUE (TREE_CHAIN (arglist)), integer_zero_node);
        }
      case 0: /* length is 1, call fputc.  */
        {
*************** expand_builtin_fputs (arglist, ignore, u
*** 3814,3822 ****
        abort ();
      }
  
!   return expand_expr (build_function_call_expr (fn, arglist),
! 		      (ignore ? const0_rtx : NULL_RTX),
! 		      VOIDmode, EXPAND_NORMAL);
  }
  
  /* Expand a call to __builtin_expect.  We return our argument and emit a
--- 4031,4037 ----
        abort ();
      }
  
!   return build_function_call_expr (fn, arglist);
  }
  
  /* Expand a call to __builtin_expect.  We return our argument and emit a
*************** expand_builtin_trap ()
*** 4000,4005 ****
--- 4215,4280 ----
    emit_barrier ();
  }
  
+ /* Front-end to the simplify_builtin_XXX routines.
+ 
+    EXP is a call to a builtin function.  If possible try to simplify
+    that into a constant, expression or call to a more efficient
+    builtin function.
+ 
+    If IGNORE is nonzero, then the result of this builtin function
+    call is ignored.
+ 
+    If simplification is possible, return the simplified tree, otherwise
+    return NULL_TREE.  */
+ 
+ tree
+ simplify_builtin (exp, ignore)
+      tree exp;
+      int ignore;
+ {
+   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+   tree arglist = TREE_OPERAND (exp, 1);
+   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+   switch (fcode)
+     {
+     case BUILT_IN_FPUTS:
+       return simplify_builtin_fputs (arglist, ignore, 0);
+     case BUILT_IN_FPUTS_UNLOCKED:
+       return simplify_builtin_fputs (arglist, ignore, 1);
+     case BUILT_IN_STRSTR:
+       return simplify_builtin_strstr (arglist);
+     case BUILT_IN_STRCAT:
+       return simplify_builtin_strcat (arglist);
+     case BUILT_IN_STRNCAT:
+       return simplify_builtin_strncat (arglist);
+     case BUILT_IN_STRSPN:
+       return simplify_builtin_strspn (arglist);
+     case BUILT_IN_STRCSPN:
+       return simplify_builtin_strcspn (arglist);
+     case BUILT_IN_STRCHR:
+     case BUILT_IN_INDEX:
+       return simplify_builtin_strchr (arglist);
+     case BUILT_IN_STRRCHR:
+     case BUILT_IN_RINDEX:
+       return simplify_builtin_strrchr (arglist);
+     case BUILT_IN_STRCPY:
+       return simplify_builtin_strcpy (arglist);
+     case BUILT_IN_STRNCPY:
+       return simplify_builtin_strncpy (arglist);
+     case BUILT_IN_STRCMP:
+       return simplify_builtin_strcmp (arglist);
+     case BUILT_IN_STRNCMP:
+       return simplify_builtin_strncmp (arglist);
+     case BUILT_IN_STRPBRK:
+       return simplify_builtin_strpbrk (arglist);
+     case BUILT_IN_BCMP:
+     case BUILT_IN_MEMCMP:
+       return simplify_builtin_memcmp (arglist);
+     default:
+       return NULL_TREE;
+     }
+ }
+ 
  /* Expand an expression EXP that calls a built-in function,
     with result going to TARGET if that's convenient
     (and in mode MODE if that's convenient).
*************** expand_builtin (exp, target, subtarget, 
*** 4304,4370 ****
  	return target;
        break;
  
-     case BUILT_IN_STRCPY:
-       target = expand_builtin_strcpy (exp, target, mode);
-       if (target)
- 	return target;
-       break;
- 
      case BUILT_IN_STRNCPY:
        target = expand_builtin_strncpy (arglist, target, mode);
        if (target)
  	return target;
        break;
  
-     case BUILT_IN_STRCAT:
-       target = expand_builtin_strcat (arglist, target, mode);
-       if (target)
- 	return target;
-       break;
- 
-     case BUILT_IN_STRNCAT:
-       target = expand_builtin_strncat (arglist, target, mode);
-       if (target)
- 	return target;
-       break;
  
      case BUILT_IN_STRSPN:
-       target = expand_builtin_strspn (arglist, target, mode);
-       if (target)
- 	return target;
-       break;
- 
      case BUILT_IN_STRCSPN:
!       target = expand_builtin_strcspn (arglist, target, mode);
!       if (target)
! 	return target;
!       break;
! 
      case BUILT_IN_STRSTR:
-       target = expand_builtin_strstr (arglist, target, mode);
-       if (target)
- 	return target;
-       break;
- 
-     case BUILT_IN_STRPBRK:
-       target = expand_builtin_strpbrk (arglist, target, mode);
-       if (target)
- 	return target;
-       break;
- 
      case BUILT_IN_INDEX:
      case BUILT_IN_STRCHR:
-       target = expand_builtin_strchr (arglist, target, mode);
-       if (target)
- 	return target;
-       break;
- 
-     case BUILT_IN_RINDEX:
      case BUILT_IN_STRRCHR:
!       target = expand_builtin_strrchr (arglist, target, mode);
!       if (target)
! 	return target;
!       break;
  
      case BUILT_IN_MEMCPY:
        target = expand_builtin_memcpy (arglist, target, mode);
--- 4579,4628 ----
  	return target;
        break;
  
      case BUILT_IN_STRNCPY:
        target = expand_builtin_strncpy (arglist, target, mode);
        if (target)
  	return target;
        break;
  
  
      case BUILT_IN_STRSPN:
      case BUILT_IN_STRCSPN:
!     case BUILT_IN_STRCAT:
!     case BUILT_IN_STRNCAT:
      case BUILT_IN_STRSTR:
      case BUILT_IN_INDEX:
      case BUILT_IN_STRCHR:
      case BUILT_IN_STRRCHR:
!     case BUILT_IN_RINDEX:
!     case BUILT_IN_STRCPY:
!     case BUILT_IN_STRNCMP:
!     case BUILT_IN_STRPBRK:
!     case BUILT_IN_FPUTS:
!     case BUILT_IN_FPUTS_UNLOCKED:
!     case BUILT_IN_STRCMP:
!       {
! 	tree new;
! 	new = simplify_builtin (exp, ignore);
! 	if (new)
! 	  {
! 	    /* First deal with any arguments which need to be expanded
! 	       merely to deal with any side effects they may have.  */
! 	    while (TREE_CODE (new) == COMPOUND_EXPR)
! 	      {
! 		expand_expr (TREE_OPERAND (new, 0), const0_rtx,
! 			     VOIDmode, EXPAND_NORMAL);
! 		new = TREE_OPERAND (new, 1);
! 	      }
! 
! 	    /* At this point NEW contains either the result of the
! 	       builtin call (if it was a compile-time constant) or
! 	       a new CALL_EXPR to another builtin function.  Expand
! 	       it and return the RTX for the result.  */
! 	    return expand_expr (new, target, mode, EXPAND_NORMAL);
! 	  }
! 	break;
!       }
  
      case BUILT_IN_MEMCPY:
        target = expand_builtin_memcpy (arglist, target, mode);
*************** expand_builtin (exp, target, subtarget, 
*** 4384,4401 ****
  	return target;
        break;
  
-     case BUILT_IN_STRCMP:
-       target = expand_builtin_strcmp (exp, target, mode);
-       if (target)
- 	return target;
-       break;
- 
-     case BUILT_IN_STRNCMP:
-       target = expand_builtin_strncmp (exp, target, mode);
-       if (target)
- 	return target;
-       break;
- 
      case BUILT_IN_BCMP:
      case BUILT_IN_MEMCMP:
        target = expand_builtin_memcmp (exp, arglist, target, mode);
--- 4642,4647 ----
*************** expand_builtin (exp, target, subtarget, 
*** 4435,4451 ****
      case BUILT_IN_TRAP:
        expand_builtin_trap ();
        return const0_rtx;
- 
-     case BUILT_IN_FPUTS:
-       target = expand_builtin_fputs (arglist, ignore,/*unlocked=*/ 0);
-       if (target)
- 	return target;
-       break;
-     case BUILT_IN_FPUTS_UNLOCKED:
-       target = expand_builtin_fputs (arglist, ignore,/*unlocked=*/ 1);
-       if (target)
- 	return target;
-       break;
  
        /* Various hooks for the DWARF 2 __throw routine.  */
      case BUILT_IN_UNWIND_INIT:
--- 4681,4686 ----
Index: gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/gimplify.c,v
retrieving revision 1.1.2.28
diff -c -3 -p -r1.1.2.28 gimplify.c
*** gimplify.c	10 Mar 2003 20:18:40 -0000	1.1.2.28
--- gimplify.c	12 Mar 2003 22:41:06 -0000
*************** static void simplify_array_ref       PAR
*** 43,49 ****
  static void simplify_array_ref_to_plus   PARAMS ((tree *, tree *, tree *));
  static void simplify_compound_lval   PARAMS ((tree *, tree *, tree *));
  static void simplify_component_ref   PARAMS ((tree *, tree *, tree *));
! static void simplify_call_expr       PARAMS ((tree *, tree *, tree *));
  static void simplify_tree_list       PARAMS ((tree *, tree *, tree *));
  static void simplify_modify_expr     PARAMS ((tree *, tree *, tree *, int));
  static void simplify_compound_expr   PARAMS ((tree *, tree *));
--- 43,50 ----
  static void simplify_array_ref_to_plus   PARAMS ((tree *, tree *, tree *));
  static void simplify_compound_lval   PARAMS ((tree *, tree *, tree *));
  static void simplify_component_ref   PARAMS ((tree *, tree *, tree *));
! static void simplify_call_expr       PARAMS ((tree *, tree *, tree *,
! 					      int (*) PARAMS ((tree))));
  static void simplify_tree_list       PARAMS ((tree *, tree *, tree *));
  static void simplify_modify_expr     PARAMS ((tree *, tree *, tree *, int));
  static void simplify_compound_expr   PARAMS ((tree *, tree *));
*************** simplify_expr (expr_p, pre_p, post_p, si
*** 370,376 ****
  	  break;
  
  	case CALL_EXPR:
! 	  simplify_call_expr (expr_p, pre_p, post_p);
  	  break;
  
  	case TREE_LIST:
--- 371,377 ----
  	  break;
  
  	case CALL_EXPR:
! 	  simplify_call_expr (expr_p, pre_p, post_p, simple_test_f);
  	  break;
  
  	case TREE_LIST:
*************** simplify_component_ref (expr_p, pre_p, p
*** 1224,1234 ****
      	*EXPR_P should be stored.  */
  
  static void
! simplify_call_expr (expr_p, pre_p, post_p)
       tree *expr_p;
       tree *pre_p;
       tree *post_p;
  {
  #if defined ENABLE_CHECKING
    if (TREE_CODE (*expr_p) != CALL_EXPR)
      abort ();
--- 1225,1237 ----
      	*EXPR_P should be stored.  */
  
  static void
! simplify_call_expr (expr_p, pre_p, post_p, simple_test_f)
       tree *expr_p;
       tree *pre_p;
       tree *post_p;
+      int (*simple_test_f) PARAMS ((tree));
  {
+   tree decl;
  #if defined ENABLE_CHECKING
    if (TREE_CODE (*expr_p) != CALL_EXPR)
      abort ();
*************** simplify_call_expr (expr_p, pre_p, post_
*** 1243,1252 ****
        return;
      }
  
!   simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, is_simple_id,
!                  fb_rvalue);
!   simplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p, is_simple_arglist,
!                  fb_rvalue);
  }
  
  /*  Simplify the TREE_LIST node pointed by EXPR_P.
--- 1246,1305 ----
        return;
      }
  
!   /* This may be a call to a builtin function.
! 
!      Builtin funtion calls may be transformed into different
!      (and more efficient) builtin function calls under certain
!      circumstances.  Unfortunately, gimplification can muck things
!      up enough that the builtin expanders are not aware that certain
!      transformations are still valid.
! 
!      So we attempt transformation/simplification of the call before
!      we gimplify the CALL_EXPR.  At this time we do not manage to
!      transform all calls in the same manner as the expanders do, but
!      we do transform most of them.  */
!   decl = get_callee_fndecl (*expr_p);
!   if (decl && DECL_BUILT_IN (decl))
!     {
!       tree new = simplify_builtin (*expr_p, simple_test_f == is_simple_stmt);
! 
!       if (new)
!         {
! 	  /* There was a transformation of this call which computes the
! 	     same value, but in a more efficient way.
! 
! 	     There may be arguments to the original function call which
! 	     must be evaluated to catch their side effects.  They will
! 	     appear on the LHS of any COMPOUND_EXPRs from simplify_builtin.  */
! 	  while (TREE_CODE (new) == COMPOUND_EXPR)
! 	    {
! 	      /* Expand an argument and add it to the pre-queue.  */
! 	      simplify_expr (&TREE_OPERAND (new, 0), pre_p, post_p,
! 			     is_simple_rhs, fb_rvalue);
! 	      add_tree (TREE_OPERAND (new, 0), pre_p);
! 	      new = TREE_OPERAND (new, 1);
! 	    }
! 
! 	  /* NEW now contains the transformed builtin call.  It may be
! 	     another call or an arbitrary expression.  If it was not
! 	     a call, then we do a recursive simplification on the
! 	     expression as a whole.  */
!           if (new && TREE_CODE (new) != CALL_EXPR)
!             {
! 	      simplify_expr (&new, pre_p, post_p, is_simple_rhs, fb_rvalue);
! 	      *expr_p = new;      	
! 	      return;
! 	    }
! 
! 	  /* NEW is another CALL_EXPR.  Fall through.  */
! 	  *expr_p = new;      	
! 	}
!     }
! 
!   simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 		 is_simple_id, fb_rvalue);
!   simplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
! 		 is_simple_arglist, fb_rvalue);
  }
  
  /*  Simplify the TREE_LIST node pointed by EXPR_P.
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.52
diff -c -3 -p -r1.342.2.52 tree.h
*** tree.h	10 Mar 2003 20:18:41 -0000	1.342.2.52
--- tree.h	12 Mar 2003 22:41:23 -0000
*************** extern enum built_in_function builtin_ma
*** 3247,3252 ****
--- 3247,3253 ----
  extern tree build_function_call_expr			PARAMS ((tree, tree));
  extern tree mathfn_built_in				PARAMS ((tree, enum built_in_function fn));
  extern tree strip_float_extensions			PARAMS ((tree));
+ extern tree simplify_builtin				PARAMS ((tree, int));
  
  /* In convert.c */
  extern tree strip_float_extensions			PARAMS ((tree));



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