OSDN Git Service

2001-05-03 David O'Brien <obrien@FreeBSD.org>
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index 1d234aa..eecf1c5 100644 (file)
@@ -1,6 +1,6 @@
 /* Expand builtin functions.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -30,14 +30,11 @@ Boston, MA 02111-1307, USA.  */
 #include "hard-reg-set.h"
 #include "except.h"
 #include "function.h"
-#include "insn-flags.h"
-#include "insn-codes.h"
 #include "insn-config.h"
 #include "expr.h"
 #include "recog.h"
 #include "output.h"
 #include "typeclass.h"
-#include "defaults.h"
 #include "toplev.h"
 #include "tm_p.h"
 
@@ -60,7 +57,7 @@ Boston, MA 02111-1307, USA.  */
 const char *const built_in_class_names[4]
   = {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
 
-#define DEF_BUILTIN(x) STRINGIFY(x),
+#define DEF_BUILTIN(x) STRINGX(x),
 const char *const built_in_names[(int) END_BUILTINS] =
 {
 #include "builtins.def"
@@ -146,6 +143,8 @@ static rtx expand_builtin_fputs             PARAMS ((tree, int));
 static tree stabilize_va_list          PARAMS ((tree, int));
 static rtx expand_builtin_expect       PARAMS ((tree, rtx));
 static tree fold_builtin_constant_p    PARAMS ((tree));
+static tree build_function_call_expr   PARAMS ((tree, tree));
+static int validate_arglist            PARAMS ((tree, ...));
 
 /* Return the alignment in bits of EXP, a pointer valued expression.
    But don't return more than MAX_ALIGN no matter what.
@@ -430,8 +429,9 @@ expand_builtin_return_addr (fndecl_code, count, tem)
       tem = DYNAMIC_CHAIN_ADDRESS (tem);
 #endif
       tem = memory_address (Pmode, tem);
-      tem = copy_to_reg (gen_rtx_MEM (Pmode, tem));
+      tem = gen_rtx_MEM (Pmode, tem);
       MEM_ALIAS_SET (tem) = get_frame_alias_set ();
+      tem = copy_to_reg (tem);
     }
 
   /* For __builtin_frame_address, return what we've got.  */
@@ -579,6 +579,13 @@ expand_builtin_setjmp_receiver (receiver_label)
     else
 #endif
       { /* Nothing */ }
+
+  /* @@@ This is a kludge.  Not all machine descriptions define a blockage
+     insn, but we must not allow the code we just generated to be reordered
+     by scheduling.  Specifically, the update of the frame pointer must
+     happen immediately, not later.  So emit an ASM_INPUT to act as blockage
+     insn.  */
+  emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
 }
 
 /* __builtin_setjmp is passed a pointer to an array of five words (not
@@ -598,8 +605,7 @@ expand_builtin_setjmp (arglist, target)
 {
   rtx buf_addr, next_lab, cont_lab;
 
-  if (arglist == 0
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
+  if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
     return NULL_RTX;
 
   if (target == 0 || GET_CODE (target) != REG
@@ -1369,9 +1375,7 @@ expand_builtin_mathfn (exp, target, subtarget)
   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
   tree arglist = TREE_OPERAND (exp, 1);
 
-  if (arglist == 0
-      /* Arg could be wrong type if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != REAL_TYPE)
+  if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
     return 0;
 
   /* Stabilize and compute the argument.  */
@@ -1424,10 +1428,10 @@ expand_builtin_mathfn (exp, target, subtarget)
       return 0;
     }
 
-  /* Check the results by default.  But if flag_fast_math is turned on,
-     then assume sqrt will always be called with valid arguments.  */
+  /* If errno must be maintained and if we are not allowing unsafe
+     math optimizations, check the result.  */
 
-  if (flag_errno_math && ! flag_fast_math)
+  if (flag_errno_math && ! flag_unsafe_math_optimizations)
     {
       rtx lab1;
 
@@ -1485,9 +1489,7 @@ expand_builtin_strlen (exp, target)
   tree arglist = TREE_OPERAND (exp, 1);
   enum machine_mode value_mode = TYPE_MODE (TREE_TYPE (exp));
 
-  if (arglist == 0
-      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
+  if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
     return 0;
   else
     {
@@ -1589,16 +1591,13 @@ expand_builtin_strstr (arglist, target, mode)
      rtx target;
      enum machine_mode mode;
 {
-  if (arglist == 0
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
+  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)
       || current_function_check_memory_usage)
     return 0;
   else
     {
       tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
-      tree call_expr, fn;
+      tree fn;
       const char *p1, *p2;
 
       p2 = c_getstr (s2);
@@ -1634,12 +1633,8 @@ expand_builtin_strstr (arglist, target, mode)
       arglist =
        build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
       arglist = tree_cons (NULL_TREE, s1, arglist);
-      call_expr = build1 (ADDR_EXPR,
-                         build_pointer_type (TREE_TYPE (fn)), fn);
-      call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
-                        call_expr, arglist, NULL_TREE);
-      TREE_SIDE_EFFECTS (call_expr) = 1;
-      return expand_expr (call_expr, target, mode, EXPAND_NORMAL);
+      return expand_expr (build_function_call_expr (fn, arglist),
+                         target, mode, EXPAND_NORMAL);
     }
 }
 
@@ -1653,10 +1648,7 @@ expand_builtin_strchr (arglist, target, mode)
      rtx target;
      enum machine_mode mode;
 {
-  if (arglist == 0
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != INTEGER_TYPE
+  if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)
       || current_function_check_memory_usage)
     return 0;
   else
@@ -1703,16 +1695,13 @@ expand_builtin_strrchr (arglist, target, mode)
      rtx target;
      enum machine_mode mode;
 {
-  if (arglist == 0
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != INTEGER_TYPE
+  if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)
       || current_function_check_memory_usage)
     return 0;
   else
     {
       tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
-      tree call_expr, fn;
+      tree fn;
       const char *p1;
 
       if (TREE_CODE (s2) != INTEGER_CST)
@@ -1746,12 +1735,8 @@ expand_builtin_strrchr (arglist, target, mode)
        return 0;
 
       /* Transform strrchr(s1, '\0') to strchr(s1, '\0').  */
-      call_expr = build1 (ADDR_EXPR,
-                         build_pointer_type (TREE_TYPE (fn)), fn);
-      call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
-                        call_expr, arglist, NULL_TREE);
-      TREE_SIDE_EFFECTS (call_expr) = 1;
-      return expand_expr (call_expr, target, mode, EXPAND_NORMAL);
+      return expand_expr (build_function_call_expr (fn, arglist),
+                         target, mode, EXPAND_NORMAL);
     }
 }
 
@@ -1765,16 +1750,13 @@ expand_builtin_strpbrk (arglist, target, mode)
      rtx target;
      enum machine_mode mode;
 {
-  if (arglist == 0
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
+  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)
       || current_function_check_memory_usage)
     return 0;
   else
     {
       tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
-      tree call_expr, fn;
+      tree fn;
       const char *p1, *p2;
 
       p2 = c_getstr (s2);
@@ -1816,12 +1798,8 @@ expand_builtin_strpbrk (arglist, target, mode)
       arglist =
        build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
       arglist = tree_cons (NULL_TREE, s1, arglist);
-      call_expr = build1 (ADDR_EXPR,
-                         build_pointer_type (TREE_TYPE (fn)), fn);
-      call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
-                        call_expr, arglist, NULL_TREE);
-      TREE_SIDE_EFFECTS (call_expr) = 1;
-      return expand_expr (call_expr, target, mode, EXPAND_NORMAL);
+      return expand_expr (build_function_call_expr (fn, arglist),
+                         target, mode, EXPAND_NORMAL);
     }
 }
 
@@ -1848,16 +1826,8 @@ static rtx
 expand_builtin_memcpy (arglist)
      tree arglist;
 {
-  if (arglist == 0
-      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
-         != POINTER_TYPE)
-      || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE
-                               (TREE_CHAIN (TREE_CHAIN (arglist)))))
-         != INTEGER_TYPE))
+  if (!validate_arglist (arglist,
+                        POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
   else
     {
@@ -1926,12 +1896,7 @@ expand_builtin_strcpy (exp)
   tree arglist = TREE_OPERAND (exp, 1);
   rtx result;
 
-  if (arglist == 0
-      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
-         != POINTER_TYPE))
+  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
   else
     {
@@ -1978,16 +1943,8 @@ expand_builtin_strncpy (arglist, target, mode)
      rtx target;
      enum machine_mode mode;
 {
-  if (arglist == 0
-      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
-         != POINTER_TYPE)
-      || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE
-                               (TREE_CHAIN (TREE_CHAIN (arglist)))))
-         != INTEGER_TYPE))
+  if (!validate_arglist (arglist,
+                        POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
   else
     {
@@ -2071,17 +2028,8 @@ expand_builtin_memset (exp)
 {
   tree arglist = TREE_OPERAND (exp, 1);
 
-  if (arglist == 0
-      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
-         != INTEGER_TYPE)
-      || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
-      || (INTEGER_TYPE
-         != (TREE_CODE (TREE_TYPE
-                        (TREE_VALUE
-                         (TREE_CHAIN (TREE_CHAIN (arglist))))))))
+  if (!validate_arglist (arglist,
+                        POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
   else
     {
@@ -2153,14 +2101,12 @@ expand_builtin_bzero (exp)
   tree dest, size, newarglist;
   rtx result;
 
-  if (arglist == 0
-      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (dest = TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || (TREE_CODE (TREE_TYPE (size = TREE_VALUE (TREE_CHAIN (arglist))))
-         != INTEGER_TYPE))
+  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).  */
   
@@ -2192,13 +2138,8 @@ expand_builtin_memcmp (exp, arglist, target)
   if (current_function_check_memory_usage)
     return 0;
 
-  if (arglist == 0
-      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
-      || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE)
+  if (!validate_arglist (arglist,
+                     POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
 
   {
@@ -2281,12 +2222,7 @@ expand_builtin_strcmp (exp, target, mode)
   if (current_function_check_memory_usage)
     return 0;
 
-  if (arglist == 0
-      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
-         != POINTER_TYPE))
+  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
 
   arg1 = TREE_VALUE (arglist);
@@ -2390,25 +2326,16 @@ expand_builtin_strncmp (exp, target, mode)
   if (current_function_check_memory_usage)
     return 0;
 
-  if (arglist == 0
-      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
-      || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE)
+  if (!validate_arglist (arglist,
+                        POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
 
   arg1 = TREE_VALUE (arglist);
   arg2 = TREE_VALUE (TREE_CHAIN (arglist));
   arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
 
-  /* We must be passed a constant len parameter.  */
-  if (TREE_CODE (arg3) != INTEGER_CST)
-    return 0;
-  
   /* If the len parameter is zero, return zero.  */
-  if (compare_tree_int (arg3, 0) == 0)
+  if (host_integerp (arg3, 1) && tree_low_cst (arg3, 1) == 0)
   {
     /* Evaluate and ignore arg1 and arg2 in case they have
        side-effects.  */
@@ -2421,17 +2348,18 @@ expand_builtin_strncmp (exp, target, mode)
   p2 = c_getstr (arg2);
 
   /* If all arguments are constant, evaluate at compile-time.  */
-  if (p1 && p2)
+  if (host_integerp (arg3, 1) && p1 && p2)
   {
-    const int r = strncmp (p1, p2, TREE_INT_CST_LOW (arg3));
+    const int r = strncmp (p1, p2, tree_low_cst (arg3, 1));
     return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
   }
 
   /* If len == 1 or (either string parameter is "" and (len >= 1)),
-      return (*(u_char*)arg1 - *(u_char*)arg2).  */
-  if (compare_tree_int (arg3, 1) == 0
-      || (compare_tree_int (arg3, 1) > 0
-         && ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))))
+      return (*(const u_char*)arg1 - *(const u_char*)arg2).  */
+  if (host_integerp (arg3, 1)
+      && (tree_low_cst (arg3, 1) == 1
+         || (tree_low_cst (arg3, 1) > 1
+             && ((p1 && *p1 == '\0') || (p2 && *p2 == '\0')))))
     {
       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
       tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
@@ -2448,28 +2376,40 @@ expand_builtin_strncmp (exp, target, mode)
     }
 
 #ifdef HAVE_cmpstrsi
-  /* If the length parameter is constant (checked above) and either
-     string parameter is constant, call expand_builtin_memcmp() using
-     a length parameter equal to the lesser of the given length and
-     the strlen+1 of the constant string.  */
-  if (HAVE_cmpstrsi && (p1 || p2))
-    {
-      /* Exactly one of the strings is constant at this point, because
-        if both were then we'd have expanded this at compile-time.  */
-      tree string_len = p1 ? c_strlen (arg1) : c_strlen (arg2);
-
-      string_len = size_binop (PLUS_EXPR, string_len, ssize_int (1));
-      
-      if (tree_int_cst_lt (string_len, arg3))
-        {
-         /* The strlen+1 is strictly shorter, use it.  */
-         tree newarglist = build_tree_list (NULL_TREE, string_len);
-         newarglist = tree_cons (NULL_TREE, arg2, newarglist);
-         newarglist = tree_cons (NULL_TREE, arg1, newarglist);
-         return expand_builtin_memcmp (exp, newarglist, target);
-       }
-      else
-       return expand_builtin_memcmp (exp, arglist, target);
+  /* If c_strlen can determine an expression for one of the string
+     lengths, and it doesn't have side effects, then call
+     expand_builtin_memcmp() using length MIN(strlen(string)+1, arg3).  */
+  if (HAVE_cmpstrsi)
+    { 
+      tree newarglist, len = 0;
+
+      /* Perhaps one of the strings is really constant, if so prefer
+         that constant length over the other string's length.  */
+      if (p1)
+       len = c_strlen (arg1);
+      else if (p2)
+       len = c_strlen (arg2);
+
+      /* If we still don't have a len, try either string arg as long
+        as they don't have side effects.  */
+      if (!len && !TREE_SIDE_EFFECTS (arg1))
+       len = c_strlen (arg1);
+      if (!len && !TREE_SIDE_EFFECTS (arg2))
+       len = c_strlen (arg2);
+      /* If we still don't have a length, punt.  */
+      if (!len)
+       return 0;
+       
+      /* Add one to the string length.  */
+      len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
+        
+      /* The actual new length parameter is MIN(len,arg3).  */
+      len = fold (build (MIN_EXPR, TREE_TYPE (len), len, arg3));
+
+      newarglist = build_tree_list (NULL_TREE, len);
+      newarglist = tree_cons (NULL_TREE, arg2, newarglist);
+      newarglist = tree_cons (NULL_TREE, arg1, newarglist);
+      return expand_builtin_memcmp (exp, newarglist, target);
     }
 #endif
   
@@ -2489,12 +2429,7 @@ expand_builtin_strcat (arglist, target, mode)
   if (current_function_check_memory_usage)
     return 0;
 
-  if (arglist == 0
-      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
-         != POINTER_TYPE))
+  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
   else
     {
@@ -2523,16 +2458,8 @@ expand_builtin_strncat (arglist, target, mode)
   if (current_function_check_memory_usage)
     return 0;
 
-  if (arglist == 0
-      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
-         != POINTER_TYPE)
-      || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE
-                               (TREE_CHAIN (TREE_CHAIN (arglist)))))
-         != INTEGER_TYPE))
+  if (!validate_arglist (arglist,
+                        POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
   else
     {
@@ -2558,7 +2485,7 @@ expand_builtin_strncat (arglist, target, mode)
       if (TREE_CODE (len) == INTEGER_CST && p
          && compare_tree_int (len, strlen (p)) >= 0)
         {
-         tree call_expr, newarglist = 
+         tree newarglist =
            tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src)),
            fn = built_in_decls[BUILT_IN_STRCAT];
          
@@ -2567,12 +2494,8 @@ expand_builtin_strncat (arglist, target, mode)
          if (!fn)
            return 0;
 
-         call_expr = build1 (ADDR_EXPR,
-                             build_pointer_type (TREE_TYPE (fn)), fn);
-         call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
-                            call_expr, newarglist, NULL_TREE);
-         TREE_SIDE_EFFECTS (call_expr) = 1;
-         return expand_expr (call_expr, target, mode, EXPAND_NORMAL);
+         return expand_expr (build_function_call_expr (fn, newarglist),
+                             target, mode, EXPAND_NORMAL);
        }
       return 0;
     }
@@ -2591,12 +2514,7 @@ expand_builtin_strspn (arglist, target, mode)
   if (current_function_check_memory_usage)
     return 0;
 
-  if (arglist == 0
-      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
-         != POINTER_TYPE))
+  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
   else
     {
@@ -2636,12 +2554,7 @@ expand_builtin_strcspn (arglist, target, mode)
   if (current_function_check_memory_usage)
     return 0;
 
-  if (arglist == 0
-      /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
-      || TREE_CHAIN (arglist) == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
-         != POINTER_TYPE))
+  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
   else
     {
@@ -2667,7 +2580,7 @@ expand_builtin_strcspn (arglist, target, mode)
       /* If the second argument is "", return __builtin_strlen(s1).  */
       if (p2 && *p2 == '\0')
         {
-         tree call_expr, newarglist = build_tree_list (NULL_TREE, s1),
+         tree newarglist = build_tree_list (NULL_TREE, s1),
            fn = built_in_decls[BUILT_IN_STRLEN];
          
          /* If the replacement _DECL isn't initialized, don't do the
@@ -2675,12 +2588,8 @@ expand_builtin_strcspn (arglist, target, mode)
          if (!fn)
            return 0;
 
-         call_expr = build1 (ADDR_EXPR,
-                             build_pointer_type (TREE_TYPE (fn)), fn);
-         call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
-                            call_expr, newarglist, NULL_TREE);
-         TREE_SIDE_EFFECTS (call_expr) = 1;
-         return expand_expr (call_expr, target, mode, EXPAND_NORMAL);
+         return expand_expr (build_function_call_expr (fn, newarglist),
+                             target, mode, EXPAND_NORMAL);
        }
       return 0;
     }
@@ -2896,8 +2805,13 @@ std_expand_builtin_va_start (stdarg_p, valist, nextarg)
 
   if (! stdarg_p)
     {
+      /* The dummy named parameter is declared as a 'word' sized
+        object, but if a 'word' is smaller than an 'int', it would
+        have been promoted to int when it was added to the arglist.  */
       int align = PARM_BOUNDARY / BITS_PER_UNIT;
-      int offset = (((UNITS_PER_WORD + align - 1) / align) * align);
+      int size = MAX (UNITS_PER_WORD,
+                     GET_MODE_SIZE (TYPE_MODE (integer_type_node)));
+      int offset = ((size + align - 1) / align) * align;
       nextarg = plus_constant (nextarg, -offset);
     }
 
@@ -3186,38 +3100,43 @@ expand_builtin_frame_address (exp)
 /* 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 (arglist, target)
      tree arglist;
      rtx target;
 {
   rtx op0;
+  rtx result;
 
-  if (arglist == 0
-      /* Arg could be non-integer if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE)
+  if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
     return 0;
 
   /* Compute the argument.  */
   op0 = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
 
   /* Allocate the desired space.  */
-  return allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
+  result = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+  result = convert_memory_address (ptr_mode, result);
+#endif
+
+  return result;
 }
 
 /* Expand a call to the ffs 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_ffs (arglist, target, subtarget)
      tree arglist;
      rtx target, subtarget;
 {
   rtx op0;
-  if (arglist == 0
-      /* Arg could be non-integer if user redeclared this fcn wrong.  */
-      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE)
+  if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
     return 0;
 
   /* Compute the argument.  */
@@ -3233,12 +3152,13 @@ expand_builtin_ffs (arglist, target, subtarget)
 
 /* If the string passed to fputs is a constant and is one character
    long, we attempt to transform this call into __builtin_fputc(). */
+
 static rtx
 expand_builtin_fputs (arglist, ignore)
      tree arglist;
      int ignore;
 {
-  tree call_expr, len, fn, fn_fputc = built_in_decls[BUILT_IN_FPUTC],
+  tree len, fn, fn_fputc = built_in_decls[BUILT_IN_FPUTC],
     fn_fwrite = built_in_decls[BUILT_IN_FWRITE];
 
   /* If the return value is used, or the replacement _DECL isn't
@@ -3247,11 +3167,7 @@ expand_builtin_fputs (arglist, ignore)
     return 0;
 
   /* Verify the arguments in the original call. */
-  if (arglist == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
-      || TREE_CHAIN (arglist) == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
-         != POINTER_TYPE)
+  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)
       || current_function_check_memory_usage)
     return 0;
 
@@ -3296,7 +3212,7 @@ expand_builtin_fputs (arglist, ignore)
           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, integer_one_node, arglist);
+       arglist = tree_cons (NULL_TREE, size_one_node, arglist);
        arglist = tree_cons (NULL_TREE, string_arg, arglist);
        fn = fn_fwrite;
        break;
@@ -3305,11 +3221,8 @@ expand_builtin_fputs (arglist, ignore)
       abort();
     }
   
-  call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
-  call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
-                    call_expr, arglist, NULL_TREE);
-  TREE_SIDE_EFFECTS (call_expr) = 1;
-  return expand_expr (call_expr, (ignore ? const0_rtx : NULL_RTX),
+  return expand_expr (build_function_call_expr (fn, arglist),
+                     (ignore ? const0_rtx : NULL_RTX),
                      VOIDmode, EXPAND_NORMAL);
 }
 
@@ -3405,10 +3318,18 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       /* build_function_call changes these into ABS_EXPR.  */
       abort ();
 
+    case BUILT_IN_CONJ:
+    case BUILT_IN_CREAL:
+    case BUILT_IN_CIMAG:
+      /* expand_tree_builtin changes these into CONJ_EXPR, REALPART_EXPR
+        and IMAGPART_EXPR.  */
+      abort ();
+
     case BUILT_IN_SIN:
     case BUILT_IN_COS:
-      /* Treat these like sqrt, but only if the user asks for them.  */
-      if (! flag_fast_math)
+      /* Treat these like sqrt only if unsafe math optimizations are allowed,
+        because of possible accuracy problems.  */
+      if (! flag_unsafe_math_optimizations)
        break;
     case BUILT_IN_FSQRT:
       target = expand_builtin_mathfn (exp, target, subtarget);
@@ -3433,13 +3354,10 @@ expand_builtin (exp, target, subtarget, mode, ignore)
         computed?  We'll also need a safe worst case value for varargs
         functions.  */
     case BUILT_IN_APPLY:
-      if (arglist == 0
-         /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-         || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
-         || TREE_CHAIN (arglist) == 0
-         || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
-         || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
-         || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE)
+      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
        {
@@ -3457,9 +3375,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
         value described by RESULT.  RESULT is address of the block of
         memory returned by __builtin_apply.  */
     case BUILT_IN_RETURN:
-      if (arglist
-         /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-         && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE)
+      if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
        expand_builtin_return (expand_expr (TREE_VALUE (arglist),
                                            NULL_RTX, VOIDmode, 0));
       return const0_rtx;
@@ -3630,8 +3546,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
         It's similar to the C library longjmp function but works with
         __builtin_setjmp above.  */
     case BUILT_IN_LONGJMP:
-      if (arglist == 0 || TREE_CHAIN (arglist) == 0
-         || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
+      if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
        break;
       else
        {
@@ -3690,9 +3605,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       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)),
-                               TREE_VALUE (TREE_CHAIN (TREE_CHAIN (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_VARARGS_START:
       return expand_builtin_va_start (0, arglist);
     case BUILT_IN_STDARG_START:
@@ -3772,9 +3690,7 @@ fold_builtin (exp)
       return fold_builtin_constant_p (arglist);
 
     case BUILT_IN_STRLEN:
-      if (arglist != 0
-         /* Arg could be non-pointer if user redeclared this fcn wrong.  */
-         && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) == POINTER_TYPE)
+      if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
        {
          tree len = c_strlen (TREE_VALUE (arglist));
          if (len != 0)
@@ -3788,3 +3704,63 @@ fold_builtin (exp)
 
   return 0;
 }
+
+static tree
+build_function_call_expr (fn, arglist)
+     tree fn, arglist;
+{
+  tree call_expr;
+
+  call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+  call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+                    call_expr, arglist);
+  TREE_SIDE_EFFECTS (call_expr) = 1;
+  return fold (call_expr);
+}
+
+/* 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 VPARAMS ((tree arglist, ...))
+{
+#ifndef ANSI_PROTOTYPES
+  tree arglist;
+#endif
+  enum tree_code code;
+  va_list ap;
+
+  VA_START (ap, arglist);
+
+#ifndef ANSI_PROTOTYPES
+  arglist = va_arg (ap, tree);
+#endif
+
+  do {
+    code = va_arg (ap, enum tree_code);
+    switch (code)
+    {
+    case 0:
+      /* This signifies an ellipses, any further arguments are all ok.  */
+      va_end (ap);
+      return 1;
+    case VOID_TYPE:
+      /* This signifies an endlink, if no arguments remain, return
+         true, otherwise return false.  */
+      va_end (ap);
+      return arglist == 0;
+    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 || code != TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))))
+        {
+         va_end (ap);
+         return 0;
+       }
+      break;
+    }
+    arglist = TREE_CHAIN (arglist);
+  } while (1);
+}