OSDN Git Service

* gcc.c-torture/compile/20021120-1.c: New test.
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index 9adbf96..7eea036 100644 (file)
@@ -1,6 +1,6 @@
 /* Expand builtin functions.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -22,9 +22,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "config.h"
 #include "system.h"
 #include "machmode.h"
+#include "real.h"
 #include "rtl.h"
 #include "tree.h"
-#include "obstack.h"
 #include "flags.h"
 #include "regs.h"
 #include "hard-reg-set.h"
@@ -41,6 +41,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "predict.h"
 #include "tm_p.h"
 #include "target.h"
+#include "langhooks.h"
 
 #define CALLED_AS_BUILT_IN(NODE) \
    (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
@@ -61,7 +62,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 const char *const built_in_class_names[4]
   = {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
 
-#define DEF_BUILTIN(X, N, C, T, LT, B, F, NA) STRINGX(X),
+#define DEF_BUILTIN(X, N, C, T, LT, B, F, NA, AT) STRINGX(X),
 const char *const built_in_names[(int) END_BUILTINS] =
 {
 #include "builtins.def"
@@ -72,14 +73,12 @@ const char *const built_in_names[(int) END_BUILTINS] =
    initialized to NULL_TREE.  */
 tree built_in_decls[(int) END_BUILTINS];
 
-tree (*lang_type_promotes_to) PARAMS ((tree));
-
 static int get_pointer_alignment       PARAMS ((tree, unsigned int));
 static tree c_strlen                   PARAMS ((tree));
 static const char *c_getstr            PARAMS ((tree));
 static rtx c_readstr                   PARAMS ((const char *,
                                                 enum machine_mode));
-static int target_char_cast            PARAMS ((tree, char *)); 
+static int target_char_cast            PARAMS ((tree, char *));
 static rtx get_memory_rtx              PARAMS ((tree));
 static int apply_args_size             PARAMS ((void));
 static int apply_result_size           PARAMS ((void));
@@ -87,6 +86,7 @@ static int apply_result_size          PARAMS ((void));
 static rtx result_vector               PARAMS ((int, rtx));
 #endif
 static rtx expand_builtin_setjmp       PARAMS ((tree, rtx));
+static void expand_builtin_prefetch    PARAMS ((tree));
 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));
@@ -97,12 +97,11 @@ static rtx expand_builtin_mathfn    PARAMS ((tree, rtx, rtx));
 static rtx expand_builtin_constant_p   PARAMS ((tree));
 static rtx expand_builtin_args_info    PARAMS ((tree));
 static rtx expand_builtin_next_arg     PARAMS ((tree));
-static rtx expand_builtin_va_start     PARAMS ((int, tree));
+static rtx expand_builtin_va_start     PARAMS ((tree));
 static rtx expand_builtin_va_end       PARAMS ((tree));
 static rtx expand_builtin_va_copy      PARAMS ((tree));
-#ifdef HAVE_cmpstrsi
-static rtx expand_builtin_memcmp       PARAMS ((tree, tree, rtx));
-#endif
+static rtx expand_builtin_memcmp       PARAMS ((tree, tree, rtx,
+                                                enum machine_mode));
 static rtx expand_builtin_strcmp       PARAMS ((tree, rtx,
                                                 enum machine_mode));
 static rtx expand_builtin_strncmp      PARAMS ((tree, rtx,
@@ -117,15 +116,20 @@ static rtx expand_builtin_strspn  PARAMS ((tree, rtx,
                                                 enum machine_mode));
 static rtx expand_builtin_strcspn      PARAMS ((tree, rtx,
                                                 enum machine_mode));
-static rtx expand_builtin_memcpy       PARAMS ((tree));
-static rtx expand_builtin_strcpy       PARAMS ((tree));
+static rtx expand_builtin_memcpy       PARAMS ((tree, rtx,
+                                                enum machine_mode));
+static rtx expand_builtin_strcpy       PARAMS ((tree, rtx,
+                                                enum machine_mode));
 static rtx builtin_strncpy_read_str    PARAMS ((PTR, HOST_WIDE_INT,
                                                 enum machine_mode));
 static rtx expand_builtin_strncpy      PARAMS ((tree, rtx,
                                                 enum machine_mode));
 static rtx builtin_memset_read_str     PARAMS ((PTR, HOST_WIDE_INT,
                                                 enum machine_mode));
-static rtx expand_builtin_memset       PARAMS ((tree));
+static rtx builtin_memset_gen_str      PARAMS ((PTR, HOST_WIDE_INT,
+                                                enum machine_mode));
+static rtx expand_builtin_memset       PARAMS ((tree, rtx,
+                                                enum machine_mode));
 static rtx expand_builtin_bzero                PARAMS ((tree));
 static rtx expand_builtin_strlen       PARAMS ((tree, rtx));
 static rtx expand_builtin_strstr       PARAMS ((tree, rtx,
@@ -139,11 +143,13 @@ static rtx expand_builtin_strrchr PARAMS ((tree, rtx,
 static rtx expand_builtin_alloca       PARAMS ((tree, rtx));
 static rtx expand_builtin_ffs          PARAMS ((tree, rtx, rtx));
 static rtx expand_builtin_frame_address        PARAMS ((tree));
-static rtx expand_builtin_fputs                PARAMS ((tree, int));
+static rtx expand_builtin_fputs                PARAMS ((tree, int, int));
 static tree stabilize_va_list          PARAMS ((tree, int));
 static rtx expand_builtin_expect       PARAMS ((tree, rtx));
 static tree fold_builtin_constant_p    PARAMS ((tree));
 static tree fold_builtin_classify_type PARAMS ((tree));
+static tree fold_builtin_inf           PARAMS ((tree, int));
+static tree fold_builtin_nan           PARAMS ((tree, tree, int));
 static tree build_function_call_expr   PARAMS ((tree, tree));
 static int validate_arglist            PARAMS ((tree, ...));
 
@@ -265,8 +271,10 @@ c_strlen (src)
 
   /* We have a known offset into the string.  Start searching there for
      a null character if we can represent it as a single HOST_WIDE_INT.  */
-  if (offset_node == 0 || ! host_integerp (offset_node, 0))
+  if (offset_node == 0)
     offset = 0;
+  else if (! host_integerp (offset_node, 0))
+    offset = -1;
   else
     offset = tree_low_cst (offset_node, 0);
 
@@ -295,30 +303,22 @@ c_getstr (src)
      tree src;
 {
   tree offset_node;
-  HOST_WIDE_INT offset;
-  int max;
-  const char *ptr;
 
   src = string_constant (src, &offset_node);
   if (src == 0)
     return 0;
 
-  max = TREE_STRING_LENGTH (src) - 1;
-  ptr = TREE_STRING_POINTER (src);
-
-  if (offset_node == 0 || !host_integerp (offset_node, 0))
-    return ptr;
-
-  offset = tree_low_cst (offset_node, 0);
-  if (offset < 0 || offset > max)
+  if (offset_node == 0)
+    return TREE_STRING_POINTER (src);
+  else if (!host_integerp (offset_node, 1)
+          || compare_tree_int (offset_node, TREE_STRING_LENGTH (src) - 1) > 0)
     return 0;
 
-  return ptr + offset;
+  return TREE_STRING_POINTER (src) + tree_low_cst (offset_node, 1);
 }
 
-/* Return a CONST_INT or CONST_DOUBLE corresponding to target
-   reading GET_MODE_BITSIZE (MODE) bits from string constant
-   STR.  */
+/* Return a CONST_INT or CONST_DOUBLE corresponding to target reading
+   GET_MODE_BITSIZE (MODE) bits from string constant STR.  */
 
 static rtx
 c_readstr (str, mode)
@@ -462,7 +462,8 @@ expand_builtin_setjmp_setup (buf_addr, receiver_label)
     setjmp_alias_set = new_alias_set ();
 
 #ifdef POINTERS_EXTEND_UNSIGNED
-  buf_addr = convert_memory_address (Pmode, buf_addr);
+  if (GET_MODE (buf_addr) != Pmode)
+    buf_addr = convert_memory_address (Pmode, buf_addr);
 #endif
 
   buf_addr = force_reg (Pmode, force_operand (buf_addr, NULL_RTX));
@@ -513,7 +514,7 @@ expand_builtin_setjmp_setup (buf_addr, receiver_label)
 
 void
 expand_builtin_setjmp_receiver (receiver_label)
-      rtx receiver_label ATTRIBUTE_UNUSED;
+     rtx receiver_label ATTRIBUTE_UNUSED;
 {
   /* Clobber the FP when we get here, so we have to make sure it's
      marked as used by this function.  */
@@ -536,7 +537,7 @@ expand_builtin_setjmp_receiver (receiver_label)
     {
 #ifdef ELIMINABLE_REGS
       size_t i;
-      static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
+      static const struct elims {const int from, to;} elim_regs[] = ELIMINABLE_REGS;
 
       for (i = 0; i < ARRAY_SIZE (elim_regs); i++)
        if (elim_regs[i].from == ARG_POINTER_REGNUM
@@ -641,15 +642,17 @@ void
 expand_builtin_longjmp (buf_addr, value)
      rtx buf_addr, value;
 {
-  rtx fp, lab, stack, insn;
+  rtx fp, lab, stack, insn, last;
   enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
 
   if (setjmp_alias_set == -1)
     setjmp_alias_set = new_alias_set ();
 
 #ifdef POINTERS_EXTEND_UNSIGNED
-  buf_addr = convert_memory_address (Pmode, buf_addr);
+  if (GET_MODE (buf_addr) != Pmode)
+    buf_addr = convert_memory_address (Pmode, buf_addr);
 #endif
+
   buf_addr = force_reg (Pmode, buf_addr);
 
   /* We used to store value in static_chain_rtx, but that fails if pointers
@@ -662,6 +665,7 @@ expand_builtin_longjmp (buf_addr, value)
 
   current_function_calls_longjmp = 1;
 
+  last = get_last_insn ();
 #ifdef HAVE_builtin_longjmp
   if (HAVE_builtin_longjmp)
     emit_insn (gen_builtin_longjmp (buf_addr));
@@ -707,6 +711,8 @@ expand_builtin_longjmp (buf_addr, value)
      internal exception handling use only.  */
   for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
     {
+      if (insn == last)
+       abort ();
       if (GET_CODE (insn) == JUMP_INSN)
        {
          REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx,
@@ -714,8 +720,96 @@ expand_builtin_longjmp (buf_addr, value)
          break;
        }
       else if (GET_CODE (insn) == CALL_INSN)
-        break;
+       break;
+    }
+}
+
+/* Expand a call to __builtin_prefetch.  For a target that does not support
+   data prefetch, evaluate the memory address argument in case it has side
+   effects.  */
+
+static void
+expand_builtin_prefetch (arglist)
+     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_2 (3, 0);
+    }
+  else
+    {
+      arg1 = integer_zero_node;
+      arg2 = build_int_2 (3, 0);
+    }
+
+  /* Argument 0 is an address.  */
+  op0 = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
+
+  /* Argument 1 (read/write flag) must be a compile-time constant int.  */
+  if (TREE_CODE (arg1) != INTEGER_CST)
+    {
+      error ("second arg to `__builtin_prefetch' must be a constant");
+      arg1 = integer_zero_node;
+    }
+  op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+  /* Argument 1 must be either zero or one.  */
+  if (INTVAL (op1) != 0 && INTVAL (op1) != 1)
+    {
+      warning ("invalid second arg to __builtin_prefetch; using zero");
+      op1 = const0_rtx;
+    }
+
+  /* Argument 2 (locality) must be a compile-time constant int.  */
+  if (TREE_CODE (arg2) != INTEGER_CST)
+    {
+      error ("third arg to `__builtin_prefetch' must be a constant");
+      arg2 = integer_zero_node;
+    }
+  op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+  /* Argument 2 must be 0, 1, 2, or 3.  */
+  if (INTVAL (op2) < 0 || INTVAL (op2) > 3)
+    {
+      warning ("invalid third arg to __builtin_prefetch; using zero");
+      op2 = const0_rtx;
+    }
+
+#ifdef HAVE_prefetch
+  if (HAVE_prefetch)
+    {
+      if ((! (*insn_data[(int) CODE_FOR_prefetch].operand[0].predicate)
+            (op0,
+             insn_data[(int) CODE_FOR_prefetch].operand[0].mode))
+         || (GET_MODE(op0) != Pmode))
+       {
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE(op0) != Pmode)
+           op0 = convert_memory_address (Pmode, op0);
+#endif
+         op0 = force_reg (Pmode, op0);
+       }
+      emit_insn (gen_prefetch (op0, op1, op2));
     }
+  else
+#endif
+    op0 = protect_from_queue (op0, 0);
+  /* Don't do anything with direct references to volatile memory, but
+     generate code to handle other side effects.  */
+  if (GET_CODE (op0) != MEM && side_effects_p (op0))
+    emit_insn (op0);
 }
 
 /* Get a MEM rtx for expression EXP which is the address of an operand
@@ -725,29 +819,36 @@ static rtx
 get_memory_rtx (exp)
      tree exp;
 {
-  rtx mem = gen_rtx_MEM (BLKmode,
-                        memory_address (BLKmode,
-                                        expand_expr (exp, NULL_RTX,
-                                                     ptr_mode, EXPAND_SUM)));
+  rtx addr = expand_expr (exp, NULL_RTX, ptr_mode, EXPAND_SUM);
+  rtx mem;
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+  if (GET_MODE (addr) != Pmode)
+    addr = convert_memory_address (Pmode, addr);
+#endif
+
+  mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr));
 
   /* Get an expression we can use to find the attributes to assign to MEM.
      If it is an ADDR_EXPR, use the operand.  Otherwise, dereference it if
      we can.  First remove any nops.  */
   while ((TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
-        || TREE_CODE (exp) == NON_LVALUE_EXPR)
+         || TREE_CODE (exp) == NON_LVALUE_EXPR)
         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
     exp = TREE_OPERAND (exp, 0);
 
   if (TREE_CODE (exp) == ADDR_EXPR)
-    exp = TREE_OPERAND (exp, 0);
+    {
+      exp = TREE_OPERAND (exp, 0);
+      set_mem_attributes (mem, exp, 0);
+    }
   else if (POINTER_TYPE_P (TREE_TYPE (exp)))
-    exp = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (exp)), exp);
-  else
-    return mem;
+    {
+      exp = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (exp)), exp);
+      /* memcpy, memset and other builtin stringops can alias with anything.  */
+      set_mem_alias_set (mem, 0);
+    }
 
-  set_mem_attributes (mem, exp, 0);
-  /* memcpy, memset and other builtin stringops can alias with anything.  */
-  set_mem_alias_set (mem, 0);
   return mem;
 }
 \f
@@ -773,11 +874,11 @@ static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER];
    used for calling a function.  */
 static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER];
 
-/* Return the offset of register REGNO into the block returned by 
+/* Return the offset of register REGNO into the block returned by
    __builtin_apply_args.  This is not declared static, since it is
    needed in objc-act.c.  */
 
-int 
+int
 apply_args_register_offset (regno)
      int regno;
 {
@@ -786,7 +887,7 @@ apply_args_register_offset (regno)
   /* Arguments are always put in outgoing registers (in the argument
      block) if such make sense.  */
 #ifdef OUTGOING_REGNO
-  regno = OUTGOING_REGNO(regno);
+  regno = OUTGOING_REGNO (regno);
 #endif
   return apply_args_reg_offset[regno];
 }
@@ -798,7 +899,8 @@ static int
 apply_args_size ()
 {
   static int size = -1;
-  int align, regno;
+  int align;
+  unsigned int regno;
   enum machine_mode mode;
 
   /* The values computed by this function never change.  */
@@ -834,6 +936,22 @@ apply_args_size ()
                    && have_insn_for (SET, mode))
                  best_mode = mode;
 
+           if (best_mode == VOIDmode)
+             for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
+                  mode != VOIDmode;
+                  mode = GET_MODE_WIDER_MODE (mode))
+               if (HARD_REGNO_MODE_OK (regno, mode)
+                   && have_insn_for (SET, mode))
+                 best_mode = mode;
+
+           if (best_mode == VOIDmode)
+             for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
+                  mode != VOIDmode;
+                  mode = GET_MODE_WIDER_MODE (mode))
+               if (HARD_REGNO_MODE_OK (regno, mode)
+                   && have_insn_for (SET, mode))
+                 best_mode = mode;
+
            mode = best_mode;
            if (mode == VOIDmode)
              abort ();
@@ -890,6 +1008,22 @@ apply_result_size ()
                    && have_insn_for (SET, mode))
                  best_mode = mode;
 
+           if (best_mode == VOIDmode)
+             for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
+                  mode != VOIDmode;
+                  mode = GET_MODE_WIDER_MODE (mode))
+               if (HARD_REGNO_MODE_OK (regno, mode)
+                   && have_insn_for (SET, mode))
+                 best_mode = mode;
+
+           if (best_mode == VOIDmode)
+             for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
+                  mode != VOIDmode;
+                  mode = GET_MODE_WIDER_MODE (mode))
+               if (HARD_REGNO_MODE_OK (regno, mode)
+                   && have_insn_for (SET, mode))
+                 best_mode = mode;
+
            mode = best_mode;
            if (mode == VOIDmode)
              abort ();
@@ -926,7 +1060,7 @@ result_vector (savep, result)
   enum machine_mode mode;
   rtx reg, mem;
   rtx *savevec = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
-  
+
   size = nelts = 0;
   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
     if ((mode = apply_result_mode[regno]) != VOIDmode)
@@ -1026,12 +1160,12 @@ expand_builtin_apply_args ()
 
     apply_args_value = temp;
 
-    /* Put the sequence after the NOTE that starts the function.
-       If this is inside a SEQUENCE, make the outer-level insn
+    /* Put the insns after the NOTE that starts the function.
+       If this is inside a start_sequence, make the outer-level insn
        chain current, so the code is placed at the start of the
        function.  */
     push_topmost_sequence ();
-    emit_insns_before (seq, NEXT_INSN (get_insns ()));
+    emit_insn_before (seq, NEXT_INSN (get_insns ()));
     pop_topmost_sequence ();
     return temp;
   }
@@ -1046,17 +1180,21 @@ expand_builtin_apply (function, arguments, argsize)
 {
   int size, align, regno;
   enum machine_mode mode;
-  rtx incoming_args, result, reg, dest, call_insn;
+  rtx incoming_args, result, reg, dest, src, call_insn;
   rtx old_stack_level = 0;
   rtx call_fusage = 0;
 
+#ifdef POINTERS_EXTEND_UNSIGNED
+  if (GET_MODE (arguments) != Pmode)
+    arguments = convert_memory_address (Pmode, arguments);
+#endif
+
   /* Create a block where the return registers can be saved.  */
   result = assign_stack_local (BLKmode, apply_result_size (), -1);
 
   /* Fetch the arg pointer from the ARGUMENTS block.  */
   incoming_args = gen_reg_rtx (Pmode);
-  emit_move_insn (incoming_args,
-                 gen_rtx_MEM (Pmode, arguments));
+  emit_move_insn (incoming_args, gen_rtx_MEM (Pmode, arguments));
 #ifndef STACK_GROWS_DOWNWARD
   incoming_args = expand_simple_binop (Pmode, MINUS, incoming_args, argsize,
                                       incoming_args, 0, OPTAB_LIB_WIDEN);
@@ -1085,13 +1223,16 @@ expand_builtin_apply (function, arguments, argsize)
      but it's likely that the source and/or destination addresses in
      the block copy will need updating in machine specific ways.  */
   dest = allocate_dynamic_stack_space (argsize, 0, BITS_PER_UNIT);
-  emit_block_move (gen_rtx_MEM (BLKmode, dest),
-                  gen_rtx_MEM (BLKmode, incoming_args),
-                  argsize, PARM_BOUNDARY);
+  dest = gen_rtx_MEM (BLKmode, dest);
+  set_mem_align (dest, PARM_BOUNDARY);
+  src = gen_rtx_MEM (BLKmode, incoming_args);
+  set_mem_align (src, PARM_BOUNDARY);
+  emit_block_move (dest, src, argsize, BLOCK_OP_NORMAL);
 
   /* Refer to the argument block.  */
   apply_args_size ();
   arguments = gen_rtx_MEM (BLKmode, arguments);
+  set_mem_align (arguments, PARM_BOUNDARY);
 
   /* Walk past the arg-pointer and structure value address.  */
   size = GET_MODE_SIZE (Pmode);
@@ -1121,7 +1262,7 @@ expand_builtin_apply (function, arguments, argsize)
       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);
+       use_reg (&call_fusage, struct_value_rtx);
       size += GET_MODE_SIZE (Pmode);
     }
 
@@ -1217,6 +1358,11 @@ expand_builtin_return (result)
   rtx reg;
   rtx call_fusage = 0;
 
+#ifdef POINTERS_EXTEND_UNSIGNED
+  if (GET_MODE (result) != Pmode)
+    result = convert_memory_address (Pmode, result);
+#endif
+
   apply_result_size ();
   result = gen_rtx_MEM (BLKmode, result);
 
@@ -1248,7 +1394,7 @@ expand_builtin_return (result)
       }
 
   /* Put the USE insns before the return.  */
-  emit_insns (call_fusage);
+  emit_insn (call_fusage);
 
   /* Return whatever values was restored by jumping directly to the end
      of the function.  */
@@ -1286,7 +1432,7 @@ type_to_class (type)
     default:              return no_type_class;
     }
 }
-  
+
 /* Expand a call to __builtin_classify_type with arguments found in
    ARGLIST.  */
 
@@ -1333,10 +1479,11 @@ expand_builtin_mathfn (exp, target, subtarget)
      tree exp;
      rtx target, subtarget;
 {
-  optab builtin_optab;  
+  optab builtin_optab;
   rtx op0, insns;
   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
   tree arglist = TREE_OPERAND (exp, 1);
+  enum machine_mode argmode;
 
   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
     return 0;
@@ -1375,18 +1522,26 @@ expand_builtin_mathfn (exp, target, subtarget)
     case BUILT_IN_COSF:
     case BUILT_IN_COSL:
       builtin_optab = cos_optab; break;
-    case BUILT_IN_FSQRT:
+    case BUILT_IN_SQRT:
     case BUILT_IN_SQRTF:
     case BUILT_IN_SQRTL:
       builtin_optab = sqrt_optab; break;
-     default:
+    case BUILT_IN_EXP:
+    case BUILT_IN_EXPF:
+    case BUILT_IN_EXPL:
+      builtin_optab = exp_optab; break;
+    case BUILT_IN_LOG:
+    case BUILT_IN_LOGF:
+    case BUILT_IN_LOGL:
+      builtin_optab = log_optab; break;
+    default:
       abort ();
     }
 
   /* Compute into TARGET.
      Set TARGET to wherever the result comes back.  */
-  target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
-                       builtin_optab, op0, target, 0);
+  argmode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist)));
+  target = expand_unop (argmode, builtin_optab, op0, target, 0);
 
   /* If we were unable to expand via the builtin, stop the
      sequence (without outputting the insns) and return 0, causing
@@ -1397,36 +1552,30 @@ expand_builtin_mathfn (exp, target, subtarget)
       return 0;
     }
 
-  /* If errno must be maintained and if we are not allowing unsafe
-     math optimizations, check the result.  */
+  /* If errno must be maintained, we must set it to EDOM for NaN results.  */
 
-  if (flag_errno_math && ! flag_unsafe_math_optimizations)
+  if (flag_errno_math && HONOR_NANS (argmode))
     {
       rtx lab1;
 
-      /* Don't define the builtin FP instructions
-        if your machine is not IEEE.  */
-      if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
-       abort ();
-
       lab1 = gen_label_rtx ();
 
       /* Test the result; if it is NaN, set errno=EDOM because
         the argument was not in the domain.  */
       emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
-                              0, 0, lab1);
+                              0, lab1);
 
 #ifdef TARGET_EDOM
-       {
+      {
 #ifdef GEN_ERRNO_RTX
-         rtx errno_rtx = GEN_ERRNO_RTX;
+       rtx errno_rtx = GEN_ERRNO_RTX;
 #else
-         rtx errno_rtx
-           = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
+       rtx errno_rtx
+         = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
 #endif
 
-         emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
-       }
+       emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
+      }
 #else
       /* We can't set errno=EDOM directly; let the library call do it.
         Pop the arguments right away in case the call gets deleted.  */
@@ -1441,8 +1590,8 @@ expand_builtin_mathfn (exp, target, subtarget)
   /* Output the entire sequence.  */
   insns = get_insns ();
   end_sequence ();
-  emit_insns (insns);
+  emit_insn (insns);
+
   return target;
 }
 
@@ -1503,14 +1652,7 @@ expand_builtin_strlen (exp, target)
 
       /* Mark the beginning of the strlen sequence so we can emit the
         source operand later.  */
-      before_strlen = get_last_insn();
-
-      /* Check the string is readable and has an end.  */
-      if (current_function_check_memory_usage)
-       emit_library_call (chkr_check_str_libfunc, LCT_CONST_MAKE_BLOCK,
-                          VOIDmode, 2, src_reg, Pmode,
-                          GEN_INT (MEMORY_USE_RO),
-                          TYPE_MODE (integer_type_node));
+      before_strlen = get_last_insn ();
 
       char_rtx = const0_rtx;
       char_mode = insn_data[(int) icode].operand[2].mode;
@@ -1526,11 +1668,11 @@ expand_builtin_strlen (exp, target)
 
       /* Now that we are assured of success, expand the source.  */
       start_sequence ();
-      pat = memory_address (BLKmode, 
+      pat = memory_address (BLKmode,
                            expand_expr (src, src_reg, ptr_mode, EXPAND_SUM));
       if (pat != src_reg)
        emit_move_insn (src_reg, pat);
-      pat = gen_sequence ();
+      pat = get_insns ();
       end_sequence ();
 
       if (before_strlen)
@@ -1560,8 +1702,7 @@ expand_builtin_strstr (arglist, target, mode)
      rtx target;
      enum machine_mode mode;
 {
-  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)
-      || current_function_check_memory_usage)
+  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
   else
     {
@@ -1617,8 +1758,7 @@ expand_builtin_strchr (arglist, target, mode)
      rtx target;
      enum machine_mode mode;
 {
-  if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)
-      || current_function_check_memory_usage)
+  if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
   else
     {
@@ -1664,8 +1804,7 @@ expand_builtin_strrchr (arglist, target, mode)
      rtx target;
      enum machine_mode mode;
 {
-  if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE)
-      || current_function_check_memory_usage)
+  if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
   else
     {
@@ -1719,8 +1858,7 @@ expand_builtin_strpbrk (arglist, target, mode)
      rtx target;
      enum machine_mode mode;
 {
-  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)
-      || current_function_check_memory_usage)
+  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
   else
     {
@@ -1792,11 +1930,16 @@ builtin_memcpy_read_str (data, offset, mode)
   return c_readstr (str + offset, mode);
 }
 
-/* Expand a call to the memcpy builtin, with arguments in ARGLIST.  */
+/* 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 (arglist)
+expand_builtin_memcpy (arglist, target, mode)
      tree arglist;
+     rtx target;
+     enum machine_mode mode;
 {
   if (!validate_arglist (arglist,
                         POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
@@ -1813,12 +1956,25 @@ expand_builtin_memcpy (arglist)
        = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
       rtx dest_mem, src_mem, dest_addr, len_rtx;
 
-      /* If either SRC or DEST is not a pointer type, don't do
-        this operation in-line.  */
-      if (src_align == 0 || dest_align == 0)
+      /* If DEST is not a pointer type, call the normal function.  */
+      if (dest_align == 0)
+       return 0;
+
+      /* If the LEN parameter is zero, return DEST.  */
+      if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
+       {
+         /* Evaluate and ignore SRC in case it has side-effects.  */
+         expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
+         return expand_expr (dest, target, mode, EXPAND_NORMAL);
+       }
+
+      /* 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);
+      set_mem_align (dest_mem, dest_align);
       len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
       src_str = c_getstr (src);
 
@@ -1826,7 +1982,6 @@ expand_builtin_memcpy (arglist)
         by pieces, we can avoid loading the string from memory
         and only stored the computed constants.  */
       if (src_str
-         && !current_function_check_memory_usage
          && GET_CODE (len_rtx) == CONST_INT
          && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
          && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
@@ -1835,58 +1990,63 @@ expand_builtin_memcpy (arglist)
          store_by_pieces (dest_mem, INTVAL (len_rtx),
                           builtin_memcpy_read_str,
                           (PTR) src_str, dest_align);
-         return force_operand (XEXP (dest_mem, 0), NULL_RTX);
+         dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (dest_mem) != ptr_mode)
+           dest_mem = convert_memory_address (ptr_mode, dest_mem);
+#endif
+         return dest_mem;
        }
 
       src_mem = get_memory_rtx (src);
-
-      /* Just copy the rights of SRC to the rights of DEST.  */
-      if (current_function_check_memory_usage)
-       emit_library_call (chkr_copy_bitmap_libfunc, LCT_CONST_MAKE_BLOCK,
-                          VOIDmode, 3, XEXP (dest_mem, 0), Pmode,
-                          XEXP (src_mem, 0), Pmode,
-                          len_rtx, TYPE_MODE (sizetype));
+      set_mem_align (src_mem, src_align);
 
       /* Copy word part most expediently.  */
-      dest_addr
-       = emit_block_move (dest_mem, src_mem, len_rtx,
-                          MIN (src_align, dest_align));
+      dest_addr = emit_block_move (dest_mem, src_mem, len_rtx,
+                                  BLOCK_OP_NORMAL);
 
       if (dest_addr == 0)
-       dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+       {
+         dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (dest_addr) != ptr_mode)
+           dest_addr = convert_memory_address (ptr_mode, dest_addr);
+#endif
+       }
 
       return dest_addr;
     }
 }
 
 /* Expand expression EXP, which is a call to the strcpy builtin.  Return 0
-   if we failed the caller should emit a normal call.  */
+   if we failed the caller should emit a normal call, otherwise try to get
+   the result in TARGET, if convenient (and in mode MODE if that's
+   convenient).  */
 
 static rtx
-expand_builtin_strcpy (exp)
+expand_builtin_strcpy (exp, target, mode)
      tree exp;
+     rtx target;
+     enum machine_mode mode;
 {
   tree arglist = TREE_OPERAND (exp, 1);
-  rtx result;
+  tree fn, len;
 
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
-  else
-    {
-      tree len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
 
-      if (len == 0)
-       return 0;
-
-      len = size_binop (PLUS_EXPR, len, ssize_int (1));
-      chainon (arglist, build_tree_list (NULL_TREE, len));
-    }
+  fn = built_in_decls[BUILT_IN_MEMCPY];
+  if (!fn)
+    return 0;
 
-  result = expand_builtin_memcpy (arglist);
+  len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
+  if (len == 0)
+    return 0;
 
-  if (! result)
-    TREE_CHAIN (TREE_CHAIN (arglist)) = 0;
-  return result;
+  len = size_binop (PLUS_EXPR, len, ssize_int (1));
+  chainon (arglist, build_tree_list (NULL_TREE, len));
+  return expand_expr (build_function_call_expr (fn, arglist),
+                     target, mode, EXPAND_NORMAL);
 }
 
 /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
@@ -1923,19 +2083,20 @@ expand_builtin_strncpy (arglist, target, mode)
     {
       tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+      tree fn;
 
       /* We must be passed a constant len parameter.  */
       if (TREE_CODE (len) != INTEGER_CST)
        return 0;
 
       /* If the len parameter is zero, return the dst parameter.  */
-      if (compare_tree_int (len, 0) == 0)
-        {
-       /* Evaluate and ignore the src argument in case it has
-           side-effects.  */
+      if (integer_zerop (len))
+       {
+         /* Evaluate and ignore the src argument in case it has
+            side-effects.  */
          expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), const0_rtx,
                       VOIDmode, EXPAND_NORMAL);
-         /* Return the dst parameter.  */                     
+         /* Return the dst parameter.  */
          return expand_expr (TREE_VALUE (arglist), target, mode,
                              EXPAND_NORMAL);
        }
@@ -1967,11 +2128,20 @@ expand_builtin_strncpy (arglist, target, mode)
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_strncpy_read_str,
                           (PTR) p, dest_align);
-         return force_operand (XEXP (dest_mem, 0), NULL_RTX);
+         dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (dest_mem) != ptr_mode)
+           dest_mem = convert_memory_address (ptr_mode, dest_mem);
+#endif
+         return dest_mem;
        }
-      
+
       /* OK transform into builtin memcpy.  */
-      return expand_builtin_memcpy (arglist);
+      fn = built_in_decls[BUILT_IN_MEMCPY];
+      if (!fn)
+       return 0;
+      return expand_expr (build_function_call_expr (fn, arglist),
+                         target, mode, EXPAND_NORMAL);
     }
 }
 
@@ -1993,12 +2163,44 @@ builtin_memset_read_str (data, offset, mode)
   return c_readstr (p, mode);
 }
 
+/* Callback routine for store_by_pieces.  Return the RTL of a register
+   containing GET_MODE_SIZE (MODE) consecutive copies of the unsigned
+   char value given in the RTL register data.  For example, if mode is
+   4 bytes wide, return the RTL for 0x01010101*data.  */
+
+static rtx
+builtin_memset_gen_str (data, offset, mode)
+     PTR data;
+     HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
+     enum machine_mode mode;
+{
+  rtx target, coeff;
+  size_t size;
+  char *p;
+
+  size = GET_MODE_SIZE (mode);
+  if (size == 1)
+    return (rtx) data;
+
+  p = alloca (size);
+  memset (p, 1, size);
+  coeff = c_readstr (p, mode);
+
+  target = convert_to_mode (mode, (rtx) data, 1);
+  target = expand_mult (mode, target, coeff, NULL_RTX, 1);
+  return force_reg (mode, target);
+}
+
 /* Expand expression EXP, which is a call to the memset builtin.  Return 0
-   if we failed the caller should emit a normal call.  */
+   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_memset (exp)
+expand_builtin_memset (exp, target, mode)
      tree exp;
+     rtx target;
+     enum machine_mode mode;
 {
   tree arglist = TREE_OPERAND (exp, 1);
 
@@ -2016,13 +2218,53 @@ expand_builtin_memset (exp)
        = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
       rtx dest_mem, dest_addr, len_rtx;
 
-      /* If DEST is not a pointer type, don't do this 
+      /* 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 (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
+       {
+         /* 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);
+       }
+
       if (TREE_CODE (val) != INTEGER_CST)
-       return 0;
+       {
+         rtx val_rtx;
+
+         if (!host_integerp (len, 1))
+           return 0;
+
+         if (optimize_size && tree_low_cst (len, 1) > 1)
+           return 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 (!can_store_by_pieces (tree_low_cst (len, 1),
+                                   builtin_memset_read_str,
+                                   (PTR) &c, dest_align))
+           return 0;
+
+         val = fold (build1 (CONVERT_EXPR, unsigned_char_type_node, val));
+         val_rtx = expand_expr (val, NULL_RTX, VOIDmode, 0);
+         val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
+                              val_rtx);
+         dest_mem = get_memory_rtx (dest);
+         store_by_pieces (dest_mem, tree_low_cst (len, 1),
+                          builtin_memset_gen_str,
+                          (PTR) val_rtx, dest_align);
+         dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (dest_mem) != ptr_mode)
+           dest_mem = convert_memory_address (ptr_mode, dest_mem);
+#endif
+         return dest_mem;
+       }
 
       if (target_char_cast (val, &c))
        return 0;
@@ -2031,36 +2273,37 @@ expand_builtin_memset (exp)
        {
          if (!host_integerp (len, 1))
            return 0;
-         if (current_function_check_memory_usage
-             || !can_store_by_pieces (tree_low_cst (len, 1),
-                                      builtin_memset_read_str,
-                                      (PTR) &c, dest_align))
+         if (!can_store_by_pieces (tree_low_cst (len, 1),
+                                   builtin_memset_read_str, (PTR) &c,
+                                   dest_align))
            return 0;
 
          dest_mem = get_memory_rtx (dest);
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_memset_read_str,
                           (PTR) &c, dest_align);
-         return force_operand (XEXP (dest_mem, 0), NULL_RTX);
+         dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (dest_mem) != ptr_mode)
+           dest_mem = convert_memory_address (ptr_mode, dest_mem);
+#endif
+         return dest_mem;
        }
 
       len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
 
       dest_mem = get_memory_rtx (dest);
-          
-      /* Just check DST is writable and mark it as readable.  */
-      if (current_function_check_memory_usage)
-       emit_library_call (chkr_check_addr_libfunc, LCT_CONST_MAKE_BLOCK,
-                          VOIDmode, 3, XEXP (dest_mem, 0), Pmode,
-                          len_rtx, TYPE_MODE (sizetype),
-                          GEN_INT (MEMORY_USE_WO),
-                          TYPE_MODE (integer_type_node));
-
-
-      dest_addr = clear_storage (dest_mem, len_rtx, dest_align);
+      set_mem_align (dest_mem, dest_align);
+      dest_addr = clear_storage (dest_mem, len_rtx);
 
       if (dest_addr == 0)
-       dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+       {
+         dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (dest_addr) != ptr_mode)
+           dest_addr = convert_memory_address (ptr_mode, dest_addr);
+#endif
+       }
 
       return dest_addr;
     }
@@ -2082,49 +2325,92 @@ expand_builtin_bzero (exp)
 
   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).  */
-  
+     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, convert (sizetype, size));
   newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
   newarglist = tree_cons (NULL_TREE, dest, newarglist);
 
   TREE_OPERAND (exp, 1) = newarglist;
-  result = expand_builtin_memset(exp);
-      
+  result = expand_builtin_memset (exp, const0_rtx, VOIDmode);
+
   /* Always restore the original arguments.  */
   TREE_OPERAND (exp, 1) = arglist;
 
   return result;
 }
 
-#ifdef HAVE_cmpstrsi
-
 /* Expand expression EXP, which is a call to the memcmp or the strcmp builtin.
    ARGLIST is the argument list for this call.  Return 0 if we failed and the
    caller should emit a normal call, otherwise try to get the result in
-   TARGET, if convenient.  */
+   TARGET, if convenient (and in mode MODE, if that's convenient).  */
 
 static rtx
-expand_builtin_memcmp (exp, arglist, target)
-     tree exp;
+expand_builtin_memcmp (exp, arglist, target, mode)
+     tree exp ATTRIBUTE_UNUSED;
      tree arglist;
      rtx target;
+     enum machine_mode mode;
 {
-  /* If we need to check memory accesses, call the library function.  */
-  if (current_function_check_memory_usage)
-    return 0;
+  tree arg1, arg2, len;
+  const char *p1, *p2;
 
   if (!validate_arglist (arglist,
-                     POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+                        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 (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
+    {
+      /* Evaluate and ignore arg1 and arg2 in case they have
+         side-effects.  */
+      expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
+      expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
+      return const0_rtx;
+    }
+
+  p1 = c_getstr (arg1);
+  p2 = c_getstr (arg2);
+
+  /* If all arguments are constant, and the value of len is not greater
+     than the lengths of arg1 and arg2, evaluate at compile-time.  */
+  if (host_integerp (len, 1) && p1 && p2
+      && compare_tree_int (len, strlen (p1) + 1) <= 0
+      && compare_tree_int (len, strlen (p2) + 1) <= 0)
+    {
+      const int r = memcmp (p1, p2, tree_low_cst (len, 1));
+
+      return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
+    }
+
+  /* If len parameter is one, return an expression corresponding to
+     (*(const unsigned char*)arg1 - (const unsigned char*)arg2).  */
+  if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
+    {
+      tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
+      tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
+      tree ind1 =
+      fold (build1 (CONVERT_EXPR, integer_type_node,
+                   build1 (INDIRECT_REF, cst_uchar_node,
+                           build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
+      tree ind2 =
+      fold (build1 (CONVERT_EXPR, integer_type_node,
+                   build1 (INDIRECT_REF, cst_uchar_node,
+                           build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
+      tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
+      return expand_expr (result, target, mode, EXPAND_NORMAL);
+    }
+
+#ifdef HAVE_cmpstrsi
   {
-    enum machine_mode mode;
-    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;
@@ -2179,9 +2465,11 @@ expand_builtin_memcmp (exp, arglist, target)
     else
       return convert_to_mode (mode, result, 0);
   }
-}
 #endif
 
+  return 0;
+}
+
 /* Expand expression EXP, which is a call to the strcmp builtin.  Return 0
    if we failed the caller should emit a normal call, otherwise try to get
    the result in TARGET, if convenient.  */
@@ -2193,13 +2481,9 @@ expand_builtin_strcmp (exp, target, mode)
      enum machine_mode mode;
 {
   tree arglist = TREE_OPERAND (exp, 1);
-  tree arg1, arg2;
+  tree arg1, arg2, len, len2, fn;
   const char *p1, *p2;
 
-  /* If we need to check memory accesses, call the library function.  */
-  if (current_function_check_memory_usage)
-    return 0;
-
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
 
@@ -2232,59 +2516,50 @@ expand_builtin_strcmp (exp, target, mode)
       tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
       return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
-  
-#ifdef HAVE_cmpstrsi
-  if (! HAVE_cmpstrsi)
-    return 0;
 
-  {
-    tree len = c_strlen (arg1);
-    tree len2 = c_strlen (arg2);
-    rtx result;
+  len = c_strlen (arg1);
+  len2 = c_strlen (arg2);
 
-    if (len)
-      len = size_binop (PLUS_EXPR, ssize_int (1), len);
+  if (len)
+    len = size_binop (PLUS_EXPR, ssize_int (1), len);
 
-    if (len2)
-      len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
+  if (len2)
+    len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
 
-    /* If we don't have a constant length for the first, use the length
-       of the second, if we know it.  We don't require a constant for
-       this case; some cost analysis could be done if both are available
-       but neither is constant.  For now, assume they're equally cheap
-       unless one has side effects.
+  /* If we don't have a constant length for the first, use the length
+     of the second, if we know it.  We don't require a constant for
+     this case; some cost analysis could be done if both are available
+     but neither is constant.  For now, assume they're equally cheap
+     unless one has side effects.
 
-       If both strings have constant lengths, use the smaller.  This
-       could arise if optimization results in strcpy being called with
-       two fixed strings, or if the code was machine-generated.  We should
-       add some code to the `memcmp' handler below to deal with such
-       situations, someday.  */
+     If both strings have constant lengths, use the smaller.  This
+     could arise if optimization results in strcpy being called with
+     two fixed strings, or if the code was machine-generated.  We should
+     add some code to the `memcmp' handler below to deal with such
+     situations, someday.  */
 
-    if (!len || TREE_CODE (len) != INTEGER_CST)
-      {
-       if (len2 && !TREE_SIDE_EFFECTS (len2))
-         len = len2;
-       else if (len == 0)
-         return 0;
-      }
-    else if (len2 && TREE_CODE (len2) == INTEGER_CST
-            && tree_int_cst_lt (len2, len))
-      len = len2;
+  if (!len || TREE_CODE (len) != INTEGER_CST)
+    {
+      if (len2 && !TREE_SIDE_EFFECTS (len2))
+       len = len2;
+      else if (len == 0)
+       return 0;
+    }
+  else if (len2 && TREE_CODE (len2) == INTEGER_CST
+          && tree_int_cst_lt (len2, len))
+    len = len2;
 
-    /* If both arguments have side effects, we cannot optimize.  */
-    if (TREE_SIDE_EFFECTS (len))
-      return 0;
+  /* If both arguments have side effects, we cannot optimize.  */
+  if (TREE_SIDE_EFFECTS (len))
+    return 0;
 
-    chainon (arglist, build_tree_list (NULL_TREE, len));
-    result = expand_builtin_memcmp (exp, arglist, target);
-    if (! result)
-      TREE_CHAIN (TREE_CHAIN (arglist)) = 0;
+  fn = built_in_decls[BUILT_IN_MEMCMP];
+  if (!fn)
+    return 0;
 
-    return result;
-  }
-#else
-  return 0;
-#endif
+  chainon (arglist, build_tree_list (NULL_TREE, len));
+  return expand_expr (build_function_call_expr (fn, arglist),
+                     target, mode, EXPAND_NORMAL);
 }
 
 /* Expand expression EXP, which is a call to the strncmp builtin.  Return 0
@@ -2298,13 +2573,10 @@ expand_builtin_strncmp (exp, target, mode)
      enum machine_mode mode;
 {
   tree arglist = TREE_OPERAND (exp, 1);
+  tree fn, newarglist, len = 0;
   tree arg1, arg2, arg3;
   const char *p1, *p2;
 
-  /* If we need to check memory accesses, call the library function.  */
-  if (current_function_check_memory_usage)
-    return 0;
-
   if (!validate_arglist (arglist,
                         POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
@@ -2315,23 +2587,23 @@ expand_builtin_strncmp (exp, target, mode)
 
   /* If the len parameter is zero, return zero.  */
   if (host_integerp (arg3, 1) && tree_low_cst (arg3, 1) == 0)
-  {
-    /* Evaluate and ignore arg1 and arg2 in case they have
-       side-effects.  */
-    expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
-    expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
-    return const0_rtx;
-  }
+    {
+      /* Evaluate and ignore arg1 and arg2 in case they have
+        side-effects.  */
+      expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
+      expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
+      return const0_rtx;
+    }
 
   p1 = c_getstr (arg1);
   p2 = c_getstr (arg2);
 
   /* If all arguments are constant, evaluate at compile-time.  */
   if (host_integerp (arg3, 1) && p1 && p2)
-  {
-    const int r = strncmp (p1, p2, tree_low_cst (arg3, 1));
-    return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
-  }
+    {
+      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 (*(const u_char*)arg1 - *(const u_char*)arg2).  */
@@ -2354,45 +2626,42 @@ expand_builtin_strncmp (exp, target, mode)
       return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
 
-#ifdef HAVE_cmpstrsi
   /* 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
-  
-  return 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;
+
+  fn = built_in_decls[BUILT_IN_MEMCMP];
+  if (!fn)
+    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_expr (build_function_call_expr (fn, newarglist),
+                     target, mode, EXPAND_NORMAL);
 }
 
 /* Expand expression EXP, which is a call to the strcat builtin.
@@ -2405,10 +2674,6 @@ expand_builtin_strcat (arglist, target, mode)
      rtx target;
      enum machine_mode mode;
 {
-  /* If we need to check memory accesses, call the library function.  */
-  if (current_function_check_memory_usage)
-    return 0;
-
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
   else
@@ -2435,10 +2700,6 @@ expand_builtin_strncat (arglist, target, mode)
      rtx target;
      enum machine_mode mode;
 {
-  /* If we need to check memory accesses, call the library function.  */
-  if (current_function_check_memory_usage)
-    return 0;
-
   if (!validate_arglist (arglist,
                         POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
@@ -2451,9 +2712,8 @@ expand_builtin_strncat (arglist, target, mode)
 
       /* If the requested length is zero, or the src parameter string
           length is zero, return the dst parameter.  */
-      if ((TREE_CODE (len) == INTEGER_CST && compare_tree_int (len, 0) == 0)
-         || (p && *p == '\0'))
-        {
+      if (integer_zerop (len) || (p && *p == '\0'))
+       {
          /* Evaluate and ignore the src and len parameters in case
             they have side-effects.  */
          expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -2465,11 +2725,11 @@ expand_builtin_strncat (arglist, target, mode)
          length, call strcat.  */
       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)),
-           fn = built_in_decls[BUILT_IN_STRCAT];
-         
+       {
+         tree newarglist
+           = tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src));
+         tree fn = built_in_decls[BUILT_IN_STRCAT];
+
          /* If the replacement _DECL isn't initialized, don't do the
             transformation.  */
          if (!fn)
@@ -2492,27 +2752,23 @@ expand_builtin_strspn (arglist, target, mode)
      rtx target;
      enum machine_mode mode;
 {
-  /* If we need to check memory accesses, call the library function.  */
-  if (current_function_check_memory_usage)
-    return 0;
-
   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.  */
       if (p1 && p2)
-        {
+       {
          const size_t r = strspn (p1, p2);
          return expand_expr (size_int (r), target, mode, EXPAND_NORMAL);
        }
-      
+
       /* If either argument is "", return 0.  */
       if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
-        {
+       {
          /* Evaluate and ignore both arguments in case either one has
             side-effects.  */
          expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -2533,27 +2789,23 @@ expand_builtin_strcspn (arglist, target, mode)
      rtx target;
      enum machine_mode mode;
 {
-  /* If we need to check memory accesses, call the library function.  */
-  if (current_function_check_memory_usage)
-    return 0;
-
   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.  */
       if (p1 && p2)
-        {
+       {
          const size_t r = strcspn (p1, p2);
          return expand_expr (size_int (r), target, mode, EXPAND_NORMAL);
        }
-      
+
       /* If the first argument is "", return 0.  */
       if (p1 && *p1 == '\0')
-        {
+       {
          /* Evaluate and ignore argument s2 in case it has
             side-effects.  */
          expand_expr (s2, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -2562,10 +2814,10 @@ expand_builtin_strcspn (arglist, target, mode)
 
       /* If the second argument is "", return __builtin_strlen(s1).  */
       if (p2 && *p2 == '\0')
-        {
+       {
          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
             transformation.  */
          if (!fn)
@@ -2618,11 +2870,11 @@ expand_builtin_saveregs ()
 
   saveregs_value = val;
 
-  /* Put the sequence after the NOTE that starts the function.  If this
-     is inside a SEQUENCE, make the outer-level insn chain current, so
+  /* Put the insns after the NOTE that starts the function.  If this
+     is inside a start_sequence, make the outer-level insn chain current, so
      the code is placed at the start of the function.  */
   push_topmost_sequence ();
-  emit_insns_after (seq, get_insns ());
+  emit_insn_after (seq, get_insns ());
   pop_topmost_sequence ();
 
   return val;
@@ -2639,7 +2891,7 @@ expand_builtin_args_info (exp)
   tree arglist = TREE_OPERAND (exp, 1);
   int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
   int *word_ptr = (int *) &current_function_args_info;
-#if 0  
+#if 0
   /* These are used by the code below that is if 0'ed away */
   int i;
   tree type, elts, result;
@@ -2678,7 +2930,7 @@ expand_builtin_args_info (exp)
   TREE_STATIC (result) = 1;
   result = build1 (INDIRECT_REF, build_pointer_type (type), result);
   TREE_CONSTANT (result) = 1;
-  return expand_expr (result, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_BAD);
+  return expand_expr (result, NULL_RTX, VOIDmode, 0);
 #endif
 }
 
@@ -2690,10 +2942,9 @@ expand_builtin_next_arg (arglist)
 {
   tree fntype = TREE_TYPE (current_function_decl);
 
-  if ((TYPE_ARG_TYPES (fntype) == 0
-       || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
-          == void_type_node))
-      && ! current_function_varargs)
+  if (TYPE_ARG_TYPES (fntype) == 0
+      || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
+         == void_type_node))
     {
       error ("`va_start' used in function with fixed args");
       return const0_rtx;
@@ -2705,7 +2956,7 @@ expand_builtin_next_arg (arglist)
       tree arg = TREE_VALUE (arglist);
 
       /* Strip off all nops for the sake of the comparison.  This
-        is not quite the same as STRIP_NOPS.  It does more.  
+        is not quite the same as STRIP_NOPS.  It does more.
         We must also strip off INDIRECT_EXPR for C++ reference
         parameters.  */
       while (TREE_CODE (arg) == NOP_EXPR
@@ -2716,7 +2967,7 @@ expand_builtin_next_arg (arglist)
       if (arg != last_parm)
        warning ("second parameter of `va_start' not last named argument");
     }
-  else if (! current_function_varargs)
+  else
     /* Evidently an out of date version of <stdarg.h>; can't validate
        va_start's second argument, but can still work as intended.  */
     warning ("`__builtin_next_arg' called without an argument");
@@ -2746,10 +2997,10 @@ stabilize_va_list (valist, needs_lvalue)
         So fix it.  */
       if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
        {
-         tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
-         tree p2 = build_pointer_type (va_list_type_node);
+         tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
+         tree p2 = build_pointer_type (va_list_type_node);
 
-         valist = build1 (ADDR_EXPR, p2, valist);
+         valist = build1 (ADDR_EXPR, p2, valist);
          valist = fold (build1 (NOP_EXPR, p1, valist));
        }
     }
@@ -2761,7 +3012,7 @@ stabilize_va_list (valist, needs_lvalue)
        {
          if (! TREE_SIDE_EFFECTS (valist))
            return valist;
-         
+
          pt = build_pointer_type (va_list_type_node);
          valist = fold (build1 (ADDR_EXPR, pt, valist));
          TREE_SIDE_EFFECTS (valist) = 1;
@@ -2780,25 +3031,12 @@ stabilize_va_list (valist, needs_lvalue)
    the variable.  */
 
 void
-std_expand_builtin_va_start (stdarg_p, valist, nextarg)
-     int stdarg_p;
+std_expand_builtin_va_start (valist, nextarg)
      tree valist;
      rtx nextarg;
 {
   tree t;
 
-  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 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);
-    }
-
   t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
             make_tree (ptr_type_node, nextarg));
   TREE_SIDE_EFFECTS (t) = 1;
@@ -2806,31 +3044,27 @@ std_expand_builtin_va_start (stdarg_p, valist, nextarg)
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 }
 
-/* Expand ARGLIST, which from a call to __builtin_stdarg_va_start or
-   __builtin_varargs_va_start, depending on STDARG_P.  */
+/* Expand ARGLIST, from a call to __builtin_va_start.  */
 
 static rtx
-expand_builtin_va_start (stdarg_p, arglist)
-     int stdarg_p;
+expand_builtin_va_start (arglist)
      tree arglist;
 {
   rtx nextarg;
-  tree chain = arglist, valist;
+  tree chain, valist;
 
-  if (stdarg_p)
-    nextarg = expand_builtin_next_arg (chain = TREE_CHAIN (arglist));
-  else
-    nextarg = expand_builtin_next_arg (NULL_TREE);
+  chain = TREE_CHAIN (arglist);
 
   if (TREE_CHAIN (chain))
     error ("too many arguments to function `va_start'");
 
+  nextarg = expand_builtin_next_arg (chain);
   valist = stabilize_va_list (TREE_VALUE (arglist), 1);
 
 #ifdef EXPAND_BUILTIN_VA_START
-  EXPAND_BUILTIN_VA_START (stdarg_p, valist, nextarg);
+  EXPAND_BUILTIN_VA_START (valist, nextarg);
 #else
-  std_expand_builtin_va_start (stdarg_p, valist, nextarg);
+  std_expand_builtin_va_start (valist, nextarg);
 #endif
 
   return const0_rtx;
@@ -2843,37 +3077,54 @@ rtx
 std_expand_builtin_va_arg (valist, type)
      tree valist, type;
 {
-  tree addr_tree, t;
-  HOST_WIDE_INT align;
-  HOST_WIDE_INT rounded_size;
+  tree addr_tree, t, type_size = NULL;
+  tree align, alignm1;
+  tree rounded_size;
   rtx addr;
 
   /* Compute the rounded size of the type.  */
-  align = PARM_BOUNDARY / BITS_PER_UNIT;
-  rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
+  align = size_int (PARM_BOUNDARY / BITS_PER_UNIT);
+  alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1);
+  if (type == error_mark_node
+      || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL
+      || TREE_OVERFLOW (type_size))
+    rounded_size = size_zero_node;
+  else
+    rounded_size = fold (build (MULT_EXPR, sizetype,
+                               fold (build (TRUNC_DIV_EXPR, sizetype,
+                                            fold (build (PLUS_EXPR, sizetype,
+                                                         type_size, alignm1)),
+                                            align)),
+                               align));
 
   /* Get AP.  */
   addr_tree = valist;
-  if (PAD_VARARGS_DOWN)
+  if (PAD_VARARGS_DOWN && ! integer_zerop (rounded_size))
     {
       /* Small args are padded downward.  */
-
-      HOST_WIDE_INT adj
-       = rounded_size > align ? rounded_size : int_size_in_bytes (type);
-
-      addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
-                        build_int_2 (rounded_size - adj, 0));
+      addr_tree = fold (build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
+                              fold (build (COND_EXPR, sizetype,
+                                           fold (build (GT_EXPR, sizetype,
+                                                        rounded_size,
+                                                        align)),
+                                           size_zero_node,
+                                           fold (build (MINUS_EXPR, sizetype,
+                                                        rounded_size,
+                                                        type_size))))));
     }
 
   addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
   addr = copy_to_reg (addr);
 
   /* Compute new value for AP.  */
-  t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
-            build (PLUS_EXPR, TREE_TYPE (valist), valist,
-                   build_int_2 (rounded_size, 0)));
-  TREE_SIDE_EFFECTS (t) = 1;
-  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+  if (! integer_zerop (rounded_size))
+    {
+      t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
+                build (PLUS_EXPR, TREE_TYPE (valist), valist,
+                       rounded_size));
+      TREE_SIDE_EFFECTS (t) = 1;
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+    }
 
   return addr;
 }
@@ -2894,7 +3145,7 @@ expand_builtin_va_arg (valist, type)
   have_va_type = TREE_TYPE (valist);
   if (TREE_CODE (want_va_type) == ARRAY_TYPE)
     {
-      /* If va_list is an array type, the argument may have decayed 
+      /* If va_list is an array type, the argument may have decayed
         to a pointer type, e.g. by being passed to another function.
          In that case, unwrap both types so that we can compare the
         underlying records.  */
@@ -2913,10 +3164,11 @@ expand_builtin_va_arg (valist, type)
 
   /* Generate a diagnostic for requesting data of a type that cannot
      be passed through `...' due to type promotion at the call site.  */
-  else if ((promoted_type = (*lang_type_promotes_to) (type)) != NULL_TREE)
+  else if ((promoted_type = (*lang_hooks.types.type_promotes_to) (type))
+          != type)
     {
       const char *name = "<anonymous type>", *pname = 0;
-      static int gave_help;
+      static bool gave_help;
 
       if (TYPE_NAME (type))
        {
@@ -2935,13 +3187,24 @@ expand_builtin_va_arg (valist, type)
            pname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (promoted_type)));
        }
 
-      error ("`%s' is promoted to `%s' when passed through `...'", name, pname);
+      /* Unfortunately, this is merely undefined, rather than a constraint
+        violation, so we cannot make this an error.  If this call is never
+        executed, the program is still strictly conforming.  */
+      warning ("`%s' is promoted to `%s' when passed through `...'",
+              name, pname);
       if (! gave_help)
        {
-         gave_help = 1;
-         error ("(so you should pass `%s' not `%s' to `va_arg')", pname, name);
+         gave_help = true;
+         warning ("(so you should pass `%s' not `%s' to `va_arg')",
+                  pname, name);
        }
 
+      /* We can, however, treat "undefined" any way we please.
+        Call abort to encourage the user to fix the program.  */
+      expand_builtin_trap ();
+
+      /* This is dead code, but go ahead and finish so that the
+        mode of the result comes out right.  */
       addr = const0_rtx;
     }
   else
@@ -2957,6 +3220,11 @@ expand_builtin_va_arg (valist, type)
 #endif
     }
 
+#ifdef POINTERS_EXTEND_UNSIGNED
+  if (GET_MODE (addr) != Pmode)
+    addr = convert_memory_address (Pmode, addr);
+#endif
+
   result = gen_rtx_MEM (TYPE_MODE (type), addr);
   set_mem_alias_set (result, get_varargs_alias_set ());
 
@@ -2973,7 +3241,7 @@ expand_builtin_va_end (arglist)
 
 #ifdef EXPAND_BUILTIN_VA_END
   valist = stabilize_va_list (valist, 0);
-  EXPAND_BUILTIN_VA_END(arglist);
+  EXPAND_BUILTIN_VA_END (arglist);
 #else
   /* Evaluate for side effects, if needed.  I hate macros that don't
      do that.  */
@@ -2984,7 +3252,7 @@ expand_builtin_va_end (arglist)
   return const0_rtx;
 }
 
-/* Expand ARGLIST, from a call to __builtin_va_copy.  We do this as a 
+/* 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.  */
 
@@ -3016,14 +3284,24 @@ expand_builtin_va_copy (arglist)
       size = expand_expr (TYPE_SIZE_UNIT (va_list_type_node), NULL_RTX,
                          VOIDmode, EXPAND_NORMAL);
 
+#ifdef POINTERS_EXTEND_UNSIGNED
+      if (GET_MODE (dstb) != Pmode)
+       dstb = convert_memory_address (Pmode, dstb);
+
+      if (GET_MODE (srcb) != Pmode)
+       srcb = convert_memory_address (Pmode, srcb);
+#endif
+
       /* "Dereference" to BLKmode memories.  */
       dstb = gen_rtx_MEM (BLKmode, dstb);
       set_mem_alias_set (dstb, get_alias_set (TREE_TYPE (TREE_TYPE (dst))));
+      set_mem_align (dstb, TYPE_ALIGN (va_list_type_node));
       srcb = gen_rtx_MEM (BLKmode, srcb);
       set_mem_alias_set (srcb, get_alias_set (TREE_TYPE (TREE_TYPE (src))));
+      set_mem_align (srcb, TYPE_ALIGN (va_list_type_node));
 
       /* Copy.  */
-      emit_block_move (dstb, srcb, size, TYPE_ALIGN (va_list_type_node));
+      emit_block_move (dstb, srcb, size, BLOCK_OP_NORMAL);
     }
 
   return const0_rtx;
@@ -3103,7 +3381,8 @@ expand_builtin_alloca (arglist, target)
   result = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
 
 #ifdef POINTERS_EXTEND_UNSIGNED
-  result = convert_memory_address (ptr_mode, result);
+  if (GET_MODE (result) != ptr_mode)
+    result = convert_memory_address (ptr_mode, result);
 #endif
 
   return result;
@@ -3138,12 +3417,16 @@ expand_builtin_ffs (arglist, target, subtarget)
    long, we attempt to transform this call into __builtin_fputc().  */
 
 static rtx
-expand_builtin_fputs (arglist, ignore)
+expand_builtin_fputs (arglist, ignore, unlocked)
      tree arglist;
      int ignore;
+     int unlocked;
 {
-  tree len, fn, fn_fputc = built_in_decls[BUILT_IN_FPUTC],
-    fn_fwrite = built_in_decls[BUILT_IN_FWRITE];
+  tree len, fn;
+  tree fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
+    : built_in_decls[BUILT_IN_FPUTC];
+  tree fn_fwrite = unlocked ? built_in_decls[BUILT_IN_FWRITE_UNLOCKED]
+    : built_in_decls[BUILT_IN_FWRITE];
 
   /* If the return value is used, or the replacement _DECL isn't
      initialized, don't do the transformation.  */
@@ -3151,8 +3434,7 @@ expand_builtin_fputs (arglist, ignore)
     return 0;
 
   /* Verify the arguments in the original call.  */
-  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)
-      || current_function_check_memory_usage)
+  if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
 
   /* Get the length of the string passed to fputs.  If the length
@@ -3176,7 +3458,7 @@ expand_builtin_fputs (arglist, ignore)
        const char *p = c_getstr (TREE_VALUE (arglist));
 
        if (p != NULL)
-         {      
+         {
            /* New argument list transforming fputs(string, stream) to
               fputc(string[0], stream).  */
            arglist =
@@ -3191,7 +3473,7 @@ expand_builtin_fputs (arglist, ignore)
     case 1: /* length is greater than 1, call fwrite.  */
       {
        tree 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)));
@@ -3202,9 +3484,9 @@ expand_builtin_fputs (arglist, ignore)
        break;
       }
     default:
-      abort();
+      abort ();
     }
-  
+
   return expand_expr (build_function_call_expr (fn, arglist),
                      (ignore ? const0_rtx : NULL_RTX),
                      VOIDmode, EXPAND_NORMAL);
@@ -3243,7 +3525,7 @@ expand_builtin_expect (arglist, target)
         moderately sure to be able to correctly interpret the branch
         condition later.  */
       target = force_reg (GET_MODE (target), target);
-  
+
       rtx_c = expand_expr (c, NULL_RTX, GET_MODE (target), EXPAND_NORMAL);
 
       note = emit_note (NULL, NOTE_INSN_EXPECTED_VALUE);
@@ -3255,7 +3537,7 @@ expand_builtin_expect (arglist, 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
+   a list 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.  */
@@ -3276,8 +3558,8 @@ expand_builtin_expect_jump (exp, if_false_label, if_true_label)
   if (TREE_CODE (TREE_TYPE (arg1)) == INTEGER_TYPE
       && (integer_zerop (arg1) || integer_onep (arg1)))
     {
-      int j;
       int num_jumps = 0;
+      rtx insn;
 
       /* If we fail to locate an appropriate conditional jump, we'll
         fall back to normal evaluation.  Ensure that the expression
@@ -3298,16 +3580,17 @@ expand_builtin_expect_jump (exp, if_false_label, if_true_label)
       /* Expand the jump insns.  */
       start_sequence ();
       do_jump (arg0, if_false_label, if_true_label);
-      ret = gen_sequence ();
+      ret = get_insns ();
       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++)
+      insn = ret;
+      while (insn != NULL_RTX)
        {
-         rtx insn = XVECEXP (ret, 0, j);
+         rtx next = NEXT_INSN (insn);
          rtx pattern;
 
          if (GET_CODE (insn) == JUMP_INSN && any_condjump_p (insn)
@@ -3318,7 +3601,7 @@ expand_builtin_expect_jump (exp, if_false_label, if_true_label)
              int taken;
 
              if (GET_CODE (ifelse) != IF_THEN_ELSE)
-               continue;
+               goto do_next_insn;
 
              if (GET_CODE (XEXP (ifelse, 1)) == LABEL_REF)
                {
@@ -3345,7 +3628,7 @@ expand_builtin_expect_jump (exp, if_false_label, if_true_label)
                  label = NULL_RTX;
                }
              else
-               continue;
+               goto do_next_insn;
 
              /* If the test is expected to fail, reverse the
                 probabilities.  */
@@ -3359,11 +3642,14 @@ expand_builtin_expect_jump (exp, if_false_label, if_true_label)
              else if (label == if_false_label)
                taken = 1 - taken;
              else if (label != if_true_label)
-               continue;
+               goto do_next_insn;
 
              num_jumps++;
              predict_insn_def (insn, PRED_BUILTIN_EXPECT, taken);
            }
+
+       do_next_insn:
+         insn = next;
        }
 
       /* If no jumps were modified, fail and do __builtin_expect the normal
@@ -3374,6 +3660,18 @@ expand_builtin_expect_jump (exp, if_false_label, if_true_label)
 
   return ret;
 }
+
+void
+expand_builtin_trap ()
+{
+#ifdef HAVE_trap
+  if (HAVE_trap)
+    emit_insn (gen_trap ());
+  else
+#endif
+    emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0);
+  emit_barrier ();
+}
 \f
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
@@ -3395,27 +3693,62 @@ expand_builtin (exp, target, subtarget, mode, ignore)
 
   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
     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_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
-         || fcode == BUILT_IN_STRCHR || fcode == BUILT_IN_STRRCHR
-         || fcode == BUILT_IN_STRLEN || fcode == BUILT_IN_STRCPY
-         || fcode == BUILT_IN_STRNCPY || fcode == BUILT_IN_STRNCMP
-         || fcode == BUILT_IN_STRSTR || fcode == BUILT_IN_STRPBRK
-         || fcode == BUILT_IN_STRCAT || fcode == BUILT_IN_STRNCAT
-         || fcode == BUILT_IN_STRSPN || fcode == BUILT_IN_STRCSPN
-         || fcode == BUILT_IN_STRCMP || fcode == BUILT_IN_FFS
-         || fcode == BUILT_IN_PUTCHAR || fcode == BUILT_IN_PUTS
-         || fcode == BUILT_IN_PRINTF || fcode == BUILT_IN_FPUTC
-         || fcode == BUILT_IN_FPUTS || fcode == BUILT_IN_FWRITE))
-    return expand_call (exp, target, ignore);
+  if (!optimize && !CALLED_AS_BUILT_IN (fndecl))
+    switch (fcode)
+      {
+      case BUILT_IN_SQRT:
+      case BUILT_IN_SQRTF:
+      case BUILT_IN_SQRTL:
+      case BUILT_IN_SIN:
+      case BUILT_IN_SINF:
+      case BUILT_IN_SINL:
+      case BUILT_IN_COS:
+      case BUILT_IN_COSF:
+      case BUILT_IN_COSL:
+      case BUILT_IN_EXP:
+      case BUILT_IN_EXPF:
+      case BUILT_IN_EXPL:
+      case BUILT_IN_MEMSET:
+      case BUILT_IN_MEMCPY:
+      case BUILT_IN_MEMCMP:
+      case BUILT_IN_BCMP:
+      case BUILT_IN_BZERO:
+      case BUILT_IN_INDEX:
+      case BUILT_IN_RINDEX:
+      case BUILT_IN_STRCHR:
+      case BUILT_IN_STRRCHR:
+      case BUILT_IN_STRLEN:
+      case BUILT_IN_STRCPY:
+      case BUILT_IN_STRNCPY:
+      case BUILT_IN_STRNCMP:
+      case BUILT_IN_STRSTR:
+      case BUILT_IN_STRPBRK:
+      case BUILT_IN_STRCAT:
+      case BUILT_IN_STRNCAT:
+      case BUILT_IN_STRSPN:
+      case BUILT_IN_STRCSPN:
+      case BUILT_IN_STRCMP:
+      case BUILT_IN_FFS:
+      case BUILT_IN_PUTCHAR:
+      case BUILT_IN_PUTS:
+      case BUILT_IN_PRINTF:
+      case BUILT_IN_FPUTC:
+      case BUILT_IN_FPUTS:
+      case BUILT_IN_FWRITE:
+      case BUILT_IN_PUTCHAR_UNLOCKED:
+      case BUILT_IN_PUTS_UNLOCKED:
+      case BUILT_IN_PRINTF_UNLOCKED:
+      case BUILT_IN_FPUTC_UNLOCKED:
+      case BUILT_IN_FPUTS_UNLOCKED:
+      case BUILT_IN_FWRITE_UNLOCKED:
+       return expand_call (exp, target, ignore);
+
+      default:
+       break;
+      }
 
   switch (fcode)
     {
@@ -3448,11 +3781,17 @@ expand_builtin (exp, target, subtarget, mode, ignore)
     case BUILT_IN_COS:
     case BUILT_IN_COSF:
     case BUILT_IN_COSL:
+    case BUILT_IN_EXP:
+    case BUILT_IN_EXPF:
+    case BUILT_IN_EXPL:
+    case BUILT_IN_LOG:
+    case BUILT_IN_LOGF:
+    case BUILT_IN_LOGL:
       /* 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_SQRT:
     case BUILT_IN_SQRTF:
     case BUILT_IN_SQRTL:
       target = expand_builtin_mathfn (exp, target, subtarget);
@@ -3460,9 +3799,6 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        return target;
       break;
 
-    case BUILT_IN_FMOD:
-      break;
-
     case BUILT_IN_APPLY_ARGS:
       return expand_builtin_apply_args ();
 
@@ -3527,11 +3863,11 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        0 otherwise.  */
     case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
       if (arglist != 0
-          || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
-          || GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) != MEM)
-        return const0_rtx;
+         || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
+         || GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) != MEM)
+       return const0_rtx;
       else
-        return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
+       return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
 
     case BUILT_IN_ALLOCA:
       target = expand_builtin_alloca (arglist, target);
@@ -3552,53 +3888,53 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       break;
 
     case BUILT_IN_STRCPY:
-      target = expand_builtin_strcpy (exp);
+      target = expand_builtin_strcpy (exp, target, mode);
       if (target)
        return target;
       break;
-      
+
     case BUILT_IN_STRNCPY:
       target = expand_builtin_strncpy (arglist, target, mode);
       if (target)
        return target;
       break;
-      
+
     case BUILT_IN_STRCAT:
       target = expand_builtin_strcat (arglist, target, mode);
       if (target)
        return target;
       break;
-      
+
     case BUILT_IN_STRNCAT:
       target = expand_builtin_strncat (arglist, target, mode);
       if (target)
        return target;
       break;
-      
+
     case BUILT_IN_STRSPN:
       target = expand_builtin_strspn (arglist, target, mode);
       if (target)
        return target;
       break;
-      
+
     case BUILT_IN_STRCSPN:
       target = expand_builtin_strcspn (arglist, target, mode);
       if (target)
        return target;
       break;
-      
+
     case BUILT_IN_STRSTR:
       target = expand_builtin_strstr (arglist, target, mode);
       if (target)
        return target;
       break;
-      
+
     case BUILT_IN_STRPBRK:
       target = expand_builtin_strpbrk (arglist, target, mode);
       if (target)
        return target;
       break;
-      
+
     case BUILT_IN_INDEX:
     case BUILT_IN_STRCHR:
       target = expand_builtin_strchr (arglist, target, mode);
@@ -3614,13 +3950,13 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       break;
 
     case BUILT_IN_MEMCPY:
-      target = expand_builtin_memcpy (arglist);
+      target = expand_builtin_memcpy (arglist, target, mode);
       if (target)
        return target;
       break;
 
     case BUILT_IN_MEMSET:
-      target = expand_builtin_memset (exp);
+      target = expand_builtin_memset (exp, target, mode);
       if (target)
        return target;
       break;
@@ -3643,21 +3979,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        return target;
       break;
 
-/* These comparison functions need an instruction that returns an actual
-   index.  An ordinary compare that just sets the condition codes
-   is not enough.  */
-#ifdef HAVE_cmpstrsi
     case BUILT_IN_BCMP:
     case BUILT_IN_MEMCMP:
-      target = expand_builtin_memcmp (exp, arglist, target);
+      target = expand_builtin_memcmp (exp, arglist, target, mode);
       if (target)
        return target;
       break;
-#else
-    case BUILT_IN_BCMP:
-    case BUILT_IN_MEMCMP:
-      break;
-#endif
 
     case BUILT_IN_SETJMP:
       target = expand_builtin_setjmp (arglist, target);
@@ -3689,26 +4016,20 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        }
 
     case BUILT_IN_TRAP:
-#ifdef HAVE_trap
-      if (HAVE_trap)
-       emit_insn (gen_trap ());
-      else
-#endif
-       error ("__builtin_trap not supported by this target");
-      emit_barrier ();
+      expand_builtin_trap ();
       return const0_rtx;
 
-    case BUILT_IN_PUTCHAR:
-    case BUILT_IN_PUTS:
-    case BUILT_IN_FPUTC:
-    case BUILT_IN_FWRITE:
-      break;
     case BUILT_IN_FPUTS:
-      target = expand_builtin_fputs (arglist, ignore);
+      target = expand_builtin_fputs (arglist, ignore,/*unlocked=*/ 0);
       if (target)
        return target;
       break;
-      
+    case BUILT_IN_FPUTS_UNLOCKED:
+      target = expand_builtin_fputs (arglist, ignore,/*unlocked=*/ 1);
+      if (target)
+       return target;
+      break;
+
       /* Various hooks for the DWARF 2 __throw routine.  */
     case BUILT_IN_UNWIND_INIT:
       expand_builtin_unwind_init ();
@@ -3734,20 +4055,24 @@ expand_builtin (exp, target, subtarget, mode, ignore)
     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_VA_START:
     case BUILT_IN_STDARG_START:
-      return expand_builtin_va_start (1, arglist);
+      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;
+
 
-    default:                   /* just do library call, if unknown builtin */
-      error ("built-in function `%s' not currently supported",
-            IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+    default:   /* just do library call, if unknown builtin */
+      if (!DECL_ASSEMBLER_NAME_SET_P (fndecl))
+       error ("built-in function `%s' not currently supported",
+              IDENTIFIER_POINTER (DECL_NAME (fndecl)));
     }
 
   /* The switch statement above can drop through to cause the function
@@ -3809,6 +4134,44 @@ fold_builtin_classify_type (arglist)
   return build_int_2 (type_to_class (TREE_TYPE (TREE_VALUE (arglist))), 0);
 }
 
+/* Fold a call to __builtin_inf or __builtin_huge_val.  */
+
+static tree
+fold_builtin_inf (type, warn)
+     tree type;
+     int warn;
+{
+  REAL_VALUE_TYPE real;
+
+  if (!MODE_HAS_INFINITIES (TYPE_MODE (type)) && warn)
+    warning ("target format does not support infinity");
+
+  real_inf (&real);
+  return build_real (type, real);
+}
+
+/* Fold a call to __builtin_nan or __builtin_nans.  */
+
+static tree
+fold_builtin_nan (arglist, type, quiet)
+     tree arglist, 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);
+}
+
 /* Used by constant folding to eliminate some builtin calls early.  EXP is
    the CALL_EXPR of a call to a builtin function.  */
 
@@ -3840,6 +4203,26 @@ fold_builtin (exp)
        }
       break;
 
+    case BUILT_IN_INF:
+    case BUILT_IN_INFF:
+    case BUILT_IN_INFL:
+      return fold_builtin_inf (TREE_TYPE (TREE_TYPE (fndecl)), true);
+
+    case BUILT_IN_HUGE_VAL:
+    case BUILT_IN_HUGE_VALF:
+    case BUILT_IN_HUGE_VALL:
+      return fold_builtin_inf (TREE_TYPE (TREE_TYPE (fndecl)), false);
+
+    case BUILT_IN_NAN:
+    case BUILT_IN_NANF:
+    case BUILT_IN_NANL:
+      return fold_builtin_nan (arglist, TREE_TYPE (TREE_TYPE (fndecl)), true);
+
+    case BUILT_IN_NANS:
+    case BUILT_IN_NANSF:
+    case BUILT_IN_NANSL:
+      return fold_builtin_nan (arglist, TREE_TYPE (TREE_TYPE (fndecl)), false);
+
     default:
       break;
     }
@@ -3874,29 +4257,32 @@ validate_arglist VPARAMS ((tree arglist, ...))
   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;
+  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);
     }
-    arglist = TREE_CHAIN (arglist);
-  } while (1);
+  while (1);
 
   /* We need gotos here since we can only have one VA_CLOSE in a
      function.  */