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]

[LTO] builtins.c CALL_EXPR hacks, take 3


I think I have fixed all the formatting and other issues that Roger pointed out. I also made some global changes throughout the file to expand comments and fix the 0 vs NULL_RTX and NULL_TREE usage issue.

OK to check in now?

BTW, I don't think any of the next few hunks of code I convert are going to involve patches quite as massive as this one. :-P

-Sandra

2006-06-30  Sandra Loosemore  <sandra@codesourcery.com>

	* gcc/tree.c (init_call_expr_arg_iterator): Define.
	(first_call_expr_arg): Define.
	(next_call_expr_arg): Define.
	(more_call_expr_args_p): Define.
	(call_expr_nargs): Define.
	(call_expr_arg): Define.
	* gcc/tree.h (CALL_EXPR_FN, CALL_EXPR_STATIC_CHAIN, CALL_EXPR_ARGS):
	Define.
	(CALL_EXPR_ARG0, CALL_EXPR_ARG1, CALL_EXPR_ARG2): Define.
	(call_expr_arg_iterator): Declare.
	(init_call_expr_arg_iterator): Declare.
	(first_call_expr_arg): Declare.
	(next_call_expr_arg): Declare.
	(more_call_expr_args_p): Declare.
	(call_expr_nargs): Declare.
	(call_expr_arg): Declare.
	(fold_call_expr): Declare new function replacing fold_builtin.
	(fold_builtin_next_arg): Add bool argument.
	(fold_build_call_expr): Declare.
	(build_call_expr): Declare.
	* gcc/builtins.c: Doc fixes throughout.  Clean up to use NULL_RTX
	or NULL_TREE instead of constant 0 where appropriate.
	(expand_builtin_setjmp): Change interfaces to all the
	expand_builtin_foo functions pass the whole CALL_EXPR instead
	of just its arglist, while the fold_builtin_foo functions get the
	individual arguments instead.  Use the new argument accessors.
	Update all callers.  
	(expand_builtin_nonlocal_goto): Likewise.
	(expand_builtin_prefetch): Likewise.
	(expand_builtin_classify_type): Likewise.
	(expand_errno_check): Likewise.
	(expand_builtin_mathfn): Likewise.
	(expand_builtin_mathfn_2): Likewise.
	(expand_builtin_mathfn_3): Likewise.
	(expand_builtin_sincos): Likewise.
	(expand_builtin_int_roundingfn): Likewise.
	(expand_builtin_pow): Likewise.
	(expand_builtin_powi): Likewise.
	(expand_builtin_strstr): Likewise.
	(expand_builtin_strchr): Likewise.
	(expand_builtin_strrchr): Likewise.
	(expand_builtin_strpbrk): Likewise.
	(expand_builtin_memcpy): Likewise.
	(expand_builtin_mempcpy): Likewise.
	(expand_builtin_memmove): Likewise, plus split off new helper 
	function expand_builtin_memmove_args.
	(expand_builtin_bcopy): Likewise.
	(expand_builtin_strcpy): Likewise, plus split off new helper
	function expand_builtin_strcpy_args.
	(expand_builtin_stpcpy): Likewise.
	(expand_builtin_strncpy): Likewise.
	(expand_builtin_memset): Likewise, plus split off new helper
	function expand_builtin_memset_args.
	(expand_builtin_bzero): Likewise.
	(expand_builtin_memcmp): Likewise.
	(expand_builtin_strcmp): Likewise.
	(expand_builtin_strncmp): Likewise.
	(expand_builtin_strcat): Likewise.
	(expand_builtin_strncat): Likewise.
	(expand_builtin_strspn): Likewise.
	(expand_builtin_strcspn): Likewise.
	(expand_builtin_args_info): Likewise.
	(expand_builtin_va_start): Likewise.
	(expand_builtin_va_end): Likewise.
	(expand_builtin_va_copy): Likewise.
	(expand_builtin_frame_address): Likewise.
	(expand_builtin_alloca): Likewise.
	(expand_builtin_unop): Likewise.
	(expand_builtin_fputs): Likewise.
	(expand_builtin_expect): Likewise.
	(expand_builtin_expect_jump): Likewise.
	(expand_builtin_fabs): Likewise.
	(expand_builtin_copysign): Likewise.
	(expand_builtin_printf): Likewise.
	(expand_builtin_fprintf): Likewise.
	(expand_builtin_sprintf): Likewise.
	(expand_builtin_init_trampoline): Likewise.
	(expand_builtin_adjust_trampoline): Likewise.
	(expand_builtin_signbit): Likewise.
	(expand_builtin_fork_or_exec): Likewise.
	(expand_builtin_sync_operation): Likewise.
	(expand_builtin_compare_and_swap): Likewise.
	(expand_builtin_lock_test_and_set): Likewise.
	(expand_builtin_lock_release): Likewise.
	(expand_builtin): Likewise.
	(builtin_mathfn_code): Likewise.
	(fold_builtin_constant_p): Likewise.
	(fold_builtin_expect): Likewise.
	(fold_builtin_classify_type): Likewise.
	(fold_builtin_strlen): Likewise.
	(fold_builtin_nan): Likewise.
	(fold_trunc_transparent_mathfn): Likewise.
	(fold_fixed_mathfn): Likewise.
	(fold_builtin_cabs): Likewise.
	(fold_builtin_sqrt): Likewise.
	(fold_builtin_cbrt): Likewise.
	(fold_builtin_sin): Likewise.
	(fold_builtin_cos): Likewise.
	(fold_builtin_tan): Likewise.
	(fold_builtin_atan): Likewise.
	(fold_builtin_trunc): Likewise.
	(fold_builtin_floor): Likewise.
	(fold_builtin_ceil): Likewise.
	(fold_builtin_round): Likewise.
	(fold_builtin_int_roundingfn): Likewise.
	(fold_builtin_bitop): Likewise.
	(fold_builtin_logarithm): Likewise.
	(fold_builtin_pow): Likewise.
	(fold_builtin_powi): Likewise.
	(fold_builtin_exponent): Likewise.
	(fold_builtin_memcpy): Likewise.
	(fold_builtin_mempcpy): Likewise.
	(fold_builtin_memmove): Likewise.
	(fold_builtin_strcpy): Likewise.
	(fold_builtin_strncpy): Likewise.
	(fold_builtin_memcmp): Likewise.
	(fold_builtin_strcmp): Likewise.
	(fold_builtin_strncmp): Likewise.
	(fold_builtin_signbit): Likewise.
	(fold_builtin_copysign): Likewise.
	(fold_builtin_isascii): Likewise.
	(fold_builtin_toascii): Likewise.
	(fold_builtin_isdigit): Likewise.
	(fold_builtin_fabs): Likewise.
	(fold_builtin_abs): Likewise.
	(fold_builtin_classify): Likewise.
	(fold_builtin_unordered_cmp): Likewise.
	(fold_builtin_1): Likewise.  Split into new functions
	fold_builtin_n, fold_builtin_0, fold_builtin_1, fold_builtin_2,
	fold_builtin_3, fold_builtin_4, and fold_builtin_varargs, to dispatch
	based on the number of arguments.
	(fold_call_expr): New function replacing fold_builtin.
	(fold_build_call_expr): New function.
	(build_call_expr): New function.
	(rewrite_call_expr): New function.
	(validate_arg): New function.
	(validate_arglist): Rewrite to use new interfaces, as above.  Change
	return type from int to bool to reflect usage.
	(fold_builtin_strstr): Likewise.
	(fold_builtin_strchr): Likewise.
	(fold_builtin_strrchr): Likewise.
	(fold_builtin_strpbrk): Likewise.
	(fold_builtin_strcat): Likewise.
	(fold_builtin_strncat): Likewise.
	(fold_builtin_strspn): Likewise.
	(fold_builtin_strcspn): Likewise.
	(fold_builtin_fputs): Likewise.
	(fold_builtin_next_arg): Likewise.  Also fix destructive
	modification of argument list, which seems like a Bad Idea.
	(fold_builtin_sprintf): Likewise.
	(expand_builtin_object_size): Likewise.
	(expand_builtin_memory_chk): Likewise.
	(maybe_emit_chk_warning): Likewise.
	(maybe_emit_sprintf_chk_warning): Likewise.
	(fold_builtin_object_size): Likewise.
	(fold_builtin_memory_chk): Likewise.
	(fold_builtin_stxcpy_chk): Likewise.
	(fold_builtin_strncpy_chk): Likewise.
	(fold_builtin_strcat_chk): Likewise.
	(fold_builtin_strncat_chk): Likewise.
	(fold_builtin_sprintf_chk): Likewise.
	(fold_builtin_snprintf_chk): Likewise.
	(fold_builtin_printf): Likewise.
	(fold_builtin_fprintf): Likewise.
	* gcc/fold-const.c (fold_ternary): Remove call to fold_builtin....
	(fold): ...and replace it with a call to fold_call_expr here.
	(fold_build3_stat): Use fold_build_call_expr to fold and construct
	CALL_EXPRs.
	* gcc/tree-ssa-ccp.c (ccp_fold): Use new arglist primitives and
	update calls to the various fold_builtin_foo functions to reflect
	their new interfaces.
	(ccp_fold_builtin): Likewise.
	* gcc/gimplify.c (gimplify_call_expr): Likewise.
	* gcc/except.c (expand_builtin_eh_return_data_regno): Change
	arguments to match other expand_builtin_foo functions.
	* gcc/tree-object-size.c (compute_object_sizes): Replace call to
	fold_builtin with fold_call_expr.
Index: gcc/tree.c
===================================================================
*** gcc/tree.c	(revision 115087)
--- gcc/tree.c	(working copy)
*************** stdarg_p (tree fntype)
*** 7603,7606 ****
--- 7603,7681 ----
  	      != void_type_node));
  }
  
+ /* Initialize the abstract argument list iterator object ITER with the argument
+    list from CALL_EXPR node EXP.  */
+ 
+ void
+ init_call_expr_arg_iterator (tree exp, call_expr_arg_iterator *iter)
+ {
+   iter->tail =  CALL_EXPR_ARGS (exp);
+ }
+ 
+ /* Initialize the abstract argument list iterator object ITER, then advance
+    past and return the first argument.  Useful in for expressions, e.g.
+      for (arg = first_call_expr_arg (exp, &iter); arg;
+           arg = next_call_expr_arg (&iter))   */
+ 
+ tree
+ first_call_expr_arg (tree exp, call_expr_arg_iterator *iter)
+ {
+   init_call_expr_arg_iterator (exp, iter);
+   return next_call_expr_arg (iter);
+ }
+ 
+ /* Return the next argument from abstract argument list iterator object ITER,
+    and advance its state.  Return NULL_TREE if there are no more arguments.  */
+ 
+ tree
+ next_call_expr_arg (call_expr_arg_iterator *iter)
+ {
+   tree result;
+   if (iter->tail == NULL_TREE)
+     return NULL_TREE;
+   result = TREE_VALUE (iter->tail);
+   iter->tail = TREE_CHAIN (iter->tail);
+   return result;
+ }
+ 
+ /* Test whether there are more arguments in abstract argument list iterator
+    ITER, without changing its state.  */
+ 
+ bool
+ more_call_expr_args_p (const call_expr_arg_iterator *iter)
+ {
+   return (iter->tail != NULL_TREE);
+ }
+ 
+ /* Count the number of arguments passed in CALL_EXPR node EXP.  */
+ 
+ int
+ call_expr_nargs (tree exp)
+ {
+   call_expr_arg_iterator iter;
+   int i = 0;
+   tree arg;
+   for (arg = first_call_expr_arg (exp, &iter); arg;
+        arg = next_call_expr_arg (&iter))
+     i++;
+   return i;
+ }
+ 
+ /* Return the Nth (zero-based) argument from CALL_EXPR node EXP.  Returns
+    NULL if there aren't that many arguments.  */
+ 
+ tree
+ call_expr_arg (tree exp, int n)
+ {
+   call_expr_arg_iterator iter;
+   tree t = NULL;
+   int i;
+   for (i = 0, t = first_call_expr_arg (exp, &iter);
+        (i < n) && t;
+        i++, t = next_call_expr_arg (&iter))
+     ;
+   return t;
+ }
+ 
+ 
  #include "gt-tree.h"
Index: gcc/tree.h
===================================================================
*** gcc/tree.h	(revision 115087)
--- gcc/tree.h	(working copy)
*************** struct tree_constructor GTY(())
*** 1533,1538 ****
--- 1533,1553 ----
  #define ASSERT_EXPR_VAR(NODE)	TREE_OPERAND (ASSERT_EXPR_CHECK (NODE), 0)
  #define ASSERT_EXPR_COND(NODE)	TREE_OPERAND (ASSERT_EXPR_CHECK (NODE), 1)
  
+ /* CALL_EXPR accessors.  */
+ #define CALL_EXPR_FN(NODE) TREE_OPERAND_CHECK_CODE ((NODE), CALL_EXPR, 0)
+ #define CALL_EXPR_STATIC_CHAIN(NODE) TREE_OPERAND_CHECK_CODE ((NODE), CALL_EXPR, 2)
+ #define CALL_EXPR_ARGS(NODE) TREE_OPERAND_CHECK_CODE ((NODE), CALL_EXPR, 1)
+ #define CALL_EXPR_ARG0(NODE) TREE_VALUE (CALL_EXPR_ARGS (NODE))
+ #define CALL_EXPR_ARG1(NODE) TREE_VALUE (TREE_CHAIN (CALL_EXPR_ARGS (NODE)))
+ #define CALL_EXPR_ARG2(NODE) TREE_VALUE (TREE_CHAIN (TREE_CHAIN (CALL_EXPR_ARGS (NODE))))
+ 
+ 
+ typedef struct call_expr_arg_iterator_d GTY (())
+ {
+   tree tail;
+ } call_expr_arg_iterator;
+ 
+ 
  /* OpenMP directive and clause accessors.  */
  
  #define OMP_BODY(NODE) \
*************** extern tree lower_bound_in_type (tree, t
*** 4135,4140 ****
--- 4150,4162 ----
  extern int operand_equal_for_phi_arg_p (tree, tree);
  extern bool empty_body_p (tree);
  extern bool stdarg_p (tree);
+ extern void init_call_expr_arg_iterator (tree, call_expr_arg_iterator *);
+ extern tree first_call_expr_arg (tree, call_expr_arg_iterator *);
+ extern tree next_call_expr_arg (call_expr_arg_iterator *);
+ extern bool more_call_expr_args_p (const call_expr_arg_iterator *);
+ extern int call_expr_nargs (tree);
+ extern tree call_expr_arg (tree, int);
+ 
  
  /* In stmt.c */
  
*************** extern enum tree_code invert_tree_compar
*** 4241,4259 ****
  extern bool tree_expr_nonzero_p (tree);
  
  /* In builtins.c */
! extern tree fold_builtin (tree, tree, bool);
! extern tree fold_builtin_fputs (tree, bool, bool, tree);
! extern tree fold_builtin_strcpy (tree, tree, tree);
! extern tree fold_builtin_strncpy (tree, tree, tree);
! extern tree fold_builtin_memory_chk (tree, tree, tree, bool,
  				     enum built_in_function);
! extern tree fold_builtin_stxcpy_chk (tree, tree, tree, bool,
  				     enum built_in_function);
! extern tree fold_builtin_strncpy_chk (tree, tree);
  extern tree fold_builtin_snprintf_chk (tree, tree, enum built_in_function);
! extern bool fold_builtin_next_arg (tree);
  extern enum built_in_function builtin_mathfn_code (tree);
  extern tree build_function_call_expr (tree, tree);
  extern tree mathfn_built_in (tree, enum built_in_function fn);
  extern tree strip_float_extensions (tree);
  extern tree c_strlen (tree, int);
--- 4263,4283 ----
  extern bool tree_expr_nonzero_p (tree);
  
  /* In builtins.c */
! extern tree fold_call_expr (tree, bool);
! extern tree fold_builtin_fputs (tree, tree, bool, bool, tree);
! extern tree fold_builtin_strcpy (tree, tree, tree, tree);
! extern tree fold_builtin_strncpy (tree, tree, tree, tree, tree);
! extern tree fold_builtin_memory_chk (tree, tree, tree, tree, tree, tree, bool,
  				     enum built_in_function);
! extern tree fold_builtin_stxcpy_chk (tree, tree, tree, tree, tree, bool,
  				     enum built_in_function);
! extern tree fold_builtin_strncpy_chk (tree, tree, tree, tree, tree);
  extern tree fold_builtin_snprintf_chk (tree, tree, enum built_in_function);
! extern bool fold_builtin_next_arg (tree, bool);
  extern enum built_in_function builtin_mathfn_code (tree);
  extern tree build_function_call_expr (tree, tree);
+ extern tree fold_build_call_expr (tree, tree, tree, tree);
+ extern tree build_call_expr (tree, int, ...);
  extern tree mathfn_built_in (tree, enum built_in_function fn);
  extern tree strip_float_extensions (tree);
  extern tree c_strlen (tree, int);
Index: gcc/builtins.c
===================================================================
*** gcc/builtins.c	(revision 115087)
--- gcc/builtins.c	(working copy)
*************** static rtx expand_builtin_next_arg (void
*** 101,107 ****
  static rtx expand_builtin_va_start (tree);
  static rtx expand_builtin_va_end (tree);
  static rtx expand_builtin_va_copy (tree);
! static rtx expand_builtin_memcmp (tree, tree, rtx, enum machine_mode);
  static rtx expand_builtin_strcmp (tree, rtx, enum machine_mode);
  static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode);
  static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
--- 101,107 ----
  static rtx expand_builtin_va_start (tree);
  static rtx expand_builtin_va_end (tree);
  static rtx expand_builtin_va_copy (tree);
! static rtx expand_builtin_memcmp (tree, rtx, enum machine_mode);
  static rtx expand_builtin_strcmp (tree, rtx, enum machine_mode);
  static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode);
  static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
*************** static rtx expand_builtin_strncat (tree,
*** 110,131 ****
  static rtx expand_builtin_strspn (tree, rtx, enum machine_mode);
  static rtx expand_builtin_strcspn (tree, rtx, enum machine_mode);
  static rtx expand_builtin_memcpy (tree, rtx, enum machine_mode);
! static rtx expand_builtin_mempcpy (tree, tree, rtx, enum machine_mode, int);
! static rtx expand_builtin_memmove (tree, tree, rtx, enum machine_mode, tree);
  static rtx expand_builtin_bcopy (tree);
  static rtx expand_builtin_strcpy (tree, tree, rtx, enum machine_mode);
  static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode);
  static rtx builtin_strncpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
  static rtx expand_builtin_strncpy (tree, rtx, enum machine_mode);
  static rtx builtin_memset_read_str (void *, HOST_WIDE_INT, enum machine_mode);
  static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, enum machine_mode);
! static rtx expand_builtin_memset (tree, rtx, enum machine_mode, tree);
  static rtx expand_builtin_bzero (tree);
  static rtx expand_builtin_strlen (tree, rtx, enum machine_mode);
! static rtx expand_builtin_strstr (tree, tree, rtx, enum machine_mode);
! static rtx expand_builtin_strpbrk (tree, tree, rtx, enum machine_mode);
! static rtx expand_builtin_strchr (tree, tree, rtx, enum machine_mode);
! static rtx expand_builtin_strrchr (tree, tree, rtx, enum machine_mode);
  static rtx expand_builtin_alloca (tree, rtx);
  static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab);
  static rtx expand_builtin_frame_address (tree, tree);
--- 110,135 ----
  static rtx expand_builtin_strspn (tree, rtx, enum machine_mode);
  static rtx expand_builtin_strcspn (tree, rtx, enum machine_mode);
  static rtx expand_builtin_memcpy (tree, rtx, enum machine_mode);
! static rtx expand_builtin_mempcpy (tree, rtx, enum machine_mode);
! static rtx expand_builtin_mempcpy_args (tree, tree, tree, tree, rtx, enum machine_mode, int);
! static rtx expand_builtin_memmove (tree, rtx, enum machine_mode);
! static rtx expand_builtin_memmove_args (tree, tree, tree, tree, rtx, enum machine_mode, tree);
  static rtx expand_builtin_bcopy (tree);
  static rtx expand_builtin_strcpy (tree, tree, rtx, enum machine_mode);
+ static rtx expand_builtin_strcpy_args (tree, tree, tree, rtx, enum machine_mode);
  static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode);
  static rtx builtin_strncpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
  static rtx expand_builtin_strncpy (tree, rtx, enum machine_mode);
  static rtx builtin_memset_read_str (void *, HOST_WIDE_INT, enum machine_mode);
  static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, enum machine_mode);
! static rtx expand_builtin_memset (tree, rtx, enum machine_mode);
! static rtx expand_builtin_memset_args (tree, tree, tree, rtx, enum machine_mode, tree);
  static rtx expand_builtin_bzero (tree);
  static rtx expand_builtin_strlen (tree, rtx, enum machine_mode);
! static rtx expand_builtin_strstr (tree, rtx, enum machine_mode);
! static rtx expand_builtin_strpbrk (tree, rtx, enum machine_mode);
! static rtx expand_builtin_strchr (tree, rtx, enum machine_mode);
! static rtx expand_builtin_strrchr (tree, rtx, enum machine_mode);
  static rtx expand_builtin_alloca (tree, rtx);
  static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab);
  static rtx expand_builtin_frame_address (tree, tree);
*************** static rtx expand_builtin_sprintf (tree,
*** 136,146 ****
  static tree stabilize_va_list (tree, int);
  static rtx expand_builtin_expect (tree, rtx);
  static tree fold_builtin_constant_p (tree);
  static tree fold_builtin_classify_type (tree);
  static tree fold_builtin_strlen (tree);
  static tree fold_builtin_inf (tree, int);
  static tree fold_builtin_nan (tree, tree, int);
! static int validate_arglist (tree, ...);
  static bool integer_valued_real_p (tree);
  static tree fold_trunc_transparent_mathfn (tree, tree);
  static bool readonly_data_expr (tree);
--- 140,153 ----
  static tree stabilize_va_list (tree, int);
  static rtx expand_builtin_expect (tree, rtx);
  static tree fold_builtin_constant_p (tree);
+ static tree fold_builtin_expect (tree);
  static tree fold_builtin_classify_type (tree);
  static tree fold_builtin_strlen (tree);
  static tree fold_builtin_inf (tree, int);
  static tree fold_builtin_nan (tree, tree, int);
! static tree rewrite_call_expr (tree, int, tree, int, ...);
! static bool validate_arg (tree, enum tree_code code);
! static bool validate_arglist (tree, ...);
  static bool integer_valued_real_p (tree);
  static tree fold_trunc_transparent_mathfn (tree, tree);
  static bool readonly_data_expr (tree);
*************** static rtx expand_builtin_signbit (tree,
*** 149,156 ****
  static tree fold_builtin_cabs (tree, tree);
  static tree fold_builtin_sqrt (tree, tree);
  static tree fold_builtin_cbrt (tree, tree);
! static tree fold_builtin_pow (tree, tree, tree);
! static tree fold_builtin_powi (tree, tree, tree);
  static tree fold_builtin_sin (tree);
  static tree fold_builtin_cos (tree, tree, tree);
  static tree fold_builtin_tan (tree);
--- 156,163 ----
  static tree fold_builtin_cabs (tree, tree);
  static tree fold_builtin_sqrt (tree, tree);
  static tree fold_builtin_cbrt (tree, tree);
! static tree fold_builtin_pow (tree, tree, tree, tree);
! static tree fold_builtin_powi (tree, tree, tree, tree);
  static tree fold_builtin_sin (tree);
  static tree fold_builtin_cos (tree, tree, tree);
  static tree fold_builtin_tan (tree);
*************** static tree fold_builtin_ceil (tree, tre
*** 161,204 ****
  static tree fold_builtin_round (tree, tree);
  static tree fold_builtin_int_roundingfn (tree, tree);
  static tree fold_builtin_bitop (tree, tree);
! static tree fold_builtin_memcpy (tree, tree);
! static tree fold_builtin_mempcpy (tree, tree, int);
! static tree fold_builtin_memmove (tree, tree);
! static tree fold_builtin_strchr (tree, tree);
! static tree fold_builtin_memcmp (tree);
! static tree fold_builtin_strcmp (tree);
! static tree fold_builtin_strncmp (tree);
  static tree fold_builtin_signbit (tree, tree);
! static tree fold_builtin_copysign (tree, tree, tree);
  static tree fold_builtin_isascii (tree);
  static tree fold_builtin_toascii (tree);
  static tree fold_builtin_isdigit (tree);
  static tree fold_builtin_fabs (tree, tree);
  static tree fold_builtin_abs (tree, tree);
! static tree fold_builtin_unordered_cmp (tree, tree, enum tree_code,
  					enum tree_code);
  static tree fold_builtin_1 (tree, tree, bool);
! 
! static tree fold_builtin_strpbrk (tree, tree);
! static tree fold_builtin_strstr (tree, tree);
! static tree fold_builtin_strrchr (tree, tree);
! static tree fold_builtin_strcat (tree);
! static tree fold_builtin_strncat (tree);
! static tree fold_builtin_strspn (tree);
! static tree fold_builtin_strcspn (tree);
! static tree fold_builtin_sprintf (tree, int);
  
  static rtx expand_builtin_object_size (tree);
  static rtx expand_builtin_memory_chk (tree, rtx, enum machine_mode,
  				      enum built_in_function);
  static void maybe_emit_chk_warning (tree, enum built_in_function);
  static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function);
! static tree fold_builtin_object_size (tree);
! static tree fold_builtin_strcat_chk (tree, tree);
! static tree fold_builtin_strncat_chk (tree, tree);
  static tree fold_builtin_sprintf_chk (tree, enum built_in_function);
! static tree fold_builtin_printf (tree, tree, bool, enum built_in_function);
! static tree fold_builtin_fprintf (tree, tree, bool, enum built_in_function);
  static bool init_target_chars (void);
  
  static unsigned HOST_WIDE_INT target_newline;
--- 168,219 ----
  static tree fold_builtin_round (tree, tree);
  static tree fold_builtin_int_roundingfn (tree, tree);
  static tree fold_builtin_bitop (tree, tree);
! static tree fold_builtin_memcpy (tree, tree, tree, tree);
! static tree fold_builtin_mempcpy (tree, tree, tree, tree, int);
! static tree fold_builtin_memmove (tree, tree, tree, tree);
! static tree fold_builtin_strchr (tree, tree, tree);
! static tree fold_builtin_memcmp (tree, tree, tree);
! static tree fold_builtin_strcmp (tree, tree);
! static tree fold_builtin_strncmp (tree, tree, tree);
  static tree fold_builtin_signbit (tree, tree);
! static tree fold_builtin_copysign (tree, tree, tree, tree);
  static tree fold_builtin_isascii (tree);
  static tree fold_builtin_toascii (tree);
  static tree fold_builtin_isdigit (tree);
  static tree fold_builtin_fabs (tree, tree);
  static tree fold_builtin_abs (tree, tree);
! static tree fold_builtin_unordered_cmp (tree, tree, tree, enum tree_code,
  					enum tree_code);
+ static tree fold_builtin_n (tree, tree *, int, bool);
+ static tree fold_builtin_0 (tree, bool);
  static tree fold_builtin_1 (tree, tree, bool);
! static tree fold_builtin_2 (tree, tree, tree, bool);
! static tree fold_builtin_3 (tree, tree, tree, tree, bool);
! static tree fold_builtin_4 (tree, tree, tree, tree, tree, bool);
! static tree fold_builtin_varargs (tree, tree, bool);
! 
! static tree fold_builtin_strpbrk (tree, tree, tree);
! static tree fold_builtin_strstr (tree, tree, tree);
! static tree fold_builtin_strrchr (tree, tree, tree);
! static tree fold_builtin_strcat (tree, tree);
! static tree fold_builtin_strncat (tree, tree, tree);
! static tree fold_builtin_strspn (tree, tree);
! static tree fold_builtin_strcspn (tree, tree);
! static tree fold_builtin_sprintf (tree, tree, tree, int);
  
  static rtx expand_builtin_object_size (tree);
  static rtx expand_builtin_memory_chk (tree, rtx, enum machine_mode,
  				      enum built_in_function);
  static void maybe_emit_chk_warning (tree, enum built_in_function);
  static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function);
! static tree fold_builtin_object_size (tree, tree);
! static tree fold_builtin_strcat_chk (tree, tree, tree, tree);
! static tree fold_builtin_strncat_chk (tree, tree, tree, tree, tree);
  static tree fold_builtin_sprintf_chk (tree, enum built_in_function);
! static tree fold_builtin_printf (tree, tree, tree, bool,
! 				 enum built_in_function);
! static tree fold_builtin_fprintf (tree, tree, tree, tree, bool,
! 				  enum built_in_function);
  static bool init_target_chars (void);
  
  static unsigned HOST_WIDE_INT target_newline;
*************** c_strlen (tree src, int only_value)
*** 347,353 ****
  
    src = string_constant (src, &offset_node);
    if (src == 0)
!     return 0;
  
    max = TREE_STRING_LENGTH (src) - 1;
    ptr = TREE_STRING_POINTER (src);
--- 362,368 ----
  
    src = string_constant (src, &offset_node);
    if (src == 0)
!     return NULL_TREE;
  
    max = TREE_STRING_LENGTH (src) - 1;
    ptr = TREE_STRING_POINTER (src);
*************** c_strlen (tree src, int only_value)
*** 361,367 ****
  
        for (i = 0; i < max; i++)
  	if (ptr[i] == 0)
! 	  return 0;
  
        /* We don't know the starting offset, but we do know that the string
  	 has no internal zero bytes.  We can assume that the offset falls
--- 376,382 ----
  
        for (i = 0; i < max; i++)
  	if (ptr[i] == 0)
! 	  return NULL_TREE;
  
        /* We don't know the starting offset, but we do know that the string
  	 has no internal zero bytes.  We can assume that the offset falls
*************** c_strlen (tree src, int only_value)
*** 387,393 ****
    if (offset < 0 || offset > max)
      {
        warning (0, "offset outside bounds of constant string");
!       return 0;
      }
  
    /* Use strlen to search for the first zero byte.  Since any strings
--- 402,408 ----
    if (offset < 0 || offset > max)
      {
        warning (0, "offset outside bounds of constant string");
!       return NULL_TREE;
      }
  
    /* Use strlen to search for the first zero byte.  Since any strings
*************** expand_builtin_setjmp_receiver (rtx rece
*** 703,720 ****
     them.  */
  
  static rtx
! expand_builtin_setjmp (tree arglist, rtx target)
  {
    rtx buf_addr, next_lab, cont_lab;
  
!   if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
      return NULL_RTX;
  
    if (target == 0 || !REG_P (target)
        || REGNO (target) < FIRST_PSEUDO_REGISTER)
      target = gen_reg_rtx (TYPE_MODE (integer_type_node));
  
!   buf_addr = expand_normal (TREE_VALUE (arglist));
  
    next_lab = gen_label_rtx ();
    cont_lab = gen_label_rtx ();
--- 718,735 ----
     them.  */
  
  static rtx
! expand_builtin_setjmp (tree exp, rtx target)
  {
    rtx buf_addr, next_lab, cont_lab;
  
!   if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
      return NULL_RTX;
  
    if (target == 0 || !REG_P (target)
        || REGNO (target) < FIRST_PSEUDO_REGISTER)
      target = gen_reg_rtx (TYPE_MODE (integer_type_node));
  
!   buf_addr = expand_normal (CALL_EXPR_ARG0 (exp));
  
    next_lab = gen_label_rtx ();
    cont_lab = gen_label_rtx ();
*************** expand_builtin_longjmp (rtx buf_addr, rt
*** 844,860 ****
     and the address of the save area.  */
  
  static rtx
! expand_builtin_nonlocal_goto (tree arglist)
  {
    tree t_label, t_save_area;
    rtx r_label, r_save_area, r_fp, r_sp, insn;
  
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      return NULL_RTX;
  
!   t_label = TREE_VALUE (arglist);
!   arglist = TREE_CHAIN (arglist);
!   t_save_area = TREE_VALUE (arglist);
  
    r_label = expand_normal (t_label);
    r_label = convert_memory_address (Pmode, r_label);
--- 859,874 ----
     and the address of the save area.  */
  
  static rtx
! expand_builtin_nonlocal_goto (tree exp)
  {
    tree t_label, t_save_area;
    rtx r_label, r_save_area, r_fp, r_sp, insn;
  
!   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      return NULL_RTX;
  
!   t_label = CALL_EXPR_ARG0 (exp);
!   t_save_area = CALL_EXPR_ARG1 (exp);
  
    r_label = expand_normal (t_label);
    r_label = convert_memory_address (Pmode, r_label);
*************** expand_builtin_update_setjmp_buf (rtx bu
*** 954,984 ****
     effects.  */
  
  static void
! expand_builtin_prefetch (tree arglist)
  {
    tree arg0, arg1, arg2;
    rtx op0, op1, op2;
  
!   if (!validate_arglist (arglist, POINTER_TYPE, 0))
      return;
  
!   arg0 = TREE_VALUE (arglist);
    /* Arguments 1 and 2 are optional; argument 1 (read/write) defaults to
       zero (read) and argument 2 (locality) defaults to 3 (high degree of
       locality).  */
!   if (TREE_CHAIN (arglist))
!     {
!       arg1 = TREE_VALUE (TREE_CHAIN (arglist));
!       if (TREE_CHAIN (TREE_CHAIN (arglist)))
! 	arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
!       else
! 	arg2 = build_int_cst (NULL_TREE, 3);
!     }
    else
!     {
!       arg1 = integer_zero_node;
!       arg2 = build_int_cst (NULL_TREE, 3);
!     }
  
    /* Argument 0 is an address.  */
    op0 = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
--- 968,995 ----
     effects.  */
  
  static void
! expand_builtin_prefetch (tree exp)
  {
    tree arg0, arg1, arg2;
+   int nargs;
    rtx op0, op1, op2;
  
!   if (!validate_arglist (exp, POINTER_TYPE, 0))
      return;
  
!   arg0 = CALL_EXPR_ARG0 (exp);
    /* Arguments 1 and 2 are optional; argument 1 (read/write) defaults to
       zero (read) and argument 2 (locality) defaults to 3 (high degree of
       locality).  */
!   nargs = call_expr_nargs (exp);
!   if (nargs > 1)
!     arg1 = CALL_EXPR_ARG1 (exp);
!   else
!     arg1 = integer_zero_node;
!   if (nargs > 2)
!     arg2 = CALL_EXPR_ARG2 (exp);
    else
!     arg2 = build_int_cst (NULL_TREE, 3);
  
    /* Argument 0 is an address.  */
    op0 = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
*************** type_to_class (tree type)
*** 1618,1631 ****
      }
  }
  
! /* Expand a call to __builtin_classify_type with arguments found in
!    ARGLIST.  */
  
  static rtx
! expand_builtin_classify_type (tree arglist)
  {
!   if (arglist != 0)
!     return GEN_INT (type_to_class (TREE_TYPE (TREE_VALUE (arglist))));
    return GEN_INT (no_type_class);
  }
  
--- 1629,1641 ----
      }
  }
  
! /* Expand a call EXP to __builtin_classify_type.  */
  
  static rtx
! expand_builtin_classify_type (tree exp)
  {
!   if (call_expr_nargs (exp))
!     return GEN_INT (type_to_class (TREE_TYPE (CALL_EXPR_ARG0 (exp))));
    return GEN_INT (no_type_class);
  }
  
*************** mathfn_built_in (tree type, enum built_i
*** 1727,1733 ****
        CASE_MATHFN (BUILT_IN_YN)
  
        default:
! 	return 0;
        }
  
    if (TYPE_MAIN_VARIANT (type) == double_type_node)
--- 1737,1743 ----
        CASE_MATHFN (BUILT_IN_YN)
  
        default:
! 	return NULL_TREE;
        }
  
    if (TYPE_MAIN_VARIANT (type) == double_type_node)
*************** mathfn_built_in (tree type, enum built_i
*** 1737,1743 ****
    else if (TYPE_MAIN_VARIANT (type) == long_double_type_node)
      return implicit_built_in_decls[fcodel];
    else
!     return 0;
  }
  
  /* If errno must be maintained, expand the RTL to check if the result,
--- 1747,1753 ----
    else if (TYPE_MAIN_VARIANT (type) == long_double_type_node)
      return implicit_built_in_decls[fcodel];
    else
!     return NULL_TREE;
  }
  
  /* If errno must be maintained, expand the RTL to check if the result,
*************** expand_errno_check (tree exp, rtx target
*** 1756,1762 ****
  
  #ifdef TARGET_EDOM
    /* If this built-in doesn't throw an exception, set errno directly.  */
!   if (TREE_NOTHROW (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
      {
  #ifdef GEN_ERRNO_RTX
        rtx errno_rtx = GEN_ERRNO_RTX;
--- 1766,1772 ----
  
  #ifdef TARGET_EDOM
    /* If this built-in doesn't throw an exception, set errno directly.  */
!   if (TREE_NOTHROW (TREE_OPERAND (CALL_EXPR_FN (exp), 0)))
      {
  #ifdef GEN_ERRNO_RTX
        rtx errno_rtx = GEN_ERRNO_RTX;
*************** expand_errno_check (tree exp, rtx target
*** 1778,1787 ****
    emit_label (lab);
  }
  
- 
  /* Expand a call to one of the builtin math functions (sqrt, exp, or log).
!    Return 0 if a normal call should be emitted rather than expanding the
!    function in-line.  EXP is the expression that is a call to the builtin
     function; if convenient, the result should be placed in TARGET.
     SUBTARGET may be used as the target for computing one of EXP's operands.  */
  
--- 1788,1796 ----
    emit_label (lab);
  }
  
  /* Expand a call to one of the builtin math functions (sqrt, exp, or log).
!    Return NULL_RTX if a normal call should be emitted rather than expanding
!    the function in-line.  EXP is the expression that is a call to the builtin
     function; if convenient, the result should be placed in TARGET.
     SUBTARGET may be used as the target for computing one of EXP's operands.  */
  
*************** expand_builtin_mathfn (tree exp, rtx tar
*** 1791,1805 ****
    optab builtin_optab;
    rtx op0, insns, before_call;
    tree fndecl = get_callee_fndecl (exp);
-   tree arglist = TREE_OPERAND (exp, 1);
    enum machine_mode mode;
    bool errno_set = false;
    tree arg, narg;
  
!   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
!     return 0;
  
!   arg = TREE_VALUE (arglist);
  
    switch (DECL_FUNCTION_CODE (fndecl))
      {
--- 1800,1813 ----
    optab builtin_optab;
    rtx op0, insns, before_call;
    tree fndecl = get_callee_fndecl (exp);
    enum machine_mode mode;
    bool errno_set = false;
    tree arg, narg;
  
!   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
!     return NULL_RTX;
  
!   arg = CALL_EXPR_ARG0 (exp);
  
    switch (DECL_FUNCTION_CODE (fndecl))
      {
*************** expand_builtin_mathfn (tree exp, rtx tar
*** 1873,1880 ****
        if (narg != arg)
  	{
  	  arg = narg;
! 	  arglist = build_tree_list (NULL_TREE, arg);
! 	  exp = build_function_call_expr (fndecl, arglist);
  	}
  
        op0 = expand_expr (arg, subtarget, VOIDmode, 0);
--- 1881,1887 ----
        if (narg != arg)
  	{
  	  arg = narg;
! 	  exp = build_call_expr (fndecl, 1, arg);
  	}
  
        op0 = expand_expr (arg, subtarget, VOIDmode, 0);
*************** expand_builtin_mathfn (tree exp, rtx tar
*** 1950,1956 ****
  }
  
  /* Expand a call to the builtin binary math functions (pow and atan2).
!    Return 0 if a normal call should be emitted rather than expanding the
     function in-line.  EXP is the expression that is a call to the builtin
     function; if convenient, the result should be placed in TARGET.
     SUBTARGET may be used as the target for computing one of EXP's
--- 1957,1963 ----
  }
  
  /* Expand a call to the builtin binary math functions (pow and atan2).
!    Return NULL_RTX if a normal call should be emitted rather than expanding the
     function in-line.  EXP is the expression that is a call to the builtin
     function; if convenient, the result should be placed in TARGET.
     SUBTARGET may be used as the target for computing one of EXP's
*************** expand_builtin_mathfn_2 (tree exp, rtx t
*** 1963,1984 ****
    rtx op0, op1, insns;
    int op1_type = REAL_TYPE;
    tree fndecl = get_callee_fndecl (exp);
!   tree arglist = TREE_OPERAND (exp, 1);
!   tree arg0, arg1, temp, narg;
    enum machine_mode mode;
    bool errno_set = true;
    bool stable = true;
  
!   if ((DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LDEXP)
!       || (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LDEXPF)
!       || (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LDEXPL))
      op1_type = INTEGER_TYPE;
  
!   if (!validate_arglist (arglist, REAL_TYPE, op1_type, VOID_TYPE))
!     return 0;
  
!   arg0 = TREE_VALUE (arglist);
!   arg1 = TREE_VALUE (TREE_CHAIN (arglist));
  
    switch (DECL_FUNCTION_CODE (fndecl))
      {
--- 1970,1990 ----
    rtx op0, op1, insns;
    int op1_type = REAL_TYPE;
    tree fndecl = get_callee_fndecl (exp);
!   tree arg0, arg1, narg;
    enum machine_mode mode;
    bool errno_set = true;
    bool stable = true;
  
!   if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LDEXP
!       || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LDEXPF
!       || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_LDEXPL)
      op1_type = INTEGER_TYPE;
  
!   if (!validate_arglist (exp, REAL_TYPE, op1_type, VOID_TYPE))
!     return NULL_RTX;
  
!   arg0 = CALL_EXPR_ARG0 (exp);
!   arg1 = CALL_EXPR_ARG1 (exp);
  
    switch (DECL_FUNCTION_CODE (fndecl))
      {
*************** expand_builtin_mathfn_2 (tree exp, rtx t
*** 2001,2007 ****
  
    /* Before working hard, check whether the instruction is available.  */
    if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
!     return 0;
  
    target = gen_reg_rtx (mode);
  
--- 2007,2013 ----
  
    /* Before working hard, check whether the instruction is available.  */
    if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
!     return NULL_RTX;
  
    target = gen_reg_rtx (mode);
  
*************** expand_builtin_mathfn_2 (tree exp, rtx t
*** 2013,2036 ****
    if (narg != arg1)
      {
        arg1 = narg;
-       temp = build_tree_list (NULL_TREE, narg);
        stable = false;
      }
-   else
-     temp = TREE_CHAIN (arglist);
- 
    narg = builtin_save_expr (arg0);
    if (narg != arg0)
      {
        arg0 = narg;
-       arglist = tree_cons (NULL_TREE, narg, temp);
        stable = false;
      }
-   else if (! stable)
-     arglist = tree_cons (NULL_TREE, arg0, temp);
  
    if (! stable)
!     exp = build_function_call_expr (fndecl, arglist);
  
    op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
    op1 = expand_normal (arg1);
--- 2019,2035 ----
    if (narg != arg1)
      {
        arg1 = narg;
        stable = false;
      }
    narg = builtin_save_expr (arg0);
    if (narg != arg0)
      {
        arg0 = narg;
        stable = false;
      }
  
    if (! stable)
!     exp = build_call_expr (fndecl, 2, arg0, arg1);
  
    op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
    op1 = expand_normal (arg1);
*************** expand_builtin_mathfn_2 (tree exp, rtx t
*** 2063,2069 ****
  }
  
  /* Expand a call to the builtin sin and cos math functions.
!    Return 0 if a normal call should be emitted rather than expanding the
     function in-line.  EXP is the expression that is a call to the builtin
     function; if convenient, the result should be placed in TARGET.
     SUBTARGET may be used as the target for computing one of EXP's
--- 2062,2068 ----
  }
  
  /* Expand a call to the builtin sin and cos math functions.
!    Return NULL_RTX if a normal call should be emitted rather than expanding the
     function in-line.  EXP is the expression that is a call to the builtin
     function; if convenient, the result should be placed in TARGET.
     SUBTARGET may be used as the target for computing one of EXP's
*************** expand_builtin_mathfn_3 (tree exp, rtx t
*** 2075,2088 ****
    optab builtin_optab;
    rtx op0, insns;
    tree fndecl = get_callee_fndecl (exp);
-   tree arglist = TREE_OPERAND (exp, 1);
    enum machine_mode mode;
    tree arg, narg;
  
!   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
!     return 0;
  
!   arg = TREE_VALUE (arglist);
  
    switch (DECL_FUNCTION_CODE (fndecl))
      {
--- 2074,2086 ----
    optab builtin_optab;
    rtx op0, insns;
    tree fndecl = get_callee_fndecl (exp);
    enum machine_mode mode;
    tree arg, narg;
  
!   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
!     return NULL_RTX;
  
!   arg = CALL_EXPR_ARG0 (exp);
  
    switch (DECL_FUNCTION_CODE (fndecl))
      {
*************** expand_builtin_mathfn_3 (tree exp, rtx t
*** 2122,2129 ****
        if (narg != arg)
  	{
  	  arg = narg;
! 	  arglist = build_tree_list (NULL_TREE, arg);
! 	  exp = build_function_call_expr (fndecl, arglist);
  	}
  
        op0 = expand_expr (arg, subtarget, VOIDmode, 0);
--- 2120,2126 ----
        if (narg != arg)
  	{
  	  arg = narg;
! 	  exp = build_call_expr (fndecl, 1, arg);
  	}
  
        op0 = expand_expr (arg, subtarget, VOIDmode, 0);
*************** expand_builtin_mathfn_3 (tree exp, rtx t
*** 2175,2181 ****
  }
  
  /* Expand a call to the builtin sincos math function.
!    Return 0 if a normal call should be emitted rather than expanding the
     function in-line.  EXP is the expression that is a call to the builtin
     function.  */
  
--- 2172,2178 ----
  }
  
  /* Expand a call to the builtin sincos math function.
!    Return NULL_RTX if a normal call should be emitted rather than expanding the
     function in-line.  EXP is the expression that is a call to the builtin
     function.  */
  
*************** static rtx
*** 2183,2200 ****
  expand_builtin_sincos (tree exp)
  {
    rtx op0, op1, op2, target1, target2;
-   tree arglist = TREE_OPERAND (exp, 1);
    enum machine_mode mode;
    tree arg, sinp, cosp;
    int result;
  
!   if (!validate_arglist (arglist, REAL_TYPE,
  			 POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
!     return 0;
  
!   arg = TREE_VALUE (arglist);
!   sinp = TREE_VALUE (TREE_CHAIN (arglist));
!   cosp = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
  
    /* Make a suitable register to place result in.  */
    mode = TYPE_MODE (TREE_TYPE (arg));
--- 2180,2196 ----
  expand_builtin_sincos (tree exp)
  {
    rtx op0, op1, op2, target1, target2;
    enum machine_mode mode;
    tree arg, sinp, cosp;
    int result;
  
!   if (!validate_arglist (exp, REAL_TYPE,
  			 POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
!     return NULL_RTX;
  
!   arg = CALL_EXPR_ARG0 (exp);
!   sinp = CALL_EXPR_ARG1 (exp);
!   cosp = CALL_EXPR_ARG2 (exp);
  
    /* Make a suitable register to place result in.  */
    mode = TYPE_MODE (TREE_TYPE (arg));
*************** expand_builtin_int_roundingfn (tree exp,
*** 2235,2250 ****
    optab builtin_optab;
    rtx op0, insns, tmp;
    tree fndecl = get_callee_fndecl (exp);
-   tree arglist = TREE_OPERAND (exp, 1);
    enum built_in_function fallback_fn;
    tree fallback_fndecl;
    enum machine_mode mode;
    tree arg, narg;
  
!   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
      gcc_unreachable ();
  
!   arg = TREE_VALUE (arglist);
  
    switch (DECL_FUNCTION_CODE (fndecl))
      {
--- 2231,2245 ----
    optab builtin_optab;
    rtx op0, insns, tmp;
    tree fndecl = get_callee_fndecl (exp);
    enum built_in_function fallback_fn;
    tree fallback_fndecl;
    enum machine_mode mode;
    tree arg, narg;
  
!   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
      gcc_unreachable ();
  
!   arg = CALL_EXPR_ARG0 (exp);
  
    switch (DECL_FUNCTION_CODE (fndecl))
      {
*************** expand_builtin_int_roundingfn (tree exp,
*** 2279,2286 ****
        if (narg != arg)
  	{
  	  arg = narg;
! 	  arglist = build_tree_list (NULL_TREE, arg);
! 	  exp = build_function_call_expr (fndecl, arglist);
  	}
  
        op0 = expand_expr (arg, subtarget, VOIDmode, 0);
--- 2274,2280 ----
        if (narg != arg)
  	{
  	  arg = narg;
! 	  exp = build_call_expr (fndecl, 1, arg);
  	}
  
        op0 = expand_expr (arg, subtarget, VOIDmode, 0);
*************** expand_builtin_int_roundingfn (tree exp,
*** 2310,2316 ****
    /* We shouldn't get here on targets without TARGET_C99_FUNCTIONS.
       ??? Perhaps convert (int)floorf(x) into (int)floor((double)x).  */
    gcc_assert (fallback_fndecl != NULL_TREE);
!   exp = build_function_call_expr (fallback_fndecl, arglist);
  
    tmp = expand_normal (exp);
  
--- 2304,2310 ----
    /* We shouldn't get here on targets without TARGET_C99_FUNCTIONS.
       ??? Perhaps convert (int)floorf(x) into (int)floor((double)x).  */
    gcc_assert (fallback_fndecl != NULL_TREE);
!   exp = build_call_expr (fallback_fndecl, 1, arg);
  
    tmp = expand_normal (exp);
  
*************** expand_powi (rtx x, enum machine_mode mo
*** 2527,2533 ****
    return result;
  }
  
! /* Expand a call to the pow built-in mathematical function.  Return 0 if
     a normal call should be emitted rather than expanding the function
     in-line.  EXP is the expression that is a call to the builtin
     function; if convenient, the result should be placed in TARGET.  */
--- 2521,2527 ----
    return result;
  }
  
! /* Expand a call to the pow built-in mathematical function.  Return NULL_RTX if
     a normal call should be emitted rather than expanding the function
     in-line.  EXP is the expression that is a call to the builtin
     function; if convenient, the result should be placed in TARGET.  */
*************** expand_powi (rtx x, enum machine_mode mo
*** 2535,2548 ****
  static rtx
  expand_builtin_pow (tree exp, rtx target, rtx subtarget)
  {
-   tree arglist = TREE_OPERAND (exp, 1);
    tree arg0, arg1;
  
!   if (! validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
!     return 0;
  
!   arg0 = TREE_VALUE (arglist);
!   arg1 = TREE_VALUE (TREE_CHAIN (arglist));
  
    if (TREE_CODE (arg1) == REAL_CST
        && ! TREE_CONSTANT_OVERFLOW (arg1))
--- 2529,2541 ----
  static rtx
  expand_builtin_pow (tree exp, rtx target, rtx subtarget)
  {
    tree arg0, arg1;
  
!   if (! validate_arglist (exp, REAL_TYPE, REAL_TYPE, VOID_TYPE))
!     return NULL_RTX;
  
!   arg0 = CALL_EXPR_ARG0 (exp);
!   arg1 = CALL_EXPR_ARG1 (exp);
  
    if (TREE_CODE (arg1) == REAL_CST
        && ! TREE_CONSTANT_OVERFLOW (arg1))
*************** expand_builtin_pow (tree exp, rtx target
*** 2577,2583 ****
    return expand_builtin_mathfn_2 (exp, target, subtarget);
  }
  
! /* Expand a call to the powi built-in mathematical function.  Return 0 if
     a normal call should be emitted rather than expanding the function
     in-line.  EXP is the expression that is a call to the builtin
     function; if convenient, the result should be placed in TARGET.  */
--- 2570,2576 ----
    return expand_builtin_mathfn_2 (exp, target, subtarget);
  }
  
! /* Expand a call to the powi built-in mathematical function.  Return NULL_RTX if
     a normal call should be emitted rather than expanding the function
     in-line.  EXP is the expression that is a call to the builtin
     function; if convenient, the result should be placed in TARGET.  */
*************** expand_builtin_pow (tree exp, rtx target
*** 2585,2601 ****
  static rtx
  expand_builtin_powi (tree exp, rtx target, rtx subtarget)
  {
-   tree arglist = TREE_OPERAND (exp, 1);
    tree arg0, arg1;
    rtx op0, op1;
    enum machine_mode mode;
    enum machine_mode mode2;
  
!   if (! validate_arglist (arglist, REAL_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
  
!   arg0 = TREE_VALUE (arglist);
!   arg1 = TREE_VALUE (TREE_CHAIN (arglist));
    mode = TYPE_MODE (TREE_TYPE (exp));
  
    /* Handle constant power.  */
--- 2578,2593 ----
  static rtx
  expand_builtin_powi (tree exp, rtx target, rtx subtarget)
  {
    tree arg0, arg1;
    rtx op0, op1;
    enum machine_mode mode;
    enum machine_mode mode2;
  
!   if (! validate_arglist (exp, REAL_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return NULL_RTX;
  
!   arg0 = CALL_EXPR_ARG0 (exp);
!   arg1 = CALL_EXPR_ARG1 (exp);
    mode = TYPE_MODE (TREE_TYPE (exp));
  
    /* Handle constant power.  */
*************** expand_builtin_powi (tree exp, rtx targe
*** 2621,2627 ****
  
    /* Emit a libcall to libgcc.  */
  
!   /* Mode of the 2nd argument must match that of an int. */
    mode2 = mode_for_size (INT_TYPE_SIZE, MODE_INT, 0);
  
    if (target == NULL_RTX)
--- 2613,2619 ----
  
    /* Emit a libcall to libgcc.  */
  
!   /* Mode of the 2nd argument must match that of an int.  */
    mode2 = mode_for_size (INT_TYPE_SIZE, MODE_INT, 0);
  
    if (target == NULL_RTX)
*************** expand_builtin_powi (tree exp, rtx targe
*** 2646,2660 ****
     try to get the result in TARGET, if convenient.  */
  
  static rtx
! expand_builtin_strlen (tree arglist, rtx target,
  		       enum machine_mode target_mode)
  {
!   if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
        rtx pat;
!       tree len, src = TREE_VALUE (arglist);
        rtx result, src_reg, char_rtx, before_strlen;
        enum machine_mode insn_mode = target_mode, char_mode;
        enum insn_code icode = CODE_FOR_nothing;
--- 2638,2652 ----
     try to get the result in TARGET, if convenient.  */
  
  static rtx
! expand_builtin_strlen (tree exp, rtx target,
  		       enum machine_mode target_mode)
  {
!   if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
!     return NULL_RTX;
    else
      {
        rtx pat;
!       tree len, src = CALL_EXPR_ARG0 (exp);
        rtx result, src_reg, char_rtx, before_strlen;
        enum machine_mode insn_mode = target_mode, char_mode;
        enum insn_code icode = CODE_FOR_nothing;
*************** expand_builtin_strlen (tree arglist, rtx
*** 2681,2687 ****
  
        /* If SRC is not a pointer type, don't do this operation inline.  */
        if (align == 0)
! 	return 0;
  
        /* Bail out if we can't compute strlen in the right mode.  */
        while (insn_mode != VOIDmode)
--- 2673,2679 ----
  
        /* If SRC is not a pointer type, don't do this operation inline.  */
        if (align == 0)
! 	return NULL_RTX;
  
        /* Bail out if we can't compute strlen in the right mode.  */
        while (insn_mode != VOIDmode)
*************** expand_builtin_strlen (tree arglist, rtx
*** 2693,2699 ****
  	  insn_mode = GET_MODE_WIDER_MODE (insn_mode);
  	}
        if (insn_mode == VOIDmode)
! 	return 0;
  
        /* Make a place to write the result of the instruction.  */
        result = target;
--- 2685,2691 ----
  	  insn_mode = GET_MODE_WIDER_MODE (insn_mode);
  	}
        if (insn_mode == VOIDmode)
! 	return NULL_RTX;
  
        /* Make a place to write the result of the instruction.  */
        result = target;
*************** expand_builtin_strlen (tree arglist, rtx
*** 2721,2727 ****
        pat = GEN_FCN (icode) (result, gen_rtx_MEM (BLKmode, src_reg),
  			     char_rtx, GEN_INT (align));
        if (! pat)
! 	return 0;
        emit_insn (pat);
  
        /* Now that we are assured of success, expand the source.  */
--- 2713,2719 ----
        pat = GEN_FCN (icode) (result, gen_rtx_MEM (BLKmode, src_reg),
  			     char_rtx, GEN_INT (align));
        if (! pat)
! 	return NULL_RTX;
        emit_insn (pat);
  
        /* Now that we are assured of success, expand the source.  */
*************** expand_builtin_strlen (tree arglist, rtx
*** 2749,2818 ****
      }
  }
  
! /* 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 (tree arglist, tree type, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      {
!       tree result = fold_builtin_strstr (arglist, type);
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
!   return 0;
  }
  
! /* 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 (tree arglist, tree type, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      {
!       tree result = fold_builtin_strchr (arglist, type);
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
  
        /* FIXME: Should use strchrM optab so that ports can optimize this.  */
      }
!   return 0;
  }
  
! /* 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 (tree arglist, tree type, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      {
!       tree result = fold_builtin_strrchr (arglist, type);
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
!   return 0;
  }
  
! /* 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 (tree arglist, tree type, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      {
!       tree result = fold_builtin_strpbrk (arglist, type);
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
!   return 0;
  }
  
  /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
--- 2741,2818 ----
      }
  }
  
! /* Expand a call to the strstr builtin.  Return NULL_RTX 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 (tree exp, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      {
!       tree type = TREE_TYPE (exp);
!       tree result = fold_builtin_strstr (CALL_EXPR_ARG0 (exp),
! 					 CALL_EXPR_ARG1 (exp), type);
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
!   return NULL_RTX;
  }
  
! /* Expand a call to the strchr builtin.  Return NULL_RTX 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 (tree exp, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      {
!       tree type = TREE_TYPE (exp);
!       tree result = fold_builtin_strchr (CALL_EXPR_ARG0 (exp),
! 					 CALL_EXPR_ARG1 (exp), type);
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
  
        /* FIXME: Should use strchrM optab so that ports can optimize this.  */
      }
!   return NULL_RTX;
  }
  
! /* Expand a call to the strrchr builtin.  Return NULL_RTX 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 (tree exp, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      {
!       tree type = TREE_TYPE (exp);
!       tree result = fold_builtin_strrchr (CALL_EXPR_ARG0 (exp),
! 					  CALL_EXPR_ARG1 (exp), type);
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
!   return NULL_RTX;
  }
  
! /* Expand a call to the strpbrk builtin.  Return NULL_RTX 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 (tree exp, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      {
!       tree type = TREE_TYPE (exp);
!       tree result = fold_builtin_strpbrk (CALL_EXPR_ARG0 (exp),
! 					  CALL_EXPR_ARG1 (exp), type);
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
!   return NULL_RTX;
  }
  
  /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
*************** builtin_memcpy_read_str (void *data, HOS
*** 2832,2872 ****
    return c_readstr (str + offset, mode);
  }
  
! /* Expand a call to the memcpy builtin, with arguments in ARGLIST.
!    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_memcpy (tree exp, rtx target, enum machine_mode mode)
  {
    tree fndecl = get_callee_fndecl (exp);
!   tree arglist = TREE_OPERAND (exp, 1);
!   if (!validate_arglist (arglist,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
!       tree dest = TREE_VALUE (arglist);
!       tree src = TREE_VALUE (TREE_CHAIN (arglist));
!       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
        const char *src_str;
        unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
        unsigned int dest_align
  	= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
        rtx dest_mem, src_mem, dest_addr, len_rtx;
!       tree result = fold_builtin_memcpy (fndecl, arglist);
  
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
  
        /* If DEST is not a pointer type, call the normal function.  */
        if (dest_align == 0)
! 	return 0;
  
        /* If either SRC is not a pointer type, don't do this
  	 operation in-line.  */
        if (src_align == 0)
! 	return 0;
  
        dest_mem = get_memory_rtx (dest, len);
        set_mem_align (dest_mem, dest_align);
--- 2832,2872 ----
    return c_readstr (str + offset, mode);
  }
  
! /* Expand a call EXP to the memcpy builtin.
!    Return NULL_RTX 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_memcpy (tree exp, rtx target, enum machine_mode mode)
  {
    tree fndecl = get_callee_fndecl (exp);
!   if (!validate_arglist (exp,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return NULL_RTX;
    else
      {
!       tree dest = CALL_EXPR_ARG0 (exp);
!       tree src = CALL_EXPR_ARG1 (exp);
!       tree len = CALL_EXPR_ARG2 (exp);
        const char *src_str;
        unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
        unsigned int dest_align
  	= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
        rtx dest_mem, src_mem, dest_addr, len_rtx;
!       tree result = fold_builtin_memcpy (dest, src, len,
! 					 TREE_TYPE (TREE_TYPE (fndecl)));
  
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
  
        /* If DEST is not a pointer type, call the normal function.  */
        if (dest_align == 0)
! 	return NULL_RTX;
  
        /* If either SRC is not a pointer type, don't do this
  	 operation in-line.  */
        if (src_align == 0)
! 	return NULL_RTX;
  
        dest_mem = get_memory_rtx (dest, len);
        set_mem_align (dest_mem, dest_align);
*************** expand_builtin_memcpy (tree exp, rtx tar
*** 2907,2914 ****
      }
  }
  
! /* Expand a call to the mempcpy builtin, with arguments in ARGLIST.
!    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).  If ENDP is 0 return the
     destination pointer, if ENDP is 1 return the end pointer ala
--- 2907,2914 ----
      }
  }
  
! /* Expand a call EXP to the mempcpy builtin.
!    Return NULL_RTX 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).  If ENDP is 0 return the
     destination pointer, if ENDP is 1 return the end pointer ala
*************** expand_builtin_memcpy (tree exp, rtx tar
*** 2916,2949 ****
     stpcpy.  */
  
  static rtx
! expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode mode,
! 			int endp)
  {
!   if (!validate_arglist (arglist,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
    /* If return value is ignored, transform mempcpy into memcpy.  */
!   else if (target == const0_rtx)
      {
        tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
  
        if (!fn)
! 	return 0;
  
!       return expand_expr (build_function_call_expr (fn, arglist),
  			  target, mode, EXPAND_NORMAL);
      }
    else
      {
-       tree dest = TREE_VALUE (arglist);
-       tree src = TREE_VALUE (TREE_CHAIN (arglist));
-       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
        const char *src_str;
        unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
        unsigned int dest_align
  	= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
        rtx dest_mem, src_mem, len_rtx;
!       tree result = fold_builtin_mempcpy (arglist, type, endp);
  
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
--- 2916,2966 ----
     stpcpy.  */
  
  static rtx
! expand_builtin_mempcpy (tree exp, rtx target, enum machine_mode mode)
  {
!   if (!validate_arglist (exp,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return NULL_RTX;
!   else
!     {
!       tree dest = CALL_EXPR_ARG0 (exp);
!       tree src = CALL_EXPR_ARG1 (exp);
!       tree len = CALL_EXPR_ARG2 (exp);
!       return expand_builtin_mempcpy_args (dest, src, len,
! 					  TREE_TYPE (exp),
! 					  target, mode, /*endp=*/ 1);
!     }
! }
! 
! /* Helper function to do the actual work for expand_builtin_mempcpy.  The
!    arguments to the builtin_mempcpy call DEST, SRC, and LEN are broken out
!    so that this can also be called without constructing an actual CALL_EXPR.
!    TYPE is the return type of the call.  The other arguments and return value
!    are the same as for expand_builtin_mempcpy.  */
! 
! static rtx
! expand_builtin_mempcpy_args (tree dest, tree src, tree len, tree type,
! 			     rtx target, enum machine_mode mode, int endp)
! {
    /* If return value is ignored, transform mempcpy into memcpy.  */
!   if (target == const0_rtx)
      {
        tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
  
        if (!fn)
! 	return NULL_RTX;
  
!       return expand_expr (build_call_expr (fn, 3, dest, src, len),
  			  target, mode, EXPAND_NORMAL);
      }
    else
      {
        const char *src_str;
        unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
        unsigned int dest_align
  	= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
        rtx dest_mem, src_mem, len_rtx;
!       tree result = fold_builtin_mempcpy (dest, src, len, type, endp);
  
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
*************** expand_builtin_mempcpy (tree arglist, tr
*** 2951,2961 ****
        /* If either SRC or DEST is not a pointer type, don't do this
  	 operation in-line.  */
        if (dest_align == 0 || src_align == 0)
! 	return 0;
  
        /* If LEN is not constant, call the normal function.  */
        if (! host_integerp (len, 1))
! 	return 0;
  
        len_rtx = expand_normal (len);
        src_str = c_getstr (src);
--- 2968,2978 ----
        /* If either SRC or DEST is not a pointer type, don't do this
  	 operation in-line.  */
        if (dest_align == 0 || src_align == 0)
! 	return NULL_RTX;
  
        /* If LEN is not constant, call the normal function.  */
        if (! host_integerp (len, 1))
! 	return NULL_RTX;
  
        len_rtx = expand_normal (len);
        src_str = c_getstr (src);
*************** expand_builtin_mempcpy (tree arglist, tr
*** 2994,3000 ****
  	  return dest_mem;
  	}
  
!       return 0;
      }
  }
  
--- 3011,3017 ----
  	  return dest_mem;
  	}
  
!       return NULL_RTX;
      }
  }
  
*************** expand_builtin_mempcpy (tree arglist, tr
*** 3002,3062 ****
     if we failed; the caller should emit a normal call.  */
  
  static rtx
! expand_builtin_memmove (tree arglist, tree type, rtx target,
! 			enum machine_mode mode, tree orig_exp)
  {
!   if (!validate_arglist (arglist,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
!       tree dest = TREE_VALUE (arglist);
!       tree src = TREE_VALUE (TREE_CHAIN (arglist));
!       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
  
!       unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
!       unsigned int dest_align
! 	= get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
!       tree result = fold_builtin_memmove (arglist, type);
  
!       if (result)
! 	return expand_expr (result, target, mode, EXPAND_NORMAL);
  
!       /* If DEST is not a pointer type, call the normal function.  */
!       if (dest_align == 0)
! 	return 0;
  
!       /* If either SRC is not a pointer type, don't do this
! 	 operation in-line.  */
!       if (src_align == 0)
! 	return 0;
  
!       /* If src is categorized for a readonly section we can use
! 	 normal memcpy.  */
!       if (readonly_data_expr (src))
! 	{
! 	  tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
! 	  if (!fn)
! 	    return 0;
! 	  fn = build_function_call_expr (fn, arglist);
! 	  if (TREE_CODE (fn) == CALL_EXPR)
! 	    CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp);
! 	  return expand_expr (fn, target, mode, EXPAND_NORMAL);
! 	}
! 
!       /* If length is 1 and we can expand memcpy call inline,
! 	 it is ok to use memcpy as well.  */
!       if (integer_onep (len))
! 	{
! 	  rtx ret = expand_builtin_mempcpy (arglist, type, target, mode,
! 					    /*endp=*/0);
! 	  if (ret)
! 	    return ret;
! 	}
! 
!       /* Otherwise, call the normal function.  */
!       return 0;
!    }
  }
  
  /* Expand expression EXP, which is a call to the bcopy builtin.  Return 0
--- 3019,3094 ----
     if we failed; the caller should emit a normal call.  */
  
  static rtx
! expand_builtin_memmove (tree exp, rtx target, enum machine_mode mode)
  {
!   if (!validate_arglist (exp,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return NULL_RTX;
    else
      {
!       tree dest = CALL_EXPR_ARG0 (exp);
!       tree src = CALL_EXPR_ARG1 (exp);
!       tree len = CALL_EXPR_ARG2 (exp);
  
!       return expand_builtin_memmove_args (dest, src, len,
! 					  TREE_TYPE (exp), target, mode, exp);
!     }
! }
  
! /* Helper function to do the actual work for expand_builtin_memmove.  The
!    arguments to the builtin_memmove call DEST, SRC, and LEN are broken out
!    so that this can also be called without constructing an actual CALL_EXPR.
!    TYPE is the return type of the call.  The other arguments and return value
!    are the same as for expand_builtin_memmove.  */
  
! static rtx
! expand_builtin_memmove_args (tree dest, tree src, tree len,
! 			     tree type, rtx target,
! 			     enum machine_mode mode, tree orig_exp)
! {
!   unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
!   unsigned int dest_align
!     = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
!   tree result = fold_builtin_memmove (dest, src, len, type);
  
!   if (result)
!     return expand_expr (result, target, mode, EXPAND_NORMAL);
  
!   /* If DEST is not a pointer type, call the normal function.  */
!   if (dest_align == 0)
!     return NULL_RTX;
! 
!   /* If either SRC is not a pointer type, don't do this
!      operation in-line.  */
!   if (src_align == 0)
!     return NULL_RTX;
! 
!   /* If src is categorized for a readonly section we can use
!      normal memcpy.  */
!   if (readonly_data_expr (src))
!     {
!       tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
!       if (!fn)
! 	return NULL_RTX;
!       fn = build_call_expr (fn, 3, dest, src, len);
!       if (TREE_CODE (fn) == CALL_EXPR)
! 	CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp);
!       return expand_expr (fn, target, mode, EXPAND_NORMAL);
!     }
! 
!   /* If length is 1 and we can expand memcpy call inline,
!      it is ok to use memcpy as well.  */
!   if (integer_onep (len))
!     {
!       rtx ret = expand_builtin_mempcpy_args (dest, src, len, type,
! 					     target, mode,
! 					     /*endp=*/0);
!       if (ret)
! 	return ret;
!     }
! 
!   /* Otherwise, call the normal function.  */
!   return NULL_RTX;
  }
  
  /* Expand expression EXP, which is a call to the bcopy builtin.  Return 0
*************** expand_builtin_memmove (tree arglist, tr
*** 3065,3092 ****
  static rtx
  expand_builtin_bcopy (tree exp)
  {
-   tree arglist = TREE_OPERAND (exp, 1);
    tree type = TREE_TYPE (exp);
!   tree src, dest, size, newarglist;
  
!   if (!validate_arglist (arglist,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      return NULL_RTX;
  
!   src = TREE_VALUE (arglist);
!   dest = TREE_VALUE (TREE_CHAIN (arglist));
!   size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
  
    /* New argument list transforming bcopy(ptr x, ptr y, int z) to
       memmove(ptr y, ptr x, size_t z).   This is done this way
       so that if it isn't expanded inline, we fallback to
       calling bcopy instead of memmove.  */
  
!   newarglist = build_tree_list (NULL_TREE, fold_convert (sizetype, size));
!   newarglist = tree_cons (NULL_TREE, src, newarglist);
!   newarglist = tree_cons (NULL_TREE, dest, newarglist);
! 
!   return expand_builtin_memmove (newarglist, type, const0_rtx, VOIDmode, exp);
  }
  
  #ifndef HAVE_movstr
--- 3097,3121 ----
  static rtx
  expand_builtin_bcopy (tree exp)
  {
    tree type = TREE_TYPE (exp);
!   tree src, dest, size;
  
!   if (!validate_arglist (exp,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      return NULL_RTX;
  
!   src = CALL_EXPR_ARG0 (exp);
!   dest = CALL_EXPR_ARG1 (exp);
!   size = CALL_EXPR_ARG2 (exp);
  
    /* New argument list transforming bcopy(ptr x, ptr y, int z) to
       memmove(ptr y, ptr x, size_t z).   This is done this way
       so that if it isn't expanded inline, we fallback to
       calling bcopy instead of memmove.  */
  
!   return expand_builtin_memmove_args (dest, src,
! 				      fold_convert (sizetype, size),
! 				      type, const0_rtx, VOIDmode, exp);
  }
  
  #ifndef HAVE_movstr
*************** expand_builtin_bcopy (tree exp)
*** 3094,3100 ****
  # define CODE_FOR_movstr CODE_FOR_nothing
  #endif
  
! /* Expand into a movstr instruction, if one is available.  Return 0 if
     we failed, the caller should emit a normal call, otherwise try to
     get the result in TARGET, if convenient.  If ENDP is 0 return the
     destination pointer, if ENDP is 1 return the end pointer ala
--- 3123,3129 ----
  # define CODE_FOR_movstr CODE_FOR_nothing
  #endif
  
! /* Expand into a movstr instruction, if one is available.  Return NULL_RTX if
     we failed, the caller should emit a normal call, otherwise try to
     get the result in TARGET, if convenient.  If ENDP is 0 return the
     destination pointer, if ENDP is 1 return the end pointer ala
*************** expand_movstr (tree dest, tree src, rtx 
*** 3111,3117 ****
    const struct insn_data * data;
  
    if (!HAVE_movstr)
!     return 0;
  
    dest_mem = get_memory_rtx (dest, NULL);
    src_mem = get_memory_rtx (src, NULL);
--- 3140,3146 ----
    const struct insn_data * data;
  
    if (!HAVE_movstr)
!     return NULL_RTX;
  
    dest_mem = get_memory_rtx (dest, NULL);
    src_mem = get_memory_rtx (src, NULL);
*************** expand_movstr (tree dest, tree src, rtx 
*** 3162,3227 ****
     convenient).  */
  
  static rtx
! expand_builtin_strcpy (tree fndecl, tree arglist, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      {
!       tree result = fold_builtin_strcpy (fndecl, arglist, 0);
!       if (result)
! 	return expand_expr (result, target, mode, EXPAND_NORMAL);
! 
!       return expand_movstr (TREE_VALUE (arglist),
! 			    TREE_VALUE (TREE_CHAIN (arglist)),
! 			    target, /*endp=*/0);
      }
!   return 0;
  }
  
! /* Expand a call to the stpcpy builtin, with arguments in ARGLIST.
!    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_stpcpy (tree exp, rtx target, enum machine_mode mode)
  {
!   tree arglist = TREE_OPERAND (exp, 1);
    /* If return value is ignored, transform stpcpy into strcpy.  */
    if (target == const0_rtx)
      {
        tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
        if (!fn)
! 	return 0;
  
!       return expand_expr (build_function_call_expr (fn, arglist),
  			  target, mode, EXPAND_NORMAL);
      }
- 
-   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
-     return 0;
    else
      {
!       tree dst, src, len, lenp1;
!       tree narglist;
        rtx ret;
  
        /* Ensure we get an actual string whose length can be evaluated at
  	 compile-time, not an expression containing a string.  This is
  	 because the latter will potentially produce pessimized code
  	 when used to produce the return value.  */
-       src = TREE_VALUE (TREE_CHAIN (arglist));
        if (! c_getstr (src) || ! (len = c_strlen (src, 0)))
! 	return expand_movstr (TREE_VALUE (arglist),
! 			      TREE_VALUE (TREE_CHAIN (arglist)),
! 			      target, /*endp=*/2);
  
-       dst = TREE_VALUE (arglist);
        lenp1 = size_binop (PLUS_EXPR, len, ssize_int (1));
!       narglist = build_tree_list (NULL_TREE, lenp1);
!       narglist = tree_cons (NULL_TREE, src, narglist);
!       narglist = tree_cons (NULL_TREE, dst, narglist);
!       ret = expand_builtin_mempcpy (narglist, TREE_TYPE (exp),
! 				    target, mode, /*endp=*/2);
  
        if (ret)
  	return ret;
--- 3191,3263 ----
     convenient).  */
  
  static rtx
! expand_builtin_strcpy (tree fndecl, tree exp, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      {
!       tree dest = CALL_EXPR_ARG0 (exp);
!       tree src = CALL_EXPR_ARG1 (exp);
!       return expand_builtin_strcpy_args (fndecl, dest, src, target, mode);
      }
!   return NULL_RTX;
! }
! 
! /* Helper function to do the actual work for expand_builtin_strcpy.  The
!    arguments to the builtin_strcpy call DEST and SRC are broken out
!    so that this can also be called without constructing an actual CALL_EXPR.
!    The other arguments and return value are the same as for
!    expand_builtin_strcpy.  */
! 
! static rtx
! expand_builtin_strcpy_args (tree fndecl, tree dest, tree src,
! 			    rtx target, enum machine_mode mode)
! {
!   tree result = fold_builtin_strcpy (fndecl, dest, src, 0);
!   if (result)
!     return expand_expr (result, target, mode, EXPAND_NORMAL);
!   return expand_movstr (dest, src, target, /*endp=*/0);
  }
  
! /* Expand a call EXP to the stpcpy builtin.
!    Return NULL_RTX 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_stpcpy (tree exp, rtx target, enum machine_mode mode)
  {
!   tree dst, src;  
!   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
!     return NULL_RTX;
! 
!   dst = CALL_EXPR_ARG0 (exp);
!   src = CALL_EXPR_ARG1 (exp);
! 
    /* If return value is ignored, transform stpcpy into strcpy.  */
    if (target == const0_rtx)
      {
        tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
        if (!fn)
! 	return NULL_RTX;
  
!       return expand_expr (build_call_expr (fn, 2, dst, src),
  			  target, mode, EXPAND_NORMAL);
      }
    else
      {
!       tree len, lenp1;
        rtx ret;
  
        /* Ensure we get an actual string whose length can be evaluated at
  	 compile-time, not an expression containing a string.  This is
  	 because the latter will potentially produce pessimized code
  	 when used to produce the return value.  */
        if (! c_getstr (src) || ! (len = c_strlen (src, 0)))
! 	return expand_movstr (dst, src, target, /*endp=*/2);
  
        lenp1 = size_binop (PLUS_EXPR, len, ssize_int (1));
!       ret = expand_builtin_mempcpy_args (dst, src, lenp1, TREE_TYPE (exp),
! 					 target, mode, /*endp=*/2);
  
        if (ret)
  	return ret;
*************** expand_builtin_stpcpy (tree exp, rtx tar
*** 3232,3239 ****
  
  	  if (GET_CODE (len_rtx) == CONST_INT)
  	    {
! 	      ret = expand_builtin_strcpy (get_callee_fndecl (exp),
! 					   arglist, target, mode);
  
  	      if (ret)
  		{
--- 3268,3275 ----
  
  	  if (GET_CODE (len_rtx) == CONST_INT)
  	    {
! 	      ret = expand_builtin_strcpy_args (get_callee_fndecl (exp),
! 						dst, src, target, mode);
  
  	      if (ret)
  		{
*************** expand_builtin_stpcpy (tree exp, rtx tar
*** 3256,3264 ****
  	    }
  	}
  
!       return expand_movstr (TREE_VALUE (arglist),
! 			    TREE_VALUE (TREE_CHAIN (arglist)),
! 			    target, /*endp=*/2);
      }
  }
  
--- 3292,3298 ----
  	    }
  	}
  
!       return expand_movstr (dst, src, target, /*endp=*/2);
      }
  }
  
*************** static rtx
*** 3285,3304 ****
  expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode)
  {
    tree fndecl = get_callee_fndecl (exp);
!   tree arglist = TREE_OPERAND (exp, 1);
!   if (validate_arglist (arglist,
  			POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      {
!       tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)), 1);
!       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
!       tree result = fold_builtin_strncpy (fndecl, arglist, slen);
  
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
  
        /* We must be passed a constant len and src parameter.  */
        if (!host_integerp (len, 1) || !slen || !host_integerp (slen, 1))
! 	return 0;
  
        slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
  
--- 3319,3339 ----
  expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode)
  {
    tree fndecl = get_callee_fndecl (exp);
!   if (validate_arglist (exp,
  			POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      {
!       tree dest = CALL_EXPR_ARG0 (exp);
!       tree src = CALL_EXPR_ARG1 (exp);
!       tree slen = c_strlen (src, 1);
!       tree len = CALL_EXPR_ARG2 (exp);
!       tree result = fold_builtin_strncpy (fndecl, dest, src, len, slen);
  
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
  
        /* We must be passed a constant len and src parameter.  */
        if (!host_integerp (len, 1) || !slen || !host_integerp (slen, 1))
! 	return NULL_RTX;
  
        slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
  
*************** expand_builtin_strncpy (tree exp, rtx ta
*** 3307,3323 ****
  	 use store_by_pieces, if it fails, punt.  */
        if (tree_int_cst_lt (slen, len))
  	{
- 	  tree dest = TREE_VALUE (arglist);
  	  unsigned int dest_align
  	    = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
! 	  const char *p = c_getstr (TREE_VALUE (TREE_CHAIN (arglist)));
  	  rtx dest_mem;
  
  	  if (!p || dest_align == 0 || !host_integerp (len, 1)
  	      || !can_store_by_pieces (tree_low_cst (len, 1),
  				       builtin_strncpy_read_str,
  				       (void *) p, dest_align))
! 	    return 0;
  
  	  dest_mem = get_memory_rtx (dest, len);
  	  store_by_pieces (dest_mem, tree_low_cst (len, 1),
--- 3342,3357 ----
  	 use store_by_pieces, if it fails, punt.  */
        if (tree_int_cst_lt (slen, len))
  	{
  	  unsigned int dest_align
  	    = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
! 	  const char *p = c_getstr (src);
  	  rtx dest_mem;
  
  	  if (!p || dest_align == 0 || !host_integerp (len, 1)
  	      || !can_store_by_pieces (tree_low_cst (len, 1),
  				       builtin_strncpy_read_str,
  				       (void *) p, dest_align))
! 	    return NULL_RTX;
  
  	  dest_mem = get_memory_rtx (dest, len);
  	  store_by_pieces (dest_mem, tree_low_cst (len, 1),
*************** expand_builtin_strncpy (tree exp, rtx ta
*** 3328,3334 ****
  	  return dest_mem;
  	}
      }
!   return 0;
  }
  
  /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
--- 3362,3368 ----
  	  return dest_mem;
  	}
      }
!   return NULL_RTX;
  }
  
  /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
*************** builtin_memset_gen_str (void *data, HOST
*** 3379,3501 ****
     convenient).  */
  
  static rtx
! expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode,
! 		       tree orig_exp)
  {
!   if (!validate_arglist (arglist,
  			 POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
!       tree dest = TREE_VALUE (arglist);
!       tree val = TREE_VALUE (TREE_CHAIN (arglist));
!       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
!       tree fndecl, fn;
!       enum built_in_function fcode;
!       char c;
!       unsigned int dest_align;
!       rtx dest_mem, dest_addr, len_rtx;
! 
!       dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
  
!       /* If DEST is not a pointer type, don't do this
! 	 operation in-line.  */
!       if (dest_align == 0)
! 	return 0;
  
!       /* If the LEN parameter is zero, return DEST.  */
!       if (integer_zerop (len))
! 	{
! 	  /* Evaluate and ignore VAL in case it has side-effects.  */
! 	  expand_expr (val, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 	  return expand_expr (dest, target, mode, EXPAND_NORMAL);
! 	}
  
!       /* Stabilize the arguments in case we fail.  */
!       dest = builtin_save_expr (dest);
!       val = builtin_save_expr (val);
!       len = builtin_save_expr (len);
  
!       len_rtx = expand_normal (len);
!       dest_mem = get_memory_rtx (dest, len);
  
!       if (TREE_CODE (val) != INTEGER_CST)
  	{
! 	  rtx val_rtx;
! 
! 	  val_rtx = expand_normal (val);
! 	  val_rtx = convert_to_mode (TYPE_MODE (unsigned_char_type_node),
! 				     val_rtx, 0);
! 
! 	  /* Assume that we can memset by pieces if we can store the
! 	   * the coefficients by pieces (in the required modes).
! 	   * We can't pass builtin_memset_gen_str as that emits RTL.  */
! 	  c = 1;
! 	  if (host_integerp (len, 1)
! 	      && !(optimize_size && tree_low_cst (len, 1) > 1)
! 	      && can_store_by_pieces (tree_low_cst (len, 1),
! 				      builtin_memset_read_str, &c, dest_align))
! 	    {
! 	      val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
! 				   val_rtx);
! 	      store_by_pieces (dest_mem, tree_low_cst (len, 1),
! 			       builtin_memset_gen_str, val_rtx, dest_align, 0);
! 	    }
! 	  else if (!set_storage_via_setmem (dest_mem, len_rtx, val_rtx,
! 					    dest_align))
! 	    goto do_libcall;
! 
! 	  dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
! 	  dest_mem = convert_memory_address (ptr_mode, dest_mem);
! 	  return dest_mem;
  	}
! 
!       if (target_char_cast (val, &c))
  	goto do_libcall;
  
!       if (c)
! 	{
! 	  if (host_integerp (len, 1)
! 	      && !(optimize_size && tree_low_cst (len, 1) > 1)
! 	      && can_store_by_pieces (tree_low_cst (len, 1),
! 				      builtin_memset_read_str, &c, dest_align))
! 	    store_by_pieces (dest_mem, tree_low_cst (len, 1),
! 			     builtin_memset_read_str, &c, dest_align, 0);
! 	  else if (!set_storage_via_setmem (dest_mem, len_rtx, GEN_INT (c),
! 					    dest_align))
! 	    goto do_libcall;
! 
! 	  dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
! 	  dest_mem = convert_memory_address (ptr_mode, dest_mem);
! 	  return dest_mem;
! 	}
! 
!       set_mem_align (dest_mem, dest_align);
!       dest_addr = clear_storage (dest_mem, len_rtx,
! 				 CALL_EXPR_TAILCALL (orig_exp)
! 				 ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL);
  
!       if (dest_addr == 0)
! 	{
! 	  dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
! 	  dest_addr = convert_memory_address (ptr_mode, dest_addr);
! 	}
  
!       return dest_addr;
  
!     do_libcall:
!       fndecl = get_callee_fndecl (orig_exp);
!       fcode = DECL_FUNCTION_CODE (fndecl);
!       gcc_assert (fcode == BUILT_IN_MEMSET || fcode == BUILT_IN_BZERO);
!       arglist = build_tree_list (NULL_TREE, len);
!       if (fcode == BUILT_IN_MEMSET)
! 	arglist = tree_cons (NULL_TREE, val, arglist);
!       arglist = tree_cons (NULL_TREE, dest, arglist);
!       fn = build_function_call_expr (fndecl, arglist);
!       if (TREE_CODE (fn) == CALL_EXPR)
! 	CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp);
!       return expand_call (fn, target, target == const0_rtx);
!     }
  }
  
  /* Expand expression EXP, which is a call to the bzero builtin.  Return 0
--- 3413,3546 ----
     convenient).  */
  
  static rtx
! expand_builtin_memset (tree exp, rtx target, enum machine_mode mode)
  {
!   if (!validate_arglist (exp,
  			 POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return NULL_RTX;
    else
      {
!       tree dest = CALL_EXPR_ARG0 (exp);
!       tree val = CALL_EXPR_ARG1 (exp);
!       tree len = CALL_EXPR_ARG2 (exp);
!       return expand_builtin_memset_args (dest, val, len, target, mode, exp);
!     }
! }
  
! /* Helper function to do the actual work for expand_builtin_memset.  The
!    arguments to the builtin_memset call DEST, VAL, and LEN are broken out
!    so that this can also be called without constructing an actual CALL_EXPR.
!    The other arguments and return value are the same as for
!    expand_builtin_memset.  */
  
! static rtx
! expand_builtin_memset_args (tree dest, tree val, tree len,
! 			    rtx target, enum machine_mode mode, tree orig_exp)
! {
!   tree fndecl, fn;
!   enum built_in_function fcode;
!   char c;
!   unsigned int dest_align;
!   rtx dest_mem, dest_addr, len_rtx;
  
!   dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
  
!   /* If DEST is not a pointer type, don't do this operation in-line.  */
!   if (dest_align == 0)
!     return NULL_RTX;
  
!   /* If the LEN parameter is zero, return DEST.  */
!   if (integer_zerop (len))
!     {
!       /* Evaluate and ignore VAL in case it has side-effects.  */
!       expand_expr (val, const0_rtx, VOIDmode, EXPAND_NORMAL);
!       return expand_expr (dest, target, mode, EXPAND_NORMAL);
!     }
! 
!   /* Stabilize the arguments in case we fail.  */
!   dest = builtin_save_expr (dest);
!   val = builtin_save_expr (val);
!   len = builtin_save_expr (len);
! 
!   len_rtx = expand_normal (len);
!   dest_mem = get_memory_rtx (dest, len);
! 
!   if (TREE_CODE (val) != INTEGER_CST)
!     {
!       rtx val_rtx;
! 
!       val_rtx = expand_normal (val);
!       val_rtx = convert_to_mode (TYPE_MODE (unsigned_char_type_node),
! 				 val_rtx, 0);
! 
!       /* Assume that we can memset by pieces if we can store the
!        * the coefficients by pieces (in the required modes).
!        * We can't pass builtin_memset_gen_str as that emits RTL.  */
!       c = 1;
!       if (host_integerp (len, 1)
! 	  && !(optimize_size && tree_low_cst (len, 1) > 1)
! 	  && can_store_by_pieces (tree_low_cst (len, 1),
! 				  builtin_memset_read_str, &c, dest_align))
  	{
! 	  val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
! 			       val_rtx);
! 	  store_by_pieces (dest_mem, tree_low_cst (len, 1),
! 			   builtin_memset_gen_str, val_rtx, dest_align, 0);
  	}
!       else if (!set_storage_via_setmem (dest_mem, len_rtx, val_rtx,
! 					dest_align))
  	goto do_libcall;
+       
+       dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+       dest_mem = convert_memory_address (ptr_mode, dest_mem);
+       return dest_mem;
+     }
+ 
+   if (target_char_cast (val, &c))
+     goto do_libcall;
+ 
+   if (c)
+     {
+       if (host_integerp (len, 1)
+ 	  && !(optimize_size && tree_low_cst (len, 1) > 1)
+ 	  && can_store_by_pieces (tree_low_cst (len, 1),
+ 				  builtin_memset_read_str, &c, dest_align))
+ 	store_by_pieces (dest_mem, tree_low_cst (len, 1),
+ 			 builtin_memset_read_str, &c, dest_align, 0);
+       else if (!set_storage_via_setmem (dest_mem, len_rtx, GEN_INT (c),
+ 					dest_align))
+ 	goto do_libcall;
+       
+       dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+       dest_mem = convert_memory_address (ptr_mode, dest_mem);
+       return dest_mem;
+     }
  
!   set_mem_align (dest_mem, dest_align);
!   dest_addr = clear_storage (dest_mem, len_rtx,
! 			     CALL_EXPR_TAILCALL (orig_exp)
! 			     ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL);
  
!   if (dest_addr == 0)
!     {
!       dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
!       dest_addr = convert_memory_address (ptr_mode, dest_addr);
!     }
  
!   return dest_addr;
  
!  do_libcall:
!   fndecl = get_callee_fndecl (orig_exp);
!   fcode = DECL_FUNCTION_CODE (fndecl);
!   if (fcode == BUILT_IN_MEMSET)
!     fn = build_call_expr (fndecl, 3, dest, val, len);
!   else if (fcode == BUILT_IN_BZERO)
!     fn = build_call_expr (fndecl, 2, dest, len);
!   else
!     gcc_unreachable ();
!   if (TREE_CODE (fn) == CALL_EXPR)
!     CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp);
!   return expand_call (fn, target, target == const0_rtx);
  }
  
  /* Expand expression EXP, which is a call to the bzero builtin.  Return 0
*************** expand_builtin_memset (tree arglist, rtx
*** 3504,3558 ****
  static rtx
  expand_builtin_bzero (tree exp)
  {
!   tree arglist = TREE_OPERAND (exp, 1);
!   tree dest, size, newarglist;
  
!   if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      return NULL_RTX;
  
!   dest = TREE_VALUE (arglist);
!   size = TREE_VALUE (TREE_CHAIN (arglist));
  
    /* New argument list transforming bzero(ptr x, int y) to
       memset(ptr x, int 0, size_t y).   This is done this way
       so that if it isn't expanded inline, we fallback to
       calling bzero instead of memset.  */
  
!   newarglist = build_tree_list (NULL_TREE, fold_convert (sizetype, size));
!   newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
!   newarglist = tree_cons (NULL_TREE, dest, newarglist);
! 
!   return expand_builtin_memset (newarglist, const0_rtx, VOIDmode, exp);
  }
  
  /* Expand expression EXP, which is a call to the memcmp built-in function.
!    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 (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target,
! 		       enum machine_mode mode)
  {
!   if (!validate_arglist (arglist,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
!       tree result = fold_builtin_memcmp (arglist);
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
  
  #if defined HAVE_cmpmemsi || defined HAVE_cmpstrnsi
    {
-     tree arg1 = TREE_VALUE (arglist);
-     tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
-     tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
      rtx arg1_rtx, arg2_rtx, arg3_rtx;
      rtx result;
      rtx insn;
  
      int arg1_align
        = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
      int arg2_align
--- 3549,3602 ----
  static rtx
  expand_builtin_bzero (tree exp)
  {
!   tree dest, size;
  
!   if (!validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      return NULL_RTX;
  
!   dest = CALL_EXPR_ARG0 (exp);
!   size = CALL_EXPR_ARG1 (exp);
  
    /* New argument list transforming bzero(ptr x, int y) to
       memset(ptr x, int 0, size_t y).   This is done this way
       so that if it isn't expanded inline, we fallback to
       calling bzero instead of memset.  */
  
!   return expand_builtin_memset_args (dest, integer_zero_node,
! 				     fold_convert (sizetype, size),
! 				     const0_rtx, VOIDmode, exp);
  }
  
  /* Expand expression EXP, which is a call to the memcmp built-in function.
!    Return NULL_RTX 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 (tree exp, rtx target, enum machine_mode mode)
  {
!   if (!validate_arglist (exp,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return NULL_RTX;
    else
      {
!       tree result = fold_builtin_memcmp (CALL_EXPR_ARG0 (exp),
! 					 CALL_EXPR_ARG1 (exp),
! 					 CALL_EXPR_ARG2 (exp));
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
  
  #if defined HAVE_cmpmemsi || defined HAVE_cmpstrnsi
    {
      rtx arg1_rtx, arg2_rtx, arg3_rtx;
      rtx result;
      rtx insn;
  
+     tree arg1 = CALL_EXPR_ARG0 (exp);
+     tree arg2 = CALL_EXPR_ARG1 (exp);
+     tree len = CALL_EXPR_ARG2 (exp);
+ 
      int arg1_align
        = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
      int arg2_align
*************** expand_builtin_memcmp (tree exp ATTRIBUT
*** 3569,3579 ****
        insn_mode = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
      else
  #endif
!       return 0;
  
      /* If we don't have POINTER_TYPE, call the function.  */
      if (arg1_align == 0 || arg2_align == 0)
!       return 0;
  
      /* Make a place to write the result of the instruction.  */
      result = target;
--- 3613,3623 ----
        insn_mode = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
      else
  #endif
!       return NULL_RTX;
  
      /* If we don't have POINTER_TYPE, call the function.  */
      if (arg1_align == 0 || arg2_align == 0)
!       return NULL_RTX;
  
      /* Make a place to write the result of the instruction.  */
      result = target;
*************** expand_builtin_memcmp (tree exp ATTRIBUT
*** 3632,3638 ****
    }
  #endif
  
!   return 0;
  }
  
  /* Expand expression EXP, which is a call to the strcmp builtin.  Return 0
--- 3676,3682 ----
    }
  #endif
  
!   return NULL_RTX;
  }
  
  /* Expand expression EXP, which is a call to the strcmp builtin.  Return 0
*************** expand_builtin_memcmp (tree exp ATTRIBUT
*** 3642,3654 ****
  static rtx
  expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
  {
!   tree arglist = TREE_OPERAND (exp, 1);
! 
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
!       tree result = fold_builtin_strcmp (arglist);
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
--- 3686,3697 ----
  static rtx
  expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
  {
!   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
!     return NULL_RTX;
    else
      {
!       tree result = fold_builtin_strcmp (CALL_EXPR_ARG0 (exp),
! 					 CALL_EXPR_ARG1 (exp));
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
*************** expand_builtin_strcmp (tree exp, rtx tar
*** 3661,3668 ****
        rtx result, insn = NULL_RTX;
        tree fndecl, fn;
  
!       tree arg1 = TREE_VALUE (arglist);
!       tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
        int arg1_align
  	= get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
        int arg2_align
--- 3704,3711 ----
        rtx result, insn = NULL_RTX;
        tree fndecl, fn;
  
!       tree arg1 = CALL_EXPR_ARG0 (exp);
!       tree arg2 = CALL_EXPR_ARG1 (exp);
        int arg1_align
  	= get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
        int arg2_align
*************** expand_builtin_strcmp (tree exp, rtx tar
*** 3670,3676 ****
  
        /* If we don't have POINTER_TYPE, call the function.  */
        if (arg1_align == 0 || arg2_align == 0)
! 	return 0;
  
        /* Stabilize the arguments in case gen_cmpstr(n)si fail.  */
        arg1 = builtin_save_expr (arg1);
--- 3713,3719 ----
  
        /* If we don't have POINTER_TYPE, call the function.  */
        if (arg1_align == 0 || arg2_align == 0)
! 	return NULL_RTX;
  
        /* Stabilize the arguments in case gen_cmpstr(n)si fail.  */
        arg1 = builtin_save_expr (arg1);
*************** expand_builtin_strcmp (tree exp, rtx tar
*** 3775,3790 ****
  #ifdef HAVE_cmpstrnsi
      do_libcall:
  #endif
-       arglist = build_tree_list (NULL_TREE, arg2);
-       arglist = tree_cons (NULL_TREE, arg1, arglist);
        fndecl = get_callee_fndecl (exp);
!       fn = build_function_call_expr (fndecl, arglist);
        if (TREE_CODE (fn) == CALL_EXPR)
  	CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
        return expand_call (fn, target, target == const0_rtx);
      }
  #endif
!   return 0;
  }
  
  /* Expand expression EXP, which is a call to the strncmp builtin.  Return 0
--- 3818,3831 ----
  #ifdef HAVE_cmpstrnsi
      do_libcall:
  #endif
        fndecl = get_callee_fndecl (exp);
!       fn = build_call_expr (fndecl, 2, arg1, arg2);
        if (TREE_CODE (fn) == CALL_EXPR)
  	CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
        return expand_call (fn, target, target == const0_rtx);
      }
  #endif
!   return NULL_RTX;
  }
  
  /* Expand expression EXP, which is a call to the strncmp builtin.  Return 0
*************** expand_builtin_strcmp (tree exp, rtx tar
*** 3794,3807 ****
  static rtx
  expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
  {
!   tree arglist = TREE_OPERAND (exp, 1);
! 
!   if (!validate_arglist (arglist,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
!       tree result = fold_builtin_strncmp (arglist);
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
--- 3835,3848 ----
  static rtx
  expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
  {
!   if (!validate_arglist (exp,
  			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return NULL_RTX;
    else
      {
!       tree result = fold_builtin_strncmp (CALL_EXPR_ARG0 (exp),
! 					  CALL_EXPR_ARG1 (exp),
! 					  CALL_EXPR_ARG2 (exp));
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
*************** expand_builtin_strncmp (tree exp, rtx ta
*** 3812,3820 ****
  #ifdef HAVE_cmpstrnsi
    if (HAVE_cmpstrnsi)
    {
!     tree arg1 = TREE_VALUE (arglist);
!     tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
!     tree arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
      tree len, len1, len2;
      rtx arg1_rtx, arg2_rtx, arg3_rtx;
      rtx result, insn;
--- 3853,3861 ----
  #ifdef HAVE_cmpstrnsi
    if (HAVE_cmpstrnsi)
    {
!     tree arg1 = CALL_EXPR_ARG0 (exp);
!     tree arg2 = CALL_EXPR_ARG1 (exp);
!     tree arg3 = CALL_EXPR_ARG2 (exp);
      tree len, len1, len2;
      rtx arg1_rtx, arg2_rtx, arg3_rtx;
      rtx result, insn;
*************** expand_builtin_strncmp (tree exp, rtx ta
*** 3861,3867 ****
  
      /* If both arguments have side effects, we cannot optimize.  */
      if (!len || TREE_SIDE_EFFECTS (len))
!       return 0;
  
      /* The actual new length parameter is MIN(len,arg3).  */
      len = fold_build2 (MIN_EXPR, TREE_TYPE (len), len,
--- 3902,3908 ----
  
      /* If both arguments have side effects, we cannot optimize.  */
      if (!len || TREE_SIDE_EFFECTS (len))
!       return NULL_RTX;
  
      /* The actual new length parameter is MIN(len,arg3).  */
      len = fold_build2 (MIN_EXPR, TREE_TYPE (len), len,
*************** expand_builtin_strncmp (tree exp, rtx ta
*** 3869,3875 ****
  
      /* If we don't have POINTER_TYPE, call the function.  */
      if (arg1_align == 0 || arg2_align == 0)
!       return 0;
  
      /* Make a place to write the result of the instruction.  */
      result = target;
--- 3910,3916 ----
  
      /* If we don't have POINTER_TYPE, call the function.  */
      if (arg1_align == 0 || arg2_align == 0)
!       return NULL_RTX;
  
      /* Make a place to write the result of the instruction.  */
      result = target;
*************** expand_builtin_strncmp (tree exp, rtx ta
*** 3904,3935 ****
  
      /* Expand the library call ourselves using a stabilized argument
         list to avoid re-evaluating the function's arguments twice.  */
-     arglist = build_tree_list (NULL_TREE, len);
-     arglist = tree_cons (NULL_TREE, arg2, arglist);
-     arglist = tree_cons (NULL_TREE, arg1, arglist);
      fndecl = get_callee_fndecl (exp);
!     fn = build_function_call_expr (fndecl, arglist);
      if (TREE_CODE (fn) == CALL_EXPR)
        CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
      return expand_call (fn, target, target == const0_rtx);
    }
  #endif
!   return 0;
  }
  
  /* 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 (tree fndecl, tree arglist, rtx target, enum machine_mode mode)
  {
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
!       tree dst = TREE_VALUE (arglist),
!       src = TREE_VALUE (TREE_CHAIN (arglist));
        const char *p = c_getstr (src);
  
        /* If the string length is zero, return the dst parameter.  */
--- 3945,3973 ----
  
      /* Expand the library call ourselves using a stabilized argument
         list to avoid re-evaluating the function's arguments twice.  */
      fndecl = get_callee_fndecl (exp);
!     fn = build_call_expr (fndecl, 3, arg1, arg2, len);
      if (TREE_CODE (fn) == CALL_EXPR)
        CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
      return expand_call (fn, target, target == const0_rtx);
    }
  #endif
!   return NULL_RTX;
  }
  
  /* Expand expression EXP, which is a call to the strcat builtin.
!    Return NULL_RTX 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 (tree fndecl, tree exp, rtx target, enum machine_mode mode)
  {
!   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
!     return NULL_RTX;
    else
      {
!       tree dst = CALL_EXPR_ARG0 (exp),
!       src = CALL_EXPR_ARG1 (exp);
        const char *p = c_getstr (src);
  
        /* If the string length is zero, return the dst parameter.  */
*************** expand_builtin_strcat (tree fndecl, tree
*** 3945,3974 ****
  
  	  /* Stabilize the argument list.  */
  	  newsrc = builtin_save_expr (src);
- 	  if (newsrc != src)
- 	    arglist = build_tree_list (NULL_TREE, newsrc);
- 	  else
- 	    arglist = TREE_CHAIN (arglist); /* Reusing arglist if safe.  */
- 
  	  dst = builtin_save_expr (dst);
  
  	  start_sequence ();
  
  	  /* Create strlen (dst).  */
! 	  newdst =
! 	    build_function_call_expr (strlen_fn,
! 				      build_tree_list (NULL_TREE, dst));
  	  /* Create (dst + (cast) strlen (dst)).  */
  	  newdst = fold_convert (TREE_TYPE (dst), newdst);
  	  newdst = fold_build2 (PLUS_EXPR, TREE_TYPE (dst), dst, newdst);
  
  	  newdst = builtin_save_expr (newdst);
- 	  arglist = tree_cons (NULL_TREE, newdst, arglist);
  
! 	  if (!expand_builtin_strcpy (fndecl, arglist, target, mode))
  	    {
  	      end_sequence (); /* Stop sequence.  */
! 	      return 0;
  	    }
  
  	  /* Output the entire sequence.  */
--- 3983,4004 ----
  
  	  /* Stabilize the argument list.  */
  	  newsrc = builtin_save_expr (src);
  	  dst = builtin_save_expr (dst);
  
  	  start_sequence ();
  
  	  /* Create strlen (dst).  */
! 	  newdst = build_call_expr (strlen_fn, 1, dst);
  	  /* Create (dst + (cast) strlen (dst)).  */
  	  newdst = fold_convert (TREE_TYPE (dst), newdst);
  	  newdst = fold_build2 (PLUS_EXPR, TREE_TYPE (dst), dst, newdst);
  
  	  newdst = builtin_save_expr (newdst);
  
! 	  if (!expand_builtin_strcpy_args (fndecl, newdst, newsrc, target, mode))
  	    {
  	      end_sequence (); /* Stop sequence.  */
! 	      return NULL_RTX;
  	    }
  
  	  /* Output the entire sequence.  */
*************** expand_builtin_strcat (tree fndecl, tree
*** 3979,4035 ****
  	  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 (tree arglist, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (arglist,
  			POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      {
!       tree result = fold_builtin_strncat (arglist);
        if (result)
  	return expand_expr (result, 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 (tree arglist, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      {
!       tree result = fold_builtin_strspn (arglist);
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
!   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 (tree arglist, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      {
!       tree result = fold_builtin_strcspn (arglist);
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
!   return 0;
  }
  
  /* Expand a call to __builtin_saveregs, generating the result in TARGET,
--- 4009,4069 ----
  	  return expand_expr (dst, target, mode, EXPAND_NORMAL);
  	}
  
!       return NULL_RTX;
      }
  }
  
  /* Expand expression EXP, which is a call to the strncat builtin.
!    Return NULL_RTX 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 (tree exp, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (exp,
  			POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      {
!       tree result = fold_builtin_strncat (CALL_EXPR_ARG0 (exp),
! 					  CALL_EXPR_ARG1 (exp),
! 					  CALL_EXPR_ARG2 (exp));
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
!   return NULL_RTX;
  }
  
  /* Expand expression EXP, which is a call to the strspn builtin.
!    Return NULL_RTX 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 (tree exp, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      {
!       tree result = fold_builtin_strspn (CALL_EXPR_ARG0 (exp),
! 					 CALL_EXPR_ARG1 (exp));
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
!   return NULL_RTX;
  }
  
  /* Expand expression EXP, which is a call to the strcspn builtin.
!    Return NULL_RTX 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 (tree exp, rtx target, enum machine_mode mode)
  {
!   if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      {
!       tree result = fold_builtin_strcspn (CALL_EXPR_ARG0 (exp),
! 					  CALL_EXPR_ARG1 (exp));
        if (result)
  	return expand_expr (result, target, mode, EXPAND_NORMAL);
      }
!   return NULL_RTX;
  }
  
  /* Expand a call to __builtin_saveregs, generating the result in TARGET,
*************** expand_builtin_saveregs (void)
*** 4074,4093 ****
     is controlled by the definition of CUMULATIVE_ARGS.  */
  
  static rtx
! expand_builtin_args_info (tree arglist)
  {
    int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
    int *word_ptr = (int *) &current_function_args_info;
  
    gcc_assert (sizeof (CUMULATIVE_ARGS) % sizeof (int) == 0);
  
!   if (arglist != 0)
      {
!       if (!host_integerp (TREE_VALUE (arglist), 0))
  	error ("argument of %<__builtin_args_info%> must be constant");
        else
  	{
! 	  HOST_WIDE_INT wordnum = tree_low_cst (TREE_VALUE (arglist), 0);
  
  	  if (wordnum < 0 || wordnum >= nwords)
  	    error ("argument of %<__builtin_args_info%> out of range");
--- 4108,4127 ----
     is controlled by the definition of CUMULATIVE_ARGS.  */
  
  static rtx
! expand_builtin_args_info (tree exp)
  {
    int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
    int *word_ptr = (int *) &current_function_args_info;
  
    gcc_assert (sizeof (CUMULATIVE_ARGS) % sizeof (int) == 0);
  
!   if (call_expr_nargs (exp) != 0)
      {
!       if (!host_integerp (CALL_EXPR_ARG0 (exp), 0))
  	error ("argument of %<__builtin_args_info%> must be constant");
        else
  	{
! 	  HOST_WIDE_INT wordnum = tree_low_cst (CALL_EXPR_ARG0 (exp), 0);
  
  	  if (wordnum < 0 || wordnum >= nwords)
  	    error ("argument of %<__builtin_args_info%> out of range");
*************** std_expand_builtin_va_start (tree valist
*** 4180,4206 ****
    expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
  }
  
! /* Expand ARGLIST, from a call to __builtin_va_start.  */
  
  static rtx
! expand_builtin_va_start (tree arglist)
  {
    rtx nextarg;
!   tree chain, valist;
  
!   chain = TREE_CHAIN (arglist);
! 
!   if (!chain)
      {
        error ("too few arguments to function %<va_start%>");
        return const0_rtx;
      }
  
!   if (fold_builtin_next_arg (chain))
      return const0_rtx;
  
    nextarg = expand_builtin_next_arg ();
!   valist = stabilize_va_list (TREE_VALUE (arglist), 1);
  
  #ifdef EXPAND_BUILTIN_VA_START
    EXPAND_BUILTIN_VA_START (valist, nextarg);
--- 4214,4238 ----
    expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
  }
  
! /* Expand EXP, a call to __builtin_va_start.  */
  
  static rtx
! expand_builtin_va_start (tree exp)
  {
    rtx nextarg;
!   tree valist;
  
!   if (call_expr_nargs (exp) < 2)
      {
        error ("too few arguments to function %<va_start%>");
        return const0_rtx;
      }
  
!   if (fold_builtin_next_arg (exp, true))
      return const0_rtx;
  
    nextarg = expand_builtin_next_arg ();
!   valist = stabilize_va_list (CALL_EXPR_ARG0 (exp), 1);
  
  #ifdef EXPAND_BUILTIN_VA_START
    EXPAND_BUILTIN_VA_START (valist, nextarg);
*************** gimplify_va_arg_expr (tree *expr_p, tree
*** 4382,4389 ****
        /* We can, however, treat "undefined" any way we please.
  	 Call abort to encourage the user to fix the program.  */
        inform ("if this code is reached, the program will abort");
!       t = build_function_call_expr (implicit_built_in_decls[BUILT_IN_TRAP],
! 				    NULL);
        append_to_statement_list (t, pre_p);
  
        /* This is dead code, but go ahead and finish so that the
--- 4414,4420 ----
        /* We can, however, treat "undefined" any way we please.
  	 Call abort to encourage the user to fix the program.  */
        inform ("if this code is reached, the program will abort");
!       t = build_call_expr (implicit_built_in_decls[BUILT_IN_TRAP], 0);
        append_to_statement_list (t, pre_p);
  
        /* This is dead code, but go ahead and finish so that the
*************** gimplify_va_arg_expr (tree *expr_p, tree
*** 4421,4432 ****
      }
  }
  
! /* Expand ARGLIST, from a call to __builtin_va_end.  */
  
  static rtx
! expand_builtin_va_end (tree arglist)
  {
!   tree valist = TREE_VALUE (arglist);
  
    /* Evaluate for side effects, if needed.  I hate macros that don't
       do that.  */
--- 4452,4463 ----
      }
  }
  
! /* Expand EXP, a call to __builtin_va_end.  */
  
  static rtx
! expand_builtin_va_end (tree exp)
  {
!   tree valist = CALL_EXPR_ARG0 (exp);
  
    /* Evaluate for side effects, if needed.  I hate macros that don't
       do that.  */
*************** expand_builtin_va_end (tree arglist)
*** 4436,4452 ****
    return const0_rtx;
  }
  
! /* Expand ARGLIST, from a call to __builtin_va_copy.  We do this as a
     builtin rather than just as an assignment in stdarg.h because of the
     nastiness of array-type va_list types.  */
  
  static rtx
! expand_builtin_va_copy (tree arglist)
  {
    tree dst, src, t;
  
!   dst = TREE_VALUE (arglist);
!   src = TREE_VALUE (TREE_CHAIN (arglist));
  
    dst = stabilize_va_list (dst, 1);
    src = stabilize_va_list (src, 0);
--- 4467,4483 ----
    return const0_rtx;
  }
  
! /* Expand EXP, a call to __builtin_va_copy.  We do this as a
     builtin rather than just as an assignment in stdarg.h because of the
     nastiness of array-type va_list types.  */
  
  static rtx
! expand_builtin_va_copy (tree exp)
  {
    tree dst, src, t;
  
!   dst = CALL_EXPR_ARG0 (exp);
!   src = CALL_EXPR_ARG1 (exp);
  
    dst = stabilize_va_list (dst, 1);
    src = stabilize_va_list (src, 0);
*************** expand_builtin_va_copy (tree arglist)
*** 4489,4503 ****
     __builtin_return_address.  */
  
  static rtx
! expand_builtin_frame_address (tree fndecl, tree arglist)
  {
    /* The argument must be a nonnegative integer constant.
       It counts the number of frames to scan up the stack.
       The value is the return address saved in that frame.  */
!   if (arglist == 0)
      /* Warning about missing arg was already issued.  */
      return const0_rtx;
!   else if (! host_integerp (TREE_VALUE (arglist), 1))
      {
        if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
  	error ("invalid argument to %<__builtin_frame_address%>");
--- 4520,4534 ----
     __builtin_return_address.  */
  
  static rtx
! expand_builtin_frame_address (tree fndecl, tree exp)
  {
    /* The argument must be a nonnegative integer constant.
       It counts the number of frames to scan up the stack.
       The value is the return address saved in that frame.  */
!   if (call_expr_nargs (exp) == 0)
      /* Warning about missing arg was already issued.  */
      return const0_rtx;
!   else if (! host_integerp (CALL_EXPR_ARG0 (exp), 1))
      {
        if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
  	error ("invalid argument to %<__builtin_frame_address%>");
*************** expand_builtin_frame_address (tree fndec
*** 4509,4515 ****
      {
        rtx tem
  	= expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl),
! 				      tree_low_cst (TREE_VALUE (arglist), 1));
  
        /* Some ports cannot access arbitrary stack frames.  */
        if (tem == NULL)
--- 4540,4546 ----
      {
        rtx tem
  	= expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl),
! 				      tree_low_cst (CALL_EXPR_ARG0 (exp), 1));
  
        /* Some ports cannot access arbitrary stack frames.  */
        if (tem == NULL)
*************** expand_builtin_frame_address (tree fndec
*** 4532,4543 ****
      }
  }
  
! /* Expand a call to the alloca builtin, with arguments ARGLIST.  Return 0 if
     we failed and the caller should emit a normal call, otherwise try to get
     the result in TARGET, if convenient.  */
  
  static rtx
! expand_builtin_alloca (tree arglist, rtx target)
  {
    rtx op0;
    rtx result;
--- 4563,4574 ----
      }
  }
  
! /* Expand EXP, a call to the alloca builtin.  Return NULL_RTX if
     we failed and the caller should emit a normal call, otherwise try to get
     the result in TARGET, if convenient.  */
  
  static rtx
! expand_builtin_alloca (tree exp, rtx target)
  {
    rtx op0;
    rtx result;
*************** expand_builtin_alloca (tree arglist, rtx
*** 4546,4558 ****
       should always expand to function calls.  These can be intercepted
       in libmudflap.  */
    if (flag_mudflap)
!     return 0;
  
!   if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
!     return 0;
  
    /* Compute the argument.  */
!   op0 = expand_normal (TREE_VALUE (arglist));
  
    /* Allocate the desired space.  */
    result = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
--- 4577,4589 ----
       should always expand to function calls.  These can be intercepted
       in libmudflap.  */
    if (flag_mudflap)
!     return NULL_RTX;
  
!   if (!validate_arglist (exp, INTEGER_TYPE, VOID_TYPE))
!     return NULL_RTX;
  
    /* Compute the argument.  */
!   op0 = expand_normal (CALL_EXPR_ARG0 (exp));
  
    /* Allocate the desired space.  */
    result = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
*************** expand_builtin_alloca (tree arglist, rtx
*** 4561,4584 ****
    return result;
  }
  
! /* Expand a call to a unary builtin.  The arguments are in ARGLIST.
!    Return 0 if a normal call should be emitted rather than expanding the
     function in-line.  If convenient, the result should be placed in TARGET.
     SUBTARGET may be used as the target for computing one of EXP's operands.  */
  
  static rtx
! expand_builtin_unop (enum machine_mode target_mode, tree arglist, rtx target,
  		     rtx subtarget, optab op_optab)
  {
    rtx op0;
!   if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
!     return 0;
  
    /* Compute the argument.  */
!   op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
    /* Compute op, into TARGET if possible.
       Set TARGET to wherever the result comes back.  */
!   target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
  			op_optab, op0, target, 1);
    gcc_assert (target);
  
--- 4592,4615 ----
    return result;
  }
  
! /* Expand a call to a unary builtin in EXP.
!    Return NULL_RTX if a normal call should be emitted rather than expanding the
     function in-line.  If convenient, the result should be placed in TARGET.
     SUBTARGET may be used as the target for computing one of EXP's operands.  */
  
  static rtx
! expand_builtin_unop (enum machine_mode target_mode, tree exp, rtx target,
  		     rtx subtarget, optab op_optab)
  {
    rtx op0;
!   if (!validate_arglist (exp, INTEGER_TYPE, VOID_TYPE))
!     return NULL_RTX;
  
    /* Compute the argument.  */
!   op0 = expand_expr (CALL_EXPR_ARG0 (exp), subtarget, VOIDmode, 0);
    /* Compute op, into TARGET if possible.
       Set TARGET to wherever the result comes back.  */
!   target = expand_unop (TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG0 (exp))),
  			op_optab, op0, target, 1);
    gcc_assert (target);
  
*************** expand_builtin_unop (enum machine_mode t
*** 4589,4605 ****
     long, we attempt to transform this call into __builtin_fputc().  */
  
  static rtx
! expand_builtin_fputs (tree arglist, rtx target, bool unlocked)
  {
    /* Verify the arguments in the original call.  */
!   if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      {
!       tree result = fold_builtin_fputs (arglist, (target == const0_rtx),
  					unlocked, NULL_TREE);
        if (result)
  	return expand_expr (result, target, VOIDmode, EXPAND_NORMAL);
      }
!   return 0;
  }
  
  /* Expand a call to __builtin_expect.  We return our argument and emit a
--- 4620,4638 ----
     long, we attempt to transform this call into __builtin_fputc().  */
  
  static rtx
! expand_builtin_fputs (tree exp, rtx target, bool unlocked)
  {
    /* Verify the arguments in the original call.  */
!   if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
      {
!       tree result = fold_builtin_fputs (CALL_EXPR_ARG0 (exp),
! 					CALL_EXPR_ARG1 (exp),
! 					(target == const0_rtx),
  					unlocked, NULL_TREE);
        if (result)
  	return expand_expr (result, target, VOIDmode, EXPAND_NORMAL);
      }
!   return NULL_RTX;
  }
  
  /* Expand a call to __builtin_expect.  We return our argument and emit a
*************** expand_builtin_fputs (tree arglist, rtx 
*** 4607,4622 ****
     a non-jump context.  */
  
  static rtx
! expand_builtin_expect (tree arglist, rtx target)
  {
!   tree exp, c;
    rtx note, rtx_c;
  
!   if (arglist == NULL_TREE
!       || TREE_CHAIN (arglist) == NULL_TREE)
      return const0_rtx;
!   exp = TREE_VALUE (arglist);
!   c = TREE_VALUE (TREE_CHAIN (arglist));
  
    if (TREE_CODE (c) != INTEGER_CST)
      {
--- 4640,4654 ----
     a non-jump context.  */
  
  static rtx
! expand_builtin_expect (tree exp, rtx target)
  {
!   tree arg, c;
    rtx note, rtx_c;
  
!   if (call_expr_nargs (exp) < 2)
      return const0_rtx;
!   arg = CALL_EXPR_ARG0 (exp);
!   c = CALL_EXPR_ARG1 (exp);
  
    if (TREE_CODE (c) != INTEGER_CST)
      {
*************** expand_builtin_expect (tree arglist, rtx
*** 4624,4630 ****
        c = integer_zero_node;
      }
  
!   target = expand_expr (exp, target, VOIDmode, EXPAND_NORMAL);
  
    /* Don't bother with expected value notes for integral constants.  */
    if (flag_guess_branch_prob && GET_CODE (target) != CONST_INT)
--- 4656,4662 ----
        c = integer_zero_node;
      }
  
!   target = expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
  
    /* Don't bother with expected value notes for integral constants.  */
    if (flag_guess_branch_prob && GET_CODE (target) != CONST_INT)
*************** expand_builtin_expect (tree arglist, rtx
*** 4653,4661 ****
  rtx
  expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label)
  {
!   tree arglist = TREE_OPERAND (exp, 1);
!   tree arg0 = TREE_VALUE (arglist);
!   tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
    rtx ret = NULL_RTX;
  
    /* Only handle __builtin_expect (test, 0) and
--- 4685,4692 ----
  rtx
  expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label)
  {
!   tree arg0 = CALL_EXPR_ARG0 (exp);
!   tree arg1 = CALL_EXPR_ARG1 (exp);
    rtx ret = NULL_RTX;
  
    /* Only handle __builtin_expect (test, 0) and
*************** expand_builtin_trap (void)
*** 4773,4818 ****
    emit_barrier ();
  }
  
! /* Expand a call to fabs, fabsf or fabsl with arguments ARGLIST.
!    Return 0 if a normal call should be emitted rather than expanding
     the function inline.  If convenient, the result should be placed
     in TARGET.  SUBTARGET may be used as the target for computing
     the operand.  */
  
  static rtx
! expand_builtin_fabs (tree arglist, rtx target, rtx subtarget)
  {
    enum machine_mode mode;
    tree arg;
    rtx op0;
  
!   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
!     return 0;
  
!   arg = TREE_VALUE (arglist);
    mode = TYPE_MODE (TREE_TYPE (arg));
    op0 = expand_expr (arg, subtarget, VOIDmode, 0);
    return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1));
  }
  
! /* Expand a call to copysign, copysignf, or copysignl with arguments ARGLIST.
     Return NULL is a normal call should be emitted rather than expanding the
     function inline.  If convenient, the result should be placed in TARGET.
     SUBTARGET may be used as the target for computing the operand.  */
  
  static rtx
! expand_builtin_copysign (tree arglist, rtx target, rtx subtarget)
  {
    rtx op0, op1;
    tree arg;
  
!   if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
!     return 0;
  
!   arg = TREE_VALUE (arglist);
    op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
  
!   arg = TREE_VALUE (TREE_CHAIN (arglist));
    op1 = expand_normal (arg);
  
    return expand_copysign (op0, op1, target);
--- 4804,4849 ----
    emit_barrier ();
  }
  
! /* Expand EXP, a call to fabs, fabsf or fabsl.
!    Return NULL_RTX if a normal call should be emitted rather than expanding
     the function inline.  If convenient, the result should be placed
     in TARGET.  SUBTARGET may be used as the target for computing
     the operand.  */
  
  static rtx
! expand_builtin_fabs (tree exp, rtx target, rtx subtarget)
  {
    enum machine_mode mode;
    tree arg;
    rtx op0;
  
!   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
!     return NULL_RTX;
  
!   arg = CALL_EXPR_ARG0 (exp);
    mode = TYPE_MODE (TREE_TYPE (arg));
    op0 = expand_expr (arg, subtarget, VOIDmode, 0);
    return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1));
  }
  
! /* Expand EXP, a call to copysign, copysignf, or copysignl.
     Return NULL is a normal call should be emitted rather than expanding the
     function inline.  If convenient, the result should be placed in TARGET.
     SUBTARGET may be used as the target for computing the operand.  */
  
  static rtx
! expand_builtin_copysign (tree exp, rtx target, rtx subtarget)
  {
    rtx op0, op1;
    tree arg;
  
!   if (!validate_arglist (exp, REAL_TYPE, REAL_TYPE, VOID_TYPE))
!     return NULL_RTX;
  
!   arg = CALL_EXPR_ARG0 (exp);
    op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
  
!   arg = CALL_EXPR_ARG1 (exp);
    op1 = expand_normal (arg);
  
    return expand_copysign (op0, op1, target);
*************** build_string_literal (int len, const cha
*** 4844,4850 ****
  }
  
  /* Expand EXP, a call to printf or printf_unlocked.
!    Return 0 if a normal call should be emitted rather than transforming
     the function inline.  If convenient, the result should be placed in
     TARGET with mode MODE.  UNLOCKED indicates this is a printf_unlocked
     call.  */
--- 4875,4881 ----
  }
  
  /* Expand EXP, a call to printf or printf_unlocked.
!    Return NULL_RTX if a normal call should be emitted rather than transforming
     the function inline.  If convenient, the result should be placed in
     TARGET with mode MODE.  UNLOCKED indicates this is a printf_unlocked
     call.  */
*************** static rtx
*** 4852,4858 ****
  expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
  		       bool unlocked)
  {
-   tree arglist = TREE_OPERAND (exp, 1);
    /* If we're using an unlocked function, assume the other unlocked
       functions exist explicitly.  */
    tree const fn_putchar = unlocked ? built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED]
--- 4883,4888 ----
*************** expand_builtin_printf (tree exp, rtx tar
*** 4860,4913 ****
    tree const fn_puts = unlocked ? built_in_decls[BUILT_IN_PUTS_UNLOCKED]
      : implicit_built_in_decls[BUILT_IN_PUTS];
    const char *fmt_str;
!   tree fn, fmt, arg;
  
    /* If the return value is used, don't do the transformation.  */
    if (target != const0_rtx)
!     return 0;
  
    /* Verify the required arguments in the original call.  */
!   if (! arglist)
!     return 0;
!   fmt = TREE_VALUE (arglist);
    if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
!     return 0;
!   arglist = TREE_CHAIN (arglist);
  
    /* Check whether the format is a literal string constant.  */
    fmt_str = c_getstr (fmt);
    if (fmt_str == NULL)
!     return 0;
  
    if (!init_target_chars())
!     return 0;
  
    /* If the format specifier was "%s\n", call __builtin_puts(arg).  */
    if (strcmp (fmt_str, target_percent_s_newline) == 0)
      {
!       if (! arglist
! 	  || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
! 	  || TREE_CHAIN (arglist))
! 	return 0;
!       fn = fn_puts;
      }
    /* If the format specifier was "%c", call __builtin_putchar(arg).  */
    else if (strcmp (fmt_str, target_percent_c) == 0)
      {
!       if (! arglist
! 	  || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
! 	  || TREE_CHAIN (arglist))
! 	return 0;
!       fn = fn_putchar;
      }
    else
      {
        /* We can't handle anything else with % args or %% ... yet.  */
        if (strchr (fmt_str, target_percent))
! 	return 0;
  
!       if (arglist)
! 	return 0;
  
        /* If the format specifier was "", printf does nothing.  */
        if (fmt_str[0] == '\0')
--- 4890,4944 ----
    tree const fn_puts = unlocked ? built_in_decls[BUILT_IN_PUTS_UNLOCKED]
      : implicit_built_in_decls[BUILT_IN_PUTS];
    const char *fmt_str;
!   tree fn = 0;
!   tree fmt, arg;
!   int nargs = call_expr_nargs (exp);
  
    /* If the return value is used, don't do the transformation.  */
    if (target != const0_rtx)
!     return NULL_RTX;
  
    /* Verify the required arguments in the original call.  */
!   if (nargs == 0)
!     return NULL_RTX;
!   fmt = CALL_EXPR_ARG0 (exp);
    if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
!     return NULL_RTX;
  
    /* Check whether the format is a literal string constant.  */
    fmt_str = c_getstr (fmt);
    if (fmt_str == NULL)
!     return NULL_RTX;
  
    if (!init_target_chars())
!     return NULL_RTX;
  
    /* If the format specifier was "%s\n", call __builtin_puts(arg).  */
    if (strcmp (fmt_str, target_percent_s_newline) == 0)
      {
!       if ((nargs != 2)
! 	  || ! POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_ARG1 (exp))))
! 	return NULL_RTX;
!       if (fn_puts)
! 	fn = build_call_expr (fn_puts, 1, CALL_EXPR_ARG1 (exp));
      }
    /* If the format specifier was "%c", call __builtin_putchar(arg).  */
    else if (strcmp (fmt_str, target_percent_c) == 0)
      {
!       if ((nargs != 2)
! 	  || TREE_CODE (TREE_TYPE (CALL_EXPR_ARG1 (exp))) != INTEGER_TYPE)
! 	return NULL_RTX;
!       if (fn_putchar)
! 	fn = build_call_expr (fn_putchar, 1, CALL_EXPR_ARG1 (exp));
      }
    else
      {
        /* We can't handle anything else with % args or %% ... yet.  */
        if (strchr (fmt_str, target_percent))
! 	return NULL_RTX;
  
!       if (nargs > 1)
! 	return NULL_RTX;
  
        /* If the format specifier was "", printf does nothing.  */
        if (fmt_str[0] == '\0')
*************** expand_builtin_printf (tree exp, rtx tar
*** 4919,4926 ****
  	     convert "c"[0] to an int and pass that to the replacement
  	     function.  */
  	  arg = build_int_cst (NULL_TREE, fmt_str[0]);
! 	  arglist = build_tree_list (NULL_TREE, arg);
! 	  fn = fn_putchar;
  	}
        else
  	{
--- 4950,4957 ----
  	     convert "c"[0] to an int and pass that to the replacement
  	     function.  */
  	  arg = build_int_cst (NULL_TREE, fmt_str[0]);
! 	  if (fn_putchar)
! 	    fn = build_call_expr (fn_putchar, 1, arg);
  	}
        else
  	{
*************** expand_builtin_printf (tree exp, rtx tar
*** 4933,4960 ****
  	      char *newstr = alloca (len);
  	      memcpy (newstr, fmt_str, len - 1);
  	      newstr[len - 1] = 0;
- 
  	      arg = build_string_literal (len, newstr);
! 	      arglist = build_tree_list (NULL_TREE, arg);
! 	      fn = fn_puts;
  	    }
  	  else
  	    /* We'd like to arrange to call fputs(string,stdout) here,
  	       but we need stdout and don't have a way to get it yet.  */
! 	    return 0;
  	}
      }
  
    if (!fn)
!     return 0;
!   fn = build_function_call_expr (fn, arglist);
    if (TREE_CODE (fn) == CALL_EXPR)
      CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
    return expand_expr (fn, target, mode, EXPAND_NORMAL);
  }
  
  /* Expand EXP, a call to fprintf or fprintf_unlocked.
!    Return 0 if a normal call should be emitted rather than transforming
     the function inline.  If convenient, the result should be placed in
     TARGET with mode MODE.  UNLOCKED indicates this is a fprintf_unlocked
     call.  */
--- 4964,4989 ----
  	      char *newstr = alloca (len);
  	      memcpy (newstr, fmt_str, len - 1);
  	      newstr[len - 1] = 0;
  	      arg = build_string_literal (len, newstr);
! 	      if (fn_puts)
! 		fn = build_call_expr (fn_puts, 1, arg);
  	    }
  	  else
  	    /* We'd like to arrange to call fputs(string,stdout) here,
  	       but we need stdout and don't have a way to get it yet.  */
! 	    return NULL_RTX;
  	}
      }
  
    if (!fn)
!     return NULL_RTX;
    if (TREE_CODE (fn) == CALL_EXPR)
      CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
    return expand_expr (fn, target, mode, EXPAND_NORMAL);
  }
  
  /* Expand EXP, a call to fprintf or fprintf_unlocked.
!    Return NULL_RTX if a normal call should be emitted rather than transforming
     the function inline.  If convenient, the result should be placed in
     TARGET with mode MODE.  UNLOCKED indicates this is a fprintf_unlocked
     call.  */
*************** static rtx
*** 4962,4968 ****
  expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode,
  			bool unlocked)
  {
-   tree arglist = TREE_OPERAND (exp, 1);
    /* If we're using an unlocked function, assume the other unlocked
       functions exist explicitly.  */
    tree const fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
--- 4991,4996 ----
*************** expand_builtin_fprintf (tree exp, rtx ta
*** 4970,5035 ****
    tree const fn_fputs = unlocked ? built_in_decls[BUILT_IN_FPUTS_UNLOCKED]
      : implicit_built_in_decls[BUILT_IN_FPUTS];
    const char *fmt_str;
!   tree fn, fmt, fp, arg;
  
    /* If the return value is used, don't do the transformation.  */
    if (target != const0_rtx)
!     return 0;
  
    /* Verify the required arguments in the original call.  */
!   if (! arglist)
!     return 0;
!   fp = TREE_VALUE (arglist);
    if (! POINTER_TYPE_P (TREE_TYPE (fp)))
!     return 0;
!   arglist = TREE_CHAIN (arglist);
!   if (! arglist)
!     return 0;
!   fmt = TREE_VALUE (arglist);
    if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
!     return 0;
!   arglist = TREE_CHAIN (arglist);
  
    /* Check whether the format is a literal string constant.  */
    fmt_str = c_getstr (fmt);
    if (fmt_str == NULL)
!     return 0;
  
    if (!init_target_chars())
!     return 0;
  
    /* If the format specifier was "%s", call __builtin_fputs(arg,fp).  */
    if (strcmp (fmt_str, target_percent_s) == 0)
      {
!       if (! arglist
! 	  || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
! 	  || TREE_CHAIN (arglist))
! 	return 0;
!       arg = TREE_VALUE (arglist);
!       arglist = build_tree_list (NULL_TREE, fp);
!       arglist = tree_cons (NULL_TREE, arg, arglist);
!       fn = fn_fputs;
      }
    /* If the format specifier was "%c", call __builtin_fputc(arg,fp).  */
    else if (strcmp (fmt_str, target_percent_c) == 0)
      {
!       if (! arglist
! 	  || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
! 	  || TREE_CHAIN (arglist))
! 	return 0;
!       arg = TREE_VALUE (arglist);
!       arglist = build_tree_list (NULL_TREE, fp);
!       arglist = tree_cons (NULL_TREE, arg, arglist);
!       fn = fn_fputc;
      }
    else
      {
        /* We can't handle anything else with % args or %% ... yet.  */
        if (strchr (fmt_str, target_percent))
! 	return 0;
  
!       if (arglist)
! 	return 0;
  
        /* If the format specifier was "", fprintf does nothing.  */
        if (fmt_str[0] == '\0')
--- 4998,5057 ----
    tree const fn_fputs = unlocked ? built_in_decls[BUILT_IN_FPUTS_UNLOCKED]
      : implicit_built_in_decls[BUILT_IN_FPUTS];
    const char *fmt_str;
!   tree fn = 0;
!   tree fmt, fp, arg;
!   int nargs = call_expr_nargs (exp);
  
    /* If the return value is used, don't do the transformation.  */
    if (target != const0_rtx)
!     return NULL_RTX;
  
    /* Verify the required arguments in the original call.  */
!   if (nargs < 2)
!     return NULL_RTX;
!   fp = CALL_EXPR_ARG0 (exp);
    if (! POINTER_TYPE_P (TREE_TYPE (fp)))
!     return NULL_RTX;
!   fmt = CALL_EXPR_ARG1 (exp);
    if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
!     return NULL_RTX;
  
    /* Check whether the format is a literal string constant.  */
    fmt_str = c_getstr (fmt);
    if (fmt_str == NULL)
!     return NULL_RTX;
  
    if (!init_target_chars())
!     return NULL_RTX;
  
    /* If the format specifier was "%s", call __builtin_fputs(arg,fp).  */
    if (strcmp (fmt_str, target_percent_s) == 0)
      {
!       if ((nargs != 3)
! 	  || ! POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_ARG2 (exp))))
! 	return NULL_RTX;
!       arg = CALL_EXPR_ARG2 (exp);
!       if (fn_fputs)
! 	fn = build_call_expr (fn_fputs, 2, arg, fp);
      }
    /* If the format specifier was "%c", call __builtin_fputc(arg,fp).  */
    else if (strcmp (fmt_str, target_percent_c) == 0)
      {
!       if ((nargs != 3)
! 	  || TREE_CODE (TREE_TYPE (CALL_EXPR_ARG2 (exp))) != INTEGER_TYPE)
! 	return NULL_RTX;
!       arg = CALL_EXPR_ARG2 (exp);
!       if (fn_fputc)
! 	fn = build_call_expr (fn_fputc, 2, arg, fp);
      }
    else
      {
        /* We can't handle anything else with % args or %% ... yet.  */
        if (strchr (fmt_str, target_percent))
! 	return NULL_RTX;
  
!       if (nargs > 2)
! 	return NULL_RTX;
  
        /* If the format specifier was "", fprintf does nothing.  */
        if (fmt_str[0] == '\0')
*************** expand_builtin_fprintf (tree exp, rtx ta
*** 5042,5094 ****
        /* When "string" doesn't contain %, replace all cases of
  	 fprintf(stream,string) with fputs(string,stream).  The fputs
  	 builtin will take care of special cases like length == 1.  */
!       arglist = build_tree_list (NULL_TREE, fp);
!       arglist = tree_cons (NULL_TREE, fmt, arglist);
!       fn = fn_fputs;
      }
  
    if (!fn)
!     return 0;
!   fn = build_function_call_expr (fn, arglist);
    if (TREE_CODE (fn) == CALL_EXPR)
      CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
    return expand_expr (fn, target, mode, EXPAND_NORMAL);
  }
  
! /* Expand a call to sprintf with argument list ARGLIST.  Return 0 if
     a normal call should be emitted rather than expanding the function
     inline.  If convenient, the result should be placed in TARGET with
     mode MODE.  */
  
  static rtx
! expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode)
  {
!   tree orig_arglist, dest, fmt;
    const char *fmt_str;
! 
!   orig_arglist = arglist;
  
    /* Verify the required arguments in the original call.  */
!   if (! arglist)
!     return 0;
!   dest = TREE_VALUE (arglist);
    if (! POINTER_TYPE_P (TREE_TYPE (dest)))
!     return 0;
!   arglist = TREE_CHAIN (arglist);
!   if (! arglist)
!     return 0;
!   fmt = TREE_VALUE (arglist);
    if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
!     return 0;
!   arglist = TREE_CHAIN (arglist);
  
    /* Check whether the format is a literal string constant.  */
    fmt_str = c_getstr (fmt);
    if (fmt_str == NULL)
!     return 0;
  
    if (!init_target_chars())
!     return 0;
  
    /* If the format doesn't contain % args or %%, use strcpy.  */
    if (strchr (fmt_str, target_percent) == 0)
--- 5064,5109 ----
        /* When "string" doesn't contain %, replace all cases of
  	 fprintf(stream,string) with fputs(string,stream).  The fputs
  	 builtin will take care of special cases like length == 1.  */
!       if (fn_fputs)
! 	fn = build_call_expr (fn_fputs, 2, fmt, fp);
      }
  
    if (!fn)
!     return NULL_RTX;
    if (TREE_CODE (fn) == CALL_EXPR)
      CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
    return expand_expr (fn, target, mode, EXPAND_NORMAL);
  }
  
! /* Expand a call EXP to sprintf.  Return NULL_RTX if
     a normal call should be emitted rather than expanding the function
     inline.  If convenient, the result should be placed in TARGET with
     mode MODE.  */
  
  static rtx
! expand_builtin_sprintf (tree exp, rtx target, enum machine_mode mode)
  {
!   tree dest, fmt;
    const char *fmt_str;
!   int nargs = call_expr_nargs (exp);
  
    /* Verify the required arguments in the original call.  */
!   if (nargs < 2)
!     return NULL_RTX;
!   dest = CALL_EXPR_ARG0 (exp);
    if (! POINTER_TYPE_P (TREE_TYPE (dest)))
!     return NULL_RTX;
!   fmt = CALL_EXPR_ARG0 (exp);
    if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
!     return NULL_RTX;
  
    /* Check whether the format is a literal string constant.  */
    fmt_str = c_getstr (fmt);
    if (fmt_str == NULL)
!     return NULL_RTX;
  
    if (!init_target_chars())
!     return NULL_RTX;
  
    /* If the format doesn't contain % args or %%, use strcpy.  */
    if (strchr (fmt_str, target_percent) == 0)
*************** expand_builtin_sprintf (tree arglist, rt
*** 5096,5104 ****
        tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
        tree exp;
  
!       if (arglist || ! fn)
! 	return 0;
!       expand_expr (build_function_call_expr (fn, orig_arglist),
  		   const0_rtx, VOIDmode, EXPAND_NORMAL);
        if (target == const0_rtx)
  	return const0_rtx;
--- 5111,5119 ----
        tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
        tree exp;
  
!       if ((nargs > 2) || ! fn)
! 	return NULL_RTX;
!       expand_expr (build_call_expr (fn, 2, dest, fmt),
  		   const0_rtx, VOIDmode, EXPAND_NORMAL);
        if (target == const0_rtx)
  	return const0_rtx;
*************** expand_builtin_sprintf (tree arglist, rt
*** 5112,5137 ****
        fn = implicit_built_in_decls[BUILT_IN_STRCPY];
  
        if (! fn)
! 	return 0;
! 
!       if (! arglist || TREE_CHAIN (arglist))
! 	return 0;
!       arg = TREE_VALUE (arglist);
        if (! POINTER_TYPE_P (TREE_TYPE (arg)))
! 	return 0;
  
        if (target != const0_rtx)
  	{
  	  len = c_strlen (arg, 1);
  	  if (! len || TREE_CODE (len) != INTEGER_CST)
! 	    return 0;
  	}
        else
  	len = NULL_TREE;
  
!       arglist = build_tree_list (NULL_TREE, arg);
!       arglist = tree_cons (NULL_TREE, dest, arglist);
!       expand_expr (build_function_call_expr (fn, arglist),
  		   const0_rtx, VOIDmode, EXPAND_NORMAL);
  
        if (target == const0_rtx)
--- 5127,5149 ----
        fn = implicit_built_in_decls[BUILT_IN_STRCPY];
  
        if (! fn)
! 	return NULL_RTX;
!       if (nargs != 3)
! 	return NULL_RTX;
!       arg = CALL_EXPR_ARG2 (exp);
        if (! POINTER_TYPE_P (TREE_TYPE (arg)))
! 	return NULL_RTX;
  
        if (target != const0_rtx)
  	{
  	  len = c_strlen (arg, 1);
  	  if (! len || TREE_CODE (len) != INTEGER_CST)
! 	    return NULL_RTX;
  	}
        else
  	len = NULL_TREE;
  
!       expand_expr (build_call_expr (fn, 2, dest, arg),
  		   const0_rtx, VOIDmode, EXPAND_NORMAL);
  
        if (target == const0_rtx)
*************** expand_builtin_sprintf (tree arglist, rt
*** 5139,5145 ****
        return expand_expr (len, target, mode, EXPAND_NORMAL);
      }
  
!   return 0;
  }
  
  /* Expand a call to either the entry or exit function profiler.  */
--- 5151,5157 ----
        return expand_expr (len, target, mode, EXPAND_NORMAL);
      }
  
!   return NULL_RTX;
  }
  
  /* Expand a call to either the entry or exit function profiler.  */
*************** round_trampoline_addr (rtx tramp)
*** 5192,5198 ****
  }
  
  static rtx
! expand_builtin_init_trampoline (tree arglist)
  {
    tree t_tramp, t_func, t_chain;
    rtx r_tramp, r_func, r_chain;
--- 5204,5210 ----
  }
  
  static rtx
! expand_builtin_init_trampoline (tree exp)
  {
    tree t_tramp, t_func, t_chain;
    rtx r_tramp, r_func, r_chain;
*************** expand_builtin_init_trampoline (tree arg
*** 5200,5214 ****
    rtx blktramp;
  #endif
  
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE,
  			 POINTER_TYPE, VOID_TYPE))
      return NULL_RTX;
  
!   t_tramp = TREE_VALUE (arglist);
!   arglist = TREE_CHAIN (arglist);
!   t_func = TREE_VALUE (arglist);
!   arglist = TREE_CHAIN (arglist);
!   t_chain = TREE_VALUE (arglist);
  
    r_tramp = expand_normal (t_tramp);
    r_func = expand_normal (t_func);
--- 5212,5224 ----
    rtx blktramp;
  #endif
  
!   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE,
  			 POINTER_TYPE, VOID_TYPE))
      return NULL_RTX;
  
!   t_tramp = CALL_EXPR_ARG0 (exp);
!   t_func = CALL_EXPR_ARG1 (exp);
!   t_chain = CALL_EXPR_ARG2 (exp);
  
    r_tramp = expand_normal (t_tramp);
    r_func = expand_normal (t_func);
*************** expand_builtin_init_trampoline (tree arg
*** 5229,5242 ****
  }
  
  static rtx
! expand_builtin_adjust_trampoline (tree arglist)
  {
    rtx tramp;
  
!   if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
      return NULL_RTX;
  
!   tramp = expand_normal (TREE_VALUE (arglist));
    tramp = round_trampoline_addr (tramp);
  #ifdef TRAMPOLINE_ADJUST_ADDRESS
    TRAMPOLINE_ADJUST_ADDRESS (tramp);
--- 5239,5252 ----
  }
  
  static rtx
! expand_builtin_adjust_trampoline (tree exp)
  {
    rtx tramp;
  
!   if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
      return NULL_RTX;
  
!   tramp = expand_normal (CALL_EXPR_ARG0 (exp));
    tramp = round_trampoline_addr (tramp);
  #ifdef TRAMPOLINE_ADJUST_ADDRESS
    TRAMPOLINE_ADJUST_ADDRESS (tramp);
*************** expand_builtin_signbit (tree exp, rtx ta
*** 5256,5270 ****
    const struct real_format *fmt;
    enum machine_mode fmode, imode, rmode;
    HOST_WIDE_INT hi, lo;
!   tree arg, arglist;
    int word, bitpos;
    rtx temp;
  
!   arglist = TREE_OPERAND (exp, 1);
!   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
!     return 0;
  
!   arg = TREE_VALUE (arglist);
    fmode = TYPE_MODE (TREE_TYPE (arg));
    rmode = TYPE_MODE (TREE_TYPE (exp));
    fmt = REAL_MODE_FORMAT (fmode);
--- 5266,5279 ----
    const struct real_format *fmt;
    enum machine_mode fmode, imode, rmode;
    HOST_WIDE_INT hi, lo;
!   tree arg;
    int word, bitpos;
    rtx temp;
  
!   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
!     return NULL_RTX;
  
!   arg = CALL_EXPR_ARG0 (exp);
    fmode = TYPE_MODE (TREE_TYPE (arg));
    rmode = TYPE_MODE (TREE_TYPE (exp));
    fmt = REAL_MODE_FORMAT (fmode);
*************** expand_builtin_signbit (tree exp, rtx ta
*** 5276,5282 ****
    {
      /* But we can't do this if the format supports signed zero.  */
      if (fmt->has_signed_zero && HONOR_SIGNED_ZEROS (fmode))
!       return 0;
  
      arg = fold_build2 (LT_EXPR, TREE_TYPE (exp), arg,
  		       build_real (TREE_TYPE (arg), dconst0));
--- 5285,5291 ----
    {
      /* But we can't do this if the format supports signed zero.  */
      if (fmt->has_signed_zero && HONOR_SIGNED_ZEROS (fmode))
!       return NULL_RTX;
  
      arg = fold_build2 (LT_EXPR, TREE_TYPE (exp), arg,
  		       build_real (TREE_TYPE (arg), dconst0));
*************** expand_builtin_signbit (tree exp, rtx ta
*** 5288,5294 ****
      {
        imode = int_mode_for_mode (fmode);
        if (imode == BLKmode)
! 	return 0;
        temp = gen_lowpart (imode, temp);
      }
    else
--- 5297,5303 ----
      {
        imode = int_mode_for_mode (fmode);
        if (imode == BLKmode)
! 	return NULL_RTX;
        temp = gen_lowpart (imode, temp);
      }
    else
*************** expand_builtin_signbit (tree exp, rtx ta
*** 5347,5358 ****
  }
  
  /* Expand fork or exec calls.  TARGET is the desired target of the
!    call.  ARGLIST is the list of arguments of the call.  FN is the
     identificator of the actual function.  IGNORE is nonzero if the
     value is to be ignored.  */
  
  static rtx
! expand_builtin_fork_or_exec (tree fn, tree arglist, rtx target, int ignore)
  {
    tree id, decl;
    tree call;
--- 5356,5367 ----
  }
  
  /* Expand fork or exec calls.  TARGET is the desired target of the
!    call.  EXP is the call. FN is the
     identificator of the actual function.  IGNORE is nonzero if the
     value is to be ignored.  */
  
  static rtx
! expand_builtin_fork_or_exec (tree fn, tree exp, rtx target, int ignore)
  {
    tree id, decl;
    tree call;
*************** expand_builtin_fork_or_exec (tree fn, tr
*** 5406,5415 ****
    TREE_NOTHROW (decl) = 1;
    DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
    DECL_VISIBILITY_SPECIFIED (decl) = 1;
!   call = build_function_call_expr (decl, arglist);
! 
    return expand_call (call, target, ignore);
! }
  
  
  /* Reconstitute a mode for a __sync intrinsic operation.  Since the type of
--- 5415,5424 ----
    TREE_NOTHROW (decl) = 1;
    DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
    DECL_VISIBILITY_SPECIFIED (decl) = 1;
!   call = rewrite_call_expr (exp, 0, decl, 0);
    return expand_call (call, target, ignore);
!  }
!   
  
  
  /* Reconstitute a mode for a __sync intrinsic operation.  Since the type of
*************** get_builtin_sync_mem (tree loc, enum mac
*** 5451,5457 ****
  }
  
  /* Expand the __sync_xxx_and_fetch and __sync_fetch_and_xxx intrinsics.
!    ARGLIST is the operands list to the function.  CODE is the rtx code
     that corresponds to the arithmetic or logical operation from the name;
     an exception here is that NOT actually means NAND.  TARGET is an optional
     place for us to store the results; AFTER is true if this is the
--- 5460,5466 ----
  }
  
  /* Expand the __sync_xxx_and_fetch and __sync_fetch_and_xxx intrinsics.
!    EXP is the CALL_EXPR.  CODE is the rtx code
     that corresponds to the arithmetic or logical operation from the name;
     an exception here is that NOT actually means NAND.  TARGET is an optional
     place for us to store the results; AFTER is true if this is the
*************** get_builtin_sync_mem (tree loc, enum mac
*** 5459,5475 ****
     the result of the operation at all.  */
  
  static rtx
! expand_builtin_sync_operation (enum machine_mode mode, tree arglist,
  			       enum rtx_code code, bool after,
  			       rtx target, bool ignore)
  {
    rtx val, mem;
  
    /* Expand the operands.  */
!   mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
  
!   arglist = TREE_CHAIN (arglist);
!   val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
  
    if (ignore)
      return expand_sync_operation (mem, val, code);
--- 5468,5483 ----
     the result of the operation at all.  */
  
  static rtx
! expand_builtin_sync_operation (enum machine_mode mode, tree exp,
  			       enum rtx_code code, bool after,
  			       rtx target, bool ignore)
  {
    rtx val, mem;
  
    /* Expand the operands.  */
!   mem = get_builtin_sync_mem (CALL_EXPR_ARG0 (exp), mode);
  
!   val = expand_expr (CALL_EXPR_ARG1 (exp), NULL, mode, EXPAND_NORMAL);
  
    if (ignore)
      return expand_sync_operation (mem, val, code);
*************** expand_builtin_sync_operation (enum mach
*** 5478,5525 ****
  }
  
  /* Expand the __sync_val_compare_and_swap and __sync_bool_compare_and_swap
!    intrinsics.  ARGLIST is the operands list to the function.  IS_BOOL is
     true if this is the boolean form.  TARGET is a place for us to store the
     results; this is NOT optional if IS_BOOL is true.  */
  
  static rtx
! expand_builtin_compare_and_swap (enum machine_mode mode, tree arglist,
  				 bool is_bool, rtx target)
  {
    rtx old_val, new_val, mem;
  
    /* Expand the operands.  */
!   mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
! 
!   arglist = TREE_CHAIN (arglist);
!   old_val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
! 
!   arglist = TREE_CHAIN (arglist);
!   new_val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
  
    if (is_bool)
      return expand_bool_compare_and_swap (mem, old_val, new_val, target);
    else
      return expand_val_compare_and_swap (mem, old_val, new_val, target);
  }
  
  /* Expand the __sync_lock_test_and_set intrinsic.  Note that the most
     general form is actually an atomic exchange, and some targets only
     support a reduced form with the second argument being a constant 1.
!    ARGLIST is the operands list to the function; TARGET is an optional
     place for us to store the results.  */
  
  static rtx
! expand_builtin_lock_test_and_set (enum machine_mode mode, tree arglist,
  				  rtx target)
  {
    rtx val, mem;
  
    /* Expand the operands.  */
!   mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
! 
!   arglist = TREE_CHAIN (arglist);
!   val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
  
    return expand_sync_lock_test_and_set (mem, val, target);
  }
--- 5486,5528 ----
  }
  
  /* Expand the __sync_val_compare_and_swap and __sync_bool_compare_and_swap
!    intrinsics.  EXP is the CALL_EXPR.  IS_BOOL is
     true if this is the boolean form.  TARGET is a place for us to store the
     results; this is NOT optional if IS_BOOL is true.  */
  
  static rtx
! expand_builtin_compare_and_swap (enum machine_mode mode, tree exp,
  				 bool is_bool, rtx target)
  {
    rtx old_val, new_val, mem;
  
    /* Expand the operands.  */
!   mem = get_builtin_sync_mem (CALL_EXPR_ARG0 (exp), mode);
!   old_val = expand_expr (CALL_EXPR_ARG1 (exp), NULL, mode, EXPAND_NORMAL);
!   new_val = expand_expr (CALL_EXPR_ARG2 (exp), NULL, mode, EXPAND_NORMAL);
  
    if (is_bool)
      return expand_bool_compare_and_swap (mem, old_val, new_val, target);
    else
      return expand_val_compare_and_swap (mem, old_val, new_val, target);
  }
+  
  
  /* Expand the __sync_lock_test_and_set intrinsic.  Note that the most
     general form is actually an atomic exchange, and some targets only
     support a reduced form with the second argument being a constant 1.
!    EXP is the CALL_EXPR; TARGET is an optional
     place for us to store the results.  */
  
  static rtx
! expand_builtin_lock_test_and_set (enum machine_mode mode, tree exp,
  				  rtx target)
  {
    rtx val, mem;
  
    /* Expand the operands.  */
!   mem = get_builtin_sync_mem (CALL_EXPR_ARG0 (exp), mode);
!   val = expand_expr (CALL_EXPR_ARG1 (exp), NULL, mode, EXPAND_NORMAL);
  
    return expand_sync_lock_test_and_set (mem, val, target);
  }
*************** expand_builtin_synchronize (void)
*** 5547,5564 ****
    expand_asm_expr (x);
  }
  
! /* Expand the __sync_lock_release intrinsic.  ARGLIST is the operands list
!    to the function.  */
  
  static void
! expand_builtin_lock_release (enum machine_mode mode, tree arglist)
  {
    enum insn_code icode;
    rtx mem, insn;
    rtx val = const0_rtx;
  
    /* Expand the operands.  */
!   mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
  
    /* If there is an explicit operation in the md file, use it.  */
    icode = sync_lock_release[mode];
--- 5550,5566 ----
    expand_asm_expr (x);
  }
  
! /* Expand the __sync_lock_release intrinsic.  EXP is the CALL_EXPR.  */
  
  static void
! expand_builtin_lock_release (enum machine_mode mode, tree exp)
  {
    enum insn_code icode;
    rtx mem, insn;
    rtx val = const0_rtx;
  
    /* Expand the operands.  */
!   mem = get_builtin_sync_mem (CALL_EXPR_ARG0 (exp), mode);
  
    /* If there is an explicit operation in the md file, use it.  */
    icode = sync_lock_release[mode];
*************** expand_builtin (tree exp, rtx target, rt
*** 5592,5598 ****
  		int ignore)
  {
    tree fndecl = get_callee_fndecl (exp);
-   tree arglist = TREE_OPERAND (exp, 1);
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
    enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp));
  
--- 5594,5599 ----
*************** expand_builtin (tree exp, rtx target, rt
*** 5620,5628 ****
      {
        bool volatilep = false;
        tree arg;
  
!       for (arg = arglist; arg; arg = TREE_CHAIN (arg))
! 	if (TREE_THIS_VOLATILE (TREE_VALUE (arg)))
  	  {
  	    volatilep = true;
  	    break;
--- 5621,5631 ----
      {
        bool volatilep = false;
        tree arg;
+       call_expr_arg_iterator iter;
  
!       for (arg = first_call_expr_arg (exp, &iter); arg;
! 	   arg = next_call_expr_arg (&iter))
! 	if (TREE_THIS_VOLATILE (arg))
  	  {
  	    volatilep = true;
  	    break;
*************** expand_builtin (tree exp, rtx target, rt
*** 5630,5638 ****
  
        if (! volatilep)
  	{
! 	  for (arg = arglist; arg; arg = TREE_CHAIN (arg))
! 	    expand_expr (TREE_VALUE (arg), const0_rtx,
! 			 VOIDmode, EXPAND_NORMAL);
  	  return const0_rtx;
  	}
      }
--- 5633,5641 ----
  
        if (! volatilep)
  	{
! 	  for (arg = first_call_expr_arg (exp, &iter); arg;
! 	       arg = next_call_expr_arg (&iter))
! 	    expand_expr (arg, const0_rtx, VOIDmode, EXPAND_NORMAL);
  	  return const0_rtx;
  	}
      }
*************** expand_builtin (tree exp, rtx target, rt
*** 5640,5652 ****
    switch (fcode)
      {
      CASE_FLT_FN (BUILT_IN_FABS):
!       target = expand_builtin_fabs (arglist, target, subtarget);
        if (target)
  	return target;
        break;
  
      CASE_FLT_FN (BUILT_IN_COPYSIGN):
!       target = expand_builtin_copysign (arglist, target, subtarget);
        if (target)
  	return target;
        break;
--- 5643,5655 ----
    switch (fcode)
      {
      CASE_FLT_FN (BUILT_IN_FABS):
!       target = expand_builtin_fabs (exp, target, subtarget);
        if (target)
  	return target;
        break;
  
      CASE_FLT_FN (BUILT_IN_COPYSIGN):
!       target = expand_builtin_copysign (exp, target, subtarget);
        if (target)
  	return target;
        break;
*************** expand_builtin (tree exp, rtx target, rt
*** 5752,5770 ****
  	 computed?  We'll also need a safe worst case value for varargs
  	 functions.  */
      case BUILT_IN_APPLY:
!       if (!validate_arglist (arglist, POINTER_TYPE,
  			     POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)
! 	  && !validate_arglist (arglist, REFERENCE_TYPE,
  				POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
  	return const0_rtx;
        else
  	{
- 	  int i;
- 	  tree t;
  	  rtx ops[3];
  
! 	  for (t = arglist, i = 0; t; t = TREE_CHAIN (t), i++)
! 	    ops[i] = expand_normal (TREE_VALUE (t));
  
  	  return expand_builtin_apply (ops[0], ops[1], ops[2]);
  	}
--- 5755,5772 ----
  	 computed?  We'll also need a safe worst case value for varargs
  	 functions.  */
      case BUILT_IN_APPLY:
!       if (!validate_arglist (exp, POINTER_TYPE,
  			     POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)
! 	  && !validate_arglist (exp, REFERENCE_TYPE,
  				POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
  	return const0_rtx;
        else
  	{
  	  rtx ops[3];
  
! 	  ops[0] = expand_normal (CALL_EXPR_ARG0 (exp));
! 	  ops[1] = expand_normal (CALL_EXPR_ARG1 (exp));
! 	  ops[2] = expand_normal (CALL_EXPR_ARG2 (exp));
  
  	  return expand_builtin_apply (ops[0], ops[1], ops[2]);
  	}
*************** expand_builtin (tree exp, rtx target, rt
*** 5773,5808 ****
  	 value described by RESULT.  RESULT is address of the block of
  	 memory returned by __builtin_apply.  */
      case BUILT_IN_RETURN:
!       if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
! 	expand_builtin_return (expand_normal (TREE_VALUE (arglist)));
        return const0_rtx;
  
      case BUILT_IN_SAVEREGS:
        return expand_builtin_saveregs ();
  
      case BUILT_IN_ARGS_INFO:
!       return expand_builtin_args_info (arglist);
  
        /* Return the address of the first anonymous stack arg.  */
      case BUILT_IN_NEXT_ARG:
!       if (fold_builtin_next_arg (arglist))
  	return const0_rtx;
        return expand_builtin_next_arg ();
  
      case BUILT_IN_CLASSIFY_TYPE:
!       return expand_builtin_classify_type (arglist);
  
      case BUILT_IN_CONSTANT_P:
        return const0_rtx;
  
      case BUILT_IN_FRAME_ADDRESS:
      case BUILT_IN_RETURN_ADDRESS:
!       return expand_builtin_frame_address (fndecl, arglist);
  
      /* Returns the address of the area where the structure is returned.
         0 otherwise.  */
      case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
!       if (arglist != 0
  	  || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
  	  || !MEM_P (DECL_RTL (DECL_RESULT (current_function_decl))))
  	return const0_rtx;
--- 5775,5810 ----
  	 value described by RESULT.  RESULT is address of the block of
  	 memory returned by __builtin_apply.  */
      case BUILT_IN_RETURN:
!       if (validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
! 	expand_builtin_return (expand_normal (CALL_EXPR_ARG0 (exp)));
        return const0_rtx;
  
      case BUILT_IN_SAVEREGS:
        return expand_builtin_saveregs ();
  
      case BUILT_IN_ARGS_INFO:
!       return expand_builtin_args_info (exp);
  
        /* Return the address of the first anonymous stack arg.  */
      case BUILT_IN_NEXT_ARG:
!       if (fold_builtin_next_arg (exp, false))
  	return const0_rtx;
        return expand_builtin_next_arg ();
  
      case BUILT_IN_CLASSIFY_TYPE:
!       return expand_builtin_classify_type (exp);
  
      case BUILT_IN_CONSTANT_P:
        return const0_rtx;
  
      case BUILT_IN_FRAME_ADDRESS:
      case BUILT_IN_RETURN_ADDRESS:
!       return expand_builtin_frame_address (fndecl, exp);
  
      /* Returns the address of the area where the structure is returned.
         0 otherwise.  */
      case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
!       if (call_expr_nargs (exp) != 0
  	  || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
  	  || !MEM_P (DECL_RTL (DECL_RESULT (current_function_decl))))
  	return const0_rtx;
*************** expand_builtin (tree exp, rtx target, rt
*** 5810,5816 ****
  	return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
  
      case BUILT_IN_ALLOCA:
!       target = expand_builtin_alloca (arglist, target);
        if (target)
  	return target;
        break;
--- 5812,5818 ----
  	return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
  
      case BUILT_IN_ALLOCA:
!       target = expand_builtin_alloca (exp, target);
        if (target)
  	return target;
        break;
*************** expand_builtin (tree exp, rtx target, rt
*** 5819,5830 ****
        return expand_stack_save ();
  
      case BUILT_IN_STACK_RESTORE:
!       expand_stack_restore (TREE_VALUE (arglist));
        return const0_rtx;
  
      CASE_INT_FN (BUILT_IN_FFS):
      case BUILT_IN_FFSIMAX:
!       target = expand_builtin_unop (target_mode, arglist, target,
  				    subtarget, ffs_optab);
        if (target)
  	return target;
--- 5821,5832 ----
        return expand_stack_save ();
  
      case BUILT_IN_STACK_RESTORE:
!       expand_stack_restore (CALL_EXPR_ARG0 (exp));
        return const0_rtx;
  
      CASE_INT_FN (BUILT_IN_FFS):
      case BUILT_IN_FFSIMAX:
!       target = expand_builtin_unop (target_mode, exp, target,
  				    subtarget, ffs_optab);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 5832,5838 ****
  
      CASE_INT_FN (BUILT_IN_CLZ):
      case BUILT_IN_CLZIMAX:
!       target = expand_builtin_unop (target_mode, arglist, target,
  				    subtarget, clz_optab);
        if (target)
  	return target;
--- 5834,5840 ----
  
      CASE_INT_FN (BUILT_IN_CLZ):
      case BUILT_IN_CLZIMAX:
!       target = expand_builtin_unop (target_mode, exp, target,
  				    subtarget, clz_optab);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 5840,5846 ****
  
      CASE_INT_FN (BUILT_IN_CTZ):
      case BUILT_IN_CTZIMAX:
!       target = expand_builtin_unop (target_mode, arglist, target,
  				    subtarget, ctz_optab);
        if (target)
  	return target;
--- 5842,5848 ----
  
      CASE_INT_FN (BUILT_IN_CTZ):
      case BUILT_IN_CTZIMAX:
!       target = expand_builtin_unop (target_mode, exp, target,
  				    subtarget, ctz_optab);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 5848,5854 ****
  
      CASE_INT_FN (BUILT_IN_POPCOUNT):
      case BUILT_IN_POPCOUNTIMAX:
!       target = expand_builtin_unop (target_mode, arglist, target,
  				    subtarget, popcount_optab);
        if (target)
  	return target;
--- 5850,5856 ----
  
      CASE_INT_FN (BUILT_IN_POPCOUNT):
      case BUILT_IN_POPCOUNTIMAX:
!       target = expand_builtin_unop (target_mode, exp, target,
  				    subtarget, popcount_optab);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 5856,5875 ****
  
      CASE_INT_FN (BUILT_IN_PARITY):
      case BUILT_IN_PARITYIMAX:
!       target = expand_builtin_unop (target_mode, arglist, target,
  				    subtarget, parity_optab);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_STRLEN:
!       target = expand_builtin_strlen (arglist, target, target_mode);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_STRCPY:
!       target = expand_builtin_strcpy (fndecl, arglist, target, mode);
        if (target)
  	return target;
        break;
--- 5858,5877 ----
  
      CASE_INT_FN (BUILT_IN_PARITY):
      case BUILT_IN_PARITYIMAX:
!       target = expand_builtin_unop (target_mode, exp, target,
  				    subtarget, parity_optab);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_STRLEN:
!       target = expand_builtin_strlen (exp, target, target_mode);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_STRCPY:
!       target = expand_builtin_strcpy (fndecl, exp, target, mode);
        if (target)
  	return target;
        break;
*************** expand_builtin (tree exp, rtx target, rt
*** 5887,5937 ****
        break;
  
      case BUILT_IN_STRCAT:
!       target = expand_builtin_strcat (fndecl, 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, TREE_TYPE (exp), target, mode);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_STRPBRK:
!       target = expand_builtin_strpbrk (arglist, TREE_TYPE (exp), target, mode);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_INDEX:
      case BUILT_IN_STRCHR:
!       target = expand_builtin_strchr (arglist, TREE_TYPE (exp), target, mode);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_RINDEX:
      case BUILT_IN_STRRCHR:
!       target = expand_builtin_strrchr (arglist, TREE_TYPE (exp), target, mode);
        if (target)
  	return target;
        break;
--- 5889,5939 ----
        break;
  
      case BUILT_IN_STRCAT:
!       target = expand_builtin_strcat (fndecl, exp, target, mode);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_STRNCAT:
!       target = expand_builtin_strncat (exp, target, mode);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_STRSPN:
!       target = expand_builtin_strspn (exp, target, mode);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_STRCSPN:
!       target = expand_builtin_strcspn (exp, target, mode);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_STRSTR:
!       target = expand_builtin_strstr (exp, target, mode);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_STRPBRK:
!       target = expand_builtin_strpbrk (exp, target, mode);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_INDEX:
      case BUILT_IN_STRCHR:
!       target = expand_builtin_strchr (exp, target, mode);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_RINDEX:
      case BUILT_IN_STRRCHR:
!       target = expand_builtin_strrchr (exp, target, mode);
        if (target)
  	return target;
        break;
*************** expand_builtin (tree exp, rtx target, rt
*** 5943,5956 ****
        break;
  
      case BUILT_IN_MEMPCPY:
!       target = expand_builtin_mempcpy (arglist, TREE_TYPE (exp), target, mode, /*endp=*/ 1);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_MEMMOVE:
!       target = expand_builtin_memmove (arglist, TREE_TYPE (exp), target,
! 				       mode, exp);
        if (target)
  	return target;
        break;
--- 5945,5957 ----
        break;
  
      case BUILT_IN_MEMPCPY:
!       target = expand_builtin_mempcpy (exp, target, mode);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_MEMMOVE:
!       target = expand_builtin_memmove (exp, target, mode);
        if (target)
  	return target;
        break;
*************** expand_builtin (tree exp, rtx target, rt
*** 5962,5968 ****
        break;
  
      case BUILT_IN_MEMSET:
!       target = expand_builtin_memset (arglist, target, mode, exp);
        if (target)
  	return target;
        break;
--- 5963,5969 ----
        break;
  
      case BUILT_IN_MEMSET:
!       target = expand_builtin_memset (exp, target, mode);
        if (target)
  	return target;
        break;
*************** expand_builtin (tree exp, rtx target, rt
*** 5987,5999 ****
  
      case BUILT_IN_BCMP:
      case BUILT_IN_MEMCMP:
!       target = expand_builtin_memcmp (exp, arglist, target, mode);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_SETJMP:
!       target = expand_builtin_setjmp (arglist, target);
        if (target)
  	return target;
        break;
--- 5988,6000 ----
  
      case BUILT_IN_BCMP:
      case BUILT_IN_MEMCMP:
!       target = expand_builtin_memcmp (exp, target, mode);
        if (target)
  	return target;
        break;
  
      case BUILT_IN_SETJMP:
!       target = expand_builtin_setjmp (exp, target);
        if (target)
  	return target;
        break;
*************** expand_builtin (tree exp, rtx target, rt
*** 6002,6014 ****
  	 It's similar to the C library longjmp function but works with
  	 __builtin_setjmp above.  */
      case BUILT_IN_LONGJMP:
!       if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
  	break;
        else
  	{
! 	  rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
  				      VOIDmode, EXPAND_NORMAL);
! 	  rtx value = expand_normal (TREE_VALUE (TREE_CHAIN (arglist)));
  
  	  if (value != const1_rtx)
  	    {
--- 6003,6015 ----
  	 It's similar to the C library longjmp function but works with
  	 __builtin_setjmp above.  */
      case BUILT_IN_LONGJMP:
!       if (!validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
  	break;
        else
  	{
! 	  rtx buf_addr = expand_expr (CALL_EXPR_ARG0 (exp), subtarget,
  				      VOIDmode, EXPAND_NORMAL);
! 	  rtx value = expand_normal (CALL_EXPR_ARG1 (exp));
  
  	  if (value != const1_rtx)
  	    {
*************** expand_builtin (tree exp, rtx target, rt
*** 6021,6027 ****
  	}
  
      case BUILT_IN_NONLOCAL_GOTO:
!       target = expand_builtin_nonlocal_goto (arglist);
        if (target)
  	return target;
        break;
--- 6022,6028 ----
  	}
  
      case BUILT_IN_NONLOCAL_GOTO:
!       target = expand_builtin_nonlocal_goto (exp);
        if (target)
  	return target;
        break;
*************** expand_builtin (tree exp, rtx target, rt
*** 6029,6038 ****
        /* This updates the setjmp buffer that is its argument with the value
  	 of the current stack pointer.  */
      case BUILT_IN_UPDATE_SETJMP_BUF:
!       if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
  	{
  	  rtx buf_addr
! 	    = expand_normal (TREE_VALUE (arglist));
  
  	  expand_builtin_update_setjmp_buf (buf_addr);
  	  return const0_rtx;
--- 6030,6039 ----
        /* This updates the setjmp buffer that is its argument with the value
  	 of the current stack pointer.  */
      case BUILT_IN_UPDATE_SETJMP_BUF:
!       if (validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
  	{
  	  rtx buf_addr
! 	    = expand_normal (CALL_EXPR_ARG0 (exp));
  
  	  expand_builtin_update_setjmp_buf (buf_addr);
  	  return const0_rtx;
*************** expand_builtin (tree exp, rtx target, rt
*** 6056,6067 ****
        break;
  
      case BUILT_IN_FPUTS:
!       target = expand_builtin_fputs (arglist, target, false);
        if (target)
  	return target;
        break;
      case BUILT_IN_FPUTS_UNLOCKED:
!       target = expand_builtin_fputs (arglist, target, true);
        if (target)
  	return target;
        break;
--- 6057,6068 ----
        break;
  
      case BUILT_IN_FPUTS:
!       target = expand_builtin_fputs (exp, target, false);
        if (target)
  	return target;
        break;
      case BUILT_IN_FPUTS_UNLOCKED:
!       target = expand_builtin_fputs (exp, target, true);
        if (target)
  	return target;
        break;
*************** expand_builtin (tree exp, rtx target, rt
*** 6079,6085 ****
        break;
  
      case BUILT_IN_SPRINTF:
!       target = expand_builtin_sprintf (arglist, target, mode);
        if (target)
  	return target;
        break;
--- 6080,6086 ----
        break;
  
      case BUILT_IN_SPRINTF:
!       target = expand_builtin_sprintf (exp, target, mode);
        if (target)
  	return target;
        break;
*************** expand_builtin (tree exp, rtx target, rt
*** 6100,6134 ****
      case BUILT_IN_DWARF_SP_COLUMN:
        return expand_builtin_dwarf_sp_column ();
      case BUILT_IN_INIT_DWARF_REG_SIZES:
!       expand_builtin_init_dwarf_reg_sizes (TREE_VALUE (arglist));
        return const0_rtx;
  #endif
      case BUILT_IN_FROB_RETURN_ADDR:
!       return expand_builtin_frob_return_addr (TREE_VALUE (arglist));
      case BUILT_IN_EXTRACT_RETURN_ADDR:
!       return expand_builtin_extract_return_addr (TREE_VALUE (arglist));
      case BUILT_IN_EH_RETURN:
!       expand_builtin_eh_return (TREE_VALUE (arglist),
! 				TREE_VALUE (TREE_CHAIN (arglist)));
        return const0_rtx;
  #ifdef EH_RETURN_DATA_REGNO
      case BUILT_IN_EH_RETURN_DATA_REGNO:
!       return expand_builtin_eh_return_data_regno (arglist);
  #endif
      case BUILT_IN_EXTEND_POINTER:
!       return expand_builtin_extend_pointer (TREE_VALUE (arglist));
  
      case BUILT_IN_VA_START:
      case BUILT_IN_STDARG_START:
!       return expand_builtin_va_start (arglist);
      case BUILT_IN_VA_END:
!       return expand_builtin_va_end (arglist);
      case BUILT_IN_VA_COPY:
!       return expand_builtin_va_copy (arglist);
      case BUILT_IN_EXPECT:
!       return expand_builtin_expect (arglist, target);
      case BUILT_IN_PREFETCH:
!       expand_builtin_prefetch (arglist);
        return const0_rtx;
  
      case BUILT_IN_PROFILE_FUNC_ENTER:
--- 6101,6135 ----
      case BUILT_IN_DWARF_SP_COLUMN:
        return expand_builtin_dwarf_sp_column ();
      case BUILT_IN_INIT_DWARF_REG_SIZES:
!       expand_builtin_init_dwarf_reg_sizes (CALL_EXPR_ARG0 (exp));
        return const0_rtx;
  #endif
      case BUILT_IN_FROB_RETURN_ADDR:
!       return expand_builtin_frob_return_addr (CALL_EXPR_ARG0 (exp));
      case BUILT_IN_EXTRACT_RETURN_ADDR:
!       return expand_builtin_extract_return_addr (CALL_EXPR_ARG0 (exp));
      case BUILT_IN_EH_RETURN:
!       expand_builtin_eh_return (CALL_EXPR_ARG0 (exp),
! 				CALL_EXPR_ARG1 (exp));
        return const0_rtx;
  #ifdef EH_RETURN_DATA_REGNO
      case BUILT_IN_EH_RETURN_DATA_REGNO:
!       return expand_builtin_eh_return_data_regno (exp);
  #endif
      case BUILT_IN_EXTEND_POINTER:
!       return expand_builtin_extend_pointer (CALL_EXPR_ARG0 (exp));
  
      case BUILT_IN_VA_START:
      case BUILT_IN_STDARG_START:
!       return expand_builtin_va_start (exp);
      case BUILT_IN_VA_END:
!       return expand_builtin_va_end (exp);
      case BUILT_IN_VA_COPY:
!       return expand_builtin_va_copy (exp);
      case BUILT_IN_EXPECT:
!       return expand_builtin_expect (exp, target);
      case BUILT_IN_PREFETCH:
!       expand_builtin_prefetch (exp);
        return const0_rtx;
  
      case BUILT_IN_PROFILE_FUNC_ENTER:
*************** expand_builtin (tree exp, rtx target, rt
*** 6137,6145 ****
        return expand_builtin_profile_func (true);
  
      case BUILT_IN_INIT_TRAMPOLINE:
!       return expand_builtin_init_trampoline (arglist);
      case BUILT_IN_ADJUST_TRAMPOLINE:
!       return expand_builtin_adjust_trampoline (arglist);
  
      case BUILT_IN_FORK:
      case BUILT_IN_EXECL:
--- 6138,6146 ----
        return expand_builtin_profile_func (true);
  
      case BUILT_IN_INIT_TRAMPOLINE:
!       return expand_builtin_init_trampoline (exp);
      case BUILT_IN_ADJUST_TRAMPOLINE:
!       return expand_builtin_adjust_trampoline (exp);
  
      case BUILT_IN_FORK:
      case BUILT_IN_EXECL:
*************** expand_builtin (tree exp, rtx target, rt
*** 6148,6154 ****
      case BUILT_IN_EXECLE:
      case BUILT_IN_EXECVP:
      case BUILT_IN_EXECVE:
!       target = expand_builtin_fork_or_exec (fndecl, arglist, target, ignore);
        if (target)
  	return target;
        break;
--- 6149,6155 ----
      case BUILT_IN_EXECLE:
      case BUILT_IN_EXECVP:
      case BUILT_IN_EXECVE:
!       target = expand_builtin_fork_or_exec (fndecl, exp, target, ignore);
        if (target)
  	return target;
        break;
*************** expand_builtin (tree exp, rtx target, rt
*** 6159,6165 ****
      case BUILT_IN_FETCH_AND_ADD_8:
      case BUILT_IN_FETCH_AND_ADD_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_ADD_1);
!       target = expand_builtin_sync_operation (mode, arglist, PLUS,
  					      false, target, ignore);
        if (target)
  	return target;
--- 6160,6166 ----
      case BUILT_IN_FETCH_AND_ADD_8:
      case BUILT_IN_FETCH_AND_ADD_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_ADD_1);
!       target = expand_builtin_sync_operation (mode, exp, PLUS,
  					      false, target, ignore);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 6171,6177 ****
      case BUILT_IN_FETCH_AND_SUB_8:
      case BUILT_IN_FETCH_AND_SUB_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_SUB_1);
!       target = expand_builtin_sync_operation (mode, arglist, MINUS,
  					      false, target, ignore);
        if (target)
  	return target;
--- 6172,6178 ----
      case BUILT_IN_FETCH_AND_SUB_8:
      case BUILT_IN_FETCH_AND_SUB_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_SUB_1);
!       target = expand_builtin_sync_operation (mode, exp, MINUS,
  					      false, target, ignore);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 6183,6189 ****
      case BUILT_IN_FETCH_AND_OR_8:
      case BUILT_IN_FETCH_AND_OR_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_OR_1);
!       target = expand_builtin_sync_operation (mode, arglist, IOR,
  					      false, target, ignore);
        if (target)
  	return target;
--- 6184,6190 ----
      case BUILT_IN_FETCH_AND_OR_8:
      case BUILT_IN_FETCH_AND_OR_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_OR_1);
!       target = expand_builtin_sync_operation (mode, exp, IOR,
  					      false, target, ignore);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 6195,6201 ****
      case BUILT_IN_FETCH_AND_AND_8:
      case BUILT_IN_FETCH_AND_AND_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_AND_1);
!       target = expand_builtin_sync_operation (mode, arglist, AND,
  					      false, target, ignore);
        if (target)
  	return target;
--- 6196,6202 ----
      case BUILT_IN_FETCH_AND_AND_8:
      case BUILT_IN_FETCH_AND_AND_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_AND_1);
!       target = expand_builtin_sync_operation (mode, exp, AND,
  					      false, target, ignore);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 6207,6213 ****
      case BUILT_IN_FETCH_AND_XOR_8:
      case BUILT_IN_FETCH_AND_XOR_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_XOR_1);
!       target = expand_builtin_sync_operation (mode, arglist, XOR,
  					      false, target, ignore);
        if (target)
  	return target;
--- 6208,6214 ----
      case BUILT_IN_FETCH_AND_XOR_8:
      case BUILT_IN_FETCH_AND_XOR_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_XOR_1);
!       target = expand_builtin_sync_operation (mode, exp, XOR,
  					      false, target, ignore);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 6219,6225 ****
      case BUILT_IN_FETCH_AND_NAND_8:
      case BUILT_IN_FETCH_AND_NAND_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_NAND_1);
!       target = expand_builtin_sync_operation (mode, arglist, NOT,
  					      false, target, ignore);
        if (target)
  	return target;
--- 6220,6226 ----
      case BUILT_IN_FETCH_AND_NAND_8:
      case BUILT_IN_FETCH_AND_NAND_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_NAND_1);
!       target = expand_builtin_sync_operation (mode, exp, NOT,
  					      false, target, ignore);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 6231,6237 ****
      case BUILT_IN_ADD_AND_FETCH_8:
      case BUILT_IN_ADD_AND_FETCH_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_ADD_AND_FETCH_1);
!       target = expand_builtin_sync_operation (mode, arglist, PLUS,
  					      true, target, ignore);
        if (target)
  	return target;
--- 6232,6238 ----
      case BUILT_IN_ADD_AND_FETCH_8:
      case BUILT_IN_ADD_AND_FETCH_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_ADD_AND_FETCH_1);
!       target = expand_builtin_sync_operation (mode, exp, PLUS,
  					      true, target, ignore);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 6243,6249 ****
      case BUILT_IN_SUB_AND_FETCH_8:
      case BUILT_IN_SUB_AND_FETCH_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_SUB_AND_FETCH_1);
!       target = expand_builtin_sync_operation (mode, arglist, MINUS,
  					      true, target, ignore);
        if (target)
  	return target;
--- 6244,6250 ----
      case BUILT_IN_SUB_AND_FETCH_8:
      case BUILT_IN_SUB_AND_FETCH_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_SUB_AND_FETCH_1);
!       target = expand_builtin_sync_operation (mode, exp, MINUS,
  					      true, target, ignore);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 6255,6261 ****
      case BUILT_IN_OR_AND_FETCH_8:
      case BUILT_IN_OR_AND_FETCH_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_OR_AND_FETCH_1);
!       target = expand_builtin_sync_operation (mode, arglist, IOR,
  					      true, target, ignore);
        if (target)
  	return target;
--- 6256,6262 ----
      case BUILT_IN_OR_AND_FETCH_8:
      case BUILT_IN_OR_AND_FETCH_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_OR_AND_FETCH_1);
!       target = expand_builtin_sync_operation (mode, exp, IOR,
  					      true, target, ignore);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 6267,6273 ****
      case BUILT_IN_AND_AND_FETCH_8:
      case BUILT_IN_AND_AND_FETCH_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_AND_AND_FETCH_1);
!       target = expand_builtin_sync_operation (mode, arglist, AND,
  					      true, target, ignore);
        if (target)
  	return target;
--- 6268,6274 ----
      case BUILT_IN_AND_AND_FETCH_8:
      case BUILT_IN_AND_AND_FETCH_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_AND_AND_FETCH_1);
!       target = expand_builtin_sync_operation (mode, exp, AND,
  					      true, target, ignore);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 6279,6285 ****
      case BUILT_IN_XOR_AND_FETCH_8:
      case BUILT_IN_XOR_AND_FETCH_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_XOR_AND_FETCH_1);
!       target = expand_builtin_sync_operation (mode, arglist, XOR,
  					      true, target, ignore);
        if (target)
  	return target;
--- 6280,6286 ----
      case BUILT_IN_XOR_AND_FETCH_8:
      case BUILT_IN_XOR_AND_FETCH_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_XOR_AND_FETCH_1);
!       target = expand_builtin_sync_operation (mode, exp, XOR,
  					      true, target, ignore);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 6291,6297 ****
      case BUILT_IN_NAND_AND_FETCH_8:
      case BUILT_IN_NAND_AND_FETCH_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_NAND_AND_FETCH_1);
!       target = expand_builtin_sync_operation (mode, arglist, NOT,
  					      true, target, ignore);
        if (target)
  	return target;
--- 6292,6298 ----
      case BUILT_IN_NAND_AND_FETCH_8:
      case BUILT_IN_NAND_AND_FETCH_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_NAND_AND_FETCH_1);
!       target = expand_builtin_sync_operation (mode, exp, NOT,
  					      true, target, ignore);
        if (target)
  	return target;
*************** expand_builtin (tree exp, rtx target, rt
*** 6308,6314 ****
  	target = gen_reg_rtx (mode);
  
        mode = get_builtin_sync_mode (fcode - BUILT_IN_BOOL_COMPARE_AND_SWAP_1);
!       target = expand_builtin_compare_and_swap (mode, arglist, true, target);
        if (target)
  	return target;
        break;
--- 6309,6315 ----
  	target = gen_reg_rtx (mode);
  
        mode = get_builtin_sync_mode (fcode - BUILT_IN_BOOL_COMPARE_AND_SWAP_1);
!       target = expand_builtin_compare_and_swap (mode, exp, true, target);
        if (target)
  	return target;
        break;
*************** expand_builtin (tree exp, rtx target, rt
*** 6319,6325 ****
      case BUILT_IN_VAL_COMPARE_AND_SWAP_8:
      case BUILT_IN_VAL_COMPARE_AND_SWAP_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_VAL_COMPARE_AND_SWAP_1);
!       target = expand_builtin_compare_and_swap (mode, arglist, false, target);
        if (target)
  	return target;
        break;
--- 6320,6326 ----
      case BUILT_IN_VAL_COMPARE_AND_SWAP_8:
      case BUILT_IN_VAL_COMPARE_AND_SWAP_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_VAL_COMPARE_AND_SWAP_1);
!       target = expand_builtin_compare_and_swap (mode, exp, false, target);
        if (target)
  	return target;
        break;
*************** expand_builtin (tree exp, rtx target, rt
*** 6330,6336 ****
      case BUILT_IN_LOCK_TEST_AND_SET_8:
      case BUILT_IN_LOCK_TEST_AND_SET_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_TEST_AND_SET_1);
!       target = expand_builtin_lock_test_and_set (mode, arglist, target);
        if (target)
  	return target;
        break;
--- 6331,6337 ----
      case BUILT_IN_LOCK_TEST_AND_SET_8:
      case BUILT_IN_LOCK_TEST_AND_SET_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_TEST_AND_SET_1);
!       target = expand_builtin_lock_test_and_set (mode, exp, target);
        if (target)
  	return target;
        break;
*************** expand_builtin (tree exp, rtx target, rt
*** 6341,6347 ****
      case BUILT_IN_LOCK_RELEASE_8:
      case BUILT_IN_LOCK_RELEASE_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_RELEASE_1);
!       expand_builtin_lock_release (mode, arglist);
        return const0_rtx;
  
      case BUILT_IN_SYNCHRONIZE:
--- 6342,6348 ----
      case BUILT_IN_LOCK_RELEASE_8:
      case BUILT_IN_LOCK_RELEASE_16:
        mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_RELEASE_1);
!       expand_builtin_lock_release (mode, exp);
        return const0_rtx;
  
      case BUILT_IN_SYNCHRONIZE:
*************** expand_builtin (tree exp, rtx target, rt
*** 6392,6402 ****
  enum built_in_function
  builtin_mathfn_code (tree t)
  {
!   tree fndecl, arglist, parmlist;
    tree argtype, parmtype;
  
    if (TREE_CODE (t) != CALL_EXPR
!       || TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR)
      return END_BUILTINS;
  
    fndecl = get_callee_fndecl (t);
--- 6393,6404 ----
  enum built_in_function
  builtin_mathfn_code (tree t)
  {
!   tree fndecl, arg, parmlist;
    tree argtype, parmtype;
+   call_expr_arg_iterator iter;
  
    if (TREE_CODE (t) != CALL_EXPR
!       || TREE_CODE (CALL_EXPR_FN (t)) != ADDR_EXPR)
      return END_BUILTINS;
  
    fndecl = get_callee_fndecl (t);
*************** builtin_mathfn_code (tree t)
*** 6406,6413 ****
        || DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
      return END_BUILTINS;
  
-   arglist = TREE_OPERAND (t, 1);
    parmlist = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
    for (; parmlist; parmlist = TREE_CHAIN (parmlist))
      {
        /* If a function doesn't take a variable number of arguments,
--- 6408,6415 ----
        || DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
      return END_BUILTINS;
  
    parmlist = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+   init_call_expr_arg_iterator (t, &iter);
    for (; parmlist; parmlist = TREE_CHAIN (parmlist))
      {
        /* If a function doesn't take a variable number of arguments,
*************** builtin_mathfn_code (tree t)
*** 6415,6429 ****
        parmtype = TREE_VALUE (parmlist);
        if (VOID_TYPE_P (parmtype))
  	{
! 	  if (arglist)
  	    return END_BUILTINS;
  	  return DECL_FUNCTION_CODE (fndecl);
  	}
  
!       if (! arglist)
  	return END_BUILTINS;
! 
!       argtype = TREE_TYPE (TREE_VALUE (arglist));
  
        if (SCALAR_FLOAT_TYPE_P (parmtype))
  	{
--- 6417,6432 ----
        parmtype = TREE_VALUE (parmlist);
        if (VOID_TYPE_P (parmtype))
  	{
! 	  if (more_call_expr_args_p (&iter))
  	    return END_BUILTINS;
  	  return DECL_FUNCTION_CODE (fndecl);
  	}
  
!       if (! more_call_expr_args_p (&iter))
  	return END_BUILTINS;
!       
!       arg = next_call_expr_arg (&iter);
!       argtype = TREE_TYPE (arg);
  
        if (SCALAR_FLOAT_TYPE_P (parmtype))
  	{
*************** builtin_mathfn_code (tree t)
*** 6447,6484 ****
  	}
        else
  	return END_BUILTINS;
- 
-       arglist = TREE_CHAIN (arglist);
      }
  
    /* Variable-length argument list.  */
    return DECL_FUNCTION_CODE (fndecl);
  }
  
! /* Fold a call to __builtin_constant_p, if we know it will evaluate to a
!    constant.  ARGLIST is the argument list of the call.  */
  
  static tree
! fold_builtin_constant_p (tree arglist)
  {
-   if (arglist == 0)
-     return 0;
- 
-   arglist = TREE_VALUE (arglist);
- 
    /* We return 1 for a numeric type that's known to be a constant
       value at compile-time or for an aggregate type that's a
       literal constant.  */
!   STRIP_NOPS (arglist);
  
    /* If we know this is a constant, emit the constant of one.  */
!   if (CONSTANT_CLASS_P (arglist)
!       || (TREE_CODE (arglist) == CONSTRUCTOR
! 	  && TREE_CONSTANT (arglist)))
      return integer_one_node;
!   if (TREE_CODE (arglist) == ADDR_EXPR)
      {
!        tree op = TREE_OPERAND (arglist, 0);
         if (TREE_CODE (op) == STRING_CST
  	   || (TREE_CODE (op) == ARRAY_REF
  	       && integer_zerop (TREE_OPERAND (op, 1))
--- 6450,6480 ----
  	}
        else
  	return END_BUILTINS;
      }
  
    /* Variable-length argument list.  */
    return DECL_FUNCTION_CODE (fndecl);
  }
  
! /* Fold a call to __builtin_constant_p, if we know its argument ARG will
!    evaluate to a constant.  */
  
  static tree
! fold_builtin_constant_p (tree arg)
  {
    /* We return 1 for a numeric type that's known to be a constant
       value at compile-time or for an aggregate type that's a
       literal constant.  */
!   STRIP_NOPS (arg);
  
    /* If we know this is a constant, emit the constant of one.  */
!   if (CONSTANT_CLASS_P (arg)
!       || (TREE_CODE (arg) == CONSTRUCTOR
! 	  && TREE_CONSTANT (arg)))
      return integer_one_node;
!   if (TREE_CODE (arg) == ADDR_EXPR)
      {
!        tree op = TREE_OPERAND (arg, 0);
         if (TREE_CODE (op) == STRING_CST
  	   || (TREE_CODE (op) == ARRAY_REF
  	       && integer_zerop (TREE_OPERAND (op, 1))
*************** fold_builtin_constant_p (tree arglist)
*** 6493,6525 ****
       And finally, if we are compiling an initializer, not code, we
       need to return a definite result now; there's not going to be any
       more optimization done.  */
!   if (TREE_SIDE_EFFECTS (arglist)
!       || AGGREGATE_TYPE_P (TREE_TYPE (arglist))
!       || POINTER_TYPE_P (TREE_TYPE (arglist))
        || cfun == 0)
      return integer_zero_node;
  
!   return 0;
  }
  
! /* Fold a call to __builtin_expect, if we expect that a comparison against
!    the argument will fold to a constant.  In practice, this means a true
!    constant or the address of a non-weak symbol.  ARGLIST is the argument
!    list of the call.  */
  
  static tree
! fold_builtin_expect (tree arglist)
  {
!   tree arg, inner;
! 
!   if (arglist == 0)
!     return 0;
! 
!   arg = TREE_VALUE (arglist);
  
    /* If the argument isn't invariant, then there's nothing we can do.  */
    if (!TREE_INVARIANT (arg))
!     return 0;
  
    /* If we're looking at an address of a weak decl, then do not fold.  */
    inner = arg;
--- 6489,6515 ----
       And finally, if we are compiling an initializer, not code, we
       need to return a definite result now; there's not going to be any
       more optimization done.  */
!   if (TREE_SIDE_EFFECTS (arg)
!       || AGGREGATE_TYPE_P (TREE_TYPE (arg))
!       || POINTER_TYPE_P (TREE_TYPE (arg))
        || cfun == 0)
      return integer_zero_node;
  
!   return NULL_TREE;
  }
  
! /* Fold a call to __builtin_expect with argument ARG, if we expect that a
!    comparison against the argument will fold to a constant.  In practice,
!    this means a true constant or the address of a non-weak symbol.  */
  
  static tree
! fold_builtin_expect (tree arg)
  {
!   tree inner;
  
    /* If the argument isn't invariant, then there's nothing we can do.  */
    if (!TREE_INVARIANT (arg))
!     return NULL_TREE;
  
    /* If we're looking at an address of a weak decl, then do not fold.  */
    inner = arg;
*************** fold_builtin_expect (tree arglist)
*** 6533,6567 ****
        while (TREE_CODE (inner) == COMPONENT_REF
  	     || TREE_CODE (inner) == ARRAY_REF);
        if (DECL_P (inner) && DECL_WEAK (inner))
! 	return 0;
      }
  
    /* Otherwise, ARG already has the proper type for the return value.  */
    return arg;
  }
  
! /* Fold a call to __builtin_classify_type.  */
  
  static tree
! fold_builtin_classify_type (tree arglist)
  {
!   if (arglist == 0)
      return build_int_cst (NULL_TREE, no_type_class);
  
!   return build_int_cst (NULL_TREE,
! 			type_to_class (TREE_TYPE (TREE_VALUE (arglist))));
  }
  
! /* Fold a call to __builtin_strlen.  */
  
  static tree
! fold_builtin_strlen (tree arglist)
  {
!   if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
      return NULL_TREE;
    else
      {
!       tree len = c_strlen (TREE_VALUE (arglist), 0);
  
        if (len)
  	{
--- 6523,6556 ----
        while (TREE_CODE (inner) == COMPONENT_REF
  	     || TREE_CODE (inner) == ARRAY_REF);
        if (DECL_P (inner) && DECL_WEAK (inner))
! 	return NULL_TREE;
      }
  
    /* Otherwise, ARG already has the proper type for the return value.  */
    return arg;
  }
  
! /* Fold a call to __builtin_classify_type with argument ARG.  */
  
  static tree
! fold_builtin_classify_type (tree arg)
  {
!   if (arg == 0)
      return build_int_cst (NULL_TREE, no_type_class);
  
!   return build_int_cst (NULL_TREE, type_to_class (TREE_TYPE (arg)));
  }
  
! /* Fold a call to __builtin_strlen with argument ARG.  */
  
  static tree
! fold_builtin_strlen (tree arg)
  {
!   if (!validate_arg (arg, POINTER_TYPE))
      return NULL_TREE;
    else
      {
!       tree len = c_strlen (arg, 0);
  
        if (len)
  	{
*************** fold_builtin_inf (tree type, int warn)
*** 6596,6617 ****
    return build_real (type, real);
  }
  
! /* Fold a call to __builtin_nan or __builtin_nans.  */
  
  static tree
! fold_builtin_nan (tree arglist, tree type, int quiet)
  {
    REAL_VALUE_TYPE real;
    const char *str;
  
!   if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
!     return 0;
!   str = c_getstr (TREE_VALUE (arglist));
    if (!str)
!     return 0;
  
    if (!real_nan (&real, str, quiet, TYPE_MODE (type)))
!     return 0;
  
    return build_real (type, real);
  }
--- 6585,6606 ----
    return build_real (type, real);
  }
  
! /* Fold a call to __builtin_nan or __builtin_nans with argument ARG.  */
  
  static tree
! fold_builtin_nan (tree arg, tree type, int quiet)
  {
    REAL_VALUE_TYPE real;
    const char *str;
  
!   if (!validate_arg (arg, POINTER_TYPE))
!     return NULL_TREE;
!   str = c_getstr (arg);
    if (!str)
!     return NULL_TREE;
  
    if (!real_nan (&real, str, quiet, TYPE_MODE (type)))
!     return NULL_TREE;
  
    return build_real (type, real);
  }
*************** integer_valued_real_p (tree t)
*** 6692,6711 ****
    return false;
  }
  
! /* EXP is assumed to be builtin call where truncation can be propagated
     across (for instance floor((double)f) == (double)floorf (f).
!    Do the transformation.  */
  
  static tree
! fold_trunc_transparent_mathfn (tree fndecl, tree arglist)
  {
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
-   tree arg;
  
!   if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
!     return 0;
  
-   arg = TREE_VALUE (arglist);
    /* Integer rounding functions are idempotent.  */
    if (fcode == builtin_mathfn_code (arg))
      return arg;
--- 6681,6698 ----
    return false;
  }
  
! /* FNDECL is assumed to be a builtin where truncation can be propagated
     across (for instance floor((double)f) == (double)floorf (f).
!    Do the transformation for a call with argument ARG.  */
  
  static tree
! fold_trunc_transparent_mathfn (tree fndecl, tree arg)
  {
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
  
!   if (!validate_arg (arg, REAL_TYPE))
!     return NULL_TREE;
  
    /* Integer rounding functions are idempotent.  */
    if (fcode == builtin_mathfn_code (arg))
      return arg;
*************** fold_trunc_transparent_mathfn (tree fnde
*** 6724,6752 ****
  
        if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype)
  	  && (decl = mathfn_built_in (newtype, fcode)))
! 	{
! 	  arglist =
! 	    build_tree_list (NULL_TREE, fold_convert (newtype, arg0));
! 	  return fold_convert (ftype,
! 			       build_function_call_expr (decl, arglist));
! 	}
      }
!   return 0;
  }
  
! /* EXP is assumed to be builtin call which can narrow the FP type of
!    the argument, for instance lround((double)f) -> lroundf (f).  */
  
  static tree
! fold_fixed_mathfn (tree fndecl, tree arglist)
  {
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
-   tree arg;
  
!   if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
!     return 0;
! 
!   arg = TREE_VALUE (arglist);
  
    /* If argument is already integer valued, and we don't need to worry
       about setting errno, there's no need to perform rounding.  */
--- 6711,6734 ----
  
        if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype)
  	  && (decl = mathfn_built_in (newtype, fcode)))
! 	return fold_convert (ftype,
! 			     build_call_expr (decl, 1,
! 					      fold_convert (newtype, arg0)));
      }
!   return NULL_TREE;
  }
  
! /* FNDECL is assumed to be builtin which can narrow the FP type of
!    the argument, for instance lround((double)f) -> lroundf (f).
!    Do the transformation for a call with argument ARG.  */
  
  static tree
! fold_fixed_mathfn (tree fndecl, tree arg)
  {
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
  
!   if (!validate_arg (arg, REAL_TYPE))
!     return NULL_TREE;
  
    /* If argument is already integer valued, and we don't need to worry
       about setting errno, there's no need to perform rounding.  */
*************** fold_fixed_mathfn (tree fndecl, tree arg
*** 6762,6789 ****
  
        if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype)
  	  && (decl = mathfn_built_in (newtype, fcode)))
! 	{
! 	  arglist =
! 	    build_tree_list (NULL_TREE, fold_convert (newtype, arg0));
! 	  return build_function_call_expr (decl, arglist);
! 	}
      }
!   return 0;
  }
  
! /* Fold function call to builtin cabs, cabsf or cabsl.  ARGLIST
!    is the argument list and TYPE is the return type.  Return
!    NULL_TREE if no if no simplification can be made.  */
  
  static tree
! fold_builtin_cabs (tree arglist, tree type)
  {
-   tree arg;
- 
-   if (!arglist || TREE_CHAIN (arglist))
-     return NULL_TREE;
- 
-   arg = TREE_VALUE (arglist);
    if (TREE_CODE (TREE_TYPE (arg)) != COMPLEX_TYPE
        || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
      return NULL_TREE;
--- 6744,6760 ----
  
        if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype)
  	  && (decl = mathfn_built_in (newtype, fcode)))
! 	return build_call_expr (decl, 1, fold_convert (newtype, arg0));
      }
!   return NULL_TREE;
  }
  
! /* Fold call to builtin cabs, cabsf or cabsl with argument ARG.  TYPE is the
!    return type.  Return NULL_TREE if no if no simplification can be made.  */
  
  static tree
! fold_builtin_cabs (tree arg, tree type)
  {
    if (TREE_CODE (TREE_TYPE (arg)) != COMPLEX_TYPE
        || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
      return NULL_TREE;
*************** fold_builtin_cabs (tree arglist, tree ty
*** 6825,6831 ****
  
        if (sqrtfn != NULL_TREE)
  	{
! 	  tree rpart, ipart, result, arglist;
  
  	  arg = builtin_save_expr (arg);
  
--- 6796,6802 ----
  
        if (sqrtfn != NULL_TREE)
  	{
! 	  tree rpart, ipart, result;
  
  	  arg = builtin_save_expr (arg);
  
*************** fold_builtin_cabs (tree arglist, tree ty
*** 6841,6865 ****
  				fold_build2 (MULT_EXPR, type,
  					     ipart, ipart));
  
! 	  arglist = build_tree_list (NULL_TREE, result);
! 	  return build_function_call_expr (sqrtfn, arglist);
  	}
      }
  
    return NULL_TREE;
  }
  
! /* Fold a builtin function call to sqrt, sqrtf, or sqrtl.  Return
!    NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_sqrt (tree arglist, tree type)
  {
  
    enum built_in_function fcode;
-   tree arg = TREE_VALUE (arglist);
  
!   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
      return NULL_TREE;
  
    /* Optimize sqrt of constant value.  */
--- 6812,6834 ----
  				fold_build2 (MULT_EXPR, type,
  					     ipart, ipart));
  
! 	  return build_call_expr (sqrtfn, 1, result);
  	}
      }
  
    return NULL_TREE;
  }
  
! /* Fold a builtin function call to sqrt, sqrtf, or sqrtl with argument ARG.
!    Return NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_sqrt (tree arg, tree type)
  {
  
    enum built_in_function fcode;
  
!   if (!validate_arg (arg, REAL_TYPE))
      return NULL_TREE;
  
    /* Optimize sqrt of constant value.  */
*************** fold_builtin_sqrt (tree arglist, tree ty
*** 6878,6889 ****
    fcode = builtin_mathfn_code (arg);
    if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
      {
!       tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
        arg = fold_build2 (MULT_EXPR, type,
! 			 TREE_VALUE (TREE_OPERAND (arg, 1)),
  			 build_real (type, dconsthalf));
!       arglist = build_tree_list (NULL_TREE, arg);
!       return build_function_call_expr (expfn, arglist);
      }
  
    /* Optimize sqrt(Nroot(x)) -> pow(x,1/(2*N)).  */
--- 6847,6857 ----
    fcode = builtin_mathfn_code (arg);
    if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
      {
!       tree expfn = TREE_OPERAND (CALL_EXPR_FN (arg), 0);
        arg = fold_build2 (MULT_EXPR, type,
! 			 CALL_EXPR_ARG0 (arg),
  			 build_real (type, dconsthalf));
!       return build_call_expr (expfn, 1, arg);
      }
  
    /* Optimize sqrt(Nroot(x)) -> pow(x,1/(2*N)).  */
*************** fold_builtin_sqrt (tree arglist, tree ty
*** 6893,6899 ****
  
        if (powfn)
  	{
! 	  tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
  	  tree tree_root;
  	  /* The inner root was either sqrt or cbrt.  */
  	  REAL_VALUE_TYPE dconstroot =
--- 6861,6867 ----
  
        if (powfn)
  	{
! 	  tree arg0 = CALL_EXPR_ARG0 (arg);
  	  tree tree_root;
  	  /* The inner root was either sqrt or cbrt.  */
  	  REAL_VALUE_TYPE dconstroot =
*************** fold_builtin_sqrt (tree arglist, tree ty
*** 6903,6911 ****
  	  SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
  	  dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
  	  tree_root = build_real (type, dconstroot);
! 	  arglist = tree_cons (NULL_TREE, arg0,
! 			       build_tree_list (NULL_TREE, tree_root));
! 	  return build_function_call_expr (powfn, arglist);
  	}
      }
  
--- 6871,6877 ----
  	  SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
  	  dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
  	  tree_root = build_real (type, dconstroot);
! 	  return build_call_expr (powfn, 2, arg0, tree_root);
  	}
      }
  
*************** fold_builtin_sqrt (tree arglist, tree ty
*** 6915,6945 ****
  	  || fcode == BUILT_IN_POWF
  	  || fcode == BUILT_IN_POWL))
      {
!       tree powfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
!       tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
!       tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1)));
        tree narg1;
        if (!tree_expr_nonnegative_p (arg0))
  	arg0 = build1 (ABS_EXPR, type, arg0);
        narg1 = fold_build2 (MULT_EXPR, type, arg1,
  			   build_real (type, dconsthalf));
!       arglist = tree_cons (NULL_TREE, arg0,
! 			   build_tree_list (NULL_TREE, narg1));
!       return build_function_call_expr (powfn, arglist);
      }
  
    return NULL_TREE;
  }
  
! /* Fold a builtin function call to cbrt, cbrtf, or cbrtl.  Return
!    NULL_TREE if no simplification can be made.  */
  static tree
! fold_builtin_cbrt (tree arglist, tree type)
  {
-   tree arg = TREE_VALUE (arglist);
    const enum built_in_function fcode = builtin_mathfn_code (arg);
  
!   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
      return NULL_TREE;
  
    /* Optimize cbrt of constant value.  */
--- 6881,6908 ----
  	  || fcode == BUILT_IN_POWF
  	  || fcode == BUILT_IN_POWL))
      {
!       tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg), 0);
!       tree arg0 = CALL_EXPR_ARG0 (arg);
!       tree arg1 = CALL_EXPR_ARG1 (arg);
        tree narg1;
        if (!tree_expr_nonnegative_p (arg0))
  	arg0 = build1 (ABS_EXPR, type, arg0);
        narg1 = fold_build2 (MULT_EXPR, type, arg1,
  			   build_real (type, dconsthalf));
!       return build_call_expr (powfn, 2, arg0, narg1);
      }
  
    return NULL_TREE;
  }
  
! /* Fold a builtin function call to cbrt, cbrtf, or cbrtl with argument ARG.
!    Return NULL_TREE if no simplification can be made.  */
  static tree
! fold_builtin_cbrt (tree arg, tree type)
  {
    const enum built_in_function fcode = builtin_mathfn_code (arg);
  
!   if (!validate_arg (arg, REAL_TYPE))
      return NULL_TREE;
  
    /* Optimize cbrt of constant value.  */
*************** fold_builtin_cbrt (tree arglist, tree ty
*** 6951,6964 ****
        /* Optimize cbrt(expN(x)) -> expN(x/3).  */
        if (BUILTIN_EXPONENT_P (fcode))
  	{
! 	  tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
  	  const REAL_VALUE_TYPE third_trunc =
  	    real_value_truncate (TYPE_MODE (type), dconstthird);
  	  arg = fold_build2 (MULT_EXPR, type,
  			     TREE_VALUE (TREE_OPERAND (arg, 1)),
  			     build_real (type, third_trunc));
! 	  arglist = build_tree_list (NULL_TREE, arg);
! 	  return build_function_call_expr (expfn, arglist);
  	}
  
        /* Optimize cbrt(sqrt(x)) -> pow(x,1/6).  */
--- 6914,6926 ----
        /* Optimize cbrt(expN(x)) -> expN(x/3).  */
        if (BUILTIN_EXPONENT_P (fcode))
  	{
! 	  tree expfn = TREE_OPERAND (CALL_EXPR_FN (arg), 0);
  	  const REAL_VALUE_TYPE third_trunc =
  	    real_value_truncate (TYPE_MODE (type), dconstthird);
  	  arg = fold_build2 (MULT_EXPR, type,
  			     TREE_VALUE (TREE_OPERAND (arg, 1)),
  			     build_real (type, third_trunc));
! 	  return build_call_expr (expfn, 1, arg);
  	}
  
        /* Optimize cbrt(sqrt(x)) -> pow(x,1/6).  */
*************** fold_builtin_cbrt (tree arglist, tree ty
*** 6968,6990 ****
  
  	  if (powfn)
  	    {
! 	      tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
  	      tree tree_root;
  	      REAL_VALUE_TYPE dconstroot = dconstthird;
  
  	      SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
  	      dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
  	      tree_root = build_real (type, dconstroot);
! 	      arglist = tree_cons (NULL_TREE, arg0,
! 				   build_tree_list (NULL_TREE, tree_root));
! 	      return build_function_call_expr (powfn, arglist);
  	    }
  	}
  
        /* Optimize cbrt(cbrt(x)) -> pow(x,1/9) iff x is nonnegative.  */
        if (BUILTIN_CBRT_P (fcode))
  	{
! 	  tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
  	  if (tree_expr_nonnegative_p (arg0))
  	    {
  	      tree powfn = mathfn_built_in (type, BUILT_IN_POW);
--- 6930,6950 ----
  
  	  if (powfn)
  	    {
! 	      tree arg0 = CALL_EXPR_ARG0 (arg);
  	      tree tree_root;
  	      REAL_VALUE_TYPE dconstroot = dconstthird;
  
  	      SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
  	      dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
  	      tree_root = build_real (type, dconstroot);
! 	      return build_call_expr (powfn, 2, arg0, tree_root);
  	    }
  	}
  
        /* Optimize cbrt(cbrt(x)) -> pow(x,1/9) iff x is nonnegative.  */
        if (BUILTIN_CBRT_P (fcode))
  	{
! 	  tree arg0 = CALL_EXPR_ARG0 (arg);
  	  if (tree_expr_nonnegative_p (arg0))
  	    {
  	      tree powfn = mathfn_built_in (type, BUILT_IN_POW);
*************** fold_builtin_cbrt (tree arglist, tree ty
*** 6997,7039 ****
  		  real_arithmetic (&dconstroot, MULT_EXPR, &dconstthird, &dconstthird);
  		  dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
  		  tree_root = build_real (type, dconstroot);
! 		  arglist = tree_cons (NULL_TREE, arg0,
! 				       build_tree_list (NULL_TREE, tree_root));
! 		  return build_function_call_expr (powfn, arglist);
  		}
  	    }
  	}
  
        /* Optimize cbrt(pow(x,y)) -> pow(x,y/3) iff x is nonnegative.  */
!       if (fcode == BUILT_IN_POW || fcode == BUILT_IN_POWF
  	  || fcode == BUILT_IN_POWL)
  	{
! 	  tree arg00 = TREE_VALUE (TREE_OPERAND (arg, 1));
! 	  tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1)));
  	  if (tree_expr_nonnegative_p (arg00))
  	    {
! 	      tree powfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
  	      const REAL_VALUE_TYPE dconstroot
  		= real_value_truncate (TYPE_MODE (type), dconstthird);
  	      tree narg01 = fold_build2 (MULT_EXPR, type, arg01,
  					 build_real (type, dconstroot));
! 	      arglist = tree_cons (NULL_TREE, arg00,
! 				   build_tree_list (NULL_TREE, narg01));
! 	      return build_function_call_expr (powfn, arglist);
  	    }
  	}
      }
    return NULL_TREE;
  }
  
! /* Fold function call to builtin sin, sinf, or sinl.  Return
!    NULL_TREE if no simplification can be made.  */
  static tree
! fold_builtin_sin (tree arglist)
  {
!   tree arg = TREE_VALUE (arglist);
! 
!   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
      return NULL_TREE;
  
    /* Optimize sin (0.0) = 0.0.  */
--- 6957,6994 ----
  		  real_arithmetic (&dconstroot, MULT_EXPR, &dconstthird, &dconstthird);
  		  dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
  		  tree_root = build_real (type, dconstroot);
! 		  return build_call_expr (powfn, 2, arg0, tree_root);
  		}
  	    }
  	}
  
        /* Optimize cbrt(pow(x,y)) -> pow(x,y/3) iff x is nonnegative.  */
!       if (fcode == BUILT_IN_POW
! 	  || fcode == BUILT_IN_POWF
  	  || fcode == BUILT_IN_POWL)
  	{
! 	  tree arg00 = CALL_EXPR_ARG0 (arg);
! 	  tree arg01 = CALL_EXPR_ARG1 (arg);
  	  if (tree_expr_nonnegative_p (arg00))
  	    {
! 	      tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg), 0);
  	      const REAL_VALUE_TYPE dconstroot
  		= real_value_truncate (TYPE_MODE (type), dconstthird);
  	      tree narg01 = fold_build2 (MULT_EXPR, type, arg01,
  					 build_real (type, dconstroot));
! 	      return build_call_expr (powfn, 2, arg00, narg01);
  	    }
  	}
      }
    return NULL_TREE;
  }
  
! /* Fold function call to builtin sin, sinf, or sinl with argument ARG.
!    Return NULL_TREE if no simplification can be made.  */
  static tree
! fold_builtin_sin (tree arg)
  {
!   if (!validate_arg (arg, REAL_TYPE))
      return NULL_TREE;
  
    /* Optimize sin (0.0) = 0.0.  */
*************** fold_builtin_sin (tree arglist)
*** 7043,7056 ****
    return NULL_TREE;
  }
  
! /* Fold function call to builtin cos, cosf, or cosl.  Return
!    NULL_TREE if no simplification can be made.  */
  static tree
! fold_builtin_cos (tree arglist, tree type, tree fndecl)
  {
!   tree arg = TREE_VALUE (arglist);
! 
!   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
      return NULL_TREE;
  
    /* Optimize cos (0.0) = 1.0.  */
--- 6998,7010 ----
    return NULL_TREE;
  }
  
! /* Fold function call to builtin cos, cosf, or cosl with argument ARG.
!    TYPE is the type of the return value.  Return NULL_TREE if no
!    simplification can be made.  */
  static tree
! fold_builtin_cos (tree arg, tree type, tree fndecl)
  {
!   if (!validate_arg (arg, REAL_TYPE))
      return NULL_TREE;
  
    /* Optimize cos (0.0) = 1.0.  */
*************** fold_builtin_cos (tree arglist, tree typ
*** 7059,7082 ****
  
    /* Optimize cos(-x) into cos (x).  */
    if (TREE_CODE (arg) == NEGATE_EXPR)
!     {
!       tree args = build_tree_list (NULL_TREE,
! 				   TREE_OPERAND (arg, 0));
!       return build_function_call_expr (fndecl, args);
!     }
  
    return NULL_TREE;
  }
  
! /* Fold function call to builtin tan, tanf, or tanl.  Return
!    NULL_TREE if no simplification can be made.  */
  static tree
! fold_builtin_tan (tree arglist)
  {
    enum built_in_function fcode;
-   tree arg = TREE_VALUE (arglist);
  
!   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
      return NULL_TREE;
  
    /* Optimize tan(0.0) = 0.0.  */
--- 7013,7031 ----
  
    /* Optimize cos(-x) into cos (x).  */
    if (TREE_CODE (arg) == NEGATE_EXPR)
!     return build_call_expr (fndecl, 1, TREE_OPERAND (arg, 0));
  
    return NULL_TREE;
  }
  
! /* Fold function call to builtin tan, tanf, or tanl with argument ARG.
!    Return NULL_TREE if no simplification can be made.  */
  static tree
! fold_builtin_tan (tree arg)
  {
    enum built_in_function fcode;
  
!   if (!validate_arg (arg, REAL_TYPE))
      return NULL_TREE;
  
    /* Optimize tan(0.0) = 0.0.  */
*************** fold_builtin_tan (tree arglist)
*** 7089,7109 ****
        && (fcode == BUILT_IN_ATAN
  	  || fcode == BUILT_IN_ATANF
  	  || fcode == BUILT_IN_ATANL))
!     return TREE_VALUE (TREE_OPERAND (arg, 1));
  
    return NULL_TREE;
  }
  
! /* Fold function call to builtin atan, atanf, or atanl.  Return
!    NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_atan (tree arglist, tree type)
  {
! 
!   tree arg = TREE_VALUE (arglist);
! 
!   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
      return NULL_TREE;
  
    /* Optimize atan(0.0) = 0.0.  */
--- 7038,7055 ----
        && (fcode == BUILT_IN_ATAN
  	  || fcode == BUILT_IN_ATANF
  	  || fcode == BUILT_IN_ATANL))
!     return CALL_EXPR_ARG0 (arg);
  
    return NULL_TREE;
  }
  
! /* Fold function call to builtin atan, atanf, or atanl with argument ARG.
!    Return NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_atan (tree arg, tree type)
  {
!   if (!validate_arg (arg, REAL_TYPE))
      return NULL_TREE;
  
    /* Optimize atan(0.0) = 0.0.  */
*************** fold_builtin_atan (tree arglist, tree ty
*** 7123,7141 ****
    return NULL_TREE;
  }
  
! /* Fold function call to builtin trunc, truncf or truncl.  Return
!    NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_trunc (tree fndecl, tree arglist)
  {
!   tree arg;
! 
!   if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
!     return 0;
  
    /* Optimize trunc of constant value.  */
-   arg = TREE_VALUE (arglist);
    if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
      {
        REAL_VALUE_TYPE r, x;
--- 7069,7084 ----
    return NULL_TREE;
  }
  
! /* Fold function call to builtin trunc, truncf or truncl with argument ARG.
!    Return NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_trunc (tree fndecl, tree arg)
  {
!   if (!validate_arg (arg, REAL_TYPE))
!     return NULL_TREE;
  
    /* Optimize trunc of constant value.  */
    if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
      {
        REAL_VALUE_TYPE r, x;
*************** fold_builtin_trunc (tree fndecl, tree ar
*** 7146,7167 ****
        return build_real (type, r);
      }
  
!   return fold_trunc_transparent_mathfn (fndecl, arglist);
  }
  
! /* Fold function call to builtin floor, floorf or floorl.  Return
!    NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_floor (tree fndecl, tree arglist)
  {
!   tree arg;
! 
!   if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
!     return 0;
  
    /* Optimize floor of constant value.  */
-   arg = TREE_VALUE (arglist);
    if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
      {
        REAL_VALUE_TYPE x;
--- 7089,7107 ----
        return build_real (type, r);
      }
  
!   return fold_trunc_transparent_mathfn (fndecl, arg);
  }
  
! /* Fold function call to builtin floor, floorf or floorl with argument ARG.
!    Return NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_floor (tree fndecl, tree arg)
  {
!   if (!validate_arg (arg, REAL_TYPE))
!     return NULL_TREE;
  
    /* Optimize floor of constant value.  */
    if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
      {
        REAL_VALUE_TYPE x;
*************** fold_builtin_floor (tree fndecl, tree ar
*** 7177,7198 ****
  	}
      }
  
!   return fold_trunc_transparent_mathfn (fndecl, arglist);
  }
  
! /* Fold function call to builtin ceil, ceilf or ceill.  Return
!    NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_ceil (tree fndecl, tree arglist)
  {
!   tree arg;
! 
!   if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
!     return 0;
  
    /* Optimize ceil of constant value.  */
-   arg = TREE_VALUE (arglist);
    if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
      {
        REAL_VALUE_TYPE x;
--- 7117,7135 ----
  	}
      }
  
!   return fold_trunc_transparent_mathfn (fndecl, arg);
  }
  
! /* Fold function call to builtin ceil, ceilf or ceill with argument ARG.
!    Return NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_ceil (tree fndecl, tree arg)
  {
!   if (!validate_arg (arg, REAL_TYPE))
!     return NULL_TREE;
  
    /* Optimize ceil of constant value.  */
    if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
      {
        REAL_VALUE_TYPE x;
*************** fold_builtin_ceil (tree fndecl, tree arg
*** 7208,7229 ****
  	}
      }
  
!   return fold_trunc_transparent_mathfn (fndecl, arglist);
  }
  
! /* Fold function call to builtin round, roundf or roundl.  Return
!    NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_round (tree fndecl, tree arglist)
  {
!   tree arg;
! 
!   if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
!     return 0;
  
    /* Optimize round of constant value.  */
-   arg = TREE_VALUE (arglist);
    if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
      {
        REAL_VALUE_TYPE x;
--- 7145,7163 ----
  	}
      }
  
!   return fold_trunc_transparent_mathfn (fndecl, arg);
  }
  
! /* Fold function call to builtin round, roundf or roundl with argument ARG.
!    Return NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_round (tree fndecl, tree arg)
  {
!   if (!validate_arg (arg, REAL_TYPE))
!     return NULL_TREE;
  
    /* Optimize round of constant value.  */
    if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
      {
        REAL_VALUE_TYPE x;
*************** fold_builtin_round (tree fndecl, tree ar
*** 7239,7261 ****
  	}
      }
  
!   return fold_trunc_transparent_mathfn (fndecl, arglist);
  }
  
  /* Fold function call to builtin lround, lroundf or lroundl (or the
!    corresponding long long versions) and other rounding functions.
!    Return NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_int_roundingfn (tree fndecl, tree arglist)
  {
!   tree arg;
! 
!   if (! validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
!     return 0;
  
    /* Optimize lround of constant value.  */
-   arg = TREE_VALUE (arglist);
    if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
      {
        const REAL_VALUE_TYPE x = TREE_REAL_CST (arg);
--- 7173,7193 ----
  	}
      }
  
!   return fold_trunc_transparent_mathfn (fndecl, arg);
  }
  
  /* Fold function call to builtin lround, lroundf or lroundl (or the
!    corresponding long long versions) and other rounding functions.  ARG
!    is the argument to the call.  Return NULL_TREE if no simplification
!    can be made.  */
  
  static tree
! fold_builtin_int_roundingfn (tree fndecl, tree arg)
  {
!   if (!validate_arg (arg, REAL_TYPE))
!     return NULL_TREE;
  
    /* Optimize lround of constant value.  */
    if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
      {
        const REAL_VALUE_TYPE x = TREE_REAL_CST (arg);
*************** fold_builtin_int_roundingfn (tree fndecl
*** 7295,7317 ****
  	}
      }
  
!   return fold_fixed_mathfn (fndecl, arglist);
  }
  
  /* Fold function call to builtin ffs, clz, ctz, popcount and parity
!    and their long and long long variants (i.e. ffsl and ffsll).
!    Return NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_bitop (tree fndecl, tree arglist)
  {
!   tree arg;
! 
!   if (! validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
      return NULL_TREE;
  
    /* Optimize for constant argument.  */
-   arg = TREE_VALUE (arglist);
    if (TREE_CODE (arg) == INTEGER_CST && ! TREE_CONSTANT_OVERFLOW (arg))
      {
        HOST_WIDE_INT hi, width, result;
--- 7227,7247 ----
  	}
      }
  
!   return fold_fixed_mathfn (fndecl, arg);
  }
  
  /* Fold function call to builtin ffs, clz, ctz, popcount and parity
!    and their long and long long variants (i.e. ffsl and ffsll).  ARG is
!    the argument to the call.  Return NULL_TREE if no simplification can
!    be made.  */
  
  static tree
! fold_builtin_bitop (tree fndecl, tree arg)
  {
!   if (!validate_arg (arg, INTEGER_TYPE))
      return NULL_TREE;
  
    /* Optimize for constant argument.  */
    if (TREE_CODE (arg) == INTEGER_CST && ! TREE_CONSTANT_OVERFLOW (arg))
      {
        HOST_WIDE_INT hi, width, result;
*************** real_dconstp (tree expr, const REAL_VALU
*** 7408,7424 ****
  }
  
  /* A subroutine of fold_builtin to fold the various logarithmic
!    functions.  EXP is the CALL_EXPR of a call to a builtin logN
     function.  VALUE is the base of the logN function.  */
  
  static tree
! fold_builtin_logarithm (tree fndecl, tree arglist,
  			const REAL_VALUE_TYPE *value)
  {
!   if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
      {
        tree type = TREE_TYPE (TREE_TYPE (fndecl));
-       tree arg = TREE_VALUE (arglist);
        const enum built_in_function fcode = builtin_mathfn_code (arg);
  
        /* Optimize logN(1.0) = 0.0.  */
--- 7338,7353 ----
  }
  
  /* A subroutine of fold_builtin to fold the various logarithmic
!    functions.  ARG is the argument of a call to a builtin logN
     function.  VALUE is the base of the logN function.  */
  
  static tree
! fold_builtin_logarithm (tree fndecl, tree arg,
  			const REAL_VALUE_TYPE *value)
  {
!   if (validate_arg (arg, REAL_TYPE))
      {
        tree type = TREE_TYPE (TREE_TYPE (fndecl));
        const enum built_in_function fcode = builtin_mathfn_code (arg);
  
        /* Optimize logN(1.0) = 0.0.  */
*************** fold_builtin_logarithm (tree fndecl, tre
*** 7447,7453 ****
  		      || fcode == BUILT_IN_EXP2F
  		      || fcode == BUILT_IN_EXP2L))
  	      || (value == &dconst10 && (BUILTIN_EXP10_P (fcode)))))
! 	return fold_convert (type, TREE_VALUE (TREE_OPERAND (arg, 1)));
  
        /* Optimize logN(func()) for various exponential functions.  We
  	 want to determine the value "x" and the power "exponent" in
--- 7376,7382 ----
  		      || fcode == BUILT_IN_EXP2F
  		      || fcode == BUILT_IN_EXP2L))
  	      || (value == &dconst10 && (BUILTIN_EXP10_P (fcode)))))
! 	return fold_convert (type, CALL_EXPR_ARG0 (arg));
  
        /* Optimize logN(func()) for various exponential functions.  We
  	 want to determine the value "x" and the power "exponent" in
*************** fold_builtin_logarithm (tree fndecl, tre
*** 7462,7495 ****
  	    /* Prepare to do logN(exp(exponent) -> exponent*logN(e).  */
  	    x = build_real (type,
  			    real_value_truncate (TYPE_MODE (type), dconste));
! 	    exponent = TREE_VALUE (TREE_OPERAND (arg, 1));
  	    break;
  	  CASE_FLT_FN (BUILT_IN_EXP2):
  	    /* Prepare to do logN(exp2(exponent) -> exponent*logN(2).  */
  	    x = build_real (type, dconst2);
! 	    exponent = TREE_VALUE (TREE_OPERAND (arg, 1));
  	    break;
  	  CASE_FLT_FN (BUILT_IN_EXP10):
  	  CASE_FLT_FN (BUILT_IN_POW10):
  	    /* Prepare to do logN(exp10(exponent) -> exponent*logN(10).  */
  	    x = build_real (type, dconst10);
! 	    exponent = TREE_VALUE (TREE_OPERAND (arg, 1));
  	    break;
  	  CASE_FLT_FN (BUILT_IN_SQRT):
  	    /* Prepare to do logN(sqrt(x) -> 0.5*logN(x).  */
! 	    x = TREE_VALUE (TREE_OPERAND (arg, 1));
  	    exponent = build_real (type, dconsthalf);
  	    break;
  	  CASE_FLT_FN (BUILT_IN_CBRT):
  	    /* Prepare to do logN(cbrt(x) -> (1/3)*logN(x).  */
! 	    x = TREE_VALUE (TREE_OPERAND (arg, 1));
  	    exponent = build_real (type, real_value_truncate (TYPE_MODE (type),
  							      dconstthird));
  	    break;
  	  CASE_FLT_FN (BUILT_IN_POW):
  	    /* Prepare to do logN(pow(x,exponent) -> exponent*logN(x).  */
! 	    x = TREE_VALUE (TREE_OPERAND (arg, 1));
! 	    exponent = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1)));
  	    break;
  	  default:
  	    break;
--- 7391,7424 ----
  	    /* Prepare to do logN(exp(exponent) -> exponent*logN(e).  */
  	    x = build_real (type,
  			    real_value_truncate (TYPE_MODE (type), dconste));
! 	    exponent = CALL_EXPR_ARG0 (arg);
  	    break;
  	  CASE_FLT_FN (BUILT_IN_EXP2):
  	    /* Prepare to do logN(exp2(exponent) -> exponent*logN(2).  */
  	    x = build_real (type, dconst2);
! 	    exponent = CALL_EXPR_ARG0 (arg);
  	    break;
  	  CASE_FLT_FN (BUILT_IN_EXP10):
  	  CASE_FLT_FN (BUILT_IN_POW10):
  	    /* Prepare to do logN(exp10(exponent) -> exponent*logN(10).  */
  	    x = build_real (type, dconst10);
! 	    exponent = CALL_EXPR_ARG0 (arg);
  	    break;
  	  CASE_FLT_FN (BUILT_IN_SQRT):
  	    /* Prepare to do logN(sqrt(x) -> 0.5*logN(x).  */
! 	    x = CALL_EXPR_ARG0 (arg);
  	    exponent = build_real (type, dconsthalf);
  	    break;
  	  CASE_FLT_FN (BUILT_IN_CBRT):
  	    /* Prepare to do logN(cbrt(x) -> (1/3)*logN(x).  */
! 	    x = CALL_EXPR_ARG0 (arg);
  	    exponent = build_real (type, real_value_truncate (TYPE_MODE (type),
  							      dconstthird));
  	    break;
  	  CASE_FLT_FN (BUILT_IN_POW):
  	    /* Prepare to do logN(pow(x,exponent) -> exponent*logN(x).  */
! 	    x = CALL_EXPR_ARG0 (arg);
! 	    exponent = CALL_EXPR_ARG1 (arg);
  	    break;
  	  default:
  	    break;
*************** fold_builtin_logarithm (tree fndecl, tre
*** 7498,7523 ****
  	  /* Now perform the optimization.  */
  	  if (x && exponent)
  	    {
! 	      tree logfn;
! 	      arglist = build_tree_list (NULL_TREE, x);
! 	      logfn = build_function_call_expr (fndecl, arglist);
  	      return fold_build2 (MULT_EXPR, type, exponent, logfn);
  	    }
  	}
      }
  
!   return 0;
  }
  
! /* Fold a builtin function call to pow, powf, or powl.  Return
!    NULL_TREE if no simplification can be made.  */
  static tree
! fold_builtin_pow (tree fndecl, tree arglist, tree type)
  {
!   tree arg0 = TREE_VALUE (arglist);
!   tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
! 
!   if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
      return NULL_TREE;
  
    /* Optimize pow(1.0,y) = 1.0.  */
--- 7427,7448 ----
  	  /* Now perform the optimization.  */
  	  if (x && exponent)
  	    {
! 	      tree logfn = build_call_expr (fndecl, 1, x);
  	      return fold_build2 (MULT_EXPR, type, exponent, logfn);
  	    }
  	}
      }
  
!   return NULL_TREE;
  }
  
! /* Fold a builtin function call to pow, powf, or powl with argument ARG.
!    Return NULL_TREE if no simplification can be made.  */
  static tree
! fold_builtin_pow (tree fndecl, tree arg0, tree arg1, tree type)
  {
!   if (!validate_arg (arg0, REAL_TYPE)
!       || !validate_arg (arg1, REAL_TYPE))
      return NULL_TREE;
  
    /* Optimize pow(1.0,y) = 1.0.  */
*************** fold_builtin_pow (tree fndecl, tree argl
*** 7554,7563 ****
  	  tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
  
  	  if (sqrtfn != NULL_TREE)
! 	    {
! 	      tree arglist = build_tree_list (NULL_TREE, arg0);
! 	      return build_function_call_expr (sqrtfn, arglist);
! 	    }
  	}
  
        /* Check for an integer exponent.  */
--- 7479,7485 ----
  	  tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
  
  	  if (sqrtfn != NULL_TREE)
! 	    return build_call_expr (sqrtfn, 1, arg0);
  	}
  
        /* Check for an integer exponent.  */
*************** fold_builtin_pow (tree fndecl, tree argl
*** 7583,7593 ****
  	    {
  	      tree narg0 = fold_strip_sign_ops (arg0);
  	      if (narg0)
! 		{
! 		  arglist = build_tree_list (NULL_TREE, arg1);
! 		  arglist = tree_cons (NULL_TREE, narg0, arglist);
! 		  return build_function_call_expr (fndecl, arglist);
! 		}
  	    }
  	}
      }
--- 7505,7511 ----
  	    {
  	      tree narg0 = fold_strip_sign_ops (arg0);
  	      if (narg0)
! 		return build_call_expr (fndecl, 2, narg0, arg1);
  	    }
  	}
      }
*************** fold_builtin_pow (tree fndecl, tree argl
*** 7599,7664 ****
        /* Optimize pow(expN(x),y) = expN(x*y).  */
        if (BUILTIN_EXPONENT_P (fcode))
  	{
! 	  tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
! 	  tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
  	  arg = fold_build2 (MULT_EXPR, type, arg, arg1);
! 	  arglist = build_tree_list (NULL_TREE, arg);
! 	  return build_function_call_expr (expfn, arglist);
  	}
  
        /* Optimize pow(sqrt(x),y) = pow(x,y*0.5).  */
        if (BUILTIN_SQRT_P (fcode))
  	{
! 	  tree narg0 = TREE_VALUE (TREE_OPERAND (arg0, 1));
  	  tree narg1 = fold_build2 (MULT_EXPR, type, arg1,
  				    build_real (type, dconsthalf));
! 
! 	  arglist = tree_cons (NULL_TREE, narg0,
! 			       build_tree_list (NULL_TREE, narg1));
! 	  return build_function_call_expr (fndecl, arglist);
  	}
  
        /* Optimize pow(cbrt(x),y) = pow(x,y/3) iff x is nonnegative.  */
        if (BUILTIN_CBRT_P (fcode))
  	{
! 	  tree arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
  	  if (tree_expr_nonnegative_p (arg))
  	    {
  	      const REAL_VALUE_TYPE dconstroot
  		= real_value_truncate (TYPE_MODE (type), dconstthird);
  	      tree narg1 = fold_build2 (MULT_EXPR, type, arg1,
  					build_real (type, dconstroot));
! 	      arglist = tree_cons (NULL_TREE, arg,
! 				   build_tree_list (NULL_TREE, narg1));
! 	      return build_function_call_expr (fndecl, arglist);
  	    }
  	}
  
        /* Optimize pow(pow(x,y),z) = pow(x,y*z).  */
!       if (fcode == BUILT_IN_POW || fcode == BUILT_IN_POWF
! 	   || fcode == BUILT_IN_POWL)
  	{
! 	  tree arg00 = TREE_VALUE (TREE_OPERAND (arg0, 1));
! 	  tree arg01 = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg0, 1)));
  	  tree narg1 = fold_build2 (MULT_EXPR, type, arg01, arg1);
! 	  arglist = tree_cons (NULL_TREE, arg00,
! 			       build_tree_list (NULL_TREE, narg1));
! 	  return build_function_call_expr (fndecl, arglist);
  	}
      }
  
    return NULL_TREE;
  }
  
! /* Fold a builtin function call to powi, powif, or powil.  Return
!    NULL_TREE if no simplification can be made.  */
  static tree
! fold_builtin_powi (tree fndecl ATTRIBUTE_UNUSED, tree arglist, tree type)
  {
!   tree arg0 = TREE_VALUE (arglist);
!   tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
! 
!   if (!validate_arglist (arglist, REAL_TYPE, INTEGER_TYPE, VOID_TYPE))
      return NULL_TREE;
  
    /* Optimize pow(1.0,y) = 1.0.  */
--- 7517,7574 ----
        /* Optimize pow(expN(x),y) = expN(x*y).  */
        if (BUILTIN_EXPONENT_P (fcode))
  	{
! 	  tree expfn = TREE_OPERAND (CALL_EXPR_FN (arg0), 0);
! 	  tree arg = CALL_EXPR_ARG0 (arg0);
  	  arg = fold_build2 (MULT_EXPR, type, arg, arg1);
! 	  return build_call_expr (expfn, 1, arg);
  	}
  
        /* Optimize pow(sqrt(x),y) = pow(x,y*0.5).  */
        if (BUILTIN_SQRT_P (fcode))
  	{
! 	  tree narg0 = CALL_EXPR_ARG0 (arg0);
  	  tree narg1 = fold_build2 (MULT_EXPR, type, arg1,
  				    build_real (type, dconsthalf));
! 	  return build_call_expr (fndecl, 2, narg0, narg1);
  	}
  
        /* Optimize pow(cbrt(x),y) = pow(x,y/3) iff x is nonnegative.  */
        if (BUILTIN_CBRT_P (fcode))
  	{
! 	  tree arg = CALL_EXPR_ARG0 (arg0);
  	  if (tree_expr_nonnegative_p (arg))
  	    {
  	      const REAL_VALUE_TYPE dconstroot
  		= real_value_truncate (TYPE_MODE (type), dconstthird);
  	      tree narg1 = fold_build2 (MULT_EXPR, type, arg1,
  					build_real (type, dconstroot));
! 	      return build_call_expr (fndecl, 2, arg, narg1);
  	    }
  	}
  
        /* Optimize pow(pow(x,y),z) = pow(x,y*z).  */
!       if (fcode == BUILT_IN_POW
! 	  || fcode == BUILT_IN_POWF
! 	  || fcode == BUILT_IN_POWL)
  	{
! 	  tree arg00 = CALL_EXPR_ARG0 (arg0);
! 	  tree arg01 = CALL_EXPR_ARG1 (arg0);
  	  tree narg1 = fold_build2 (MULT_EXPR, type, arg01, arg1);
! 	  return build_call_expr (fndecl, 2, arg00, narg1);
  	}
      }
  
    return NULL_TREE;
  }
  
! /* Fold a builtin function call to powi, powif, or powil with argument ARG.
!    Return NULL_TREE if no simplification can be made.  */
  static tree
! fold_builtin_powi (tree fndecl ATTRIBUTE_UNUSED,
! 		   tree arg0, tree arg1, tree type)
  {
!   if (!validate_arg (arg0, REAL_TYPE)
!       || !validate_arg (arg1, INTEGER_TYPE))
      return NULL_TREE;
  
    /* Optimize pow(1.0,y) = 1.0.  */
*************** fold_builtin_powi (tree fndecl ATTRIBUTE
*** 7698,7714 ****
  }
  
  /* A subroutine of fold_builtin to fold the various exponent
!    functions.  EXP is the CALL_EXPR of a call to a builtin function.
     VALUE is the value which will be raised to a power.  */
  
  static tree
! fold_builtin_exponent (tree fndecl, tree arglist,
  		       const REAL_VALUE_TYPE *value)
  {
!   if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
      {
        tree type = TREE_TYPE (TREE_TYPE (fndecl));
-       tree arg = TREE_VALUE (arglist);
  
        /* Optimize exp*(0.0) = 1.0.  */
        if (real_zerop (arg))
--- 7608,7623 ----
  }
  
  /* A subroutine of fold_builtin to fold the various exponent
!    functions.  ARG is the argument of a call to a builtin function.
     VALUE is the value which will be raised to a power.  */
  
  static tree
! fold_builtin_exponent (tree fndecl, tree arg,
  		       const REAL_VALUE_TYPE *value)
  {
!   if (validate_arg (arg, REAL_TYPE))
      {
        tree type = TREE_TYPE (TREE_TYPE (fndecl));
  
        /* Optimize exp*(0.0) = 1.0.  */
        if (real_zerop (arg))
*************** fold_builtin_exponent (tree fndecl, tree
*** 7762,7851 ****
  		  && (fcode == BUILT_IN_LOG10
  		      || fcode == BUILT_IN_LOG10F
  		      || fcode == BUILT_IN_LOG10L)))
! 	    return fold_convert (type, TREE_VALUE (TREE_OPERAND (arg, 1)));
  	}
      }
  
!   return 0;
  }
  
! /* Fold function call to builtin memcpy.  Return
!    NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_memcpy (tree fndecl, tree arglist)
  {
!   tree dest, src, len;
! 
!   if (!validate_arglist (arglist,
! 			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
! 
!   dest = TREE_VALUE (arglist);
!   src = TREE_VALUE (TREE_CHAIN (arglist));
!   len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
  
    /* If the LEN parameter is zero, return DEST.  */
    if (integer_zerop (len))
!     return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
  
    /* If SRC and DEST are the same (and not volatile), return DEST.  */
    if (operand_equal_p (src, dest, 0))
!     return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, len);
  
!   return 0;
  }
  
! /* Fold function call to builtin mempcpy.  Return
!    NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_mempcpy (tree arglist, tree type, int endp)
  {
!   if (validate_arglist (arglist,
! 			POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     {
!       tree dest = TREE_VALUE (arglist);
!       tree src = TREE_VALUE (TREE_CHAIN (arglist));
!       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
! 
!       /* If the LEN parameter is zero, return DEST.  */
!       if (integer_zerop (len))
! 	return omit_one_operand (type, dest, src);
  
!       /* If SRC and DEST are the same (and not volatile), return DEST+LEN.  */
!       if (operand_equal_p (src, dest, 0))
! 	{
! 	  if (endp == 0)
! 	    return omit_one_operand (type, dest, len);
  
! 	  if (endp == 2)
! 	    len = fold_build2 (MINUS_EXPR, TREE_TYPE (len), len,
! 			       ssize_int (1));
  
! 	  len = fold_convert (TREE_TYPE (dest), len);
! 	  len = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, len);
! 	  return fold_convert (type, len);
! 	}
      }
!   return 0;
  }
  
! /* Fold function call to builtin memmove.  Return
!    NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_memmove (tree arglist, tree type)
  {
-   tree dest, src, len;
- 
-   if (!validate_arglist (arglist,
- 			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
-     return 0;
  
!   dest = TREE_VALUE (arglist);
!   src = TREE_VALUE (TREE_CHAIN (arglist));
!   len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
  
    /* If the LEN parameter is zero, return DEST.  */
    if (integer_zerop (len))
--- 7671,7752 ----
  		  && (fcode == BUILT_IN_LOG10
  		      || fcode == BUILT_IN_LOG10F
  		      || fcode == BUILT_IN_LOG10L)))
! 	    return fold_convert (type, CALL_EXPR_ARG0 (arg));
  	}
      }
  
!   return NULL_TREE;
  }
  
! /* Fold function call to builtin memcpy with arguments DEST, SRC, and LEN.
!    TYPE is the return type of the call.  Return NULL_TREE if no
!    simplification can be made.  */
  
  static tree
! fold_builtin_memcpy (tree dest, tree src, tree len, tree type)
  {
!   if (!validate_arg (dest, POINTER_TYPE)
!       || !validate_arg (src, POINTER_TYPE)
!       || !validate_arg (len, INTEGER_TYPE))
!     return NULL_TREE;
  
    /* If the LEN parameter is zero, return DEST.  */
    if (integer_zerop (len))
!     return omit_one_operand (type, dest, src);
  
    /* If SRC and DEST are the same (and not volatile), return DEST.  */
    if (operand_equal_p (src, dest, 0))
!     return omit_one_operand (type, dest, len);
  
!   return NULL_TREE;
  }
  
! /* Fold function call to builtin mempcpy with arguments DEST, SRC, and LEN.
!    TYPE is the return type of the call.  Return NULL_TREE if no
!    simplification can be made.  */
  
  static tree
! fold_builtin_mempcpy (tree dest, tree src, tree len, tree type, int endp)
  {
!   if (!validate_arg (dest, POINTER_TYPE)
!       || !validate_arg (src, POINTER_TYPE)
!       || !validate_arg (len, INTEGER_TYPE))
!     return NULL_TREE;
  
!   /* If the LEN parameter is zero, return DEST.  */
!   if (integer_zerop (len))
!     return omit_one_operand (type, dest, src);
  
!   /* If SRC and DEST are the same (and not volatile), return DEST+LEN.  */
!   if (operand_equal_p (src, dest, 0))
!     {
!       if (endp == 0)
! 	return omit_one_operand (type, dest, len);
  
!       if (endp == 2)
! 	len = fold_build2 (MINUS_EXPR, TREE_TYPE (len), len,
! 			   ssize_int (1));
! 
!       len = fold_convert (TREE_TYPE (dest), len);
!       len = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, len);
!       return fold_convert (type, len);
      }
! 
!   return NULL_TREE;
  }
  
! /* Fold function call to builtin memmove with arguments DEST, SRC, and LEN.
!    TYPE is the return type of the call.  Return NULL_TREE if no
!    simplification can be made.  */
  
  static tree
! fold_builtin_memmove (tree dest, tree src, tree len, tree type)
  {
  
!   if (!validate_arg (dest, POINTER_TYPE)
!       || !validate_arg (src, POINTER_TYPE)
!       || !validate_arg (len, INTEGER_TYPE))
!     return NULL_TREE;
  
    /* If the LEN parameter is zero, return DEST.  */
    if (integer_zerop (len))
*************** fold_builtin_memmove (tree arglist, tree
*** 7855,7921 ****
    if (operand_equal_p (src, dest, 0))
      return omit_one_operand (type, dest, len);
  
!   return 0;
  }
  
! /* Fold function call to builtin strcpy.  If LEN is not NULL, it represents
!    the length of the string to be copied.  Return NULL_TREE if no
!    simplification can be made.  */
  
  tree
! fold_builtin_strcpy (tree fndecl, tree arglist, tree len)
  {
!   tree dest, src, fn;
! 
!   if (!validate_arglist (arglist,
! 			 POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
!     return 0;
  
!   dest = TREE_VALUE (arglist);
!   src = TREE_VALUE (TREE_CHAIN (arglist));
  
    /* If SRC and DEST are the same (and not volatile), return DEST.  */
    if (operand_equal_p (src, dest, 0))
      return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), dest);
  
    if (optimize_size)
!     return 0;
  
    fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
    if (!fn)
!     return 0;
  
    if (!len)
      {
        len = c_strlen (src, 1);
        if (! len || TREE_SIDE_EFFECTS (len))
! 	return 0;
      }
  
    len = size_binop (PLUS_EXPR, len, ssize_int (1));
-   arglist = build_tree_list (NULL_TREE, len);
-   arglist = tree_cons (NULL_TREE, src, arglist);
-   arglist = tree_cons (NULL_TREE, dest, arglist);
    return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)),
! 		       build_function_call_expr (fn, arglist));
  }
  
! /* Fold function call to builtin strncpy.  If SLEN is not NULL, it represents
!    the length of the source string.  Return NULL_TREE if no simplification
!    can be made.  */
  
  tree
! fold_builtin_strncpy (tree fndecl, tree arglist, tree slen)
  {
!   tree dest, src, len, fn;
! 
!   if (!validate_arglist (arglist,
! 			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
  
!   dest = TREE_VALUE (arglist);
!   src = TREE_VALUE (TREE_CHAIN (arglist));
!   len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
  
    /* If the LEN parameter is zero, return DEST.  */
    if (integer_zerop (len))
--- 7756,7813 ----
    if (operand_equal_p (src, dest, 0))
      return omit_one_operand (type, dest, len);
  
!   return NULL_TREE;
  }
  
! /* Fold function call to builtin strcpy with arguments DEST and SRC.
!    If LEN is not NULL, it represents the length of the string to be
!    copied.  Return NULL_TREE if no simplification can be made.  */
  
  tree
! fold_builtin_strcpy (tree fndecl, tree dest, tree src, tree len)
  {
!   tree fn;
  
!   if (!validate_arg (dest, POINTER_TYPE)
!       || !validate_arg (src, POINTER_TYPE))
!     return NULL_TREE;
  
    /* If SRC and DEST are the same (and not volatile), return DEST.  */
    if (operand_equal_p (src, dest, 0))
      return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), dest);
  
    if (optimize_size)
!     return NULL_TREE;
  
    fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
    if (!fn)
!     return NULL_TREE;
  
    if (!len)
      {
        len = c_strlen (src, 1);
        if (! len || TREE_SIDE_EFFECTS (len))
! 	return NULL_TREE;
      }
  
    len = size_binop (PLUS_EXPR, len, ssize_int (1));
    return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)),
! 		       build_call_expr (fn, 3, dest, src, len));
  }
  
! /* Fold function call to builtin strncpy with arguments DEST, SRC, and LEN.
!    If SLEN is not NULL, it represents the length of the source string.
!    Return NULL_TREE if no simplification can be made.  */
  
  tree
! fold_builtin_strncpy (tree fndecl, tree dest, tree src, tree len, tree slen)
  {
!   tree fn;
  
!   if (!validate_arg (dest, POINTER_TYPE)
!       || !validate_arg (src, POINTER_TYPE)
!       || !validate_arg (len, INTEGER_TYPE))
!     return NULL_TREE;
  
    /* If the LEN parameter is zero, return DEST.  */
    if (integer_zerop (len))
*************** fold_builtin_strncpy (tree fndecl, tree 
*** 7924,7937 ****
    /* We can't compare slen with len as constants below if len is not a
       constant.  */
    if (len == 0 || TREE_CODE (len) != INTEGER_CST)
!     return 0;
  
    if (!slen)
      slen = c_strlen (src, 1);
  
    /* 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));
  
--- 7816,7829 ----
    /* We can't compare slen with len as constants below if len is not a
       constant.  */
    if (len == 0 || TREE_CODE (len) != INTEGER_CST)
!     return NULL_TREE;
  
    if (!slen)
      slen = c_strlen (src, 1);
  
    /* Now, we must be passed a constant src ptr parameter.  */
    if (slen == 0 || TREE_CODE (slen) != INTEGER_CST)
!     return NULL_TREE;
  
    slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
  
*************** fold_builtin_strncpy (tree fndecl, tree 
*** 7939,7970 ****
       support it when expanding trees into RTL.  */
    /* FIXME: generate a call to __builtin_memset.  */
    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 fold_convert (TREE_TYPE (TREE_TYPE (fndecl)),
! 		       build_function_call_expr (fn, arglist));
  }
  
! /* Fold function call to builtin memcmp.  Return
!    NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_memcmp (tree arglist)
  {
-   tree arg1, arg2, len;
    const char *p1, *p2;
  
!   if (!validate_arglist (arglist,
! 			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
! 
!   arg1 = TREE_VALUE (arglist);
!   arg2 = TREE_VALUE (TREE_CHAIN (arglist));
!   len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
  
    /* If the LEN parameter is zero, return zero.  */
    if (integer_zerop (len))
--- 7831,7858 ----
       support it when expanding trees into RTL.  */
    /* FIXME: generate a call to __builtin_memset.  */
    if (tree_int_cst_lt (slen, len))
!     return NULL_TREE;
  
    /* OK transform into builtin memcpy.  */
    fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
    if (!fn)
!     return NULL_TREE;
    return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)),
! 		       build_call_expr (fn, 3, dest, src, len));
  }
  
! /* Fold function call to builtin memcmp with arguments ARG1 and ARG2.
!    Return NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_memcmp (tree arg1, tree arg2, tree len)
  {
    const char *p1, *p2;
  
!   if (!validate_arg (arg1, POINTER_TYPE)
!       || !validate_arg (arg2, POINTER_TYPE)
!       || !validate_arg (len, INTEGER_TYPE))
!     return NULL_TREE;
  
    /* If the LEN parameter is zero, return zero.  */
    if (integer_zerop (len))
*************** fold_builtin_memcmp (tree arglist)
*** 8013,8035 ****
        return fold_build2 (MINUS_EXPR, integer_type_node, ind1, ind2);
      }
  
!   return 0;
  }
  
! /* Fold function call to builtin strcmp.  Return
!    NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_strcmp (tree arglist)
  {
-   tree arg1, arg2;
    const char *p1, *p2;
  
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
!     return 0;
! 
!   arg1 = TREE_VALUE (arglist);
!   arg2 = TREE_VALUE (TREE_CHAIN (arglist));
  
    /* If ARG1 and ARG2 are the same (and not volatile), return zero.  */
    if (operand_equal_p (arg1, arg2, 0))
--- 7901,7920 ----
        return fold_build2 (MINUS_EXPR, integer_type_node, ind1, ind2);
      }
  
!   return NULL_TREE;
  }
  
! /* Fold function call to builtin strcmp with arguments ARG1 and ARG2.
!    Return NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_strcmp (tree arg1, tree arg2)
  {
    const char *p1, *p2;
  
!   if (!validate_arg (arg1, POINTER_TYPE)
!       || !validate_arg (arg2, POINTER_TYPE))
!     return NULL_TREE;
  
    /* If ARG1 and ARG2 are the same (and not volatile), return zero.  */
    if (operand_equal_p (arg1, arg2, 0))
*************** fold_builtin_strcmp (tree arglist)
*** 8076,8100 ****
        return fold_build1 (NEGATE_EXPR, integer_type_node, temp);
      }
  
!   return 0;
  }
  
! /* Fold function call to builtin strncmp.  Return
!    NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_strncmp (tree arglist)
  {
-   tree arg1, arg2, len;
    const char *p1, *p2;
  
!   if (!validate_arglist (arglist,
! 			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
! 
!   arg1 = TREE_VALUE (arglist);
!   arg2 = TREE_VALUE (TREE_CHAIN (arglist));
!   len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
  
    /* If the LEN parameter is zero, return zero.  */
    if (integer_zerop (len))
--- 7961,7981 ----
        return fold_build1 (NEGATE_EXPR, integer_type_node, temp);
      }
  
!   return NULL_TREE;
  }
  
! /* Fold function call to builtin strncmp with arguments ARG1, ARG2, and LEN.
!    Return NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_strncmp (tree arg1, tree arg2, tree len)
  {
    const char *p1, *p2;
  
!   if (!validate_arg (arg1, POINTER_TYPE)
!       || !validate_arg (arg2, POINTER_TYPE)
!       || !validate_arg (len, INTEGER_TYPE))
!     return NULL_TREE;
  
    /* If the LEN parameter is zero, return zero.  */
    if (integer_zerop (len))
*************** fold_builtin_strncmp (tree arglist)
*** 8171,8193 ****
        return fold_build2 (MINUS_EXPR, integer_type_node, ind1, ind2);
      }
  
!   return 0;
  }
  
! /* Fold function call to builtin signbit, signbitf or signbitl.  Return
!    NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_signbit (tree fndecl, tree arglist)
  {
!   tree type = TREE_TYPE (TREE_TYPE (fndecl));
!   tree arg, temp;
  
!   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
      return NULL_TREE;
  
-   arg = TREE_VALUE (arglist);
- 
    /* If ARG is a compile-time constant, determine the result.  */
    if (TREE_CODE (arg) == REAL_CST
        && !TREE_CONSTANT_OVERFLOW (arg))
--- 8052,8071 ----
        return fold_build2 (MINUS_EXPR, integer_type_node, ind1, ind2);
      }
  
!   return NULL_TREE;
  }
  
! /* Fold function call to builtin signbit, signbitf or signbitl with argument
!    ARG.  Return NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_signbit (tree arg, tree type)
  {
!   tree temp;
  
!   if (!validate_arg (arg, REAL_TYPE))
      return NULL_TREE;
  
    /* If ARG is a compile-time constant, determine the result.  */
    if (TREE_CODE (arg) == REAL_CST
        && !TREE_CONSTANT_OVERFLOW (arg))
*************** fold_builtin_signbit (tree fndecl, tree 
*** 8211,8230 ****
    return NULL_TREE;
  }
  
! /* Fold function call to builtin copysign, copysignf or copysignl.
!    Return NULL_TREE if no simplification can be made.  */
  
  static tree
! fold_builtin_copysign (tree fndecl, tree arglist, tree type)
  {
!   tree arg1, arg2, tem;
  
!   if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
      return NULL_TREE;
  
-   arg1 = TREE_VALUE (arglist);
-   arg2 = TREE_VALUE (TREE_CHAIN (arglist));
- 
    /* copysign(X,X) is X.  */
    if (operand_equal_p (arg1, arg2, 0))
      return fold_convert (type, arg1);
--- 8089,8107 ----
    return NULL_TREE;
  }
  
! /* Fold function call to builtin copysign, copysignf or copysignl with
!    arguments ARG1 and ARG2.  Return NULL_TREE if no simplification can
!    be made.  */
  
  static tree
! fold_builtin_copysign (tree fndecl, tree arg1, tree arg2, tree type)
  {
!   tree tem;
  
!   if (!validate_arg (arg1, REAL_TYPE)
!       || !validate_arg (arg2, REAL_TYPE))
      return NULL_TREE;
  
    /* copysign(X,X) is X.  */
    if (operand_equal_p (arg1, arg2, 0))
      return fold_convert (type, arg1);
*************** fold_builtin_copysign (tree fndecl, tree
*** 8254,8279 ****
    /* Strip sign changing operations for the first argument.  */
    tem = fold_strip_sign_ops (arg1);
    if (tem)
!     {
!       arglist = tree_cons (NULL_TREE, tem, TREE_CHAIN (arglist));
!       return build_function_call_expr (fndecl, arglist);
!     }
  
    return NULL_TREE;
  }
  
! /* Fold a call to builtin isascii.  */
  
  static tree
! fold_builtin_isascii (tree arglist)
  {
!   if (! validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
        /* Transform isascii(c) -> ((c & ~0x7f) == 0).  */
-       tree arg = TREE_VALUE (arglist);
- 
        arg = build2 (BIT_AND_EXPR, integer_type_node, arg,
  		    build_int_cst (NULL_TREE,
  				   ~ (unsigned HOST_WIDE_INT) 0x7f));
--- 8131,8151 ----
    /* Strip sign changing operations for the first argument.  */
    tem = fold_strip_sign_ops (arg1);
    if (tem)
!     return build_call_expr (fndecl, 2, tem, arg2);
  
    return NULL_TREE;
  }
  
! /* Fold a call to builtin isascii with argument ARG.  */
  
  static tree
! fold_builtin_isascii (tree arg)
  {
!   if (!validate_arg (arg, INTEGER_TYPE))
!     return NULL_TREE;
    else
      {
        /* Transform isascii(c) -> ((c & ~0x7f) == 0).  */
        arg = build2 (BIT_AND_EXPR, integer_type_node, arg,
  		    build_int_cst (NULL_TREE,
  				   ~ (unsigned HOST_WIDE_INT) 0x7f));
*************** fold_builtin_isascii (tree arglist)
*** 8287,8329 ****
      }
  }
  
! /* Fold a call to builtin toascii.  */
  
  static tree
! fold_builtin_toascii (tree arglist)
  {
!   if (! validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
        /* Transform toascii(c) -> (c & 0x7f).  */
-       tree arg = TREE_VALUE (arglist);
- 
        return fold_build2 (BIT_AND_EXPR, integer_type_node, arg,
  			  build_int_cst (NULL_TREE, 0x7f));
      }
  }
  
! /* Fold a call to builtin isdigit.  */
  
  static tree
! fold_builtin_isdigit (tree arglist)
  {
!   if (! validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
        /* Transform isdigit(c) -> (unsigned)(c) - '0' <= 9.  */
        /* According to the C standard, isdigit is unaffected by locale.
  	 However, it definitely is affected by the target character set.  */
-       tree arg;
        unsigned HOST_WIDE_INT target_digit0
  	= lang_hooks.to_target_charset ('0');
  
        if (target_digit0 == 0)
  	return NULL_TREE;
  
!       arg = fold_convert (unsigned_type_node, TREE_VALUE (arglist));
        arg = build2 (MINUS_EXPR, unsigned_type_node, arg,
  		    build_int_cst (unsigned_type_node, target_digit0));
        arg = fold_build2 (LE_EXPR, integer_type_node, arg,
--- 8159,8198 ----
      }
  }
  
! /* Fold a call to builtin toascii with argument ARG.  */
  
  static tree
! fold_builtin_toascii (tree arg)
  {
!   if (!validate_arg (arg, INTEGER_TYPE))
!     return NULL_TREE;
    else
      {
        /* Transform toascii(c) -> (c & 0x7f).  */
        return fold_build2 (BIT_AND_EXPR, integer_type_node, arg,
  			  build_int_cst (NULL_TREE, 0x7f));
      }
  }
  
! /* Fold a call to builtin isdigit with argument ARG.  */
  
  static tree
! fold_builtin_isdigit (tree arg)
  {
!   if (!validate_arg (arg, INTEGER_TYPE))
!     return NULL_TREE;
    else
      {
        /* Transform isdigit(c) -> (unsigned)(c) - '0' <= 9.  */
        /* According to the C standard, isdigit is unaffected by locale.
  	 However, it definitely is affected by the target character set.  */
        unsigned HOST_WIDE_INT target_digit0
  	= lang_hooks.to_target_charset ('0');
  
        if (target_digit0 == 0)
  	return NULL_TREE;
  
!       arg = fold_convert (unsigned_type_node, arg);
        arg = build2 (MINUS_EXPR, unsigned_type_node, arg,
  		    build_int_cst (unsigned_type_node, target_digit0));
        arg = fold_build2 (LE_EXPR, integer_type_node, arg,
*************** fold_builtin_isdigit (tree arglist)
*** 8335,8368 ****
      }
  }
  
! /* Fold a call to fabs, fabsf or fabsl.  */
  
  static tree
! fold_builtin_fabs (tree arglist, tree type)
  {
!   tree arg;
! 
!   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
!     return 0;
  
-   arg = TREE_VALUE (arglist);
    arg = fold_convert (type, arg);
    if (TREE_CODE (arg) == REAL_CST)
      return fold_abs_const (arg, type);
    return fold_build1 (ABS_EXPR, type, arg);
  }
  
! /* Fold a call to abs, labs, llabs or imaxabs.  */
  
  static tree
! fold_builtin_abs (tree arglist, tree type)
  {
!   tree arg;
! 
!   if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
!     return 0;
  
-   arg = TREE_VALUE (arglist);
    arg = fold_convert (type, arg);
    if (TREE_CODE (arg) == INTEGER_CST)
      return fold_abs_const (arg, type);
--- 8204,8231 ----
      }
  }
  
! /* Fold a call to fabs, fabsf or fabsl with argument ARG.  */
  
  static tree
! fold_builtin_fabs (tree arg, tree type)
  {
!   if (!validate_arg (arg, REAL_TYPE))
!     return NULL_TREE;
  
    arg = fold_convert (type, arg);
    if (TREE_CODE (arg) == REAL_CST)
      return fold_abs_const (arg, type);
    return fold_build1 (ABS_EXPR, type, arg);
  }
  
! /* Fold a call to abs, labs, llabs or imaxabs with argument ARG.  */
  
  static tree
! fold_builtin_abs (tree arg, tree type)
  {
!   if (!validate_arg (arg, INTEGER_TYPE))
!     return NULL_TREE;
  
    arg = fold_convert (type, arg);
    if (TREE_CODE (arg) == INTEGER_CST)
      return fold_abs_const (arg, type);
*************** fold_builtin_abs (tree arglist, tree typ
*** 8370,8408 ****
  }
  
  /* Fold a call to __builtin_isnan(), __builtin_isinf, __builtin_finite.
!    EXP is the CALL_EXPR for the call.  */
  
  static tree
! fold_builtin_classify (tree fndecl, tree arglist, int builtin_index)
  {
    tree type = TREE_TYPE (TREE_TYPE (fndecl));
-   tree arg;
    REAL_VALUE_TYPE r;
  
!   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
      {
!       /* Check that we have exactly one argument.  */
!       if (arglist == 0)
! 	{
! 	  error ("too few arguments to function %qs",
! 		 IDENTIFIER_POINTER (DECL_NAME (fndecl)));
! 	  return error_mark_node;
! 	}
!       else if (TREE_CHAIN (arglist) != 0)
! 	{
! 	  error ("too many arguments to function %qs",
! 		 IDENTIFIER_POINTER (DECL_NAME (fndecl)));
! 	  return error_mark_node;
! 	}
!       else
! 	{
! 	  error ("non-floating-point argument to function %qs",
! 		 IDENTIFIER_POINTER (DECL_NAME (fndecl)));
! 	  return error_mark_node;
! 	}
      }
  
-   arg = TREE_VALUE (arglist);
    switch (builtin_index)
      {
      case BUILT_IN_ISINF:
--- 8233,8253 ----
  }
  
  /* Fold a call to __builtin_isnan(), __builtin_isinf, __builtin_finite.
!    ARG is the argument for the call.  */
  
  static tree
! fold_builtin_classify (tree fndecl, tree arg, int builtin_index)
  {
    tree type = TREE_TYPE (TREE_TYPE (fndecl));
    REAL_VALUE_TYPE r;
  
!   if (!validate_arg (arg, REAL_TYPE))
      {
!       error ("non-floating-point argument to function %qs",
! 	     IDENTIFIER_POINTER (DECL_NAME (fndecl)));
!       return error_mark_node;
      }
  
    switch (builtin_index)
      {
      case BUILT_IN_ISINF:
*************** fold_builtin_classify (tree fndecl, tree
*** 8455,8498 ****
  
  /* Fold a call to an unordered comparison function such as
     __builtin_isgreater().  FNDECL is the FUNCTION_DECL for the function
!    being called and ARGLIST is the argument list for the call.
     UNORDERED_CODE and ORDERED_CODE are comparison codes that give
     the opposite of the desired result.  UNORDERED_CODE is used
     for modes that can hold NaNs and ORDERED_CODE is used for
     the rest.  */
  
  static tree
! fold_builtin_unordered_cmp (tree fndecl, tree arglist,
  			    enum tree_code unordered_code,
  			    enum tree_code ordered_code)
  {
    tree type = TREE_TYPE (TREE_TYPE (fndecl));
    enum tree_code code;
-   tree arg0, arg1;
    tree type0, type1;
    enum tree_code code0, code1;
    tree cmp_type = NULL_TREE;
  
-   if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
-     {
-       /* Check that we have exactly two arguments.  */
-       if (arglist == 0 || TREE_CHAIN (arglist) == 0)
- 	{
- 	  error ("too few arguments to function %qs",
- 		 IDENTIFIER_POINTER (DECL_NAME (fndecl)));
- 	  return error_mark_node;
- 	}
-       else if (TREE_CHAIN (TREE_CHAIN (arglist)) != 0)
- 	{
- 	  error ("too many arguments to function %qs",
- 		 IDENTIFIER_POINTER (DECL_NAME (fndecl)));
- 	  return error_mark_node;
- 	}
-     }
- 
-   arg0 = TREE_VALUE (arglist);
-   arg1 = TREE_VALUE (TREE_CHAIN (arglist));
- 
    type0 = TREE_TYPE (arg0);
    type1 = TREE_TYPE (arg1);
  
--- 8300,8322 ----
  
  /* Fold a call to an unordered comparison function such as
     __builtin_isgreater().  FNDECL is the FUNCTION_DECL for the function
!    being called and ARG0 and ARG1 are the arguments for the call.
     UNORDERED_CODE and ORDERED_CODE are comparison codes that give
     the opposite of the desired result.  UNORDERED_CODE is used
     for modes that can hold NaNs and ORDERED_CODE is used for
     the rest.  */
  
  static tree
! fold_builtin_unordered_cmp (tree fndecl, tree arg0, tree arg1,
  			    enum tree_code unordered_code,
  			    enum tree_code ordered_code)
  {
    tree type = TREE_TYPE (TREE_TYPE (fndecl));
    enum tree_code code;
    tree type0, type1;
    enum tree_code code0, code1;
    tree cmp_type = NULL_TREE;
  
    type0 = TREE_TYPE (arg0);
    type1 = TREE_TYPE (arg1);
  
*************** fold_builtin_unordered_cmp (tree fndecl,
*** 8530,8608 ****
  		      fold_build2 (code, type, arg0, arg1));
  }
  
! /* Used by constant folding to simplify calls to builtin functions.  EXP is
!    the CALL_EXPR of a call to a builtin function.  IGNORE is true if the
!    result of the function call is ignored.  This function returns NULL_TREE
!    if no simplification was possible.  */
  
  static tree
! fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
  {
    tree type = TREE_TYPE (TREE_TYPE (fndecl));
!   enum built_in_function fcode;
! 
!   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
!     return targetm.fold_builtin (fndecl, arglist, ignore);
! 
!   fcode = DECL_FUNCTION_CODE (fndecl);
    switch (fcode)
      {
!     case BUILT_IN_FPUTS:
!       return fold_builtin_fputs (arglist, ignore, false, NULL_TREE);
! 
!     case BUILT_IN_FPUTS_UNLOCKED:
!       return fold_builtin_fputs (arglist, ignore, true, NULL_TREE);
! 
!     case BUILT_IN_STRSTR:
!       return fold_builtin_strstr (arglist, type);
  
!     case BUILT_IN_STRCAT:
!       return fold_builtin_strcat (arglist);
  
!     case BUILT_IN_STRNCAT:
!       return fold_builtin_strncat (arglist);
  
!     case BUILT_IN_STRSPN:
!       return fold_builtin_strspn (arglist);
  
!     case BUILT_IN_STRCSPN:
!       return fold_builtin_strcspn (arglist);
  
!     case BUILT_IN_STRCHR:
!     case BUILT_IN_INDEX:
!       return fold_builtin_strchr (arglist, type);
! 
!     case BUILT_IN_STRRCHR:
!     case BUILT_IN_RINDEX:
!       return fold_builtin_strrchr (arglist, type);
! 
!     case BUILT_IN_STRCPY:
!       return fold_builtin_strcpy (fndecl, arglist, NULL_TREE);
! 
!     case BUILT_IN_STRNCPY:
!       return fold_builtin_strncpy (fndecl, arglist, NULL_TREE);
! 
!     case BUILT_IN_STRCMP:
!       return fold_builtin_strcmp (arglist);
! 
!     case BUILT_IN_STRNCMP:
!       return fold_builtin_strncmp (arglist);
! 
!     case BUILT_IN_STRPBRK:
!       return fold_builtin_strpbrk (arglist, type);
! 
!     case BUILT_IN_BCMP:
!     case BUILT_IN_MEMCMP:
!       return fold_builtin_memcmp (arglist);
! 
!     case BUILT_IN_SPRINTF:
!       return fold_builtin_sprintf (arglist, ignore);
  
      case BUILT_IN_CONSTANT_P:
        {
! 	tree val;
  
- 	val = fold_builtin_constant_p (arglist);
  	/* Gimplification will pull the CALL_EXPR for the builtin out of
  	   an if condition.  When not optimizing, we'll not CSE it back.
  	   To avoid link error types of regressions, return false now.  */
--- 8354,8404 ----
  		      fold_build2 (code, type, arg0, arg1));
  }
  
! /* Fold a call to built-in function FNDECL with 0 arguments.
!    IGNORE is true if the result of the function call is ignored.  This
!    function returns NULL_TREE if no simplification was possible.  */
  
  static tree
! fold_builtin_0 (tree fndecl, bool ignore ATTRIBUTE_UNUSED)
  {
    tree type = TREE_TYPE (TREE_TYPE (fndecl));
!   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
    switch (fcode)
      {
!     CASE_FLT_FN (BUILT_IN_INF):
!     case BUILT_IN_INFD32:
!     case BUILT_IN_INFD64:
!     case BUILT_IN_INFD128:
!       return fold_builtin_inf (type, true);
  
!     CASE_FLT_FN (BUILT_IN_HUGE_VAL):
!       return fold_builtin_inf (type, false);
  
!     case BUILT_IN_CLASSIFY_TYPE:
!       return fold_builtin_classify_type (NULL_TREE);
  
!     default:
!       break;
!     }
!   return NULL_TREE;
! }
  
! /* Fold a call to built-in function FNDECL with 1 argument, ARG0.
!    IGNORE is true if the result of the function call is ignored.  This
!    function returns NULL_TREE if no simplification was possible.  */
  
! static tree
! fold_builtin_1 (tree fndecl, tree arg0, bool ignore)
! {
!   tree type = TREE_TYPE (TREE_TYPE (fndecl));
!   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
!   switch (fcode)
!     {
  
      case BUILT_IN_CONSTANT_P:
        {
! 	tree val = fold_builtin_constant_p (arg0);
  
  	/* Gimplification will pull the CALL_EXPR for the builtin out of
  	   an if condition.  When not optimizing, we'll not CSE it back.
  	   To avoid link error types of regressions, return false now.  */
*************** fold_builtin_1 (tree fndecl, tree arglis
*** 8612,8731 ****
  	return val;
        }
  
-     case BUILT_IN_EXPECT:
-       return fold_builtin_expect (arglist);
- 
      case BUILT_IN_CLASSIFY_TYPE:
!       return fold_builtin_classify_type (arglist);
  
      case BUILT_IN_STRLEN:
!       return fold_builtin_strlen (arglist);
  
      CASE_FLT_FN (BUILT_IN_FABS):
!       return fold_builtin_fabs (arglist, type);
  
      case BUILT_IN_ABS:
      case BUILT_IN_LABS:
      case BUILT_IN_LLABS:
      case BUILT_IN_IMAXABS:
!       return fold_builtin_abs (arglist, type);
  
      CASE_FLT_FN (BUILT_IN_CONJ):
!       if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
! 	return fold_build1 (CONJ_EXPR, type, TREE_VALUE (arglist));
        break;
  
      CASE_FLT_FN (BUILT_IN_CREAL):
!       if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
! 	return non_lvalue (fold_build1 (REALPART_EXPR, type,
! 					TREE_VALUE (arglist)));
        break;
  
      CASE_FLT_FN (BUILT_IN_CIMAG):
!       if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
! 	return non_lvalue (fold_build1 (IMAGPART_EXPR, type,
! 					TREE_VALUE (arglist)));
        break;
  
      CASE_FLT_FN (BUILT_IN_CABS):
!       return fold_builtin_cabs (arglist, type);
  
      CASE_FLT_FN (BUILT_IN_SQRT):
!       return fold_builtin_sqrt (arglist, type);
  
      CASE_FLT_FN (BUILT_IN_CBRT):
!       return fold_builtin_cbrt (arglist, type);
  
      CASE_FLT_FN (BUILT_IN_SIN):
!       return fold_builtin_sin (arglist);
  
      CASE_FLT_FN (BUILT_IN_COS):
!       return fold_builtin_cos (arglist, type, fndecl);
  
      CASE_FLT_FN (BUILT_IN_EXP):
!       return fold_builtin_exponent (fndecl, arglist, &dconste);
  
      CASE_FLT_FN (BUILT_IN_EXP2):
!       return fold_builtin_exponent (fndecl, arglist, &dconst2);
  
      CASE_FLT_FN (BUILT_IN_EXP10):
      CASE_FLT_FN (BUILT_IN_POW10):
!       return fold_builtin_exponent (fndecl, arglist, &dconst10);
  
      CASE_FLT_FN (BUILT_IN_LOG):
!       return fold_builtin_logarithm (fndecl, arglist, &dconste);
  
      CASE_FLT_FN (BUILT_IN_LOG2):
!       return fold_builtin_logarithm (fndecl, arglist, &dconst2);
  
      CASE_FLT_FN (BUILT_IN_LOG10):
!       return fold_builtin_logarithm (fndecl, arglist, &dconst10);
  
      CASE_FLT_FN (BUILT_IN_TAN):
!       return fold_builtin_tan (arglist);
  
      CASE_FLT_FN (BUILT_IN_ATAN):
!       return fold_builtin_atan (arglist, type);
! 
!     CASE_FLT_FN (BUILT_IN_POW):
!       return fold_builtin_pow (fndecl, arglist, type);
! 
!     CASE_FLT_FN (BUILT_IN_POWI):
!       return fold_builtin_powi (fndecl, arglist, type);
! 
!     CASE_FLT_FN (BUILT_IN_INF):
!     case BUILT_IN_INFD32:
!     case BUILT_IN_INFD64:
!     case BUILT_IN_INFD128:
!       return fold_builtin_inf (type, true);
! 
!     CASE_FLT_FN (BUILT_IN_HUGE_VAL):
!       return fold_builtin_inf (type, false);
  
      CASE_FLT_FN (BUILT_IN_NAN):
      case BUILT_IN_NAND32:
      case BUILT_IN_NAND64:
      case BUILT_IN_NAND128:
!       return fold_builtin_nan (arglist, type, true);
  
      CASE_FLT_FN (BUILT_IN_NANS):
!       return fold_builtin_nan (arglist, type, false);
  
      CASE_FLT_FN (BUILT_IN_FLOOR):
!       return fold_builtin_floor (fndecl, arglist);
  
      CASE_FLT_FN (BUILT_IN_CEIL):
!       return fold_builtin_ceil (fndecl, arglist);
  
      CASE_FLT_FN (BUILT_IN_TRUNC):
!       return fold_builtin_trunc (fndecl, arglist);
  
      CASE_FLT_FN (BUILT_IN_ROUND):
!       return fold_builtin_round (fndecl, arglist);
  
      CASE_FLT_FN (BUILT_IN_NEARBYINT):
      CASE_FLT_FN (BUILT_IN_RINT):
!       return fold_trunc_transparent_mathfn (fndecl, arglist);
  
      CASE_FLT_FN (BUILT_IN_LCEIL):
      CASE_FLT_FN (BUILT_IN_LLCEIL):
--- 8408,8507 ----
  	return val;
        }
  
      case BUILT_IN_CLASSIFY_TYPE:
!       return fold_builtin_classify_type (arg0);
  
      case BUILT_IN_STRLEN:
!       return fold_builtin_strlen (arg0);
  
      CASE_FLT_FN (BUILT_IN_FABS):
!       return fold_builtin_fabs (arg0, type);
  
      case BUILT_IN_ABS:
      case BUILT_IN_LABS:
      case BUILT_IN_LLABS:
      case BUILT_IN_IMAXABS:
!       return fold_builtin_abs (arg0, type);
  
      CASE_FLT_FN (BUILT_IN_CONJ):
!       if (validate_arg (arg0, COMPLEX_TYPE))
! 	return fold_build1 (CONJ_EXPR, type, arg0);
        break;
  
      CASE_FLT_FN (BUILT_IN_CREAL):
!       if (validate_arg (arg0, COMPLEX_TYPE))
! 	return non_lvalue (fold_build1 (REALPART_EXPR, type, arg0));
        break;
  
      CASE_FLT_FN (BUILT_IN_CIMAG):
!       if (validate_arg (arg0, COMPLEX_TYPE))
! 	return non_lvalue (fold_build1 (IMAGPART_EXPR, type, arg0));
        break;
  
      CASE_FLT_FN (BUILT_IN_CABS):
!       return fold_builtin_cabs (arg0, type);
  
      CASE_FLT_FN (BUILT_IN_SQRT):
!       return fold_builtin_sqrt (arg0, type);
  
      CASE_FLT_FN (BUILT_IN_CBRT):
!       return fold_builtin_cbrt (arg0, type);
  
      CASE_FLT_FN (BUILT_IN_SIN):
!       return fold_builtin_sin (arg0);
  
      CASE_FLT_FN (BUILT_IN_COS):
!       return fold_builtin_cos (arg0, type, fndecl);
  
      CASE_FLT_FN (BUILT_IN_EXP):
!       return fold_builtin_exponent (fndecl, arg0, &dconste);
  
      CASE_FLT_FN (BUILT_IN_EXP2):
!       return fold_builtin_exponent (fndecl, arg0, &dconst2);
  
      CASE_FLT_FN (BUILT_IN_EXP10):
      CASE_FLT_FN (BUILT_IN_POW10):
!       return fold_builtin_exponent (fndecl, arg0, &dconst10);
  
      CASE_FLT_FN (BUILT_IN_LOG):
!       return fold_builtin_logarithm (fndecl, arg0, &dconste);
  
      CASE_FLT_FN (BUILT_IN_LOG2):
!       return fold_builtin_logarithm (fndecl, arg0, &dconst2);
  
      CASE_FLT_FN (BUILT_IN_LOG10):
!       return fold_builtin_logarithm (fndecl, arg0, &dconst10);
  
      CASE_FLT_FN (BUILT_IN_TAN):
!       return fold_builtin_tan (arg0);
  
      CASE_FLT_FN (BUILT_IN_ATAN):
!       return fold_builtin_atan (arg0, type);
  
      CASE_FLT_FN (BUILT_IN_NAN):
      case BUILT_IN_NAND32:
      case BUILT_IN_NAND64:
      case BUILT_IN_NAND128:
!       return fold_builtin_nan (arg0, type, true);
  
      CASE_FLT_FN (BUILT_IN_NANS):
!       return fold_builtin_nan (arg0, type, false);
  
      CASE_FLT_FN (BUILT_IN_FLOOR):
!       return fold_builtin_floor (fndecl, arg0);
  
      CASE_FLT_FN (BUILT_IN_CEIL):
!       return fold_builtin_ceil (fndecl, arg0);
  
      CASE_FLT_FN (BUILT_IN_TRUNC):
!       return fold_builtin_trunc (fndecl, arg0);
  
      CASE_FLT_FN (BUILT_IN_ROUND):
!       return fold_builtin_round (fndecl, arg0);
  
      CASE_FLT_FN (BUILT_IN_NEARBYINT):
      CASE_FLT_FN (BUILT_IN_RINT):
!       return fold_trunc_transparent_mathfn (fndecl, arg0);
  
      CASE_FLT_FN (BUILT_IN_LCEIL):
      CASE_FLT_FN (BUILT_IN_LLCEIL):
*************** fold_builtin_1 (tree fndecl, tree arglis
*** 8733,8858 ****
      CASE_FLT_FN (BUILT_IN_LLFLOOR):
      CASE_FLT_FN (BUILT_IN_LROUND):
      CASE_FLT_FN (BUILT_IN_LLROUND):
!       return fold_builtin_int_roundingfn (fndecl, arglist);
  
      CASE_FLT_FN (BUILT_IN_LRINT):
      CASE_FLT_FN (BUILT_IN_LLRINT):
!       return fold_fixed_mathfn (fndecl, arglist);
  
      CASE_INT_FN (BUILT_IN_FFS):
      CASE_INT_FN (BUILT_IN_CLZ):
      CASE_INT_FN (BUILT_IN_CTZ):
      CASE_INT_FN (BUILT_IN_POPCOUNT):
      CASE_INT_FN (BUILT_IN_PARITY):
!       return fold_builtin_bitop (fndecl, arglist);
! 
!     case BUILT_IN_MEMCPY:
!       return fold_builtin_memcpy (fndecl, arglist);
! 
!     case BUILT_IN_MEMPCPY:
!       return fold_builtin_mempcpy (arglist, type, /*endp=*/1);
! 
!     case BUILT_IN_MEMMOVE:
!       return fold_builtin_memmove (arglist, type);
  
      CASE_FLT_FN (BUILT_IN_SIGNBIT):
!       return fold_builtin_signbit (fndecl, arglist);
  
      case BUILT_IN_ISASCII:
!       return fold_builtin_isascii (arglist);
  
      case BUILT_IN_TOASCII:
!       return fold_builtin_toascii (arglist);
  
      case BUILT_IN_ISDIGIT:
!       return fold_builtin_isdigit (arglist);
! 
!     CASE_FLT_FN (BUILT_IN_COPYSIGN):
!       return fold_builtin_copysign (fndecl, arglist, type);
  
      CASE_FLT_FN (BUILT_IN_FINITE):
      case BUILT_IN_FINITED32:
      case BUILT_IN_FINITED64:
      case BUILT_IN_FINITED128:
!       return fold_builtin_classify (fndecl, arglist, BUILT_IN_FINITE);
  
      CASE_FLT_FN (BUILT_IN_ISINF):
      case BUILT_IN_ISINFD32:
      case BUILT_IN_ISINFD64:
      case BUILT_IN_ISINFD128:
!       return fold_builtin_classify (fndecl, arglist, BUILT_IN_ISINF);
  
      CASE_FLT_FN (BUILT_IN_ISNAN):
      case BUILT_IN_ISNAND32:
      case BUILT_IN_ISNAND64:
      case BUILT_IN_ISNAND128:
!       return fold_builtin_classify (fndecl, arglist, BUILT_IN_ISNAN);
  
      case BUILT_IN_ISGREATER:
!       return fold_builtin_unordered_cmp (fndecl, arglist, UNLE_EXPR, LE_EXPR);
      case BUILT_IN_ISGREATEREQUAL:
!       return fold_builtin_unordered_cmp (fndecl, arglist, UNLT_EXPR, LT_EXPR);
      case BUILT_IN_ISLESS:
!       return fold_builtin_unordered_cmp (fndecl, arglist, UNGE_EXPR, GE_EXPR);
      case BUILT_IN_ISLESSEQUAL:
!       return fold_builtin_unordered_cmp (fndecl, arglist, UNGT_EXPR, GT_EXPR);
      case BUILT_IN_ISLESSGREATER:
!       return fold_builtin_unordered_cmp (fndecl, arglist, UNEQ_EXPR, EQ_EXPR);
      case BUILT_IN_ISUNORDERED:
!       return fold_builtin_unordered_cmp (fndecl, arglist, UNORDERED_EXPR,
! 					 NOP_EXPR);
! 
        /* We do the folding for va_start in the expander.  */
      case BUILT_IN_VA_START:
        break;
  
      case BUILT_IN_OBJECT_SIZE:
!       return fold_builtin_object_size (arglist);
!     case BUILT_IN_MEMCPY_CHK:
!     case BUILT_IN_MEMPCPY_CHK:
!     case BUILT_IN_MEMMOVE_CHK:
!     case BUILT_IN_MEMSET_CHK:
!       return fold_builtin_memory_chk (fndecl, arglist, NULL_TREE, ignore,
! 				      DECL_FUNCTION_CODE (fndecl));
!     case BUILT_IN_STRCPY_CHK:
!     case BUILT_IN_STPCPY_CHK:
!       return fold_builtin_stxcpy_chk (fndecl, arglist, NULL_TREE, ignore,
! 				      DECL_FUNCTION_CODE (fndecl));
!     case BUILT_IN_STRNCPY_CHK:
!       return fold_builtin_strncpy_chk (arglist, NULL_TREE);
!     case BUILT_IN_STRCAT_CHK:
!       return fold_builtin_strcat_chk (fndecl, arglist);
!     case BUILT_IN_STRNCAT_CHK:
!       return fold_builtin_strncat_chk (fndecl, arglist);
!     case BUILT_IN_SPRINTF_CHK:
!     case BUILT_IN_VSPRINTF_CHK:
!       return fold_builtin_sprintf_chk (arglist, DECL_FUNCTION_CODE (fndecl));
!     case BUILT_IN_SNPRINTF_CHK:
!     case BUILT_IN_VSNPRINTF_CHK:
!       return fold_builtin_snprintf_chk (arglist, NULL_TREE,
! 					DECL_FUNCTION_CODE (fndecl));
  
      case BUILT_IN_PRINTF:
      case BUILT_IN_PRINTF_UNLOCKED:
      case BUILT_IN_VPRINTF:
      case BUILT_IN_PRINTF_CHK:
      case BUILT_IN_VPRINTF_CHK:
!       return fold_builtin_printf (fndecl, arglist, ignore,
! 				  DECL_FUNCTION_CODE (fndecl));
  
      case BUILT_IN_FPRINTF:
      case BUILT_IN_FPRINTF_UNLOCKED:
      case BUILT_IN_VFPRINTF:
      case BUILT_IN_FPRINTF_CHK:
      case BUILT_IN_VFPRINTF_CHK:
!       return fold_builtin_fprintf (fndecl, arglist, ignore,
! 				   DECL_FUNCTION_CODE (fndecl));
  
      default:
        break;
      }
  
!   return 0;
  }
  
  /* A wrapper function for builtin folding that prevents warnings for
--- 8509,8872 ----
      CASE_FLT_FN (BUILT_IN_LLFLOOR):
      CASE_FLT_FN (BUILT_IN_LROUND):
      CASE_FLT_FN (BUILT_IN_LLROUND):
!       return fold_builtin_int_roundingfn (fndecl, arg0);
  
      CASE_FLT_FN (BUILT_IN_LRINT):
      CASE_FLT_FN (BUILT_IN_LLRINT):
!       return fold_fixed_mathfn (fndecl, arg0);
  
      CASE_INT_FN (BUILT_IN_FFS):
      CASE_INT_FN (BUILT_IN_CLZ):
      CASE_INT_FN (BUILT_IN_CTZ):
      CASE_INT_FN (BUILT_IN_POPCOUNT):
      CASE_INT_FN (BUILT_IN_PARITY):
!       return fold_builtin_bitop (fndecl, arg0);
  
      CASE_FLT_FN (BUILT_IN_SIGNBIT):
!       return fold_builtin_signbit (arg0, type);
  
      case BUILT_IN_ISASCII:
!       return fold_builtin_isascii (arg0);
  
      case BUILT_IN_TOASCII:
!       return fold_builtin_toascii (arg0);
  
      case BUILT_IN_ISDIGIT:
!       return fold_builtin_isdigit (arg0);
  
      CASE_FLT_FN (BUILT_IN_FINITE):
      case BUILT_IN_FINITED32:
      case BUILT_IN_FINITED64:
      case BUILT_IN_FINITED128:
!       return fold_builtin_classify (fndecl, arg0, BUILT_IN_FINITE);
  
      CASE_FLT_FN (BUILT_IN_ISINF):
      case BUILT_IN_ISINFD32:
      case BUILT_IN_ISINFD64:
      case BUILT_IN_ISINFD128:
!       return fold_builtin_classify (fndecl, arg0, BUILT_IN_ISINF);
  
      CASE_FLT_FN (BUILT_IN_ISNAN):
      case BUILT_IN_ISNAND32:
      case BUILT_IN_ISNAND64:
      case BUILT_IN_ISNAND128:
!       return fold_builtin_classify (fndecl, arg0, BUILT_IN_ISNAN);
! 
!     case BUILT_IN_PRINTF:
!     case BUILT_IN_PRINTF_UNLOCKED:
!     case BUILT_IN_VPRINTF:
!       return fold_builtin_printf (fndecl, arg0, NULL_TREE, ignore, fcode);
! 
!     default:
!       break;
!     }
! 
!   return NULL_TREE;
! }
! 
! /* Fold a call to built-in function FNDECL with 2 arguments, ARG0 and ARG1.
!    IGNORE is true if the result of the function call is ignored.  This
!    function returns NULL_TREE if no simplification was possible.  */
! 
! static tree
! fold_builtin_2 (tree fndecl, tree arg0, tree arg1, bool ignore)
! {
!   tree type = TREE_TYPE (TREE_TYPE (fndecl));
!   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
!   switch (fcode)
!     {
!     case BUILT_IN_FPUTS:
!       return fold_builtin_fputs (arg0, arg1, ignore, false, NULL_TREE);
! 
!     case BUILT_IN_FPUTS_UNLOCKED:
!       return fold_builtin_fputs (arg0, arg1, ignore, true, NULL_TREE);
! 
!     case BUILT_IN_STRSTR:
!       return fold_builtin_strstr (arg0, arg1, type);
! 
!     case BUILT_IN_STRCAT:
!       return fold_builtin_strcat (arg0, arg1);
! 
!     case BUILT_IN_STRSPN:
!       return fold_builtin_strspn (arg0, arg1);
! 
!     case BUILT_IN_STRCSPN:
!       return fold_builtin_strcspn (arg0, arg1);
! 
!     case BUILT_IN_STRCHR:
!     case BUILT_IN_INDEX:
!       return fold_builtin_strchr (arg0, arg1, type);
! 
!     case BUILT_IN_STRRCHR:
!     case BUILT_IN_RINDEX:
!       return fold_builtin_strrchr (arg0, arg1, type);
! 
!     case BUILT_IN_STRCPY:
!       return fold_builtin_strcpy (fndecl, arg0, arg1, NULL_TREE);
! 
!     case BUILT_IN_STRCMP:
!       return fold_builtin_strcmp (arg0, arg1);
! 
!     case BUILT_IN_STRPBRK:
!       return fold_builtin_strpbrk (arg0, arg1, type);
! 
!     case BUILT_IN_EXPECT:
!       return fold_builtin_expect (arg0);
! 
!     CASE_FLT_FN (BUILT_IN_POW):
!       return fold_builtin_pow (fndecl, arg0, arg1, type);
! 
!     CASE_FLT_FN (BUILT_IN_POWI):
!       return fold_builtin_powi (fndecl, arg0, arg1, type);
! 
!     CASE_FLT_FN (BUILT_IN_COPYSIGN):
!       return fold_builtin_copysign (fndecl, arg0, arg1, type);
  
      case BUILT_IN_ISGREATER:
!       return fold_builtin_unordered_cmp (fndecl, arg0, arg1,
! 					 UNLE_EXPR, LE_EXPR);
      case BUILT_IN_ISGREATEREQUAL:
!       return fold_builtin_unordered_cmp (fndecl, arg0, arg1,
! 					 UNLT_EXPR, LT_EXPR);
      case BUILT_IN_ISLESS:
!       return fold_builtin_unordered_cmp (fndecl, arg0, arg1,
! 					 UNGE_EXPR, GE_EXPR);
      case BUILT_IN_ISLESSEQUAL:
!       return fold_builtin_unordered_cmp (fndecl, arg0, arg1,
! 					 UNGT_EXPR, GT_EXPR);
      case BUILT_IN_ISLESSGREATER:
!       return fold_builtin_unordered_cmp (fndecl, arg0, arg1,
! 					 UNEQ_EXPR, EQ_EXPR);
      case BUILT_IN_ISUNORDERED:
!       return fold_builtin_unordered_cmp (fndecl, arg0, arg1,
! 					 UNORDERED_EXPR, NOP_EXPR);
        /* We do the folding for va_start in the expander.  */
      case BUILT_IN_VA_START:
        break;
  
+     case BUILT_IN_SPRINTF:
+       return fold_builtin_sprintf (arg0, arg1, NULL_TREE, ignore);
+ 
      case BUILT_IN_OBJECT_SIZE:
!       return fold_builtin_object_size (arg0, arg1);
  
      case BUILT_IN_PRINTF:
      case BUILT_IN_PRINTF_UNLOCKED:
      case BUILT_IN_VPRINTF:
+       return fold_builtin_printf (fndecl, arg0, arg1, ignore, fcode);
+ 
+     case BUILT_IN_PRINTF_CHK:
+     case BUILT_IN_VPRINTF_CHK:
+       if (!validate_arg (arg0, INTEGER_TYPE)
+ 	  || TREE_SIDE_EFFECTS (arg0))
+ 	return NULL_TREE;
+       else
+ 	return fold_builtin_printf (fndecl, arg1, NULL_TREE, ignore, fcode);
+ 
+     case BUILT_IN_FPRINTF:
+     case BUILT_IN_FPRINTF_UNLOCKED:
+     case BUILT_IN_VFPRINTF:
+       return fold_builtin_fprintf (fndecl, arg0, arg1, NULL_TREE,
+ 				   ignore, fcode);
+ 
+     default:
+       break;
+     }
+   return NULL_TREE;
+ }
+ 
+ /* Fold a call to built-in function FNDECL with 3 arguments, ARG0, ARG1,
+    and ARG2.  IGNORE is true if the result of the function call is ignored.
+    This function returns NULL_TREE if no simplification was possible.  */
+ 
+ static tree
+ fold_builtin_3 (tree fndecl, tree arg0, tree arg1, tree arg2, bool ignore)
+ {
+   tree type = TREE_TYPE (TREE_TYPE (fndecl));
+   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+   switch (fcode)
+     {
+ 
+     case BUILT_IN_STRNCAT:
+       return fold_builtin_strncat (arg0, arg1, arg2);
+ 
+     case BUILT_IN_STRNCPY:
+       return fold_builtin_strncpy (fndecl, arg0, arg1, arg2, NULL_TREE);
+ 
+     case BUILT_IN_STRNCMP:
+       return fold_builtin_strncmp (arg0, arg1, arg2);
+ 
+     case BUILT_IN_BCMP:
+     case BUILT_IN_MEMCMP:
+       return fold_builtin_memcmp (arg0, arg1, arg2);
+ 
+     case BUILT_IN_MEMCPY:
+       return fold_builtin_memcpy (arg0, arg1, arg2, type);
+ 
+     case BUILT_IN_MEMPCPY:
+       return fold_builtin_mempcpy (arg0, arg1, arg2, type, 1);
+ 
+     case BUILT_IN_MEMMOVE:
+       return fold_builtin_memmove (arg0, arg1, arg2, type);
+ 
+     case BUILT_IN_SPRINTF:
+       return fold_builtin_sprintf (arg0, arg1, arg2, ignore);
+ 
+     case BUILT_IN_STRCPY_CHK:
+     case BUILT_IN_STPCPY_CHK:
+       return fold_builtin_stxcpy_chk (fndecl, arg0, arg1, arg2, NULL_TREE,
+ 				      ignore, fcode);
+ 
+     case BUILT_IN_STRCAT_CHK:
+       return fold_builtin_strcat_chk (fndecl, arg0, arg1, arg2);
+ 
      case BUILT_IN_PRINTF_CHK:
      case BUILT_IN_VPRINTF_CHK:
!       if (!validate_arg (arg0, INTEGER_TYPE)
! 	  || TREE_SIDE_EFFECTS (arg0))
! 	return NULL_TREE;
!       else
! 	return fold_builtin_printf (fndecl, arg1, arg2, ignore, fcode);
  
      case BUILT_IN_FPRINTF:
      case BUILT_IN_FPRINTF_UNLOCKED:
      case BUILT_IN_VFPRINTF:
+       return fold_builtin_fprintf (fndecl, arg0, arg1, arg2, ignore, fcode);
+ 
      case BUILT_IN_FPRINTF_CHK:
      case BUILT_IN_VFPRINTF_CHK:
!       if (!validate_arg (arg1, INTEGER_TYPE)
! 	  || TREE_SIDE_EFFECTS (arg1))
! 	return NULL_TREE;
!       else
! 	return fold_builtin_fprintf (fndecl, arg0, arg2, NULL_TREE,
! 				     ignore, fcode);
  
      default:
        break;
      }
+   return NULL_TREE;
+ }
  
! /* Fold a call to built-in function FNDECL with 4 arguments, ARG0, ARG1,
!    ARG2, and ARG3.  IGNORE is true if the result of the function call is
!    ignored.  This function returns NULL_TREE if no simplification was
!    possible.  */
! 
! static tree
! fold_builtin_4 (tree fndecl, tree arg0, tree arg1, tree arg2, tree arg3,
! 		bool ignore)
! {
!   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
! 
!   switch (fcode)
!     {
!     case BUILT_IN_MEMCPY_CHK:
!     case BUILT_IN_MEMPCPY_CHK:
!     case BUILT_IN_MEMMOVE_CHK:
!     case BUILT_IN_MEMSET_CHK:
!       return fold_builtin_memory_chk (fndecl, arg0, arg1, arg2, arg3,
! 				      NULL_TREE, ignore,
! 				      DECL_FUNCTION_CODE (fndecl));
! 
!     case BUILT_IN_STRNCPY_CHK:
!       return fold_builtin_strncpy_chk (arg0, arg1, arg2, arg3, NULL_TREE);
! 
!     case BUILT_IN_STRNCAT_CHK:
!       return fold_builtin_strncat_chk (fndecl, arg0, arg1, arg2, arg3);
! 
!     case BUILT_IN_FPRINTF_CHK:
!     case BUILT_IN_VFPRINTF_CHK:
!       if (!validate_arg (arg1, INTEGER_TYPE)
! 	  || TREE_SIDE_EFFECTS (arg1))
! 	return NULL_TREE;
!       else
! 	return fold_builtin_fprintf (fndecl, arg0, arg2, arg3,
! 				     ignore, fcode);
!     default:
!       break;
!     }
!   return NULL_TREE;
! }
! 
! /* Fold a call to built-in function FNDECL.  ARGS is an array of NARGS
!    arguments, where NARGS <= 4.  IGNORE is true if the result of the
!    function call is ignored.  This function returns NULL_TREE if no
!    simplification was possible.  Note that this only folds builtins with
!    fixed argument patterns.  Foldings that do varargs-to-varargs
!    transformations, or that match calls with more than 4 arguments,
!    need to be handled with fold_builtin_varargs instead.  */
! 
! #define MAX_ARGS_TO_FOLD_BUILTIN 4
! 
! static tree
! fold_builtin_n (tree fndecl, tree *args, int nargs, bool ignore)
! {
!   tree ret = NULL_TREE;
!   switch (nargs)
!     {
!     case 0:
!       ret = fold_builtin_0 (fndecl, ignore);
!       break;
!     case 1:
!       ret = fold_builtin_1 (fndecl, args[0], ignore);
!       break;
!     case 2:
!       ret = fold_builtin_2 (fndecl, args[0], args[1], ignore);
!       break;
!     case 3:
!       ret = fold_builtin_3 (fndecl, args[0], args[1], args[2], ignore);
!       break;
!     case 4:
!       ret = fold_builtin_4 (fndecl, args[0], args[1], args[2], args[3],
! 			    ignore);
!       break;
!     default:
!       break;
!     }
!   if (ret)
!     {
!       ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
!       TREE_NO_WARNING (ret) = 1;
!       return ret;
!     }
!   return NULL_TREE;
! }
! 
! /* Builtins with folding operations that operate on "..." arguments
!    need special handling; we need to store the arguments in a convenient
!    data structure before attempting any folding.  Fortunately there are
!    only a few builtins that fall into this category.  FNDECL is the
!    function, EXP is the CALL_EXPR for the call, and IGNORE is true if the
!    result of the function call is ignored.  */
! 
! static tree
! fold_builtin_varargs (tree fndecl, tree exp, bool ignore ATTRIBUTE_UNUSED)
! {
!   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
!   tree ret = NULL_TREE;
! 
!   switch (fcode)
!     {
!     case BUILT_IN_SPRINTF_CHK:
!     case BUILT_IN_VSPRINTF_CHK:
!       ret = fold_builtin_sprintf_chk (exp, fcode);
!       break;
! 
!     case BUILT_IN_SNPRINTF_CHK:
!     case BUILT_IN_VSNPRINTF_CHK:
!       ret = fold_builtin_snprintf_chk (exp, NULL_TREE, fcode);
! 
!     default:
!       break;
!     }
!   if (ret)
!     {
!       ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
!       TREE_NO_WARNING (ret) = 1;
!       return ret;
!     }
!   return NULL_TREE;
  }
  
  /* A wrapper function for builtin folding that prevents warnings for
*************** fold_builtin_1 (tree fndecl, tree arglis
*** 8860,8902 ****
     call node earlier than the warning is generated.  */
  
  tree
! fold_builtin (tree fndecl, tree arglist, bool ignore)
  {
!   tree exp = fold_builtin_1 (fndecl, arglist, ignore);
!   if (exp)
      {
!       exp = build1 (NOP_EXPR, TREE_TYPE (exp), exp);
!       TREE_NO_WARNING (exp) = 1;
      }
  
    return exp;
  }
  
! /* Conveniently construct a function call expression.  */
  
! tree
! build_function_call_expr (tree fn, tree arglist)
  {
!   tree call_expr;
  
!   call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
!   return fold_build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
! 		      call_expr, arglist, NULL_TREE);
  }
  
  /* This function validates the types of a function call argument list
!    represented as a tree chain of parameters against a specified list
!    of tree_codes.  If the last specifier is a 0, that represents an
!    ellipses, otherwise the last specifier must be a VOID_TYPE.  */
  
! static int
! validate_arglist (tree arglist, ...)
  {
    enum tree_code code;
!   int res = 0;
    va_list ap;
  
!   va_start (ap, arglist);
  
    do
      {
--- 8874,9119 ----
     call node earlier than the warning is generated.  */
  
  tree
! fold_call_expr (tree exp, bool ignore)
  {
!   tree ret = NULL_TREE;
!   tree fndecl = get_callee_fndecl (exp);
!   if (fndecl
!       && TREE_CODE (fndecl) == FUNCTION_DECL
!       && DECL_BUILT_IN (fndecl))
!     {
!       /* FIXME: Don't use a list in this interface.  */
!       if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
! 	return targetm.fold_builtin (fndecl, CALL_EXPR_ARGS (exp), ignore);
! 
! 
!       /* FIXME: When the CALL_EXPR representation changes to store the
! 	 arguments in an array instead of in a TREE_LIST, we can just pass
! 	 that array to fold_builtin_n instead of copying the arguments
! 	 to a local array.  */
!       else
! 	{
! 	  int nargs = call_expr_nargs (exp);
! 	  if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN)
! 	    {
! 	      int i;
! 	      tree args[MAX_ARGS_TO_FOLD_BUILTIN];
! 	      for (i = 0; i < nargs; i++)
! 		args[i] = call_expr_arg (exp, i);
! 	      ret = fold_builtin_n (fndecl, args, nargs, ignore);
! 	      if (ret)
! 		return ret;
! 	    }
! 	  return fold_builtin_varargs (fndecl, exp, ignore);
! 	}
!     }
!   return NULL_TREE;
! }
! 
! /* Conveniently construct a function call expression.  FNDECL names the
!    function to be called and ARGLIST is a TREE_LIST of arguments.  */
! 
! tree
! build_function_call_expr (tree fndecl, tree arglist)
! {
!   tree fntype = TREE_TYPE (fndecl);
!   tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
!   return fold_build_call_expr (TREE_TYPE (fntype), fn, arglist, NULL_TREE);
! }
! 
! /* Construct a function call expression with type TYPE with FN as the
!    function expression.  ARGLIST is a TREE_LIST of arguments, and
!    STATIC_CHAIN is the static chain.
! 
!    FIXME:  This needs to be rewritten when the underlying CALL_EXPR
!    representation changes not to use a TREE_LIST to hold the arguments.  */
! 
! tree
! fold_build_call_expr (tree type, tree fn, tree arglist, tree static_chain)
! {
!   tree ret = NULL_TREE;
!   if (TREE_CODE (fn) == ADDR_EXPR)
!     {
!       tree fndecl = TREE_OPERAND (fn, 0);
!       if (TREE_CODE (fndecl) == FUNCTION_DECL
! 	  && DECL_BUILT_IN (fndecl))
! 	{
! 	  /* FIXME: Don't use a list in this interface.  */
! 	  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
! 	    {
! 	      ret = targetm.fold_builtin (fndecl, arglist, false);
! 	      if (ret)
! 		return ret;
! 	    }
! 	  else
! 	    {
! 	      tree tail = arglist;
! 	      tree args[MAX_ARGS_TO_FOLD_BUILTIN];
! 	      int nargs;
! 	      tree temp;
! 	      for (nargs = 0; nargs < MAX_ARGS_TO_FOLD_BUILTIN; nargs++)
! 		{
! 		  if (!tail)
! 		    break;
! 		  args[nargs] = TREE_VALUE (tail);
! 		  tail = TREE_CHAIN (tail);
! 		}
! 	      if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN)
! 		{
! 		  ret = fold_builtin_n (fndecl, args, nargs, false);
! 		  if (ret)
! 		    return ret;
! 		}
! 	      temp = build3 (CALL_EXPR, type, fn, arglist, static_chain);
! 	      ret = fold_builtin_varargs (fndecl, temp, false);
! 	      return ret ? ret : temp;
! 	    }
! 	}
!     }
!   return build3 (CALL_EXPR, type, fn, arglist, static_chain);
! }
! 
! /* Conveniently construct a function call expression.  FNDECL names the
!    function to be called, N is the number of arguments, and the "..."
!    parameters are the argument expressions.
! 
!    FIXME: This needs to be rewritten when the underlying CALL_EXPR
!    representation changes not to use a TREE_LIST to hold the arguments.  */
! 
! tree
! build_call_expr (tree fndecl, int n, ...)
! {
!   va_list ap;
!   int i;
!   tree arglist = NULL_TREE;
!   tree ret = NULL_TREE;
!   tree exp;
!   tree fntype;
! 
!   if (TREE_CODE (fndecl) == FUNCTION_DECL
!       && DECL_BUILT_IN (fndecl)
!       && n <= MAX_ARGS_TO_FOLD_BUILTIN
!       && DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_MD)
!     
!     {
!       /* First try the transformations that don't require consing up
! 	 an arglist or exp.  */
!       tree args[MAX_ARGS_TO_FOLD_BUILTIN];
!       va_start (ap, n);
!       for (i = 0; i < n; i++)
! 	args[i] = va_arg (ap, tree);
!       va_end (ap);
!       ret = fold_builtin_n (fndecl, args, n, false);
!       if (ret)
! 	return ret;
!     }
! 
!   /* We at least need an arglist....  */
!   va_start (ap, n);
!   for (i = 0; i < n; i++)
      {
!       tree arg = va_arg (ap, tree);
!       arglist = tree_cons (NULL_TREE, arg, arglist);
!     }
!   va_end (ap);
!   arglist = nreverse (arglist);
! 
!   if (TREE_CODE (fndecl) == FUNCTION_DECL
!       && DECL_BUILT_IN (fndecl)
!       && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
!     {
!       /* FIXME: Don't use a list in this interface.  */
!       ret = targetm.fold_builtin (fndecl, arglist, false);
!       if (ret)
! 	return ret;
!     }
! 
!   /* If we got this far, we need to build an exp.  */
!   fntype = TREE_TYPE (fndecl);
!   exp = build3 (CALL_EXPR,
! 		TREE_TYPE (fntype),
! 		build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl),
! 		arglist, NULL_TREE);
! 
!   if (TREE_CODE (fndecl) == FUNCTION_DECL
!       && DECL_BUILT_IN (fndecl))
!     {
!       ret = fold_builtin_varargs (fndecl, exp, false);
!       if (ret)
! 	return ret;
      }
  
    return exp;
  }
  
! /* Construct a new CALL_EXPR using the tail of the argument list of EXP
!    along with N new arguments specified as the "..." parameters.  SKIP
!    is the number of arguments in EXP to be omitted.  This function is used
!    to do varargs-to-varargs transformations.
  
!    FIXME: This needs to be rewritten when the underlying CALL_EXPR
!    representation changes not to use a TREE_LIST to hold the arguments.  */
! 
! static tree
! rewrite_call_expr (tree exp, int skip, tree fn, int n, ...)
  {
!   tree arglist = CALL_EXPR_ARGS (exp);
!   int i;
!   for (i = 0; i < skip; i++)
!     arglist = TREE_CHAIN (arglist);
!   if (n > 0)
!     {
!       tree temp = NULL_TREE;
!       va_list ap;
!       va_start (ap, n);
!       /* Build TEMP backwards, then destructively reverse and concatenate
! 	 it onto ARGLIST.  */
!       for (i = 0; i < n; i++)
! 	{
! 	  tree arg = va_arg (ap, tree);
! 	  temp = tree_cons (NULL_TREE, arg, temp);
! 	}
!       va_end (ap);
!       for (i = 0; i < n; i++)
! 	{
! 	  tree next = TREE_CHAIN (temp);
! 	  TREE_CHAIN (temp) = arglist;
! 	  arglist = temp;
! 	  temp = next;
! 	}
!     }
!   return build_function_call_expr (fn, arglist);
! }
! 
! /* Validate a single argument ARG against a tree code CODE representing
!    a type.  */
  
! static bool
! validate_arg (tree arg, enum tree_code code)
! {
!   if (!arg)
!     return false;
!   else if (code == POINTER_TYPE)
!     return POINTER_TYPE_P (TREE_TYPE (arg));
!   return code == TREE_CODE (TREE_TYPE (arg));
  }
  
  /* This function validates the types of a function call argument list
!    against a specified list of tree_codes.  If the last specifier is a 0,
!    that represents an ellipses, otherwise the last specifier must be a
!    VOID_TYPE.  */
  
! static bool
! validate_arglist (tree callexpr, ...)
  {
    enum tree_code code;
!   bool res = false;
    va_list ap;
+   call_expr_arg_iterator iter;
+   tree arg;
  
!   va_start (ap, callexpr);
!   init_call_expr_arg_iterator (callexpr, &iter);
  
    do
      {
*************** validate_arglist (tree arglist, ...)
*** 8905,8933 ****
  	{
  	case 0:
  	  /* This signifies an ellipses, any further arguments are all ok.  */
! 	  res = 1;
  	  goto end;
  	case VOID_TYPE:
  	  /* This signifies an endlink, if no arguments remain, return
  	     true, otherwise return false.  */
! 	  res = arglist == 0;
  	  goto end;
  	default:
  	  /* If no parameters remain or the parameter's code does not
  	     match the specified code, return false.  Otherwise continue
  	     checking any remaining arguments.  */
! 	  if (arglist == 0)
! 	    goto end;
! 	  if (code == POINTER_TYPE)
! 	    {
! 	      if (! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist))))
! 		goto end;
! 	    }
! 	  else if (code != TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))))
  	    goto end;
  	  break;
  	}
-       arglist = TREE_CHAIN (arglist);
      }
    while (1);
  
--- 9122,9143 ----
  	{
  	case 0:
  	  /* This signifies an ellipses, any further arguments are all ok.  */
! 	  res = true;
  	  goto end;
  	case VOID_TYPE:
  	  /* This signifies an endlink, if no arguments remain, return
  	     true, otherwise return false.  */
! 	  res = !more_call_expr_args_p (&iter);
  	  goto end;
  	default:
  	  /* If no parameters remain or the parameter's code does not
  	     match the specified code, return false.  Otherwise continue
  	     checking any remaining arguments.  */
! 	  arg = next_call_expr_arg (&iter);
! 	  if (!validate_arg (arg, code))
  	    goto end;
  	  break;
  	}
      }
    while (1);
  
*************** readonly_data_expr (tree exp)
*** 8977,8985 ****
      return false;
  }
  
! /* 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
--- 9187,9196 ----
      return false;
  }
  
! /* Simplify a call to the strstr builtin.  S1 and S2 are the arguments
!    to the call, and TYPE is its return type.
  
!    Return NULL_TREE 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
*************** readonly_data_expr (tree exp)
*** 8995,9013 ****
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strstr (tree arglist, tree type)
  {
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
-       tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
        tree fn;
        const char *p1, *p2;
  
        p2 = c_getstr (s2);
        if (p2 == NULL)
! 	return 0;
  
        p1 = c_getstr (s1);
        if (p1 != NULL)
--- 9206,9224 ----
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strstr (tree s1, tree s2, tree type)
  {
!   if (!validate_arg (s1, POINTER_TYPE)
!       || !validate_arg (s2, POINTER_TYPE))
!     return NULL_TREE;
    else
      {
        tree fn;
        const char *p1, *p2;
  
        p2 = c_getstr (s2);
        if (p2 == NULL)
! 	return NULL_TREE;
  
        p1 = c_getstr (s1);
        if (p1 != NULL)
*************** fold_builtin_strstr (tree arglist, tree 
*** 9030,9053 ****
  	return fold_convert (type, s1);
  
        if (p2[1] != '\0')
! 	return 0;
  
        fn = implicit_built_in_decls[BUILT_IN_STRCHR];
        if (!fn)
! 	return 0;
  
        /* New argument list transforming strstr(s1, s2) to
  	 strchr(s1, s2[0]).  */
!       arglist = build_tree_list (NULL_TREE,
! 				 build_int_cst (NULL_TREE, p2[0]));
!       arglist = tree_cons (NULL_TREE, s1, arglist);
!       return build_function_call_expr (fn, arglist);
      }
  }
  
! /* Simplify a call to the strchr 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
--- 9241,9262 ----
  	return fold_convert (type, s1);
  
        if (p2[1] != '\0')
! 	return NULL_TREE;
  
        fn = implicit_built_in_decls[BUILT_IN_STRCHR];
        if (!fn)
! 	return NULL_TREE;
  
        /* New argument list transforming strstr(s1, s2) to
  	 strchr(s1, s2[0]).  */
!       return build_call_expr (fn, 2, s1, build_int_cst (NULL_TREE, p2[0]));
      }
  }
  
! /* Simplify a call to the strchr builtin.  S1 and S2 are the arguments to
!    the call, and TYPE is its return type.
  
!    Return NULL_TREE 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
*************** fold_builtin_strstr (tree arglist, tree 
*** 9063,9079 ****
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strchr (tree arglist, tree type)
  {
!   if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
-       tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
        const char *p1;
  
        if (TREE_CODE (s2) != INTEGER_CST)
! 	return 0;
  
        p1 = c_getstr (s1);
        if (p1 != NULL)
--- 9272,9288 ----
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strchr (tree s1, tree s2, tree type)
  {
!   if (!validate_arg (s1, POINTER_TYPE)
!       || !validate_arg (s2, INTEGER_TYPE))
!     return NULL_TREE;
    else
      {
        const char *p1;
  
        if (TREE_CODE (s2) != INTEGER_CST)
! 	return NULL_TREE;
  
        p1 = c_getstr (s1);
        if (p1 != NULL)
*************** fold_builtin_strchr (tree arglist, tree 
*** 9083,9089 ****
  	  tree tem;
  
  	  if (target_char_cast (s2, &c))
! 	    return 0;
  
  	  r = strchr (p1, c);
  
--- 9292,9298 ----
  	  tree tem;
  
  	  if (target_char_cast (s2, &c))
! 	    return NULL_TREE;
  
  	  r = strchr (p1, c);
  
*************** fold_builtin_strchr (tree arglist, tree 
*** 9095,9107 ****
  			     s1, build_int_cst (TREE_TYPE (s1), r - p1));
  	  return fold_convert (type, tem);
  	}
!       return 0;
      }
  }
  
! /* 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
--- 9304,9317 ----
  			     s1, build_int_cst (TREE_TYPE (s1), r - p1));
  	  return fold_convert (type, tem);
  	}
!       return NULL_TREE;
      }
  }
  
! /* Simplify a call to the strrchr builtin.  S1 and S2 are the arguments to
!    the call, and TYPE is its return type.
  
!    Return NULL_TREE 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
*************** fold_builtin_strchr (tree arglist, tree 
*** 9117,9134 ****
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strrchr (tree arglist, tree type)
  {
!   if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
-       tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
        tree fn;
        const char *p1;
  
        if (TREE_CODE (s2) != INTEGER_CST)
! 	return 0;
  
        p1 = c_getstr (s1);
        if (p1 != NULL)
--- 9327,9344 ----
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strrchr (tree s1, tree s2, tree type)
  {
!   if (!validate_arg (s1, POINTER_TYPE)
!       || !validate_arg (s2, INTEGER_TYPE))
!     return NULL_TREE;
    else
      {
        tree fn;
        const char *p1;
  
        if (TREE_CODE (s2) != INTEGER_CST)
! 	return NULL_TREE;
  
        p1 = c_getstr (s1);
        if (p1 != NULL)
*************** fold_builtin_strrchr (tree arglist, tree
*** 9138,9144 ****
  	  tree tem;
  
  	  if (target_char_cast (s2, &c))
! 	    return 0;
  
  	  r = strrchr (p1, c);
  
--- 9348,9354 ----
  	  tree tem;
  
  	  if (target_char_cast (s2, &c))
! 	    return NULL_TREE;
  
  	  r = strrchr (p1, c);
  
*************** fold_builtin_strrchr (tree arglist, tree
*** 9152,9171 ****
  	}
  
        if (! integer_zerop (s2))
! 	return 0;
  
        fn = implicit_built_in_decls[BUILT_IN_STRCHR];
        if (!fn)
! 	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
--- 9362,9382 ----
  	}
  
        if (! integer_zerop (s2))
! 	return NULL_TREE;
  
        fn = implicit_built_in_decls[BUILT_IN_STRCHR];
        if (!fn)
! 	return NULL_TREE;
  
        /* Transform strrchr(s1, '\0') to strchr(s1, '\0').  */
!       return build_call_expr (fn, 2, s1, s2);
      }
  }
  
! /* Simplify a call to the strpbrk builtin.  S1 and S2 are the arguments
!    to the call, and TYPE is its return type.
  
!    Return NULL_TREE 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
*************** fold_builtin_strrchr (tree arglist, tree
*** 9181,9199 ****
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strpbrk (tree arglist, tree type)
  {
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
-       tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
        tree fn;
        const char *p1, *p2;
  
        p2 = c_getstr (s2);
        if (p2 == NULL)
! 	return 0;
  
        p1 = c_getstr (s1);
        if (p1 != NULL)
--- 9392,9410 ----
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strpbrk (tree s1, tree s2, tree type)
  {
!   if (!validate_arg (s1, POINTER_TYPE)
!       || !validate_arg (s2, POINTER_TYPE))
!     return NULL_TREE;
    else
      {
        tree fn;
        const char *p1, *p2;
  
        p2 = c_getstr (s2);
        if (p2 == NULL)
! 	return NULL_TREE;
  
        p1 = c_getstr (s1);
        if (p1 != NULL)
*************** fold_builtin_strpbrk (tree arglist, tree
*** 9216,9239 ****
  	return omit_one_operand (TREE_TYPE (s1), integer_zero_node, s1);
  
        if (p2[1] != '\0')
! 	return 0;  /* Really call strpbrk.  */
  
        fn = implicit_built_in_decls[BUILT_IN_STRCHR];
        if (!fn)
! 	return 0;
  
        /* New argument list transforming strpbrk(s1, s2) to
  	 strchr(s1, s2[0]).  */
!       arglist = build_tree_list (NULL_TREE,
! 				 build_int_cst (NULL_TREE, p2[0]));
!       arglist = tree_cons (NULL_TREE, s1, arglist);
!       return build_function_call_expr (fn, arglist);
      }
  }
  
! /* 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
--- 9427,9448 ----
  	return omit_one_operand (TREE_TYPE (s1), integer_zero_node, s1);
  
        if (p2[1] != '\0')
! 	return NULL_TREE;  /* Really call strpbrk.  */
  
        fn = implicit_built_in_decls[BUILT_IN_STRCHR];
        if (!fn)
! 	return NULL_TREE;
  
        /* New argument list transforming strpbrk(s1, s2) to
  	 strchr(s1, s2[0]).  */
!       return build_call_expr (fn, 2, s1, build_int_cst (NULL_TREE, p2[0]));
      }
  }
  
! /* Simplify a call to the strcat builtin.  DST and SRC are the arguments
!    to the call.
  
!    Return NULL_TREE 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
*************** fold_builtin_strpbrk (tree arglist, tree
*** 9249,9275 ****
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strcat (tree arglist)
  {
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
-       tree dst = TREE_VALUE (arglist),
- 	src = TREE_VALUE (TREE_CHAIN (arglist));
        const char *p = c_getstr (src);
  
        /* 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
--- 9458,9484 ----
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strcat (tree dst, tree src)
  {
!   if (!validate_arg (dst, POINTER_TYPE)
!       || !validate_arg (src, POINTER_TYPE))
!     return NULL_TREE;
    else
      {
        const char *p = c_getstr (src);
  
        /* If the string length is zero, return the dst parameter.  */
        if (p && *p == '\0')
  	return dst;
  
!       return NULL_TREE;
      }
  }
  
! /* Simplify a call to the strncat builtin.  DST, SRC, and LEN are the
!    arguments to the call.
  
!    Return NULL_TREE 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
*************** fold_builtin_strcat (tree arglist)
*** 9285,9300 ****
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strncat (tree arglist)
  {
!   if (!validate_arglist (arglist,
! 			 POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
-       tree dst = TREE_VALUE (arglist);
-       tree src = TREE_VALUE (TREE_CHAIN (arglist));
-       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
        const char *p = c_getstr (src);
  
        /* If the requested length is zero, or the src parameter string
--- 9494,9507 ----
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strncat (tree dst, tree src, tree len)
  {
!   if (!validate_arg (dst, POINTER_TYPE)
!       || !validate_arg (src, POINTER_TYPE)
!       || !validate_arg (len, INTEGER_TYPE))
!     return NULL_TREE;
    else
      {
        const char *p = c_getstr (src);
  
        /* If the requested length is zero, or the src parameter string
*************** fold_builtin_strncat (tree arglist)
*** 9307,9330 ****
        if (TREE_CODE (len) == INTEGER_CST && p
  	  && compare_tree_int (len, strlen (p)) >= 0)
  	{
- 	  tree newarglist
- 	    = tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src));
  	  tree fn = implicit_built_in_decls[BUILT_IN_STRCAT];
  
  	  /* If the replacement _DECL isn't initialized, don't do the
  	     transformation.  */
  	  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
--- 9514,9536 ----
        if (TREE_CODE (len) == INTEGER_CST && p
  	  && compare_tree_int (len, strlen (p)) >= 0)
  	{
  	  tree fn = implicit_built_in_decls[BUILT_IN_STRCAT];
  
  	  /* If the replacement _DECL isn't initialized, don't do the
  	     transformation.  */
  	  if (!fn)
! 	    return NULL_TREE;
  
! 	  return build_call_expr (fn, 2, dst, src);
  	}
!       return NULL_TREE;
      }
  }
  
! /* Simplify a call to the strspn builtin.  S1 and S2 are the arguments
!    to the call.
  
!    Return NULL_TREE 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
*************** fold_builtin_strncat (tree arglist)
*** 9340,9352 ****
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strspn (tree arglist)
  {
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
-       tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
        const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
  
        /* If both arguments are constants, evaluate at compile-time.  */
--- 9546,9558 ----
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strspn (tree s1, tree s2)
  {
!   if (!validate_arg (s1, POINTER_TYPE)
!       || !validate_arg (s2, POINTER_TYPE))
!     return NULL_TREE;
    else
      {
        const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
  
        /* If both arguments are constants, evaluate at compile-time.  */
*************** fold_builtin_strspn (tree arglist)
*** 9356,9374 ****
  	  return size_int (r);
  	}
  
!       /* If either argument is "", return 0.  */
        if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
  	/* Evaluate and ignore both arguments in case either one has
  	   side-effects.  */
  	return omit_two_operands (integer_type_node, integer_zero_node,
  				  s1, s2);
!       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
--- 9562,9581 ----
  	  return size_int (r);
  	}
  
!       /* If either argument is "", return NULL_TREE.  */
        if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
  	/* Evaluate and ignore both arguments in case either one has
  	   side-effects.  */
  	return omit_two_operands (integer_type_node, integer_zero_node,
  				  s1, s2);
!       return NULL_TREE;
      }
  }
  
! /* Simplify a call to the strcspn builtin.  S1 and S2 are the arguments
!    to the call.
  
!    Return NULL_TREE 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
*************** fold_builtin_strspn (tree arglist)
*** 9384,9396 ****
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strcspn (tree arglist)
  {
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
!     return 0;
    else
      {
-       tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
        const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
  
        /* If both arguments are constants, evaluate at compile-time.  */
--- 9591,9603 ----
     form of the builtin function call.  */
  
  static tree
! fold_builtin_strcspn (tree s1, tree s2)
  {
!   if (!validate_arg (s1, POINTER_TYPE)
!       || !validate_arg (s2, POINTER_TYPE))
!     return NULL_TREE;
    else
      {
        const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
  
        /* If both arguments are constants, evaluate at compile-time.  */
*************** fold_builtin_strcspn (tree arglist)
*** 9400,9406 ****
  	  return size_int (r);
  	}
  
!       /* If the first argument is "", return 0.  */
        if (p1 && *p1 == '\0')
  	{
  	  /* Evaluate and ignore argument s2 in case it has
--- 9607,9613 ----
  	  return size_int (r);
  	}
  
!       /* If the first argument is "", return NULL_TREE.  */
        if (p1 && *p1 == '\0')
  	{
  	  /* Evaluate and ignore argument s2 in case it has
*************** fold_builtin_strcspn (tree arglist)
*** 9412,9441 ****
        /* If the second argument is "", return __builtin_strlen(s1).  */
        if (p2 && *p2 == '\0')
  	{
! 	  tree newarglist = build_tree_list (NULL_TREE, s1),
! 	    fn = implicit_built_in_decls[BUILT_IN_STRLEN];
  
  	  /* If the replacement _DECL isn't initialized, don't do the
  	     transformation.  */
  	  if (!fn)
! 	    return 0;
  
! 	  return build_function_call_expr (fn, newarglist);
  	}
!       return 0;
      }
  }
  
! /* Fold a call to the fputs builtin.  IGNORE is true if the value returned
     by the builtin will be ignored.  UNLOCKED is true is true if this
     actually a call to fputs_unlocked.  If LEN in non-NULL, it represents
     the known length of the string.  Return NULL_TREE if no simplification
     was possible.  */
  
  tree
! fold_builtin_fputs (tree arglist, bool ignore, bool unlocked, tree len)
  {
-   tree fn;
    /* If we're using an unlocked function, assume the other unlocked
       functions exist explicitly.  */
    tree const fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
--- 9619,9647 ----
        /* If the second argument is "", return __builtin_strlen(s1).  */
        if (p2 && *p2 == '\0')
  	{
! 	  tree fn = implicit_built_in_decls[BUILT_IN_STRLEN];
  
  	  /* If the replacement _DECL isn't initialized, don't do the
  	     transformation.  */
  	  if (!fn)
! 	    return NULL_TREE;
  
! 	  return build_call_expr (fn, 1, s1);
  	}
!       return NULL_TREE;
      }
  }
  
! /* Fold a call to the fputs builtin.  ARG0 and ARG1 are the arguments
!    to the call.  IGNORE is true if the value returned
     by the builtin will be ignored.  UNLOCKED is true is true if this
     actually a call to fputs_unlocked.  If LEN in non-NULL, it represents
     the known length of the string.  Return NULL_TREE if no simplification
     was possible.  */
  
  tree
! fold_builtin_fputs (tree arg0, tree arg1, bool ignore, bool unlocked, tree len)
  {
    /* If we're using an unlocked function, assume the other unlocked
       functions exist explicitly.  */
    tree const fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
*************** fold_builtin_fputs (tree arglist, bool i
*** 9445,9556 ****
  
    /* If the return value is used, don't do the transformation.  */
    if (!ignore)
!     return 0;
  
    /* Verify the arguments in the original call.  */
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
!     return 0;
  
    if (! len)
!     len = c_strlen (TREE_VALUE (arglist), 0);
  
    /* Get the length of the string passed to fputs.  If the length
       can't be determined, punt.  */
    if (!len
        || TREE_CODE (len) != INTEGER_CST)
!     return 0;
  
    switch (compare_tree_int (len, 1))
      {
      case -1: /* length is 0, delete the call entirely .  */
!       return omit_one_operand (integer_type_node, integer_zero_node,
! 			       TREE_VALUE (TREE_CHAIN (arglist)));
  
      case 0: /* length is 1, call fputc.  */
        {
! 	const char *p = c_getstr (TREE_VALUE (arglist));
  
  	if (p != NULL)
  	  {
  	    /* New argument list transforming fputs(string, stream) to
  	       fputc(string[0], stream).  */
! 	    arglist = build_tree_list (NULL_TREE,
! 				       TREE_VALUE (TREE_CHAIN (arglist)));
! 	    arglist = tree_cons (NULL_TREE,
! 				 build_int_cst (NULL_TREE, p[0]),
! 				 arglist);
! 	    fn = fn_fputc;
! 	    break;
  	  }
        }
        /* FALLTHROUGH */
      case 1: /* length is greater than 1, call fwrite.  */
        {
- 	tree string_arg;
- 
  	/* If optimizing for size keep fputs.  */
  	if (optimize_size)
! 	  return 0;
! 	string_arg = TREE_VALUE (arglist);
  	/* New argument list transforming fputs(string, stream) to
  	   fwrite(string, 1, len, stream).  */
! 	arglist = build_tree_list (NULL_TREE,
! 				   TREE_VALUE (TREE_CHAIN (arglist)));
! 	arglist = tree_cons (NULL_TREE, len, arglist);
! 	arglist = tree_cons (NULL_TREE, size_one_node, arglist);
! 	arglist = tree_cons (NULL_TREE, string_arg, arglist);
! 	fn = fn_fwrite;
! 	break;
        }
      default:
        gcc_unreachable ();
      }
! 
!   /* If the replacement _DECL isn't initialized, don't do the
!      transformation.  */
!   if (!fn)
!     return 0;
! 
!   /* These optimizations are only performed when the result is ignored,
!      hence there's no need to cast the result to integer_type_node.  */
!   return build_function_call_expr (fn, arglist);
  }
  
! /* Fold the new_arg's arguments (ARGLIST). Returns true if there was an error
     produced.  False otherwise.  This is done so that we don't output the error
     or warning twice or three times.  */
  bool
! fold_builtin_next_arg (tree arglist)
  {
    tree fntype = TREE_TYPE (current_function_decl);
  
    if (!stdarg_p (fntype))
      {
        error ("%<va_start%> used in function with fixed args");
        return true;
      }
!   else if (!arglist)
      {
!       /* Evidently an out of date version of <stdarg.h>; can't validate
! 	 va_start's second argument, but can still work as intended.  */
!       warning (0, "%<__builtin_next_arg%> called without an argument");
!       return true;
      }
!   /* We use __builtin_va_start (ap, 0, 0) or __builtin_next_arg (0, 0)
!      when we checked the arguments and if needed issued a warning.  */
!   else if (!TREE_CHAIN (arglist)
! 	   || !integer_zerop (TREE_VALUE (arglist))
! 	   || !integer_zerop (TREE_VALUE (TREE_CHAIN (arglist)))
! 	   || TREE_CHAIN (TREE_CHAIN (arglist)))
      {
!       tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl));
!       tree arg = TREE_VALUE (arglist);
! 
!       if (TREE_CHAIN (arglist))
  	{
! 	  error ("%<va_start%> used with too many arguments");
  	  return true;
  	}
  
        /* Strip off all nops for the sake of the comparison.  This
  	 is not quite the same as STRIP_NOPS.  It does more.
--- 9651,9760 ----
  
    /* If the return value is used, don't do the transformation.  */
    if (!ignore)
!     return NULL_TREE;
  
    /* Verify the arguments in the original call.  */
!   if (!validate_arg (arg0, POINTER_TYPE)
!       || !validate_arg (arg1, POINTER_TYPE))
!     return NULL_TREE;
  
    if (! len)
!     len = c_strlen (arg0, 0);
  
    /* Get the length of the string passed to fputs.  If the length
       can't be determined, punt.  */
    if (!len
        || TREE_CODE (len) != INTEGER_CST)
!     return NULL_TREE;
  
    switch (compare_tree_int (len, 1))
      {
      case -1: /* length is 0, delete the call entirely .  */
!       return omit_one_operand (integer_type_node, integer_zero_node, arg1);
  
      case 0: /* length is 1, call fputc.  */
        {
! 	const char *p = c_getstr (arg0);
  
  	if (p != NULL)
  	  {
  	    /* New argument list transforming fputs(string, stream) to
  	       fputc(string[0], stream).  */
! 	    if (fn_fputc)
! 	      return build_call_expr (fn_fputc, 2,
! 				      build_int_cst (NULL_TREE, p[0]), arg1);
! 	    else
! 	      return NULL_TREE;
  	  }
        }
        /* FALLTHROUGH */
      case 1: /* length is greater than 1, call fwrite.  */
        {
  	/* If optimizing for size keep fputs.  */
  	if (optimize_size)
! 	  return NULL_TREE;
  	/* New argument list transforming fputs(string, stream) to
  	   fwrite(string, 1, len, stream).  */
! 	if (fn_fwrite)
! 	  return build_call_expr (fn_fwrite, 4, arg0, size_one_node, len, arg1);
! 	else
! 	  return NULL_TREE;
        }
      default:
        gcc_unreachable ();
      }
!   return NULL_TREE;
  }
  
! 
! /* Fold the next_arg or va_start call EXP. Returns true if there was an error
     produced.  False otherwise.  This is done so that we don't output the error
     or warning twice or three times.  */
  bool
! fold_builtin_next_arg (tree exp, bool va_start_p)
  {
    tree fntype = TREE_TYPE (current_function_decl);
+   int nargs = call_expr_nargs (exp);
+   tree arg;
  
    if (!stdarg_p (fntype))
      {
        error ("%<va_start%> used in function with fixed args");
        return true;
      }
! 
!   if (va_start_p)
      {
!       if (va_start_p && (nargs != 2))
! 	{
! 	  error ("wrong number of arguments to function %<va_start%>");
! 	  return true;
! 	}
!       arg = CALL_EXPR_ARG1 (exp);
      }
!   else
      {
!       if (nargs == 0)
! 	{
! 	  /* Evidently an out of date version of <stdarg.h>; can't validate
! 	     va_start's second argument, but can still work as intended.  */
! 	  warning (0, "%<__builtin_next_arg%> called without an argument");
! 	  return true;
! 	}
!       else if (nargs > 1)
  	{
! 	  error ("wrong number of arguments to function %<__builtin_next_arg%>");
  	  return true;
  	}
+       arg = CALL_EXPR_ARG0 (exp);
+     }
+ 
+   /* We destructively modify the call to be __builtin_va_start (ap, 0)
+      or __builtin_next_arg (0) the first time we see it, after checking 
+      the arguments and if needed issuing a warning.  */
+   if (!integer_zerop (arg))
+     {
+       tree last_parm = tree_last (DECL_ARGUMENTS (current_function_decl));
  
        /* Strip off all nops for the sake of the comparison.  This
  	 is not quite the same as STRIP_NOPS.  It does more.
*************** fold_builtin_next_arg (tree arglist)
*** 9575,9610 ****
  	 as otherwise we could warn even for correct code like:
  	 void foo (int i, ...)
  	 { va_list ap; i++; va_start (ap, i); va_end (ap); }  */
!       TREE_VALUE (arglist) = integer_zero_node;
!       TREE_CHAIN (arglist) = build_tree_list (NULL, integer_zero_node);
      }
    return false;
  }
  
  
! /* Simplify a call to the sprintf builtin.
  
!    Return 0 if no simplification was possible, otherwise return the
     simplified form of the call as a tree.  If IGNORED is true, it means that
     the caller does not use the returned value of the function.  */
  
  static tree
! fold_builtin_sprintf (tree arglist, int ignored)
  {
!   tree call, retval, dest, fmt;
    const char *fmt_str = NULL;
  
    /* Verify the required arguments in the original call.  We deal with two
       types of sprintf() calls: 'sprintf (str, fmt)' and
       'sprintf (dest, "%s", orig)'.  */
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)
!       && !validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, POINTER_TYPE,
! 			    VOID_TYPE))
      return NULL_TREE;
- 
-   /* Get the destination string and the format specifier.  */
-   dest = TREE_VALUE (arglist);
-   fmt = TREE_VALUE (TREE_CHAIN (arglist));
  
    /* Check whether the format is a literal string constant.  */
    fmt_str = c_getstr (fmt);
--- 9779,9815 ----
  	 as otherwise we could warn even for correct code like:
  	 void foo (int i, ...)
  	 { va_list ap; i++; va_start (ap, i); va_end (ap); }  */
!       if (va_start_p)
! 	CALL_EXPR_ARG1 (exp) = integer_zero_node;
!       else
! 	CALL_EXPR_ARG0 (exp) = integer_zero_node;
      }
    return false;
  }
  
  
! /* Simplify a call to the sprintf builtin with arguments DEST, FMT, and ORIG.
!    ORIG may be null if this is a 2-argument call.  We don't attempt to
!    simplify calls with more than 3 arguments.
  
!    Return NULL_TREE if no simplification was possible, otherwise return the
     simplified form of the call as a tree.  If IGNORED is true, it means that
     the caller does not use the returned value of the function.  */
  
  static tree
! fold_builtin_sprintf (tree dest, tree fmt, tree orig, int ignored)
  {
!   tree call, retval;
    const char *fmt_str = NULL;
  
    /* Verify the required arguments in the original call.  We deal with two
       types of sprintf() calls: 'sprintf (str, fmt)' and
       'sprintf (dest, "%s", orig)'.  */
!   if (!validate_arg (dest, POINTER_TYPE)
!       || !validate_arg (fmt, POINTER_TYPE))
!     return NULL_TREE;
!   if (orig && !validate_arg (orig, POINTER_TYPE))
      return NULL_TREE;
  
    /* Check whether the format is a literal string constant.  */
    fmt_str = c_getstr (fmt);
*************** fold_builtin_sprintf (tree arglist, int 
*** 9615,9621 ****
    retval = NULL_TREE;
  
    if (!init_target_chars())
!     return 0;
  
    /* If the format doesn't contain % args or %%, use strcpy.  */
    if (strchr (fmt_str, target_percent) == NULL)
--- 9820,9826 ----
    retval = NULL_TREE;
  
    if (!init_target_chars())
!     return NULL_TREE;
  
    /* If the format doesn't contain % args or %%, use strcpy.  */
    if (strchr (fmt_str, target_percent) == NULL)
*************** fold_builtin_sprintf (tree arglist, int 
*** 9627,9635 ****
  
        /* Convert sprintf (str, fmt) into strcpy (str, fmt) when
  	 'format' is known to contain no % formats.  */
!       arglist = build_tree_list (NULL_TREE, fmt);
!       arglist = tree_cons (NULL_TREE, dest, arglist);
!       call = build_function_call_expr (fn, arglist);
        if (!ignored)
  	retval = build_int_cst (NULL_TREE, strlen (fmt_str));
      }
--- 9832,9838 ----
  
        /* Convert sprintf (str, fmt) into strcpy (str, fmt) when
  	 'format' is known to contain no % formats.  */
!       call = build_call_expr (fn, 2, dest, fmt);
        if (!ignored)
  	retval = build_int_cst (NULL_TREE, strlen (fmt_str));
      }
*************** fold_builtin_sprintf (tree arglist, int 
*** 9637,9659 ****
    /* If the format is "%s", use strcpy if the result isn't used.  */
    else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
      {
!       tree fn, orig;
        fn = implicit_built_in_decls[BUILT_IN_STRCPY];
  
        if (!fn)
  	return NULL_TREE;
  
        /* Convert sprintf (str1, "%s", str2) into strcpy (str1, str2).  */
-       orig = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
-       arglist = build_tree_list (NULL_TREE, orig);
-       arglist = tree_cons (NULL_TREE, dest, arglist);
        if (!ignored)
  	{
  	  retval = c_strlen (orig, 1);
  	  if (!retval || TREE_CODE (retval) != INTEGER_CST)
  	    return NULL_TREE;
  	}
!       call = build_function_call_expr (fn, arglist);
      }
  
    if (call && retval)
--- 9840,9859 ----
    /* If the format is "%s", use strcpy if the result isn't used.  */
    else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
      {
!       tree fn;
        fn = implicit_built_in_decls[BUILT_IN_STRCPY];
  
        if (!fn)
  	return NULL_TREE;
  
        /* Convert sprintf (str1, "%s", str2) into strcpy (str1, str2).  */
        if (!ignored)
  	{
  	  retval = c_strlen (orig, 1);
  	  if (!retval || TREE_CODE (retval) != INTEGER_CST)
  	    return NULL_TREE;
  	}
!       call = build_call_expr (fn, 2, dest, orig);
      }
  
    if (call && retval)
*************** fold_builtin_sprintf (tree arglist, int 
*** 9667,9673 ****
      return call;
  }
  
! /* Expand a call to __builtin_object_size.  */
  
  rtx
  expand_builtin_object_size (tree exp)
--- 9867,9873 ----
      return call;
  }
  
! /* Expand a call EXP to __builtin_object_size.  */
  
  rtx
  expand_builtin_object_size (tree exp)
*************** expand_builtin_object_size (tree exp)
*** 9675,9684 ****
    tree ost;
    int object_size_type;
    tree fndecl = get_callee_fndecl (exp);
-   tree arglist = TREE_OPERAND (exp, 1);
    location_t locus = EXPR_LOCATION (exp);
  
!   if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      {
        error ("%Hfirst argument of %D must be a pointer, second integer constant",
  	     &locus, fndecl);
--- 9875,9883 ----
    tree ost;
    int object_size_type;
    tree fndecl = get_callee_fndecl (exp);
    location_t locus = EXPR_LOCATION (exp);
  
!   if (!validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
      {
        error ("%Hfirst argument of %D must be a pointer, second integer constant",
  	     &locus, fndecl);
*************** expand_builtin_object_size (tree exp)
*** 9686,9692 ****
        return const0_rtx;
      }
  
!   ost = TREE_VALUE (TREE_CHAIN (arglist));
    STRIP_NOPS (ost);
  
    if (TREE_CODE (ost) != INTEGER_CST
--- 9885,9891 ----
        return const0_rtx;
      }
  
!   ost = CALL_EXPR_ARG1 (exp);
    STRIP_NOPS (ost);
  
    if (TREE_CODE (ost) != INTEGER_CST
*************** expand_builtin_object_size (tree exp)
*** 9706,9712 ****
  
  /* Expand EXP, a call to the __mem{cpy,pcpy,move,set}_chk builtin.
     FCODE is the BUILT_IN_* to use.
!    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).  */
  
--- 9905,9911 ----
  
  /* Expand EXP, a call to the __mem{cpy,pcpy,move,set}_chk builtin.
     FCODE is the BUILT_IN_* to use.
!    Return NULL_RTX 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
*** 9714,9736 ****
  expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
  			   enum built_in_function fcode)
  {
-   tree arglist = TREE_OPERAND (exp, 1);
    tree dest, src, len, size;
  
!   if (!validate_arglist (arglist,
  			 POINTER_TYPE,
  			 fcode == BUILT_IN_MEMSET_CHK
  			 ? INTEGER_TYPE : POINTER_TYPE,
  			 INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
  
!   dest = TREE_VALUE (arglist);
!   src = TREE_VALUE (TREE_CHAIN (arglist));
!   len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
!   size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
  
    if (! host_integerp (size, 1))
!     return 0;
  
    if (host_integerp (len, 1) || integer_all_onesp (size))
      {
--- 9913,9934 ----
  expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
  			   enum built_in_function fcode)
  {
    tree dest, src, len, size;
  
!   if (!validate_arglist (exp,
  			 POINTER_TYPE,
  			 fcode == BUILT_IN_MEMSET_CHK
  			 ? INTEGER_TYPE : POINTER_TYPE,
  			 INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return NULL_RTX;
  
!   dest = CALL_EXPR_ARG0 (exp);
!   src = CALL_EXPR_ARG1 (exp);
!   len = CALL_EXPR_ARG2 (exp);
!   size = call_expr_arg (exp, 3);
  
    if (! host_integerp (size, 1))
!     return NULL_RTX;
  
    if (host_integerp (len, 1) || integer_all_onesp (size))
      {
*************** expand_builtin_memory_chk (tree exp, rtx
*** 9741,9753 ****
  	  location_t locus = EXPR_LOCATION (exp);
  	  warning (0, "%Hcall to %D will always overflow destination buffer",
  		   &locus, get_callee_fndecl (exp));
! 	  return 0;
  	}
  
-       arglist = build_tree_list (NULL_TREE, len);
-       arglist = tree_cons (NULL_TREE, src, arglist);
-       arglist = tree_cons (NULL_TREE, dest, arglist);
- 
        fn = NULL_TREE;
        /* If __builtin_mem{cpy,pcpy,move,set}_chk is used, assume
  	 mem{cpy,pcpy,move,set} is available.  */
--- 9939,9947 ----
  	  location_t locus = EXPR_LOCATION (exp);
  	  warning (0, "%Hcall to %D will always overflow destination buffer",
  		   &locus, get_callee_fndecl (exp));
! 	  return NULL_RTX;
  	}
  
        fn = NULL_TREE;
        /* If __builtin_mem{cpy,pcpy,move,set}_chk is used, assume
  	 mem{cpy,pcpy,move,set} is available.  */
*************** expand_builtin_memory_chk (tree exp, rtx
*** 9770,9784 ****
  	}
  
        if (! fn)
! 	return 0;
  
!       fn = build_function_call_expr (fn, arglist);
        if (TREE_CODE (fn) == CALL_EXPR)
  	CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
        return expand_expr (fn, target, mode, EXPAND_NORMAL);
      }
    else if (fcode == BUILT_IN_MEMSET_CHK)
!     return 0;
    else
      {
        unsigned int dest_align
--- 9964,9978 ----
  	}
  
        if (! fn)
! 	return NULL_RTX;
  
!       fn = build_call_expr (fn, 3, dest, src, len);
        if (TREE_CODE (fn) == CALL_EXPR)
  	CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
        return expand_expr (fn, target, mode, EXPAND_NORMAL);
      }
    else if (fcode == BUILT_IN_MEMSET_CHK)
!     return NULL_RTX;
    else
      {
        unsigned int dest_align
*************** expand_builtin_memory_chk (tree exp, rtx
*** 9786,9792 ****
  
        /* If DEST is not a pointer type, call the normal function.  */
        if (dest_align == 0)
! 	return 0;
  
        /* If SRC and DEST are the same (and not volatile), do nothing.  */
        if (operand_equal_p (src, dest, 0))
--- 9980,9986 ----
  
        /* If DEST is not a pointer type, call the normal function.  */
        if (dest_align == 0)
! 	return NULL_RTX;
  
        /* If SRC and DEST are the same (and not volatile), do nothing.  */
        if (operand_equal_p (src, dest, 0))
*************** expand_builtin_memory_chk (tree exp, rtx
*** 9812,9818 ****
  	    = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
  
  	  if (src_align == 0)
! 	    return 0;
  
  	  /* If src is categorized for a readonly section we can use
  	     normal __memcpy_chk.  */
--- 10006,10012 ----
  	    = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
  
  	  if (src_align == 0)
! 	    return NULL_RTX;
  
  	  /* If src is categorized for a readonly section we can use
  	     normal __memcpy_chk.  */
*************** expand_builtin_memory_chk (tree exp, rtx
*** 9820,9833 ****
  	    {
  	      tree fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
  	      if (!fn)
! 		return 0;
! 	      fn = build_function_call_expr (fn, arglist);
  	      if (TREE_CODE (fn) == CALL_EXPR)
  		CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
  	      return expand_expr (fn, target, mode, EXPAND_NORMAL);
  	    }
  	}
!       return 0;
      }
  }
  
--- 10014,10027 ----
  	    {
  	      tree fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
  	      if (!fn)
! 		return NULL_RTX;
! 	      fn = build_call_expr (fn, 4, dest, src, len, size);
  	      if (TREE_CODE (fn) == CALL_EXPR)
  		CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
  	      return expand_expr (fn, target, mode, EXPAND_NORMAL);
  	    }
  	}
!       return NULL_RTX;
      }
  }
  
*************** expand_builtin_memory_chk (tree exp, rtx
*** 9836,9843 ****
  static void
  maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
  {
!   int arg_mask, is_strlen = 0;
!   tree arglist = TREE_OPERAND (exp, 1), a;
    tree len, size;
    location_t locus;
  
--- 10030,10036 ----
  static void
  maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
  {
!   int is_strlen = 0;
    tree len, size;
    location_t locus;
  
*************** maybe_emit_chk_warning (tree exp, enum b
*** 9848,9884 ****
      /* For __strcat_chk the warning will be emitted only if overflowing
         by at least strlen (dest) + 1 bytes.  */
      case BUILT_IN_STRCAT_CHK:
!       arg_mask = 6;
        is_strlen = 1;
        break;
      case BUILT_IN_STRNCPY_CHK:
!       arg_mask = 12;
        break;
      case BUILT_IN_SNPRINTF_CHK:
      case BUILT_IN_VSNPRINTF_CHK:
!       arg_mask = 10;
        break;
      default:
        gcc_unreachable ();
      }
  
-   len = NULL_TREE;
-   size = NULL_TREE;
-   for (a = arglist; a && arg_mask; a = TREE_CHAIN (a), arg_mask >>= 1)
-     if (arg_mask & 1)
-       {
- 	if (len)
- 	  size = a;
- 	else
- 	  len = a;
-       }
- 
    if (!len || !size)
      return;
  
-   len = TREE_VALUE (len);
-   size = TREE_VALUE (size);
- 
    if (! host_integerp (size, 1) || integer_all_onesp (size))
      return;
  
--- 10041,10066 ----
      /* For __strcat_chk the warning will be emitted only if overflowing
         by at least strlen (dest) + 1 bytes.  */
      case BUILT_IN_STRCAT_CHK:
!       len = call_expr_arg (exp, 1);
!       size = call_expr_arg (exp, 2);
        is_strlen = 1;
        break;
      case BUILT_IN_STRNCPY_CHK:
!       len = call_expr_arg (exp, 2);
!       size = call_expr_arg (exp, 3);
        break;
      case BUILT_IN_SNPRINTF_CHK:
      case BUILT_IN_VSNPRINTF_CHK:
!       len = call_expr_arg (exp, 1);
!       size = call_expr_arg (exp, 3);
        break;
      default:
        gcc_unreachable ();
      }
  
    if (!len || !size)
      return;
  
    if (! host_integerp (size, 1) || integer_all_onesp (size))
      return;
  
*************** maybe_emit_chk_warning (tree exp, enum b
*** 9902,9928 ****
  static void
  maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode)
  {
-   tree arglist = TREE_OPERAND (exp, 1);
    tree dest, size, len, fmt, flag;
    const char *fmt_str;
  
    /* Verify the required arguments in the original call.  */
!   if (! arglist)
!     return;
!   dest = TREE_VALUE (arglist);
!   arglist = TREE_CHAIN (arglist);
!   if (! arglist)
      return;
!   flag = TREE_VALUE (arglist);
!   arglist = TREE_CHAIN (arglist);
!   if (! arglist)
!     return;
!   size = TREE_VALUE (arglist);
!   arglist = TREE_CHAIN (arglist);
!   if (! arglist)
!     return;
!   fmt = TREE_VALUE (arglist);
!   arglist = TREE_CHAIN (arglist);
  
    if (! host_integerp (size, 1) || integer_all_onesp (size))
      return;
--- 10084,10101 ----
  static void
  maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode)
  {
    tree dest, size, len, fmt, flag;
    const char *fmt_str;
+   int nargs = call_expr_nargs (exp);
  
    /* Verify the required arguments in the original call.  */
!   
!   if (nargs < 4)
      return;
!   dest = CALL_EXPR_ARG0 (exp);
!   flag = CALL_EXPR_ARG1 (exp);
!   size = CALL_EXPR_ARG2 (exp);
!   fmt = call_expr_arg (exp, 3);
  
    if (! host_integerp (size, 1) || integer_all_onesp (size))
      return;
*************** maybe_emit_sprintf_chk_warning (tree exp
*** 9940,9952 ****
      len = build_int_cstu (size_type_node, strlen (fmt_str));
    /* If the format is "%s" and first ... argument is a string literal,
       we know it too.  */
!   else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, target_percent_s) == 0)
      {
        tree arg;
  
!       if (! arglist)
  	return;
!       arg = TREE_VALUE (arglist);
        if (! POINTER_TYPE_P (TREE_TYPE (arg)))
  	return;
  
--- 10113,10126 ----
      len = build_int_cstu (size_type_node, strlen (fmt_str));
    /* If the format is "%s" and first ... argument is a string literal,
       we know it too.  */
!   else if (fcode == BUILT_IN_SPRINTF_CHK
! 	   && strcmp (fmt_str, target_percent_s) == 0)
      {
        tree arg;
  
!       if (nargs < 5)
  	return;
!       arg = call_expr_arg (exp, 4);
        if (! POINTER_TYPE_P (TREE_TYPE (arg)))
  	return;
  
*************** maybe_emit_sprintf_chk_warning (tree exp
*** 9965,9989 ****
      }
  }
  
! /* Fold a call to __builtin_object_size, if possible.  */
  
  tree
! fold_builtin_object_size (tree arglist)
  {
!   tree ptr, ost, ret = 0;
    int object_size_type;
  
!   if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
  
-   ptr = TREE_VALUE (arglist);
-   ost = TREE_VALUE (TREE_CHAIN (arglist));
    STRIP_NOPS (ost);
  
    if (TREE_CODE (ost) != INTEGER_CST
        || tree_int_cst_sgn (ost) < 0
        || compare_tree_int (ost, 3) > 0)
!     return 0;
  
    object_size_type = tree_low_cst (ost, 0);
  
--- 10139,10163 ----
      }
  }
  
! /* Fold a call to __builtin_object_size with arguments PTR and OST,
!    if possible.  */
  
  tree
! fold_builtin_object_size (tree ptr, tree ost)
  {
!   tree ret = NULL_TREE;
    int object_size_type;
  
!   if (!validate_arg (ptr, POINTER_TYPE)
!       || !validate_arg (ost, INTEGER_TYPE))
!     return NULL_TREE;
  
    STRIP_NOPS (ost);
  
    if (TREE_CODE (ost) != INTEGER_CST
        || tree_int_cst_sgn (ost) < 0
        || compare_tree_int (ost, 3) > 0)
!     return NULL_TREE;
  
    object_size_type = tree_low_cst (ost, 0);
  
*************** fold_builtin_object_size (tree arglist)
*** 10016,10050 ****
      {
        ret = force_fit_type (ret, -1, false, false);
        if (TREE_CONSTANT_OVERFLOW (ret))
! 	ret = 0;
      }
  
    return ret;
  }
  
  /* Fold a call to the __mem{cpy,pcpy,move,set}_chk builtin.
     IGNORE is true, if return value can be ignored.  FCODE is the BUILT_IN_*
     code of the builtin.  If MAXLEN is not NULL, it is maximum length
     passed as third argument.  */
  
  tree
! fold_builtin_memory_chk (tree fndecl, tree arglist, tree maxlen, bool ignore,
  			 enum built_in_function fcode)
  {
!   tree dest, src, len, size, fn;
! 
!   if (!validate_arglist (arglist,
! 			 POINTER_TYPE,
! 			 fcode == BUILT_IN_MEMSET_CHK
! 			 ? INTEGER_TYPE : POINTER_TYPE,
! 			 INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
!     return 0;
  
!   dest = TREE_VALUE (arglist);
!   /* Actually val for __memset_chk, but it doesn't matter.  */
!   src = TREE_VALUE (TREE_CHAIN (arglist));
!   len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
!   size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
  
    /* If SRC and DEST are the same (and not volatile), return DEST
       (resp. DEST+LEN for __mempcpy_chk).  */
--- 10190,10222 ----
      {
        ret = force_fit_type (ret, -1, false, false);
        if (TREE_CONSTANT_OVERFLOW (ret))
! 	ret = NULL_TREE;
      }
  
    return ret;
  }
  
  /* Fold a call to the __mem{cpy,pcpy,move,set}_chk builtin.
+    DEST, SRC, LEN, and SIZE are the arguments to the call.
     IGNORE is true, if return value can be ignored.  FCODE is the BUILT_IN_*
     code of the builtin.  If MAXLEN is not NULL, it is maximum length
     passed as third argument.  */
  
  tree
! fold_builtin_memory_chk (tree fndecl,
! 			 tree dest, tree src, tree len, tree size,
! 			 tree maxlen, bool ignore,
  			 enum built_in_function fcode)
  {
!   tree fn;
  
!   if (!validate_arg (dest, POINTER_TYPE)
!       || !validate_arg (src,
! 			(fcode == BUILT_IN_MEMSET_CHK
! 			 ? INTEGER_TYPE : POINTER_TYPE))
!       || !validate_arg (len, INTEGER_TYPE)
!       || !validate_arg (size, INTEGER_TYPE))
!     return NULL_TREE;
  
    /* If SRC and DEST are the same (and not volatile), return DEST
       (resp. DEST+LEN for __mempcpy_chk).  */
*************** fold_builtin_memory_chk (tree fndecl, tr
*** 10061,10067 ****
      }
  
    if (! host_integerp (size, 1))
!     return 0;
  
    if (! integer_all_onesp (size))
      {
--- 10233,10239 ----
      }
  
    if (! host_integerp (size, 1))
!     return NULL_TREE;
  
    if (! integer_all_onesp (size))
      {
*************** fold_builtin_memory_chk (tree fndecl, tr
*** 10078,10101 ****
  		     (void) __memcpy_chk ().  */
  		  fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
  		  if (!fn)
! 		    return 0;
  
! 		  return build_function_call_expr (fn, arglist);
  		}
! 	      return 0;
  	    }
  	}
        else
  	maxlen = len;
  
        if (tree_int_cst_lt (size, maxlen))
! 	return 0;
      }
  
-   arglist = build_tree_list (NULL_TREE, len);
-   arglist = tree_cons (NULL_TREE, src, arglist);
-   arglist = tree_cons (NULL_TREE, dest, arglist);
- 
    fn = NULL_TREE;
    /* If __builtin_mem{cpy,pcpy,move,set}_chk is used, assume
       mem{cpy,pcpy,move,set} is available.  */
--- 10250,10269 ----
  		     (void) __memcpy_chk ().  */
  		  fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
  		  if (!fn)
! 		    return NULL_TREE;
  
! 		  return build_call_expr (fn, 4, dest, src, len, size);
  		}
! 	      return NULL_TREE;
  	    }
  	}
        else
  	maxlen = len;
  
        if (tree_int_cst_lt (size, maxlen))
! 	return NULL_TREE;
      }
  
    fn = NULL_TREE;
    /* If __builtin_mem{cpy,pcpy,move,set}_chk is used, assume
       mem{cpy,pcpy,move,set} is available.  */
*************** fold_builtin_memory_chk (tree fndecl, tr
*** 10118,10153 ****
      }
  
    if (!fn)
!     return 0;
  
!   return build_function_call_expr (fn, arglist);
  }
  
  /* Fold a call to the __st[rp]cpy_chk builtin.
!    IGNORE is true, if return value can be ignored.  FCODE is the BUILT_IN_*
     code of the builtin.  If MAXLEN is not NULL, it is maximum length of
     strings passed as second argument.  */
  
  tree
! fold_builtin_stxcpy_chk (tree fndecl, tree arglist, tree maxlen, bool ignore,
  			 enum built_in_function fcode)
  {
!   tree dest, src, size, len, fn;
! 
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE,
! 			 VOID_TYPE))
!     return 0;
  
!   dest = TREE_VALUE (arglist);
!   src = TREE_VALUE (TREE_CHAIN (arglist));
!   size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
  
    /* If SRC and DEST are the same (and not volatile), return DEST.  */
    if (fcode == BUILT_IN_STRCPY_CHK && operand_equal_p (src, dest, 0))
      return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), dest);
  
    if (! host_integerp (size, 1))
!     return 0;
  
    if (! integer_all_onesp (size))
      {
--- 10286,10320 ----
      }
  
    if (!fn)
!     return NULL_TREE;
  
!   return build_call_expr (fn, 3, dest, src, len);
  }
  
  /* Fold a call to the __st[rp]cpy_chk builtin.
!    DEST, SRC, and SIZE are the arguments to the call.
!    IGNORE is true if return value can be ignored.  FCODE is the BUILT_IN_*
     code of the builtin.  If MAXLEN is not NULL, it is maximum length of
     strings passed as second argument.  */
  
  tree
! fold_builtin_stxcpy_chk (tree fndecl, tree dest, tree src, tree size,
! 			 tree maxlen, bool ignore,
  			 enum built_in_function fcode)
  {
!   tree len, fn;
  
!   if (!validate_arg (dest, POINTER_TYPE)
!       || !validate_arg (src, POINTER_TYPE)
!       || !validate_arg (size, INTEGER_TYPE))
!     return NULL_TREE;
  
    /* If SRC and DEST are the same (and not volatile), return DEST.  */
    if (fcode == BUILT_IN_STRCPY_CHK && operand_equal_p (src, dest, 0))
      return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), dest);
  
    if (! host_integerp (size, 1))
!     return NULL_TREE;
  
    if (! integer_all_onesp (size))
      {
*************** fold_builtin_stxcpy_chk (tree fndecl, tr
*** 10162,10234 ****
  	      if (fcode == BUILT_IN_STPCPY_CHK)
  		{
  		  if (! ignore)
! 		    return 0;
  
  		  /* If return value of __stpcpy_chk is ignored,
  		     optimize into __strcpy_chk.  */
  		  fn = built_in_decls[BUILT_IN_STRCPY_CHK];
  		  if (!fn)
! 		    return 0;
  
! 		  return build_function_call_expr (fn, arglist);
  		}
  
  	      if (! len || TREE_SIDE_EFFECTS (len))
! 		return 0;
  
  	      /* If c_strlen returned something, but not a constant,
  		 transform __strcpy_chk into __memcpy_chk.  */
  	      fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
  	      if (!fn)
! 		return 0;
  
  	      len = size_binop (PLUS_EXPR, len, ssize_int (1));
- 	      arglist = build_tree_list (NULL_TREE, size);
- 	      arglist = tree_cons (NULL_TREE, len, arglist);
- 	      arglist = tree_cons (NULL_TREE, src, arglist);
- 	      arglist = tree_cons (NULL_TREE, dest, arglist);
  	      return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)),
! 				   build_function_call_expr (fn, arglist));
  	    }
  	}
        else
  	maxlen = len;
  
        if (! tree_int_cst_lt (maxlen, size))
! 	return 0;
      }
  
-   arglist = build_tree_list (NULL_TREE, src);
-   arglist = tree_cons (NULL_TREE, dest, arglist);
- 
    /* If __builtin_st{r,p}cpy_chk is used, assume st{r,p}cpy is available.  */
    fn = built_in_decls[fcode == BUILT_IN_STPCPY_CHK
  		      ? BUILT_IN_STPCPY : BUILT_IN_STRCPY];
    if (!fn)
!     return 0;
  
!   return build_function_call_expr (fn, arglist);
  }
  
! /* Fold a call to the __strncpy_chk builtin.
!    If MAXLEN is not NULL, it is maximum length passed as third argument.  */
  
  tree
! fold_builtin_strncpy_chk (tree arglist, tree maxlen)
  {
!   tree dest, src, size, len, fn;
! 
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE,
! 			 INTEGER_TYPE, VOID_TYPE))
!     return 0;
  
!   dest = TREE_VALUE (arglist);
!   src = TREE_VALUE (TREE_CHAIN (arglist));
!   len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
!   size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
  
    if (! host_integerp (size, 1))
!     return 0;
  
    if (! integer_all_onesp (size))
      {
--- 10329,10394 ----
  	      if (fcode == BUILT_IN_STPCPY_CHK)
  		{
  		  if (! ignore)
! 		    return NULL_TREE;
  
  		  /* If return value of __stpcpy_chk is ignored,
  		     optimize into __strcpy_chk.  */
  		  fn = built_in_decls[BUILT_IN_STRCPY_CHK];
  		  if (!fn)
! 		    return NULL_TREE;
  
! 		  return build_call_expr (fn, 3, dest, src, size);
  		}
  
  	      if (! len || TREE_SIDE_EFFECTS (len))
! 		return NULL_TREE;
  
  	      /* If c_strlen returned something, but not a constant,
  		 transform __strcpy_chk into __memcpy_chk.  */
  	      fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
  	      if (!fn)
! 		return NULL_TREE;
  
  	      len = size_binop (PLUS_EXPR, len, ssize_int (1));
  	      return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)),
! 				   build_call_expr (fn, 4,
! 						    dest, src, len, size));
  	    }
  	}
        else
  	maxlen = len;
  
        if (! tree_int_cst_lt (maxlen, size))
! 	return NULL_TREE;
      }
  
    /* If __builtin_st{r,p}cpy_chk is used, assume st{r,p}cpy is available.  */
    fn = built_in_decls[fcode == BUILT_IN_STPCPY_CHK
  		      ? BUILT_IN_STPCPY : BUILT_IN_STRCPY];
    if (!fn)
!     return NULL_TREE;
  
!   return build_call_expr (fn, 2, dest, src);
  }
  
! /* Fold a call to the __strncpy_chk builtin.  DEST, SRC, LEN, and SIZE
!    are the arguments to the call.  If MAXLEN is not NULL, it is maximum
!    length passed as third argument.  */
  
  tree
! fold_builtin_strncpy_chk (tree dest, tree src, tree len, tree size,
! 			  tree maxlen)
  {
!   tree fn;
  
!   if (!validate_arg (dest, POINTER_TYPE)
!       || !validate_arg (src, POINTER_TYPE)
!       || !validate_arg (len, INTEGER_TYPE)
!       || !validate_arg (size, INTEGER_TYPE))
!     return NULL_TREE;
  
    if (! host_integerp (size, 1))
!     return NULL_TREE;
  
    if (! integer_all_onesp (size))
      {
*************** fold_builtin_strncpy_chk (tree arglist, 
*** 10238,10279 ****
  	     For MAXLEN only allow optimizing into non-_ocs function
  	     if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
  	  if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
! 	    return 0;
  	}
        else
  	maxlen = len;
  
        if (tree_int_cst_lt (size, maxlen))
! 	return 0;
      }
  
-   arglist = build_tree_list (NULL_TREE, len);
-   arglist = tree_cons (NULL_TREE, src, arglist);
-   arglist = tree_cons (NULL_TREE, dest, arglist);
- 
    /* If __builtin_strncpy_chk is used, assume strncpy is available.  */
    fn = built_in_decls[BUILT_IN_STRNCPY];
    if (!fn)
!     return 0;
  
!   return build_function_call_expr (fn, arglist);
  }
  
! /* Fold a call to the __strcat_chk builtin FNDECL with ARGLIST.  */
  
  static tree
! fold_builtin_strcat_chk (tree fndecl, tree arglist)
  {
!   tree dest, src, size, fn;
    const char *p;
  
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE,
! 			 VOID_TYPE))
!     return 0;
! 
!   dest = TREE_VALUE (arglist);
!   src = TREE_VALUE (TREE_CHAIN (arglist));
!   size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
  
    p = c_getstr (src);
    /* If the SRC parameter is "", return DEST.  */
--- 10398,10433 ----
  	     For MAXLEN only allow optimizing into non-_ocs function
  	     if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
  	  if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
! 	    return NULL_TREE;
  	}
        else
  	maxlen = len;
  
        if (tree_int_cst_lt (size, maxlen))
! 	return NULL_TREE;
      }
  
    /* If __builtin_strncpy_chk is used, assume strncpy is available.  */
    fn = built_in_decls[BUILT_IN_STRNCPY];
    if (!fn)
!     return NULL_TREE;
  
!   return build_call_expr (fn, 3, dest, src, len);
  }
  
! /* Fold a call to the __strcat_chk builtin FNDECL.  DEST, SRC, and SIZE
!    are the arguments to the call.  */
  
  static tree
! fold_builtin_strcat_chk (tree fndecl, tree dest, tree src, tree size)
  {
!   tree fn;
    const char *p;
  
!   if (!validate_arg (dest, POINTER_TYPE)
!       || !validate_arg (src, POINTER_TYPE)
!       || !validate_arg (size, INTEGER_TYPE))
!     return NULL_TREE;
  
    p = c_getstr (src);
    /* If the SRC parameter is "", return DEST.  */
*************** fold_builtin_strcat_chk (tree fndecl, tr
*** 10281,10315 ****
      return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
  
    if (! host_integerp (size, 1) || ! integer_all_onesp (size))
!     return 0;
! 
!   arglist = build_tree_list (NULL_TREE, src);
!   arglist = tree_cons (NULL_TREE, dest, arglist);
  
    /* If __builtin_strcat_chk is used, assume strcat is available.  */
    fn = built_in_decls[BUILT_IN_STRCAT];
    if (!fn)
!     return 0;
  
!   return build_function_call_expr (fn, arglist);
  }
  
! /* Fold a call to the __strncat_chk builtin EXP.  */
  
  static tree
! fold_builtin_strncat_chk (tree fndecl, tree arglist)
  {
!   tree dest, src, size, len, fn;
    const char *p;
  
!   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE,
! 			 INTEGER_TYPE, VOID_TYPE))
!     return 0;
! 
!   dest = TREE_VALUE (arglist);
!   src = TREE_VALUE (TREE_CHAIN (arglist));
!   len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
!   size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
  
    p = c_getstr (src);
    /* If the SRC parameter is "" or if LEN is 0, return DEST.  */
--- 10435,10465 ----
      return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
  
    if (! host_integerp (size, 1) || ! integer_all_onesp (size))
!     return NULL_TREE;
  
    /* If __builtin_strcat_chk is used, assume strcat is available.  */
    fn = built_in_decls[BUILT_IN_STRCAT];
    if (!fn)
!     return NULL_TREE;
  
!   return build_call_expr (fn, 2, dest, src);
  }
  
! /* Fold a call to the __strncat_chk builtin with arguments DEST, SRC,
!    LEN, and SIZE.  */
  
  static tree
! fold_builtin_strncat_chk (tree fndecl,
! 			  tree dest, tree src, tree len, tree size)
  {
!   tree fn;
    const char *p;
  
!   if (!validate_arg (dest, POINTER_TYPE)
!       || !validate_arg (src, POINTER_TYPE)
!       || !validate_arg (size, INTEGER_TYPE)
!       || !validate_arg (size, INTEGER_TYPE))
!     return NULL_TREE;
  
    p = c_getstr (src);
    /* If the SRC parameter is "" or if LEN is 0, return DEST.  */
*************** fold_builtin_strncat_chk (tree fndecl, t
*** 10319,10325 ****
      return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
  
    if (! host_integerp (size, 1))
!     return 0;
  
    if (! integer_all_onesp (size))
      {
--- 10469,10475 ----
      return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
  
    if (! host_integerp (size, 1))
!     return NULL_TREE;
  
    if (! integer_all_onesp (size))
      {
*************** fold_builtin_strncat_chk (tree fndecl, t
*** 10332,10402 ****
  	  /* If LEN >= strlen (SRC), optimize into __strcat_chk.  */
  	  fn = built_in_decls[BUILT_IN_STRCAT_CHK];
  	  if (!fn)
! 	    return 0;
  
! 	  arglist = build_tree_list (NULL_TREE, size);
! 	  arglist = tree_cons (NULL_TREE, src, arglist);
! 	  arglist = tree_cons (NULL_TREE, dest, arglist);
! 	  return build_function_call_expr (fn, arglist);
  	}
!       return 0;
      }
  
-   arglist = build_tree_list (NULL_TREE, len);
-   arglist = tree_cons (NULL_TREE, src, arglist);
-   arglist = tree_cons (NULL_TREE, dest, arglist);
- 
    /* If __builtin_strncat_chk is used, assume strncat is available.  */
    fn = built_in_decls[BUILT_IN_STRNCAT];
    if (!fn)
!     return 0;
  
!   return build_function_call_expr (fn, arglist);
  }
  
! /* Fold a call to __{,v}sprintf_chk with argument list ARGLIST.  Return 0 if
     a normal call should be emitted rather than expanding the function
     inline.  FCODE is either BUILT_IN_SPRINTF_CHK or BUILT_IN_VSPRINTF_CHK.  */
  
  static tree
! fold_builtin_sprintf_chk (tree arglist, enum built_in_function fcode)
  {
    tree dest, size, len, fn, fmt, flag;
    const char *fmt_str;
  
    /* Verify the required arguments in the original call.  */
!   if (! arglist)
!     return 0;
!   dest = TREE_VALUE (arglist);
!   if (! POINTER_TYPE_P (TREE_TYPE (dest)))
!     return 0;
!   arglist = TREE_CHAIN (arglist);
!   if (! arglist)
!     return 0;
!   flag = TREE_VALUE (arglist);
!   if (TREE_CODE (TREE_TYPE (flag)) != INTEGER_TYPE)
!     return 0;
!   arglist = TREE_CHAIN (arglist);
!   if (! arglist)
!     return 0;
!   size = TREE_VALUE (arglist);
!   if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE)
!     return 0;
!   arglist = TREE_CHAIN (arglist);
!   if (! arglist)
!     return 0;
!   fmt = TREE_VALUE (arglist);
!   if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
!     return 0;
!   arglist = TREE_CHAIN (arglist);
  
    if (! host_integerp (size, 1))
!     return 0;
  
    len = NULL_TREE;
  
    if (!init_target_chars())
!     return 0;
  
    /* Check whether the format is a literal string constant.  */
    fmt_str = c_getstr (fmt);
--- 10482,10536 ----
  	  /* If LEN >= strlen (SRC), optimize into __strcat_chk.  */
  	  fn = built_in_decls[BUILT_IN_STRCAT_CHK];
  	  if (!fn)
! 	    return NULL_TREE;
  
! 	  return build_call_expr (fn, 3, dest, src, size);
  	}
!       return NULL_TREE;
      }
  
    /* If __builtin_strncat_chk is used, assume strncat is available.  */
    fn = built_in_decls[BUILT_IN_STRNCAT];
    if (!fn)
!     return NULL_TREE;
  
!   return build_call_expr (fn, 3, dest, src, len);
  }
  
! /* Fold a call EXP to __{,v}sprintf_chk.  Return NULL_TREE if
     a normal call should be emitted rather than expanding the function
     inline.  FCODE is either BUILT_IN_SPRINTF_CHK or BUILT_IN_VSPRINTF_CHK.  */
  
  static tree
! fold_builtin_sprintf_chk (tree exp, enum built_in_function fcode)
  {
    tree dest, size, len, fn, fmt, flag;
    const char *fmt_str;
+   int nargs = call_expr_nargs (exp);
  
    /* Verify the required arguments in the original call.  */
!   if (nargs < 4)
!     return NULL_TREE;
!   dest = CALL_EXPR_ARG0 (exp);
!   if (!validate_arg (dest, POINTER_TYPE))
!     return NULL_TREE;
!   flag = CALL_EXPR_ARG1 (exp);
!   if (!validate_arg (flag, INTEGER_TYPE))
!     return NULL_TREE;
!   size = CALL_EXPR_ARG2 (exp);
!   if (!validate_arg (size, INTEGER_TYPE))
!     return NULL_TREE;
!   fmt = call_expr_arg (exp, 3);
!   if (!validate_arg (fmt, POINTER_TYPE))
!     return NULL_TREE;
  
    if (! host_integerp (size, 1))
!     return NULL_TREE;
  
    len = NULL_TREE;
  
    if (!init_target_chars())
!     return NULL_TREE;
  
    /* Check whether the format is a literal string constant.  */
    fmt_str = c_getstr (fmt);
*************** fold_builtin_sprintf_chk (tree arglist, 
*** 10405,10423 ****
        /* If the format doesn't contain % args or %%, we know the size.  */
        if (strchr (fmt_str, target_percent) == 0)
  	{
! 	  if (fcode != BUILT_IN_SPRINTF_CHK || arglist == NULL_TREE)
  	    len = build_int_cstu (size_type_node, strlen (fmt_str));
  	}
        /* If the format is "%s" and first ... argument is a string literal,
  	 we know the size too.  */
!       else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, target_percent_s) == 0)
  	{
  	  tree arg;
  
! 	  if (arglist && !TREE_CHAIN (arglist))
  	    {
! 	      arg = TREE_VALUE (arglist);
! 	      if (POINTER_TYPE_P (TREE_TYPE (arg)))
  		{
  		  len = c_strlen (arg, 1);
  		  if (! len || ! host_integerp (len, 1))
--- 10539,10558 ----
        /* If the format doesn't contain % args or %%, we know the size.  */
        if (strchr (fmt_str, target_percent) == 0)
  	{
! 	  if (fcode != BUILT_IN_SPRINTF_CHK || nargs == 4)
  	    len = build_int_cstu (size_type_node, strlen (fmt_str));
  	}
        /* If the format is "%s" and first ... argument is a string literal,
  	 we know the size too.  */
!       else if (fcode == BUILT_IN_SPRINTF_CHK
! 	       && strcmp (fmt_str, target_percent_s) == 0)
  	{
  	  tree arg;
  
! 	  if (nargs == 5)
  	    {
! 	      arg = call_expr_arg (exp, 4);
! 	      if (validate_arg (arg, POINTER_TYPE))
  		{
  		  len = c_strlen (arg, 1);
  		  if (! len || ! host_integerp (len, 1))
*************** fold_builtin_sprintf_chk (tree arglist, 
*** 10430,10436 ****
    if (! integer_all_onesp (size))
      {
        if (! len || ! tree_int_cst_lt (len, size))
! 	return 0;
      }
  
    /* Only convert __{,v}sprintf_chk to {,v}sprintf if flag is 0
--- 10565,10571 ----
    if (! integer_all_onesp (size))
      {
        if (! len || ! tree_int_cst_lt (len, size))
! 	return NULL_TREE;
      }
  
    /* Only convert __{,v}sprintf_chk to {,v}sprintf if flag is 0
*************** fold_builtin_sprintf_chk (tree arglist, 
*** 10438,10507 ****
    if (! integer_zerop (flag))
      {
        if (fmt_str == NULL)
! 	return 0;
!       if (strchr (fmt_str, target_percent) != NULL && strcmp (fmt_str, target_percent_s))
! 	return 0;
      }
  
-   arglist = tree_cons (NULL_TREE, fmt, arglist);
-   arglist = tree_cons (NULL_TREE, dest, arglist);
- 
    /* If __builtin_{,v}sprintf_chk is used, assume {,v}sprintf is available.  */
    fn = built_in_decls[fcode == BUILT_IN_VSPRINTF_CHK
  		      ? BUILT_IN_VSPRINTF : BUILT_IN_SPRINTF];
    if (!fn)
!     return 0;
  
!   return build_function_call_expr (fn, arglist);
  }
  
! /* Fold a call to {,v}snprintf with argument list ARGLIST.  Return 0 if
     a normal call should be emitted rather than expanding the function
     inline.  FCODE is either BUILT_IN_SNPRINTF_CHK or
     BUILT_IN_VSNPRINTF_CHK.  If MAXLEN is not NULL, it is maximum length
     passed as second argument.  */
  
  tree
! fold_builtin_snprintf_chk (tree arglist, tree maxlen,
  			   enum built_in_function fcode)
  {
    tree dest, size, len, fn, fmt, flag;
    const char *fmt_str;
  
    /* Verify the required arguments in the original call.  */
!   if (! arglist)
!     return 0;
!   dest = TREE_VALUE (arglist);
!   if (! POINTER_TYPE_P (TREE_TYPE (dest)))
!     return 0;
!   arglist = TREE_CHAIN (arglist);
!   if (! arglist)
!     return 0;
!   len = TREE_VALUE (arglist);
!   if (TREE_CODE (TREE_TYPE (len)) != INTEGER_TYPE)
!     return 0;
!   arglist = TREE_CHAIN (arglist);
!   if (! arglist)
!     return 0;
!   flag = TREE_VALUE (arglist);
!   if (TREE_CODE (TREE_TYPE (len)) != INTEGER_TYPE)
!     return 0;
!   arglist = TREE_CHAIN (arglist);
!   if (! arglist)
!     return 0;
!   size = TREE_VALUE (arglist);
!   if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE)
!     return 0;
!   arglist = TREE_CHAIN (arglist);
!   if (! arglist)
!     return 0;
!   fmt = TREE_VALUE (arglist);
!   if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
!     return 0;
!   arglist = TREE_CHAIN (arglist);
  
    if (! host_integerp (size, 1))
!     return 0;
  
    if (! integer_all_onesp (size))
      {
--- 10573,10627 ----
    if (! integer_zerop (flag))
      {
        if (fmt_str == NULL)
! 	return NULL_TREE;
!       if (strchr (fmt_str, target_percent) != NULL
! 	  && strcmp (fmt_str, target_percent_s))
! 	return NULL_TREE;
      }
  
    /* If __builtin_{,v}sprintf_chk is used, assume {,v}sprintf is available.  */
    fn = built_in_decls[fcode == BUILT_IN_VSPRINTF_CHK
  		      ? BUILT_IN_VSPRINTF : BUILT_IN_SPRINTF];
    if (!fn)
!     return NULL_TREE;
  
!   return rewrite_call_expr (exp, 4, fn, 2, dest, fmt);
  }
  
! /* Fold a call EXP to {,v}snprintf.  Return NULL_TREE if
     a normal call should be emitted rather than expanding the function
     inline.  FCODE is either BUILT_IN_SNPRINTF_CHK or
     BUILT_IN_VSNPRINTF_CHK.  If MAXLEN is not NULL, it is maximum length
     passed as second argument.  */
  
  tree
! fold_builtin_snprintf_chk (tree exp, tree maxlen,
  			   enum built_in_function fcode)
  {
    tree dest, size, len, fn, fmt, flag;
    const char *fmt_str;
  
    /* Verify the required arguments in the original call.  */
!   if (call_expr_nargs (exp) < 5)
!     return NULL_TREE;
!   dest = call_expr_arg (exp, 0);
!   if (!validate_arg (dest, POINTER_TYPE))
!     return NULL_TREE;
!   len = call_expr_arg (exp, 1);
!   if (!validate_arg (len, INTEGER_TYPE))
!     return NULL_TREE;
!   flag = call_expr_arg (exp, 2);
!   if (!validate_arg (flag, INTEGER_TYPE))
!     return NULL_TREE;
!   size = call_expr_arg (exp, 3);
!   if (!validate_arg (size, INTEGER_TYPE))
!     return NULL_TREE;
!   fmt = call_expr_arg (exp, 4);
!   if (!validate_arg (fmt, POINTER_TYPE))
!     return NULL_TREE;
  
    if (! host_integerp (size, 1))
!     return NULL_TREE;
  
    if (! integer_all_onesp (size))
      {
*************** fold_builtin_snprintf_chk (tree arglist,
*** 10511,10527 ****
  	     For MAXLEN only allow optimizing into non-_ocs function
  	     if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
  	  if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
! 	    return 0;
  	}
        else
  	maxlen = len;
  
        if (tree_int_cst_lt (size, maxlen))
! 	return 0;
      }
  
    if (!init_target_chars())
!     return 0;
  
    /* Only convert __{,v}snprintf_chk to {,v}snprintf if flag is 0
       or if format doesn't contain % chars or is "%s".  */
--- 10631,10647 ----
  	     For MAXLEN only allow optimizing into non-_ocs function
  	     if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
  	  if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
! 	    return NULL_TREE;
  	}
        else
  	maxlen = len;
  
        if (tree_int_cst_lt (size, maxlen))
! 	return NULL_TREE;
      }
  
    if (!init_target_chars())
!     return NULL_TREE;
  
    /* Only convert __{,v}snprintf_chk to {,v}snprintf if flag is 0
       or if format doesn't contain % chars or is "%s".  */
*************** fold_builtin_snprintf_chk (tree arglist,
*** 10529,10590 ****
      {
        fmt_str = c_getstr (fmt);
        if (fmt_str == NULL)
! 	return 0;
!       if (strchr (fmt_str, target_percent) != NULL && strcmp (fmt_str, target_percent_s))
! 	return 0;
      }
  
-   arglist = tree_cons (NULL_TREE, fmt, arglist);
-   arglist = tree_cons (NULL_TREE, len, arglist);
-   arglist = tree_cons (NULL_TREE, dest, arglist);
- 
    /* If __builtin_{,v}snprintf_chk is used, assume {,v}snprintf is
       available.  */
    fn = built_in_decls[fcode == BUILT_IN_VSNPRINTF_CHK
  		      ? BUILT_IN_VSNPRINTF : BUILT_IN_SNPRINTF];
    if (!fn)
!     return 0;
  
!   return build_function_call_expr (fn, arglist);
  }
  
  /* Fold a call to the {,v}printf{,_unlocked} and __{,v}printf_chk builtins.
  
!    Return 0 if no simplification was possible, otherwise return the
     simplified form of the call as a tree.  FCODE is the BUILT_IN_*
     code of the function to be simplified.  */
  
  static tree
! fold_builtin_printf (tree fndecl, tree arglist, bool ignore,
  		     enum built_in_function fcode)
  {
!   tree fmt, fn = NULL_TREE, fn_putchar, fn_puts, arg, call;
    const char *fmt_str = NULL;
  
    /* If the return value is used, don't do the transformation.  */
    if (! ignore)
!     return 0;
  
    /* Verify the required arguments in the original call.  */
!   if (fcode == BUILT_IN_PRINTF_CHK || fcode == BUILT_IN_VPRINTF_CHK)
!     {
!       tree flag;
! 
!       if (! arglist)
! 	return 0;
!       flag = TREE_VALUE (arglist);
!       if (TREE_CODE (TREE_TYPE (flag)) != INTEGER_TYPE
! 	  || TREE_SIDE_EFFECTS (flag))
! 	return 0;
!       arglist = TREE_CHAIN (arglist);
!     }
! 
!   if (! arglist)
!     return 0;
!   fmt = TREE_VALUE (arglist);
!   if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
!     return 0;
!   arglist = TREE_CHAIN (arglist);
  
    /* Check whether the format is a literal string constant.  */
    fmt_str = c_getstr (fmt);
--- 10649,10692 ----
      {
        fmt_str = c_getstr (fmt);
        if (fmt_str == NULL)
! 	return NULL_TREE;
!       if (strchr (fmt_str, target_percent) != NULL
! 	  && strcmp (fmt_str, target_percent_s))
! 	return NULL_TREE;
      }
  
    /* If __builtin_{,v}snprintf_chk is used, assume {,v}snprintf is
       available.  */
    fn = built_in_decls[fcode == BUILT_IN_VSNPRINTF_CHK
  		      ? BUILT_IN_VSNPRINTF : BUILT_IN_SNPRINTF];
    if (!fn)
!     return NULL_TREE;
  
!   return rewrite_call_expr (exp, 5, fn, 3, dest, len, fmt);
  }
  
  /* Fold a call to the {,v}printf{,_unlocked} and __{,v}printf_chk builtins.
+    FMT and ARG are the arguments to the call; we don't fold cases with
+    more than 2 arguments, and ARG may be null if this is a 1-argument case.
  
!    Return NULL_TREE if no simplification was possible, otherwise return the
     simplified form of the call as a tree.  FCODE is the BUILT_IN_*
     code of the function to be simplified.  */
  
  static tree
! fold_builtin_printf (tree fndecl, tree fmt, tree arg, bool ignore,
  		     enum built_in_function fcode)
  {
!   tree fn_putchar, fn_puts, newarg, call = NULL_TREE;
    const char *fmt_str = NULL;
  
    /* If the return value is used, don't do the transformation.  */
    if (! ignore)
!     return NULL_TREE;
  
    /* Verify the required arguments in the original call.  */
!   if (!validate_arg (fmt, POINTER_TYPE))
!     return NULL_TREE;
  
    /* Check whether the format is a literal string constant.  */
    fmt_str = c_getstr (fmt);
*************** fold_builtin_printf (tree fndecl, tree a
*** 10605,10636 ****
      }
  
    if (!init_target_chars())
!     return 0;
  
!   if (strcmp (fmt_str, target_percent_s) == 0 || strchr (fmt_str, target_percent) == NULL)
      {
        const char *str;
  
        if (strcmp (fmt_str, target_percent_s) == 0)
  	{
  	  if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK)
! 	    return 0;
  
! 	  if (! arglist
! 	      || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
! 	      || TREE_CHAIN (arglist))
! 	    return 0;
  
! 	  str = c_getstr (TREE_VALUE (arglist));
  	  if (str == NULL)
! 	    return 0;
  	}
        else
  	{
  	  /* The format specifier doesn't contain any '%' characters.  */
  	  if (fcode != BUILT_IN_VPRINTF && fcode != BUILT_IN_VPRINTF_CHK
! 	      && arglist)
! 	    return 0;
  	  str = fmt_str;
  	}
  
--- 10707,10737 ----
      }
  
    if (!init_target_chars())
!     return NULL_TREE;
  
!   if (strcmp (fmt_str, target_percent_s) == 0
!       || strchr (fmt_str, target_percent) == NULL)
      {
        const char *str;
  
        if (strcmp (fmt_str, target_percent_s) == 0)
  	{
  	  if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK)
! 	    return NULL_TREE;
  
! 	  if (!arg || !validate_arg (arg, POINTER_TYPE))
! 	    return NULL_TREE;
  
! 	  str = c_getstr (arg);
  	  if (str == NULL)
! 	    return NULL_TREE;
  	}
        else
  	{
  	  /* The format specifier doesn't contain any '%' characters.  */
  	  if (fcode != BUILT_IN_VPRINTF && fcode != BUILT_IN_VPRINTF_CHK
! 	      && arg)
! 	    return NULL_TREE;
  	  str = fmt_str;
  	}
  
*************** fold_builtin_printf (tree fndecl, tree a
*** 10644,10652 ****
  	  /* Given printf("c"), (where c is any one character,)
  	     convert "c"[0] to an int and pass that to the replacement
  	     function.  */
! 	  arg = build_int_cst (NULL_TREE, str[0]);
! 	  arglist = build_tree_list (NULL_TREE, arg);
! 	  fn = fn_putchar;
  	}
        else
  	{
--- 10745,10753 ----
  	  /* Given printf("c"), (where c is any one character,)
  	     convert "c"[0] to an int and pass that to the replacement
  	     function.  */
! 	  newarg = build_int_cst (NULL_TREE, str[0]);
! 	  if (fn_putchar)
! 	    call = build_call_expr (fn_putchar, 1, newarg);
  	}
        else
  	{
*************** fold_builtin_printf (tree fndecl, tree a
*** 10660,10751 ****
  	      memcpy (newstr, str, len - 1);
  	      newstr[len - 1] = 0;
  
! 	      arg = build_string_literal (len, newstr);
! 	      arglist = build_tree_list (NULL_TREE, arg);
! 	      fn = fn_puts;
  	    }
  	  else
  	    /* We'd like to arrange to call fputs(string,stdout) here,
  	       but we need stdout and don't have a way to get it yet.  */
! 	    return 0;
  	}
      }
  
    /* The other optimizations can be done only on the non-va_list variants.  */
    else if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK)
!     return 0;
  
    /* If the format specifier was "%s\n", call __builtin_puts(arg).  */
    else if (strcmp (fmt_str, target_percent_s_newline) == 0)
      {
!       if (! arglist
! 	  || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
! 	  || TREE_CHAIN (arglist))
! 	return 0;
!       fn = fn_puts;
      }
  
    /* If the format specifier was "%c", call __builtin_putchar(arg).  */
    else if (strcmp (fmt_str, target_percent_c) == 0)
      {
!       if (! arglist
! 	  || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
! 	  || TREE_CHAIN (arglist))
! 	return 0;
!       fn = fn_putchar;
      }
  
!   if (!fn)
!     return 0;
  
-   call = build_function_call_expr (fn, arglist);
    return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), call);
  }
  
  /* Fold a call to the {,v}fprintf{,_unlocked} and __{,v}printf_chk builtins.
  
!    Return 0 if no simplification was possible, otherwise return the
     simplified form of the call as a tree.  FCODE is the BUILT_IN_*
     code of the function to be simplified.  */
  
  static tree
! fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore,
  		      enum built_in_function fcode)
  {
!   tree fp, fmt, fn = NULL_TREE, fn_fputc, fn_fputs, arg, call;
    const char *fmt_str = NULL;
  
    /* If the return value is used, don't do the transformation.  */
    if (! ignore)
!     return 0;
  
    /* Verify the required arguments in the original call.  */
!   if (! arglist)
!     return 0;
!   fp = TREE_VALUE (arglist);
!   if (! POINTER_TYPE_P (TREE_TYPE (fp)))
!     return 0;
!   arglist = TREE_CHAIN (arglist);
! 
!   if (fcode == BUILT_IN_FPRINTF_CHK || fcode == BUILT_IN_VFPRINTF_CHK)
!     {
!       tree flag;
! 
!       if (! arglist)
! 	return 0;
!       flag = TREE_VALUE (arglist);
!       if (TREE_CODE (TREE_TYPE (flag)) != INTEGER_TYPE
! 	  || TREE_SIDE_EFFECTS (flag))
! 	return 0;
!       arglist = TREE_CHAIN (arglist);
!     }
! 
!   if (! arglist)
!     return 0;
!   fmt = TREE_VALUE (arglist);
!   if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
!     return 0;
!   arglist = TREE_CHAIN (arglist);
  
    /* Check whether the format is a literal string constant.  */
    fmt_str = c_getstr (fmt);
--- 10761,10829 ----
  	      memcpy (newstr, str, len - 1);
  	      newstr[len - 1] = 0;
  
! 	      newarg = build_string_literal (len, newstr);
! 	      if (fn_puts)
! 		call = build_call_expr (fn_puts, 1, newarg);
  	    }
  	  else
  	    /* We'd like to arrange to call fputs(string,stdout) here,
  	       but we need stdout and don't have a way to get it yet.  */
! 	    return NULL_TREE;
  	}
      }
  
    /* The other optimizations can be done only on the non-va_list variants.  */
    else if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK)
!     return NULL_TREE;
  
    /* If the format specifier was "%s\n", call __builtin_puts(arg).  */
    else if (strcmp (fmt_str, target_percent_s_newline) == 0)
      {
!       if (!arg || !validate_arg (arg, POINTER_TYPE))
! 	return NULL_TREE;
!       if (fn_puts)
! 	call = build_call_expr (fn_puts, 1, arg);
      }
  
    /* If the format specifier was "%c", call __builtin_putchar(arg).  */
    else if (strcmp (fmt_str, target_percent_c) == 0)
      {
!       if (!arg || !validate_arg (arg, INTEGER_TYPE))
! 	return NULL_TREE;
!       if (fn_putchar)
! 	call = build_call_expr (fn_putchar, 1, arg);
      }
  
!   if (!call)
!     return NULL_TREE;
  
    return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), call);
  }
  
  /* Fold a call to the {,v}fprintf{,_unlocked} and __{,v}printf_chk builtins.
+    FP, FMT, and ARG are the arguments to the call.  We don't fold calls with
+    more than 3 arguments, and ARG may be null in the 2-argument case.
  
!    Return NULL_TREE if no simplification was possible, otherwise return the
     simplified form of the call as a tree.  FCODE is the BUILT_IN_*
     code of the function to be simplified.  */
  
  static tree
! fold_builtin_fprintf (tree fndecl, tree fp, tree fmt, tree arg, bool ignore,
  		      enum built_in_function fcode)
  {
!   tree fn_fputc, fn_fputs, call = NULL_TREE;
    const char *fmt_str = NULL;
  
    /* If the return value is used, don't do the transformation.  */
    if (! ignore)
!     return NULL_TREE;
  
    /* Verify the required arguments in the original call.  */
!   if (!validate_arg (fp, POINTER_TYPE))
!     return NULL_TREE;
!   if (!validate_arg (fmt, POINTER_TYPE))
!     return NULL_TREE;
  
    /* Check whether the format is a literal string constant.  */
    fmt_str = c_getstr (fmt);
*************** fold_builtin_fprintf (tree fndecl, tree 
*** 10766,10779 ****
      }
  
    if (!init_target_chars())
!     return 0;
  
    /* If the format doesn't contain % args or %%, use strcpy.  */
    if (strchr (fmt_str, target_percent) == NULL)
      {
        if (fcode != BUILT_IN_VFPRINTF && fcode != BUILT_IN_VFPRINTF_CHK
! 	  && arglist)
! 	return 0;
  
        /* If the format specifier was "", fprintf does nothing.  */
        if (fmt_str[0] == '\0')
--- 10844,10857 ----
      }
  
    if (!init_target_chars())
!     return NULL_TREE;
  
    /* If the format doesn't contain % args or %%, use strcpy.  */
    if (strchr (fmt_str, target_percent) == NULL)
      {
        if (fcode != BUILT_IN_VFPRINTF && fcode != BUILT_IN_VFPRINTF_CHK
! 	  && arg)
! 	return NULL_TREE;
  
        /* If the format specifier was "", fprintf does nothing.  */
        if (fmt_str[0] == '\0')
*************** fold_builtin_fprintf (tree fndecl, tree 
*** 10781,10787 ****
  	  /* If FP has side-effects, just wait until gimplification is
  	     done.  */
  	  if (TREE_SIDE_EFFECTS (fp))
! 	    return 0;
  
  	  return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), 0);
  	}
--- 10859,10865 ----
  	  /* If FP has side-effects, just wait until gimplification is
  	     done.  */
  	  if (TREE_SIDE_EFFECTS (fp))
! 	    return NULL_TREE;
  
  	  return build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), 0);
  	}
*************** fold_builtin_fprintf (tree fndecl, tree 
*** 10789,10833 ****
        /* When "string" doesn't contain %, replace all cases of
  	 fprintf (fp, string) with fputs (string, fp).  The fputs
  	 builtin will take care of special cases like length == 1.  */
!       arglist = build_tree_list (NULL_TREE, fp);
!       arglist = tree_cons (NULL_TREE, fmt, arglist);
!       fn = fn_fputs;
      }
  
    /* The other optimizations can be done only on the non-va_list variants.  */
    else if (fcode == BUILT_IN_VFPRINTF || fcode == BUILT_IN_VFPRINTF_CHK)
!     return 0;
  
    /* If the format specifier was "%s", call __builtin_fputs (arg, fp).  */
    else if (strcmp (fmt_str, target_percent_s) == 0)
      {
!       if (! arglist
! 	  || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
! 	  || TREE_CHAIN (arglist))
! 	return 0;
!       arg = TREE_VALUE (arglist);
!       arglist = build_tree_list (NULL_TREE, fp);
!       arglist = tree_cons (NULL_TREE, arg, arglist);
!       fn = fn_fputs;
      }
  
    /* If the format specifier was "%c", call __builtin_fputc (arg, fp).  */
    else if (strcmp (fmt_str, target_percent_c) == 0)
      {
!       if (! arglist
! 	  || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
! 	  || TREE_CHAIN (arglist))
! 	return 0;
!       arg = TREE_VALUE (arglist);
!       arglist = build_tree_list (NULL_TREE, fp);
!       arglist = tree_cons (NULL_TREE, arg, arglist);
!       fn = fn_fputc;
      }
  
!   if (!fn)
!     return 0;
! 
!   call = build_function_call_expr (fn, arglist);
    return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), call);
  }
  
--- 10867,10900 ----
        /* When "string" doesn't contain %, replace all cases of
  	 fprintf (fp, string) with fputs (string, fp).  The fputs
  	 builtin will take care of special cases like length == 1.  */
!       if (fn_fputs)
! 	call = build_call_expr (fn_fputs, 2, fmt, fp);
      }
  
    /* The other optimizations can be done only on the non-va_list variants.  */
    else if (fcode == BUILT_IN_VFPRINTF || fcode == BUILT_IN_VFPRINTF_CHK)
!     return NULL_TREE;
  
    /* If the format specifier was "%s", call __builtin_fputs (arg, fp).  */
    else if (strcmp (fmt_str, target_percent_s) == 0)
      {
!       if (!arg || !validate_arg (arg, POINTER_TYPE))
! 	return NULL_TREE;
!       if (fn_fputs)
! 	call = build_call_expr (fn_fputs, 2, arg, fp);
      }
  
    /* If the format specifier was "%c", call __builtin_fputc (arg, fp).  */
    else if (strcmp (fmt_str, target_percent_c) == 0)
      {
!       if (!arg || !validate_arg (arg, INTEGER_TYPE))
! 	return NULL_TREE;
!       if (fn_fputc)
! 	call = build_call_expr (fn_fputc, 2, arg, fp);
      }
  
!   if (!call)
!     return NULL_TREE;
    return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), call);
  }
  
Index: gcc/fold-const.c
===================================================================
*** gcc/fold-const.c	(revision 115087)
--- gcc/fold-const.c	(working copy)
*************** fold_ternary (enum tree_code code, tree 
*** 11153,11163 ****
        return NULL_TREE;
  
      case CALL_EXPR:
!       /* Check for a built-in function.  */
!       if (TREE_CODE (op0) == ADDR_EXPR
! 	  && TREE_CODE (TREE_OPERAND (op0, 0)) == FUNCTION_DECL
! 	  && DECL_BUILT_IN (TREE_OPERAND (op0, 0)))
! 	return fold_builtin (TREE_OPERAND (op0, 0), op1, false);
        return NULL_TREE;
  
      case BIT_FIELD_REF:
--- 11153,11159 ----
        return NULL_TREE;
  
      case CALL_EXPR:
!       /* Handled separately for now.  */
        return NULL_TREE;
  
      case BIT_FIELD_REF:
*************** fold (tree expr)
*** 11233,11238 ****
--- 11229,11241 ----
  	  tem = fold_binary (code, type, op0, op1);
  	  return tem ? tem : expr;
  	case 3:
+ 	  /* FIXME:  CALL_EXPRs won't be ternary expressions any more
+ 	     after representation change is implemented.  */
+ 	  if (code == CALL_EXPR)
+ 	    {
+ 	      tem = fold_call_expr (expr, false);
+ 	      return tem ? tem : expr;
+ 	    }
  	  op0 = TREE_OPERAND (t, 0);
  	  op1 = TREE_OPERAND (t, 1);
  	  op2 = TREE_OPERAND (t, 2);
*************** fold_build3_stat (enum tree_code code, t
*** 11587,11596 ****
    md5_finish_ctx (&ctx, checksum_before_op2);
    htab_empty (ht);
  #endif
!   
!   tem = fold_ternary (code, type, op0, op1, op2);
!   if (!tem)
!     tem =  build3_stat (code, type, op0, op1, op2 PASS_MEM_STAT);
        
  #ifdef ENABLE_FOLD_CHECKING
    md5_init_ctx (&ctx);
--- 11590,11606 ----
    md5_finish_ctx (&ctx, checksum_before_op2);
    htab_empty (ht);
  #endif
! 
!   /* FIXME: This is only temporary, since CALL_EXPRs won't be constructed
!      with fold_build3 after representation conversion is complete.  */
!   if (code != CALL_EXPR)
!     {
!       tem = fold_ternary (code, type, op0, op1, op2);
!       if (!tem)
! 	tem =  build3_stat (code, type, op0, op1, op2 PASS_MEM_STAT);
!     }
!   else
!     tem = fold_build_call_expr (type, op0, op1, op2);
        
  #ifdef ENABLE_FOLD_CHECKING
    md5_init_ctx (&ctx);
Index: gcc/tree-ssa-ccp.c
===================================================================
*** gcc/tree-ssa-ccp.c	(revision 115087)
--- gcc/tree-ssa-ccp.c	(working copy)
*************** ccp_fold (tree stmt)
*** 935,941 ****
        if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_USE))
  	{
  	  tree *orig, var;
- 	  tree fndecl, arglist;
  	  size_t i = 0;
  	  ssa_op_iter iter;
  	  use_operand_p var_p;
--- 935,940 ----
*************** ccp_fold (tree stmt)
*** 947,955 ****
  
  	  /* Substitute operands with their values and try to fold.  */
  	  replace_uses_in (stmt, NULL, const_val);
! 	  fndecl = get_callee_fndecl (rhs);
! 	  arglist = TREE_OPERAND (rhs, 1);
! 	  retval = fold_builtin (fndecl, arglist, false);
  
  	  /* Restore operands to their original form.  */
  	  i = 0;
--- 946,952 ----
  
  	  /* Substitute operands with their values and try to fold.  */
  	  replace_uses_in (stmt, NULL, const_val);
! 	  retval = fold_call_expr (rhs, false);
  
  	  /* Restore operands to their original form.  */
  	  i = 0;
*************** static tree
*** 2169,2186 ****
  ccp_fold_builtin (tree stmt, tree fn)
  {
    tree result, val[3];
!   tree callee, arglist, a;
    int arg_mask, i, type;
    bitmap visited;
    bool ignore;
  
    ignore = TREE_CODE (stmt) != MODIFY_EXPR;
  
    /* First try the generic builtin folder.  If that succeeds, return the
       result directly.  */
!   callee = get_callee_fndecl (fn);
!   arglist = TREE_OPERAND (fn, 1);
!   result = fold_builtin (callee, arglist, ignore);
    if (result)
      {
        if (ignore)
--- 2166,2183 ----
  ccp_fold_builtin (tree stmt, tree fn)
  {
    tree result, val[3];
!   tree callee, a;
    int arg_mask, i, type;
    bitmap visited;
    bool ignore;
+   call_expr_arg_iterator iter;
+   int nargs;
  
    ignore = TREE_CODE (stmt) != MODIFY_EXPR;
  
    /* First try the generic builtin folder.  If that succeeds, return the
       result directly.  */
!   result = fold_call_expr (fn, ignore);
    if (result)
      {
        if (ignore)
*************** ccp_fold_builtin (tree stmt, tree fn)
*** 2189,2200 ****
      }
  
    /* Ignore MD builtins.  */
    if (DECL_BUILT_IN_CLASS (callee) == BUILT_IN_MD)
      return NULL_TREE;
  
    /* If the builtin could not be folded, and it has no argument list,
       we're done.  */
!   if (!arglist)
      return NULL_TREE;
  
    /* Limit the work only for builtins we know how to simplify.  */
--- 2186,2199 ----
      }
  
    /* Ignore MD builtins.  */
+   callee = get_callee_fndecl (fn);
    if (DECL_BUILT_IN_CLASS (callee) == BUILT_IN_MD)
      return NULL_TREE;
  
    /* If the builtin could not be folded, and it has no argument list,
       we're done.  */
!   nargs = call_expr_nargs (fn);
!   if (nargs == 0)
      return NULL_TREE;
  
    /* Limit the work only for builtins we know how to simplify.  */
*************** ccp_fold_builtin (tree stmt, tree fn)
*** 2237,2251 ****
    visited = BITMAP_ALLOC (NULL);
  
    memset (val, 0, sizeof (val));
!   for (i = 0, a = arglist;
!        arg_mask;
!        i++, arg_mask >>= 1, a = TREE_CHAIN (a))
!     if (arg_mask & 1)
!       {
! 	bitmap_clear (visited);
! 	if (!get_maxval_strlen (TREE_VALUE (a), &val[i], visited, type))
! 	  val[i] = NULL_TREE;
!       }
  
    BITMAP_FREE (visited);
  
--- 2236,2252 ----
    visited = BITMAP_ALLOC (NULL);
  
    memset (val, 0, sizeof (val));
!   init_call_expr_arg_iterator (fn, &iter);
!   for (i = 0; arg_mask; i++, arg_mask >>= 1)
!     {
!       a = next_call_expr_arg (&iter);
!       if (arg_mask & 1)
! 	{
! 	  bitmap_clear (visited);
! 	  if (!get_maxval_strlen (a, &val[i], visited, type))
! 	    val[i] = NULL_TREE;
! 	}
!     }
  
    BITMAP_FREE (visited);
  
*************** ccp_fold_builtin (tree stmt, tree fn)
*** 2267,2289 ****
        break;
  
      case BUILT_IN_STRCPY:
!       if (val[1] && is_gimple_val (val[1]))
! 	result = fold_builtin_strcpy (callee, arglist, val[1]);
        break;
  
      case BUILT_IN_STRNCPY:
!       if (val[1] && is_gimple_val (val[1]))
! 	result = fold_builtin_strncpy (callee, arglist, val[1]);
        break;
  
      case BUILT_IN_FPUTS:
!       result = fold_builtin_fputs (arglist,
  				   TREE_CODE (stmt) != MODIFY_EXPR, 0,
  				   val[0]);
        break;
  
      case BUILT_IN_FPUTS_UNLOCKED:
!       result = fold_builtin_fputs (arglist,
  				   TREE_CODE (stmt) != MODIFY_EXPR, 1,
  				   val[0]);
        break;
--- 2268,2299 ----
        break;
  
      case BUILT_IN_STRCPY:
!       if (val[1] && is_gimple_val (val[1]) && nargs == 2)
! 	result = fold_builtin_strcpy (callee,
! 				      CALL_EXPR_ARG0 (fn),
! 				      CALL_EXPR_ARG1 (fn),
! 				      val[1]);
        break;
  
      case BUILT_IN_STRNCPY:
!       if (val[1] && is_gimple_val (val[1]) && nargs == 3)
! 	result = fold_builtin_strncpy (callee,
! 				       CALL_EXPR_ARG0 (fn),
! 				       CALL_EXPR_ARG1 (fn),
! 				       CALL_EXPR_ARG2 (fn),
! 				       val[1]);
        break;
  
      case BUILT_IN_FPUTS:
!       result = fold_builtin_fputs (CALL_EXPR_ARG0 (fn),
! 				   CALL_EXPR_ARG1 (fn),
  				   TREE_CODE (stmt) != MODIFY_EXPR, 0,
  				   val[0]);
        break;
  
      case BUILT_IN_FPUTS_UNLOCKED:
!       result = fold_builtin_fputs (CALL_EXPR_ARG0 (fn),
! 				   CALL_EXPR_ARG1 (fn),
  				   TREE_CODE (stmt) != MODIFY_EXPR, 1,
  				   val[0]);
        break;
*************** ccp_fold_builtin (tree stmt, tree fn)
*** 2293,2318 ****
      case BUILT_IN_MEMMOVE_CHK:
      case BUILT_IN_MEMSET_CHK:
        if (val[2] && is_gimple_val (val[2]))
! 	result = fold_builtin_memory_chk (callee, arglist, val[2], ignore,
  					  DECL_FUNCTION_CODE (callee));
        break;
  
      case BUILT_IN_STRCPY_CHK:
      case BUILT_IN_STPCPY_CHK:
        if (val[1] && is_gimple_val (val[1]))
! 	result = fold_builtin_stxcpy_chk (callee, arglist, val[1], ignore,
  					  DECL_FUNCTION_CODE (callee));
        break;
  
      case BUILT_IN_STRNCPY_CHK:
        if (val[2] && is_gimple_val (val[2]))
! 	result = fold_builtin_strncpy_chk (arglist, val[2]);
        break;
  
      case BUILT_IN_SNPRINTF_CHK:
      case BUILT_IN_VSNPRINTF_CHK:
        if (val[1] && is_gimple_val (val[1]))
! 	result = fold_builtin_snprintf_chk (arglist, val[1],
  					    DECL_FUNCTION_CODE (callee));
        break;
  
--- 2303,2341 ----
      case BUILT_IN_MEMMOVE_CHK:
      case BUILT_IN_MEMSET_CHK:
        if (val[2] && is_gimple_val (val[2]))
! 	result = fold_builtin_memory_chk (callee,
! 					  CALL_EXPR_ARG0 (fn),
! 					  CALL_EXPR_ARG1 (fn),
! 					  CALL_EXPR_ARG2 (fn),
! 					  call_expr_arg (fn, 3),
! 					  val[2], ignore,
  					  DECL_FUNCTION_CODE (callee));
        break;
  
      case BUILT_IN_STRCPY_CHK:
      case BUILT_IN_STPCPY_CHK:
        if (val[1] && is_gimple_val (val[1]))
! 	result = fold_builtin_stxcpy_chk (callee,
! 					  CALL_EXPR_ARG0 (fn),
! 					  CALL_EXPR_ARG1 (fn),
! 					  CALL_EXPR_ARG2 (fn),
! 					  val[1], ignore,
  					  DECL_FUNCTION_CODE (callee));
        break;
  
      case BUILT_IN_STRNCPY_CHK:
        if (val[2] && is_gimple_val (val[2]))
! 	result = fold_builtin_strncpy_chk (CALL_EXPR_ARG0 (fn),
! 					   CALL_EXPR_ARG1 (fn),
! 					   CALL_EXPR_ARG2 (fn),
! 					   call_expr_arg (fn, 3),
! 					   val[2]);
        break;
  
      case BUILT_IN_SNPRINTF_CHK:
      case BUILT_IN_VSNPRINTF_CHK:
        if (val[1] && is_gimple_val (val[1]))
! 	result = fold_builtin_snprintf_chk (fn, val[1],
  					    DECL_FUNCTION_CODE (callee));
        break;
  
Index: gcc/gimplify.c
===================================================================
*** gcc/gimplify.c	(revision 115087)
--- gcc/gimplify.c	(working copy)
*************** gimplify_call_expr (tree *expr_p, tree *
*** 1987,1994 ****
    decl = get_callee_fndecl (*expr_p);
    if (decl && DECL_BUILT_IN (decl))
      {
!       tree arglist = TREE_OPERAND (*expr_p, 1);
!       tree new = fold_builtin (decl, arglist, !want_value);
  
        if (new && new != *expr_p)
  	{
--- 1987,1993 ----
    decl = get_callee_fndecl (*expr_p);
    if (decl && DECL_BUILT_IN (decl))
      {
!       tree new = fold_call_expr (*expr_p, !want_value);
  
        if (new && new != *expr_p)
  	{
*************** gimplify_call_expr (tree *expr_p, tree *
*** 2002,2022 ****
        if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
  	  && DECL_FUNCTION_CODE (decl) == BUILT_IN_VA_START)
          {
! 	  if (!arglist || !TREE_CHAIN (arglist))
  	    {
  	      error ("too few arguments to function %<va_start%>");
  	      *expr_p = build_empty_stmt ();
  	      return GS_OK;
  	    }
  	  
! 	  if (fold_builtin_next_arg (TREE_CHAIN (arglist)))
  	    {
  	      *expr_p = build_empty_stmt ();
  	      return GS_OK;
  	    }
  	  /* Avoid gimplifying the second argument to va_start, which needs
  	     to be the plain PARM_DECL.  */
! 	  return gimplify_arg (&TREE_VALUE (TREE_OPERAND (*expr_p, 1)), pre_p);
  	}
      }
  
--- 2001,2021 ----
        if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
  	  && DECL_FUNCTION_CODE (decl) == BUILT_IN_VA_START)
          {
! 	  if (call_expr_nargs (*expr_p) < 2)
  	    {
  	      error ("too few arguments to function %<va_start%>");
  	      *expr_p = build_empty_stmt ();
  	      return GS_OK;
  	    }
  	  
! 	  if (fold_builtin_next_arg (*expr_p, true))
  	    {
  	      *expr_p = build_empty_stmt ();
  	      return GS_OK;
  	    }
  	  /* Avoid gimplifying the second argument to va_start, which needs
  	     to be the plain PARM_DECL.  */
! 	  return gimplify_arg (&CALL_EXPR_ARG0 (*expr_p), pre_p);
  	}
      }
  
*************** gimplify_call_expr (tree *expr_p, tree *
*** 2044,2063 ****
    /* Try this again in case gimplification exposed something.  */
    if (ret != GS_ERROR)
      {
!       decl = get_callee_fndecl (*expr_p);
!       if (decl && DECL_BUILT_IN (decl))
! 	{
! 	  tree arglist = TREE_OPERAND (*expr_p, 1);
! 	  tree new = fold_builtin (decl, arglist, !want_value);
  
! 	  if (new && new != *expr_p)
! 	    {
! 	      /* There was a transformation of this call which computes the
! 		 same value, but in a more efficient way.  Return and try
! 		 again.  */
! 	      *expr_p = new;
! 	      return GS_OK;
! 	    }
  	}
      }
  
--- 2043,2057 ----
    /* Try this again in case gimplification exposed something.  */
    if (ret != GS_ERROR)
      {
!       tree new = fold_call_expr (*expr_p, !want_value);
  
!       if (new && new != *expr_p)
! 	{
! 	  /* There was a transformation of this call which computes the
! 	     same value, but in a more efficient way.  Return and try
! 	     again.  */
! 	  *expr_p = new;
! 	  return GS_OK;
  	}
      }
  
Index: gcc/except.c
===================================================================
*** gcc/except.c	(revision 115087)
--- gcc/except.c	(working copy)
*************** expand_builtin_unwind_init (void)
*** 2888,2896 ****
  }
  
  rtx
! expand_builtin_eh_return_data_regno (tree arglist)
  {
!   tree which = TREE_VALUE (arglist);
    unsigned HOST_WIDE_INT iwhich;
  
    if (TREE_CODE (which) != INTEGER_CST)
--- 2888,2896 ----
  }
  
  rtx
! expand_builtin_eh_return_data_regno (tree exp)
  {
!   tree which = CALL_EXPR_ARG0 (exp);
    unsigned HOST_WIDE_INT iwhich;
  
    if (TREE_CODE (which) != INTEGER_CST)
Index: gcc/tree-object-size.c
===================================================================
*** gcc/tree-object-size.c	(revision 115087)
--- gcc/tree-object-size.c	(working copy)
*************** compute_object_sizes (void)
*** 1005,1011 ****
  	    continue;
  
  	  init_object_sizes ();
! 	  result = fold_builtin (callee, TREE_OPERAND (call, 1), false);
  	  if (!result)
  	    {
  	      tree arglist = TREE_OPERAND (call, 1);
--- 1005,1011 ----
  	    continue;
  
  	  init_object_sizes ();
! 	  result = fold_call_expr (call, false);
  	  if (!result)
  	    {
  	      tree arglist = TREE_OPERAND (call, 1);

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