OSDN Git Service

* config/mips/mips.c (save_restore_insns): Don't mark any register
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index ddcaeac..70ed30e 100644 (file)
@@ -1,23 +1,23 @@
 /* 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.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -30,16 +30,17 @@ 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 "optabs.h"
+#include "libfuncs.h"
 #include "recog.h"
 #include "output.h"
 #include "typeclass.h"
-#include "defaults.h"
 #include "toplev.h"
+#include "predict.h"
 #include "tm_p.h"
+#include "target.h"
 
 #define CALLED_AS_BUILT_IN(NODE) \
    (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
@@ -60,7 +61,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, N, C, T, LT, B, F, NA) STRINGX(X),
 const char *const built_in_names[(int) END_BUILTINS] =
 {
 #include "builtins.def"
@@ -69,12 +70,7 @@ const char *const built_in_names[(int) END_BUILTINS] =
 
 /* Setup an array of _DECL trees, make sure each element is
    initialized to NULL_TREE.  */
-#define DEF_BUILTIN(x) NULL_TREE,
-tree built_in_decls[(int) END_BUILTINS] =
-{
-#include "builtins.def"
-};
-#undef DEF_BUILTIN
+tree built_in_decls[(int) END_BUILTINS];
 
 tree (*lang_type_promotes_to) PARAMS ((tree));
 
@@ -95,6 +91,7 @@ static rtx expand_builtin_apply_args  PARAMS ((void));
 static rtx expand_builtin_apply_args_1 PARAMS ((void));
 static rtx expand_builtin_apply                PARAMS ((rtx, rtx, rtx));
 static void expand_builtin_return      PARAMS ((rtx));
+static enum type_class type_to_class   PARAMS ((tree));
 static rtx expand_builtin_classify_type        PARAMS ((tree));
 static rtx expand_builtin_mathfn       PARAMS ((tree, rtx, rtx));
 static rtx expand_builtin_constant_p   PARAMS ((tree));
@@ -146,7 +143,9 @@ 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 fold_builtin_classify_type 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.
@@ -191,8 +190,8 @@ get_pointer_alignment (exp, max_align)
          if (! host_integerp (TREE_OPERAND (exp, 1), 1))
            return align;
 
-         while (((tree_low_cst (TREE_OPERAND (exp, 1), 1) * BITS_PER_UNIT)
-                 & (max_align - 1))
+         while (((tree_low_cst (TREE_OPERAND (exp, 1), 1))
+                 & (max_align / BITS_PER_UNIT - 1))
                 != 0)
            max_align >>= 1;
 
@@ -431,8 +430,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));
-      MEM_ALIAS_SET (tem) = get_frame_alias_set ();
+      tem = gen_rtx_MEM (Pmode, tem);
+      set_mem_alias_set (tem, get_frame_alias_set ());
+      tem = copy_to_reg (tem);
     }
 
   /* For __builtin_frame_address, return what we've got.  */
@@ -447,7 +447,7 @@ expand_builtin_return_addr (fndecl_code, count, tem)
   tem = memory_address (Pmode,
                        plus_constant (tem, GET_MODE_SIZE (Pmode)));
   tem = gen_rtx_MEM (Pmode, tem);
-  MEM_ALIAS_SET (tem) = get_frame_alias_set ();
+  set_mem_alias_set (tem, get_frame_alias_set ());
 #endif
   return tem;
 }
@@ -488,11 +488,11 @@ expand_builtin_setjmp_setup (buf_addr, receiver_label)
 #endif
 
   mem = gen_rtx_MEM (Pmode, buf_addr);
-  MEM_ALIAS_SET (mem) = setjmp_alias_set;
+  set_mem_alias_set (mem, setjmp_alias_set);
   emit_move_insn (mem, BUILTIN_SETJMP_FRAME_VALUE);
 
   mem = gen_rtx_MEM (Pmode, plus_constant (buf_addr, GET_MODE_SIZE (Pmode))),
-  MEM_ALIAS_SET (mem) = setjmp_alias_set;
+  set_mem_alias_set (mem, setjmp_alias_set);
 
   emit_move_insn (validize_mem (mem),
                  force_reg (Pmode, gen_rtx_LABEL_REF (Pmode, receiver_label)));
@@ -500,7 +500,7 @@ expand_builtin_setjmp_setup (buf_addr, receiver_label)
   stack_save = gen_rtx_MEM (sa_mode,
                            plus_constant (buf_addr,
                                           2 * GET_MODE_SIZE (Pmode)));
-  MEM_ALIAS_SET (stack_save) = setjmp_alias_set;
+  set_mem_alias_set (stack_save, setjmp_alias_set);
   emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
 
   /* If there is further processing to do, do it.  */
@@ -514,7 +514,7 @@ expand_builtin_setjmp_setup (buf_addr, receiver_label)
   current_function_calls_setjmp = 1;
 
   /* Set this so all the registers get saved in our frame; we need to be
-     able to copy the saved values for any registers from frames we unwind. */
+     able to copy the saved values for any registers from frames we unwind.  */
   current_function_has_nonlocal_label = 1;
 }
 
@@ -557,14 +557,9 @@ expand_builtin_setjmp_receiver (receiver_label)
 #endif
        {
          /* Now restore our arg pointer from the address at which it
-            was saved in our stack frame.
-            If there hasn't be space allocated for it yet, make
-            some now.  */
-         if (arg_pointer_save_area == 0)
-           arg_pointer_save_area
-             = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
+            was saved in our stack frame.  */
          emit_move_insn (virtual_incoming_args_rtx,
-                         copy_to_reg (arg_pointer_save_area));
+                         copy_to_reg (get_arg_pointer_save_area (cfun)));
        }
     }
 #endif
@@ -580,6 +575,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
@@ -599,8 +601,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
@@ -683,8 +684,9 @@ expand_builtin_longjmp (buf_addr, value)
 
       stack = gen_rtx_MEM (sa_mode, plus_constant (buf_addr,
                                                   2 * GET_MODE_SIZE (Pmode)));
-      MEM_ALIAS_SET (fp) = MEM_ALIAS_SET (lab) = MEM_ALIAS_SET (stack)
-       = setjmp_alias_set;
+      set_mem_alias_set (fp, setjmp_alias_set);
+      set_mem_alias_set (lab, setjmp_alias_set);
+      set_mem_alias_set (stack, setjmp_alias_set);
 
       /* Pick up FP, label, and SP from the block and jump.  This code is
         from expand_goto in stmt.c; see there for detailed comments.  */
@@ -693,7 +695,7 @@ expand_builtin_longjmp (buf_addr, value)
        /* We have to pass a value to the nonlocal_goto pattern that will
           get copied into the static_chain pointer, but it does not matter
           what that value is, because builtin_setjmp does not use it.  */
-       emit_insn (gen_nonlocal_goto (value, fp, stack, lab));
+       emit_insn (gen_nonlocal_goto (value, lab, stack, fp));
       else
 #endif
        {
@@ -713,12 +715,17 @@ expand_builtin_longjmp (buf_addr, value)
      __builtin_setjmp target in the same function.  However, we've
      already cautioned the user that these functions are for
      internal exception handling use only.  */
-  for (insn = get_last_insn ();
-       GET_CODE (insn) != JUMP_INSN;
-       insn = PREV_INSN (insn))
-    continue;
-  REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx,
-                                     REG_NOTES (insn));
+  for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
+    {
+      if (GET_CODE (insn) == JUMP_INSN)
+       {
+         REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx,
+                                             REG_NOTES (insn));
+         break;
+       }
+      else if (GET_CODE (insn) == CALL_INSN)
+        break;
+    }
 }
 
 /* Get a MEM rtx for expression EXP which is the address of an operand
@@ -749,9 +756,8 @@ get_memory_rtx (exp)
     return mem;
 
   set_mem_attributes (mem, exp, 0);
-
-  /* memcpy, memset and other builtin stringops can alias with anything. */
-  MEM_ALIAS_SET (mem) = 0;
+  /* memcpy, memset and other builtin stringops can alias with anything.  */
+  set_mem_alias_set (mem, 0);
   return mem;
 }
 \f
@@ -835,8 +841,7 @@ apply_args_size ()
                   mode != VOIDmode;
                   mode = GET_MODE_WIDER_MODE (mode))
                if (HARD_REGNO_MODE_OK (regno, mode)
-                   && (mov_optab->handlers[(int) mode].insn_code
-                       != CODE_FOR_nothing))
+                   && have_insn_for (SET, mode))
                  best_mode = mode;
 
            mode = best_mode;
@@ -892,8 +897,7 @@ apply_result_size ()
                   mode != VOIDmode;
                   mode = GET_MODE_WIDER_MODE (mode))
                if (HARD_REGNO_MODE_OK (regno, mode)
-                   && (mov_optab->handlers[(int) mode].insn_code
-                       != CODE_FOR_nothing))
+                   && have_insn_for (SET, mode))
                  best_mode = mode;
 
            mode = best_mode;
@@ -941,8 +945,7 @@ result_vector (savep, result)
        if (size % align != 0)
          size = CEIL (size, align) * align;
        reg = gen_rtx_REG (mode, savep ? regno : INCOMING_REGNO (regno));
-       mem = change_address (result, mode,
-                             plus_constant (XEXP (result, 0), size));
+       mem = adjust_address (result, mode, size);
        savevec[nelts++] = (savep
                            ? gen_rtx_SET (VOIDmode, mem, reg)
                            : gen_rtx_SET (VOIDmode, reg, mem));
@@ -983,15 +986,12 @@ expand_builtin_apply_args_1 ()
 
        tem = gen_rtx_REG (mode, INCOMING_REGNO (regno));
 
-       emit_move_insn (change_address (registers, mode,
-                                       plus_constant (XEXP (registers, 0),
-                                                      size)),
-                       tem);
+       emit_move_insn (adjust_address (registers, mode, size), tem);
        size += GET_MODE_SIZE (mode);
       }
 
   /* Save the arg pointer to the block.  */
-  emit_move_insn (change_address (registers, Pmode, XEXP (registers, 0)),
+  emit_move_insn (adjust_address (registers, Pmode, 0),
                  copy_to_reg (virtual_incoming_args_rtx));
   size = GET_MODE_SIZE (Pmode);
 
@@ -999,9 +999,7 @@ expand_builtin_apply_args_1 ()
      "invisible" first argument.  */
   if (struct_value_incoming_rtx)
     {
-      emit_move_insn (change_address (registers, Pmode,
-                                     plus_constant (XEXP (registers, 0),
-                                                    size)),
+      emit_move_insn (adjust_address (registers, Pmode, size),
                      copy_to_reg (struct_value_incoming_rtx));
       size += GET_MODE_SIZE (Pmode);
     }
@@ -1069,8 +1067,8 @@ expand_builtin_apply (function, arguments, argsize)
   emit_move_insn (incoming_args,
                  gen_rtx_MEM (Pmode, arguments));
 #ifndef STACK_GROWS_DOWNWARD
-  incoming_args = expand_binop (Pmode, sub_optab, incoming_args, argsize,
-                               incoming_args, 0, OPTAB_LIB_WIDEN);
+  incoming_args = expand_simple_binop (Pmode, MINUS, incoming_args, argsize,
+                                      incoming_args, 0, OPTAB_LIB_WIDEN);
 #endif
 
   /* Perform postincrements before actually calling the function.  */
@@ -1118,11 +1116,7 @@ expand_builtin_apply (function, arguments, argsize)
        if (size % align != 0)
          size = CEIL (size, align) * align;
        reg = gen_rtx_REG (mode, regno);
-       emit_move_insn (reg,
-                       change_address (arguments, mode,
-                                       plus_constant (XEXP (arguments, 0),
-                                                      size)));
-
+       emit_move_insn (reg, adjust_address (arguments, mode, size));
        use_reg (&call_fusage, reg);
        size += GET_MODE_SIZE (mode);
       }
@@ -1133,10 +1127,7 @@ expand_builtin_apply (function, arguments, argsize)
   if (struct_value_rtx)
     {
       rtx value = gen_reg_rtx (Pmode);
-      emit_move_insn (value,
-                     change_address (arguments, Pmode,
-                                     plus_constant (XEXP (arguments, 0),
-                                                    size)));
+      emit_move_insn (value, adjust_address (arguments, Pmode, size));
       emit_move_insn (struct_value_rtx, value);
       if (GET_CODE (struct_value_rtx) == REG)
          use_reg (&call_fusage, struct_value_rtx);
@@ -1144,7 +1135,7 @@ expand_builtin_apply (function, arguments, argsize)
     }
 
   /* All arguments and registers used for the call are set up by now!  */
-  function = prepare_call_address (function, NULL_TREE, &call_fusage, 0);
+  function = prepare_call_address (function, NULL_TREE, &call_fusage, 0, 0);
 
   /* Ensure address is valid.  SYMBOL_REF is already valid, so no need,
      and we don't want to load it into a register as an optimization,
@@ -1180,9 +1171,7 @@ expand_builtin_apply (function, arguments, argsize)
                                      gen_rtx_MEM (FUNCTION_MODE, function),
                                      const0_rtx, NULL_RTX, const0_rtx));
 
-      emit_move_insn (change_address (result, GET_MODE (valreg),
-                                     XEXP (result, 0)),
-                     valreg);
+      emit_move_insn (adjust_address (result, GET_MODE (valreg), 0), valreg);
     }
   else
 #endif
@@ -1258,10 +1247,7 @@ expand_builtin_return (result)
        if (size % align != 0)
          size = CEIL (size, align) * align;
        reg = gen_rtx_REG (mode, INCOMING_REGNO (regno));
-       emit_move_insn (reg,
-                       change_address (result, mode,
-                                       plus_constant (XEXP (result, 0),
-                                                      size)));
+       emit_move_insn (reg, adjust_address (result, mode, size));
 
        push_to_sequence (call_fusage);
        emit_insn (gen_rtx_USE (VOIDmode, reg));
@@ -1278,6 +1264,37 @@ expand_builtin_return (result)
   expand_null_return ();
 }
 
+/* Used by expand_builtin_classify_type and fold_builtin_classify_type.  */
+static enum type_class
+type_to_class (type)
+     tree type;
+{
+  switch (TREE_CODE (type))
+    {
+    case VOID_TYPE:       return void_type_class;
+    case INTEGER_TYPE:    return integer_type_class;
+    case CHAR_TYPE:       return char_type_class;
+    case ENUMERAL_TYPE:           return enumeral_type_class;
+    case BOOLEAN_TYPE:    return boolean_type_class;
+    case POINTER_TYPE:    return pointer_type_class;
+    case REFERENCE_TYPE:   return reference_type_class;
+    case OFFSET_TYPE:     return offset_type_class;
+    case REAL_TYPE:       return real_type_class;
+    case COMPLEX_TYPE:    return complex_type_class;
+    case FUNCTION_TYPE:           return function_type_class;
+    case METHOD_TYPE:     return method_type_class;
+    case RECORD_TYPE:     return record_type_class;
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:  return union_type_class;
+    case ARRAY_TYPE:      return (TYPE_STRING_FLAG (type)
+                                  ? string_type_class : array_type_class);
+    case SET_TYPE:        return set_type_class;
+    case FILE_TYPE:       return file_type_class;
+    case LANG_TYPE:       return lang_type_class;
+    default:              return no_type_class;
+    }
+}
+  
 /* Expand a call to __builtin_classify_type with arguments found in
    ARGLIST.  */
 static rtx
@@ -1285,51 +1302,7 @@ expand_builtin_classify_type (arglist)
      tree arglist;
 {
   if (arglist != 0)
-    {
-      tree type = TREE_TYPE (TREE_VALUE (arglist));
-      enum tree_code code = TREE_CODE (type);
-      if (code == VOID_TYPE)
-       return GEN_INT (void_type_class);
-      if (code == INTEGER_TYPE)
-       return GEN_INT (integer_type_class);
-      if (code == CHAR_TYPE)
-       return GEN_INT (char_type_class);
-      if (code == ENUMERAL_TYPE)
-       return GEN_INT (enumeral_type_class);
-      if (code == BOOLEAN_TYPE)
-       return GEN_INT (boolean_type_class);
-      if (code == POINTER_TYPE)
-       return GEN_INT (pointer_type_class);
-      if (code == REFERENCE_TYPE)
-       return GEN_INT (reference_type_class);
-      if (code == OFFSET_TYPE)
-       return GEN_INT (offset_type_class);
-      if (code == REAL_TYPE)
-       return GEN_INT (real_type_class);
-      if (code == COMPLEX_TYPE)
-       return GEN_INT (complex_type_class);
-      if (code == FUNCTION_TYPE)
-       return GEN_INT (function_type_class);
-      if (code == METHOD_TYPE)
-       return GEN_INT (method_type_class);
-      if (code == RECORD_TYPE)
-       return GEN_INT (record_type_class);
-      if (code == UNION_TYPE || code == QUAL_UNION_TYPE)
-       return GEN_INT (union_type_class);
-      if (code == ARRAY_TYPE)
-       {
-         if (TYPE_STRING_FLAG (type))
-           return GEN_INT (string_type_class);
-         else
-           return GEN_INT (array_type_class);
-       }
-      if (code == SET_TYPE)
-       return GEN_INT (set_type_class);
-      if (code == FILE_TYPE)
-       return GEN_INT (file_type_class);
-      if (code == LANG_TYPE)
-       return GEN_INT (lang_type_class);
-    }
+    return GEN_INT (type_to_class (TREE_TYPE (TREE_VALUE (arglist))));
   return GEN_INT (no_type_class);
 }
 
@@ -1370,9 +1343,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.  */
@@ -1401,11 +1372,17 @@ expand_builtin_mathfn (exp, target, subtarget)
 
   switch (DECL_FUNCTION_CODE (fndecl))
     {
-     case BUILT_IN_SIN:
+    case BUILT_IN_SIN:
+    case BUILT_IN_SINF:
+    case BUILT_IN_SINL:
       builtin_optab = sin_optab; break;
-     case BUILT_IN_COS:
+    case BUILT_IN_COS:
+    case BUILT_IN_COSF:
+    case BUILT_IN_COSL:
       builtin_optab = cos_optab; break;
-     case BUILT_IN_FSQRT:
+    case BUILT_IN_FSQRT:
+    case BUILT_IN_SQRTF:
+    case BUILT_IN_SQRTL:
       builtin_optab = sqrt_optab; break;
      default:
       abort ();
@@ -1425,10 +1402,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;
 
@@ -1486,9 +1463,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
     {
@@ -1590,10 +1565,7 @@ 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
@@ -1650,10 +1622,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
@@ -1700,10 +1669,7 @@ 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
@@ -1758,10 +1724,7 @@ 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
@@ -1837,16 +1800,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
     {
@@ -1915,12 +1870,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
     {
@@ -1967,16 +1917,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
     {
@@ -2060,17 +2002,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
     {
@@ -2142,14 +2075,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).  */
   
@@ -2181,13 +2112,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;
 
   {
@@ -2270,12 +2196,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);
@@ -2379,25 +2300,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.  */
@@ -2410,17 +2322,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);
@@ -2437,28 +2350,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
   
@@ -2478,12 +2403,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
     {
@@ -2512,16 +2432,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
     {
@@ -2552,7 +2464,7 @@ expand_builtin_strncat (arglist, target, mode)
            fn = built_in_decls[BUILT_IN_STRCAT];
          
          /* If the replacement _DECL isn't initialized, don't do the
-            transformation. */
+            transformation.  */
          if (!fn)
            return 0;
 
@@ -2576,12 +2488,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
     {
@@ -2621,12 +2528,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
     {
@@ -2656,7 +2558,7 @@ expand_builtin_strcspn (arglist, target, mode)
            fn = built_in_decls[BUILT_IN_STRLEN];
          
          /* If the replacement _DECL isn't initialized, don't do the
-            transformation. */
+            transformation.  */
          if (!fn)
            return 0;
 
@@ -2877,8 +2779,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);
     }
 
@@ -3042,7 +2949,7 @@ expand_builtin_va_arg (valist, type)
     }
 
   result = gen_rtx_MEM (TYPE_MODE (type), addr);
-  MEM_ALIAS_SET (result) = get_varargs_alias_set ();
+  set_mem_alias_set (result, get_varargs_alias_set ());
 
   return result;
 }
@@ -3102,9 +3009,9 @@ expand_builtin_va_copy (arglist)
 
       /* "Dereference" to BLKmode memories.  */
       dstb = gen_rtx_MEM (BLKmode, dstb);
-      MEM_ALIAS_SET (dstb) = get_alias_set (TREE_TYPE (TREE_TYPE (dst)));
+      set_mem_alias_set (dstb, get_alias_set (TREE_TYPE (TREE_TYPE (dst))));
       srcb = gen_rtx_MEM (BLKmode, srcb);
-      MEM_ALIAS_SET (srcb) = get_alias_set (TREE_TYPE (TREE_TYPE (src)));
+      set_mem_alias_set (srcb, get_alias_set (TREE_TYPE (TREE_TYPE (src))));
 
       /* Copy.  */
       emit_block_move (dstb, srcb, size, TYPE_ALIGN (va_list_type_node));
@@ -3167,38 +3074,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.  */
@@ -3213,7 +3125,8 @@ 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(). */
+   long, we attempt to transform this call into __builtin_fputc().  */
+
 static rtx
 expand_builtin_fputs (arglist, ignore)
      tree arglist;
@@ -3223,16 +3136,12 @@ expand_builtin_fputs (arglist, ignore)
     fn_fwrite = built_in_decls[BUILT_IN_FWRITE];
 
   /* If the return value is used, or the replacement _DECL isn't
-     initialized, don't do the transformation. */
+     initialized, don't do the transformation.  */
   if (!ignore || !fn_fputc || !fn_fwrite)
     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)
+  /* Verify the arguments in the original call.  */
+  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)
       || current_function_check_memory_usage)
     return 0;
 
@@ -3277,7 +3186,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;
@@ -3291,8 +3200,9 @@ expand_builtin_fputs (arglist, ignore)
                      VOIDmode, EXPAND_NORMAL);
 }
 
-/* Expand a call to __builtin_expect.  We return our argument and
-   emit a NOTE_INSN_EXPECTED_VALUE note.  */
+/* Expand a call to __builtin_expect.  We return our argument and emit a
+   NOTE_INSN_EXPECTED_VALUE note.  This is the expansion of __builtin_expect in
+   a non-jump context.  */
 
 static rtx
 expand_builtin_expect (arglist, target)
@@ -3332,6 +3242,131 @@ expand_builtin_expect (arglist, target)
 
   return target;
 }
+
+/* Like expand_builtin_expect, except do this in a jump context.  This is
+   called from do_jump if the conditional is a __builtin_expect.  Return either
+   a SEQUENCE of insns to emit the jump or NULL if we cannot optimize
+   __builtin_expect.  We need to optimize this at jump time so that machines
+   like the PowerPC don't turn the test into a SCC operation, and then jump
+   based on the test being 0/1.  */
+
+rtx
+expand_builtin_expect_jump (exp, if_false_label, if_true_label)
+     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
+     __builtin_expect (test, 1).  */
+  if (TREE_CODE (TREE_TYPE (arg1)) == INTEGER_TYPE
+      && TREE_CODE (arg1) == INTEGER_CST
+      && (TREE_INT_CST_LOW (arg1) == 0 || TREE_INT_CST_LOW (arg1) == 1)
+      && TREE_INT_CST_HIGH (arg1) == 0)
+    {
+      int j;
+      int num_jumps = 0;
+
+      /* If we fail to locate an appropriate conditional jump, we'll
+        fall back to normal evaluation.  Ensure that the expression
+        can be re-evaluated.  */
+      switch (unsafe_for_reeval (arg0))
+       {
+       case 0: /* Safe.  */
+         break;
+
+       case 1: /* Mildly unsafe.  */
+         arg0 = unsave_expr (arg0);
+         break;
+
+       case 2: /* Wildly unsafe.  */
+         return NULL_RTX;
+       }
+
+      /* Expand the jump insns.  */
+      start_sequence ();
+      do_jump (arg0, if_false_label, if_true_label);
+      ret = gen_sequence ();
+      end_sequence ();
+
+      /* Now that the __builtin_expect has been validated, go through and add
+        the expect's to each of the conditional jumps.  If we run into an
+        error, just give up and generate the 'safe' code of doing a SCC
+        operation and then doing a branch on that.  */
+      for (j = 0; j < XVECLEN (ret, 0); j++)
+       {
+         rtx insn = XVECEXP (ret, 0, j);
+         rtx pattern;
+
+         if (GET_CODE (insn) == JUMP_INSN && any_condjump_p (insn)
+             && (pattern = pc_set (insn)) != NULL_RTX)
+           {
+             rtx ifelse = SET_SRC (pattern);
+             rtx label;
+             int taken;
+
+             if (GET_CODE (ifelse) != IF_THEN_ELSE)
+               continue;
+
+             if (GET_CODE (XEXP (ifelse, 1)) == LABEL_REF)
+               {
+                 taken = 1;
+                 label = XEXP (XEXP (ifelse, 1), 0);
+               }
+             /* An inverted jump reverses the probabilities.  */
+             else if (GET_CODE (XEXP (ifelse, 2)) == LABEL_REF)
+               {
+                 taken = 0;
+                 label = XEXP (XEXP (ifelse, 2), 0);
+               }
+             /* We shouldn't have to worry about conditional returns during
+                the expansion stage, but handle it gracefully anyway.  */
+             else if (GET_CODE (XEXP (ifelse, 1)) == RETURN)
+               {
+                 taken = 1;
+                 label = NULL_RTX;
+               }
+             /* An inverted return reverses the probabilities.  */
+             else if (GET_CODE (XEXP (ifelse, 2)) == RETURN)
+               {
+                 taken = 0;
+                 label = NULL_RTX;
+               }
+             else
+               continue;
+
+             /* If the test is expected to fail, reverse the
+                probabilities.  */
+             if (TREE_INT_CST_LOW (arg1) == 0)
+               taken = 1 - taken;
+
+             /* If we are jumping to the false label, reverse the
+                probabilities.  */
+             if (label == NULL_RTX)
+               ;               /* conditional return */
+             else if (label == if_false_label)
+               taken = 1 - taken;
+             else if (label != if_true_label)
+               continue;
+
+             num_jumps++;
+             predict_insn_def (insn, PRED_BUILTIN_EXPECT, taken);
+           }
+       }
+
+      /* If no jumps were modified, fail and do __builtin_expect the normal
+        way.  */
+      if (num_jumps == 0)
+       ret = NULL_RTX;
+    }
+
+  return ret;
+}
+
 \f
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
@@ -3351,16 +3386,15 @@ expand_builtin (exp, target, subtarget, mode, ignore)
   tree arglist = TREE_OPERAND (exp, 1);
   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
 
-#ifdef MD_EXPAND_BUILTIN
   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
-    return MD_EXPAND_BUILTIN (exp, target, subtarget, mode, ignore);
-#endif
+    return (*targetm.expand_builtin) (exp, target, subtarget, mode, ignore);
   
   /* When not optimizing, generate calls to library functions for a certain
      set of builtins.  */
   if (! optimize && ! CALLED_AS_BUILT_IN (fndecl)
       && (fcode == BUILT_IN_SIN || fcode == BUILT_IN_COS
-         || fcode == BUILT_IN_FSQRT || fcode == BUILT_IN_MEMSET
+         || fcode == BUILT_IN_FSQRT || fcode == BUILT_IN_SQRTF
+         || fcode == BUILT_IN_SQRTL || fcode == BUILT_IN_MEMSET
          || fcode == BUILT_IN_MEMCPY || fcode == BUILT_IN_MEMCMP
          || fcode == BUILT_IN_BCMP || fcode == BUILT_IN_BZERO
          || fcode == BUILT_IN_INDEX || fcode == BUILT_IN_RINDEX
@@ -3379,16 +3413,41 @@ expand_builtin (exp, target, subtarget, mode, ignore)
   switch (fcode)
     {
     case BUILT_IN_ABS:
+    case BUILT_IN_LABS:
+    case BUILT_IN_LLABS:
+    case BUILT_IN_IMAXABS:
     case BUILT_IN_FABS:
+    case BUILT_IN_FABSF:
+    case BUILT_IN_FABSL:
       /* build_function_call changes these into ABS_EXPR.  */
       abort ();
 
+    case BUILT_IN_CONJ:
+    case BUILT_IN_CONJF:
+    case BUILT_IN_CONJL:
+    case BUILT_IN_CREAL:
+    case BUILT_IN_CREALF:
+    case BUILT_IN_CREALL:
+    case BUILT_IN_CIMAG:
+    case BUILT_IN_CIMAGF:
+    case BUILT_IN_CIMAGL:
+      /* expand_tree_builtin changes these into CONJ_EXPR, REALPART_EXPR
+        and IMAGPART_EXPR.  */
+      abort ();
+
     case BUILT_IN_SIN:
+    case BUILT_IN_SINF:
+    case BUILT_IN_SINL:
     case BUILT_IN_COS:
-      /* Treat these like sqrt, but only if the user asks for them.  */
-      if (! flag_fast_math)
+    case BUILT_IN_COSF:
+    case BUILT_IN_COSL:
+      /* 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:
+    case BUILT_IN_SQRTF:
+    case BUILT_IN_SQRTL:
       target = expand_builtin_mathfn (exp, target, subtarget);
       if (target)
        return target;
@@ -3411,13 +3470,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
        {
@@ -3435,9 +3491,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;
@@ -3608,8 +3662,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
        {
@@ -3668,9 +3721,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:
@@ -3721,15 +3777,30 @@ fold_builtin_constant_p (arglist)
      has side effects, show we don't know it to be a constant.
      Likewise if it's a pointer or aggregate type since in those
      case we only want literals, since those are only optimized
-     when generating RTL, not later.  */
+     when generating RTL, not later.
+     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) || cse_not_expected
       || AGGREGATE_TYPE_P (TREE_TYPE (arglist))
-      || POINTER_TYPE_P (TREE_TYPE (arglist)))
+      || POINTER_TYPE_P (TREE_TYPE (arglist))
+      || cfun == 0)
     return integer_zero_node;
 
   return 0;
 }
 
+/* Fold a call to __builtin_classify_type.  */
+static tree
+fold_builtin_classify_type (arglist)
+     tree arglist;
+{
+  if (arglist == 0)
+    return build_int_2 (no_type_class, 0);
+
+  return build_int_2 (type_to_class (TREE_TYPE (TREE_VALUE (arglist))), 0);
+}
+
 /* Used by constant folding to eliminate some builtin calls early.  EXP is
    the CALL_EXPR of a call to a builtin function.  */
 
@@ -3749,10 +3820,11 @@ fold_builtin (exp)
     case BUILT_IN_CONSTANT_P:
       return fold_builtin_constant_p (arglist);
 
+    case BUILT_IN_CLASSIFY_TYPE:
+      return fold_builtin_classify_type (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)
@@ -3779,3 +3851,68 @@ build_function_call_expr (fn, 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, ...))
+{
+  enum tree_code code;
+  int res = 0;
+
+  VA_OPEN (ap, arglist);
+  VA_FIXEDARG (ap, tree, arglist);
+
+  do {
+    code = va_arg (ap, enum tree_code);
+    switch (code)
+    {
+    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 || code != TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))))
+       goto end;
+      break;
+    }
+    arglist = TREE_CHAIN (arglist);
+  } while (1);
+
+  /* We need gotos here since we can only have one VA_CLOSE in a
+     function.  */
+ end: ;
+  VA_CLOSE (ap);
+
+  return res;
+}
+
+/* Default version of target-specific builtin setup that does nothing.  */
+
+void
+default_init_builtins ()
+{
+}
+
+/* Default target-specific builtin expander that does nothing.  */
+
+rtx
+default_expand_builtin (exp, target, subtarget, mode, ignore)
+     tree exp ATTRIBUTE_UNUSED;
+     rtx target ATTRIBUTE_UNUSED;
+     rtx subtarget ATTRIBUTE_UNUSED;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+     int ignore ATTRIBUTE_UNUSED;
+{
+  return NULL_RTX;
+}