OSDN Git Service

* haifa-sched.c (extend_global): Split to extend_global_data and
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index 3e1ab59..953fb7b 100644 (file)
@@ -1,13 +1,13 @@
 /* Expand builtin functions.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 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
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -16,9 +16,8 @@ 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 GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -28,7 +27,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "real.h"
 #include "rtl.h"
 #include "tree.h"
-#include "tree-gimple.h"
+#include "gimple.h"
 #include "flags.h"
 #include "regs.h"
 #include "hard-reg-set.h"
@@ -50,6 +49,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "tree-mudflap.h"
 #include "tree-flow.h"
 #include "value-prof.h"
+#include "diagnostic.h"
 
 #ifndef PAD_VARARGS_DOWN
 #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
@@ -98,13 +98,14 @@ static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
 static rtx expand_builtin_interclass_mathfn (tree, rtx, rtx);
 static rtx expand_builtin_sincos (tree);
 static rtx expand_builtin_cexpi (tree, rtx, rtx);
-static rtx expand_builtin_int_roundingfn (tree, rtx, rtx);
-static rtx expand_builtin_int_roundingfn_2 (tree, rtx, rtx);
+static rtx expand_builtin_int_roundingfn (tree, rtx);
+static rtx expand_builtin_int_roundingfn_2 (tree, rtx);
 static rtx expand_builtin_args_info (tree);
 static rtx expand_builtin_next_arg (void);
 static rtx expand_builtin_va_start (tree);
 static rtx expand_builtin_va_end (tree);
 static rtx expand_builtin_va_copy (tree);
+static rtx expand_builtin_memchr (tree, rtx, enum machine_mode);
 static rtx expand_builtin_memcmp (tree, rtx, enum machine_mode);
 static rtx expand_builtin_strcmp (tree, rtx, enum machine_mode);
 static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode);
@@ -124,7 +125,6 @@ static rtx expand_builtin_bcopy (tree, int);
 static rtx expand_builtin_strcpy (tree, tree, rtx, enum machine_mode);
 static rtx expand_builtin_strcpy_args (tree, tree, tree, rtx, enum machine_mode);
 static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode);
-static rtx builtin_strncpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
 static rtx expand_builtin_strncpy (tree, rtx, enum machine_mode);
 static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, enum machine_mode);
 static rtx expand_builtin_memset (tree, rtx, enum machine_mode);
@@ -145,13 +145,13 @@ static rtx expand_builtin_sprintf (tree, rtx, enum machine_mode);
 static tree stabilize_va_list (tree, int);
 static rtx expand_builtin_expect (tree, rtx);
 static tree fold_builtin_constant_p (tree);
-static tree fold_builtin_expect (tree);
+static tree fold_builtin_expect (tree, tree);
 static tree fold_builtin_classify_type (tree);
 static tree fold_builtin_strlen (tree);
 static tree fold_builtin_inf (tree, int);
 static tree fold_builtin_nan (tree, tree, int);
 static tree rewrite_call_expr (tree, int, tree, int, ...);
-static bool validate_arg (tree, enum tree_code code);
+static bool validate_arg (const_tree, enum tree_code code);
 static bool integer_valued_real_p (tree);
 static tree fold_trunc_transparent_mathfn (tree, tree);
 static bool readonly_data_expr (tree);
@@ -172,6 +172,7 @@ static tree fold_builtin_int_roundingfn (tree, tree);
 static tree fold_builtin_bitop (tree, tree);
 static tree fold_builtin_memory_op (tree, tree, tree, tree, bool, int);
 static tree fold_builtin_strchr (tree, tree, tree);
+static tree fold_builtin_memchr (tree, tree, tree, tree);
 static tree fold_builtin_memcmp (tree, tree, tree);
 static tree fold_builtin_strcmp (tree, tree);
 static tree fold_builtin_strncmp (tree, tree, tree);
@@ -206,6 +207,7 @@ static rtx expand_builtin_memory_chk (tree, rtx, enum machine_mode,
                                      enum built_in_function);
 static void maybe_emit_chk_warning (tree, enum built_in_function);
 static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function);
+static void maybe_emit_free_warning (tree);
 static tree fold_builtin_object_size (tree, tree);
 static tree fold_builtin_strcat_chk (tree, tree, tree, tree);
 static tree fold_builtin_strncat_chk (tree, tree, tree, tree, tree);
@@ -229,6 +231,13 @@ static tree do_mpfr_arg2 (tree, tree, tree,
 static tree do_mpfr_arg3 (tree, tree, tree, tree,
                          int (*)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t));
 static tree do_mpfr_sincos (tree, tree, tree);
+#if MPFR_VERSION >= MPFR_VERSION_NUM(2,3,0)
+static tree do_mpfr_bessel_n (tree, tree, tree,
+                             int (*)(mpfr_ptr, long, mpfr_srcptr, mp_rnd_t),
+                             const REAL_VALUE_TYPE *, bool);
+static tree do_mpfr_remquo (tree, tree, tree);
+static tree do_mpfr_lgamma_r (tree, tree, tree);
+#endif
 
 /* Return true if NODE should be considered for inline expansion regardless
    of the optimization level.  This means whenever a function is invoked with
@@ -271,9 +280,7 @@ get_pointer_alignment (tree exp, unsigned int max_align)
     {
       switch (TREE_CODE (exp))
        {
-       case NOP_EXPR:
-       case CONVERT_EXPR:
-       case NON_LVALUE_EXPR:
+       CASE_CONVERT:
          exp = TREE_OPERAND (exp, 0);
          if (! POINTER_TYPE_P (TREE_TYPE (exp)))
            return align;
@@ -282,7 +289,7 @@ get_pointer_alignment (tree exp, unsigned int max_align)
          align = MIN (inner, max_align);
          break;
 
-       case PLUS_EXPR:
+       case POINTER_PLUS_EXPR:
          /* If sum of pointer + int, restrict our maximum alignment to that
             imposed by the integer.  If not, we can't do any better than
             ALIGN.  */
@@ -340,9 +347,7 @@ get_pointer_alignment (tree exp, unsigned int max_align)
              else if (offset)
                inner = MIN (inner, BITS_PER_UNIT);
            }
-         if (TREE_CODE (exp) == FUNCTION_DECL)
-           align = FUNCTION_BOUNDARY;
-         else if (DECL_P (exp))
+         if (DECL_P (exp))
            align = MIN (inner, DECL_ALIGN (exp));
 #ifdef CONSTANT_ALIGNMENT
          else if (CONSTANT_CLASS_P (exp))
@@ -442,7 +447,12 @@ c_strlen (tree src, int only_value)
      runtime.  */
   if (offset < 0 || offset > max)
     {
-      warning (0, "offset outside bounds of constant string");
+     /* Suppress multiple warnings for propagated constant strings.  */
+      if (! TREE_NO_WARNING (src))
+        {
+          warning (0, "offset outside bounds of constant string");
+          TREE_NO_WARNING (src) = 1;
+        }
       return NULL_TREE;
     }
 
@@ -582,7 +592,7 @@ expand_builtin_return_addr (enum built_in_function fndecl_code, int count)
       tem = hard_frame_pointer_rtx;
 
       /* Tell reload not to eliminate the frame pointer.  */
-      current_function_accesses_prior_frames = 1;
+      crtl->accesses_prior_frames = 1;
     }
 #endif
 
@@ -637,7 +647,7 @@ expand_builtin_return_addr (enum built_in_function fndecl_code, int count)
 }
 
 /* Alias set used for setjmp buffer.  */
-static HOST_WIDE_INT setjmp_alias_set = -1;
+static alias_set_type setjmp_alias_set = -1;
 
 /* Construct the leading half of a __builtin_setjmp call.  Control will
    return to RECEIVER_LABEL.  This is also called directly by the SJLJ
@@ -685,11 +695,10 @@ expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
 
   /* Tell optimize_save_area_alloca that extra work is going to
      need to go on during alloca.  */
-  current_function_calls_setjmp = 1;
+  cfun->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.  */
-  current_function_has_nonlocal_label = 1;
+  /* We have a nonlocal label.   */
+  cfun->has_nonlocal_label = 1;
 }
 
 /* Construct the trailing part of a __builtin_setjmp call.  This is
@@ -700,11 +709,11 @@ expand_builtin_setjmp_receiver (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.  */
-  emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
+  emit_use (hard_frame_pointer_rtx);
 
   /* Mark the static chain as clobbered here so life information
      doesn't get messed up for it.  */
-  emit_insn (gen_rtx_CLOBBER (VOIDmode, static_chain_rtx));
+  emit_clobber (static_chain_rtx);
 
   /* Now put in the code to restore the frame pointer, and argument
      pointer, if needed.  */
@@ -715,7 +724,7 @@ expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
       emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
       /* This might change the hard frame pointer in ways that aren't
         apparent to early optimization passes, so force a clobber.  */
-      emit_insn (gen_rtx_CLOBBER (VOIDmode, hard_frame_pointer_rtx));
+      emit_clobber (hard_frame_pointer_rtx);
     }
 
 #if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
@@ -735,8 +744,8 @@ expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
        {
          /* Now restore our arg pointer from the address at which it
             was saved in our stack frame.  */
-         emit_move_insn (virtual_incoming_args_rtx,
-                         copy_to_reg (get_arg_pointer_save_area (cfun)));
+         emit_move_insn (crtl->args.internal_arg_pointer,
+                         copy_to_reg (get_arg_pointer_save_area ()));
        }
     }
 #endif
@@ -753,12 +762,10 @@ expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
 #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, ""));
+  /* 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.  */
+  emit_insn (gen_blockage ());
 }
 
 /* __builtin_longjmp is passed a pointer to an array of five words (not
@@ -772,6 +779,11 @@ expand_builtin_longjmp (rtx buf_addr, rtx value)
   rtx fp, lab, stack, insn, last;
   enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
 
+  /* DRAP is needed for stack realign if longjmp is expanded to current 
+     function  */
+  if (SUPPORTS_STACK_ALIGNMENT)
+    crtl->need_drap = true;
+
   if (setjmp_alias_set == -1)
     setjmp_alias_set = new_alias_set ();
 
@@ -816,18 +828,14 @@ expand_builtin_longjmp (rtx buf_addr, rtx value)
        {
          lab = copy_to_reg (lab);
 
-         emit_insn (gen_rtx_CLOBBER (VOIDmode,
-                                     gen_rtx_MEM (BLKmode,
-                                                  gen_rtx_SCRATCH (VOIDmode))));
-         emit_insn (gen_rtx_CLOBBER (VOIDmode,
-                                     gen_rtx_MEM (BLKmode,
-                                                  hard_frame_pointer_rtx)));
+         emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
+         emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
 
          emit_move_insn (hard_frame_pointer_rtx, fp);
          emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
 
-         emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
-         emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
+         emit_use (hard_frame_pointer_rtx);
+         emit_use (stack_pointer_rtx);
          emit_indirect_jump (lab);
        }
     }
@@ -843,8 +851,7 @@ expand_builtin_longjmp (rtx buf_addr, rtx value)
 
       if (JUMP_P (insn))
        {
-         REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx,
-                                             REG_NOTES (insn));
+         add_reg_note (insn, REG_NON_LOCAL_GOTO, const0_rtx);
          break;
        }
       else if (CALL_P (insn))
@@ -871,11 +878,14 @@ expand_builtin_nonlocal_goto (tree exp)
   r_label = convert_memory_address (Pmode, r_label);
   r_save_area = expand_normal (t_save_area);
   r_save_area = convert_memory_address (Pmode, r_save_area);
+  /* Copy the address of the save location to a register just in case it was based
+    on the frame pointer.   */
+  r_save_area = copy_to_reg (r_save_area);
   r_fp = gen_rtx_MEM (Pmode, r_save_area);
   r_sp = gen_rtx_MEM (STACK_SAVEAREA_MODE (SAVE_NONLOCAL),
                      plus_constant (r_save_area, GET_MODE_SIZE (Pmode)));
 
-  current_function_has_nonlocal_goto = 1;
+  crtl->has_nonlocal_goto = 1;
 
 #ifdef HAVE_nonlocal_goto
   /* ??? We no longer need to pass the static chain value, afaik.  */
@@ -886,13 +896,8 @@ expand_builtin_nonlocal_goto (tree exp)
     {
       r_label = copy_to_reg (r_label);
 
-      emit_insn (gen_rtx_CLOBBER (VOIDmode,
-                                 gen_rtx_MEM (BLKmode,
-                                              gen_rtx_SCRATCH (VOIDmode))));
-
-      emit_insn (gen_rtx_CLOBBER (VOIDmode,
-                                 gen_rtx_MEM (BLKmode,
-                                              hard_frame_pointer_rtx)));
+      emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
+      emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
 
       /* Restore frame pointer for containing function.
         This sets the actual hard register used for the frame pointer
@@ -904,8 +909,22 @@ expand_builtin_nonlocal_goto (tree exp)
 
       /* USE of hard_frame_pointer_rtx added for consistency;
         not clear if really needed.  */
-      emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
-      emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
+      emit_use (hard_frame_pointer_rtx);
+      emit_use (stack_pointer_rtx);
+
+      /* If the architecture is using a GP register, we must
+        conservatively assume that the target function makes use of it.
+        The prologue of functions with nonlocal gotos must therefore
+        initialize the GP register to the appropriate value, and we
+        must then make sure that this value is live at the point
+        of the jump.  (Note that this doesn't necessarily apply
+        to targets with a nonlocal_goto pattern; they are free
+        to implement it in their own way.  Note also that this is
+        a no-op if the GP register is a global invariant.)  */
+      if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
+         && fixed_regs[PIC_OFFSET_TABLE_REGNUM])
+       emit_use (pic_offset_table_rtx);
+
       emit_indirect_jump (r_label);
     }
 
@@ -915,8 +934,7 @@ expand_builtin_nonlocal_goto (tree exp)
     {
       if (JUMP_P (insn))
        {
-         REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO,
-                                             const0_rtx, REG_NOTES (insn));
+         add_reg_note (insn, REG_NON_LOCAL_GOTO, const0_rtx);
          break;
        }
       else if (CALL_P (insn))
@@ -1056,8 +1074,7 @@ get_memory_rtx (tree exp, tree len)
   /* 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)
+  while (CONVERT_EXPR_P (exp)
         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
     exp = TREE_OPERAND (exp, 0);
 
@@ -1087,9 +1104,7 @@ get_memory_rtx (tree exp, tree len)
          tree inner = exp;
 
          while (TREE_CODE (inner) == ARRAY_REF
-                || TREE_CODE (inner) == NOP_EXPR
-                || TREE_CODE (inner) == CONVERT_EXPR
-                || TREE_CODE (inner) == NON_LVALUE_EXPR
+                || CONVERT_EXPR_P (inner)
                 || TREE_CODE (inner) == VIEW_CONVERT_EXPR
                 || TREE_CODE (inner) == SAVE_EXPR)
            inner = TREE_OPERAND (inner, 0);
@@ -1106,19 +1121,27 @@ get_memory_rtx (tree exp, tree len)
          while (TREE_CODE (inner) == COMPONENT_REF)
            {
              tree field = TREE_OPERAND (inner, 1);
-             gcc_assert (! DECL_BIT_FIELD (field));
              gcc_assert (TREE_CODE (mem_expr) == COMPONENT_REF);
              gcc_assert (field == TREE_OPERAND (mem_expr, 1));
 
+             /* Bitfields are generally not byte-addressable.  */
+             gcc_assert (!DECL_BIT_FIELD (field)
+                         || ((tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
+                              % BITS_PER_UNIT) == 0
+                             && host_integerp (DECL_SIZE (field), 0)
+                             && (TREE_INT_CST_LOW (DECL_SIZE (field))
+                                 % BITS_PER_UNIT) == 0));
+
+             /* If we can prove that the memory starting at XEXP (mem, 0) and
+                ending at XEXP (mem, 0) + LENGTH will fit into this field, we
+                can keep the COMPONENT_REF in MEM_EXPR.  But be careful with
+                fields without DECL_SIZE_UNIT like flexible array members.  */
              if (length >= 0
-                 && TYPE_SIZE_UNIT (TREE_TYPE (inner))
-                 && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0))
+                 && DECL_SIZE_UNIT (field)
+                 && host_integerp (DECL_SIZE_UNIT (field), 0))
                {
                  HOST_WIDE_INT size
-                   = tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0);
-                 /* If we can prove the memory starting at XEXP (mem, 0)
-                    and ending at XEXP (mem, 0) + LENGTH will fit into
-                    this field, we can keep that COMPONENT_REF in MEM_EXPR.  */
+                   = TREE_INT_CST_LOW (DECL_SIZE_UNIT (field));
                  if (offset <= size
                      && length <= size
                      && offset + length <= size)
@@ -1127,7 +1150,7 @@ get_memory_rtx (tree exp, tree len)
 
              if (offset >= 0
                  && host_integerp (DECL_FIELD_OFFSET (field), 0))
-               offset += tree_low_cst (DECL_FIELD_OFFSET (field), 0)
+               offset += TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field))
                          + tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
                            / BITS_PER_UNIT;
              else
@@ -1273,7 +1296,7 @@ result_vector (int savep, rtx result)
   int regno, size, align, nelts;
   enum machine_mode mode;
   rtx reg, mem;
-  rtx *savevec = alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
+  rtx *savevec = XALLOCAVEC (rtx, FIRST_PSEUDO_REGISTER);
 
   size = nelts = 0;
   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
@@ -1328,13 +1351,13 @@ expand_builtin_apply_args_1 (void)
       }
 
   /* Save the arg pointer to the block.  */
-  tem = copy_to_reg (virtual_incoming_args_rtx);
+  tem = copy_to_reg (crtl->args.internal_arg_pointer);
 #ifdef STACK_GROWS_DOWNWARD
   /* We need the pointer as the caller actually passed them to us, not
      as we might have pretended they were passed.  Make sure it's a valid
      operand, as emit_move_insn isn't expected to handle a PLUS.  */
   tem
-    = force_operand (plus_constant (tem, current_function_pretend_args_size),
+    = force_operand (plus_constant (tem, crtl->args.pretend_args_size),
                     NULL_RTX);
 #endif
   emit_move_insn (adjust_address (registers, Pmode, 0), tem);
@@ -1436,6 +1459,14 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
   /* Allocate a block of memory onto the stack and copy the memory
      arguments to the outgoing arguments address.  */
   allocate_dynamic_stack_space (argsize, 0, BITS_PER_UNIT);
+
+  /* Set DRAP flag to true, even though allocate_dynamic_stack_space
+     may have already set current_function_calls_alloca to true.
+     current_function_calls_alloca won't be set if argsize is zero,
+     so we have to guarantee need_drap is true here.  */
+  if (SUPPORTS_STACK_ALIGNMENT)
+    crtl->need_drap = true;
+
   dest = virtual_outgoing_args_rtx;
 #ifndef STACK_GROWS_DOWNWARD
   if (GET_CODE (argsize) == CONST_INT)
@@ -1585,7 +1616,7 @@ expand_builtin_return (rtx result)
        emit_move_insn (reg, adjust_address (result, mode, size));
 
        push_to_sequence (call_fusage);
-       emit_insn (gen_rtx_USE (VOIDmode, reg));
+       emit_use (reg);
        call_fusage = get_insns ();
        end_sequence ();
        size += GET_MODE_SIZE (mode);
@@ -1645,12 +1676,22 @@ expand_builtin_classify_type (tree exp)
   case BUILT_IN_MATHFN: case BUILT_IN_MATHFN##F: case BUILT_IN_MATHFN##L: \
   fcode = BUILT_IN_MATHFN; fcodef = BUILT_IN_MATHFN##F ; \
   fcodel = BUILT_IN_MATHFN##L ; break;
+/* Similar to above, but appends _R after any F/L suffix.  */
+#define CASE_MATHFN_REENT(BUILT_IN_MATHFN) \
+  case BUILT_IN_MATHFN##_R: case BUILT_IN_MATHFN##F_R: case BUILT_IN_MATHFN##L_R: \
+  fcode = BUILT_IN_MATHFN##_R; fcodef = BUILT_IN_MATHFN##F_R ; \
+  fcodel = BUILT_IN_MATHFN##L_R ; break;
 
 /* Return mathematic function equivalent to FN but operating directly
-   on TYPE, if available.  If we can't do the conversion, return zero.  */
-tree
-mathfn_built_in (tree type, enum built_in_function fn)
+   on TYPE, if available.  If IMPLICIT is true find the function in
+   implicit_built_in_decls[], otherwise use built_in_decls[].  If we
+   can't do the conversion, return zero.  */
+
+static tree
+mathfn_built_in_1 (tree type, enum built_in_function fn, bool implicit)
 {
+  tree const *const fn_arr
+    = implicit ? implicit_built_in_decls : built_in_decls;
   enum built_in_function fcode, fcodef, fcodel;
 
   switch (fn)
@@ -1684,6 +1725,7 @@ mathfn_built_in (tree type, enum built_in_function fn)
       CASE_MATHFN (BUILT_IN_FMOD)
       CASE_MATHFN (BUILT_IN_FREXP)
       CASE_MATHFN (BUILT_IN_GAMMA)
+      CASE_MATHFN_REENT (BUILT_IN_GAMMA) /* GAMMA_R */
       CASE_MATHFN (BUILT_IN_HUGE_VAL)
       CASE_MATHFN (BUILT_IN_HYPOT)
       CASE_MATHFN (BUILT_IN_ILOGB)
@@ -1696,6 +1738,7 @@ mathfn_built_in (tree type, enum built_in_function fn)
       CASE_MATHFN (BUILT_IN_LDEXP)
       CASE_MATHFN (BUILT_IN_LFLOOR)
       CASE_MATHFN (BUILT_IN_LGAMMA)
+      CASE_MATHFN_REENT (BUILT_IN_LGAMMA) /* LGAMMA_R */
       CASE_MATHFN (BUILT_IN_LLCEIL)
       CASE_MATHFN (BUILT_IN_LLFLOOR)
       CASE_MATHFN (BUILT_IN_LLRINT)
@@ -1723,6 +1766,7 @@ mathfn_built_in (tree type, enum built_in_function fn)
       CASE_MATHFN (BUILT_IN_SCALB)
       CASE_MATHFN (BUILT_IN_SCALBLN)
       CASE_MATHFN (BUILT_IN_SCALBN)
+      CASE_MATHFN (BUILT_IN_SIGNBIT)
       CASE_MATHFN (BUILT_IN_SIGNIFICAND)
       CASE_MATHFN (BUILT_IN_SIN)
       CASE_MATHFN (BUILT_IN_SINCOS)
@@ -1741,15 +1785,23 @@ mathfn_built_in (tree type, enum built_in_function fn)
       }
 
   if (TYPE_MAIN_VARIANT (type) == double_type_node)
-    return implicit_built_in_decls[fcode];
+    return fn_arr[fcode];
   else if (TYPE_MAIN_VARIANT (type) == float_type_node)
-    return implicit_built_in_decls[fcodef];
+    return fn_arr[fcodef];
   else if (TYPE_MAIN_VARIANT (type) == long_double_type_node)
-    return implicit_built_in_decls[fcodel];
+    return fn_arr[fcodel];
   else
     return NULL_TREE;
 }
 
+/* Like mathfn_built_in_1(), but always use the implicit array.  */
+
+tree
+mathfn_built_in (tree type, enum built_in_function fn)
+{
+  return mathfn_built_in_1 (type, fn, /*implicit=*/ 1);
+}
+
 /* If errno must be maintained, expand the RTL to check if the result,
    TARGET, of a built-in function call, EXP, is NaN, and if so set
    errno to EDOM.  */
@@ -1780,6 +1832,9 @@ expand_errno_check (tree exp, rtx target)
     }
 #endif
 
+  /* Make sure the library call isn't expanded as a tail call.  */
+  CALL_EXPR_TAILCALL (exp) = 0;
+
   /* We can't set errno=EDOM directly; let the library call do it.
      Pop the arguments right away in case the call gets deleted.  */
   NO_DEFER_POP;
@@ -1802,7 +1857,7 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
   tree fndecl = get_callee_fndecl (exp);
   enum machine_mode mode;
   bool errno_set = false;
-  tree arg, narg;
+  tree arg;
 
   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
     return NULL_RTX;
@@ -1868,21 +1923,16 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
     errno_set = false;
 
   /* Before working hard, check whether the instruction is available.  */
-  if (builtin_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+  if (optab_handler (builtin_optab, mode)->insn_code != CODE_FOR_nothing)
     {
       target = gen_reg_rtx (mode);
 
       /* Wrap the computation of the argument in a SAVE_EXPR, as we may
         need to expand the argument again.  This way, we will not perform
         side-effects more the once.  */
-      narg = builtin_save_expr (arg);
-      if (narg != arg)
-       {
-         arg = narg;
-         exp = build_call_expr (fndecl, 1, arg);
-       }
+      CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
 
-      op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+      op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
 
       start_sequence ();
 
@@ -1910,48 +1960,7 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
 
   before_call = get_last_insn ();
 
-  target = expand_call (exp, target, target == const0_rtx);
-
-  /* If this is a sqrt operation and we don't care about errno, try to
-     attach a REG_EQUAL note with a SQRT rtx to the emitted libcall.
-     This allows the semantics of the libcall to be visible to the RTL
-     optimizers.  */
-  if (builtin_optab == sqrt_optab && !errno_set)
-    {
-      /* Search backwards through the insns emitted by expand_call looking
-        for the instruction with the REG_RETVAL note.  */
-      rtx last = get_last_insn ();
-      while (last != before_call)
-       {
-         if (find_reg_note (last, REG_RETVAL, NULL))
-           {
-             rtx note = find_reg_note (last, REG_EQUAL, NULL);
-             /* Check that the REQ_EQUAL note is an EXPR_LIST with
-                two elements, i.e. symbol_ref(sqrt) and the operand.  */
-             if (note
-                 && GET_CODE (note) == EXPR_LIST
-                 && GET_CODE (XEXP (note, 0)) == EXPR_LIST
-                 && XEXP (XEXP (note, 0), 1) != NULL_RTX
-                 && XEXP (XEXP (XEXP (note, 0), 1), 1) == NULL_RTX)
-               {
-                 rtx operand = XEXP (XEXP (XEXP (note, 0), 1), 0);
-                 /* Check operand is a register with expected mode.  */
-                 if (operand
-                     && REG_P (operand)
-                     && GET_MODE (operand) == mode)
-                   {
-                     /* Replace the REG_EQUAL note with a SQRT rtx.  */
-                     rtx equiv = gen_rtx_SQRT (mode, operand);
-                     set_unique_reg_note (last, REG_EQUAL, equiv);
-                   }
-               }
-             break;
-           }
-         last = PREV_INSN (last);
-       }
-    }
-
-  return target;
+  return expand_call (exp, target, target == const0_rtx);
 }
 
 /* Expand a call to the builtin binary math functions (pow and atan2).
@@ -1968,10 +1977,9 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
   rtx op0, op1, insns;
   int op1_type = REAL_TYPE;
   tree fndecl = get_callee_fndecl (exp);
-  tree arg0, arg1, narg;
+  tree arg0, arg1;
   enum machine_mode mode;
   bool errno_set = true;
-  bool stable = true;
 
   switch (DECL_FUNCTION_CODE (fndecl))
     {
@@ -2019,7 +2027,7 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
   mode = TYPE_MODE (TREE_TYPE (exp));
 
   /* Before working hard, check whether the instruction is available.  */
-  if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
+  if (optab_handler (builtin_optab, mode)->insn_code == CODE_FOR_nothing)
     return NULL_RTX;
 
   target = gen_reg_rtx (mode);
@@ -2028,21 +2036,8 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
     errno_set = false;
 
   /* Always stabilize the argument list.  */
-  narg = builtin_save_expr (arg1);
-  if (narg != arg1)
-    {
-      arg1 = narg;
-      stable = false;
-    }
-  narg = builtin_save_expr (arg0);
-  if (narg != arg0)
-    {
-      arg0 = narg;
-      stable = false;
-    }
-
-  if (! stable)
-    exp = build_call_expr (fndecl, 2, arg0, arg1);
+  CALL_EXPR_ARG (exp, 0) = arg0 = builtin_save_expr (arg0);
+  CALL_EXPR_ARG (exp, 1) = arg1 = builtin_save_expr (arg1);
 
   op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
   op1 = expand_normal (arg1);
@@ -2088,7 +2083,7 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
   rtx op0, insns;
   tree fndecl = get_callee_fndecl (exp);
   enum machine_mode mode;
-  tree arg, narg;
+  tree arg;
 
   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
     return NULL_RTX;
@@ -2109,7 +2104,7 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
 
   /* Check if sincos insn is available, otherwise fallback
      to sin or cos insn.  */
-  if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
+  if (optab_handler (builtin_optab, mode)->insn_code == CODE_FOR_nothing)
     switch (DECL_FUNCTION_CODE (fndecl))
       {
       CASE_FLT_FN (BUILT_IN_SIN):
@@ -2121,21 +2116,16 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
       }
 
   /* Before working hard, check whether the instruction is available.  */
-  if (builtin_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+  if (optab_handler (builtin_optab, mode)->insn_code != CODE_FOR_nothing)
     {
       target = gen_reg_rtx (mode);
 
       /* Wrap the computation of the argument in a SAVE_EXPR, as we may
         need to expand the argument again.  This way, we will not perform
         side-effects more the once.  */
-      narg = save_expr (arg);
-      if (narg != arg)
-       {
-         arg = narg;
-         exp = build_call_expr (fndecl, 1, arg);
-       }
+      CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
 
-      op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+      op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
 
       start_sequence ();
 
@@ -2194,13 +2184,13 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
 static rtx
 expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
 {
-  optab builtin_optab;
-  enum insn_code icode;
+  optab builtin_optab = 0;
+  enum insn_code icode = CODE_FOR_nothing;
   rtx op0;
   tree fndecl = get_callee_fndecl (exp);
   enum machine_mode mode;
   bool errno_set = false;
-  tree arg, narg;
+  tree arg;
 
   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
     return NULL_RTX;
@@ -2213,6 +2203,11 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
       errno_set = true; builtin_optab = ilogb_optab; break;
     CASE_FLT_FN (BUILT_IN_ISINF):
       builtin_optab = isinf_optab; break;
+    case BUILT_IN_ISNORMAL:
+    case BUILT_IN_ISFINITE:
+    CASE_FLT_FN (BUILT_IN_FINITE):
+      /* These builtins have no optabs (yet).  */
+      break;
     default:
       gcc_unreachable ();
     }
@@ -2224,7 +2219,8 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
   /* Optab mode depends on the mode of the input argument.  */
   mode = TYPE_MODE (TREE_TYPE (arg));
 
-  icode = builtin_optab->handlers[(int) mode].insn_code;
+  if (builtin_optab)
+    icode = optab_handler (builtin_optab, mode)->insn_code;
  
   /* Before working hard, check whether the instruction is available.  */
   if (icode != CODE_FOR_nothing)
@@ -2240,14 +2236,9 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
       /* Wrap the computation of the argument in a SAVE_EXPR, as we may
         need to expand the argument again.  This way, we will not perform
         side-effects more the once.  */
-      narg = builtin_save_expr (arg);
-      if (narg != arg)
-       {
-         arg = narg;
-         exp = build_call_expr (fndecl, 1, arg);
-       }
+      CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
 
-      op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+      op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
 
       if (mode != GET_MODE (op0))
        op0 = convert_to_mode (mode, op0, 0);
@@ -2258,6 +2249,68 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
       return target;
     }
 
+  /* If there is no optab, try generic code.  */
+  switch (DECL_FUNCTION_CODE (fndecl))
+    {
+      tree result;
+
+    CASE_FLT_FN (BUILT_IN_ISINF):
+      {
+       /* isinf(x) -> isgreater(fabs(x),DBL_MAX).  */
+       tree const isgr_fn = built_in_decls[BUILT_IN_ISGREATER];
+       tree const type = TREE_TYPE (arg);
+       REAL_VALUE_TYPE r;
+       char buf[128];
+
+       get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
+       real_from_string (&r, buf);
+       result = build_call_expr (isgr_fn, 2,
+                                 fold_build1 (ABS_EXPR, type, arg),
+                                 build_real (type, r));
+       return expand_expr (result, target, VOIDmode, EXPAND_NORMAL);
+      }
+    CASE_FLT_FN (BUILT_IN_FINITE):
+    case BUILT_IN_ISFINITE:
+      {
+       /* isfinite(x) -> islessequal(fabs(x),DBL_MAX).  */
+       tree const isle_fn = built_in_decls[BUILT_IN_ISLESSEQUAL];
+       tree const type = TREE_TYPE (arg);
+       REAL_VALUE_TYPE r;
+       char buf[128];
+
+       get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
+       real_from_string (&r, buf);
+       result = build_call_expr (isle_fn, 2,
+                                 fold_build1 (ABS_EXPR, type, arg),
+                                 build_real (type, r));
+       return expand_expr (result, target, VOIDmode, EXPAND_NORMAL);
+      }
+    case BUILT_IN_ISNORMAL:
+      {
+       /* isnormal(x) -> isgreaterequal(fabs(x),DBL_MIN) &
+          islessequal(fabs(x),DBL_MAX).  */
+       tree const isle_fn = built_in_decls[BUILT_IN_ISLESSEQUAL];
+       tree const isge_fn = built_in_decls[BUILT_IN_ISGREATEREQUAL];
+       tree const type = TREE_TYPE (arg);
+       REAL_VALUE_TYPE rmax, rmin;
+       char buf[128];
+
+       get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
+       real_from_string (&rmax, buf);
+       sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (mode)->emin - 1);
+       real_from_string (&rmin, buf);
+       arg = builtin_save_expr (fold_build1 (ABS_EXPR, type, arg));
+       result = build_call_expr (isle_fn, 2, arg,
+                                 build_real (type, rmax));
+       result = fold_build2 (BIT_AND_EXPR, integer_type_node, result,
+                             build_call_expr (isge_fn, 2, arg,
+                                              build_real (type, rmin)));
+       return expand_expr (result, target, VOIDmode, EXPAND_NORMAL);
+      }
+    default:
+      break;
+    }
+
   target = expand_call (exp, target, target == const0_rtx);
 
   return target;
@@ -2288,7 +2341,7 @@ expand_builtin_sincos (tree exp)
   mode = TYPE_MODE (TREE_TYPE (arg));
 
   /* Check if sincos insn is available, otherwise emit the call.  */
-  if (sincos_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
+  if (optab_handler (sincos_optab, mode)->insn_code == CODE_FOR_nothing)
     return NULL_RTX;
 
   target1 = gen_reg_rtx (mode);
@@ -2334,12 +2387,12 @@ expand_builtin_cexpi (tree exp, rtx target, rtx subtarget)
   /* Try expanding via a sincos optab, fall back to emitting a libcall
      to sincos or cexp.  We are sure we have sincos or cexp because cexpi
      is only generated from sincos, cexp or if we have either of them.  */
-  if (sincos_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+  if (optab_handler (sincos_optab, mode)->insn_code != CODE_FOR_nothing)
     {
       op1 = gen_reg_rtx (mode);
       op2 = gen_reg_rtx (mode);
 
-      op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+      op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
 
       /* Compute into op1 and op2.  */
       expand_twoval_unop (sincos_optab, op0, op2, op1, 0);
@@ -2376,9 +2429,6 @@ expand_builtin_cexpi (tree exp, rtx target, rtx subtarget)
       tree call, fn = NULL_TREE, narg;
       tree ctype = build_complex_type (type);
 
-      /* We can expand via the C99 cexp function.  */
-      gcc_assert (TARGET_C99_FUNCTIONS);
-
       if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIF)
        fn = built_in_decls[BUILT_IN_CEXPF];
       else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPI)
@@ -2387,20 +2437,40 @@ expand_builtin_cexpi (tree exp, rtx target, rtx subtarget)
        fn = built_in_decls[BUILT_IN_CEXPL];
       else
        gcc_unreachable ();
+
+      /* If we don't have a decl for cexp create one.  This is the
+        friendliest fallback if the user calls __builtin_cexpi
+        without full target C99 function support.  */
+      if (fn == NULL_TREE)
+       {
+         tree fntype;
+         const char *name = NULL;
+
+         if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIF)
+           name = "cexpf";
+         else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPI)
+           name = "cexp";
+         else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIL)
+           name = "cexpl";
+
+         fntype = build_function_type_list (ctype, ctype, NULL_TREE);
+         fn = build_fn_decl (name, fntype);
+       }
+
       narg = fold_build2 (COMPLEX_EXPR, ctype,
                          build_real (type, dconst0), arg);
 
       /* Make sure not to fold the cexp call again.  */
       call = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
-      return expand_expr (build_call_nary (ctype, call, 1, arg), 
-                         target, VOIDmode, 0);
+      return expand_expr (build_call_nary (ctype, call, 1, narg), 
+                         target, VOIDmode, EXPAND_NORMAL);
     }
 
   /* Now build the proper return type.  */
   return expand_expr (build2 (COMPLEX_EXPR, build_complex_type (type),
                              make_tree (TREE_TYPE (arg), op2),
                              make_tree (TREE_TYPE (arg), op1)),
-                     target, VOIDmode, 0);
+                     target, VOIDmode, EXPAND_NORMAL);
 }
 
 /* Expand a call to one of the builtin rounding functions gcc defines
@@ -2408,11 +2478,10 @@ expand_builtin_cexpi (tree exp, rtx target, rtx subtarget)
    do not need to worry about setting errno to EDOM.
    If expanding via optab fails, lower expression to (int)(floor(x)).
    EXP is the expression that is a call to the builtin function;
-   if convenient, the result should be placed in TARGET.  SUBTARGET may
-   be used as the target for computing one of EXP's operands.  */
+   if convenient, the result should be placed in TARGET.  */
 
 static rtx
-expand_builtin_int_roundingfn (tree exp, rtx target, rtx subtarget)
+expand_builtin_int_roundingfn (tree exp, rtx target)
 {
   convert_optab builtin_optab;
   rtx op0, insns, tmp;
@@ -2420,7 +2489,7 @@ expand_builtin_int_roundingfn (tree exp, rtx target, rtx subtarget)
   enum built_in_function fallback_fn;
   tree fallback_fndecl;
   enum machine_mode mode;
-  tree arg, narg;
+  tree arg;
 
   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
     gcc_unreachable ();
@@ -2453,14 +2522,9 @@ expand_builtin_int_roundingfn (tree exp, rtx target, rtx subtarget)
   /* Wrap the computation of the argument in a SAVE_EXPR, as we may
      need to expand the argument again.  This way, we will not perform
      side-effects more the once.  */
-  narg = builtin_save_expr (arg);
-  if (narg != arg)
-    {
-      arg = narg;
-      exp = build_call_expr (fndecl, 1, arg);
-    }
+  CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
 
-  op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+  op0 = expand_expr (arg, NULL, VOIDmode, EXPAND_NORMAL);
 
   start_sequence ();
 
@@ -2480,9 +2544,51 @@ expand_builtin_int_roundingfn (tree exp, rtx target, rtx subtarget)
 
   /* Fall back to floating point rounding optab.  */
   fallback_fndecl = mathfn_built_in (TREE_TYPE (arg), fallback_fn);
-  /* We shouldn't get here on targets without TARGET_C99_FUNCTIONS.
-     ??? Perhaps convert (int)floorf(x) into (int)floor((double)x).  */
-  gcc_assert (fallback_fndecl != NULL_TREE);
+
+  /* For non-C99 targets we may end up without a fallback fndecl here
+     if the user called __builtin_lfloor directly.  In this case emit
+     a call to the floor/ceil variants nevertheless.  This should result
+     in the best user experience for not full C99 targets.  */
+  if (fallback_fndecl == NULL_TREE)
+    {
+      tree fntype;
+      const char *name = NULL;
+
+      switch (DECL_FUNCTION_CODE (fndecl))
+       {
+       case BUILT_IN_LCEIL:
+       case BUILT_IN_LLCEIL:
+         name = "ceil";
+         break;
+       case BUILT_IN_LCEILF:
+       case BUILT_IN_LLCEILF:
+         name = "ceilf";
+         break;
+       case BUILT_IN_LCEILL:
+       case BUILT_IN_LLCEILL:
+         name = "ceill";
+         break;
+       case BUILT_IN_LFLOOR:
+       case BUILT_IN_LLFLOOR:
+         name = "floor";
+         break;
+       case BUILT_IN_LFLOORF:
+       case BUILT_IN_LLFLOORF:
+         name = "floorf";
+         break;
+       case BUILT_IN_LFLOORL:
+       case BUILT_IN_LLFLOORL:
+         name = "floorl";
+         break;
+       default:
+         gcc_unreachable ();
+       }
+
+      fntype = build_function_type_list (TREE_TYPE (arg),
+                                        TREE_TYPE (arg), NULL_TREE);
+      fallback_fndecl = build_fn_decl (name, fntype);
+    }
+
   exp = build_call_expr (fallback_fndecl, 1, arg);
 
   tmp = expand_normal (exp);
@@ -2499,16 +2605,15 @@ expand_builtin_int_roundingfn (tree exp, rtx target, rtx subtarget)
    conversion (lrint).
    Return 0 if a normal call should be emitted rather than expanding the
    function in-line.  EXP is the expression that is a call to the builtin
-   function; if convenient, the result should be placed in TARGET.
-   SUBTARGET may be used as the target for computing one of EXP's operands.  */
+   function; if convenient, the result should be placed in TARGET.  */
 
 static rtx
-expand_builtin_int_roundingfn_2 (tree exp, rtx target, rtx subtarget)
+expand_builtin_int_roundingfn_2 (tree exp, rtx target)
 {
   convert_optab builtin_optab;
   rtx op0, insns;
   tree fndecl = get_callee_fndecl (exp);
-  tree arg, narg;
+  tree arg;
   enum machine_mode mode;
 
   /* There's no easy way to detect the case we need to set EDOM.  */
@@ -2540,14 +2645,9 @@ expand_builtin_int_roundingfn_2 (tree exp, rtx target, rtx subtarget)
   /* Wrap the computation of the argument in a SAVE_EXPR, as we may
      need to expand the argument again.  This way, we will not perform
      side-effects more the once.  */
-  narg = builtin_save_expr (arg);
-  if (narg != arg)
-    {
-      arg = narg;
-      exp = build_call_expr (fndecl, 1, arg);
-    }
+  CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
 
-  op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+  op0 = expand_expr (arg, NULL, VOIDmode, EXPAND_NORMAL);
 
   start_sequence ();
 
@@ -2811,10 +2911,10 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
   if (real_identical (&c, &cint)
       && ((n >= -1 && n <= 2)
          || (flag_unsafe_math_optimizations
-             && !optimize_size
+             && optimize_insn_for_speed_p ()
              && powi_cost (n) <= POWI_MAX_MULTS)))
     {
-      op = expand_expr (arg0, subtarget, VOIDmode, 0);
+      op = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
       if (n != 1)
        {
          op = force_reg (mode, op);
@@ -2835,15 +2935,17 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
       real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
       if (real_identical (&c2, &cint)
          && ((flag_unsafe_math_optimizations
-              && !optimize_size
+              && optimize_insn_for_speed_p ()
               && powi_cost (n/2) <= POWI_MAX_MULTS)
              || n == 1))
        {
          tree call_expr = build_call_expr (fn, 1, narg0);
-         op = expand_builtin (call_expr, NULL_RTX, subtarget, mode, 0);
+         /* Use expand_expr in case the newly built call expression
+            was folded to a non-call.  */
+         op = expand_expr (call_expr, subtarget, mode, EXPAND_NORMAL);
          if (n != 1)
            {
-             op2 = expand_expr (narg0, subtarget, VOIDmode, 0);
+             op2 = expand_expr (narg0, subtarget, VOIDmode, EXPAND_NORMAL);
              op2 = force_reg (mode, op2);
              op2 = expand_powi (op2, mode, abs (n / 2));
              op = expand_simple_binop (mode, MULT, op, op2, NULL_RTX,
@@ -2869,6 +2971,8 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
       && (tree_expr_nonnegative_p (arg0)
          || !HONOR_NANS (mode)))
     {
+      REAL_VALUE_TYPE dconst3;
+      real_from_integer (&dconst3, VOIDmode, 3, 0, 0);
       real_arithmetic (&c2, MULT_EXPR, &c, &dconst3);
       real_round (&c2, mode, &c2);
       n = real_to_integer (&c2);
@@ -2876,7 +2980,7 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
       real_arithmetic (&c2, RDIV_EXPR, &cint, &dconst3);
       real_convert (&c2, mode, &c2);
       if (real_identical (&c2, &c)
-         && ((!optimize_size
+         && ((optimize_insn_for_speed_p ()
               && powi_cost (n/3) <= POWI_MAX_MULTS)
              || n == 1))
        {
@@ -2887,7 +2991,7 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
                                      0, OPTAB_LIB_WIDEN);
          if (n != 1)
            {
-             op2 = expand_expr (narg0, subtarget, VOIDmode, 0);
+             op2 = expand_expr (narg0, subtarget, VOIDmode, EXPAND_NORMAL);
              op2 = force_reg (mode, op2);
              op2 = expand_powi (op2, mode, abs (n / 3));
              op = expand_simple_binop (mode, MULT, op, op2, NULL_RTX,
@@ -2938,10 +3042,10 @@ expand_builtin_powi (tree exp, rtx target, rtx subtarget)
       if ((TREE_INT_CST_HIGH (arg1) == 0
           || TREE_INT_CST_HIGH (arg1) == -1)
          && ((n >= -1 && n <= 2)
-             || (! optimize_size
+             || (optimize_insn_for_speed_p ()
                  && powi_cost (n) <= POWI_MAX_MULTS)))
        {
-         op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
+         op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
          op0 = force_reg (mode, op0);
          return expand_powi (op0, mode, n);
        }
@@ -2955,15 +3059,15 @@ expand_builtin_powi (tree exp, rtx target, rtx subtarget)
   if (target == NULL_RTX)
     target = gen_reg_rtx (mode);
 
-  op0 = expand_expr (arg0, subtarget, mode, 0);
+  op0 = expand_expr (arg0, subtarget, mode, EXPAND_NORMAL);
   if (GET_MODE (op0) != mode)
     op0 = convert_to_mode (mode, op0, 0);
-  op1 = expand_expr (arg1, 0, mode2, 0);
+  op1 = expand_expr (arg1, NULL_RTX, mode2, EXPAND_NORMAL);
   if (GET_MODE (op1) != mode2)
     op1 = convert_to_mode (mode2, op1, 0);
 
-  target = emit_library_call_value (powi_optab->handlers[(int) mode].libfunc,
-                                   target, LCT_CONST_MAKE_BLOCK, mode, 2,
+  target = emit_library_call_value (optab_libfunc (powi_optab, mode),
+                                   target, LCT_CONST, mode, 2,
                                    op0, mode, op1, mode2);
 
   return target;
@@ -3015,7 +3119,7 @@ expand_builtin_strlen (tree exp, rtx target,
       /* Bail out if we can't compute strlen in the right mode.  */
       while (insn_mode != VOIDmode)
        {
-         icode = strlen_optab->handlers[(int) insn_mode].insn_code;
+         icode = optab_handler (strlen_optab, insn_mode)->insn_code;
          if (icode != CODE_FOR_nothing)
            break;
 
@@ -3197,6 +3301,7 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
                                            false, /*endp=*/0);
       HOST_WIDE_INT expected_size = -1;
       unsigned int expected_align = 0;
+      tree_ann_common_t ann;
 
       if (result)
        {
@@ -3218,7 +3323,10 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
       if (src_align == 0)
        return NULL_RTX;
  
-      stringop_block_profile (exp, &expected_align, &expected_size);
+      ann = tree_common_ann (exp);
+      if (ann)
+        stringop_block_profile (ann->stmt, &expected_align, &expected_size);
+
       if (expected_align < dest_align)
        expected_align = dest_align;
       dest_mem = get_memory_rtx (dest, len);
@@ -3233,11 +3341,13 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
          && 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,
-                                 (void *) src_str, dest_align))
+                                 CONST_CAST (char *, src_str),
+                                 dest_align, false))
        {
          dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
                                      builtin_memcpy_read_str,
-                                     (void *) src_str, dest_align, 0);
+                                     CONST_CAST (char *, src_str),
+                                     dest_align, false, 0);
          dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
          dest_mem = convert_memory_address (ptr_mode, dest_mem);
          return dest_mem;
@@ -3346,13 +3456,15 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len, tree type,
          && 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,
-                                 (void *) src_str, dest_align))
+                                 CONST_CAST (char *, src_str),
+                                 dest_align, false))
        {
          dest_mem = get_memory_rtx (dest, len);
          set_mem_align (dest_mem, dest_align);
          dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
                                      builtin_memcpy_read_str,
-                                     (void *) src_str, dest_align, endp);
+                                     CONST_CAST (char *, src_str),
+                                     dest_align, false, endp);
          dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
          dest_mem = convert_memory_address (ptr_mode, dest_mem);
          return dest_mem;
@@ -3411,6 +3523,7 @@ expand_builtin_memmove_args (tree dest, tree src, tree len,
 
   if (result)
     {
+      STRIP_TYPE_NOPS (result);
       while (TREE_CODE (result) == COMPOUND_EXPR)
        {
          expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
@@ -3634,7 +3747,7 @@ expand_builtin_stpcpy (tree exp, rtx target, enum machine_mode mode)
    bytes from constant string DATA + OFFSET and return it as target
    constant.  */
 
-static rtx
+rtx
 builtin_strncpy_read_str (void *data, HOST_WIDE_INT offset,
                          enum machine_mode mode)
 {
@@ -3693,13 +3806,14 @@ expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode)
          if (!p || dest_align == 0 || !host_integerp (len, 1)
              || !can_store_by_pieces (tree_low_cst (len, 1),
                                       builtin_strncpy_read_str,
-                                      (void *) p, dest_align))
+                                      CONST_CAST (char *, p),
+                                      dest_align, false))
            return NULL_RTX;
 
          dest_mem = get_memory_rtx (dest, len);
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_strncpy_read_str,
-                          (void *) p, dest_align, 0);
+                          CONST_CAST (char *, p), dest_align, false, 0);
          dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
          dest_mem = convert_memory_address (ptr_mode, dest_mem);
          return dest_mem;
@@ -3717,7 +3831,7 @@ builtin_memset_read_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
                         enum machine_mode mode)
 {
   const char *c = (const char *) data;
-  char *p = alloca (GET_MODE_SIZE (mode));
+  char *p = XALLOCAVEC (char, GET_MODE_SIZE (mode));
 
   memset (p, *c, GET_MODE_SIZE (mode));
 
@@ -3741,7 +3855,7 @@ builtin_memset_gen_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
   if (size == 1)
     return (rtx) data;
 
-  p = alloca (size);
+  p = XALLOCAVEC (char, size);
   memset (p, 1, size);
   coeff = c_readstr (p, mode);
 
@@ -3787,6 +3901,7 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
   rtx dest_mem, dest_addr, len_rtx;
   HOST_WIDE_INT expected_size = -1;
   unsigned int expected_align = 0;
+  tree_ann_common_t ann;
 
   dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
 
@@ -3794,7 +3909,10 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
   if (dest_align == 0)
     return NULL_RTX;
 
-  stringop_block_profile (orig_exp, &expected_align, &expected_size);
+  ann = tree_common_ann (orig_exp);
+  if (ann)
+    stringop_block_profile (ann->stmt, &expected_align, &expected_size);
+
   if (expected_align < dest_align)
     expected_align = dest_align;
 
@@ -3827,14 +3945,15 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
        * We can't pass builtin_memset_gen_str as that emits RTL.  */
       c = 1;
       if (host_integerp (len, 1)
-         && !(optimize_size && tree_low_cst (len, 1) > 1)
          && can_store_by_pieces (tree_low_cst (len, 1),
-                                 builtin_memset_read_str, &c, dest_align))
+                                 builtin_memset_read_str, &c, dest_align,
+                                 true))
        {
          val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
                               val_rtx);
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
-                          builtin_memset_gen_str, val_rtx, dest_align, 0);
+                          builtin_memset_gen_str, val_rtx, dest_align,
+                          true, 0);
        }
       else if (!set_storage_via_setmem (dest_mem, len_rtx, val_rtx,
                                        dest_align, expected_align,
@@ -3852,11 +3971,11 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
   if (c)
     {
       if (host_integerp (len, 1)
-         && !(optimize_size && tree_low_cst (len, 1) > 1)
          && can_store_by_pieces (tree_low_cst (len, 1),
-                                 builtin_memset_read_str, &c, dest_align))
+                                 builtin_memset_read_str, &c, dest_align,
+                                 true))
        store_by_pieces (dest_mem, tree_low_cst (len, 1),
-                        builtin_memset_read_str, &c, dest_align, 0);
+                        builtin_memset_read_str, &c, dest_align, true, 0);
       else if (!set_storage_via_setmem (dest_mem, len_rtx, GEN_INT (c),
                                        dest_align, expected_align,
                                        expected_size))
@@ -3919,6 +4038,26 @@ expand_builtin_bzero (tree exp)
                                     const0_rtx, VOIDmode, exp);
 }
 
+/* Expand a call to the memchr builtin.  Return NULL_RTX if we failed the
+   caller should emit a normal call, otherwise try to get the result
+   in TARGET, if convenient (and in mode MODE if that's convenient).  */
+
+static rtx
+expand_builtin_memchr (tree exp, rtx target, enum machine_mode mode)
+{
+  if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE,
+                       INTEGER_TYPE, VOID_TYPE))
+    {
+      tree type = TREE_TYPE (exp);
+      tree result = fold_builtin_memchr (CALL_EXPR_ARG (exp, 0),
+                                        CALL_EXPR_ARG (exp, 1),
+                                        CALL_EXPR_ARG (exp, 2), type);
+      if (result)
+       return expand_expr (result, target, mode, EXPAND_NORMAL);
+    }
+  return NULL_RTX;
+}
+
 /* Expand expression EXP, which is a call to the memcmp built-in function.
    Return NULL_RTX if we failed and the
    caller should emit a normal call, otherwise try to get the result in
@@ -4005,7 +4144,7 @@ expand_builtin_memcmp (tree exp, rtx target, enum machine_mode mode)
     if (insn)
       emit_insn (insn);
     else
-      emit_library_call_value (memcmp_libfunc, result, LCT_PURE_MAKE_BLOCK,
+      emit_library_call_value (memcmp_libfunc, result, LCT_PURE,
                               TYPE_MODE (integer_type_node), 3,
                               XEXP (arg1_rtx, 0), Pmode,
                               XEXP (arg2_rtx, 0), Pmode,
@@ -4325,7 +4464,7 @@ expand_builtin_strcat (tree fndecl, tree exp, rtx target, enum machine_mode mode
       if (p && *p == '\0')
        return expand_expr (dst, target, mode, EXPAND_NORMAL);
 
-      if (!optimize_size)
+      if (optimize_insn_for_speed_p ())
        {
          /* See if we can store by pieces into (dst + strlen(dst)).  */
          tree newsrc, newdst,
@@ -4340,10 +4479,9 @@ expand_builtin_strcat (tree fndecl, tree exp, rtx target, enum machine_mode mode
 
          /* Create strlen (dst).  */
          newdst = build_call_expr (strlen_fn, 1, dst);
-         /* Create (dst + (cast) strlen (dst)).  */
-         newdst = fold_convert (TREE_TYPE (dst), newdst);
-         newdst = fold_build2 (PLUS_EXPR, TREE_TYPE (dst), dst, newdst);
+         /* Create (dst p+ strlen (dst)).  */
 
+         newdst = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (dst), dst, newdst);
          newdst = builtin_save_expr (newdst);
 
          if (!expand_builtin_strcpy_args (fndecl, newdst, newsrc, target, mode))
@@ -4462,7 +4600,7 @@ static rtx
 expand_builtin_args_info (tree exp)
 {
   int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
-  int *word_ptr = (int *) &current_function_args_info;
+  int *word_ptr = (int *) &crtl->args.info;
 
   gcc_assert (sizeof (CUMULATIVE_ARGS) % sizeof (int) == 0);
 
@@ -4493,9 +4631,9 @@ expand_builtin_next_arg (void)
 {
   /* Checking arguments is already done in fold_builtin_next_arg
      that must be called before this function.  */
-  return expand_binop (Pmode, add_optab,
-                      current_function_internal_arg_pointer,
-                      current_function_arg_offset_rtx,
+  return expand_binop (ptr_mode, add_optab,
+                      crtl->args.internal_arg_pointer,
+                      crtl->args.arg_offset_rtx,
                       NULL_RTX, 0, OPTAB_LIB_WIDEN);
 }
 
@@ -4505,18 +4643,22 @@ expand_builtin_next_arg (void)
 static tree
 stabilize_va_list (tree valist, int needs_lvalue)
 {
-  if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
+  tree vatype = targetm.canonical_va_list_type (TREE_TYPE (valist));
+
+  gcc_assert (vatype != NULL_TREE);
+
+  if (TREE_CODE (vatype) == ARRAY_TYPE)
     {
       if (TREE_SIDE_EFFECTS (valist))
        valist = save_expr (valist);
 
       /* For this case, the backends will be expecting a pointer to
-        TREE_TYPE (va_list_type_node), but it's possible we've
-        actually been given an array (an actual va_list_type_node).
+        vatype, but it's possible we've actually been given an array
+        (an actual TARGET_CANONICAL_VA_LIST_TYPE (valist)).
         So fix it.  */
       if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
        {
-         tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
+         tree p1 = build_pointer_type (TREE_TYPE (vatype));
          valist = build_fold_addr_expr_with_type (valist, p1);
        }
     }
@@ -4529,7 +4671,7 @@ stabilize_va_list (tree valist, int needs_lvalue)
          if (! TREE_SIDE_EFFECTS (valist))
            return valist;
 
-         pt = build_pointer_type (va_list_type_node);
+         pt = build_pointer_type (vatype);
          valist = fold_build1 (ADDR_EXPR, pt, valist);
          TREE_SIDE_EFFECTS (valist) = 1;
        }
@@ -4550,19 +4692,57 @@ std_build_builtin_va_list (void)
   return ptr_type_node;
 }
 
+/* The "standard" abi va_list is va_list_type_node.  */
+
+tree
+std_fn_abi_va_list (tree fndecl ATTRIBUTE_UNUSED)
+{
+  return va_list_type_node;
+}
+
+/* The "standard" type of va_list is va_list_type_node.  */
+
+tree
+std_canonical_va_list_type (tree type)
+{
+  tree wtype, htype;
+
+  if (INDIRECT_REF_P (type))
+    type = TREE_TYPE (type);
+  else if (POINTER_TYPE_P (type) && POINTER_TYPE_P (TREE_TYPE(type)))
+    type = TREE_TYPE (type);
+  wtype = va_list_type_node;
+  htype = type;
+  /* Treat structure va_list types.  */
+  if (TREE_CODE (wtype) == RECORD_TYPE && POINTER_TYPE_P (htype))
+    htype = TREE_TYPE (htype);
+  else if (TREE_CODE (wtype) == ARRAY_TYPE)
+    {
+      /* 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.  */
+      if (TREE_CODE (htype) == ARRAY_TYPE
+         || POINTER_TYPE_P (htype))
+       {
+         wtype = TREE_TYPE (wtype);
+         htype = TREE_TYPE (htype);
+       }
+    }
+  if (TYPE_MAIN_VARIANT (wtype) == TYPE_MAIN_VARIANT (htype))
+    return va_list_type_node;
+
+  return NULL_TREE;
+}
+
 /* The "standard" implementation of va_start: just assign `nextarg' to
    the variable.  */
 
 void
 std_expand_builtin_va_start (tree valist, rtx nextarg)
 {
-  tree t;
-
-  t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist,
-             make_tree (ptr_type_node, nextarg));
-  TREE_SIDE_EFFECTS (t) = 1;
-
-  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+  rtx va_r = expand_expr (valist, NULL_RTX, VOIDmode, EXPAND_WRITE);
+  convert_move (va_r, nextarg, 0);
 }
 
 /* Expand EXP, a call to __builtin_va_start.  */
@@ -4585,11 +4765,10 @@ expand_builtin_va_start (tree exp)
   nextarg = expand_builtin_next_arg ();
   valist = stabilize_va_list (CALL_EXPR_ARG (exp, 0), 1);
 
-#ifdef EXPAND_BUILTIN_VA_START
-  EXPAND_BUILTIN_VA_START (valist, nextarg);
-#else
-  std_expand_builtin_va_start (valist, nextarg);
-#endif
+  if (targetm.expand_builtin_va_start)
+    targetm.expand_builtin_va_start (valist, nextarg);
+  else
+    std_expand_builtin_va_start (valist, nextarg);
 
   return const0_rtx;
 }
@@ -4598,7 +4777,8 @@ expand_builtin_va_start (tree exp)
    current (padded) address and increment by the (padded) size.  */
 
 tree
-std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
+std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
+                         gimple_seq *post_p)
 {
   tree addr, t, type_size, rounded_size, valist_tmp;
   unsigned HOST_WIDE_INT align, boundary;
@@ -4616,7 +4796,16 @@ std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
     type = build_pointer_type (type);
 
   align = PARM_BOUNDARY / BITS_PER_UNIT;
-  boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type) / BITS_PER_UNIT;
+  boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type);
+
+  /* When we align parameter on stack for caller, if the parameter
+     alignment is beyond MAX_SUPPORTED_STACK_ALIGNMENT, it will be
+     aligned at MAX_SUPPORTED_STACK_ALIGNMENT.  We will match callee
+     here with caller.  */
+  if (boundary > MAX_SUPPORTED_STACK_ALIGNMENT)
+    boundary = MAX_SUPPORTED_STACK_ALIGNMENT;
+
+  boundary /= BITS_PER_UNIT;
 
   /* Hoist the valist value into a temporary for the moment.  */
   valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
@@ -4626,14 +4815,16 @@ std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
   if (boundary > align
       && !integer_zerop (TYPE_SIZE (type)))
     {
-      t = fold_convert (TREE_TYPE (valist), size_int (boundary - 1));
       t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
-                 build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t));
+                 fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (valist),
+                              valist_tmp, size_int (boundary - 1)));
       gimplify_and_add (t, pre_p);
 
-      t = fold_convert (TREE_TYPE (valist), size_int (-boundary));
+      t = fold_convert (sizetype, valist_tmp);
       t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
-                 build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist_tmp, t));
+                 fold_convert (TREE_TYPE (valist),
+                               fold_build2 (BIT_AND_EXPR, sizetype, t,
+                                            size_int (-boundary))));
       gimplify_and_add (t, pre_p);
     }
   else
@@ -4641,7 +4832,7 @@ std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
 
   /* If the actual alignment is less than the alignment of the type,
      adjust the type accordingly so that we don't assume strict alignment
-     when deferencing the pointer.  */
+     when dereferencing the pointer.  */
   boundary *= BITS_PER_UNIT;
   if (boundary < TYPE_ALIGN (type))
     {
@@ -4664,13 +4855,11 @@ std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
       t = fold_build2 (GT_EXPR, sizetype, rounded_size, size_int (align));
       t = fold_build3 (COND_EXPR, sizetype, t, size_zero_node,
                       size_binop (MINUS_EXPR, rounded_size, type_size));
-      t = fold_convert (TREE_TYPE (addr), t);
-      addr = fold_build2 (PLUS_EXPR, TREE_TYPE (addr), addr, t);
+      addr = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (addr), addr, t);
     }
 
   /* Compute new value for AP.  */
-  t = fold_convert (TREE_TYPE (valist), rounded_size);
-  t = build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t);
+  t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (valist), valist_tmp, rounded_size);
   t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
   gimplify_and_add (t, pre_p);
 
@@ -4709,35 +4898,20 @@ dummy_object (tree type)
    builtin function, but a very special sort of operator.  */
 
 enum gimplify_status
-gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p)
+gimplify_va_arg_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
 {
-  tree promoted_type, want_va_type, have_va_type;
+  tree promoted_type, have_va_type;
   tree valist = TREE_OPERAND (*expr_p, 0);
   tree type = TREE_TYPE (*expr_p);
   tree t;
 
   /* Verify that valist is of the proper type.  */
-  want_va_type = va_list_type_node;
   have_va_type = TREE_TYPE (valist);
-
   if (have_va_type == error_mark_node)
     return GS_ERROR;
+  have_va_type = targetm.canonical_va_list_type (have_va_type);
 
-  if (TREE_CODE (want_va_type) == ARRAY_TYPE)
-    {
-      /* 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.  */
-      if (TREE_CODE (have_va_type) == ARRAY_TYPE
-         || POINTER_TYPE_P (have_va_type))
-       {
-         want_va_type = TREE_TYPE (want_va_type);
-         have_va_type = TREE_TYPE (have_va_type);
-       }
-    }
-
-  if (TYPE_MAIN_VARIANT (want_va_type) != TYPE_MAIN_VARIANT (have_va_type))
+  if (have_va_type == NULL_TREE)
     {
       error ("first argument to %<va_arg%> not of type %<va_list%>");
       return GS_ERROR;
@@ -4745,7 +4919,7 @@ gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p)
 
   /* 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_hooks.types.type_promotes_to (type))
+  if ((promoted_type = lang_hooks.types.type_promotes_to (type))
           != type)
     {
       static bool gave_help;
@@ -4758,7 +4932,7 @@ gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p)
       if (! gave_help)
        {
          gave_help = true;
-         warning (0, "(so you should pass %qT not %qT to %<va_arg%>)",
+         inform ("(so you should pass %qT not %qT to %<va_arg%>)",
                   promoted_type, type);
        }
 
@@ -4766,7 +4940,7 @@ gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p)
         Call abort to encourage the user to fix the program.  */
       inform ("if this code is reached, the program will abort");
       t = build_call_expr (implicit_built_in_decls[BUILT_IN_TRAP], 0);
-      append_to_statement_list (t, pre_p);
+      gimplify_and_add (t, pre_p);
 
       /* This is dead code, but go ahead and finish so that the
         mode of the result comes out right.  */
@@ -4777,24 +4951,25 @@ gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p)
     {
       /* Make it easier for the backends by protecting the valist argument
         from multiple evaluations.  */
-      if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
+      if (TREE_CODE (have_va_type) == ARRAY_TYPE)
        {
          /* For this case, the backends will be expecting a pointer to
-            TREE_TYPE (va_list_type_node), but it's possible we've
-            actually been given an array (an actual va_list_type_node).
+            TREE_TYPE (abi), but it's possible we've
+            actually been given an array (an actual TARGET_FN_ABI_VA_LIST).
             So fix it.  */
          if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
            {
-             tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
+             tree p1 = build_pointer_type (TREE_TYPE (have_va_type));
              valist = build_fold_addr_expr_with_type (valist, p1);
            }
+
          gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue);
        }
       else
        gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
 
       if (!targetm.gimplify_va_arg_expr)
-       /* FIXME:Once most targets are converted we should merely
+       /* FIXME: Once most targets are converted we should merely
           assert this is non-null.  */
        return GS_ALL_DONE;
 
@@ -4833,9 +5008,11 @@ expand_builtin_va_copy (tree exp)
   dst = stabilize_va_list (dst, 1);
   src = stabilize_va_list (src, 0);
 
-  if (TREE_CODE (va_list_type_node) != ARRAY_TYPE)
+  gcc_assert (cfun != NULL && cfun->decl != NULL_TREE);
+
+  if (TREE_CODE (targetm.fn_abi_va_list (cfun->decl)) != ARRAY_TYPE)
     {
-      t = build2 (MODIFY_EXPR, va_list_type_node, dst, src);
+      t = build2 (MODIFY_EXPR, targetm.fn_abi_va_list (cfun->decl), dst, src);
       TREE_SIDE_EFFECTS (t) = 1;
       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
     }
@@ -4846,8 +5023,8 @@ expand_builtin_va_copy (tree exp)
       /* Evaluate to pointers.  */
       dstb = expand_expr (dst, NULL_RTX, Pmode, EXPAND_NORMAL);
       srcb = expand_expr (src, NULL_RTX, Pmode, EXPAND_NORMAL);
-      size = expand_expr (TYPE_SIZE_UNIT (va_list_type_node), NULL_RTX,
-                         VOIDmode, EXPAND_NORMAL);
+      size = expand_expr (TYPE_SIZE_UNIT (targetm.fn_abi_va_list (cfun->decl)),
+                 NULL_RTX, VOIDmode, EXPAND_NORMAL);
 
       dstb = convert_memory_address (Pmode, dstb);
       srcb = convert_memory_address (Pmode, srcb);
@@ -4855,10 +5032,10 @@ expand_builtin_va_copy (tree exp)
       /* "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));
+      set_mem_align (dstb, TYPE_ALIGN (targetm.fn_abi_va_list (cfun->decl)));
       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));
+      set_mem_align (srcb, TYPE_ALIGN (targetm.fn_abi_va_list (cfun->decl)));
 
       /* Copy.  */
       emit_block_move (dstb, srcb, size, BLOCK_OP_NORMAL);
@@ -4958,7 +5135,7 @@ expand_builtin_bswap (tree exp, rtx target, rtx subtarget)
 
   arg = CALL_EXPR_ARG (exp, 0);
   mode = TYPE_MODE (TREE_TYPE (arg));
-  op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+  op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
 
   target = expand_unop (mode, bswap_optab, op0, target, 1);
 
@@ -4982,7 +5159,8 @@ expand_builtin_unop (enum machine_mode target_mode, tree exp, rtx target,
     return NULL_RTX;
 
   /* Compute the argument.  */
-  op0 = expand_expr (CALL_EXPR_ARG (exp, 0), subtarget, VOIDmode, 0);
+  op0 = expand_expr (CALL_EXPR_ARG (exp, 0), subtarget,
+                    VOIDmode, EXPAND_NORMAL);
   /* Compute op, into TARGET if possible.
      Set TARGET to wherever the result comes back.  */
   target = expand_unop (TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 0))),
@@ -5027,7 +5205,8 @@ expand_builtin_expect (tree exp, rtx target)
 
   target = expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
   /* When guessing was done, the hints should be already stripped away.  */
-  gcc_assert (!flag_guess_branch_prob);
+  gcc_assert (!flag_guess_branch_prob
+             || optimize == 0 || errorcount || sorrycount);
   return target;
 }
 
@@ -5060,8 +5239,9 @@ expand_builtin_fabs (tree exp, rtx target, rtx subtarget)
     return NULL_RTX;
 
   arg = CALL_EXPR_ARG (exp, 0);
+  CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
   mode = TYPE_MODE (TREE_TYPE (arg));
-  op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+  op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
   return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1));
 }
 
@@ -5097,19 +5277,17 @@ build_string_literal (int len, const char *str)
 
   t = build_string (len, str);
   elem = build_type_variant (char_type_node, 1, 0);
-  index = build_index_type (build_int_cst (NULL_TREE, len - 1));
+  index = build_index_type (size_int (len - 1));
   type = build_array_type (elem, index);
   TREE_TYPE (t) = type;
   TREE_CONSTANT (t) = 1;
-  TREE_INVARIANT (t) = 1;
   TREE_READONLY (t) = 1;
   TREE_STATIC (t) = 1;
 
-  type = build_pointer_type (type);
-  t = build1 (ADDR_EXPR, type, t);
-
   type = build_pointer_type (elem);
-  t = build1 (NOP_EXPR, type, t);
+  t = build1 (ADDR_EXPR, type,
+             build4 (ARRAY_REF, elem,
+                     t, integer_zero_node, NULL_TREE, NULL_TREE));
   return t;
 }
 
@@ -5200,7 +5378,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
            {
              /* Create a NUL-terminated string that's one char shorter
                 than the original, stripping off the trailing '\n'.  */
-             char *newstr = alloca (len);
+             char *newstr = XALLOCAVEC (char, len);
              memcpy (newstr, fmt_str, len - 1);
              newstr[len - 1] = 0;
              arg = build_string_literal (len, newstr);
@@ -5417,6 +5595,59 @@ expand_builtin_profile_func (bool exitp)
   return const0_rtx;
 }
 
+/* Expand a call to __builtin___clear_cache.  */
+
+static rtx
+expand_builtin___clear_cache (tree exp ATTRIBUTE_UNUSED)
+{
+#ifndef HAVE_clear_cache
+#ifdef CLEAR_INSN_CACHE
+  /* There is no "clear_cache" insn, and __clear_cache() in libgcc
+     does something.  Just do the default expansion to a call to
+     __clear_cache().  */
+  return NULL_RTX;
+#else
+  /* There is no "clear_cache" insn, and __clear_cache() in libgcc
+     does nothing.  There is no need to call it.  Do nothing.  */
+  return const0_rtx;
+#endif /* CLEAR_INSN_CACHE */
+#else
+  /* We have a "clear_cache" insn, and it will handle everything.  */
+  tree begin, end;
+  rtx begin_rtx, end_rtx;
+  enum insn_code icode;
+
+  /* We must not expand to a library call.  If we did, any
+     fallback library function in libgcc that might contain a call to
+     __builtin___clear_cache() would recurse infinitely.  */
+  if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
+    {
+      error ("both arguments to %<__builtin___clear_cache%> must be pointers");
+      return const0_rtx;
+    }
+
+  if (HAVE_clear_cache)
+    {
+      icode = CODE_FOR_clear_cache;
+
+      begin = CALL_EXPR_ARG (exp, 0);
+      begin_rtx = expand_expr (begin, NULL_RTX, Pmode, EXPAND_NORMAL);
+      begin_rtx = convert_memory_address (Pmode, begin_rtx);
+      if (!insn_data[icode].operand[0].predicate (begin_rtx, Pmode))
+       begin_rtx = copy_to_mode_reg (Pmode, begin_rtx);
+
+      end = CALL_EXPR_ARG (exp, 1);
+      end_rtx = expand_expr (end, NULL_RTX, Pmode, EXPAND_NORMAL);
+      end_rtx = convert_memory_address (Pmode, end_rtx);
+      if (!insn_data[icode].operand[1].predicate (end_rtx, Pmode))
+       end_rtx = copy_to_mode_reg (Pmode, end_rtx);
+
+      emit_insn (gen_clear_cache (begin_rtx, end_rtx));
+    }
+  return const0_rtx;
+#endif /* HAVE_clear_cache */
+}
+
 /* Given a trampoline address, make sure it satisfies TRAMPOLINE_ALIGNMENT.  */
 
 static rtx
@@ -5494,11 +5725,15 @@ expand_builtin_adjust_trampoline (tree exp)
   return tramp;
 }
 
-/* Expand a call to the built-in signbit, signbitf or signbitl function.
-   Return NULL_RTX if a normal call should be emitted rather than expanding
-   the function in-line.  EXP is the expression that is a call to the builtin
-   function; if convenient, the result should be placed in TARGET.  */
-
+/* Expand the call EXP to the built-in signbit, signbitf or signbitl
+   function.  The function first checks whether the back end provides
+   an insn to implement signbit for the respective mode.  If not, it
+   checks whether the floating point format of the value is such that
+   the sign bit can be extracted.  If that is not the case, the
+   function returns NULL_RTX to indicate that a normal call should be
+   emitted rather than expanding the function in-line.  EXP is the
+   expression that is a call to the builtin function; if convenient,
+   the result should be placed in TARGET.  */
 static rtx
 expand_builtin_signbit (tree exp, rtx target)
 {
@@ -5507,6 +5742,7 @@ expand_builtin_signbit (tree exp, rtx target)
   HOST_WIDE_INT hi, lo;
   tree arg;
   int word, bitpos;
+  enum insn_code icode;
   rtx temp;
 
   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
@@ -5517,6 +5753,21 @@ expand_builtin_signbit (tree exp, rtx target)
   rmode = TYPE_MODE (TREE_TYPE (exp));
   fmt = REAL_MODE_FORMAT (fmode);
 
+  arg = builtin_save_expr (arg);
+
+  /* Expand the argument yielding a RTX expression. */
+  temp = expand_normal (arg);
+
+  /* Check if the back end provides an insn that handles signbit for the
+     argument's mode. */
+  icode = signbit_optab->handlers [(int) fmode].insn_code;
+  if (icode != CODE_FOR_nothing)
+    {
+      target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
+      emit_unop_insn (icode, target, temp, UNKNOWN);
+      return target;
+    }
+
   /* For floating point formats without a sign bit, implement signbit
      as "ARG < 0.0".  */
   bitpos = fmt->signbit_ro;
@@ -5531,7 +5782,6 @@ expand_builtin_signbit (tree exp, rtx target)
     return expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
   }
 
-  temp = expand_normal (arg);
   if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD)
     {
       imode = int_mode_for_mode (fmode);
@@ -5573,7 +5823,7 @@ expand_builtin_signbit (tree exp, rtx target)
          lo = 0;
        }
 
-      if (imode != rmode)
+      if (GET_MODE_SIZE (imode) > GET_MODE_SIZE (rmode))
        temp = gen_lowpart (rmode, temp);
       temp = expand_binop (rmode, and_optab, temp,
                           immed_double_const (lo, hi, rmode),
@@ -5684,7 +5934,7 @@ get_builtin_sync_mem (tree loc, enum machine_mode mode)
 {
   rtx addr, mem;
 
-  addr = expand_expr (loc, NULL, Pmode, EXPAND_SUM);
+  addr = expand_expr (loc, NULL_RTX, Pmode, EXPAND_SUM);
 
   /* Note that we explicitly do not want any alias information for this
      memory, so that we kill all other live memories.  Otherwise we don't
@@ -5712,13 +5962,18 @@ expand_builtin_sync_operation (enum machine_mode mode, tree exp,
                               rtx target, bool ignore)
 {
   rtx val, mem;
+  enum machine_mode old_mode;
 
   /* Expand the operands.  */
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
 
-  val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL, mode, EXPAND_NORMAL);
-  /* If VAL is promoted to a wider mode, convert it back to MODE.  */
-  val = convert_to_mode (mode, val, 1);
+  val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL_RTX, mode, EXPAND_NORMAL);
+  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
+     of CONST_INTs, where we know the old_mode only from the call argument.  */
+  old_mode = GET_MODE (val);
+  if (old_mode == VOIDmode)
+    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1)));
+  val = convert_modes (mode, old_mode, val, 1);
 
   if (ignore)
     return expand_sync_operation (mem, val, code);
@@ -5736,18 +5991,29 @@ expand_builtin_compare_and_swap (enum machine_mode mode, tree exp,
                                 bool is_bool, rtx target)
 {
   rtx old_val, new_val, mem;
+  enum machine_mode old_mode;
 
   /* Expand the operands.  */
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
 
 
-  old_val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL, mode, EXPAND_NORMAL);
-  /* If OLD_VAL is promoted to a wider mode, convert it back to MODE.  */
-  old_val = convert_to_mode (mode, old_val, 1);
-
-  new_val = expand_expr (CALL_EXPR_ARG (exp, 2), NULL, mode, EXPAND_NORMAL);
-  /* If NEW_VAL is promoted to a wider mode, convert it back to MODE.  */
-  new_val = convert_to_mode (mode, new_val, 1);
+  old_val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL_RTX,
+                        mode, EXPAND_NORMAL);
+  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
+     of CONST_INTs, where we know the old_mode only from the call argument.  */
+  old_mode = GET_MODE (old_val);
+  if (old_mode == VOIDmode)
+    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1)));
+  old_val = convert_modes (mode, old_mode, old_val, 1);
+
+  new_val = expand_expr (CALL_EXPR_ARG (exp, 2), NULL_RTX,
+                        mode, EXPAND_NORMAL);
+  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
+     of CONST_INTs, where we know the old_mode only from the call argument.  */
+  old_mode = GET_MODE (new_val);
+  if (old_mode == VOIDmode)
+    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 2)));
+  new_val = convert_modes (mode, old_mode, new_val, 1);
 
   if (is_bool)
     return expand_bool_compare_and_swap (mem, old_val, new_val, target);
@@ -5766,12 +6032,17 @@ expand_builtin_lock_test_and_set (enum machine_mode mode, tree exp,
                                  rtx target)
 {
   rtx val, mem;
+  enum machine_mode old_mode;
 
   /* Expand the operands.  */
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
-  val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL, mode, EXPAND_NORMAL);
-  /* If VAL is promoted to a wider mode, convert it back to MODE.  */
-  val = convert_to_mode (mode, val, 1);
+  val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL_RTX, mode, EXPAND_NORMAL);
+  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
+     of CONST_INTs, where we know the old_mode only from the call argument.  */
+  old_mode = GET_MODE (val);
+  if (old_mode == VOIDmode)
+    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1)));
+  val = convert_modes (mode, old_mode, val, 1);
 
   return expand_sync_lock_test_and_set (mem, val, target);
 }
@@ -5791,6 +6062,12 @@ expand_builtin_synchronize (void)
     }
 #endif
 
+  if (synchronize_libfunc != NULL_RTX)
+    {
+      emit_library_call (synchronize_libfunc, LCT_NORMAL, VOIDmode, 0);
+      return;
+    }
+
   /* If no explicit memory barrier instruction is available, create an
      empty asm stmt with a memory clobber.  */
   x = build4 (ASM_EXPR, void_type_node, build_string (0, ""), NULL, NULL,
@@ -5854,7 +6131,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
   if (!optimize
       && !called_as_built_in (fndecl)
       && DECL_ASSEMBLER_NAME_SET_P (fndecl)
-      && fcode != BUILT_IN_ALLOCA)
+      && fcode != BUILT_IN_ALLOCA
+      && fcode != BUILT_IN_FREE)
     return expand_call (exp, target, ignore);
 
   /* The built-in function expanders test for target == const0_rtx
@@ -5866,7 +6144,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
      none of its arguments are volatile, we can avoid expanding the
      built-in call and just evaluate the arguments for side-effects.  */
   if (target == const0_rtx
-      && (DECL_IS_PURE (fndecl) || TREE_READONLY (fndecl)))
+      && (DECL_PURE_P (fndecl) || TREE_READONLY (fndecl)))
     {
       bool volatilep = false;
       tree arg;
@@ -5940,6 +6218,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       if (! flag_unsafe_math_optimizations)
        break;
     CASE_FLT_FN (BUILT_IN_ISINF):
+    CASE_FLT_FN (BUILT_IN_FINITE):
+    case BUILT_IN_ISFINITE:
+    case BUILT_IN_ISNORMAL:
       target = expand_builtin_interclass_mathfn (exp, target, subtarget);
       if (target)
        return target;
@@ -5949,7 +6230,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     CASE_FLT_FN (BUILT_IN_LLCEIL):
     CASE_FLT_FN (BUILT_IN_LFLOOR):
     CASE_FLT_FN (BUILT_IN_LLFLOOR):
-      target = expand_builtin_int_roundingfn (exp, target, subtarget);
+      target = expand_builtin_int_roundingfn (exp, target);
       if (target)
        return target;
       break;
@@ -5958,7 +6239,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     CASE_FLT_FN (BUILT_IN_LLRINT):
     CASE_FLT_FN (BUILT_IN_LROUND):
     CASE_FLT_FN (BUILT_IN_LLROUND):
-      target = expand_builtin_int_roundingfn_2 (exp, target, subtarget);
+      target = expand_builtin_int_roundingfn_2 (exp, target);
       if (target)
        return target;
       break;
@@ -6057,12 +6338,30 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_ARGS_INFO:
       return expand_builtin_args_info (exp);
 
+    case BUILT_IN_VA_ARG_PACK:
+      /* All valid uses of __builtin_va_arg_pack () are removed during
+        inlining.  */
+      error ("%Kinvalid use of %<__builtin_va_arg_pack ()%>", exp);
+      return const0_rtx;
+
+    case BUILT_IN_VA_ARG_PACK_LEN:
+      /* All valid uses of __builtin_va_arg_pack_len () are removed during
+        inlining.  */
+      error ("%Kinvalid use of %<__builtin_va_arg_pack_len ()%>", exp);
+      return const0_rtx;
+
       /* Return the address of the first anonymous stack arg.  */
     case BUILT_IN_NEXT_ARG:
       if (fold_builtin_next_arg (exp, false))
        return const0_rtx;
       return expand_builtin_next_arg ();
 
+    case BUILT_IN_CLEAR_CACHE:
+      target = expand_builtin___clear_cache (exp);
+      if (target)
+        return target;
+      break;
+
     case BUILT_IN_CLASSIFY_TYPE:
       return expand_builtin_classify_type (exp);
 
@@ -6266,6 +6565,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
+    case BUILT_IN_MEMCHR:
+      target = expand_builtin_memchr (exp, target, mode);
+      if (target)
+       return target;
+      break;
+
     case BUILT_IN_BCMP:
     case BUILT_IN_MEMCMP:
       target = expand_builtin_memcmp (exp, target, mode);
@@ -6412,6 +6717,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       break;
 
     CASE_FLT_FN (BUILT_IN_SIGNBIT):
+    case BUILT_IN_SIGNBITD32:
+    case BUILT_IN_SIGNBITD64:
+    case BUILT_IN_SIGNBITD128:
       target = expand_builtin_signbit (exp, target);
       if (target)
        return target;
@@ -6446,7 +6754,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       return expand_builtin_extend_pointer (CALL_EXPR_ARG (exp, 0));
 
     case BUILT_IN_VA_START:
-    case BUILT_IN_STDARG_START:
       return expand_builtin_va_start (exp);
     case BUILT_IN_VA_END:
       return expand_builtin_va_end (exp);
@@ -6702,6 +7009,10 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       maybe_emit_sprintf_chk_warning (exp, fcode);
       break;
 
+    case BUILT_IN_FREE:
+      maybe_emit_free_warning (exp);
+      break;
+
     default:   /* just do library call, if unknown builtin */
       break;
     }
@@ -6718,11 +7029,11 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
    Otherwise the return value is END_BUILTINS.  */
 
 enum built_in_function
-builtin_mathfn_code (tree t)
+builtin_mathfn_code (const_tree t)
 {
-  tree fndecl, arg, parmlist;
-  tree argtype, parmtype;
-  call_expr_arg_iterator iter;
+  const_tree fndecl, arg, parmlist;
+  const_tree argtype, parmtype;
+  const_call_expr_arg_iterator iter;
 
   if (TREE_CODE (t) != CALL_EXPR
       || TREE_CODE (CALL_EXPR_FN (t)) != ADDR_EXPR)
@@ -6736,7 +7047,7 @@ builtin_mathfn_code (tree t)
     return END_BUILTINS;
 
   parmlist = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
-  init_call_expr_arg_iterator (t, &iter);
+  init_const_call_expr_arg_iterator (t, &iter);
   for (; parmlist; parmlist = TREE_CHAIN (parmlist))
     {
       /* If a function doesn't take a variable number of arguments,
@@ -6744,15 +7055,15 @@ builtin_mathfn_code (tree t)
       parmtype = TREE_VALUE (parmlist);
       if (VOID_TYPE_P (parmtype))
        {
-         if (more_call_expr_args_p (&iter))
+         if (more_const_call_expr_args_p (&iter))
            return END_BUILTINS;
          return DECL_FUNCTION_CODE (fndecl);
        }
 
-      if (! more_call_expr_args_p (&iter))
+      if (! more_const_call_expr_args_p (&iter))
        return END_BUILTINS;
       
-      arg = next_call_expr_arg (&iter);
+      arg = next_const_call_expr_arg (&iter);
       argtype = TREE_TYPE (arg);
 
       if (SCALAR_FLOAT_TYPE_P (parmtype))
@@ -6826,21 +7137,80 @@ fold_builtin_constant_p (tree arg)
   return NULL_TREE;
 }
 
-/* Fold a call to __builtin_expect with argument ARG, if we expect that a
-   comparison against the argument will fold to a constant.  In practice,
-   this means a true constant or the address of a non-weak symbol.  */
+/* Create builtin_expect with PRED and EXPECTED as its arguments and
+   return it as a truthvalue.  */
+
+static tree
+build_builtin_expect_predicate (tree pred, tree expected)
+{
+  tree fn, arg_types, pred_type, expected_type, call_expr, ret_type;
+
+  fn = built_in_decls[BUILT_IN_EXPECT];
+  arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
+  ret_type = TREE_TYPE (TREE_TYPE (fn));
+  pred_type = TREE_VALUE (arg_types);
+  expected_type = TREE_VALUE (TREE_CHAIN (arg_types));
+
+  pred = fold_convert (pred_type, pred);
+  expected = fold_convert (expected_type, expected);
+  call_expr = build_call_expr (fn, 2, pred, expected);
+
+  return build2 (NE_EXPR, TREE_TYPE (pred), call_expr,
+                build_int_cst (ret_type, 0));
+}
+
+/* Fold a call to builtin_expect with arguments ARG0 and ARG1.  Return
+   NULL_TREE if no simplification is possible.  */
 
 static tree
-fold_builtin_expect (tree arg)
+fold_builtin_expect (tree arg0, tree arg1)
 {
-  tree inner;
+  tree inner, fndecl;
+  enum tree_code code;
+
+  /* If this is a builtin_expect within a builtin_expect keep the
+     inner one.  See through a comparison against a constant.  It
+     might have been added to create a thruthvalue.  */
+  inner = arg0;
+  if (COMPARISON_CLASS_P (inner)
+      && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST)
+    inner = TREE_OPERAND (inner, 0);
+
+  if (TREE_CODE (inner) == CALL_EXPR
+      && (fndecl = get_callee_fndecl (inner))
+      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+      && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT)
+    return arg0;
+
+  /* Distribute the expected value over short-circuiting operators.
+     See through the cast from truthvalue_type_node to long.  */
+  inner = arg0;
+  while (TREE_CODE (inner) == NOP_EXPR
+        && INTEGRAL_TYPE_P (TREE_TYPE (inner))
+        && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (inner, 0))))
+    inner = TREE_OPERAND (inner, 0);
+
+  code = TREE_CODE (inner);
+  if (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
+    {
+      tree op0 = TREE_OPERAND (inner, 0);
+      tree op1 = TREE_OPERAND (inner, 1);
+
+      op0 = build_builtin_expect_predicate (op0, arg1);
+      op1 = build_builtin_expect_predicate (op1, arg1);
+      inner = build2 (code, TREE_TYPE (inner), op0, op1);
+
+      return fold_convert (TREE_TYPE (arg0), inner);
+    }
 
-  /* If the argument isn't invariant, then there's nothing we can do.  */
-  if (!TREE_INVARIANT (arg))
+  /* If the argument isn't invariant then there's nothing else we can do.  */
+  if (!TREE_CONSTANT (arg0))
     return NULL_TREE;
 
-  /* If we're looking at an address of a weak decl, then do not fold.  */
-  inner = arg;
+  /* If we expect that a comparison against the argument will fold to
+     a constant return the constant.  In practice, this means a true
+     constant or the address of a non-weak symbol.  */
+  inner = arg0;
   STRIP_NOPS (inner);
   if (TREE_CODE (inner) == ADDR_EXPR)
     {
@@ -6854,8 +7224,8 @@ fold_builtin_expect (tree arg)
        return NULL_TREE;
     }
 
-  /* Otherwise, ARG already has the proper type for the return value.  */
-  return arg;
+  /* Otherwise, ARG0 already has the proper type for the return value.  */
+  return arg0;
 }
 
 /* Fold a call to __builtin_classify_type with argument ARG.  */
@@ -6907,7 +7277,7 @@ fold_builtin_inf (tree type, int warn)
      Thus we pedwarn to ensure this constraint violation is
      diagnosed.  */
   if (!MODE_HAS_INFINITIES (TYPE_MODE (type)) && warn)
-    pedwarn ("target format does not support infinity");
+    pedwarn (0, "target format does not support infinity");
 
   real_inf (&real);
   return build_real (type, real);
@@ -6946,13 +7316,12 @@ integer_valued_real_p (tree t)
 
     case ABS_EXPR:
     case SAVE_EXPR:
-    case NON_LVALUE_EXPR:
       return integer_valued_real_p (TREE_OPERAND (t, 0));
 
     case COMPOUND_EXPR:
     case MODIFY_EXPR:
     case BIND_EXPR:
-      return integer_valued_real_p (GENERIC_TREE_OPERAND (t, 1));
+      return integer_valued_real_p (TREE_OPERAND (t, 1));
 
     case PLUS_EXPR:
     case MINUS_EXPR:
@@ -7144,7 +7513,8 @@ fold_builtin_cabs (tree arg, tree type, tree fndecl)
          && operand_equal_p (real, imag, OEP_PURE_SAME))
         {
          const REAL_VALUE_TYPE sqrt2_trunc
-           = real_value_truncate (TYPE_MODE (type), dconstsqrt2);
+           = real_value_truncate (TYPE_MODE (type),
+                                  *get_real_const (rv_sqrt2));
          STRIP_NOPS (real);
          return fold_build2 (MULT_EXPR, type,
                              fold_build1 (ABS_EXPR, type, real),
@@ -7227,7 +7597,7 @@ fold_builtin_sqrt (tree arg, tree type)
          tree tree_root;
          /* The inner root was either sqrt or cbrt.  */
          REAL_VALUE_TYPE dconstroot =
-           BUILTIN_SQRT_P (fcode) ? dconsthalf : dconstthird;
+           BUILTIN_SQRT_P (fcode) ? dconsthalf : *get_real_const (rv_third);
 
          /* Adjust for the outer root.  */
          SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
@@ -7280,7 +7650,7 @@ fold_builtin_cbrt (tree arg, tree type)
        {
          tree expfn = TREE_OPERAND (CALL_EXPR_FN (arg), 0);
          const REAL_VALUE_TYPE third_trunc =
-           real_value_truncate (TYPE_MODE (type), dconstthird);
+           real_value_truncate (TYPE_MODE (type), *get_real_const (rv_third));
          arg = fold_build2 (MULT_EXPR, type,
                             CALL_EXPR_ARG (arg, 0),
                             build_real (type, third_trunc));
@@ -7296,7 +7666,7 @@ fold_builtin_cbrt (tree arg, tree type)
            {
              tree arg0 = CALL_EXPR_ARG (arg, 0);
              tree tree_root;
-             REAL_VALUE_TYPE dconstroot = dconstthird;
+             REAL_VALUE_TYPE dconstroot = *get_real_const (rv_third);
 
              SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
              dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
@@ -7318,7 +7688,9 @@ fold_builtin_cbrt (tree arg, tree type)
                  tree tree_root;
                  REAL_VALUE_TYPE dconstroot;
 
-                 real_arithmetic (&dconstroot, MULT_EXPR, &dconstthird, &dconstthird);
+                 real_arithmetic (&dconstroot, MULT_EXPR,
+                                  get_real_const (rv_third),
+                                  get_real_const (rv_third));
                  dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
                  tree_root = build_real (type, dconstroot);
                  return build_call_expr (powfn, 2, arg0, tree_root);
@@ -7337,7 +7709,8 @@ fold_builtin_cbrt (tree arg, tree type)
            {
              tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg), 0);
              const REAL_VALUE_TYPE dconstroot
-               = real_value_truncate (TYPE_MODE (type), dconstthird);
+               = real_value_truncate (TYPE_MODE (type),
+                                      *get_real_const (rv_third));
              tree narg01 = fold_build2 (MULT_EXPR, type, arg01,
                                         build_real (type, dconstroot));
              return build_call_expr (powfn, 2, arg00, narg01);
@@ -7506,13 +7879,13 @@ fold_builtin_cexp (tree arg0, tree type)
       icall = builtin_save_expr (icall);
       rcall = build_call_expr (rfn, 1, realp);
       rcall = builtin_save_expr (rcall);
-      return build2 (COMPLEX_EXPR, type,
-                    build2 (MULT_EXPR, rtype,
-                            rcall,
-                            build1 (REALPART_EXPR, rtype, icall)),
-                    build2 (MULT_EXPR, rtype,
-                            rcall,
-                            build1 (IMAGPART_EXPR, rtype, icall)));
+      return fold_build2 (COMPLEX_EXPR, type,
+                         fold_build2 (MULT_EXPR, rtype,
+                                      rcall,
+                                      fold_build1 (REALPART_EXPR, rtype, icall)),
+                         fold_build2 (MULT_EXPR, rtype,
+                                      rcall,
+                                      fold_build1 (IMAGPART_EXPR, rtype, icall)));
     }
 
   return NULL_TREE;
@@ -7649,7 +8022,7 @@ fold_builtin_int_roundingfn (tree fndecl, tree arg)
     {
       const REAL_VALUE_TYPE x = TREE_REAL_CST (arg);
 
-      if (! REAL_VALUE_ISNAN (x) && ! REAL_VALUE_ISINF (x))
+      if (real_isfinite (&x))
        {
          tree itype = TREE_TYPE (TREE_TYPE (fndecl));
          tree ftype = TREE_TYPE (arg);
@@ -7885,7 +8258,7 @@ fold_builtin_logarithm (tree fndecl, tree arg,
       if (flag_unsafe_math_optimizations && func == mpfr_log)
         {
          const REAL_VALUE_TYPE e_truncated =
-           real_value_truncate (TYPE_MODE (type), dconste);
+           real_value_truncate (TYPE_MODE (type), *get_real_const (rv_e));
          if (real_dconstp (arg, &e_truncated))
            return build_real (type, dconst1);
        }
@@ -7919,7 +8292,8 @@ fold_builtin_logarithm (tree fndecl, tree arg,
          CASE_FLT_FN (BUILT_IN_EXP):
            /* Prepare to do logN(exp(exponent) -> exponent*logN(e).  */
            x = build_real (type,
-                           real_value_truncate (TYPE_MODE (type), dconste));
+                           real_value_truncate (TYPE_MODE (type),
+                                                *get_real_const (rv_e)));
            exponent = CALL_EXPR_ARG (arg, 0);
            break;
          CASE_FLT_FN (BUILT_IN_EXP2):
@@ -7930,7 +8304,11 @@ fold_builtin_logarithm (tree fndecl, tree arg,
          CASE_FLT_FN (BUILT_IN_EXP10):
          CASE_FLT_FN (BUILT_IN_POW10):
            /* Prepare to do logN(exp10(exponent) -> exponent*logN(10).  */
-           x = build_real (type, dconst10);
+           {
+             REAL_VALUE_TYPE dconst10;
+             real_from_integer (&dconst10, VOIDmode, 10, 0, 0);
+             x = build_real (type, dconst10);
+           }
            exponent = CALL_EXPR_ARG (arg, 0);
            break;
          CASE_FLT_FN (BUILT_IN_SQRT):
@@ -7942,7 +8320,7 @@ fold_builtin_logarithm (tree fndecl, tree arg,
            /* Prepare to do logN(cbrt(x) -> (1/3)*logN(x).  */
            x = CALL_EXPR_ARG (arg, 0);
            exponent = build_real (type, real_value_truncate (TYPE_MODE (type),
-                                                             dconstthird));
+                                                             *get_real_const (rv_third)));
            break;
          CASE_FLT_FN (BUILT_IN_POW):
            /* Prepare to do logN(pow(x,exponent) -> exponent*logN(x).  */
@@ -8002,7 +8380,7 @@ fold_builtin_hypot (tree fndecl, tree arg0, tree arg1, tree type)
       && operand_equal_p (arg0, arg1, OEP_PURE_SAME))
     {
       const REAL_VALUE_TYPE sqrt2_trunc
-       = real_value_truncate (TYPE_MODE (type), dconstsqrt2);
+       = real_value_truncate (TYPE_MODE (type), *get_real_const (rv_sqrt2));
       return fold_build2 (MULT_EXPR, type,
                          fold_build1 (ABS_EXPR, type, arg0),
                          build_real (type, sqrt2_trunc));
@@ -8068,7 +8446,8 @@ fold_builtin_pow (tree fndecl, tree arg0, tree arg1, tree type)
       if (flag_unsafe_math_optimizations)
        {
          const REAL_VALUE_TYPE dconstroot
-           = real_value_truncate (TYPE_MODE (type), dconstthird);
+           = real_value_truncate (TYPE_MODE (type),
+                                  *get_real_const (rv_third));
 
          if (REAL_VALUES_EQUAL (c, dconstroot))
            {
@@ -8135,7 +8514,8 @@ fold_builtin_pow (tree fndecl, tree arg0, tree arg1, tree type)
          if (tree_expr_nonnegative_p (arg))
            {
              const REAL_VALUE_TYPE dconstroot
-               = real_value_truncate (TYPE_MODE (type), dconstthird);
+               = real_value_truncate (TYPE_MODE (type),
+                                      *get_real_const (rv_third));
              tree narg1 = fold_build2 (MULT_EXPR, type, arg1,
                                        build_real (type, dconstroot));
              return build_call_expr (fndecl, 2, arg, narg1);
@@ -8436,9 +8816,9 @@ fold_builtin_memory_op (tree dest, tree src, tree len, tree type, bool ignore, i
       if (!tree_int_cst_equal (lang_hooks.expr_size (srcvar), len))
        return NULL_TREE;
       /* With memcpy, it is possible to bypass aliasing rules, so without
-         this check i. e. execute/20060930-2.c would be misoptimized, because
+         this check i.e. execute/20060930-2.c would be misoptimized, because
         it use conflicting alias set to hold argument for the memcpy call.
-        This check is probably unnecesary with -fno-strict-aliasing. 
+        This check is probably unnecessary with -fno-strict-aliasing.
         Similarly for destvar.  See also PR29286.  */
       if (!var_decl_component_p (srcvar)
          /* Accept: memcpy (*char_var, "test", 1); that simplify
@@ -8457,7 +8837,7 @@ fold_builtin_memory_op (tree dest, tree src, tree len, tree type, bool ignore, i
 
       if (srctype == desttype
          || (gimple_in_ssa_p (cfun)
-             && tree_ssa_useless_type_conversion_1 (desttype, srctype)))
+             && useless_type_conversion_p (desttype, srctype)))
        expr = srcvar;
       else if ((INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
           || POINTER_TYPE_P (TREE_TYPE (srcvar)))
@@ -8482,8 +8862,7 @@ fold_builtin_memory_op (tree dest, tree src, tree len, tree type, bool ignore, i
     len = fold_build2 (MINUS_EXPR, TREE_TYPE (len), len,
                       ssize_int (1));
 
-  len = fold_convert (TREE_TYPE (dest), len);
-  dest = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, len);
+  dest = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (dest), dest, len);
   dest = fold_convert (type, dest);
   if (expr)
     dest = omit_one_operand (type, dest, expr);
@@ -8572,23 +8951,65 @@ fold_builtin_strncpy (tree fndecl, tree dest, tree src, tree len, tree slen)
                       build_call_expr (fn, 3, dest, src, len));
 }
 
-/* Fold function call to builtin memcmp with arguments ARG1 and ARG2.
+/* Fold function call to builtin memchr.  ARG1, ARG2 and LEN are the
+   arguments to the call, and TYPE is its return type.
    Return NULL_TREE if no simplification can be made.  */
 
 static tree
-fold_builtin_memcmp (tree arg1, tree arg2, tree len)
+fold_builtin_memchr (tree arg1, tree arg2, tree len, tree type)
 {
-  const char *p1, *p2;
-
   if (!validate_arg (arg1, POINTER_TYPE)
-      || !validate_arg (arg2, POINTER_TYPE)
+      || !validate_arg (arg2, INTEGER_TYPE)
       || !validate_arg (len, INTEGER_TYPE))
     return NULL_TREE;
+  else
+    {
+      const char *p1;
 
-  /* If the LEN parameter is zero, return zero.  */
-  if (integer_zerop (len))
-    return omit_two_operands (integer_type_node, integer_zero_node,
-                             arg1, arg2);
+      if (TREE_CODE (arg2) != INTEGER_CST
+         || !host_integerp (len, 1))
+       return NULL_TREE;
+
+      p1 = c_getstr (arg1);
+      if (p1 && compare_tree_int (len, strlen (p1) + 1) <= 0)
+       {
+         char c;
+         const char *r;
+         tree tem;
+
+         if (target_char_cast (arg2, &c))
+           return NULL_TREE;
+
+         r = (char *) memchr (p1, c, tree_low_cst (len, 1));
+
+         if (r == NULL)
+           return build_int_cst (TREE_TYPE (arg1), 0);
+
+         tem = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (arg1), arg1,
+                            size_int (r - p1));
+         return fold_convert (type, tem);
+       }
+      return NULL_TREE;
+    }
+}
+
+/* Fold function call to builtin memcmp with arguments ARG1 and ARG2.
+   Return NULL_TREE if no simplification can be made.  */
+
+static tree
+fold_builtin_memcmp (tree arg1, tree arg2, tree len)
+{
+  const char *p1, *p2;
+
+  if (!validate_arg (arg1, POINTER_TYPE)
+      || !validate_arg (arg2, POINTER_TYPE)
+      || !validate_arg (len, INTEGER_TYPE))
+    return NULL_TREE;
+
+  /* If the LEN parameter is zero, return zero.  */
+  if (integer_zerop (len))
+    return omit_two_operands (integer_type_node, integer_zero_node,
+                             arg1, arg2);
 
   /* If ARG1 and ARG2 are the same (and not volatile), return zero.  */
   if (operand_equal_p (arg1, arg2, 0))
@@ -9168,8 +9589,7 @@ fold_builtin_load_exponent (tree arg0, tree arg1, tree type, bool ldexp)
       /* If arg0 is 0, Inf or NaN, or if arg1 is 0, then return arg0.  */
       if (real_zerop (arg0) || integer_zerop (arg1)
          || (TREE_CODE (arg0) == REAL_CST
-             && (real_isnan (&TREE_REAL_CST (arg0))
-                 || real_isinf (&TREE_REAL_CST (arg0)))))
+             && !real_isfinite (&TREE_REAL_CST (arg0))))
        return omit_one_operand (type, arg0, arg1);
       
       /* If both arguments are constant, then try to evaluate it.  */
@@ -9280,11 +9700,7 @@ fold_builtin_classify (tree fndecl, tree arg, int builtin_index)
   REAL_VALUE_TYPE r;
 
   if (!validate_arg (arg, REAL_TYPE))
-    {
-      error ("non-floating-point argument to function %qs",
-            IDENTIFIER_POINTER (DECL_NAME (fndecl)));
-      return error_mark_node;
-    }
+    return NULL_TREE;
 
   switch (builtin_index)
     {
@@ -9304,7 +9720,38 @@ fold_builtin_classify (tree fndecl, tree arg, int builtin_index)
 
       return NULL_TREE;
 
-    case BUILT_IN_FINITE:
+    case BUILT_IN_ISINF_SIGN:
+      {
+       /* isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0 */
+       /* In a boolean context, GCC will fold the inner COND_EXPR to
+          1.  So e.g. "if (isinf_sign(x))" would be folded to just
+          "if (isinf(x) ? 1 : 0)" which becomes "if (isinf(x))". */
+       tree signbit_fn = mathfn_built_in_1 (TREE_TYPE (arg), BUILT_IN_SIGNBIT, 0);
+       tree isinf_fn = built_in_decls[BUILT_IN_ISINF];
+       tree tmp = NULL_TREE;
+
+       arg = builtin_save_expr (arg);
+
+       if (signbit_fn && isinf_fn)
+         {
+           tree signbit_call = build_call_expr (signbit_fn, 1, arg);
+           tree isinf_call = build_call_expr (isinf_fn, 1, arg);
+
+           signbit_call = fold_build2 (NE_EXPR, integer_type_node,
+                                       signbit_call, integer_zero_node);
+           isinf_call = fold_build2 (NE_EXPR, integer_type_node,
+                                     isinf_call, integer_zero_node);
+           
+           tmp = fold_build3 (COND_EXPR, integer_type_node, signbit_call,
+                              integer_minus_one_node, integer_one_node);
+           tmp = fold_build3 (COND_EXPR, integer_type_node, isinf_call, tmp,
+                              integer_zero_node);
+         }
+
+       return tmp;
+      }
+
+    case BUILT_IN_ISFINITE:
       if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg)))
          && !HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg))))
        return omit_one_operand (type, integer_one_node, arg);
@@ -9312,8 +9759,7 @@ fold_builtin_classify (tree fndecl, tree arg, int builtin_index)
       if (TREE_CODE (arg) == REAL_CST)
        {
          r = TREE_REAL_CST (arg);
-         return real_isinf (&r) || real_isnan (&r)
-                ? integer_zero_node : integer_one_node;
+         return real_isfinite (&r) ? integer_one_node : integer_zero_node;
        }
 
       return NULL_TREE;
@@ -9336,6 +9782,71 @@ fold_builtin_classify (tree fndecl, tree arg, int builtin_index)
     }
 }
 
+/* Fold a call to __builtin_fpclassify(int, int, int, int, int, ...).
+   This builtin will generate code to return the appropriate floating
+   point classification depending on the value of the floating point
+   number passed in.  The possible return values must be supplied as
+   int arguments to the call in the following order: FP_NAN, FP_INFINITE,
+   FP_NORMAL, FP_SUBNORMAL and FP_ZERO.  The ellipses is for exactly
+   one floating point argument which is "type generic".  */
+
+static tree
+fold_builtin_fpclassify (tree exp)
+{
+  tree fp_nan, fp_infinite, fp_normal, fp_subnormal, fp_zero,
+    arg, type, res, tmp;
+  enum machine_mode mode;
+  REAL_VALUE_TYPE r;
+  char buf[128];
+  
+  /* Verify the required arguments in the original call.  */
+  if (!validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE,
+                        INTEGER_TYPE, INTEGER_TYPE,
+                        INTEGER_TYPE, REAL_TYPE, VOID_TYPE))
+    return NULL_TREE;
+  
+  fp_nan = CALL_EXPR_ARG (exp, 0);
+  fp_infinite = CALL_EXPR_ARG (exp, 1);
+  fp_normal = CALL_EXPR_ARG (exp, 2);
+  fp_subnormal = CALL_EXPR_ARG (exp, 3);
+  fp_zero = CALL_EXPR_ARG (exp, 4);
+  arg = CALL_EXPR_ARG (exp, 5);
+  type = TREE_TYPE (arg);
+  mode = TYPE_MODE (type);
+  arg = builtin_save_expr (fold_build1 (ABS_EXPR, type, arg));
+
+  /* fpclassify(x) -> 
+       isnan(x) ? FP_NAN :
+         (fabs(x) == Inf ? FP_INFINITE :
+          (fabs(x) >= DBL_MIN ? FP_NORMAL :
+            (x == 0 ? FP_ZERO : FP_SUBNORMAL))).  */
+  
+  tmp = fold_build2 (EQ_EXPR, integer_type_node, arg,
+                    build_real (type, dconst0));
+  res = fold_build3 (COND_EXPR, integer_type_node, tmp, fp_zero, fp_subnormal);
+
+  sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (mode)->emin - 1);
+  real_from_string (&r, buf);
+  tmp = fold_build2 (GE_EXPR, integer_type_node, arg, build_real (type, r));
+  res = fold_build3 (COND_EXPR, integer_type_node, tmp, fp_normal, res);
+  
+  if (HONOR_INFINITIES (mode))
+    {
+      real_inf (&r);
+      tmp = fold_build2 (EQ_EXPR, integer_type_node, arg,
+                        build_real (type, r));
+      res = fold_build3 (COND_EXPR, integer_type_node, tmp, fp_infinite, res);
+    }
+
+  if (HONOR_NANS (mode))
+    {
+      tmp = fold_build2 (ORDERED_EXPR, integer_type_node, arg, arg);
+      res = fold_build3 (COND_EXPR, integer_type_node, tmp, res, fp_nan);
+    }
+  
+  return res;
+}
+
 /* Fold a call to an unordered comparison function such as
    __builtin_isgreater().  FNDECL is the FUNCTION_DECL for the function
    being called and ARG0 and ARG1 are the arguments for the call.
@@ -9369,12 +9880,6 @@ fold_builtin_unordered_cmp (tree fndecl, tree arg0, tree arg1,
     cmp_type = type0;
   else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE)
     cmp_type = type1;
-  else
-    {
-      error ("non-floating-point argument to function %qs",
-                IDENTIFIER_POINTER (DECL_NAME (fndecl)));
-      return error_mark_node;
-    }
 
   arg0 = fold_convert (cmp_type, arg0);
   arg1 = fold_convert (cmp_type, arg1);
@@ -9611,6 +10116,32 @@ fold_builtin_1 (tree fndecl, tree arg0, bool ignore)
                             &dconstm1, NULL, false);
     break;
 
+#if MPFR_VERSION >= MPFR_VERSION_NUM(2,3,0)
+    CASE_FLT_FN (BUILT_IN_J0):
+      if (validate_arg (arg0, REAL_TYPE))
+       return do_mpfr_arg1 (arg0, type, mpfr_j0,
+                            NULL, NULL, 0);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_J1):
+      if (validate_arg (arg0, REAL_TYPE))
+       return do_mpfr_arg1 (arg0, type, mpfr_j1,
+                            NULL, NULL, 0);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_Y0):
+      if (validate_arg (arg0, REAL_TYPE))
+       return do_mpfr_arg1 (arg0, type, mpfr_y0,
+                            &dconst0, NULL, false);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_Y1):
+      if (validate_arg (arg0, REAL_TYPE))
+       return do_mpfr_arg1 (arg0, type, mpfr_y1,
+                            &dconst0, NULL, false);
+    break;
+#endif
+
     CASE_FLT_FN (BUILT_IN_NAN):
     case BUILT_IN_NAND32:
     case BUILT_IN_NAND64:
@@ -9682,7 +10213,8 @@ fold_builtin_1 (tree fndecl, tree arg0, bool ignore)
     case BUILT_IN_FINITED32:
     case BUILT_IN_FINITED64:
     case BUILT_IN_FINITED128:
-      return fold_builtin_classify (fndecl, arg0, BUILT_IN_FINITE);
+    case BUILT_IN_ISFINITE:
+      return fold_builtin_classify (fndecl, arg0, BUILT_IN_ISFINITE);
 
     CASE_FLT_FN (BUILT_IN_ISINF):
     case BUILT_IN_ISINFD32:
@@ -9690,6 +10222,9 @@ fold_builtin_1 (tree fndecl, tree arg0, bool ignore)
     case BUILT_IN_ISINFD128:
       return fold_builtin_classify (fndecl, arg0, BUILT_IN_ISINF);
 
+    case BUILT_IN_ISINF_SIGN:
+      return fold_builtin_classify (fndecl, arg0, BUILT_IN_ISINF_SIGN);
+
     CASE_FLT_FN (BUILT_IN_ISNAN):
     case BUILT_IN_ISNAND32:
     case BUILT_IN_ISNAND64:
@@ -9721,6 +10256,34 @@ fold_builtin_2 (tree fndecl, tree arg0, tree arg1, bool ignore)
 
   switch (fcode)
     {
+#if MPFR_VERSION >= MPFR_VERSION_NUM(2,3,0)
+    CASE_FLT_FN (BUILT_IN_JN):
+      if (validate_arg (arg0, INTEGER_TYPE)
+         && validate_arg (arg1, REAL_TYPE))
+       return do_mpfr_bessel_n (arg0, arg1, type, mpfr_jn, NULL, 0);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_YN):
+      if (validate_arg (arg0, INTEGER_TYPE)
+         && validate_arg (arg1, REAL_TYPE))
+       return do_mpfr_bessel_n (arg0, arg1, type, mpfr_yn,
+                                &dconst0, false);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_DREM):
+    CASE_FLT_FN (BUILT_IN_REMAINDER):
+      if (validate_arg (arg0, REAL_TYPE)
+          && validate_arg(arg1, REAL_TYPE))
+        return do_mpfr_arg2 (arg0, arg1, type, mpfr_remainder);
+    break;
+
+    CASE_FLT_FN_REENT (BUILT_IN_GAMMA): /* GAMMA_R */
+    CASE_FLT_FN_REENT (BUILT_IN_LGAMMA): /* LGAMMA_R */
+      if (validate_arg (arg0, REAL_TYPE)
+         && validate_arg(arg1, POINTER_TYPE))
+       return do_mpfr_lgamma_r (arg0, arg1, type);
+    break;
+#endif
 
     CASE_FLT_FN (BUILT_IN_ATAN2):
       if (validate_arg (arg0, REAL_TYPE)
@@ -9788,7 +10351,7 @@ fold_builtin_2 (tree fndecl, tree arg0, tree arg1, bool ignore)
       return fold_builtin_strpbrk (arg0, arg1, type);
 
     case BUILT_IN_EXPECT:
-      return fold_builtin_expect (arg0);
+      return fold_builtin_expect (arg0, arg1);
 
     CASE_FLT_FN (BUILT_IN_POW):
       return fold_builtin_pow (fndecl, arg0, arg1, type);
@@ -9877,6 +10440,15 @@ fold_builtin_3 (tree fndecl, tree arg0, tree arg1, tree arg2, bool ignore)
        return do_mpfr_arg3 (arg0, arg1, arg2, type, mpfr_fma);
     break;
 
+#if MPFR_VERSION >= MPFR_VERSION_NUM(2,3,0)
+    CASE_FLT_FN (BUILT_IN_REMQUO):
+      if (validate_arg (arg0, REAL_TYPE)
+         && validate_arg(arg1, REAL_TYPE)
+         && validate_arg(arg2, POINTER_TYPE))
+       return do_mpfr_remquo (arg0, arg1, arg2);
+    break;
+#endif
+
     case BUILT_IN_MEMSET:
       return fold_builtin_memset (arg0, arg1, arg2, type, ignore);
 
@@ -9901,6 +10473,9 @@ fold_builtin_3 (tree fndecl, tree arg0, tree arg1, tree arg2, bool ignore)
     case BUILT_IN_STRNCMP:
       return fold_builtin_strncmp (arg0, arg1, arg2);
 
+    case BUILT_IN_MEMCHR:
+      return fold_builtin_memchr (arg0, arg1, arg2, type);
+
     case BUILT_IN_BCMP:
     case BUILT_IN_MEMCMP:
       return fold_builtin_memcmp (arg0, arg1, arg2);;
@@ -10002,6 +10577,7 @@ static tree
 fold_builtin_n (tree fndecl, tree *args, int nargs, bool ignore)
 {
   tree ret = NULL_TREE;
+
   switch (nargs)
     {
     case 0:
@@ -10025,7 +10601,7 @@ fold_builtin_n (tree fndecl, tree *args, int nargs, bool ignore)
     }
   if (ret)
     {
-      ret = build1 (NOP_EXPR, GENERIC_TREE_TYPE (ret), ret);
+      ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
       TREE_NO_WARNING (ret) = 1;
       return ret;
     }
@@ -10055,6 +10631,11 @@ fold_builtin_varargs (tree fndecl, tree exp, bool ignore ATTRIBUTE_UNUSED)
     case BUILT_IN_SNPRINTF_CHK:
     case BUILT_IN_VSNPRINTF_CHK:
       ret = fold_builtin_snprintf_chk (exp, NULL_TREE, fcode);
+      break;
+
+    case BUILT_IN_FPCLASSIFY:
+      ret = fold_builtin_fpclassify (exp);
+      break;
 
     default:
       break;
@@ -10079,14 +10660,32 @@ fold_call_expr (tree exp, bool ignore)
   tree fndecl = get_callee_fndecl (exp);
   if (fndecl
       && TREE_CODE (fndecl) == FUNCTION_DECL
-      && DECL_BUILT_IN (fndecl))
-    {
+      && DECL_BUILT_IN (fndecl)
+      /* If CALL_EXPR_VA_ARG_PACK is set, the arguments aren't finalized
+        yet.  Defer folding until we see all the arguments
+        (after inlining).  */
+      && !CALL_EXPR_VA_ARG_PACK (exp))
+    {
+      int nargs = call_expr_nargs (exp);
+
+      /* Before gimplification CALL_EXPR_VA_ARG_PACK is not set, but
+        instead last argument is __builtin_va_arg_pack ().  Defer folding
+        even in that case, until arguments are finalized.  */
+      if (nargs && TREE_CODE (CALL_EXPR_ARG (exp, nargs - 1)) == CALL_EXPR)
+       {
+         tree fndecl2 = get_callee_fndecl (CALL_EXPR_ARG (exp, nargs - 1));
+         if (fndecl2
+             && TREE_CODE (fndecl2) == FUNCTION_DECL
+             && DECL_BUILT_IN_CLASS (fndecl2) == BUILT_IN_NORMAL
+             && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK)
+           return NULL_TREE;
+       }
+
       /* FIXME: Don't use a list in this interface.  */
       if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
          return targetm.fold_builtin (fndecl, CALL_EXPR_ARGS (exp), ignore);
       else
        {
-         int nargs = call_expr_nargs (exp);
          if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN)
            {
              tree *args = CALL_EXPR_ARGP (exp);
@@ -10108,6 +10707,7 @@ fold_call_expr (tree exp, bool ignore)
                  if (CAN_HAVE_LOCATION_P (realret)
                      && !EXPR_HAS_LOCATION (realret))
                    SET_EXPR_LOCATION (realret, EXPR_LOCATION (exp));
+                 return realret;
                }
              return ret;
            }
@@ -10124,56 +10724,13 @@ build_function_call_expr (tree fndecl, tree arglist)
 {
   tree fntype = TREE_TYPE (fndecl);
   tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
-  return fold_builtin_call_list (TREE_TYPE (fntype), fn, arglist);
-}
-
-/* Construct a CALL_EXPR with type TYPE with FN as the function expression.
-   ARGLIST is a TREE_LIST of arguments.  */
-
-tree
-fold_builtin_call_list (tree type, tree fn, tree arglist)
-{
-  tree ret = NULL_TREE;
-  if (TREE_CODE (fn) == ADDR_EXPR)
-    {
-      tree fndecl = TREE_OPERAND (fn, 0);
-      if (TREE_CODE (fndecl) == FUNCTION_DECL
-         && DECL_BUILT_IN (fndecl))
-       {
-         /* FIXME: Don't use a list in this interface.  */
-         if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
-           {
-             ret = targetm.fold_builtin (fndecl, arglist, false);
-             if (ret)
-               return ret;
-           }
-         else
-           {
-             tree tail = arglist;
-             tree args[MAX_ARGS_TO_FOLD_BUILTIN];
-             int nargs;
-             tree exp;
-
-             for (nargs = 0; nargs < MAX_ARGS_TO_FOLD_BUILTIN; nargs++)
-               {
-                 if (!tail)
-                   break;
-                 args[nargs] = TREE_VALUE (tail);
-                 tail = TREE_CHAIN (tail);
-               }
-             if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN)
-               {
-                 ret = fold_builtin_n (fndecl, args, nargs, false);
-                 if (ret)
-                   return ret;
-               }
-             exp = build_call_list (type, fn, arglist);
-             ret = fold_builtin_varargs (fndecl, exp, false);
-             return ret ? ret : exp;
-           }
-       }
-    }
-  return build_call_list (type, fn, arglist);
+  int n = list_length (arglist);
+  tree *argarray = (tree *) alloca (n * sizeof (tree));
+  int i;
+  
+  for (i = 0; i < n; i++, arglist = TREE_CHAIN (arglist))
+    argarray[i] = TREE_VALUE (arglist);
+  return fold_builtin_call_array (TREE_TYPE (fntype), fn, n, argarray);
 }
 
 /* Conveniently construct a function call expression.  FNDECL names the
@@ -10184,24 +10741,26 @@ tree
 build_call_expr (tree fndecl, int n, ...)
 {
   va_list ap;
-  tree ret;
   tree fntype = TREE_TYPE (fndecl);
   tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
+  tree *argarray = (tree *) alloca (n * sizeof (tree));
+  int i;
 
   va_start (ap, n);
-  ret = fold_builtin_call_valist (TREE_TYPE (fntype), fn, n, ap);
+  for (i = 0; i < n; i++)
+    argarray[i] = va_arg (ap, tree);
   va_end (ap);
-  return ret;
+  return fold_builtin_call_array (TREE_TYPE (fntype), fn, n, argarray);
 }
 
 /* Construct a CALL_EXPR with type TYPE with FN as the function expression.
-   N arguments are passed in the va_list AP.  */
+   N arguments are passed in the array ARGARRAY.  */
 
 tree
-fold_builtin_call_valist (tree type,
-                         tree fn,
-                         int n,
-                         va_list ap)
+fold_builtin_call_array (tree type,
+                        tree fn,
+                        int n,
+                        tree *argarray)
 {
   tree ret = NULL_TREE;
   int i;
@@ -10213,18 +10772,22 @@ fold_builtin_call_valist (tree type,
     if (TREE_CODE (fndecl) == FUNCTION_DECL
         && DECL_BUILT_IN (fndecl))
       {
+       /* If last argument is __builtin_va_arg_pack (), arguments to this
+          function are not finalized yet.  Defer folding until they are.  */
+       if (n && TREE_CODE (argarray[n - 1]) == CALL_EXPR)
+         {
+           tree fndecl2 = get_callee_fndecl (argarray[n - 1]);
+           if (fndecl2
+               && TREE_CODE (fndecl2) == FUNCTION_DECL
+               && DECL_BUILT_IN_CLASS (fndecl2) == BUILT_IN_NORMAL
+               && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK)
+             return build_call_array (type, fn, n, argarray);
+         }
         if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
           {
             tree arglist = NULL_TREE;
-            va_list ap0;
-            va_copy (ap0, ap);
-            for (i = 0; i < n; i++)
-              {
-                tree arg = va_arg (ap0, tree);
-                arglist = tree_cons (NULL_TREE, arg, arglist);
-              }
-            va_end (ap0);
-            arglist = nreverse (arglist);
+           for (i = n - 1; i >= 0; i--)
+             arglist = tree_cons (NULL_TREE, argarray[i], arglist);
             ret = targetm.fold_builtin (fndecl, arglist, false);
             if (ret)
               return ret;
@@ -10233,25 +10796,19 @@ fold_builtin_call_valist (tree type,
           {
             /* First try the transformations that don't require consing up
                an exp.  */
-            tree args[MAX_ARGS_TO_FOLD_BUILTIN];
-            va_list ap0;
-            va_copy (ap0, ap);
-            for (i = 0; i < n; i++)
-              args[i] = va_arg (ap0, tree);
-            va_end (ap0);
-            ret = fold_builtin_n (fndecl, args, n, false);
+            ret = fold_builtin_n (fndecl, argarray, n, false);
             if (ret)
               return ret;
           }
 
         /* If we got this far, we need to build an exp.  */
-        exp = build_call_valist (type, fn, n, ap);
+        exp = build_call_array (type, fn, n, argarray);
         ret = fold_builtin_varargs (fndecl, exp, false);
         return ret ? ret : exp;
       }
   }
 
-  return build_call_valist (type, fn, n, ap);
+  return build_call_array (type, fn, n, argarray);
 }
 
 /* Construct a new CALL_EXPR using the tail of the argument list of EXP
@@ -10273,7 +10830,7 @@ rewrite_call_expr (tree exp, int skip, tree fndecl, int n, ...)
       int i, j;
       va_list ap;
 
-      buffer = alloca (nargs * sizeof (tree));
+      buffer = XALLOCAVEC (tree, nargs);
       va_start (ap, n);
       for (i = 0; i < n; i++)
        buffer[i] = va_arg (ap, tree);
@@ -10291,31 +10848,88 @@ rewrite_call_expr (tree exp, int skip, tree fndecl, int n, ...)
    a type.  */
   
 static bool
-validate_arg (tree arg, enum tree_code code)
+validate_arg (const_tree arg, enum tree_code code)
 {
   if (!arg)
     return false;
   else if (code == POINTER_TYPE)
     return POINTER_TYPE_P (TREE_TYPE (arg));
+  else if (code == INTEGER_TYPE)
+    return INTEGRAL_TYPE_P (TREE_TYPE (arg));
   return code == TREE_CODE (TREE_TYPE (arg));
 }
 
 /* This function validates the types of a function call argument list
    against a specified list of tree_codes.  If the last specifier is a 0,
    that represents an ellipses, otherwise the last specifier must be a
+   VOID_TYPE.
+
+   This is the GIMPLE version of validate_arglist.  Eventually we want to
+   completely convert builtins.c to work from GIMPLEs and the tree based
+   validate_arglist will then be removed.  */
+
+bool
+validate_gimple_arglist (const_gimple call, ...)
+{
+  enum tree_code code;
+  bool res = 0;
+  va_list ap;
+  const_tree arg;
+  size_t i;
+
+  va_start (ap, call);
+  i = 0;
+
+  do
+    {
+      code = va_arg (ap, enum tree_code);
+      switch (code)
+       {
+       case 0:
+         /* This signifies an ellipses, any further arguments are all ok.  */
+         res = true;
+         goto end;
+       case VOID_TYPE:
+         /* This signifies an endlink, if no arguments remain, return
+            true, otherwise return false.  */
+         res = (i == gimple_call_num_args (call));
+         goto end;
+       default:
+         /* If no parameters remain or the parameter's code does not
+            match the specified code, return false.  Otherwise continue
+            checking any remaining arguments.  */
+         arg = gimple_call_arg (call, i++);
+         if (!validate_arg (arg, code))
+           goto end;
+         break;
+       }
+    }
+  while (1);
+
+  /* We need gotos here since we can only have one VA_CLOSE in a
+     function.  */
+ end: ;
+  va_end (ap);
+
+  return res;
+}
+
+/* This function validates the types of a function call argument list
+   against a specified list of tree_codes.  If the last specifier is a 0,
+   that represents an ellipses, otherwise the last specifier must be a
    VOID_TYPE.  */
 
 bool
-validate_arglist (tree callexpr, ...)
+validate_arglist (const_tree callexpr, ...)
 {
   enum tree_code code;
   bool res = 0;
   va_list ap;
-  call_expr_arg_iterator iter;
-  tree arg;
+  const_call_expr_arg_iterator iter;
+  const_tree arg;
 
   va_start (ap, callexpr);
-  init_call_expr_arg_iterator (callexpr, &iter);
+  init_const_call_expr_arg_iterator (callexpr, &iter);
 
   do
     {
@@ -10329,13 +10943,13 @@ validate_arglist (tree callexpr, ...)
        case VOID_TYPE:
          /* This signifies an endlink, if no arguments remain, return
             true, otherwise return false.  */
-         res = !more_call_expr_args_p (&iter);
+         res = !more_const_call_expr_args_p (&iter);
          goto end;
        default:
          /* If no parameters remain or the parameter's code does not
             match the specified code, return false.  Otherwise continue
             checking any remaining arguments.  */
-         arg = next_call_expr_arg (&iter);
+         arg = next_const_call_expr_arg (&iter);
          if (!validate_arg (arg, code))
            goto end;
          break;
@@ -10432,8 +11046,8 @@ fold_builtin_strstr (tree s1, tree s2, tree type)
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
-         tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1),
-                            s1, build_int_cst (TREE_TYPE (s1), r - p1));
+         tem = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (s1),
+                            s1, size_int (r - p1));
          return fold_convert (type, tem);
        }
 
@@ -10502,8 +11116,8 @@ fold_builtin_strchr (tree s1, tree s2, tree type)
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
-         tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1),
-                            s1, build_int_cst (TREE_TYPE (s1), r - p1));
+         tem = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (s1),
+                            s1, size_int (r - p1));
          return fold_convert (type, tem);
        }
       return NULL_TREE;
@@ -10558,8 +11172,8 @@ fold_builtin_strrchr (tree s1, tree s2, tree type)
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
-         tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1),
-                            s1, build_int_cst (TREE_TYPE (s1), r - p1));
+         tem = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (s1),
+                            s1, size_int (r - p1));
          return fold_convert (type, tem);
        }
 
@@ -10618,8 +11232,8 @@ fold_builtin_strpbrk (tree s1, tree s2, tree type)
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
-         tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1),
-                            s1, build_int_cst (TREE_TYPE (s1), r - p1));
+         tem = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (s1),
+                            s1, size_int (r - p1));
          return fold_convert (type, tem);
        }
 
@@ -10909,6 +11523,7 @@ fold_builtin_fputs (tree arg0, tree arg1, bool ignore, bool unlocked, tree len)
 /* Fold the next_arg or va_start call EXP. Returns true if there was an error
    produced.  False otherwise.  This is done so that we don't output the error
    or warning twice or three times.  */
+
 bool
 fold_builtin_next_arg (tree exp, bool va_start_p)
 {
@@ -10963,9 +11578,7 @@ fold_builtin_next_arg (tree exp, bool va_start_p)
         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
-            || TREE_CODE (arg) == CONVERT_EXPR
-            || TREE_CODE (arg) == NON_LVALUE_EXPR
+      while (CONVERT_EXPR_P (arg)
             || TREE_CODE (arg) == INDIRECT_REF)
        arg = TREE_OPERAND (arg, 0);
       if (arg != last_parm)
@@ -11086,12 +11699,11 @@ expand_builtin_object_size (tree exp)
   tree ost;
   int object_size_type;
   tree fndecl = get_callee_fndecl (exp);
-  location_t locus = EXPR_LOCATION (exp);
 
   if (!validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     {
-      error ("%Hfirst argument of %D must be a pointer, second integer constant",
-            &locus, fndecl);
+      error ("%Kfirst argument of %D must be a pointer, second integer constant",
+            exp, fndecl);
       expand_builtin_trap ();
       return const0_rtx;
     }
@@ -11103,8 +11715,8 @@ expand_builtin_object_size (tree exp)
       || tree_int_cst_sgn (ost) < 0
       || compare_tree_int (ost, 3) > 0)
     {
-      error ("%Hlast argument of %D is not integer constant between 0 and 3",
-            &locus, fndecl);
+      error ("%Klast argument of %D is not integer constant between 0 and 3",
+            exp, fndecl);
       expand_builtin_trap ();
       return const0_rtx;
     }
@@ -11147,9 +11759,8 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
 
       if (! integer_all_onesp (size) && tree_int_cst_lt (size, len))
        {
-         location_t locus = EXPR_LOCATION (exp);
-         warning (0, "%Hcall to %D will always overflow destination buffer",
-                  &locus, get_callee_fndecl (exp));
+         warning (0, "%Kcall to %D will always overflow destination buffer",
+                  exp, get_callee_fndecl (exp));
          return NULL_RTX;
        }
 
@@ -11178,6 +11789,13 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
        return NULL_RTX;
 
       fn = build_call_expr (fn, 3, dest, src, len);
+      STRIP_TYPE_NOPS (fn);
+      while (TREE_CODE (fn) == COMPOUND_EXPR)
+       {
+         expand_expr (TREE_OPERAND (fn, 0), const0_rtx, VOIDmode,
+                      EXPAND_NORMAL);
+         fn = TREE_OPERAND (fn, 1);
+       }
       if (TREE_CODE (fn) == CALL_EXPR)
        CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
       return expand_expr (fn, target, mode, EXPAND_NORMAL);
@@ -11205,8 +11823,7 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
              return expand_expr (dest, target, mode, EXPAND_NORMAL);
            }
 
-         len = fold_convert (TREE_TYPE (dest), len);
-         expr = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, len);
+         expr = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (dest), dest, len);
          return expand_expr (expr, target, mode, EXPAND_NORMAL);
        }
 
@@ -11227,6 +11844,13 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
              if (!fn)
                return NULL_RTX;
              fn = build_call_expr (fn, 4, dest, src, len, size);
+             STRIP_TYPE_NOPS (fn);
+             while (TREE_CODE (fn) == COMPOUND_EXPR)
+               {
+                 expand_expr (TREE_OPERAND (fn, 0), const0_rtx, VOIDmode,
+                              EXPAND_NORMAL);
+                 fn = TREE_OPERAND (fn, 1);
+               }
              if (TREE_CODE (fn) == CALL_EXPR)
                CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
              return expand_expr (fn, target, mode, EXPAND_NORMAL);
@@ -11243,7 +11867,6 @@ maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
 {
   int is_strlen = 0;
   tree len, size;
-  location_t locus;
 
   switch (fcode)
     {
@@ -11290,9 +11913,8 @@ maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
       src = c_strlen (src, 1);
       if (! src || ! host_integerp (src, 1))
        {
-         locus = EXPR_LOCATION (exp);
-         warning (0, "%Hcall to %D might overflow destination buffer",
-                  &locus, get_callee_fndecl (exp));
+         warning (0, "%Kcall to %D might overflow destination buffer",
+                  exp, get_callee_fndecl (exp));
          return;
        }
       else if (tree_int_cst_lt (src, size))
@@ -11301,9 +11923,8 @@ maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
   else if (! host_integerp (len, 1) || ! tree_int_cst_lt (size, len))
     return;
 
-  locus = EXPR_LOCATION (exp);
-  warning (0, "%Hcall to %D will always overflow destination buffer",
-          &locus, get_callee_fndecl (exp));
+  warning (0, "%Kcall to %D will always overflow destination buffer",
+          exp, get_callee_fndecl (exp));
 }
 
 /* Emit warning if a buffer overflow is detected at compile time
@@ -11361,12 +11982,32 @@ maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode)
 
   if (! tree_int_cst_lt (len, size))
     {
-      location_t locus = EXPR_LOCATION (exp);
-      warning (0, "%Hcall to %D will always overflow destination buffer",
-              &locus, get_callee_fndecl (exp));
+      warning (0, "%Kcall to %D will always overflow destination buffer",
+              exp, get_callee_fndecl (exp));
     }
 }
 
+/* Emit warning if a free is called with address of a variable.  */
+
+static void
+maybe_emit_free_warning (tree exp)
+{
+  tree arg = CALL_EXPR_ARG (exp, 0);
+
+  STRIP_NOPS (arg);
+  if (TREE_CODE (arg) != ADDR_EXPR)
+    return;
+
+  arg = get_base_address (TREE_OPERAND (arg, 0));
+  if (arg == NULL || INDIRECT_REF_P (arg))
+    return;
+
+  if (SSA_VAR_P (arg))
+    warning (0, "%Kattempt to free a non-heap object %qD", exp, arg);
+  else
+    warning (0, "%Kattempt to free a non-heap object", exp);
+}
+
 /* Fold a call to __builtin_object_size with arguments PTR and OST,
    if possible.  */
 
@@ -11453,8 +12094,7 @@ fold_builtin_memory_chk (tree fndecl,
        return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, len);
       else
        {
-         tree temp = fold_convert (TREE_TYPE (dest), len);
-         temp = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, temp);
+         tree temp = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (dest), dest, len);
          return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), temp);
        }
     }
@@ -11984,7 +12624,7 @@ fold_builtin_printf (tree fndecl, tree fmt, tree arg, bool ignore,
            {
              /* Create a NUL-terminated string that's one char shorter
                 than the original, stripping off the trailing '\n'.  */
-             char *newstr = alloca (len);
+             char *newstr = XALLOCAVEC (char, len);
              memcpy (newstr, str, len - 1);
              newstr[len - 1] = 0;
 
@@ -12177,12 +12817,12 @@ do_mpfr_ckconv (mpfr_srcptr m, tree type, int inexact)
     {
       REAL_VALUE_TYPE rr;
 
-      real_from_mpfr (&rr, m);
+      real_from_mpfr (&rr, m, type, GMP_RNDN);
       /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR value,
         check for overflow/underflow.  If the REAL_VALUE_TYPE is zero
         but the mpft_t is not, then we underflowed in the
         conversion.  */
-      if (!real_isnan (&rr) && !real_isinf (&rr)
+      if (real_isfinite (&rr)
          && (rr.cl == rvc_zero) == (mpfr_zero_p (m) != 0))
         {
          REAL_VALUE_TYPE rmode;
@@ -12221,7 +12861,7 @@ do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t),
     {
       const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg);
 
-      if (!real_isnan (ra) && !real_isinf (ra)
+      if (real_isfinite (ra)
          && (!min || real_compare (inclusive ? GE_EXPR: GT_EXPR , ra, min))
          && (!max || real_compare (inclusive ? LE_EXPR: LT_EXPR , ra, max)))
         {
@@ -12230,7 +12870,7 @@ do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t),
          mpfr_t m;
 
          mpfr_init2 (m, prec);
-         mpfr_from_real (m, ra);
+         mpfr_from_real (m, ra, GMP_RNDN);
          mpfr_clear_flags ();
          inexact = func (m, m, GMP_RNDN);
          result = do_mpfr_ckconv (m, type, inexact);
@@ -12265,16 +12905,15 @@ do_mpfr_arg2 (tree arg1, tree arg2, tree type,
       const REAL_VALUE_TYPE *const ra1 = &TREE_REAL_CST (arg1);
       const REAL_VALUE_TYPE *const ra2 = &TREE_REAL_CST (arg2);
 
-      if (!real_isnan (ra1) && !real_isinf (ra1)
-         && !real_isnan (ra2) && !real_isinf (ra2))
+      if (real_isfinite (ra1) && real_isfinite (ra2))
         {
          const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
          int inexact;
          mpfr_t m1, m2;
 
          mpfr_inits2 (prec, m1, m2, NULL);
-         mpfr_from_real (m1, ra1);
-         mpfr_from_real (m2, ra2);
+         mpfr_from_real (m1, ra1, GMP_RNDN);
+         mpfr_from_real (m2, ra2, GMP_RNDN);
          mpfr_clear_flags ();
          inexact = func (m1, m1, m2, GMP_RNDN);
          result = do_mpfr_ckconv (m1, type, inexact);
@@ -12312,18 +12951,16 @@ do_mpfr_arg3 (tree arg1, tree arg2, tree arg3, tree type,
       const REAL_VALUE_TYPE *const ra2 = &TREE_REAL_CST (arg2);
       const REAL_VALUE_TYPE *const ra3 = &TREE_REAL_CST (arg3);
 
-      if (!real_isnan (ra1) && !real_isinf (ra1)
-         && !real_isnan (ra2) && !real_isinf (ra2)
-         && !real_isnan (ra3) && !real_isinf (ra3))
+      if (real_isfinite (ra1) && real_isfinite (ra2) && real_isfinite (ra3))
         {
          const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
          int inexact;
          mpfr_t m1, m2, m3;
 
          mpfr_inits2 (prec, m1, m2, m3, NULL);
-         mpfr_from_real (m1, ra1);
-         mpfr_from_real (m2, ra2);
-         mpfr_from_real (m3, ra3);
+         mpfr_from_real (m1, ra1, GMP_RNDN);
+         mpfr_from_real (m2, ra2, GMP_RNDN);
+         mpfr_from_real (m3, ra3, GMP_RNDN);
          mpfr_clear_flags ();
          inexact = func (m1, m1, m2, m3, GMP_RNDN);
          result = do_mpfr_ckconv (m1, type, inexact);
@@ -12357,7 +12994,7 @@ do_mpfr_sincos (tree arg, tree arg_sinp, tree arg_cosp)
     {
       const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg);
 
-      if (!real_isnan (ra) && !real_isinf (ra))
+      if (real_isfinite (ra))
         {
          const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
          tree result_s, result_c;
@@ -12365,7 +13002,7 @@ do_mpfr_sincos (tree arg, tree arg_sinp, tree arg_cosp)
          mpfr_t m, ms, mc;
 
          mpfr_inits2 (prec, m, ms, mc, NULL);
-         mpfr_from_real (m, ra);
+         mpfr_from_real (m, ra, GMP_RNDN);
          mpfr_clear_flags ();
          inexact = mpfr_sin_cos (ms, mc, m, GMP_RNDN);
          result_s = do_mpfr_ckconv (ms, type, inexact);
@@ -12401,3 +13038,484 @@ do_mpfr_sincos (tree arg, tree arg_sinp, tree arg_cosp)
     }
   return result;
 }
+
+#if MPFR_VERSION >= MPFR_VERSION_NUM(2,3,0)
+/* If argument ARG1 is an INTEGER_CST and ARG2 is a REAL_CST, call the
+   two-argument mpfr order N Bessel function FUNC on them and return
+   the resulting value as a tree with type TYPE.  The mpfr precision
+   is set to the precision of TYPE.  We assume that function FUNC
+   returns zero if the result could be calculated exactly within the
+   requested precision.  */
+static tree
+do_mpfr_bessel_n (tree arg1, tree arg2, tree type,
+                 int (*func)(mpfr_ptr, long, mpfr_srcptr, mp_rnd_t),
+                 const REAL_VALUE_TYPE *min, bool inclusive)
+{
+  tree result = NULL_TREE;
+
+  STRIP_NOPS (arg1);
+  STRIP_NOPS (arg2);
+
+  /* To proceed, MPFR must exactly represent the target floating point
+     format, which only happens when the target base equals two.  */
+  if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
+      && host_integerp (arg1, 0)
+      && TREE_CODE (arg2) == REAL_CST && !TREE_OVERFLOW (arg2))
+    {
+      const HOST_WIDE_INT n = tree_low_cst(arg1, 0);
+      const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg2);
+
+      if (n == (long)n
+         && real_isfinite (ra)
+         && (!min || real_compare (inclusive ? GE_EXPR: GT_EXPR , ra, min)))
+        {
+         const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+         int inexact;
+         mpfr_t m;
+
+         mpfr_init2 (m, prec);
+         mpfr_from_real (m, ra, GMP_RNDN);
+         mpfr_clear_flags ();
+         inexact = func (m, n, m, GMP_RNDN);
+         result = do_mpfr_ckconv (m, type, inexact);
+         mpfr_clear (m);
+       }
+    }
+  
+  return result;
+}
+
+/* If arguments ARG0 and ARG1 are REAL_CSTs, call mpfr_remquo() to set
+   the pointer *(ARG_QUO) and return the result.  The type is taken
+   from the type of ARG0 and is used for setting the precision of the
+   calculation and results.  */
+
+static tree
+do_mpfr_remquo (tree arg0, tree arg1, tree arg_quo)
+{
+  tree const type = TREE_TYPE (arg0);
+  tree result = NULL_TREE;
+  
+  STRIP_NOPS (arg0);
+  STRIP_NOPS (arg1);
+  
+  /* To proceed, MPFR must exactly represent the target floating point
+     format, which only happens when the target base equals two.  */
+  if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
+      && TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0)
+      && TREE_CODE (arg1) == REAL_CST && !TREE_OVERFLOW (arg1))
+    {
+      const REAL_VALUE_TYPE *const ra0 = TREE_REAL_CST_PTR (arg0);
+      const REAL_VALUE_TYPE *const ra1 = TREE_REAL_CST_PTR (arg1);
+
+      if (real_isfinite (ra0) && real_isfinite (ra1))
+        {
+         const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+         tree result_rem;
+         long integer_quo;
+         mpfr_t m0, m1;
+
+         mpfr_inits2 (prec, m0, m1, NULL);
+         mpfr_from_real (m0, ra0, GMP_RNDN);
+         mpfr_from_real (m1, ra1, GMP_RNDN);
+         mpfr_clear_flags ();
+         mpfr_remquo (m0, &integer_quo, m0, m1, GMP_RNDN);
+         /* Remquo is independent of the rounding mode, so pass
+            inexact=0 to do_mpfr_ckconv().  */
+         result_rem = do_mpfr_ckconv (m0, type, /*inexact=*/ 0);
+         mpfr_clears (m0, m1, NULL);
+         if (result_rem)
+           {
+             /* MPFR calculates quo in the host's long so it may
+                return more bits in quo than the target int can hold
+                if sizeof(host long) > sizeof(target int).  This can
+                happen even for native compilers in LP64 mode.  In
+                these cases, modulo the quo value with the largest
+                number that the target int can hold while leaving one
+                bit for the sign.  */
+             if (sizeof (integer_quo) * CHAR_BIT > INT_TYPE_SIZE)
+               integer_quo %= (long)(1UL << (INT_TYPE_SIZE - 1));
+
+             /* Dereference the quo pointer argument.  */
+             arg_quo = build_fold_indirect_ref (arg_quo);
+             /* Proceed iff a valid pointer type was passed in.  */
+             if (TYPE_MAIN_VARIANT (TREE_TYPE (arg_quo)) == integer_type_node)
+               {
+                 /* Set the value. */
+                 tree result_quo = fold_build2 (MODIFY_EXPR,
+                                                TREE_TYPE (arg_quo), arg_quo,
+                                                build_int_cst (NULL, integer_quo));
+                 TREE_SIDE_EFFECTS (result_quo) = 1;
+                 /* Combine the quo assignment with the rem.  */
+                 result = non_lvalue (fold_build2 (COMPOUND_EXPR, type,
+                                                   result_quo, result_rem));
+               }
+           }
+       }
+    }
+  return result;
+}
+
+/* If ARG is a REAL_CST, call mpfr_lgamma() on it and return the
+   resulting value as a tree with type TYPE.  The mpfr precision is
+   set to the precision of TYPE.  We assume that this mpfr function
+   returns zero if the result could be calculated exactly within the
+   requested precision.  In addition, the integer pointer represented
+   by ARG_SG will be dereferenced and set to the appropriate signgam
+   (-1,1) value.  */
+
+static tree
+do_mpfr_lgamma_r (tree arg, tree arg_sg, tree type)
+{
+  tree result = NULL_TREE;
+
+  STRIP_NOPS (arg);
+  
+  /* To proceed, MPFR must exactly represent the target floating point
+     format, which only happens when the target base equals two.  Also
+     verify ARG is a constant and that ARG_SG is an int pointer.  */
+  if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
+      && TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg)
+      && TREE_CODE (TREE_TYPE (arg_sg)) == POINTER_TYPE
+      && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (arg_sg))) == integer_type_node)
+    {
+      const REAL_VALUE_TYPE *const ra = TREE_REAL_CST_PTR (arg);
+
+      /* In addition to NaN and Inf, the argument cannot be zero or a
+        negative integer.  */
+      if (real_isfinite (ra)
+         && ra->cl != rvc_zero
+         && !(real_isneg(ra) && real_isinteger(ra, TYPE_MODE (type))))
+        {
+         const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+         int inexact, sg;
+         mpfr_t m;
+         tree result_lg;
+
+         mpfr_init2 (m, prec);
+         mpfr_from_real (m, ra, GMP_RNDN);
+         mpfr_clear_flags ();
+         inexact = mpfr_lgamma (m, &sg, m, GMP_RNDN);
+         result_lg = do_mpfr_ckconv (m, type, inexact);
+         mpfr_clear (m);
+         if (result_lg)
+           {
+             tree result_sg;
+
+             /* Dereference the arg_sg pointer argument.  */
+             arg_sg = build_fold_indirect_ref (arg_sg);
+             /* Assign the signgam value into *arg_sg. */
+             result_sg = fold_build2 (MODIFY_EXPR,
+                                      TREE_TYPE (arg_sg), arg_sg,
+                                      build_int_cst (NULL, sg));
+             TREE_SIDE_EFFECTS (result_sg) = 1;
+             /* Combine the signgam assignment with the lgamma result.  */
+             result = non_lvalue (fold_build2 (COMPOUND_EXPR, type,
+                                               result_sg, result_lg));
+           }
+       }
+    }
+
+  return result;
+}
+#endif
+
+/* FIXME tuples.
+   The functions below provide an alternate interface for folding
+   builtin function calls presented as GIMPLE_CALL statements rather
+   than as CALL_EXPRs.  The folded result is still expressed as a
+   tree.  There is too much code duplication in the handling of
+   varargs functions, and a more intrusive re-factoring would permit
+   better sharing of code between the tree and statement-based
+   versions of these functions.  */
+
+/* Construct a new CALL_EXPR using the tail of the argument list of STMT
+   along with N new arguments specified as the "..." parameters.  SKIP
+   is the number of arguments in STMT to be omitted.  This function is used
+   to do varargs-to-varargs transformations.  */
+
+static tree
+gimple_rewrite_call_expr (gimple stmt, int skip, tree fndecl, int n, ...)
+{
+  int oldnargs = gimple_call_num_args (stmt);
+  int nargs = oldnargs - skip + n;
+  tree fntype = TREE_TYPE (fndecl);
+  tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
+  tree *buffer;
+  int i, j;
+  va_list ap;
+
+  buffer = XALLOCAVEC (tree, nargs);
+  va_start (ap, n);
+  for (i = 0; i < n; i++)
+    buffer[i] = va_arg (ap, tree);
+  va_end (ap);
+  for (j = skip; j < oldnargs; j++, i++)
+    buffer[i] = gimple_call_arg (stmt, j);
+
+  return fold (build_call_array (TREE_TYPE (fntype), fn, nargs, buffer));
+}
+
+/* Fold a call STMT to __{,v}sprintf_chk.  Return NULL_TREE if
+   a normal call should be emitted rather than expanding the function
+   inline.  FCODE is either BUILT_IN_SPRINTF_CHK or BUILT_IN_VSPRINTF_CHK.  */
+
+static tree
+gimple_fold_builtin_sprintf_chk (gimple stmt, enum built_in_function fcode)
+{
+  tree dest, size, len, fn, fmt, flag;
+  const char *fmt_str;
+  int nargs = gimple_call_num_args (stmt);
+
+  /* Verify the required arguments in the original call.  */
+  if (nargs < 4)
+    return NULL_TREE;
+  dest = gimple_call_arg (stmt, 0);
+  if (!validate_arg (dest, POINTER_TYPE))
+    return NULL_TREE;
+  flag = gimple_call_arg (stmt, 1);
+  if (!validate_arg (flag, INTEGER_TYPE))
+    return NULL_TREE;
+  size = gimple_call_arg (stmt, 2);
+  if (!validate_arg (size, INTEGER_TYPE))
+    return NULL_TREE;
+  fmt = gimple_call_arg (stmt, 3);
+  if (!validate_arg (fmt, POINTER_TYPE))
+    return NULL_TREE;
+
+  if (! host_integerp (size, 1))
+    return NULL_TREE;
+
+  len = NULL_TREE;
+
+  if (!init_target_chars ())
+    return NULL_TREE;
+
+  /* Check whether the format is a literal string constant.  */
+  fmt_str = c_getstr (fmt);
+  if (fmt_str != NULL)
+    {
+      /* If the format doesn't contain % args or %%, we know the size.  */
+      if (strchr (fmt_str, target_percent) == 0)
+       {
+         if (fcode != BUILT_IN_SPRINTF_CHK || nargs == 4)
+           len = build_int_cstu (size_type_node, strlen (fmt_str));
+       }
+      /* If the format is "%s" and first ... argument is a string literal,
+        we know the size too.  */
+      else if (fcode == BUILT_IN_SPRINTF_CHK
+              && strcmp (fmt_str, target_percent_s) == 0)
+       {
+         tree arg;
+
+         if (nargs == 5)
+           {
+             arg = gimple_call_arg (stmt, 4);
+             if (validate_arg (arg, POINTER_TYPE))
+               {
+                 len = c_strlen (arg, 1);
+                 if (! len || ! host_integerp (len, 1))
+                   len = NULL_TREE;
+               }
+           }
+       }
+    }
+
+  if (! integer_all_onesp (size))
+    {
+      if (! len || ! tree_int_cst_lt (len, size))
+       return NULL_TREE;
+    }
+
+  /* Only convert __{,v}sprintf_chk to {,v}sprintf if flag is 0
+     or if format doesn't contain % chars or is "%s".  */
+  if (! integer_zerop (flag))
+    {
+      if (fmt_str == NULL)
+       return NULL_TREE;
+      if (strchr (fmt_str, target_percent) != NULL
+         && strcmp (fmt_str, target_percent_s))
+       return NULL_TREE;
+    }
+
+  /* If __builtin_{,v}sprintf_chk is used, assume {,v}sprintf is available.  */
+  fn = built_in_decls[fcode == BUILT_IN_VSPRINTF_CHK
+                     ? BUILT_IN_VSPRINTF : BUILT_IN_SPRINTF];
+  if (!fn)
+    return NULL_TREE;
+
+  return gimple_rewrite_call_expr (stmt, 4, fn, 2, dest, fmt);
+}
+
+/* Fold a call STMT to {,v}snprintf.  Return NULL_TREE if
+   a normal call should be emitted rather than expanding the function
+   inline.  FCODE is either BUILT_IN_SNPRINTF_CHK or
+   BUILT_IN_VSNPRINTF_CHK.  If MAXLEN is not NULL, it is maximum length
+   passed as second argument.  */
+
+tree
+gimple_fold_builtin_snprintf_chk (gimple stmt, tree maxlen,
+                                  enum built_in_function fcode)
+{
+  tree dest, size, len, fn, fmt, flag;
+  const char *fmt_str;
+
+  /* Verify the required arguments in the original call.  */
+  if (gimple_call_num_args (stmt) < 5)
+    return NULL_TREE;
+  dest = gimple_call_arg (stmt, 0);
+  if (!validate_arg (dest, POINTER_TYPE))
+    return NULL_TREE;
+  len = gimple_call_arg (stmt, 1);
+  if (!validate_arg (len, INTEGER_TYPE))
+    return NULL_TREE;
+  flag = gimple_call_arg (stmt, 2);
+  if (!validate_arg (flag, INTEGER_TYPE))
+    return NULL_TREE;
+  size = gimple_call_arg (stmt, 3);
+  if (!validate_arg (size, INTEGER_TYPE))
+    return NULL_TREE;
+  fmt = gimple_call_arg (stmt, 4);
+  if (!validate_arg (fmt, POINTER_TYPE))
+    return NULL_TREE;
+
+  if (! host_integerp (size, 1))
+    return NULL_TREE;
+
+  if (! integer_all_onesp (size))
+    {
+      if (! host_integerp (len, 1))
+       {
+         /* If LEN is not constant, try MAXLEN too.
+            For MAXLEN only allow optimizing into non-_ocs function
+            if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
+         if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
+           return NULL_TREE;
+       }
+      else
+       maxlen = len;
+
+      if (tree_int_cst_lt (size, maxlen))
+       return NULL_TREE;
+    }
+
+  if (!init_target_chars ())
+    return NULL_TREE;
+
+  /* Only convert __{,v}snprintf_chk to {,v}snprintf if flag is 0
+     or if format doesn't contain % chars or is "%s".  */
+  if (! integer_zerop (flag))
+    {
+      fmt_str = c_getstr (fmt);
+      if (fmt_str == NULL)
+       return NULL_TREE;
+      if (strchr (fmt_str, target_percent) != NULL
+         && strcmp (fmt_str, target_percent_s))
+       return NULL_TREE;
+    }
+
+  /* If __builtin_{,v}snprintf_chk is used, assume {,v}snprintf is
+     available.  */
+  fn = built_in_decls[fcode == BUILT_IN_VSNPRINTF_CHK
+                     ? BUILT_IN_VSNPRINTF : BUILT_IN_SNPRINTF];
+  if (!fn)
+    return NULL_TREE;
+
+  return gimple_rewrite_call_expr (stmt, 5, fn, 3, dest, len, fmt);
+}
+
+/* Builtins with folding operations that operate on "..." arguments
+   need special handling; we need to store the arguments in a convenient
+   data structure before attempting any folding.  Fortunately there are
+   only a few builtins that fall into this category.  FNDECL is the
+   function, EXP is the CALL_EXPR for the call, and IGNORE is true if the
+   result of the function call is ignored.  */
+
+static tree
+gimple_fold_builtin_varargs (tree fndecl, gimple stmt, bool ignore ATTRIBUTE_UNUSED)
+{
+  enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+  tree ret = NULL_TREE;
+
+  switch (fcode)
+    {
+    case BUILT_IN_SPRINTF_CHK:
+    case BUILT_IN_VSPRINTF_CHK:
+      ret = gimple_fold_builtin_sprintf_chk (stmt, fcode);
+      break;
+
+    case BUILT_IN_SNPRINTF_CHK:
+    case BUILT_IN_VSNPRINTF_CHK:
+      ret = gimple_fold_builtin_snprintf_chk (stmt, NULL_TREE, fcode);
+
+    default:
+      break;
+    }
+  if (ret)
+    {
+      ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
+      TREE_NO_WARNING (ret) = 1;
+      return ret;
+    }
+  return NULL_TREE;
+}
+
+/* A wrapper function for builtin folding that prevents warnings for
+   "statement without effect" and the like, caused by removing the
+   call node earlier than the warning is generated.  */
+
+tree
+fold_call_stmt (gimple stmt, bool ignore)
+{
+  tree ret = NULL_TREE;
+  tree fndecl = gimple_call_fndecl (stmt);
+  if (fndecl
+      && TREE_CODE (fndecl) == FUNCTION_DECL
+      && DECL_BUILT_IN (fndecl)
+      && !gimple_call_va_arg_pack_p (stmt))
+    {
+      int nargs = gimple_call_num_args (stmt);
+
+      /* FIXME: Don't use a list in this interface.  */
+      if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
+        {
+          tree arglist = NULL_TREE;
+          int i;
+          for (i = nargs - 1; i >= 0; i--)
+            arglist = tree_cons (NULL_TREE, gimple_call_arg (stmt, i), arglist);
+         return targetm.fold_builtin (fndecl, arglist, ignore);
+        }
+      else
+       {
+         if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN)
+           {
+              tree args[MAX_ARGS_TO_FOLD_BUILTIN];
+              int i;
+              for (i = 0; i < nargs; i++)
+                args[i] = gimple_call_arg (stmt, i);
+             ret = fold_builtin_n (fndecl, args, nargs, ignore);
+           }
+         if (!ret)
+           ret = gimple_fold_builtin_varargs (fndecl, stmt, ignore);
+         if (ret)
+           {
+             /* Propagate location information from original call to
+                expansion of builtin.  Otherwise things like
+                maybe_emit_chk_warning, that operate on the expansion
+                of a builtin, will use the wrong location information.  */
+             if (gimple_has_location (stmt))
+                {
+                 tree realret = ret;
+                 if (TREE_CODE (ret) == NOP_EXPR)
+                   realret = TREE_OPERAND (ret, 0);
+                 if (CAN_HAVE_LOCATION_P (realret)
+                     && !EXPR_HAS_LOCATION (realret))
+                   SET_EXPR_LOCATION (realret, gimple_location (stmt));
+                  return realret;
+                }
+             return ret;
+           }
+       }
+    }
+  return NULL_TREE;
+}