OSDN Git Service

2010-11-24 Tobias Burnus <burnus@net-b.de>
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index 5a474cd..c9e8e68 100644 (file)
@@ -1,6 +1,6 @@
 /* Expand builtin functions.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -24,9 +24,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "machmode.h"
-#include "real.h"
 #include "rtl.h"
 #include "tree.h"
+#include "realmpfr.h"
 #include "gimple.h"
 #include "flags.h"
 #include "regs.h"
@@ -49,7 +49,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-mudflap.h"
 #include "tree-flow.h"
 #include "value-prof.h"
-#include "diagnostic.h"
+#include "diagnostic-core.h"
+#include "builtins.h"
 
 #ifndef SLOW_UNALIGNED_ACCESS
 #define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) STRICT_ALIGNMENT
@@ -58,11 +59,11 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef PAD_VARARGS_DOWN
 #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
 #endif
-#ifdef HAVE_mpc
 static tree do_mpc_arg1 (tree, tree, int (*)(mpc_ptr, mpc_srcptr, mpc_rnd_t));
-#ifdef HAVE_mpc_pow
-static tree do_mpc_arg2 (tree, tree, tree, int (*)(mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t));
-#endif
+
+struct target_builtins default_target_builtins;
+#if SWITCHABLE_TARGET
+struct target_builtins *this_target_builtins = &default_target_builtins;
 #endif
 
 /* Define the names of the builtin function types and codes.  */
@@ -105,59 +106,42 @@ static void expand_errno_check (tree, rtx);
 static rtx expand_builtin_mathfn (tree, rtx, rtx);
 static rtx expand_builtin_mathfn_2 (tree, rtx, rtx);
 static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
-static rtx expand_builtin_interclass_mathfn (tree, rtx, rtx);
+static rtx expand_builtin_mathfn_ternary (tree, rtx, rtx);
+static rtx expand_builtin_interclass_mathfn (tree, rtx);
 static rtx expand_builtin_sincos (tree);
-static rtx expand_builtin_cexpi (tree, rtx, rtx);
+static rtx expand_builtin_cexpi (tree, 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_strcmp (tree, rtx);
 static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode);
 static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
-static rtx expand_builtin_strcat (tree, tree, rtx, enum machine_mode);
-static rtx expand_builtin_strncat (tree, rtx, enum machine_mode);
-static rtx expand_builtin_strspn (tree, rtx, enum machine_mode);
-static rtx expand_builtin_strcspn (tree, rtx, enum machine_mode);
-static rtx expand_builtin_memcpy (tree, rtx, enum machine_mode);
+static rtx expand_builtin_memcpy (tree, rtx);
 static rtx expand_builtin_mempcpy (tree, rtx, enum machine_mode);
-static rtx expand_builtin_mempcpy_args (tree, tree, tree, tree, rtx, 
+static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx,
                                        enum machine_mode, int);
-static rtx expand_builtin_memmove (tree, rtx, enum machine_mode, int);
-static rtx expand_builtin_memmove_args (tree, tree, tree, tree, rtx, 
-                                       enum machine_mode, int);
-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_strcpy (tree, rtx);
+static rtx expand_builtin_strcpy_args (tree, tree, rtx);
 static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode);
-static rtx expand_builtin_strncpy (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strncpy (tree, rtx);
 static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, enum machine_mode);
 static rtx expand_builtin_memset (tree, rtx, enum machine_mode);
 static rtx expand_builtin_memset_args (tree, tree, tree, rtx, enum machine_mode, tree);
 static rtx expand_builtin_bzero (tree);
 static rtx expand_builtin_strlen (tree, rtx, enum machine_mode);
-static rtx expand_builtin_strstr (tree, rtx, enum machine_mode);
-static rtx expand_builtin_strpbrk (tree, rtx, enum machine_mode);
-static rtx expand_builtin_strchr (tree, rtx, enum machine_mode);
-static rtx expand_builtin_strrchr (tree, rtx, enum machine_mode);
-static rtx expand_builtin_alloca (tree, rtx);
+static rtx expand_builtin_alloca (tree, bool);
 static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab);
 static rtx expand_builtin_frame_address (tree, tree);
-static rtx expand_builtin_fputs (tree, rtx, bool);
-static rtx expand_builtin_printf (tree, rtx, enum machine_mode, bool);
-static rtx expand_builtin_fprintf (tree, rtx, enum machine_mode, bool);
-static rtx expand_builtin_sprintf (tree, rtx, enum machine_mode);
 static tree stabilize_va_list_loc (location_t, tree, int);
 static rtx expand_builtin_expect (tree, rtx);
 static tree fold_builtin_constant_p (tree);
 static tree fold_builtin_expect (location_t, tree, tree);
 static tree fold_builtin_classify_type (tree);
-static tree fold_builtin_strlen (location_t, tree);
+static tree fold_builtin_strlen (location_t, tree, tree);
 static tree fold_builtin_inf (location_t, tree, int);
 static tree fold_builtin_nan (tree, tree, int);
 static tree rewrite_call_expr (location_t, tree, int, tree, int, ...);
@@ -247,6 +231,8 @@ static tree do_mpfr_bessel_n (tree, tree, tree,
 static tree do_mpfr_remquo (tree, tree, tree);
 static tree do_mpfr_lgamma_r (tree, tree, tree);
 
+/* Return true if NAME starts with __builtin_ or __sync_.  */
+
 bool
 is_builtin_name (const char *name)
 {
@@ -257,6 +243,16 @@ is_builtin_name (const char *name)
   return false;
 }
 
+
+/* Return true if DECL is a function symbol representing a built-in.  */
+
+bool
+is_builtin_fn (tree decl)
+{
+  return TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl);
+}
+
+
 /* Return true if NODE should be considered for inline expansion regardless
    of the optimization level.  This means whenever a function is invoked with
    its "internal" name, which normally contains the prefix "__builtin".  */
@@ -272,78 +268,158 @@ called_as_built_in (tree node)
 }
 
 /* Return the alignment in bits of EXP, an object.
-   Don't return more than MAX_ALIGN no matter what, ALIGN is the inital
-   guessed alignment e.g. from type alignment.  */
+   Don't return more than MAX_ALIGN no matter what.  */
 
-int
-get_object_alignment (tree exp, unsigned int align, unsigned int max_align)
+unsigned int
+get_object_alignment (tree exp, unsigned int max_align)
 {
-  unsigned int inner;
+  HOST_WIDE_INT bitsize, bitpos;
+  tree offset;
+  enum machine_mode mode;
+  int unsignedp, volatilep;
+  unsigned int align, inner;
+
+  /* Get the innermost object and the constant (bitpos) and possibly
+     variable (offset) offset of the access.  */
+  exp = get_inner_reference (exp, &bitsize, &bitpos, &offset,
+                            &mode, &unsignedp, &volatilep, true);
+
+  /* Extract alignment information from the innermost object and
+     possibly adjust bitpos and offset.  */
+  if (TREE_CODE (exp) == CONST_DECL)
+    exp = DECL_INITIAL (exp);
+  if (DECL_P (exp)
+      && TREE_CODE (exp) != LABEL_DECL)
+    align = DECL_ALIGN (exp);
+  else if (CONSTANT_CLASS_P (exp))
+    {
+      align = TYPE_ALIGN (TREE_TYPE (exp));
+#ifdef CONSTANT_ALIGNMENT
+      align = (unsigned)CONSTANT_ALIGNMENT (exp, align);
+#endif
+    }
+  else if (TREE_CODE (exp) == VIEW_CONVERT_EXPR)
+    align = TYPE_ALIGN (TREE_TYPE (exp));
+  else if (TREE_CODE (exp) == INDIRECT_REF)
+    align = TYPE_ALIGN (TREE_TYPE (exp));
+  else if (TREE_CODE (exp) == MEM_REF)
+    {
+      tree addr = TREE_OPERAND (exp, 0);
+      struct ptr_info_def *pi;
+      if (TREE_CODE (addr) == BIT_AND_EXPR
+         && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST)
+       {
+         align = (TREE_INT_CST_LOW (TREE_OPERAND (addr, 1))
+                   & -TREE_INT_CST_LOW (TREE_OPERAND (addr, 1)));
+         align *= BITS_PER_UNIT;
+         addr = TREE_OPERAND (addr, 0);
+       }
+      else
+       align = BITS_PER_UNIT;
+      if (TREE_CODE (addr) == SSA_NAME
+         && (pi = SSA_NAME_PTR_INFO (addr)))
+       {
+         bitpos += (pi->misalign * BITS_PER_UNIT) & ~(align - 1);
+         align = MAX (pi->align * BITS_PER_UNIT, align);
+       }
+      else if (TREE_CODE (addr) == ADDR_EXPR)
+       align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0),
+                                                 max_align));
+      bitpos += mem_ref_offset (exp).low * BITS_PER_UNIT;
+    }
+  else if (TREE_CODE (exp) == TARGET_MEM_REF)
+    {
+      struct ptr_info_def *pi;
+      tree addr = TMR_BASE (exp);
+      if (TREE_CODE (addr) == BIT_AND_EXPR
+         && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST)
+       {
+         align = (TREE_INT_CST_LOW (TREE_OPERAND (addr, 1))
+                  & -TREE_INT_CST_LOW (TREE_OPERAND (addr, 1)));
+         align *= BITS_PER_UNIT;
+         addr = TREE_OPERAND (addr, 0);
+       }
+      else
+       align = BITS_PER_UNIT;
+      if (TREE_CODE (addr) == SSA_NAME
+         && (pi = SSA_NAME_PTR_INFO (addr)))
+       {
+         bitpos += (pi->misalign * BITS_PER_UNIT) & ~(align - 1);
+         align = MAX (pi->align * BITS_PER_UNIT, align);
+       }
+      else if (TREE_CODE (addr) == ADDR_EXPR)
+       align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0),
+                                                 max_align));
+      if (TMR_OFFSET (exp))
+       bitpos += TREE_INT_CST_LOW (TMR_OFFSET (exp)) * BITS_PER_UNIT;
+      if (TMR_INDEX (exp) && TMR_STEP (exp))
+       {
+         unsigned HOST_WIDE_INT step = TREE_INT_CST_LOW (TMR_STEP (exp));
+         align = MIN (align, (step & -step) * BITS_PER_UNIT);
+       }
+      else if (TMR_INDEX (exp))
+       align = BITS_PER_UNIT;
+      if (TMR_INDEX2 (exp))
+       align = BITS_PER_UNIT;
+    }
+  else
+    align = BITS_PER_UNIT;
 
+  /* If there is a non-constant offset part extract the maximum
+     alignment that can prevail.  */
   inner = max_align;
-  if (handled_component_p (exp))
-   {
-      HOST_WIDE_INT bitsize, bitpos;
-      tree offset;
-      enum machine_mode mode; 
-      int unsignedp, volatilep;
+  while (offset)
+    {
+      tree next_offset;
 
-      exp = get_inner_reference (exp, &bitsize, &bitpos, &offset,
-                                &mode, &unsignedp, &volatilep, true);
-      if (bitpos)
-       inner = MIN (inner, (unsigned) (bitpos & -bitpos));
-      while (offset)
+      if (TREE_CODE (offset) == PLUS_EXPR)
+       {
+         next_offset = TREE_OPERAND (offset, 0);
+         offset = TREE_OPERAND (offset, 1);
+       }
+      else
+       next_offset = NULL;
+      if (host_integerp (offset, 1))
        {
-         tree next_offset;
+         /* Any overflow in calculating offset_bits won't change
+            the alignment.  */
+         unsigned offset_bits
+           = ((unsigned) tree_low_cst (offset, 1) * BITS_PER_UNIT);
 
-         if (TREE_CODE (offset) == PLUS_EXPR)
-           {
-             next_offset = TREE_OPERAND (offset, 0);
-             offset = TREE_OPERAND (offset, 1);
-           }
-         else
-           next_offset = NULL;
-         if (host_integerp (offset, 1))
-           {
-             /* Any overflow in calculating offset_bits won't change
-                the alignment.  */
-             unsigned offset_bits
-               = ((unsigned) tree_low_cst (offset, 1) * BITS_PER_UNIT);
+         if (offset_bits)
+           inner = MIN (inner, (offset_bits & -offset_bits));
+       }
+      else if (TREE_CODE (offset) == MULT_EXPR
+              && host_integerp (TREE_OPERAND (offset, 1), 1))
+       {
+         /* Any overflow in calculating offset_factor won't change
+            the alignment.  */
+         unsigned offset_factor
+           = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1)
+              * BITS_PER_UNIT);
 
-             if (offset_bits)
-               inner = MIN (inner, (offset_bits & -offset_bits));
-           }
-         else if (TREE_CODE (offset) == MULT_EXPR
-                  && host_integerp (TREE_OPERAND (offset, 1), 1))
-           {
-             /* Any overflow in calculating offset_factor won't change
-                the alignment.  */
-             unsigned offset_factor
-               = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1)
-                  * BITS_PER_UNIT);
-
-             if (offset_factor)
-               inner = MIN (inner, (offset_factor & -offset_factor));
-           }
-         else
-           {
-             inner = MIN (inner, BITS_PER_UNIT);
-             break;
-           }
-         offset = next_offset;
+         if (offset_factor)
+           inner = MIN (inner, (offset_factor & -offset_factor));
+       }
+      else
+       {
+         inner = MIN (inner, BITS_PER_UNIT);
+         break;
        }
+      offset = next_offset;
     }
-  if (DECL_P (exp))
-    align = MIN (inner, DECL_ALIGN (exp));
-#ifdef CONSTANT_ALIGNMENT
-  else if (CONSTANT_CLASS_P (exp))
-    align = MIN (inner, (unsigned)CONSTANT_ALIGNMENT (exp, align));
-#endif
-  else if (TREE_CODE (exp) == VIEW_CONVERT_EXPR
-          || TREE_CODE (exp) == INDIRECT_REF)
-    align = MIN (TYPE_ALIGN (TREE_TYPE (exp)), inner);
-  else
-    align = MIN (align, inner);
+
+  /* Alignment is innermost object alignment adjusted by the constant
+     and non-constant offset parts.  */
+  align = MIN (align, inner);
+  bitpos = bitpos & (align - 1);
+
+  /* align and bitpos now specify known low bits of the pointer.
+     ptr & (align - 1) == bitpos.  */
+
+  if (bitpos != 0)
+    align = (bitpos & -bitpos);
+
   return MIN (align, max_align);
 }
 
@@ -365,56 +441,28 @@ can_trust_pointer_alignment (void)
    Otherwise, look at the expression to see if we can do better, i.e., if the
    expression is actually pointing at an object whose alignment is tighter.  */
 
-int
+unsigned int
 get_pointer_alignment (tree exp, unsigned int max_align)
 {
-  unsigned int align, inner;
-
-  if (!can_trust_pointer_alignment ())
-    return 0;
-
-  if (!POINTER_TYPE_P (TREE_TYPE (exp)))
-    return 0;
-
-  align = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
-  align = MIN (align, max_align);
-
-  while (1)
-    {
-      switch (TREE_CODE (exp))
-       {
-       CASE_CONVERT:
-         exp = TREE_OPERAND (exp, 0);
-         if (! POINTER_TYPE_P (TREE_TYPE (exp)))
-           return align;
-
-         inner = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
-         align = MIN (inner, max_align);
-         break;
-
-       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.  */
-         if (! host_integerp (TREE_OPERAND (exp, 1), 1))
-           return align;
-
-         while (((tree_low_cst (TREE_OPERAND (exp, 1), 1))
-                 & (max_align / BITS_PER_UNIT - 1))
-                != 0)
-           max_align >>= 1;
-
-         exp = TREE_OPERAND (exp, 0);
-         break;
-
-       case ADDR_EXPR:
-         /* See what we are pointing at and look at its alignment.  */
-         return get_object_alignment (TREE_OPERAND (exp, 0), align, max_align);
+  STRIP_NOPS (exp);
 
-       default:
-         return align;
-       }
+  if (TREE_CODE (exp) == ADDR_EXPR)
+    return get_object_alignment (TREE_OPERAND (exp, 0), max_align);
+  else if (TREE_CODE (exp) == SSA_NAME
+          && POINTER_TYPE_P (TREE_TYPE (exp)))
+    {
+      struct ptr_info_def *pi = SSA_NAME_PTR_INFO (exp);
+      unsigned align;
+      if (!pi)
+       return BITS_PER_UNIT;
+      if (pi->misalign != 0)
+       align = (pi->misalign & -pi->misalign);
+      else
+       align = pi->align;
+      return MIN (max_align, align * BITS_PER_UNIT);
     }
+
+  return POINTER_TYPE_P (TREE_TYPE (exp)) ? BITS_PER_UNIT : 0;
 }
 
 /* Compute the length of a C string.  TREE_STRING_LENGTH is not the right
@@ -440,6 +488,7 @@ c_strlen (tree src, int only_value)
   HOST_WIDE_INT offset;
   int max;
   const char *ptr;
+  location_t loc;
 
   STRIP_NOPS (src);
   if (TREE_CODE (src) == COND_EXPR
@@ -457,6 +506,8 @@ c_strlen (tree src, int only_value)
       && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
     return c_strlen (TREE_OPERAND (src, 1), only_value);
 
+  loc = EXPR_LOC_OR_HERE (src);
+
   src = string_constant (src, &offset_node);
   if (src == 0)
     return NULL_TREE;
@@ -482,7 +533,7 @@ c_strlen (tree src, int only_value)
         and return that.  This would perhaps not be valid if we were dealing
         with named arrays in addition to literal string constants.  */
 
-      return size_diffop_loc (input_location, size_int (max), offset_node);
+      return size_diffop_loc (loc, size_int (max), offset_node);
     }
 
   /* We have a known offset into the string.  Start searching there for
@@ -501,7 +552,7 @@ c_strlen (tree src, int only_value)
      /* Suppress multiple warnings for propagated constant strings.  */
       if (! TREE_NO_WARNING (src))
         {
-          warning (0, "offset outside bounds of constant string");
+          warning_at (loc, 0, "offset outside bounds of constant string");
           TREE_NO_WARNING (src) = 1;
         }
       return NULL_TREE;
@@ -561,7 +612,7 @@ c_readstr (const char *str, enum machine_mode mode)
          && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
        j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
       j *= BITS_PER_UNIT;
-      gcc_assert (j <= 2 * HOST_BITS_PER_WIDE_INT);
+      gcc_assert (j < 2 * HOST_BITS_PER_WIDE_INT);
 
       if (ch)
        ch = (unsigned char) str[i];
@@ -758,13 +809,17 @@ expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
 void
 expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
 {
+  rtx chain;
+
   /* Clobber the FP when we get here, so we have to make sure it's
      marked as used by this function.  */
   emit_use (hard_frame_pointer_rtx);
 
   /* Mark the static chain as clobbered here so life information
      doesn't get messed up for it.  */
-  emit_clobber (static_chain_rtx);
+  chain = targetm.calls.static_chain (current_function_decl, true);
+  if (chain && REG_P (chain))
+    emit_clobber (chain);
 
   /* Now put in the code to restore the frame pointer, and argument
      pointer, if needed.  */
@@ -778,7 +833,7 @@ expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
       emit_clobber (hard_frame_pointer_rtx);
     }
 
-#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+#if !HARD_FRAME_POINTER_IS_ARG_POINTER
   if (fixed_regs[ARG_POINTER_REGNUM])
     {
 #ifdef ELIMINABLE_REGS
@@ -830,7 +885,7 @@ 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 
+  /* DRAP is needed for stack realign if longjmp is expanded to current
      function  */
   if (SUPPORTS_STACK_ALIGNMENT)
     crtl->need_drap = true;
@@ -842,11 +897,8 @@ expand_builtin_longjmp (rtx buf_addr, rtx value)
 
   buf_addr = force_reg (Pmode, buf_addr);
 
-  /* We used to store value in static_chain_rtx, but that fails if pointers
-     are smaller than integers.  We instead require that the user must pass
-     a second argument of 1, because that is what builtin_setjmp will
-     return.  This also makes EH slightly more efficient, since we are no
-     longer copying around a value that we don't care about.  */
+  /* We require that the user must pass a second argument of 1, because
+     that is what builtin_setjmp will return.  */
   gcc_assert (value == const1_rtx);
 
   last = get_last_insn ();
@@ -1056,7 +1108,7 @@ expand_builtin_prefetch (tree exp)
   if (nargs > 2)
     arg2 = CALL_EXPR_ARG (exp, 2);
   else
-    arg2 = build_int_cst (NULL_TREE, 3);
+    arg2 = integer_three_node;
 
   /* Argument 0 is an address.  */
   op0 = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
@@ -1249,25 +1301,10 @@ get_memory_rtx (tree exp, tree len)
 \f
 /* Built-in functions to perform an untyped call and return.  */
 
-/* For each register that may be used for calling a function, this
-   gives a mode used to copy the register's value.  VOIDmode indicates
-   the register is not used for calling a function.  If the machine
-   has register windows, this gives only the outbound registers.
-   INCOMING_REGNO gives the corresponding inbound register.  */
-static enum machine_mode apply_args_mode[FIRST_PSEUDO_REGISTER];
-
-/* For each register that may be used for returning values, this gives
-   a mode used to copy the register's value.  VOIDmode indicates the
-   register is not used for returning values.  If the machine has
-   register windows, this gives only the outbound registers.
-   INCOMING_REGNO gives the corresponding inbound register.  */
-static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER];
-
-/* For each register that may be used for calling a function, this
-   gives the offset of that register into the block returned by
-   __builtin_apply_args.  0 indicates that the register is not
-   used for calling a function.  */
-static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER];
+#define apply_args_mode \
+  (this_target_builtins->x_apply_args_mode)
+#define apply_result_mode \
+  (this_target_builtins->x_apply_result_mode)
 
 /* Return the size required for the block returned by __builtin_apply_args,
    and initialize apply_args_mode.  */
@@ -1294,21 +1331,19 @@ apply_args_size (void)
       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
        if (FUNCTION_ARG_REGNO_P (regno))
          {
-           mode = reg_raw_mode[regno];
+           mode = targetm.calls.get_raw_arg_mode (regno);
 
            gcc_assert (mode != VOIDmode);
 
            align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
            if (size % align != 0)
              size = CEIL (size, align) * align;
-           apply_args_reg_offset[regno] = size;
            size += GET_MODE_SIZE (mode);
            apply_args_mode[regno] = mode;
          }
        else
          {
            apply_args_mode[regno] = VOIDmode;
-           apply_args_reg_offset[regno] = 0;
          }
     }
   return size;
@@ -1330,9 +1365,9 @@ apply_result_size (void)
       size = 0;
 
       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-       if (FUNCTION_VALUE_REGNO_P (regno))
+       if (targetm.calls.function_value_regno_p (regno))
          {
-           mode = reg_raw_mode[regno];
+           mode = targetm.calls.get_raw_result_mode (regno);
 
            gcc_assert (mode != VOIDmode);
 
@@ -1532,8 +1567,10 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
     emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
 
   /* 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);
+     arguments to the outgoing arguments address.  We can pass TRUE
+     as the 4th argument because we just saved the stack pointer
+     and will restore it right after the call.  */
+  allocate_dynamic_stack_space (argsize, 0, BIGGEST_ALIGNMENT, true);
 
   /* Set DRAP flag to true, even though allocate_dynamic_stack_space
      may have already set current_function_calls_alloca to true.
@@ -1593,7 +1630,7 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
     }
 
   /* All arguments and registers used for the call are set up by now!  */
-  function = prepare_call_address (function, NULL, &call_fusage, 0, 0);
+  function = prepare_call_address (NULL, function, NULL, &call_fusage, 0, 0);
 
   /* Ensure address is valid.  SYMBOL_REF is already valid, so no need,
      and we don't want to load it into a register as an optimization,
@@ -1889,7 +1926,9 @@ expand_errno_check (tree exp, rtx target)
   /* Test the result; if it is NaN, set errno=EDOM because
      the argument was not in the domain.  */
   do_compare_rtx_and_jump (target, target, EQ, 0, GET_MODE (target),
-                           NULL_RTX, NULL_RTX, lab);
+                          NULL_RTX, NULL_RTX, lab,
+                          /* The jump is very likely.  */
+                          REG_BR_PROB_BASE - (REG_BR_PROB_BASE / 2000 - 1));
 
 #ifdef TARGET_EDOM
   /* If this built-in doesn't throw an exception, set errno directly.  */
@@ -1928,7 +1967,7 @@ static rtx
 expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
 {
   optab builtin_optab;
-  rtx op0, insns, before_call;
+  rtx op0, insns;
   tree fndecl = get_callee_fndecl (exp);
   enum machine_mode mode;
   bool errno_set = false;
@@ -2000,7 +2039,8 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
     errno_set = false;
 
   /* Before working hard, check whether the instruction is available.  */
-  if (optab_handler (builtin_optab, mode)->insn_code != CODE_FOR_nothing)
+  if (optab_handler (builtin_optab, mode) != CODE_FOR_nothing
+      && (!errno_set || !optimize_insn_for_size_p ()))
     {
       target = gen_reg_rtx (mode);
 
@@ -2035,8 +2075,6 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
       end_sequence ();
     }
 
-  before_call = get_last_insn ();
-
   return expand_call (exp, target, target == const0_rtx);
 }
 
@@ -2104,7 +2142,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 (optab_handler (builtin_optab, mode)->insn_code == CODE_FOR_nothing)
+  if (optab_handler (builtin_optab, mode) == CODE_FOR_nothing)
     return NULL_RTX;
 
   target = gen_reg_rtx (mode);
@@ -2112,6 +2150,9 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
   if (! flag_errno_math || ! HONOR_NANS (mode))
     errno_set = false;
 
+  if (errno_set && optimize_insn_for_size_p ())
+    return 0;
+
   /* Always stabilize the argument list.  */
   CALL_EXPR_ARG (exp, 0) = arg0 = builtin_save_expr (arg0);
   CALL_EXPR_ARG (exp, 1) = arg1 = builtin_save_expr (arg1);
@@ -2146,6 +2187,79 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
   return target;
 }
 
+/* Expand a call to the builtin trinary math functions (fma).
+   Return NULL_RTX if a normal call should be emitted rather than expanding the
+   function in-line.  EXP is the expression that is a call to the builtin
+   function; if convenient, the result should be placed in TARGET.
+   SUBTARGET may be used as the target for computing one of EXP's
+   operands.  */
+
+static rtx
+expand_builtin_mathfn_ternary (tree exp, rtx target, rtx subtarget)
+{
+  optab builtin_optab;
+  rtx op0, op1, op2, insns;
+  tree fndecl = get_callee_fndecl (exp);
+  tree arg0, arg1, arg2;
+  enum machine_mode mode;
+
+  if (!validate_arglist (exp, REAL_TYPE, REAL_TYPE, REAL_TYPE, VOID_TYPE))
+    return NULL_RTX;
+
+  arg0 = CALL_EXPR_ARG (exp, 0);
+  arg1 = CALL_EXPR_ARG (exp, 1);
+  arg2 = CALL_EXPR_ARG (exp, 2);
+
+  switch (DECL_FUNCTION_CODE (fndecl))
+    {
+    CASE_FLT_FN (BUILT_IN_FMA):
+      builtin_optab = fma_optab; break;
+    default:
+      gcc_unreachable ();
+    }
+
+  /* Make a suitable register to place result in.  */
+  mode = TYPE_MODE (TREE_TYPE (exp));
+
+  /* Before working hard, check whether the instruction is available.  */
+  if (optab_handler (builtin_optab, mode) == CODE_FOR_nothing)
+    return NULL_RTX;
+
+  target = gen_reg_rtx (mode);
+
+  /* Always stabilize the argument list.  */
+  CALL_EXPR_ARG (exp, 0) = arg0 = builtin_save_expr (arg0);
+  CALL_EXPR_ARG (exp, 1) = arg1 = builtin_save_expr (arg1);
+  CALL_EXPR_ARG (exp, 2) = arg2 = builtin_save_expr (arg2);
+
+  op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
+  op1 = expand_normal (arg1);
+  op2 = expand_normal (arg2);
+
+  start_sequence ();
+
+  /* Compute into TARGET.
+     Set TARGET to wherever the result comes back.  */
+  target = expand_ternary_op (mode, builtin_optab, op0, op1, op2,
+                             target, 0);
+
+  /* If we were unable to expand via the builtin, stop the sequence
+     (without outputting the insns) and call to the library function
+     with the stabilized argument list.  */
+  if (target == 0)
+    {
+      end_sequence ();
+      return expand_call (exp, target, target == const0_rtx);
+    }
+
+  /* Output the entire sequence.  */
+  insns = get_insns ();
+  end_sequence ();
+  emit_insn (insns);
+
+  return target;
+}
+
 /* Expand a call to the builtin sin and cos math functions.
    Return NULL_RTX if a normal call should be emitted rather than expanding the
    function in-line.  EXP is the expression that is a call to the builtin
@@ -2181,7 +2295,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 (optab_handler (builtin_optab, mode)->insn_code == CODE_FOR_nothing)
+  if (optab_handler (builtin_optab, mode) == CODE_FOR_nothing)
     switch (DECL_FUNCTION_CODE (fndecl))
       {
       CASE_FLT_FN (BUILT_IN_SIN):
@@ -2193,7 +2307,7 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
       }
 
   /* Before working hard, check whether the instruction is available.  */
-  if (optab_handler (builtin_optab, mode)->insn_code != CODE_FOR_nothing)
+  if (optab_handler (builtin_optab, mode) != CODE_FOR_nothing)
     {
       target = gen_reg_rtx (mode);
 
@@ -2250,30 +2364,16 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
   return target;
 }
 
-/* Expand a call to one of the builtin math functions that operate on
-   floating point argument and output an integer result (ilogb, isinf,
-   isnan, etc).
-   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.  */
+/* Given an interclass math builtin decl FNDECL and it's argument ARG
+   return an RTL instruction code that implements the functionality.
+   If that isn't possible or available return CODE_FOR_nothing.  */
 
-static rtx
-expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
+static enum insn_code
+interclass_mathfn_icode (tree arg, tree fndecl)
 {
+  bool errno_set = false;
   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;
-  location_t loc = EXPR_LOCATION (exp);
-
-  if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
-    return NULL_RTX;
-
-  arg = CALL_EXPR_ARG (exp, 0);
 
   switch (DECL_FUNCTION_CODE (fndecl))
     {
@@ -2284,6 +2384,12 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
     case BUILT_IN_ISNORMAL:
     case BUILT_IN_ISFINITE:
     CASE_FLT_FN (BUILT_IN_FINITE):
+    case BUILT_IN_FINITED32:
+    case BUILT_IN_FINITED64:
+    case BUILT_IN_FINITED128:
+    case BUILT_IN_ISINFD32:
+    case BUILT_IN_ISINFD64:
+    case BUILT_IN_ISINFD128:
       /* These builtins have no optabs (yet).  */
       break;
     default:
@@ -2292,20 +2398,47 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
 
   /* There's no easy way to detect the case we need to set EDOM.  */
   if (flag_errno_math && errno_set)
-    return NULL_RTX;
+    return CODE_FOR_nothing;
 
   /* Optab mode depends on the mode of the input argument.  */
   mode = TYPE_MODE (TREE_TYPE (arg));
 
   if (builtin_optab)
-    icode = optab_handler (builtin_optab, mode)->insn_code;
-  /* Before working hard, check whether the instruction is available.  */
+    return optab_handler (builtin_optab, mode);
+  return CODE_FOR_nothing;
+}
+
+/* Expand a call to one of the builtin math functions that operate on
+   floating point argument and output an integer result (ilogb, isinf,
+   isnan, etc).
+   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.  */
+
+static rtx
+expand_builtin_interclass_mathfn (tree exp, rtx target)
+{
+  enum insn_code icode = CODE_FOR_nothing;
+  rtx op0;
+  tree fndecl = get_callee_fndecl (exp);
+  enum machine_mode mode;
+  tree arg;
+
+  if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
+    return NULL_RTX;
+
+  arg = CALL_EXPR_ARG (exp, 0);
+  icode = interclass_mathfn_icode (arg, fndecl);
+  mode = TYPE_MODE (TREE_TYPE (arg));
+
   if (icode != CODE_FOR_nothing)
     {
+      rtx last = get_last_insn ();
+      tree orig_arg = arg;
       /* Make a suitable register to place result in.  */
       if (!target
-         || GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
+         || GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp))
+         || !insn_data[icode].operand[0].predicate (target, GET_MODE (target)))
          target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
 
       gcc_assert (insn_data[icode].operand[0].predicate
@@ -2316,97 +2449,36 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
         side-effects more the once.  */
       CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
 
-      op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
+      op0 = expand_expr (arg, NULL_RTX, VOIDmode, EXPAND_NORMAL);
 
       if (mode != GET_MODE (op0))
        op0 = convert_to_mode (mode, op0, 0);
 
       /* Compute into TARGET.
         Set TARGET to wherever the result comes back.  */
-      emit_unop_insn (icode, target, op0, UNKNOWN);
-      return target;
+      if (maybe_emit_unop_insn (icode, target, op0, UNKNOWN))
+       return target;
+      delete_insns_since (last);
+      CALL_EXPR_ARG (exp, 0) = orig_arg;
     }
 
-  /* If there is no optab, try generic code.  */
-  switch (DECL_FUNCTION_CODE (fndecl))
-    {
-      tree result;
+  return NULL_RTX;
+}
 
-    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];
+/* Expand a call to the builtin sincos math function.
+   Return NULL_RTX if a normal call should be emitted rather than expanding the
+   function in-line.  EXP is the expression that is a call to the builtin
+   function.  */
 
-       get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
-       real_from_string (&r, buf);
-       result = build_call_expr (isgr_fn, 2,
-                                 fold_build1_loc (loc, 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_loc (loc, 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_loc (loc, 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;
-}
-
-/* Expand a call to the builtin sincos math function.
-   Return NULL_RTX if a normal call should be emitted rather than expanding the
-   function in-line.  EXP is the expression that is a call to the builtin
-   function.  */
-
-static rtx
-expand_builtin_sincos (tree exp)
-{
-  rtx op0, op1, op2, target1, target2;
-  enum machine_mode mode;
-  tree arg, sinp, cosp;
-  int result;
-  location_t loc = EXPR_LOCATION (exp);
+static rtx
+expand_builtin_sincos (tree exp)
+{
+  rtx op0, op1, op2, target1, target2;
+  enum machine_mode mode;
+  tree arg, sinp, cosp;
+  int result;
+  location_t loc = EXPR_LOCATION (exp);
+  tree alias_type, alias_off;
 
   if (!validate_arglist (exp, REAL_TYPE,
                         POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
@@ -2420,15 +2492,19 @@ expand_builtin_sincos (tree exp)
   mode = TYPE_MODE (TREE_TYPE (arg));
 
   /* Check if sincos insn is available, otherwise emit the call.  */
-  if (optab_handler (sincos_optab, mode)->insn_code == CODE_FOR_nothing)
+  if (optab_handler (sincos_optab, mode) == CODE_FOR_nothing)
     return NULL_RTX;
 
   target1 = gen_reg_rtx (mode);
   target2 = gen_reg_rtx (mode);
 
   op0 = expand_normal (arg);
-  op1 = expand_normal (build_fold_indirect_ref_loc (loc, sinp));
-  op2 = expand_normal (build_fold_indirect_ref_loc (loc, cosp));
+  alias_type = build_pointer_type_for_mode (TREE_TYPE (arg), ptr_mode, true);
+  alias_off = build_int_cst (alias_type, 0);
+  op1 = expand_normal (fold_build2_loc (loc, MEM_REF, TREE_TYPE (arg),
+                                       sinp, alias_off));
+  op2 = expand_normal (fold_build2_loc (loc, MEM_REF, TREE_TYPE (arg),
+                                       cosp, alias_off));
 
   /* Compute into target1 and target2.
      Set TARGET to wherever the result comes back.  */
@@ -2445,11 +2521,10 @@ expand_builtin_sincos (tree exp)
 
 /* Expand a call to the internal cexpi builtin to the sincos math function.
    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.  */
+   the result should be placed in TARGET.  */
 
 static rtx
-expand_builtin_cexpi (tree exp, rtx target, rtx subtarget)
+expand_builtin_cexpi (tree exp, rtx target)
 {
   tree fndecl = get_callee_fndecl (exp);
   tree arg, type;
@@ -2467,12 +2542,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 (optab_handler (sincos_optab, mode)->insn_code != CODE_FOR_nothing)
+  if (optab_handler (sincos_optab, mode) != CODE_FOR_nothing)
     {
       op1 = gen_reg_rtx (mode);
       op2 = gen_reg_rtx (mode);
 
-      op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
+      op0 = expand_expr (arg, NULL_RTX, VOIDmode, EXPAND_NORMAL);
 
       /* Compute into op1 and op2.  */
       expand_twoval_unop (sincos_optab, op0, op2, op1, 0);
@@ -2491,7 +2566,7 @@ expand_builtin_cexpi (tree exp, rtx target, rtx subtarget)
        fn = built_in_decls[BUILT_IN_SINCOSL];
       else
        gcc_unreachable ();
+
       op1 = assign_temp (TREE_TYPE (arg), 0, 1, 1);
       op2 = assign_temp (TREE_TYPE (arg), 0, 1, 1);
       op1a = copy_to_mode_reg (Pmode, XEXP (op1, 0));
@@ -2542,7 +2617,7 @@ expand_builtin_cexpi (tree exp, rtx target, rtx subtarget)
 
       /* 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, narg), 
+      return expand_expr (build_call_nary (ctype, call, 1, narg),
                          target, VOIDmode, EXPAND_NORMAL);
     }
 
@@ -2553,6 +2628,25 @@ expand_builtin_cexpi (tree exp, rtx target, rtx subtarget)
                      target, VOIDmode, EXPAND_NORMAL);
 }
 
+/* Conveniently construct a function call expression.  FNDECL names the
+   function to be called, N is the number of arguments, and the "..."
+   parameters are the argument expressions.  Unlike build_call_exr
+   this doesn't fold the call, hence it will always return a CALL_EXPR.  */
+
+static tree
+build_call_nofold_loc (location_t loc, tree fndecl, int n, ...)
+{
+  va_list ap;
+  tree fntype = TREE_TYPE (fndecl);
+  tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
+
+  va_start (ap, n);
+  fn = build_call_valist (TREE_TYPE (fntype), fn, n, ap);
+  va_end (ap);
+  SET_EXPR_LOCATION (fn, loc);
+  return fn;
+}
+
 /* Expand a call to one of the builtin rounding functions gcc defines
    as an extension (lfloor and lceil).  As these are gcc extensions we
    do not need to worry about setting errno to EDOM.
@@ -2669,7 +2763,7 @@ expand_builtin_int_roundingfn (tree exp, rtx target)
       fallback_fndecl = build_fn_decl (name, fntype);
     }
 
-  exp = build_call_expr (fallback_fndecl, 1, arg);
+  exp = build_call_nofold_loc (EXPR_LOCATION (exp), fallback_fndecl, 1, arg);
 
   tmp = expand_normal (exp);
 
@@ -2702,7 +2796,7 @@ expand_builtin_int_roundingfn_2 (tree exp, rtx target)
 
   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
      gcc_unreachable ();
+
   arg = CALL_EXPR_ARG (exp, 0);
 
   switch (DECL_FUNCTION_CODE (fndecl))
@@ -2933,15 +3027,12 @@ expand_powi_1 (enum machine_mode mode, unsigned HOST_WIDE_INT n, rtx *cache)
 static rtx
 expand_powi (rtx x, enum machine_mode mode, HOST_WIDE_INT n)
 {
-  unsigned HOST_WIDE_INT val;
   rtx cache[POWI_TABLE_SIZE];
   rtx result;
 
   if (n == 0)
     return CONST1_RTX (mode);
 
-  val = (n < 0) ? -n : n;
-
   memset (cache, 0, sizeof (cache));
   cache[1] = x;
 
@@ -2955,6 +3046,95 @@ expand_powi (rtx x, enum machine_mode mode, HOST_WIDE_INT n)
   return result;
 }
 
+/* Fold a builtin function call to pow, powf, or powl into a series of sqrts or
+   cbrts.  Return NULL_RTX if no simplification can be made or expand the tree
+   if we can simplify it.  */
+static rtx
+expand_builtin_pow_root (location_t loc, tree arg0, tree arg1, tree type,
+                        rtx subtarget)
+{
+  if (TREE_CODE (arg1) == REAL_CST
+      && !TREE_OVERFLOW (arg1)
+      && flag_unsafe_math_optimizations)
+    {
+      enum machine_mode mode = TYPE_MODE (type);
+      tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
+      tree cbrtfn = mathfn_built_in (type, BUILT_IN_CBRT);
+      REAL_VALUE_TYPE c = TREE_REAL_CST (arg1);
+      tree op = NULL_TREE;
+
+      if (sqrtfn)
+       {
+         /* Optimize pow (x, 0.5) into sqrt.  */
+         if (REAL_VALUES_EQUAL (c, dconsthalf))
+           op = build_call_nofold_loc (loc, sqrtfn, 1, arg0);
+
+         else
+           {
+             REAL_VALUE_TYPE dconst1_4 = dconst1;
+             REAL_VALUE_TYPE dconst3_4;
+             SET_REAL_EXP (&dconst1_4, REAL_EXP (&dconst1_4) - 2);
+
+             real_from_integer (&dconst3_4, VOIDmode, 3, 0, 0);
+             SET_REAL_EXP (&dconst3_4, REAL_EXP (&dconst3_4) - 2);
+
+             /* Optimize pow (x, 0.25) into sqrt (sqrt (x)).  Assume on most
+                machines that a builtin sqrt instruction is smaller than a
+                call to pow with 0.25, so do this optimization even if
+                -Os.  */
+             if (REAL_VALUES_EQUAL (c, dconst1_4))
+               {
+                 op = build_call_nofold_loc (loc, sqrtfn, 1, arg0);
+                 op = build_call_nofold_loc (loc, sqrtfn, 1, op);
+               }
+
+             /* Optimize pow (x, 0.75) = sqrt (x) * sqrt (sqrt (x)) unless we
+                are optimizing for space.  */
+             else if (optimize_insn_for_speed_p ()
+                      && !TREE_SIDE_EFFECTS (arg0)
+                      && REAL_VALUES_EQUAL (c, dconst3_4))
+               {
+                 tree sqrt1 = build_call_expr_loc (loc, sqrtfn, 1, arg0);
+                 tree sqrt2 = builtin_save_expr (sqrt1);
+                 tree sqrt3 = build_call_expr_loc (loc, sqrtfn, 1, sqrt1);
+                 op = fold_build2_loc (loc, MULT_EXPR, type, sqrt2, sqrt3);
+               }
+           }
+       }
+
+      /* Check whether we can do cbrt insstead of pow (x, 1./3.) and
+        cbrt/sqrts instead of pow (x, 1./6.).  */
+      if (cbrtfn && ! op
+         && (tree_expr_nonnegative_p (arg0) || !HONOR_NANS (mode)))
+       {
+         /* First try 1/3.  */
+         REAL_VALUE_TYPE dconst1_3
+           = real_value_truncate (mode, dconst_third ());
+
+         if (REAL_VALUES_EQUAL (c, dconst1_3))
+           op = build_call_nofold_loc (loc, cbrtfn, 1, arg0);
+
+             /* Now try 1/6.  */
+         else if (optimize_insn_for_speed_p ())
+           {
+             REAL_VALUE_TYPE dconst1_6 = dconst1_3;
+             SET_REAL_EXP (&dconst1_6, REAL_EXP (&dconst1_6) - 1);
+
+             if (REAL_VALUES_EQUAL (c, dconst1_6))
+               {
+                 op = build_call_nofold_loc (loc, sqrtfn, 1, arg0);
+                 op = build_call_nofold_loc (loc, cbrtfn, 1, op);
+               }
+           }
+       }
+
+      if (op)
+       return expand_expr (op, subtarget, mode, EXPAND_NORMAL);
+    }
+
+  return NULL_RTX;
+}
+
 /* Expand a call to the pow built-in mathematical function.  Return NULL_RTX if
    a normal call should be emitted rather than expanding the function
    in-line.  EXP is the expression that is a call to the builtin
@@ -3017,9 +3197,18 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
          && ((flag_unsafe_math_optimizations
               && optimize_insn_for_speed_p ()
               && powi_cost (n/2) <= POWI_MAX_MULTS)
-             || n == 1))
-       {
-         tree call_expr = build_call_expr (fn, 1, narg0);
+             /* Even the c == 0.5 case cannot be done unconditionally
+                when we need to preserve signed zeros, as
+                pow (-0, 0.5) is +0, while sqrt(-0) is -0.  */
+             || (!HONOR_SIGNED_ZEROS (mode) && n == 1)
+             /* For c == 1.5 we can assume that x * sqrt (x) is always
+                smaller than pow (x, 1.5) if sqrt will not be expanded
+                as a call.  */
+             || (n == 3
+                 && optab_handler (sqrt_optab, mode) != CODE_FOR_nothing)))
+       {
+         tree call_expr = build_call_nofold_loc (EXPR_LOCATION (exp), fn, 1,
+                                                 narg0);
          /* 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);
@@ -3040,6 +3229,13 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
        }
     }
 
+  /* Check whether we can do a series of sqrt or cbrt's instead of the pow
+     call.  */
+  op = expand_builtin_pow_root (EXPR_LOCATION (exp), arg0, arg1, type,
+                               subtarget);
+  if (op)
+    return op;
+
   /* Try if the exponent is a third of an integer.  In this case
      we can expand to x**(n/3) * cbrt(x)**(n%3).  As cbrt (x) is
      different from pow (x, 1./3.) due to rounding and behavior
@@ -3064,7 +3260,8 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
               && powi_cost (n/3) <= POWI_MAX_MULTS)
              || n == 1))
        {
-         tree call_expr = build_call_expr (fn, 1,narg0);
+         tree call_expr = build_call_nofold_loc (EXPR_LOCATION (exp), fn, 1,
+                                                 narg0);
          op = expand_builtin (call_expr, NULL_RTX, subtarget, mode, 0);
          if (abs (n) % 3 == 2)
            op = expand_simple_binop (mode, MULT, op, op, op,
@@ -3096,7 +3293,7 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
    function; if convenient, the result should be placed in TARGET.  */
 
 static rtx
-expand_builtin_powi (tree exp, rtx target, rtx subtarget)
+expand_builtin_powi (tree exp, rtx target)
 {
   tree arg0, arg1;
   rtx op0, op1;
@@ -3125,7 +3322,7 @@ expand_builtin_powi (tree exp, rtx target, rtx subtarget)
              || (optimize_insn_for_speed_p ()
                  && powi_cost (n) <= POWI_MAX_MULTS)))
        {
-         op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
+         op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
          op0 = force_reg (mode, op0);
          return expand_powi (op0, mode, n);
        }
@@ -3139,7 +3336,7 @@ expand_builtin_powi (tree exp, rtx target, rtx subtarget)
   if (target == NULL_RTX)
     target = gen_reg_rtx (mode);
 
-  op0 = expand_expr (arg0, subtarget, mode, EXPAND_NORMAL);
+  op0 = expand_expr (arg0, NULL_RTX, mode, EXPAND_NORMAL);
   if (GET_MODE (op0) != mode)
     op0 = convert_to_mode (mode, op0, 0);
   op1 = expand_expr (arg1, NULL_RTX, mode2, EXPAND_NORMAL);
@@ -3153,7 +3350,7 @@ expand_builtin_powi (tree exp, rtx target, rtx subtarget)
   return target;
 }
 
-/* Expand expression EXP which is a call to the strlen builtin.  Return 
+/* Expand expression EXP which is a call to the strlen builtin.  Return
    NULL_RTX if we failed the caller should emit a normal call, otherwise
    try to get the result in TARGET, if convenient.  */
 
@@ -3171,7 +3368,7 @@ expand_builtin_strlen (tree exp, rtx target,
       rtx result, src_reg, char_rtx, before_strlen;
       enum machine_mode insn_mode = target_mode, char_mode;
       enum insn_code icode = CODE_FOR_nothing;
-      int align;
+      unsigned int align;
 
       /* If the length can be computed at compile-time, return it.  */
       len = c_strlen (src, 0);
@@ -3199,7 +3396,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 = optab_handler (strlen_optab, insn_mode)->insn_code;
+         icode = optab_handler (strlen_optab, insn_mode);
          if (icode != CODE_FOR_nothing)
            break;
 
@@ -3262,84 +3459,6 @@ expand_builtin_strlen (tree exp, rtx target,
     }
 }
 
-/* Expand a call to the strstr builtin.  Return NULL_RTX if we failed the
-   caller should emit a normal call, otherwise try to get the result
-   in TARGET, if convenient (and in mode MODE if that's convenient).  */
-
-static rtx
-expand_builtin_strstr (tree exp, rtx target, enum machine_mode mode)
-{
-  if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
-    {
-      tree type = TREE_TYPE (exp);
-      tree result = fold_builtin_strstr (EXPR_LOCATION (exp),
-                                        CALL_EXPR_ARG (exp, 0),
-                                        CALL_EXPR_ARG (exp, 1), type);
-      if (result)
-       return expand_expr (result, target, mode, EXPAND_NORMAL);
-    }
-  return NULL_RTX;
-}
-
-/* Expand a call to the strchr builtin.  Return NULL_RTX if we failed the
-   caller should emit a normal call, otherwise try to get the result
-   in TARGET, if convenient (and in mode MODE if that's convenient).  */
-
-static rtx
-expand_builtin_strchr (tree exp, rtx target, enum machine_mode mode)
-{
-  if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
-    {
-      tree type = TREE_TYPE (exp);
-      tree result = fold_builtin_strchr (EXPR_LOCATION (exp),
-                                        CALL_EXPR_ARG (exp, 0),
-                                        CALL_EXPR_ARG (exp, 1), type);
-      if (result)
-       return expand_expr (result, target, mode, EXPAND_NORMAL);
-
-      /* FIXME: Should use strchrM optab so that ports can optimize this.  */
-    }
-  return NULL_RTX;
-}
-
-/* Expand a call to the strrchr builtin.  Return NULL_RTX if we failed the
-   caller should emit a normal call, otherwise try to get the result
-   in TARGET, if convenient (and in mode MODE if that's convenient).  */
-
-static rtx
-expand_builtin_strrchr (tree exp, rtx target, enum machine_mode mode)
-{
-  if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
-    {
-      tree type = TREE_TYPE (exp);
-      tree result = fold_builtin_strrchr (EXPR_LOCATION (exp),
-                                         CALL_EXPR_ARG (exp, 0),
-                                         CALL_EXPR_ARG (exp, 1), type);
-      if (result)
-       return expand_expr (result, target, mode, EXPAND_NORMAL);
-    }
-  return NULL_RTX;
-}
-
-/* Expand a call to the strpbrk builtin.  Return NULL_RTX if we failed the
-   caller should emit a normal call, otherwise try to get the result
-   in TARGET, if convenient (and in mode MODE if that's convenient).  */
-
-static rtx
-expand_builtin_strpbrk (tree exp, rtx target, enum machine_mode mode)
-{
-  if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
-    {
-      tree type = TREE_TYPE (exp);
-      tree result = fold_builtin_strpbrk (EXPR_LOCATION (exp),
-                                         CALL_EXPR_ARG (exp, 0),
-                                         CALL_EXPR_ARG (exp, 1), type);
-      if (result)
-       return expand_expr (result, target, mode, EXPAND_NORMAL);
-    }
-  return NULL_RTX;
-}
-
 /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
    bytes from constant string DATA + OFFSET and return it as target
    constant.  */
@@ -3363,10 +3482,8 @@ builtin_memcpy_read_str (void *data, HOST_WIDE_INT offset,
    mode MODE if that's convenient).  */
 
 static rtx
-expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
+expand_builtin_memcpy (tree exp, rtx target)
 {
-  tree fndecl = get_callee_fndecl (exp);
-
   if (!validate_arglist (exp,
                         POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return NULL_RTX;
@@ -3380,24 +3497,8 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
       unsigned int dest_align
        = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
       rtx dest_mem, src_mem, dest_addr, len_rtx;
-      tree result = fold_builtin_memory_op (EXPR_LOCATION (exp),
-                                           dest, src, len, 
-                                           TREE_TYPE (TREE_TYPE (fndecl)),
-                                           false, /*endp=*/0);
       HOST_WIDE_INT expected_size = -1;
       unsigned int expected_align = 0;
-      tree_ann_common_t ann;
-
-      if (result)
-       {
-         while (TREE_CODE (result) == COMPOUND_EXPR)
-           {
-             expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
-                          EXPAND_NORMAL);
-             result = TREE_OPERAND (result, 1);
-           }
-         return expand_expr (result, target, mode, EXPAND_NORMAL);
-       }
 
       /* If DEST is not a pointer type, call the normal function.  */
       if (dest_align == 0)
@@ -3407,10 +3508,10 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
         operation in-line.  */
       if (src_align == 0)
        return NULL_RTX;
-      ann = tree_common_ann (exp);
-      if (ann)
-        stringop_block_profile (ann->stmt, &expected_align, &expected_size);
+
+      if (currently_expanding_gimple_stmt)
+        stringop_block_profile (currently_expanding_gimple_stmt,
+                               &expected_align, &expected_size);
 
       if (expected_align < dest_align)
        expected_align = dest_align;
@@ -3433,7 +3534,7 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
                                      builtin_memcpy_read_str,
                                      CONST_CAST (char *, src_str),
                                      dest_align, false, 0);
-         dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+         dest_mem = force_operand (XEXP (dest_mem, 0), target);
          dest_mem = convert_memory_address (ptr_mode, dest_mem);
          return dest_mem;
        }
@@ -3449,7 +3550,7 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
 
       if (dest_addr == 0)
        {
-         dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+         dest_addr = force_operand (XEXP (dest_mem, 0), target);
          dest_addr = convert_memory_address (ptr_mode, dest_addr);
        }
       return dest_addr;
@@ -3476,7 +3577,6 @@ expand_builtin_mempcpy (tree exp, rtx target, enum machine_mode mode)
       tree src = CALL_EXPR_ARG (exp, 1);
       tree len = CALL_EXPR_ARG (exp, 2);
       return expand_builtin_mempcpy_args (dest, src, len,
-                                         TREE_TYPE (exp),
                                          target, mode, /*endp=*/ 1);
     }
 }
@@ -3484,25 +3584,19 @@ expand_builtin_mempcpy (tree exp, rtx target, enum machine_mode mode)
 /* Helper function to do the actual work for expand_builtin_mempcpy.  The
    arguments to the builtin_mempcpy call DEST, SRC, and LEN are broken out
    so that this can also be called without constructing an actual CALL_EXPR.
-   TYPE is the return type of the call.  The other arguments and return value
-   are the same as for expand_builtin_mempcpy.  */
+   The other arguments and return value are the same as for
+   expand_builtin_mempcpy.  */
 
 static rtx
-expand_builtin_mempcpy_args (tree dest, tree src, tree len, tree type,
+expand_builtin_mempcpy_args (tree dest, tree src, tree len,
                             rtx target, enum machine_mode mode, int endp)
 {
     /* If return value is ignored, transform mempcpy into memcpy.  */
   if (target == const0_rtx && implicit_built_in_decls[BUILT_IN_MEMCPY])
     {
       tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
-      tree result = build_call_expr (fn, 3, dest, src, len);
-
-      while (TREE_CODE (result) == COMPOUND_EXPR)
-       {
-         expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
-                      EXPAND_NORMAL);
-         result = TREE_OPERAND (result, 1);
-       }
+      tree result = build_call_nofold_loc (UNKNOWN_LOCATION, fn, 3,
+                                          dest, src, len);
       return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
   else
@@ -3512,19 +3606,6 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len, tree type,
       unsigned int dest_align
        = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
       rtx dest_mem, src_mem, len_rtx;
-      tree result = fold_builtin_memory_op (UNKNOWN_LOCATION,
-                                           dest, src, len, type, false, endp);
-
-      if (result)
-       {
-         while (TREE_CODE (result) == COMPOUND_EXPR)
-           {
-             expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
-                          EXPAND_NORMAL);
-             result = TREE_OPERAND (result, 1);
-           }
-         return expand_expr (result, target, mode, EXPAND_NORMAL);
-       }
 
       /* If either SRC or DEST is not a pointer type, don't do this
         operation in-line.  */
@@ -3578,82 +3659,6 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len, tree type,
     }
 }
 
-/* Expand expression EXP, which is a call to the memmove builtin.  Return 
-   NULL_RTX if we failed; the caller should emit a normal call.  */
-
-static rtx
-expand_builtin_memmove (tree exp, rtx target, enum machine_mode mode, int ignore)
-{
-  if (!validate_arglist (exp,
-                        POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
-    return NULL_RTX;
-  else
-    {
-      tree dest = CALL_EXPR_ARG (exp, 0);
-      tree src = CALL_EXPR_ARG (exp, 1);
-      tree len = CALL_EXPR_ARG (exp, 2);
-      return expand_builtin_memmove_args (dest, src, len, TREE_TYPE (exp), 
-                                         target, mode, ignore);
-    }
-}
-
-/* Helper function to do the actual work for expand_builtin_memmove.  The
-   arguments to the builtin_memmove call DEST, SRC, and LEN are broken out
-   so that this can also be called without constructing an actual CALL_EXPR.
-   TYPE is the return type of the call.  The other arguments and return value
-   are the same as for expand_builtin_memmove.  */
-
-static rtx
-expand_builtin_memmove_args (tree dest, tree src, tree len,
-                            tree type, rtx target, enum machine_mode mode, 
-                             int ignore)
-{
-  tree result = fold_builtin_memory_op (UNKNOWN_LOCATION,
-                                       dest, src, len, type, ignore, /*endp=*/3);
-
-  if (result)
-    {
-      STRIP_TYPE_NOPS (result);
-      while (TREE_CODE (result) == COMPOUND_EXPR)
-       {
-         expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
-                      EXPAND_NORMAL);
-         result = TREE_OPERAND (result, 1);
-       }
-      return expand_expr (result, target, mode, EXPAND_NORMAL);
-    }
-  
-  /* Otherwise, call the normal function.  */
-  return NULL_RTX;
-}
-
-/* Expand expression EXP, which is a call to the bcopy builtin.  Return 
-   NULL_RTX if we failed the caller should emit a normal call.  */
-
-static rtx
-expand_builtin_bcopy (tree exp, int ignore)
-{
-  tree type = TREE_TYPE (exp);
-  tree src, dest, size;
-  location_t loc = EXPR_LOCATION (exp);
-
-  if (!validate_arglist (exp,
-                        POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
-    return NULL_RTX;
-
-  src = CALL_EXPR_ARG (exp, 0);
-  dest = CALL_EXPR_ARG (exp, 1);
-  size = CALL_EXPR_ARG (exp, 2);
-
-  /* Transform bcopy(ptr x, ptr y, int z) to memmove(ptr y, ptr x, size_t z).
-     This is done this way so that if it isn't expanded inline, we fall
-     back to calling bcopy instead of memmove.  */
-  return expand_builtin_memmove_args (dest, src,
-                                     fold_convert_loc (loc, sizetype, size),
-                                     type, const0_rtx, VOIDmode, 
-                                     ignore);
-}
-
 #ifndef HAVE_movstr
 # define HAVE_movstr 0
 # define CODE_FOR_movstr CODE_FOR_nothing
@@ -3673,13 +3678,14 @@ expand_movstr (tree dest, tree src, rtx target, int endp)
   rtx dest_mem;
   rtx src_mem;
   rtx insn;
-  const struct insn_data * data;
+  const struct insn_data_d * data;
 
   if (!HAVE_movstr)
     return NULL_RTX;
 
   dest_mem = get_memory_rtx (dest, NULL);
   src_mem = get_memory_rtx (src, NULL);
+  data = insn_data + CODE_FOR_movstr;
   if (!endp)
     {
       target = force_reg (Pmode, XEXP (dest_mem, 0));
@@ -3688,18 +3694,18 @@ expand_movstr (tree dest, tree src, rtx target, int endp)
     }
   else
     {
-      if (target == 0 || target == const0_rtx)
+      if (target == 0
+         || target == const0_rtx
+         || ! (*data->operand[0].predicate) (target, Pmode))
        {
          end = gen_reg_rtx (Pmode);
-         if (target == 0)
+         if (target != const0_rtx)
            target = end;
        }
       else
        end = target;
     }
 
-  data = insn_data + CODE_FOR_movstr;
-
   if (data->operand[0].mode != VOIDmode)
     end = gen_lowpart (data->operand[0].mode, end);
 
@@ -3721,19 +3727,19 @@ expand_movstr (tree dest, tree src, rtx target, int endp)
   return target;
 }
 
-/* Expand expression EXP, which is a call to the strcpy builtin.  Return 
-   NULL_RTX if we failed the caller should emit a normal call, otherwise 
+/* Expand expression EXP, which is a call to the strcpy 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_strcpy (tree fndecl, tree exp, rtx target, enum machine_mode mode)
+expand_builtin_strcpy (tree exp, rtx target)
 {
   if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
    {
      tree dest = CALL_EXPR_ARG (exp, 0);
      tree src = CALL_EXPR_ARG (exp, 1);
-     return expand_builtin_strcpy_args (fndecl, dest, src, target, mode);
+     return expand_builtin_strcpy_args (dest, src, target);
    }
    return NULL_RTX;
 }
@@ -3745,15 +3751,9 @@ expand_builtin_strcpy (tree fndecl, tree exp, rtx target, enum machine_mode mode
    expand_builtin_strcpy.  */
 
 static rtx
-expand_builtin_strcpy_args (tree fndecl, tree dest, tree src,
-                           rtx target, enum machine_mode mode)
+expand_builtin_strcpy_args (tree dest, tree src, rtx target)
 {
-  tree result = fold_builtin_strcpy (UNKNOWN_LOCATION,
-                                    fndecl, dest, src, 0);
-  if (result)
-    return expand_expr (result, target, mode, EXPAND_NORMAL);
   return expand_movstr (dest, src, target, /*endp=*/0);
-
 }
 
 /* Expand a call EXP to the stpcpy builtin.
@@ -3777,15 +3777,7 @@ expand_builtin_stpcpy (tree exp, rtx target, enum machine_mode mode)
   if (target == const0_rtx && implicit_built_in_decls[BUILT_IN_STRCPY])
     {
       tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
-      tree result = build_call_expr (fn, 2, dst, src);
-
-      STRIP_NOPS (result);
-      while (TREE_CODE (result) == COMPOUND_EXPR)
-       {
-         expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
-                      EXPAND_NORMAL);
-         result = TREE_OPERAND (result, 1);
-       }
+      tree result = build_call_nofold_loc (loc, fn, 2, dst, src);
       return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
   else
@@ -3801,7 +3793,7 @@ expand_builtin_stpcpy (tree exp, rtx target, enum machine_mode mode)
        return expand_movstr (dst, src, target, /*endp=*/2);
 
       lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1));
-      ret = expand_builtin_mempcpy_args (dst, src, lenp1, TREE_TYPE (exp),
+      ret = expand_builtin_mempcpy_args (dst, src, lenp1,
                                         target, mode, /*endp=*/2);
 
       if (ret)
@@ -3813,8 +3805,7 @@ expand_builtin_stpcpy (tree exp, rtx target, enum machine_mode mode)
 
          if (CONST_INT_P (len_rtx))
            {
-             ret = expand_builtin_strcpy_args (get_callee_fndecl (exp),
-                                               dst, src, target, mode);
+             ret = expand_builtin_strcpy_args (dst, src, target);
 
              if (ret)
                {
@@ -3857,13 +3848,12 @@ builtin_strncpy_read_str (void *data, HOST_WIDE_INT offset,
   return c_readstr (str + offset, mode);
 }
 
-/* Expand expression EXP, which is a call to the strncpy builtin.  Return 
+/* Expand expression EXP, which is a call to the strncpy builtin.  Return
    NULL_RTX if we failed the caller should emit a normal call.  */
 
 static rtx
-expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode)
+expand_builtin_strncpy (tree exp, rtx target)
 {
-  tree fndecl = get_callee_fndecl (exp);
   location_t loc = EXPR_LOCATION (exp);
 
   if (validate_arglist (exp,
@@ -3873,19 +3863,6 @@ expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode)
       tree src = CALL_EXPR_ARG (exp, 1);
       tree len = CALL_EXPR_ARG (exp, 2);
       tree slen = c_strlen (src, 1);
-      tree result = fold_builtin_strncpy (EXPR_LOCATION (exp),
-                                         fndecl, dest, src, len, slen);
-
-      if (result)
-       {
-         while (TREE_CODE (result) == COMPOUND_EXPR)
-           {
-             expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
-                          EXPAND_NORMAL);
-             result = TREE_OPERAND (result, 1);
-           }
-         return expand_expr (result, target, mode, EXPAND_NORMAL);
-       }
 
       /* We must be passed a constant len and src parameter.  */
       if (!host_integerp (len, 1) || !slen || !host_integerp (slen, 1))
@@ -3914,7 +3891,7 @@ expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode)
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_strncpy_read_str,
                           CONST_CAST (char *, p), dest_align, false, 0);
-         dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+         dest_mem = force_operand (XEXP (dest_mem, 0), target);
          dest_mem = convert_memory_address (ptr_mode, dest_mem);
          return dest_mem;
        }
@@ -3964,8 +3941,8 @@ builtin_memset_gen_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
   return force_reg (mode, target);
 }
 
-/* Expand expression EXP, which is a call to the memset builtin.  Return 
-   NULL_RTX if we failed the caller should emit a normal call, otherwise 
+/* Expand expression EXP, which is a call to the memset 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).  */
 
@@ -4001,7 +3978,6 @@ 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);
 
@@ -4009,9 +3985,9 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
   if (dest_align == 0)
     return NULL_RTX;
 
-  ann = tree_common_ann (orig_exp);
-  if (ann)
-    stringop_block_profile (ann->stmt, &expected_align, &expected_size);
+  if (currently_expanding_gimple_stmt)
+    stringop_block_profile (currently_expanding_gimple_stmt,
+                           &expected_align, &expected_size);
 
   if (expected_align < dest_align)
     expected_align = dest_align;
@@ -4059,7 +4035,7 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
                                        dest_align, expected_align,
                                        expected_size))
        goto do_libcall;
-      
+
       dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
       dest_mem = convert_memory_address (ptr_mode, dest_mem);
       return dest_mem;
@@ -4080,7 +4056,7 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
                                        dest_align, expected_align,
                                        expected_size))
        goto do_libcall;
-      
+
       dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
       dest_mem = convert_memory_address (ptr_mode, dest_mem);
       return dest_mem;
@@ -4104,17 +4080,19 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
   fndecl = get_callee_fndecl (orig_exp);
   fcode = DECL_FUNCTION_CODE (fndecl);
   if (fcode == BUILT_IN_MEMSET)
-    fn = build_call_expr (fndecl, 3, dest, val, len);
+    fn = build_call_nofold_loc (EXPR_LOCATION (orig_exp), fndecl, 3,
+                               dest, val, len);
   else if (fcode == BUILT_IN_BZERO)
-    fn = build_call_expr (fndecl, 2, dest, len);
+    fn = build_call_nofold_loc (EXPR_LOCATION (orig_exp), fndecl, 2,
+                               dest, len);
   else
     gcc_unreachable ();
-  if (TREE_CODE (fn) == CALL_EXPR)
-    CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp);
+  gcc_assert (TREE_CODE (fn) == CALL_EXPR);
+  CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (orig_exp);
   return expand_call (fn, target, target == const0_rtx);
 }
 
-/* Expand expression EXP, which is a call to the bzero builtin.  Return 
+/* Expand expression EXP, which is a call to the bzero builtin.  Return
    NULL_RTX if we failed the caller should emit a normal call.  */
 
 static rtx
@@ -4139,49 +4117,20 @@ 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 (EXPR_LOCATION (exp),
-                                        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
    TARGET, if convenient (and in mode MODE, if that's convenient).  */
 
 static rtx
-expand_builtin_memcmp (tree exp, rtx target, enum machine_mode mode)
+expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target,
+                      ATTRIBUTE_UNUSED enum machine_mode mode)
 {
-  location_t loc = EXPR_LOCATION (exp);
+  location_t loc ATTRIBUTE_UNUSED = EXPR_LOCATION (exp);
 
   if (!validate_arglist (exp,
                         POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return NULL_RTX;
-  else
-    {
-      tree result = fold_builtin_memcmp (EXPR_LOCATION (exp),
-                                        CALL_EXPR_ARG (exp, 0),
-                                        CALL_EXPR_ARG (exp, 1),
-                                        CALL_EXPR_ARG (exp, 2));
-      if (result)
-       return expand_expr (result, target, mode, EXPAND_NORMAL);
-    }
 
 #if defined HAVE_cmpmemsi || defined HAVE_cmpstrnsi
   {
@@ -4192,9 +4141,9 @@ expand_builtin_memcmp (tree exp, rtx target, enum machine_mode mode)
     tree arg2 = CALL_EXPR_ARG (exp, 1);
     tree len = CALL_EXPR_ARG (exp, 2);
 
-    int arg1_align
+    unsigned int arg1_align
       = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
-    int arg2_align
+    unsigned int arg2_align
       = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
     enum machine_mode insn_mode;
 
@@ -4279,24 +4228,14 @@ expand_builtin_memcmp (tree exp, rtx target, enum machine_mode mode)
    the result in TARGET, if convenient.  */
 
 static rtx
-expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
+expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
 {
-  location_t loc = EXPR_LOCATION (exp);
-
   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return NULL_RTX;
-  else
-    {
-      tree result = fold_builtin_strcmp (loc,
-                                        CALL_EXPR_ARG (exp, 0),
-                                        CALL_EXPR_ARG (exp, 1));
-      if (result)
-       return expand_expr (result, target, mode, EXPAND_NORMAL);
-    }
 
 #if defined HAVE_cmpstrsi || defined HAVE_cmpstrnsi
-  if (cmpstr_optab[SImode] != CODE_FOR_nothing
-      || cmpstrn_optab[SImode] != CODE_FOR_nothing)
+  if (direct_optab_handler (cmpstr_optab, SImode) != CODE_FOR_nothing
+      || direct_optab_handler (cmpstrn_optab, SImode) != CODE_FOR_nothing)
     {
       rtx arg1_rtx, arg2_rtx;
       rtx result, insn = NULL_RTX;
@@ -4304,9 +4243,9 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
       tree arg1 = CALL_EXPR_ARG (exp, 0);
       tree arg2 = CALL_EXPR_ARG (exp, 1);
 
-      int arg1_align
+      unsigned int arg1_align
        = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
-      int arg2_align
+      unsigned int arg2_align
        = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
 
       /* If we don't have POINTER_TYPE, call the function.  */
@@ -4399,6 +4338,7 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
 
       if (insn)
        {
+         enum machine_mode mode;
          emit_insn (insn);
 
          /* Return the value in the proper mode for this function.  */
@@ -4417,36 +4357,28 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
     do_libcall:
 #endif
       fndecl = get_callee_fndecl (exp);
-      fn = build_call_expr (fndecl, 2, arg1, arg2);
-      if (TREE_CODE (fn) == CALL_EXPR)
-       CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
+      fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 2, arg1, arg2);
+      gcc_assert (TREE_CODE (fn) == CALL_EXPR);
+      CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
       return expand_call (fn, target, target == const0_rtx);
     }
 #endif
   return NULL_RTX;
 }
 
-/* Expand expression EXP, which is a call to the strncmp builtin. Return 
+/* Expand expression EXP, which is a call to the strncmp builtin. Return
    NULL_RTX if we failed the caller should emit a normal call, otherwise try to get
    the result in TARGET, if convenient.  */
 
 static rtx
-expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
+expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
+                       ATTRIBUTE_UNUSED enum machine_mode mode)
 {
-  location_t loc = EXPR_LOCATION (exp);
+  location_t loc ATTRIBUTE_UNUSED = EXPR_LOCATION (exp);
 
   if (!validate_arglist (exp,
                         POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return NULL_RTX;
-  else
-    {
-      tree result = fold_builtin_strncmp (EXPR_LOCATION (exp),
-                                         CALL_EXPR_ARG (exp, 0),
-                                         CALL_EXPR_ARG (exp, 1),
-                                         CALL_EXPR_ARG (exp, 2));
-      if (result)
-       return expand_expr (result, target, mode, EXPAND_NORMAL);
-    }
 
   /* If c_strlen can determine an expression for one of the string
      lengths, and it doesn't have side effects, then emit cmpstrnsi
@@ -4462,9 +4394,9 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
     tree arg2 = CALL_EXPR_ARG (exp, 1);
     tree arg3 = CALL_EXPR_ARG (exp, 2);
 
-    int arg1_align
+    unsigned int arg1_align
       = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
-    int arg2_align
+    unsigned int arg2_align
       = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
     enum machine_mode insn_mode
       = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
@@ -4547,138 +4479,23 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
     /* Expand the library call ourselves using a stabilized argument
        list to avoid re-evaluating the function's arguments twice.  */
     fndecl = get_callee_fndecl (exp);
-    fn = build_call_expr (fndecl, 3, arg1, arg2, len);
-    if (TREE_CODE (fn) == CALL_EXPR)
-      CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
+    fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 3,
+                               arg1, arg2, len);
+    gcc_assert (TREE_CODE (fn) == CALL_EXPR);
+    CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
     return expand_call (fn, target, target == const0_rtx);
   }
 #endif
   return NULL_RTX;
 }
 
-/* Expand expression EXP, which is a call to the strcat builtin.
-   Return NULL_RTX if we failed the caller should emit a normal call,
-   otherwise try to get the result in TARGET, if convenient.  */
+/* Expand a call to __builtin_saveregs, generating the result in TARGET,
+   if that's convenient.  */
 
-static rtx
-expand_builtin_strcat (tree fndecl, tree exp, rtx target, enum machine_mode mode)
+rtx
+expand_builtin_saveregs (void)
 {
-  location_t loc = EXPR_LOCATION (exp);
-
-  if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
-    return NULL_RTX;
-  else
-    {
-      tree dst = CALL_EXPR_ARG (exp, 0);
-      tree src = CALL_EXPR_ARG (exp, 1);
-      const char *p = c_getstr (src);
-
-      /* If the string length is zero, return the dst parameter.  */
-      if (p && *p == '\0')
-       return expand_expr (dst, target, mode, EXPAND_NORMAL);
-
-      if (optimize_insn_for_speed_p ())
-       {
-         /* See if we can store by pieces into (dst + strlen(dst)).  */
-         tree newsrc, newdst,
-           strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN];
-         rtx insns;
-
-         /* Stabilize the argument list.  */
-         newsrc = builtin_save_expr (src);
-         dst = builtin_save_expr (dst);
-
-         start_sequence ();
-
-         /* Create strlen (dst).  */
-         newdst = build_call_expr (strlen_fn, 1, dst);
-         /* Create (dst p+ strlen (dst)).  */
-
-         newdst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
-                               TREE_TYPE (dst), dst, newdst);
-         newdst = builtin_save_expr (newdst);
-
-         if (!expand_builtin_strcpy_args (fndecl, newdst, newsrc, target, mode))
-           {
-             end_sequence (); /* Stop sequence.  */
-             return NULL_RTX;
-           }
-
-         /* Output the entire sequence.  */
-         insns = get_insns ();
-         end_sequence ();
-         emit_insn (insns);
-
-         return expand_expr (dst, target, mode, EXPAND_NORMAL);
-       }
-
-      return NULL_RTX;
-    }
-}
-
-/* Expand expression EXP, which is a call to the strncat builtin.
-   Return NULL_RTX if we failed the caller should emit a normal call,
-   otherwise try to get the result in TARGET, if convenient.  */
-
-static rtx
-expand_builtin_strncat (tree exp, rtx target, enum machine_mode mode)
-{
-  if (validate_arglist (exp,
-                       POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
-    {
-      tree result = fold_builtin_strncat (EXPR_LOCATION (exp),
-                                         CALL_EXPR_ARG (exp, 0),
-                                         CALL_EXPR_ARG (exp, 1),
-                                         CALL_EXPR_ARG (exp, 2));
-      if (result)
-       return expand_expr (result, target, mode, EXPAND_NORMAL);
-    }
-  return NULL_RTX;
-}
-
-/* Expand expression EXP, which is a call to the strspn builtin.
-   Return NULL_RTX if we failed the caller should emit a normal call,
-   otherwise try to get the result in TARGET, if convenient.  */
-
-static rtx
-expand_builtin_strspn (tree exp, rtx target, enum machine_mode mode)
-{
-  if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
-    {
-      tree result = fold_builtin_strspn (EXPR_LOCATION (exp),
-                                        CALL_EXPR_ARG (exp, 0),
-                                        CALL_EXPR_ARG (exp, 1));
-      if (result)
-       return expand_expr (result, target, mode, EXPAND_NORMAL);
-    }
-  return NULL_RTX;
-}
-
-/* Expand expression EXP, which is a call to the strcspn builtin.
-   Return NULL_RTX if we failed the caller should emit a normal call,
-   otherwise try to get the result in TARGET, if convenient.  */
-
-static rtx
-expand_builtin_strcspn (tree exp, rtx target, enum machine_mode mode)
-{
-  if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
-    {
-      tree result = fold_builtin_strcspn (EXPR_LOCATION (exp),
-                                         CALL_EXPR_ARG (exp, 0),
-                                         CALL_EXPR_ARG (exp, 1));
-      if (result)
-       return expand_expr (result, target, mode, EXPAND_NORMAL);
-    }
-  return NULL_RTX;
-}
-
-/* Expand a call to __builtin_saveregs, generating the result in TARGET,
-   if that's convenient.  */
-
-rtx
-expand_builtin_saveregs (void)
-{
-  rtx val, seq;
+  rtx val, seq;
 
   /* Don't do __builtin_saveregs more than once in a function.
      Save the result of the first call and reuse it.  */
@@ -4709,38 +4526,6 @@ expand_builtin_saveregs (void)
   return val;
 }
 
-/* __builtin_args_info (N) returns word N of the arg space info
-   for the current function.  The number and meanings of words
-   is controlled by the definition of CUMULATIVE_ARGS.  */
-
-static rtx
-expand_builtin_args_info (tree exp)
-{
-  int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
-  int *word_ptr = (int *) &crtl->args.info;
-
-  gcc_assert (sizeof (CUMULATIVE_ARGS) % sizeof (int) == 0);
-
-  if (call_expr_nargs (exp) != 0)
-    {
-      if (!host_integerp (CALL_EXPR_ARG (exp, 0), 0))
-       error ("argument of %<__builtin_args_info%> must be constant");
-      else
-       {
-         HOST_WIDE_INT wordnum = tree_low_cst (CALL_EXPR_ARG (exp, 0), 0);
-
-         if (wordnum < 0 || wordnum >= nwords)
-           error ("argument of %<__builtin_args_info%> out of range");
-         else
-           return GEN_INT (word_ptr[wordnum]);
-       }
-    }
-  else
-    error ("missing argument in %<__builtin_args_info%>");
-
-  return const0_rtx;
-}
-
 /* Expand a call to __builtin_next_arg.  */
 
 static rtx
@@ -4762,7 +4547,10 @@ stabilize_va_list_loc (location_t loc, tree valist, int needs_lvalue)
 {
   tree vatype = targetm.canonical_va_list_type (TREE_TYPE (valist));
 
-  gcc_assert (vatype != NULL_TREE);
+  /* The current way of determining the type of valist is completely
+     bogus.  We should have the information on the va builtin instead.  */
+  if (!vatype)
+    vatype = targetm.fn_abi_va_list (cfun->decl);
 
   if (TREE_CODE (vatype) == ARRAY_TYPE)
     {
@@ -4781,21 +4569,21 @@ stabilize_va_list_loc (location_t loc, tree valist, int needs_lvalue)
     }
   else
     {
-      tree pt;
+      tree pt = build_pointer_type (vatype);
 
       if (! needs_lvalue)
        {
          if (! TREE_SIDE_EFFECTS (valist))
            return valist;
 
-         pt = build_pointer_type (vatype);
          valist = fold_build1_loc (loc, ADDR_EXPR, pt, valist);
          TREE_SIDE_EFFECTS (valist) = 1;
        }
 
       if (TREE_SIDE_EFFECTS (valist))
        valist = save_expr (valist);
-      valist = build_fold_indirect_ref_loc (loc, valist);
+      valist = fold_build2_loc (loc, MEM_REF,
+                               vatype, valist, build_int_cst (pt, 0));
     }
 
   return valist;
@@ -4914,7 +4702,7 @@ std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
     type = build_pointer_type (type);
 
   align = PARM_BOUNDARY / BITS_PER_UNIT;
-  boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type);
+  boundary = targetm.calls.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
@@ -5012,7 +4800,7 @@ static tree
 dummy_object (tree type)
 {
   tree t = build_int_cst (build_pointer_type (type), 0);
-  return build1 (INDIRECT_REF, type, t);
+  return build2 (MEM_REF, type, t, t);
 }
 
 /* Gimplify __builtin_va_arg, aka VA_ARG_EXPR, which is not really a
@@ -5104,7 +4892,6 @@ gimplify_va_arg_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
        return GS_ALL_DONE;
 
       *expr_p = targetm.gimplify_va_arg_expr (valist, type, pre_p, post_p);
-      SET_EXPR_LOCATION (*expr_p, loc);
       return GS_OK;
     }
 }
@@ -5223,18 +5010,18 @@ expand_builtin_frame_address (tree fndecl, tree exp)
     }
 }
 
-/* Expand EXP, a call to the alloca builtin.  Return NULL_RTX if
-   we failed and the caller should emit a normal call, otherwise try to get
-   the result in TARGET, if convenient.  */
+/* Expand EXP, a call to the alloca builtin.  Return NULL_RTX if we
+   failed and the caller should emit a normal call.  CANNOT_ACCUMULATE
+   is the same as for allocate_dynamic_stack_space.  */
 
 static rtx
-expand_builtin_alloca (tree exp, rtx target)
+expand_builtin_alloca (tree exp, bool cannot_accumulate)
 {
   rtx op0;
   rtx result;
 
   /* Emit normal call if marked not-inlineable.  */
-  if (CALL_CANNOT_INLINE_P (exp)) 
+  if (CALL_CANNOT_INLINE_P (exp))
     return NULL_RTX;
 
   if (!validate_arglist (exp, INTEGER_TYPE, VOID_TYPE))
@@ -5244,7 +5031,8 @@ expand_builtin_alloca (tree exp, rtx target)
   op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
 
   /* Allocate the desired space.  */
-  result = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
+  result = allocate_dynamic_stack_space (op0, 0, BIGGEST_ALIGNMENT,
+                                        cannot_accumulate);
   result = convert_memory_address (ptr_mode, result);
 
   return result;
@@ -5289,7 +5077,10 @@ 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,
+  op0 = expand_expr (CALL_EXPR_ARG (exp, 0),
+                    (subtarget
+                     && (TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 0)))
+                         == GET_MODE (subtarget))) ? subtarget : NULL_RTX,
                     VOIDmode, EXPAND_NORMAL);
   /* Compute op, into TARGET if possible.
      Set TARGET to wherever the result comes back.  */
@@ -5300,44 +5091,23 @@ expand_builtin_unop (enum machine_mode target_mode, tree exp, rtx target,
   return convert_to_mode (target_mode, target, 0);
 }
 
-/* If the string passed to fputs is a constant and is one character
-   long, we attempt to transform this call into __builtin_fputc().  */
-
-static rtx
-expand_builtin_fputs (tree exp, rtx target, bool unlocked)
-{
-  /* Verify the arguments in the original call.  */
-  if (validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
-    {
-      tree result = fold_builtin_fputs (EXPR_LOCATION (exp),
-                                       CALL_EXPR_ARG (exp, 0),
-                                       CALL_EXPR_ARG (exp, 1),
-                                       (target == const0_rtx),
-                                       unlocked, NULL_TREE);
-      if (result)
-       return expand_expr (result, target, VOIDmode, EXPAND_NORMAL);
-    }
-  return NULL_RTX;
-}
-
-/* Expand a call to __builtin_expect.  We just return our argument 
+/* Expand a call to __builtin_expect.  We just return our argument
    as the builtin_expect semantic should've been already executed by
    tree branch prediction pass. */
 
 static rtx
 expand_builtin_expect (tree exp, rtx target)
 {
-  tree arg, c;
+  tree arg;
 
   if (call_expr_nargs (exp) < 2)
     return const0_rtx;
   arg = CALL_EXPR_ARG (exp, 0);
-  c = CALL_EXPR_ARG (exp, 1);
 
   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
-             || optimize == 0 || errorcount || sorrycount);
+             || optimize == 0 || seen_error ());
   return target;
 }
 
@@ -5433,286 +5203,6 @@ build_string_literal (int len, const char *str)
   return t;
 }
 
-/* Expand EXP, a call to printf or printf_unlocked.
-   Return NULL_RTX if a normal call should be emitted rather than transforming
-   the function inline.  If convenient, the result should be placed in
-   TARGET with mode MODE.  UNLOCKED indicates this is a printf_unlocked
-   call.  */
-static rtx
-expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
-                      bool unlocked)
-{
-  /* If we're using an unlocked function, assume the other unlocked
-     functions exist explicitly.  */
-  tree const fn_putchar = unlocked ? built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED]
-    : implicit_built_in_decls[BUILT_IN_PUTCHAR];
-  tree const fn_puts = unlocked ? built_in_decls[BUILT_IN_PUTS_UNLOCKED]
-    : implicit_built_in_decls[BUILT_IN_PUTS];
-  const char *fmt_str;
-  tree fn = 0;
-  tree fmt, arg;
-  int nargs = call_expr_nargs (exp);
-
-  /* If the return value is used, don't do the transformation.  */
-  if (target != const0_rtx)
-    return NULL_RTX;
-
-  /* Verify the required arguments in the original call.  */
-  if (nargs == 0)
-    return NULL_RTX;
-  fmt = CALL_EXPR_ARG (exp, 0);
-  if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
-    return NULL_RTX;
-
-  /* Check whether the format is a literal string constant.  */
-  fmt_str = c_getstr (fmt);
-  if (fmt_str == NULL)
-    return NULL_RTX;
-
-  if (!init_target_chars ())
-    return NULL_RTX;
-
-  /* If the format specifier was "%s\n", call __builtin_puts(arg).  */
-  if (strcmp (fmt_str, target_percent_s_newline) == 0)
-    {
-      if ((nargs != 2)
-         || ! POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_ARG (exp, 1))))
-       return NULL_RTX;
-      if (fn_puts)
-       fn = build_call_expr (fn_puts, 1, CALL_EXPR_ARG (exp, 1));
-    }
-  /* If the format specifier was "%c", call __builtin_putchar(arg).  */
-  else if (strcmp (fmt_str, target_percent_c) == 0)
-    {
-      if ((nargs != 2)
-         || TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1))) != INTEGER_TYPE)
-       return NULL_RTX;
-      if (fn_putchar)
-       fn = build_call_expr (fn_putchar, 1, CALL_EXPR_ARG (exp, 1));
-    }
-  else
-    {
-      /* We can't handle anything else with % args or %% ... yet.  */
-      if (strchr (fmt_str, target_percent))
-       return NULL_RTX;
-
-      if (nargs > 1)
-       return NULL_RTX;
-
-      /* If the format specifier was "", printf does nothing.  */
-      if (fmt_str[0] == '\0')
-       return const0_rtx;
-      /* If the format specifier has length of 1, call putchar.  */
-      if (fmt_str[1] == '\0')
-       {
-         /* Given printf("c"), (where c is any one character,)
-            convert "c"[0] to an int and pass that to the replacement
-            function.  */
-         arg = build_int_cst (NULL_TREE, fmt_str[0]);
-         if (fn_putchar)
-           fn = build_call_expr (fn_putchar, 1, arg);
-       }
-      else
-       {
-         /* If the format specifier was "string\n", call puts("string").  */
-         size_t len = strlen (fmt_str);
-         if ((unsigned char)fmt_str[len - 1] == target_newline)
-           {
-             /* Create a NUL-terminated string that's one char shorter
-                than the original, stripping off the trailing '\n'.  */
-             char *newstr = XALLOCAVEC (char, len);
-             memcpy (newstr, fmt_str, len - 1);
-             newstr[len - 1] = 0;
-             arg = build_string_literal (len, newstr);
-             if (fn_puts)
-               fn = build_call_expr (fn_puts, 1, arg);
-           }
-         else
-           /* We'd like to arrange to call fputs(string,stdout) here,
-              but we need stdout and don't have a way to get it yet.  */
-           return NULL_RTX;
-       }
-    }
-
-  if (!fn)
-    return NULL_RTX;
-  if (TREE_CODE (fn) == CALL_EXPR)
-    CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
-  return expand_expr (fn, target, mode, EXPAND_NORMAL);
-}
-
-/* Expand EXP, a call to fprintf or fprintf_unlocked.
-   Return NULL_RTX if a normal call should be emitted rather than transforming
-   the function inline.  If convenient, the result should be placed in
-   TARGET with mode MODE.  UNLOCKED indicates this is a fprintf_unlocked
-   call.  */
-static rtx
-expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode,
-                       bool unlocked)
-{
-  /* If we're using an unlocked function, assume the other unlocked
-     functions exist explicitly.  */
-  tree const fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
-    : implicit_built_in_decls[BUILT_IN_FPUTC];
-  tree const fn_fputs = unlocked ? built_in_decls[BUILT_IN_FPUTS_UNLOCKED]
-    : implicit_built_in_decls[BUILT_IN_FPUTS];
-  const char *fmt_str;
-  tree fn = 0;
-  tree fmt, fp, arg;
-  int nargs = call_expr_nargs (exp);
-
-  /* If the return value is used, don't do the transformation.  */
-  if (target != const0_rtx)
-    return NULL_RTX;
-
-  /* Verify the required arguments in the original call.  */
-  if (nargs < 2)
-    return NULL_RTX;
-  fp = CALL_EXPR_ARG (exp, 0);
-  if (! POINTER_TYPE_P (TREE_TYPE (fp)))
-    return NULL_RTX;
-  fmt = CALL_EXPR_ARG (exp, 1);
-  if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
-    return NULL_RTX;
-
-  /* Check whether the format is a literal string constant.  */
-  fmt_str = c_getstr (fmt);
-  if (fmt_str == NULL)
-    return NULL_RTX;
-
-  if (!init_target_chars ())
-    return NULL_RTX;
-
-  /* If the format specifier was "%s", call __builtin_fputs(arg,fp).  */
-  if (strcmp (fmt_str, target_percent_s) == 0)
-    {
-      if ((nargs != 3)
-         || ! POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_ARG (exp, 2))))
-       return NULL_RTX;
-      arg = CALL_EXPR_ARG (exp, 2);
-      if (fn_fputs)
-       fn = build_call_expr (fn_fputs, 2, arg, fp);
-    }
-  /* If the format specifier was "%c", call __builtin_fputc(arg,fp).  */
-  else if (strcmp (fmt_str, target_percent_c) == 0)
-    {
-      if ((nargs != 3)
-         || TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (exp, 2))) != INTEGER_TYPE)
-       return NULL_RTX;
-      arg = CALL_EXPR_ARG (exp, 2);
-      if (fn_fputc)
-       fn = build_call_expr (fn_fputc, 2, arg, fp);
-    }
-  else
-    {
-      /* We can't handle anything else with % args or %% ... yet.  */
-      if (strchr (fmt_str, target_percent))
-       return NULL_RTX;
-
-      if (nargs > 2)
-       return NULL_RTX;
-
-      /* If the format specifier was "", fprintf does nothing.  */
-      if (fmt_str[0] == '\0')
-       {
-         /* Evaluate and ignore FILE* argument for side-effects.  */
-         expand_expr (fp, const0_rtx, VOIDmode, EXPAND_NORMAL);
-         return const0_rtx;
-       }
-
-      /* When "string" doesn't contain %, replace all cases of
-        fprintf(stream,string) with fputs(string,stream).  The fputs
-        builtin will take care of special cases like length == 1.  */
-      if (fn_fputs)
-       fn = build_call_expr (fn_fputs, 2, fmt, fp);
-    }
-
-  if (!fn)
-    return NULL_RTX;
-  if (TREE_CODE (fn) == CALL_EXPR)
-    CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
-  return expand_expr (fn, target, mode, EXPAND_NORMAL);
-}
-
-/* Expand a call EXP to sprintf.  Return NULL_RTX if
-   a normal call should be emitted rather than expanding the function
-   inline.  If convenient, the result should be placed in TARGET with
-   mode MODE.  */
-
-static rtx
-expand_builtin_sprintf (tree exp, rtx target, enum machine_mode mode)
-{
-  tree dest, fmt;
-  const char *fmt_str;
-  int nargs = call_expr_nargs (exp);
-
-  /* Verify the required arguments in the original call.  */
-  if (nargs < 2)
-    return NULL_RTX;
-  dest = CALL_EXPR_ARG (exp, 0);
-  if (! POINTER_TYPE_P (TREE_TYPE (dest)))
-    return NULL_RTX;
-  fmt = CALL_EXPR_ARG (exp, 0);
-  if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
-    return NULL_RTX;
-
-  /* Check whether the format is a literal string constant.  */
-  fmt_str = c_getstr (fmt);
-  if (fmt_str == NULL)
-    return NULL_RTX;
-
-  if (!init_target_chars ())
-    return NULL_RTX;
-
-  /* If the format doesn't contain % args or %%, use strcpy.  */
-  if (strchr (fmt_str, target_percent) == 0)
-    {
-      tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
-      tree exp;
-
-      if ((nargs > 2) || ! fn)
-       return NULL_RTX;
-      expand_expr (build_call_expr (fn, 2, dest, fmt),
-                  const0_rtx, VOIDmode, EXPAND_NORMAL);
-      if (target == const0_rtx)
-       return const0_rtx;
-      exp = build_int_cst (NULL_TREE, strlen (fmt_str));
-      return expand_expr (exp, target, mode, EXPAND_NORMAL);
-    }
-  /* If the format is "%s", use strcpy if the result isn't used.  */
-  else if (strcmp (fmt_str, target_percent_s) == 0)
-    {
-      tree fn, arg, len;
-      fn = implicit_built_in_decls[BUILT_IN_STRCPY];
-
-      if (! fn)
-       return NULL_RTX;
-      if (nargs != 3)
-       return NULL_RTX;
-      arg = CALL_EXPR_ARG (exp, 2);
-      if (! POINTER_TYPE_P (TREE_TYPE (arg)))
-       return NULL_RTX;
-
-      if (target != const0_rtx)
-       {
-         len = c_strlen (arg, 1);
-         if (! len || TREE_CODE (len) != INTEGER_CST)
-           return NULL_RTX;
-       }
-      else
-       len = NULL_TREE;
-
-      expand_expr (build_call_expr (fn, 2, dest, arg),
-                  const0_rtx, VOIDmode, EXPAND_NORMAL);
-
-      if (target == const0_rtx)
-       return const0_rtx;
-      return expand_expr (len, target, mode, EXPAND_NORMAL);
-    }
-
-  return NULL_RTX;
-}
-
 /* Expand a call to either the entry or exit function profiler.  */
 
 static rtx
@@ -5819,10 +5309,7 @@ static rtx
 expand_builtin_init_trampoline (tree exp)
 {
   tree t_tramp, t_func, t_chain;
-  rtx r_tramp, r_func, r_chain;
-#ifdef TRAMPOLINE_TEMPLATE
-  rtx blktramp;
-#endif
+  rtx m_tramp, r_tramp, r_chain, tmp;
 
   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE,
                         POINTER_TYPE, VOID_TYPE))
@@ -5833,19 +5320,39 @@ expand_builtin_init_trampoline (tree exp)
   t_chain = CALL_EXPR_ARG (exp, 2);
 
   r_tramp = expand_normal (t_tramp);
-  r_func = expand_normal (t_func);
+  m_tramp = gen_rtx_MEM (BLKmode, r_tramp);
+  MEM_NOTRAP_P (m_tramp) = 1;
+
+  /* The TRAMP argument should be the address of a field within the
+     local function's FRAME decl.  Let's see if we can fill in the
+     to fill in the MEM_ATTRs for this memory.  */
+  if (TREE_CODE (t_tramp) == ADDR_EXPR)
+    set_mem_attributes_minus_bitpos (m_tramp, TREE_OPERAND (t_tramp, 0),
+                                    true, 0);
+
+  tmp = round_trampoline_addr (r_tramp);
+  if (tmp != r_tramp)
+    {
+      m_tramp = change_address (m_tramp, BLKmode, tmp);
+      set_mem_align (m_tramp, TRAMPOLINE_ALIGNMENT);
+      set_mem_size (m_tramp, GEN_INT (TRAMPOLINE_SIZE));
+    }
+
+  /* The FUNC argument should be the address of the nested function.
+     Extract the actual function decl to pass to the hook.  */
+  gcc_assert (TREE_CODE (t_func) == ADDR_EXPR);
+  t_func = TREE_OPERAND (t_func, 0);
+  gcc_assert (TREE_CODE (t_func) == FUNCTION_DECL);
+
   r_chain = expand_normal (t_chain);
 
   /* Generate insns to initialize the trampoline.  */
-  r_tramp = round_trampoline_addr (r_tramp);
-#ifdef TRAMPOLINE_TEMPLATE
-  blktramp = gen_rtx_MEM (BLKmode, r_tramp);
-  set_mem_align (blktramp, TRAMPOLINE_ALIGNMENT);
-  emit_block_move (blktramp, assemble_trampoline_template (),
-                  GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
-#endif
+  targetm.calls.trampoline_init (m_tramp, t_func, r_chain);
+
   trampolines_created = 1;
-  INITIALIZE_TRAMPOLINE (r_tramp, r_func, r_chain);
+
+  warning_at (DECL_SOURCE_LOCATION (t_func), OPT_Wtrampolines,
+              "trampoline generated for nested function %qD", t_func);
 
   return const0_rtx;
 }
@@ -5860,9 +5367,8 @@ expand_builtin_adjust_trampoline (tree exp)
 
   tramp = expand_normal (CALL_EXPR_ARG (exp, 0));
   tramp = round_trampoline_addr (tramp);
-#ifdef TRAMPOLINE_ADJUST_ADDRESS
-  TRAMPOLINE_ADJUST_ADDRESS (tramp);
-#endif
+  if (targetm.calls.trampoline_adjust_address)
+    tramp = targetm.calls.trampoline_adjust_address (tramp);
 
   return tramp;
 }
@@ -5881,7 +5387,6 @@ expand_builtin_signbit (tree exp, rtx target)
 {
   const struct real_format *fmt;
   enum machine_mode fmode, imode, rmode;
-  HOST_WIDE_INT hi, lo;
   tree arg;
   int word, bitpos;
   enum insn_code icode;
@@ -5903,12 +5408,14 @@ expand_builtin_signbit (tree exp, rtx target)
 
   /* Check if the back end provides an insn that handles signbit for the
      argument's mode. */
-  icode = signbit_optab->handlers [(int) fmode].insn_code;
+  icode = optab_handler (signbit_optab, fmode);
   if (icode != CODE_FOR_nothing)
     {
+      rtx last = get_last_insn ();
       target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
-      emit_unop_insn (icode, target, temp, UNKNOWN);
-      return target;
+      if (maybe_emit_unop_insn (icode, target, temp, UNKNOWN))
+       return target;
+      delete_insns_since (last);
     }
 
   /* For floating point formats without a sign bit, implement signbit
@@ -5955,21 +5462,12 @@ expand_builtin_signbit (tree exp, rtx target)
 
   if (bitpos < GET_MODE_BITSIZE (rmode))
     {
-      if (bitpos < HOST_BITS_PER_WIDE_INT)
-       {
-         hi = 0;
-         lo = (HOST_WIDE_INT) 1 << bitpos;
-       }
-      else
-       {
-         hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
-         lo = 0;
-       }
+      double_int mask = double_int_setbit (double_int_zero, bitpos);
 
       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),
+                          immed_double_int_const (mask, rmode),
                           NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
   else
@@ -6051,7 +5549,7 @@ expand_builtin_fork_or_exec (tree fn, tree exp, rtx target, int ignore)
   call = rewrite_call_expr (EXPR_LOCATION (exp), exp, 0, decl, 0);
   return expand_call (call, target, ignore);
  }
-  
+
 
 \f
 /* Reconstitute a mode for a __sync intrinsic operation.  Since the type of
@@ -6078,14 +5576,17 @@ get_builtin_sync_mem (tree loc, enum machine_mode mode)
 {
   rtx addr, mem;
 
-  addr = expand_expr (loc, NULL_RTX, Pmode, EXPAND_SUM);
+  addr = expand_expr (loc, NULL_RTX, ptr_mode, EXPAND_SUM);
+  addr = convert_memory_address (Pmode, addr);
 
   /* 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
      satisfy the full barrier semantics of the intrinsic.  */
   mem = validize_mem (gen_rtx_MEM (mode, addr));
 
-  set_mem_align (mem, get_pointer_alignment (loc, BIGGEST_ALIGNMENT));
+  /* The alignment needs to be at least according to that of the mode.  */
+  set_mem_align (mem, MAX (GET_MODE_ALIGNMENT (mode),
+                          get_pointer_alignment (loc, BIGGEST_ALIGNMENT)));
   set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER);
   MEM_VOLATILE_P (mem) = 1;
 
@@ -6211,7 +5712,7 @@ expand_builtin_compare_and_swap (enum machine_mode mode, tree exp,
 /* Expand the __sync_lock_test_and_set intrinsic.  Note that the most
    general form is actually an atomic exchange, and some targets only
    support a reduced form with the second argument being a constant 1.
-   EXP is the CALL_EXPR; TARGET is an optional place for us to store 
+   EXP is the CALL_EXPR; TARGET is an optional place for us to store
    the results.  */
 
 static rtx
@@ -6239,7 +5740,8 @@ expand_builtin_lock_test_and_set (enum machine_mode mode, tree exp,
 static void
 expand_builtin_synchronize (void)
 {
-  tree x;
+  gimple x;
+  VEC (tree, gc) *v_clobbers;
 
 #ifdef HAVE_memory_barrier
   if (HAVE_memory_barrier)
@@ -6257,10 +5759,12 @@ expand_builtin_synchronize (void)
 
   /* 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,
-             tree_cons (NULL, build_string (6, "memory"), NULL));
-  ASM_VOLATILE_P (x) = 1;
-  expand_asm_expr (x);
+  v_clobbers = VEC_alloc (tree, gc, 1);
+  VEC_quick_push (tree, v_clobbers,
+                 tree_cons (NULL, build_string (6, "memory"), NULL));
+  x = gimple_build_asm_vec ("", NULL, NULL, v_clobbers, NULL);
+  gimple_asm_set_volatile (x, true);
+  expand_asm_stmt (x);
 }
 
 /* Expand the __sync_lock_release intrinsic.  EXP is the CALL_EXPR.  */
@@ -6276,7 +5780,7 @@ expand_builtin_lock_release (enum machine_mode mode, tree exp)
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
 
   /* If there is an explicit operation in the md file, use it.  */
-  icode = sync_lock_release[mode];
+  icode = direct_optab_handler (sync_lock_release_optab, mode);
   if (icode != CODE_FOR_nothing)
     {
       if (!insn_data[icode].operand[1].predicate (val, mode))
@@ -6309,6 +5813,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
   tree fndecl = get_callee_fndecl (exp);
   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
   enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp));
+  int flags;
 
   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
     return targetm.expand_builtin (exp, target, subtarget, mode, ignore);
@@ -6331,7 +5836,8 @@ 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_PURE_P (fndecl) || TREE_READONLY (fndecl)))
+      && ((flags = flags_from_decl_or_type (fndecl)) & (ECF_CONST | ECF_PURE))
+      && !(flags & ECF_LOOPING_CONST_OR_PURE))
     {
       bool volatilep = false;
       tree arg;
@@ -6402,6 +5908,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
+    CASE_FLT_FN (BUILT_IN_FMA):
+      target = expand_builtin_mathfn_ternary (exp, target, subtarget);
+      if (target)
+       return target;
+      break;
+
     CASE_FLT_FN (BUILT_IN_ILOGB):
       if (! flag_unsafe_math_optimizations)
        break;
@@ -6409,7 +5921,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     CASE_FLT_FN (BUILT_IN_FINITE):
     case BUILT_IN_ISFINITE:
     case BUILT_IN_ISNORMAL:
-      target = expand_builtin_interclass_mathfn (exp, target, subtarget);
+      target = expand_builtin_interclass_mathfn (exp, target);
       if (target)
        return target;
       break;
@@ -6439,7 +5951,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       break;
 
     CASE_FLT_FN (BUILT_IN_POWI):
-      target = expand_builtin_powi (exp, target, subtarget);
+      target = expand_builtin_powi (exp, target);
       if (target)
        return target;
       break;
@@ -6461,7 +5973,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       break;
 
     CASE_FLT_FN (BUILT_IN_CEXPI):
-      target = expand_builtin_cexpi (exp, target, subtarget);
+      target = expand_builtin_cexpi (exp, target);
       gcc_assert (target);
       return target;
 
@@ -6523,9 +6035,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_SAVEREGS:
       return expand_builtin_saveregs ();
 
-    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.  */
@@ -6571,7 +6080,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
 
     case BUILT_IN_ALLOCA:
-      target = expand_builtin_alloca (exp, target);
+      /* If the allocation stems from the declaration of a variable-sized
+        object, it cannot accumulate.  */
+      target = expand_builtin_alloca (exp, ALLOCA_FOR_VAR_P (exp));
       if (target)
        return target;
       break;
@@ -6638,13 +6149,13 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       break;
 
     case BUILT_IN_STRCPY:
-      target = expand_builtin_strcpy (fndecl, exp, target, mode);
+      target = expand_builtin_strcpy (exp, target);
       if (target)
        return target;
       break;
 
     case BUILT_IN_STRNCPY:
-      target = expand_builtin_strncpy (exp, target, mode);
+      target = expand_builtin_strncpy (exp, target);
       if (target)
        return target;
       break;
@@ -6655,58 +6166,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
-    case BUILT_IN_STRCAT:
-      target = expand_builtin_strcat (fndecl, exp, target, mode);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_STRNCAT:
-      target = expand_builtin_strncat (exp, target, mode);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_STRSPN:
-      target = expand_builtin_strspn (exp, target, mode);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_STRCSPN:
-      target = expand_builtin_strcspn (exp, target, mode);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_STRSTR:
-      target = expand_builtin_strstr (exp, target, mode);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_STRPBRK:
-      target = expand_builtin_strpbrk (exp, target, mode);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_INDEX:
-    case BUILT_IN_STRCHR:
-      target = expand_builtin_strchr (exp, target, mode);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_RINDEX:
-    case BUILT_IN_STRRCHR:
-      target = expand_builtin_strrchr (exp, target, mode);
-      if (target)
-       return target;
-      break;
-
     case BUILT_IN_MEMCPY:
-      target = expand_builtin_memcpy (exp, target, mode);
+      target = expand_builtin_memcpy (exp, target);
       if (target)
        return target;
       break;
@@ -6717,18 +6178,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
-    case BUILT_IN_MEMMOVE:
-      target = expand_builtin_memmove (exp, target, mode, ignore);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_BCOPY:
-      target = expand_builtin_bcopy (exp, ignore);
-      if (target)
-       return target;
-      break;
-
     case BUILT_IN_MEMSET:
       target = expand_builtin_memset (exp, target, mode);
       if (target)
@@ -6742,7 +6191,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       break;
 
     case BUILT_IN_STRCMP:
-      target = expand_builtin_strcmp (exp, target, mode);
+      target = expand_builtin_strcmp (exp, target);
       if (target)
        return target;
       break;
@@ -6753,12 +6202,6 @@ 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);
@@ -6867,47 +6310,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       expand_builtin_unreachable ();
       return const0_rtx;
 
-    case BUILT_IN_PRINTF:
-      target = expand_builtin_printf (exp, target, mode, false);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_PRINTF_UNLOCKED:
-      target = expand_builtin_printf (exp, target, mode, true);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_FPUTS:
-      target = expand_builtin_fputs (exp, target, false);
-      if (target)
-       return target;
-      break;
-    case BUILT_IN_FPUTS_UNLOCKED:
-      target = expand_builtin_fputs (exp, target, true);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_FPRINTF:
-      target = expand_builtin_fprintf (exp, target, mode, false);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_FPRINTF_UNLOCKED:
-      target = expand_builtin_fprintf (exp, target, mode, true);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_SPRINTF:
-      target = expand_builtin_sprintf (exp, target, mode);
-      if (target)
-       return target;
-      break;
-
     CASE_FLT_FN (BUILT_IN_SIGNBIT):
     case BUILT_IN_SIGNBITD32:
     case BUILT_IN_SIGNBITD64:
@@ -6944,6 +6346,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
 #endif
     case BUILT_IN_EXTEND_POINTER:
       return expand_builtin_extend_pointer (CALL_EXPR_ARG (exp, 0));
+    case BUILT_IN_EH_POINTER:
+      return expand_builtin_eh_pointer (exp);
+    case BUILT_IN_EH_FILTER:
+      return expand_builtin_eh_filter (exp);
+    case BUILT_IN_EH_COPY_VALUES:
+      return expand_builtin_eh_copy_values (exp);
 
     case BUILT_IN_VA_START:
       return expand_builtin_va_start (exp);
@@ -7254,7 +6662,7 @@ builtin_mathfn_code (const_tree t)
 
       if (! more_const_call_expr_args_p (&iter))
        return END_BUILTINS;
-      
+
       arg = next_const_call_expr_arg (&iter);
       argtype = TREE_TYPE (arg);
 
@@ -7436,7 +6844,7 @@ fold_builtin_classify_type (tree arg)
 /* Fold a call to __builtin_strlen with argument ARG.  */
 
 static tree
-fold_builtin_strlen (location_t loc, tree arg)
+fold_builtin_strlen (location_t loc, tree type, tree arg)
 {
   if (!validate_arg (arg, POINTER_TYPE))
     return NULL_TREE;
@@ -7445,12 +6853,7 @@ fold_builtin_strlen (location_t loc, tree arg)
       tree len = c_strlen (arg, 0);
 
       if (len)
-       {
-         /* Convert from the internal "sizetype" type to "size_t".  */
-         if (size_type_node)
-           len = fold_convert_loc (loc, size_type_node, len);
-         return len;
-       }
+       return fold_convert_loc (loc, type, len);
 
       return NULL_TREE;
     }
@@ -7686,7 +7089,7 @@ fold_builtin_cabs (location_t loc, tree arg, tree type, tree fndecl)
 {
   tree res;
 
-  if (TREE_CODE (TREE_TYPE (arg)) != COMPLEX_TYPE
+  if (!validate_arg (arg, COMPLEX_TYPE)
       || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
     return NULL_TREE;
 
@@ -7695,12 +7098,12 @@ fold_builtin_cabs (location_t loc, tree arg, tree type, tree fndecl)
       && (res = do_mpfr_arg2 (TREE_REALPART (arg), TREE_IMAGPART (arg),
                              type, mpfr_hypot)))
     return res;
-  
+
   if (TREE_CODE (arg) == COMPLEX_EXPR)
     {
       tree real = TREE_OPERAND (arg, 0);
       tree imag = TREE_OPERAND (arg, 1);
-      
+
       /* If either part is zero, cabs is fabs of the other.  */
       if (real_zerop (real))
        return fold_build1_loc (loc, ABS_EXPR, type, imag);
@@ -7737,20 +7140,91 @@ fold_builtin_cabs (location_t loc, tree arg, tree type, tree fndecl)
 
          arg = builtin_save_expr (arg);
 
-         rpart = fold_build1_loc (loc, REALPART_EXPR, type, arg);
-         ipart = fold_build1_loc (loc, IMAGPART_EXPR, type, arg);
+         rpart = fold_build1_loc (loc, REALPART_EXPR, type, arg);
+         ipart = fold_build1_loc (loc, IMAGPART_EXPR, type, arg);
+
+         rpart = builtin_save_expr (rpart);
+         ipart = builtin_save_expr (ipart);
+
+         result = fold_build2_loc (loc, PLUS_EXPR, type,
+                               fold_build2_loc (loc, MULT_EXPR, type,
+                                            rpart, rpart),
+                               fold_build2_loc (loc, MULT_EXPR, type,
+                                            ipart, ipart));
+
+         return build_call_expr_loc (loc, sqrtfn, 1, result);
+       }
+    }
+
+  return NULL_TREE;
+}
+
+/* Build a complex (inf +- 0i) for the result of cproj.  TYPE is the
+   complex tree type of the result.  If NEG is true, the imaginary
+   zero is negative.  */
+
+static tree
+build_complex_cproj (tree type, bool neg)
+{
+  REAL_VALUE_TYPE rinf, rzero = dconst0;
+  
+  real_inf (&rinf);
+  rzero.sign = neg;
+  return build_complex (type, build_real (TREE_TYPE (type), rinf),
+                       build_real (TREE_TYPE (type), rzero));
+}
+
+/* Fold call to builtin cproj, cprojf or cprojl with argument ARG.  TYPE is the
+   return type.  Return NULL_TREE if no simplification can be made.  */
+
+static tree
+fold_builtin_cproj (location_t loc, tree arg, tree type)
+{
+  if (!validate_arg (arg, COMPLEX_TYPE)
+      || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
+    return NULL_TREE;
 
-         rpart = builtin_save_expr (rpart);
-         ipart = builtin_save_expr (ipart);
+  /* If there are no infinities, return arg.  */
+  if (! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (type))))
+    return non_lvalue_loc (loc, arg);
 
-         result = fold_build2_loc (loc, PLUS_EXPR, type,
-                               fold_build2_loc (loc, MULT_EXPR, type,
-                                            rpart, rpart),
-                               fold_build2_loc (loc, MULT_EXPR, type,
-                                            ipart, ipart));
+  /* Calculate the result when the argument is a constant.  */
+  if (TREE_CODE (arg) == COMPLEX_CST)
+    {
+      const REAL_VALUE_TYPE *real = TREE_REAL_CST_PTR (TREE_REALPART (arg));
+      const REAL_VALUE_TYPE *imag = TREE_REAL_CST_PTR (TREE_IMAGPART (arg));
+      
+      if (real_isinf (real) || real_isinf (imag))
+       return build_complex_cproj (type, imag->sign);
+      else
+       return arg;
+    }
+  else if (TREE_CODE (arg) == COMPLEX_EXPR)
+    {
+      tree real = TREE_OPERAND (arg, 0);
+      tree imag = TREE_OPERAND (arg, 1);
 
-         return build_call_expr_loc (loc, sqrtfn, 1, result);
-       }
+      STRIP_NOPS (real);
+      STRIP_NOPS (imag);
+      
+      /* If the real part is inf and the imag part is known to be
+        nonnegative, return (inf + 0i).  Remember side-effects are
+        possible in the imag part.  */
+      if (TREE_CODE (real) == REAL_CST
+         && real_isinf (TREE_REAL_CST_PTR (real))
+         && tree_expr_nonnegative_p (imag))
+       return omit_one_operand_loc (loc, type,
+                                    build_complex_cproj (type, false),
+                                    arg);
+      
+      /* If the imag part is inf, return (inf+I*copysign(0,imag)).
+        Remember side-effects are possible in the real part.  */
+      if (TREE_CODE (imag) == REAL_CST
+         && real_isinf (TREE_REAL_CST_PTR (imag)))
+       return
+         omit_one_operand_loc (loc, type,
+                               build_complex_cproj (type, TREE_REAL_CST_PTR
+                                                    (imag)->sign), arg);
     }
 
   return NULL_TREE;
@@ -7772,7 +7246,7 @@ fold_builtin_sqrt (location_t loc, tree arg, tree type)
   /* Calculate the result when the argument is a constant.  */
   if ((res = do_mpfr_arg1 (arg, type, mpfr_sqrt, &dconst0, NULL, true)))
     return res;
-  
+
   /* Optimize sqrt(expN(x)) = expN(x*0.5).  */
   fcode = builtin_mathfn_code (arg);
   if (flag_unsafe_math_optimizations && BUILTIN_EXPONENT_P (fcode))
@@ -7901,7 +7375,7 @@ fold_builtin_cbrt (location_t loc, tree arg, tree type)
        }
 
       /* Optimize cbrt(pow(x,y)) -> pow(x,y/3) iff x is nonnegative.  */
-      if (fcode == BUILT_IN_POW 
+      if (fcode == BUILT_IN_POW
           || fcode == BUILT_IN_POWF
          || fcode == BUILT_IN_POWL)
        {
@@ -7937,7 +7411,7 @@ fold_builtin_cos (location_t loc,
   /* Calculate the result when the argument is a constant.  */
   if ((res = do_mpfr_arg1 (arg, type, mpfr_cos, NULL, NULL, 0)))
     return res;
-  
+
   /* Optimize cos(-x) into cos (x).  */
   if ((narg = fold_strip_sign_ops (arg)))
     return build_call_expr_loc (loc, fndecl, 1, narg);
@@ -7958,12 +7432,12 @@ fold_builtin_cosh (location_t loc, tree arg, tree type, tree fndecl)
       /* Calculate the result when the argument is a constant.  */
       if ((res = do_mpfr_arg1 (arg, type, mpfr_cosh, NULL, NULL, 0)))
        return res;
-  
+
       /* Optimize cosh(-x) into cosh (x).  */
       if ((narg = fold_strip_sign_ops (arg)))
        return build_call_expr_loc (loc, fndecl, 1, narg);
     }
-  
+
   return NULL_TREE;
 }
 
@@ -7972,21 +7446,18 @@ fold_builtin_cosh (location_t loc, tree arg, tree type, tree fndecl)
    NULL_TREE if no simplification can be made.  */
 
 static tree
-fold_builtin_ccos (location_t loc,
-                  tree arg, tree type ATTRIBUTE_UNUSED, tree fndecl,
-                  bool hyper ATTRIBUTE_UNUSED)
+fold_builtin_ccos (location_t loc, tree arg, tree type, tree fndecl,
+                  bool hyper)
 {
   if (validate_arg (arg, COMPLEX_TYPE)
       && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == REAL_TYPE)
     {
       tree tmp;
 
-#ifdef HAVE_mpc
       /* Calculate the result when the argument is a constant.  */
       if ((tmp = do_mpc_arg1 (arg, type, (hyper ? mpc_cosh : mpc_cos))))
        return tmp;
-#endif
-  
+
       /* Optimize fn(-x) into fn(x).  */
       if ((tmp = fold_strip_sign_ops (arg)))
        return build_call_expr_loc (loc, fndecl, 1, tmp);
@@ -8010,7 +7481,7 @@ fold_builtin_tan (tree arg, tree type)
   /* Calculate the result when the argument is a constant.  */
   if ((res = do_mpfr_arg1 (arg, type, mpfr_tan, NULL, NULL, 0)))
     return res;
-  
+
   /* Optimize tan(atan(x)) = x.  */
   fcode = builtin_mathfn_code (arg);
   if (flag_unsafe_math_optimizations
@@ -8070,20 +7541,16 @@ fold_builtin_cexp (location_t loc, tree arg0, tree type)
 {
   tree rtype;
   tree realp, imagp, ifn;
-#ifdef HAVE_mpc
   tree res;
-#endif
 
   if (!validate_arg (arg0, COMPLEX_TYPE)
-      && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
+      || TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) != REAL_TYPE)
     return NULL_TREE;
 
-#ifdef HAVE_mpc
   /* Calculate the result when the argument is a constant.  */
   if ((res = do_mpc_arg1 (arg0, type, mpc_exp)))
     return res;
-#endif
-  
+
   rtype = TREE_TYPE (TREE_TYPE (arg0));
 
   /* In case we can figure out the real part of arg0 and it is constant zero
@@ -8269,8 +7736,7 @@ fold_builtin_int_roundingfn (location_t loc, tree fndecl, tree arg)
        {
          tree itype = TREE_TYPE (TREE_TYPE (fndecl));
          tree ftype = TREE_TYPE (arg);
-         unsigned HOST_WIDE_INT lo2;
-         HOST_WIDE_INT hi, lo;
+         double_int val;
          REAL_VALUE_TYPE r;
 
          switch (DECL_FUNCTION_CODE (fndecl))
@@ -8294,9 +7760,9 @@ fold_builtin_int_roundingfn (location_t loc, tree fndecl, tree arg)
              gcc_unreachable ();
            }
 
-         REAL_VALUE_TO_INT (&lo, &hi, r);
-         if (!fit_double_type (lo, hi, &lo2, &hi, itype))
-           return build_int_cst_wide (itype, lo2, hi);
+         real_to_integer2 ((HOST_WIDE_INT *)&val.low, &val.high, &r);
+         if (double_int_fits_to_tree_p (itype, val))
+           return double_int_to_tree (itype, val);
        }
     }
 
@@ -8355,9 +7821,9 @@ fold_builtin_bitop (tree fndecl, tree arg)
        {
        CASE_INT_FN (BUILT_IN_FFS):
          if (lo != 0)
-           result = exact_log2 (lo & -lo) + 1;
+           result = ffs_hwi (lo);
          else if (hi != 0)
-           result = HOST_BITS_PER_WIDE_INT + exact_log2 (hi & -hi) + 1;
+           result = HOST_BITS_PER_WIDE_INT + ffs_hwi (hi);
          else
            result = 0;
          break;
@@ -8373,9 +7839,9 @@ fold_builtin_bitop (tree fndecl, tree arg)
 
        CASE_INT_FN (BUILT_IN_CTZ):
          if (lo != 0)
-           result = exact_log2 (lo & -lo);
+           result = ctz_hwi (lo);
          else if (hi != 0)
-           result = HOST_BITS_PER_WIDE_INT + exact_log2 (hi & -hi);
+           result = HOST_BITS_PER_WIDE_INT + ctz_hwi (hi);
          else if (! CTZ_DEFINED_VALUE_AT_ZERO (TYPE_MODE (type), result))
            result = width;
          break;
@@ -8385,7 +7851,7 @@ fold_builtin_bitop (tree fndecl, tree arg)
          while (lo)
            result++, lo &= lo - 1;
          while (hi)
-           result++, hi &= hi - 1;
+           result++, hi &= (unsigned HOST_WIDE_INT) hi - 1;
          break;
 
        CASE_INT_FN (BUILT_IN_PARITY):
@@ -8393,7 +7859,7 @@ fold_builtin_bitop (tree fndecl, tree arg)
          while (lo)
            result++, lo &= lo - 1;
          while (hi)
-           result++, hi &= hi - 1;
+           result++, hi &= (unsigned HOST_WIDE_INT) hi - 1;
          result &= 1;
          break;
 
@@ -8508,7 +7974,7 @@ fold_builtin_logarithm (location_t loc, 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), 
+           x = build_real (type, real_value_truncate (TYPE_MODE (type),
                                                        dconst_e ()));
            exponent = CALL_EXPR_ARG (arg, 0);
            break;
@@ -8575,23 +8041,23 @@ fold_builtin_hypot (location_t loc, tree fndecl,
   /* Calculate the result when the argument is a constant.  */
   if ((res = do_mpfr_arg2 (arg0, arg1, type, mpfr_hypot)))
     return res;
-  
+
   /* If either argument to hypot has a negate or abs, strip that off.
      E.g. hypot(-x,fabs(y)) -> hypot(x,y).  */
   narg0 = fold_strip_sign_ops (arg0);
   narg1 = fold_strip_sign_ops (arg1);
   if (narg0 || narg1)
     {
-      return build_call_expr_loc (loc, fndecl, 2, narg0 ? narg0 : arg0, 
+      return build_call_expr_loc (loc, fndecl, 2, narg0 ? narg0 : arg0,
                              narg1 ? narg1 : arg1);
     }
-  
+
   /* If either argument is zero, hypot is fabs of the other.  */
   if (real_zerop (arg0))
     return fold_build1_loc (loc, ABS_EXPR, type, arg1);
   else if (real_zerop (arg1))
     return fold_build1_loc (loc, ABS_EXPR, type, arg0);
-      
+
   /* hypot(x,x) -> fabs(x)*sqrt(2).  */
   if (flag_unsafe_math_optimizations
       && operand_equal_p (arg0, arg1, OEP_PURE_SAME))
@@ -8741,15 +8207,18 @@ fold_builtin_pow (location_t loc, tree fndecl, tree arg0, tree arg1, tree type)
            }
        }
 
-      /* Optimize pow(pow(x,y),z) = pow(x,y*z).  */
+      /* Optimize pow(pow(x,y),z) = pow(x,y*z) iff x is nonnegative.  */
       if (fcode == BUILT_IN_POW
          || fcode == BUILT_IN_POWF
          || fcode == BUILT_IN_POWL)
        {
          tree arg00 = CALL_EXPR_ARG (arg0, 0);
-         tree arg01 = CALL_EXPR_ARG (arg0, 1);
-         tree narg1 = fold_build2_loc (loc, MULT_EXPR, type, arg01, arg1);
-         return build_call_expr_loc (loc, fndecl, 2, arg00, narg1);
+         if (tree_expr_nonnegative_p (arg00))
+           {
+             tree arg01 = CALL_EXPR_ARG (arg0, 1);
+             tree narg1 = fold_build2_loc (loc, MULT_EXPR, type, arg01, arg1);
+             return build_call_expr_loc (loc, fndecl, 2, arg00, narg1);
+           }
        }
     }
 
@@ -8814,7 +8283,7 @@ fold_builtin_exponent (location_t loc, tree fndecl, tree arg,
     {
       tree type = TREE_TYPE (TREE_TYPE (fndecl));
       tree res;
-      
+
       /* Calculate the result when the argument is a constant.  */
       if ((res = do_mpfr_arg1 (arg, type, func, NULL, NULL, 0)))
        return res;
@@ -8902,7 +8371,7 @@ fold_builtin_memset (location_t loc, tree dest, tree c, tree len,
   length = tree_low_cst (len, 1);
   if (GET_MODE_SIZE (TYPE_MODE (etype)) != length
       || get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
-        < (int) length)
+        < length)
     return NULL_TREE;
 
   if (length > HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT)
@@ -8987,14 +8456,15 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
   else
     {
       tree srctype, desttype;
-      int src_align, dest_align;
+      unsigned int src_align, dest_align;
+      tree off0;
 
       if (endp == 3)
        {
          src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
          dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
 
-         /* Both DEST and SRC must be pointer types. 
+         /* Both DEST and SRC must be pointer types.
             ??? This is what old code did.  Is the testing for pointer types
             really mandatory?
 
@@ -9004,7 +8474,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
          if (readonly_data_expr (src)
              || (host_integerp (len, 1)
                  && (MIN (src_align, dest_align) / BITS_PER_UNIT
-                     >= tree_low_cst (len, 1))))
+                     >= (unsigned HOST_WIDE_INT) tree_low_cst (len, 1))))
            {
              tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
              if (!fn)
@@ -9013,37 +8483,26 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
            }
 
          /* If *src and *dest can't overlap, optimize into memcpy as well.  */
-         srcvar = build_fold_indirect_ref_loc (loc, src);
-         destvar = build_fold_indirect_ref_loc (loc, dest);
-         if (srcvar
-             && !TREE_THIS_VOLATILE (srcvar)
-             && destvar
-             && !TREE_THIS_VOLATILE (destvar))
+         if (TREE_CODE (src) == ADDR_EXPR
+             && TREE_CODE (dest) == ADDR_EXPR)
            {
              tree src_base, dest_base, fn;
              HOST_WIDE_INT src_offset = 0, dest_offset = 0;
              HOST_WIDE_INT size = -1;
              HOST_WIDE_INT maxsize = -1;
 
-             src_base = srcvar;
-             if (handled_component_p (src_base))
-               src_base = get_ref_base_and_extent (src_base, &src_offset,
-                                                   &size, &maxsize);
-             dest_base = destvar;
-             if (handled_component_p (dest_base))
-               dest_base = get_ref_base_and_extent (dest_base, &dest_offset,
-                                                    &size, &maxsize);
+             srcvar = TREE_OPERAND (src, 0);
+             src_base = get_ref_base_and_extent (srcvar, &src_offset,
+                                                 &size, &maxsize);
+             destvar = TREE_OPERAND (dest, 0);
+             dest_base = get_ref_base_and_extent (destvar, &dest_offset,
+                                                  &size, &maxsize);
              if (host_integerp (len, 1))
-               {
-                 maxsize = tree_low_cst (len, 1);
-                 if (maxsize
-                     > INTTYPE_MAXIMUM (HOST_WIDE_INT) / BITS_PER_UNIT)
-                   maxsize = -1;
-                 else
-                   maxsize *= BITS_PER_UNIT;
-               }
+               maxsize = tree_low_cst (len, 1);
              else
                maxsize = -1;
+             src_offset /= BITS_PER_UNIT;
+             dest_offset /= BITS_PER_UNIT;
              if (SSA_VAR_P (src_base)
                  && SSA_VAR_P (dest_base))
                {
@@ -9052,13 +8511,25 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
                                           dest_offset, maxsize))
                    return NULL_TREE;
                }
-             else if (TREE_CODE (src_base) == INDIRECT_REF
-                      && TREE_CODE (dest_base) == INDIRECT_REF)
+             else if (TREE_CODE (src_base) == MEM_REF
+                      && TREE_CODE (dest_base) == MEM_REF)
                {
+                 double_int off;
                  if (! operand_equal_p (TREE_OPERAND (src_base, 0),
-                                        TREE_OPERAND (dest_base, 0), 0)
-                     || ranges_overlap_p (src_offset, maxsize,
-                                          dest_offset, maxsize))
+                                        TREE_OPERAND (dest_base, 0), 0))
+                   return NULL_TREE;
+                 off = double_int_add (mem_ref_offset (src_base),
+                                       shwi_to_double_int (src_offset));
+                 if (!double_int_fits_in_shwi_p (off))
+                   return NULL_TREE;
+                 src_offset = off.low;
+                 off = double_int_add (mem_ref_offset (dest_base),
+                                       shwi_to_double_int (dest_offset));
+                 if (!double_int_fits_in_shwi_p (off))
+                   return NULL_TREE;
+                 dest_offset = off.low;
+                 if (ranges_overlap_p (src_offset, maxsize,
+                                       dest_offset, maxsize))
                    return NULL_TREE;
                }
              else
@@ -9069,6 +8540,27 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
                return NULL_TREE;
              return build_call_expr_loc (loc, fn, 3, dest, src, len);
            }
+
+         /* If the destination and source do not alias optimize into
+            memcpy as well.  */
+         if ((is_gimple_min_invariant (dest)
+              || TREE_CODE (dest) == SSA_NAME)
+             && (is_gimple_min_invariant (src)
+                 || TREE_CODE (src) == SSA_NAME))
+           {
+             ao_ref destr, srcr;
+             ao_ref_init_from_ptr_and_size (&destr, dest, len);
+             ao_ref_init_from_ptr_and_size (&srcr, src, len);
+             if (!refs_may_alias_p_1 (&destr, &srcr, false))
+               {
+                 tree fn;
+                 fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+                 if (!fn)
+                   return NULL_TREE;
+                 return build_call_expr_loc (loc, fn, 3, dest, src, len);
+               }
+           }
+
          return NULL_TREE;
        }
 
@@ -9114,114 +8606,91 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
          dest = build1 (NOP_EXPR, build_pointer_type (desttype), dest);
        }
       if (!srctype || !desttype
+         || TREE_ADDRESSABLE (srctype)
+         || TREE_ADDRESSABLE (desttype)
          || !TYPE_SIZE_UNIT (srctype)
          || !TYPE_SIZE_UNIT (desttype)
          || TREE_CODE (TYPE_SIZE_UNIT (srctype)) != INTEGER_CST
-         || TREE_CODE (TYPE_SIZE_UNIT (desttype)) != INTEGER_CST
-         || TYPE_VOLATILE (srctype)
-         || TYPE_VOLATILE (desttype))
+         || TREE_CODE (TYPE_SIZE_UNIT (desttype)) != INTEGER_CST)
        return NULL_TREE;
 
       src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
       dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
-      if (dest_align < (int) TYPE_ALIGN (desttype)
-         || src_align < (int) TYPE_ALIGN (srctype))
+      if (dest_align < TYPE_ALIGN (desttype)
+         || src_align < TYPE_ALIGN (srctype))
        return NULL_TREE;
 
       if (!ignore)
         dest = builtin_save_expr (dest);
 
-      srcvar = NULL_TREE;
-      if (tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len))
-       {
-         srcvar = build_fold_indirect_ref_loc (loc, src);
-         if (TREE_THIS_VOLATILE (srcvar))
-           return NULL_TREE;
-         else if (!tree_int_cst_equal (lang_hooks.expr_size (srcvar), len))
-           srcvar = 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 it use conflicting alias set to hold argument for the
-            memcpy call.  This check is probably unnecessary with
-            -fno-strict-aliasing.  Similarly for destvar.  See also
-            PR29286.  */
-         else if (!var_decl_component_p (srcvar))
-           srcvar = NULL_TREE;
-       }
+      /* Build accesses at offset zero with a ref-all character type.  */
+      off0 = build_int_cst (build_pointer_type_for_mode (char_type_node,
+                                                        ptr_mode, true), 0);
 
-      destvar = NULL_TREE;
-      if (tree_int_cst_equal (TYPE_SIZE_UNIT (desttype), len))
-       {
-         destvar = build_fold_indirect_ref_loc (loc, dest);
-         if (TREE_THIS_VOLATILE (destvar))
-           return NULL_TREE;
-         else if (!tree_int_cst_equal (lang_hooks.expr_size (destvar), len))
-           destvar = NULL_TREE;
-         else if (!var_decl_component_p (destvar))
-           destvar = NULL_TREE;
+      destvar = dest;
+      STRIP_NOPS (destvar);
+      if (TREE_CODE (destvar) == ADDR_EXPR
+         && var_decl_component_p (TREE_OPERAND (destvar, 0))
+         && tree_int_cst_equal (TYPE_SIZE_UNIT (desttype), len))
+       destvar = fold_build2 (MEM_REF, desttype, destvar, off0);
+      else
+       destvar = NULL_TREE;
+
+      srcvar = src;
+      STRIP_NOPS (srcvar);
+      if (TREE_CODE (srcvar) == ADDR_EXPR
+         && var_decl_component_p (TREE_OPERAND (srcvar, 0))
+         && tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len))
+       {
+         if (!destvar
+             || src_align >= TYPE_ALIGN (desttype))
+           srcvar = fold_build2 (MEM_REF, destvar ? desttype : srctype,
+                                 srcvar, off0);
+         else if (!STRICT_ALIGNMENT)
+           {
+             srctype = build_aligned_type (TYPE_MAIN_VARIANT (desttype),
+                                           src_align);
+             srcvar = fold_build2 (MEM_REF, srctype, srcvar, off0);
+           }
+         else
+           srcvar = NULL_TREE;
        }
+      else
+       srcvar = NULL_TREE;
 
       if (srcvar == NULL_TREE && destvar == NULL_TREE)
        return NULL_TREE;
 
       if (srcvar == NULL_TREE)
        {
-         tree srcptype;
-         if (TREE_ADDRESSABLE (TREE_TYPE (destvar)))
-           return NULL_TREE;
-
-         srctype = build_qualified_type (desttype, 0);
-         if (src_align < (int) TYPE_ALIGN (srctype))
+         STRIP_NOPS (src);
+         if (src_align >= TYPE_ALIGN (desttype))
+           srcvar = fold_build2 (MEM_REF, desttype, src, off0);
+         else
            {
-             if (AGGREGATE_TYPE_P (srctype)
-                 || SLOW_UNALIGNED_ACCESS (TYPE_MODE (srctype), src_align))
+             if (STRICT_ALIGNMENT)
                return NULL_TREE;
-
-             srctype = build_variant_type_copy (srctype);
-             TYPE_ALIGN (srctype) = src_align;
-             TYPE_USER_ALIGN (srctype) = 1;
-             TYPE_PACKED (srctype) = 1;
+             srctype = build_aligned_type (TYPE_MAIN_VARIANT (desttype),
+                                           src_align);
+             srcvar = fold_build2 (MEM_REF, srctype, src, off0);
            }
-         srcptype = build_pointer_type_for_mode (srctype, ptr_mode, true);
-         src = fold_convert_loc (loc, srcptype, src);
-         srcvar = build_fold_indirect_ref_loc (loc, src);
        }
       else if (destvar == NULL_TREE)
        {
-         tree destptype;
-         if (TREE_ADDRESSABLE (TREE_TYPE (srcvar)))
-           return NULL_TREE;
-
-         desttype = build_qualified_type (srctype, 0);
-         if (dest_align < (int) TYPE_ALIGN (desttype))
+         STRIP_NOPS (dest);
+         if (dest_align >= TYPE_ALIGN (srctype))
+           destvar = fold_build2 (MEM_REF, srctype, dest, off0);
+         else
            {
-             if (AGGREGATE_TYPE_P (desttype)
-                 || SLOW_UNALIGNED_ACCESS (TYPE_MODE (desttype), dest_align))
+             if (STRICT_ALIGNMENT)
                return NULL_TREE;
-
-             desttype = build_variant_type_copy (desttype);
-             TYPE_ALIGN (desttype) = dest_align;
-             TYPE_USER_ALIGN (desttype) = 1;
-             TYPE_PACKED (desttype) = 1;
+             desttype = build_aligned_type (TYPE_MAIN_VARIANT (srctype),
+                                            dest_align);
+             destvar = fold_build2 (MEM_REF, desttype, dest, off0);
            }
-         destptype = build_pointer_type_for_mode (desttype, ptr_mode, true);
-         dest = fold_convert_loc (loc, destptype, dest);
-         destvar = build_fold_indirect_ref_loc (loc, dest);
-       }
-
-      if (srctype == desttype
-         || (gimple_in_ssa_p (cfun)
-             && useless_type_conversion_p (desttype, srctype)))
-       expr = srcvar;
-      else if ((INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
-          || POINTER_TYPE_P (TREE_TYPE (srcvar)))
-         && (INTEGRAL_TYPE_P (TREE_TYPE (destvar))
-             || POINTER_TYPE_P (TREE_TYPE (destvar))))
-       expr = fold_convert_loc (loc, TREE_TYPE (destvar), srcvar);
-      else
-       expr = fold_build1_loc (loc, VIEW_CONVERT_EXPR,
-                           TREE_TYPE (destvar), srcvar);
-      expr = build2 (MODIFY_EXPR, TREE_TYPE (destvar), destvar, expr);
+       }
+
+      expr = build2 (MODIFY_EXPR, TREE_TYPE (destvar), destvar, srcvar);
     }
 
   if (ignore)
@@ -9281,6 +8750,46 @@ fold_builtin_strcpy (location_t loc, tree fndecl, tree dest, tree src, tree len)
                           build_call_expr_loc (loc, fn, 3, dest, src, len));
 }
 
+/* Fold function call to builtin stpcpy with arguments DEST and SRC.
+   Return NULL_TREE if no simplification can be made.  */
+
+static tree
+fold_builtin_stpcpy (location_t loc, tree fndecl, tree dest, tree src)
+{
+  tree fn, len, lenp1, call, type;
+
+  if (!validate_arg (dest, POINTER_TYPE)
+      || !validate_arg (src, POINTER_TYPE))
+    return NULL_TREE;
+
+  len = c_strlen (src, 1);
+  if (!len
+      || TREE_CODE (len) != INTEGER_CST)
+    return NULL_TREE;
+
+  if (optimize_function_for_size_p (cfun)
+      /* If length is zero it's small enough.  */
+      && !integer_zerop (len))
+    return NULL_TREE;
+
+  fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+  if (!fn)
+    return NULL_TREE;
+
+  lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1));
+  /* We use dest twice in building our expression.  Save it from
+     multiple expansions.  */
+  dest = builtin_save_expr (dest);
+  call = build_call_expr_loc (loc, fn, 3, dest, src, lenp1);
+
+  type = TREE_TYPE (TREE_TYPE (fndecl));
+  len = fold_convert_loc (loc, sizetype, len);
+  dest = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (dest), dest, len);
+  dest = fold_convert_loc (loc, type, dest);
+  dest = omit_one_operand_loc (loc, type, dest, call);
+  return dest;
+}
+
 /* Fold function call to builtin strncpy with arguments DEST, SRC, and LEN.
    If SLEN is not NULL, it represents the length of the source string.
    Return NULL_TREE if no simplification can be made.  */
@@ -9601,8 +9110,6 @@ fold_builtin_strncmp (location_t loc, tree arg1, tree arg2, tree len)
 static tree
 fold_builtin_signbit (location_t loc, tree arg, tree type)
 {
-  tree temp;
-
   if (!validate_arg (arg, REAL_TYPE))
     return NULL_TREE;
 
@@ -9613,8 +9120,9 @@ fold_builtin_signbit (location_t loc, tree arg, tree type)
       REAL_VALUE_TYPE c;
 
       c = TREE_REAL_CST (arg);
-      temp = REAL_VALUE_NEGATIVE (c) ? integer_one_node : integer_zero_node;
-      return fold_convert_loc (loc, type, temp);
+      return (REAL_VALUE_NEGATIVE (c)
+             ? build_one_cst (type)
+             : build_zero_cst (type));
     }
 
   /* If ARG is non-negative, the result is always zero.  */
@@ -9687,9 +9195,9 @@ fold_builtin_isascii (location_t loc, tree arg)
   else
     {
       /* Transform isascii(c) -> ((c & ~0x7f) == 0).  */
-      arg = build2 (BIT_AND_EXPR, integer_type_node, arg,
-                   build_int_cst (NULL_TREE,
-                                  ~ (unsigned HOST_WIDE_INT) 0x7f));
+      arg = fold_build2 (BIT_AND_EXPR, integer_type_node, arg,
+                        build_int_cst (NULL_TREE,
+                                       ~ (unsigned HOST_WIDE_INT) 0x7f));
       return fold_build2_loc (loc, EQ_EXPR, integer_type_node,
                          arg, integer_zero_node);
     }
@@ -9702,7 +9210,7 @@ fold_builtin_toascii (location_t loc, tree arg)
 {
   if (!validate_arg (arg, INTEGER_TYPE))
     return NULL_TREE;
-      
+
   /* Transform toascii(c) -> (c & 0x7f).  */
   return fold_build2_loc (loc, BIT_AND_EXPR, integer_type_node, arg,
                      build_int_cst (NULL_TREE, 0x7f));
@@ -9727,8 +9235,8 @@ fold_builtin_isdigit (location_t loc, tree arg)
        return NULL_TREE;
 
       arg = fold_convert_loc (loc, unsigned_type_node, arg);
-      arg = build2 (MINUS_EXPR, unsigned_type_node, arg,
-                   build_int_cst (unsigned_type_node, target_digit0));
+      arg = fold_build2 (MINUS_EXPR, unsigned_type_node, arg,
+                        build_int_cst (unsigned_type_node, target_digit0));
       return fold_build2_loc (loc, LE_EXPR, integer_type_node, arg,
                          build_int_cst (unsigned_type_node, 9));
     }
@@ -9762,6 +9270,40 @@ fold_builtin_abs (location_t loc, tree arg, tree type)
   return fold_build1_loc (loc, ABS_EXPR, type, arg);
 }
 
+/* Fold a fma operation with arguments ARG[012].  */
+
+tree
+fold_fma (location_t loc ATTRIBUTE_UNUSED,
+         tree type, tree arg0, tree arg1, tree arg2)
+{
+  if (TREE_CODE (arg0) == REAL_CST
+      && TREE_CODE (arg1) == REAL_CST
+      && TREE_CODE (arg2) == REAL_CST)
+    return do_mpfr_arg3 (arg0, arg1, arg2, type, mpfr_fma);
+
+  return NULL_TREE;
+}
+
+/* Fold a call to fma, fmaf, or fmal with arguments ARG[012].  */
+
+static tree
+fold_builtin_fma (location_t loc, tree arg0, tree arg1, tree arg2, tree type)
+{
+  if (validate_arg (arg0, REAL_TYPE)
+      && validate_arg(arg1, REAL_TYPE)
+      && validate_arg(arg2, REAL_TYPE))
+    {
+      tree tem = fold_fma (loc, type, arg0, arg1, arg2);
+      if (tem)
+       return tem;
+
+      /* ??? Only expand to FMA_EXPR if it's directly supported.  */
+      if (optab_handler (fma_optab, TYPE_MODE (type)) != CODE_FOR_nothing)
+        return fold_build3_loc (loc, FMA_EXPR, type, arg0, arg1, arg2);
+    }
+  return NULL_TREE;
+}
+
 /* Fold a call to builtin fmin or fmax.  */
 
 static tree
@@ -9793,7 +9335,7 @@ fold_builtin_fmin_fmax (location_t loc, tree arg0, tree arg1,
       /* Transform fmin/fmax(x,x) -> x.  */
       if (operand_equal_p (arg0, arg1, OEP_PURE_SAME))
        return omit_one_operand_loc (loc, type, arg0, arg1);
-      
+
       /* Convert fmin/fmax to MIN_EXPR/MAX_EXPR.  C99 requires these
         functions to return the numeric arg if the other one is NaN.
         These tree codes don't honor that, so only transform if
@@ -9816,7 +9358,7 @@ fold_builtin_carg (location_t loc, tree arg, tree type)
       && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == REAL_TYPE)
     {
       tree atan2_fn = mathfn_built_in (type, BUILT_IN_ATAN2);
-      
+
       if (atan2_fn)
         {
          tree new_arg = builtin_save_expr (arg);
@@ -9825,7 +9367,7 @@ fold_builtin_carg (location_t loc, tree arg, tree type)
          return build_call_expr_loc (loc, atan2_fn, 2, i_arg, r_arg);
        }
     }
-  
+
   return NULL_TREE;
 }
 
@@ -9836,13 +9378,13 @@ fold_builtin_logb (location_t loc, tree arg, tree rettype)
 {
   if (! validate_arg (arg, REAL_TYPE))
     return NULL_TREE;
-  
+
   STRIP_NOPS (arg);
-      
+
   if (TREE_CODE (arg) == REAL_CST && ! TREE_OVERFLOW (arg))
     {
       const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (arg);
-         
+
       switch (value->cl)
       {
       case rvc_nan:
@@ -9867,7 +9409,7 @@ fold_builtin_logb (location_t loc, tree arg, tree rettype)
        break;
       }
     }
-  
+
   return NULL_TREE;
 }
 
@@ -9878,13 +9420,13 @@ fold_builtin_significand (location_t loc, tree arg, tree rettype)
 {
   if (! validate_arg (arg, REAL_TYPE))
     return NULL_TREE;
-  
+
   STRIP_NOPS (arg);
-      
+
   if (TREE_CODE (arg) == REAL_CST && ! TREE_OVERFLOW (arg))
     {
       const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (arg);
-         
+
       switch (value->cl)
       {
       case rvc_zero:
@@ -9906,7 +9448,7 @@ fold_builtin_significand (location_t loc, tree arg, tree rettype)
        break;
       }
     }
-  
+
   return NULL_TREE;
 }
 
@@ -9917,12 +9459,12 @@ fold_builtin_frexp (location_t loc, tree arg0, tree arg1, tree rettype)
 {
   if (! validate_arg (arg0, REAL_TYPE) || ! validate_arg (arg1, POINTER_TYPE))
     return NULL_TREE;
-  
+
   STRIP_NOPS (arg0);
-      
+
   if (!(TREE_CODE (arg0) == REAL_CST && ! TREE_OVERFLOW (arg0)))
     return NULL_TREE;
-  
+
   arg1 = build_fold_indirect_ref_loc (loc, arg1);
 
   /* Proceed if a valid pointer type was passed in.  */
@@ -9930,7 +9472,7 @@ fold_builtin_frexp (location_t loc, tree arg0, tree arg1, tree rettype)
     {
       const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (arg0);
       tree frac, exp;
-         
+
       switch (value->cl)
       {
       case rvc_zero:
@@ -9956,7 +9498,7 @@ fold_builtin_frexp (location_t loc, tree arg0, tree arg1, tree rettype)
       default:
        gcc_unreachable ();
       }
-               
+
       /* Create the COMPOUND_EXPR (*arg1 = trunc, frac). */
       arg1 = fold_build2_loc (loc, MODIFY_EXPR, rettype, arg1, exp);
       TREE_SIDE_EFFECTS (arg1) = 1;
@@ -9984,7 +9526,7 @@ fold_builtin_load_exponent (location_t loc, tree arg0, tree arg1,
          || (TREE_CODE (arg0) == REAL_CST
              && !real_isfinite (&TREE_REAL_CST (arg0))))
        return omit_one_operand_loc (loc, type, arg0, arg1);
-      
+
       /* If both arguments are constant, then try to evaluate it.  */
       if ((ldexp || REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2)
          && TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0)
@@ -9993,20 +9535,20 @@ fold_builtin_load_exponent (location_t loc, tree arg0, tree arg1,
          /* Bound the maximum adjustment to twice the range of the
             mode's valid exponents.  Use abs to ensure the range is
             positive as a sanity check.  */
-         const long max_exp_adj = 2 * 
+         const long max_exp_adj = 2 *
            labs (REAL_MODE_FORMAT (TYPE_MODE (type))->emax
                 - REAL_MODE_FORMAT (TYPE_MODE (type))->emin);
 
          /* Get the user-requested adjustment.  */
          const HOST_WIDE_INT req_exp_adj = tree_low_cst (arg1, 0);
-         
+
          /* The requested adjustment must be inside this range.  This
             is a preliminary cap to avoid things like overflow, we
             may still fail to compute the result for other reasons.  */
          if (-max_exp_adj < req_exp_adj && req_exp_adj < max_exp_adj)
            {
              REAL_VALUE_TYPE initial_result;
-             
+
              real_ldexp (&initial_result, &TREE_REAL_CST (arg0), req_exp_adj);
 
              /* Ensure we didn't overflow.  */
@@ -10014,7 +9556,7 @@ fold_builtin_load_exponent (location_t loc, tree arg0, tree arg1,
                {
                  const REAL_VALUE_TYPE trunc_result
                    = real_value_truncate (TYPE_MODE (type), initial_result);
-                 
+
                  /* Only proceed if the target mode can hold the
                     resulting value.  */
                  if (REAL_VALUES_EQUAL (initial_result, trunc_result))
@@ -10034,12 +9576,12 @@ fold_builtin_modf (location_t loc, tree arg0, tree arg1, tree rettype)
 {
   if (! validate_arg (arg0, REAL_TYPE) || ! validate_arg (arg1, POINTER_TYPE))
     return NULL_TREE;
-  
+
   STRIP_NOPS (arg0);
-      
+
   if (!(TREE_CODE (arg0) == REAL_CST && ! TREE_OVERFLOW (arg0)))
     return NULL_TREE;
-  
+
   arg1 = build_fold_indirect_ref_loc (loc, arg1);
 
   /* Proceed if a valid pointer type was passed in.  */
@@ -10050,36 +9592,126 @@ fold_builtin_modf (location_t loc, tree arg0, tree arg1, tree rettype)
 
       switch (value->cl)
       {
-      case rvc_nan:
-      case rvc_zero:
-       /* For +-NaN or +-0, return (*arg1 = arg0, arg0).  */
-       trunc = frac = *value;
-       break;
-      case rvc_inf:
-       /* For +-Inf, return (*arg1 = arg0, +-0).  */
-       frac = dconst0;
-       frac.sign = value->sign;
-       trunc = *value;
-       break;
-      case rvc_normal:
-       /* Return (*arg1 = trunc(arg0), arg0-trunc(arg0)).  */
-       real_trunc (&trunc, VOIDmode, value);
-       real_arithmetic (&frac, MINUS_EXPR, value, &trunc);
-       /* If the original number was negative and already
-          integral, then the fractional part is -0.0.  */
-       if (value->sign && frac.cl == rvc_zero)
-         frac.sign = value->sign;
-       break;
+      case rvc_nan:
+      case rvc_zero:
+       /* For +-NaN or +-0, return (*arg1 = arg0, arg0).  */
+       trunc = frac = *value;
+       break;
+      case rvc_inf:
+       /* For +-Inf, return (*arg1 = arg0, +-0).  */
+       frac = dconst0;
+       frac.sign = value->sign;
+       trunc = *value;
+       break;
+      case rvc_normal:
+       /* Return (*arg1 = trunc(arg0), arg0-trunc(arg0)).  */
+       real_trunc (&trunc, VOIDmode, value);
+       real_arithmetic (&frac, MINUS_EXPR, value, &trunc);
+       /* If the original number was negative and already
+          integral, then the fractional part is -0.0.  */
+       if (value->sign && frac.cl == rvc_zero)
+         frac.sign = value->sign;
+       break;
+      }
+
+      /* Create the COMPOUND_EXPR (*arg1 = trunc, frac). */
+      arg1 = fold_build2_loc (loc, MODIFY_EXPR, rettype, arg1,
+                         build_real (rettype, trunc));
+      TREE_SIDE_EFFECTS (arg1) = 1;
+      return fold_build2_loc (loc, COMPOUND_EXPR, rettype, arg1,
+                         build_real (rettype, frac));
+    }
+
+  return NULL_TREE;
+}
+
+/* Given a location LOC, an interclass builtin function decl FNDECL
+   and its single argument ARG, return an folded expression computing
+   the same, or NULL_TREE if we either couldn't or didn't want to fold
+   (the latter happen if there's an RTL instruction available).  */
+
+static tree
+fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg)
+{
+  enum machine_mode mode;
+
+  if (!validate_arg (arg, REAL_TYPE))
+    return NULL_TREE;
+
+  if (interclass_mathfn_icode (arg, fndecl) != CODE_FOR_nothing)
+    return NULL_TREE;
+
+  mode = TYPE_MODE (TREE_TYPE (arg));
+
+  /* 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_loc (loc, ABS_EXPR, type, arg),
+                                 build_real (type, r));
+       return result;
+      }
+    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_loc (loc, ABS_EXPR, type, arg),
+                                 build_real (type, r));
+       /*result = fold_build2_loc (loc, UNGT_EXPR,
+                                 TREE_TYPE (TREE_TYPE (fndecl)),
+                                 fold_build1_loc (loc, ABS_EXPR, type, arg),
+                                 build_real (type, r));
+       result = fold_build1_loc (loc, TRUTH_NOT_EXPR,
+                                 TREE_TYPE (TREE_TYPE (fndecl)),
+                                 result);*/
+       return result;
+      }
+    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_loc (loc, 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 result;
       }
-             
-      /* Create the COMPOUND_EXPR (*arg1 = trunc, frac). */
-      arg1 = fold_build2_loc (loc, MODIFY_EXPR, rettype, arg1,
-                         build_real (rettype, trunc));
-      TREE_SIDE_EFFECTS (arg1) = 1;
-      return fold_build2_loc (loc, COMPOUND_EXPR, rettype, arg1,
-                         build_real (rettype, frac));
+    default:
+      break;
     }
-  
+
   return NULL_TREE;
 }
 
@@ -10134,7 +9766,7 @@ fold_builtin_classify (location_t loc, tree fndecl, tree arg, int builtin_index)
                                        signbit_call, integer_zero_node);
            isinf_call = fold_build2_loc (loc, NE_EXPR, integer_type_node,
                                      isinf_call, integer_zero_node);
-           
+
            tmp = fold_build3_loc (loc, COND_EXPR, integer_type_node, signbit_call,
                               integer_minus_one_node, integer_one_node);
            tmp = fold_build3_loc (loc, COND_EXPR, integer_type_node,
@@ -10192,13 +9824,13 @@ fold_builtin_fpclassify (location_t loc, tree exp)
   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);
@@ -10209,12 +9841,12 @@ fold_builtin_fpclassify (location_t loc, tree exp)
   mode = TYPE_MODE (type);
   arg = builtin_save_expr (fold_build1_loc (loc, ABS_EXPR, type, arg));
 
-  /* fpclassify(x) -> 
+  /* 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_loc (loc, EQ_EXPR, integer_type_node, arg,
                     build_real (type, dconst0));
   res = fold_build3_loc (loc, COND_EXPR, integer_type_node,
@@ -10225,7 +9857,7 @@ fold_builtin_fpclassify (location_t loc, tree exp)
   tmp = fold_build2_loc (loc, GE_EXPR, integer_type_node,
                     arg, build_real (type, r));
   res = fold_build3_loc (loc, COND_EXPR, integer_type_node, tmp, fp_normal, res);
-  
+
   if (HONOR_INFINITIES (mode))
     {
       real_inf (&r);
@@ -10240,7 +9872,7 @@ fold_builtin_fpclassify (location_t loc, tree exp)
       tmp = fold_build2_loc (loc, ORDERED_EXPR, integer_type_node, arg, arg);
       res = fold_build3_loc (loc, COND_EXPR, integer_type_node, tmp, res, fp_nan);
     }
-  
+
   return res;
 }
 
@@ -10334,7 +9966,6 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore)
   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
   switch (fcode)
     {
-
     case BUILT_IN_CONSTANT_P:
       {
        tree val = fold_builtin_constant_p (arg0);
@@ -10352,7 +9983,7 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore)
       return fold_builtin_classify_type (arg0);
 
     case BUILT_IN_STRLEN:
-      return fold_builtin_strlen (loc, arg0);
+      return fold_builtin_strlen (loc, type, arg0);
 
     CASE_FLT_FN (BUILT_IN_FABS):
       return fold_builtin_fabs (loc, arg0, type);
@@ -10365,65 +9996,103 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore)
 
     CASE_FLT_FN (BUILT_IN_CONJ):
       if (validate_arg (arg0, COMPLEX_TYPE)
-       && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) 
+       && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
        return fold_build1_loc (loc, CONJ_EXPR, type, arg0);
     break;
 
     CASE_FLT_FN (BUILT_IN_CREAL):
       if (validate_arg (arg0, COMPLEX_TYPE)
-       && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) 
+       && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
        return non_lvalue_loc (loc, fold_build1_loc (loc, REALPART_EXPR, type, arg0));;
     break;
 
     CASE_FLT_FN (BUILT_IN_CIMAG):
-      if (validate_arg (arg0, COMPLEX_TYPE))
+      if (validate_arg (arg0, COMPLEX_TYPE)
+         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
        return non_lvalue_loc (loc, fold_build1_loc (loc, IMAGPART_EXPR, type, arg0));
     break;
 
     CASE_FLT_FN (BUILT_IN_CCOS):
       return fold_builtin_ccos(loc, arg0, type, fndecl, /*hyper=*/ false);
-    
+
     CASE_FLT_FN (BUILT_IN_CCOSH):
       return fold_builtin_ccos(loc, arg0, type, fndecl, /*hyper=*/ true);
-    
-#ifdef HAVE_mpc
+
+    CASE_FLT_FN (BUILT_IN_CPROJ):
+      return fold_builtin_cproj(loc, arg0, type);
+
     CASE_FLT_FN (BUILT_IN_CSIN):
       if (validate_arg (arg0, COMPLEX_TYPE)
-         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) 
+         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
        return do_mpc_arg1 (arg0, type, mpc_sin);
     break;
-    
+
     CASE_FLT_FN (BUILT_IN_CSINH):
       if (validate_arg (arg0, COMPLEX_TYPE)
-         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) 
+         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
        return do_mpc_arg1 (arg0, type, mpc_sinh);
     break;
-    
+
     CASE_FLT_FN (BUILT_IN_CTAN):
       if (validate_arg (arg0, COMPLEX_TYPE)
-         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) 
+         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
        return do_mpc_arg1 (arg0, type, mpc_tan);
     break;
-    
+
     CASE_FLT_FN (BUILT_IN_CTANH):
       if (validate_arg (arg0, COMPLEX_TYPE)
-         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) 
+         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
        return do_mpc_arg1 (arg0, type, mpc_tanh);
     break;
-    
+
     CASE_FLT_FN (BUILT_IN_CLOG):
       if (validate_arg (arg0, COMPLEX_TYPE)
-         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) 
+         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
        return do_mpc_arg1 (arg0, type, mpc_log);
     break;
-    
+
     CASE_FLT_FN (BUILT_IN_CSQRT):
       if (validate_arg (arg0, COMPLEX_TYPE)
-         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) 
+         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
        return do_mpc_arg1 (arg0, type, mpc_sqrt);
     break;
-#endif
-    
+
+    CASE_FLT_FN (BUILT_IN_CASIN):
+      if (validate_arg (arg0, COMPLEX_TYPE)
+         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
+       return do_mpc_arg1 (arg0, type, mpc_asin);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_CACOS):
+      if (validate_arg (arg0, COMPLEX_TYPE)
+         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
+       return do_mpc_arg1 (arg0, type, mpc_acos);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_CATAN):
+      if (validate_arg (arg0, COMPLEX_TYPE)
+         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
+       return do_mpc_arg1 (arg0, type, mpc_atan);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_CASINH):
+      if (validate_arg (arg0, COMPLEX_TYPE)
+         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
+       return do_mpc_arg1 (arg0, type, mpc_asinh);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_CACOSH):
+      if (validate_arg (arg0, COMPLEX_TYPE)
+         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
+       return do_mpc_arg1 (arg0, type, mpc_acosh);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_CATANH):
+      if (validate_arg (arg0, COMPLEX_TYPE)
+         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
+       return do_mpc_arg1 (arg0, type, mpc_atanh);
+    break;
+
     CASE_FLT_FN (BUILT_IN_CABS):
       return fold_builtin_cabs (loc, arg0, type, fndecl);
 
@@ -10516,7 +10185,7 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore)
       if (validate_arg (arg0, REAL_TYPE))
        return do_mpfr_arg1 (arg0, type, mpfr_gamma, NULL, NULL, 0);
     break;
+
     CASE_FLT_FN (BUILT_IN_EXP):
       return fold_builtin_exponent (loc, fndecl, arg0, mpfr_exp);
 
@@ -10531,7 +10200,7 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore)
       if (validate_arg (arg0, REAL_TYPE))
        return do_mpfr_arg1 (arg0, type, mpfr_expm1, NULL, NULL, 0);
     break;
+
     CASE_FLT_FN (BUILT_IN_LOG):
     return fold_builtin_logarithm (loc, fndecl, arg0, mpfr_log);
 
@@ -10643,13 +10312,26 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore)
     case BUILT_IN_FINITED64:
     case BUILT_IN_FINITED128:
     case BUILT_IN_ISFINITE:
-      return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISFINITE);
+      {
+       tree ret = fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISFINITE);
+       if (ret)
+         return ret;
+       return fold_builtin_interclass_mathfn (loc, fndecl, arg0);
+      }
 
     CASE_FLT_FN (BUILT_IN_ISINF):
     case BUILT_IN_ISINFD32:
     case BUILT_IN_ISINFD64:
     case BUILT_IN_ISINFD128:
-      return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISINF);
+      {
+       tree ret = fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISINF);
+       if (ret)
+         return ret;
+       return fold_builtin_interclass_mathfn (loc, fndecl, arg0);
+      }
+
+    case BUILT_IN_ISNORMAL:
+      return fold_builtin_interclass_mathfn (loc, fndecl, arg0);
 
     case BUILT_IN_ISINF_SIGN:
       return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISINF_SIGN);
@@ -10665,6 +10347,11 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore)
     case BUILT_IN_VPRINTF:
       return fold_builtin_printf (loc, fndecl, arg0, NULL_TREE, ignore, fcode);
 
+    case BUILT_IN_FREE:
+      if (integer_zerop (arg0))
+       return build_empty_stmt (loc);
+      break;
+
     default:
       break;
     }
@@ -10727,15 +10414,13 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1, bool ignore)
     CASE_FLT_FN (BUILT_IN_HYPOT):
       return fold_builtin_hypot (loc, fndecl, arg0, arg1, type);
 
-#ifdef HAVE_mpc_pow
     CASE_FLT_FN (BUILT_IN_CPOW):
       if (validate_arg (arg0, COMPLEX_TYPE)
          && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE
          && validate_arg (arg1, COMPLEX_TYPE)
-         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg1))) == REAL_TYPE) 
-       return do_mpc_arg2 (arg0, arg1, type, mpc_pow);
+         && TREE_CODE (TREE_TYPE (TREE_TYPE (arg1))) == REAL_TYPE)
+       return do_mpc_arg2 (arg0, arg1, type, /*do_nonfinite=*/ 0, mpc_pow);
     break;
-#endif
 
     CASE_FLT_FN (BUILT_IN_LDEXP):
       return fold_builtin_load_exponent (loc, arg0, arg1, type, /*ldexp=*/true);
@@ -10791,6 +10476,8 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1, bool ignore)
 
          return build_call_expr_loc (loc, fn, 2, arg0, arg1);
        }
+      else
+       return fold_builtin_stpcpy (loc, fndecl, arg0, arg1);
       break;
 
     case BUILT_IN_STRCMP:
@@ -10891,10 +10578,7 @@ fold_builtin_3 (location_t loc, tree fndecl,
       return fold_builtin_sincos (loc, arg0, arg1, arg2);
 
     CASE_FLT_FN (BUILT_IN_FMA):
-      if (validate_arg (arg0, REAL_TYPE)
-         && validate_arg(arg1, REAL_TYPE)
-         && validate_arg(arg2, REAL_TYPE))
-       return do_mpfr_arg3 (arg0, arg1, arg2, type, mpfr_fma);
+      return fold_builtin_fma (loc, arg0, arg1, arg2, type);
     break;
 
     CASE_FLT_FN (BUILT_IN_REMQUO):
@@ -10984,7 +10668,7 @@ fold_builtin_3 (location_t loc, tree fndecl,
    ARG2, and ARG3.  IGNORE is true if the result of the function call is
    ignored.  This function returns NULL_TREE if no simplification was
    possible.  */
+
 static tree
 fold_builtin_4 (location_t loc, tree fndecl,
                tree arg0, tree arg1, tree arg2, tree arg3, bool ignore)
@@ -11030,9 +10714,9 @@ fold_builtin_4 (location_t loc, tree fndecl,
     fixed argument patterns.  Foldings that do varargs-to-varargs
     transformations, or that match calls with more than 4 arguments,
     need to be handled with fold_builtin_varargs instead.  */
+
 #define MAX_ARGS_TO_FOLD_BUILTIN 4
+
 static tree
 fold_builtin_n (location_t loc, tree fndecl, tree *args, int nargs, bool ignore)
 {
@@ -11163,9 +10847,9 @@ fold_call_expr (location_t loc, tree exp, bool ignore)
       if (avoid_folding_inline_builtin (fndecl))
        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);
+        return targetm.fold_builtin (fndecl, call_expr_nargs (exp),
+                                    CALL_EXPR_ARGP (exp), ignore);
       else
        {
          if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN)
@@ -11181,42 +10865,65 @@ fold_call_expr (location_t loc, tree exp, bool ignore)
     }
   return NULL_TREE;
 }
+
 /* Conveniently construct a function call expression.  FNDECL names the
-    function to be called and ARGLIST is a TREE_LIST of arguments.  */
+   function to be called and N arguments are passed in the array
+   ARGARRAY.  */
+
 tree
-build_function_call_expr (location_t loc, tree fndecl, tree arglist)
+build_call_expr_loc_array (location_t loc, tree fndecl, int n, tree *argarray)
 {
   tree fntype = TREE_TYPE (fndecl);
   tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
-  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 (loc, TREE_TYPE (fntype), fn, n, argarray);
 }
 
 /* Conveniently construct a function call expression.  FNDECL names the
+   function to be called and the arguments are passed in the vector
+   VEC.  */
+
+tree
+build_call_expr_loc_vec (location_t loc, tree fndecl, VEC(tree,gc) *vec)
+{
+  return build_call_expr_loc_array (loc, fndecl, VEC_length (tree, vec),
+                                   VEC_address (tree, vec));
+}
+
+
+/* Conveniently construct a function call expression.  FNDECL names the
    function to be called, N is the number of arguments, and the "..."
    parameters are the argument expressions.  */
+
 tree
 build_call_expr_loc (location_t loc, tree fndecl, int n, ...)
 {
   va_list ap;
-  tree fntype = TREE_TYPE (fndecl);
-  tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
-  tree *argarray = (tree *) alloca (n * sizeof (tree));
+  tree *argarray = XALLOCAVEC (tree, n);
   int i;
 
   va_start (ap, n);
   for (i = 0; i < n; i++)
     argarray[i] = va_arg (ap, tree);
   va_end (ap);
-  return fold_builtin_call_array (loc, TREE_TYPE (fntype), fn, n, argarray);
+  return build_call_expr_loc_array (loc, fndecl, n, argarray);
+}
+
+/* Like build_call_expr_loc (UNKNOWN_LOCATION, ...).  Duplicated because
+   varargs macros aren't supported by all bootstrap compilers.  */
+
+tree
+build_call_expr (tree fndecl, int n, ...)
+{
+  va_list ap;
+  tree *argarray = XALLOCAVEC (tree, n);
+  int i;
+
+  va_start (ap, n);
+  for (i = 0; i < n; i++)
+    argarray[i] = va_arg (ap, tree);
+  va_end (ap);
+  return build_call_expr_loc_array (UNKNOWN_LOCATION, fndecl, n, argarray);
 }
 
 /* Construct a CALL_EXPR with type TYPE with FN as the function expression.
@@ -11229,7 +10936,6 @@ fold_builtin_call_array (location_t loc, tree type,
                         tree *argarray)
 {
   tree ret = NULL_TREE;
-  int i;
    tree exp;
 
   if (TREE_CODE (fn) == ADDR_EXPR)
@@ -11253,12 +10959,10 @@ fold_builtin_call_array (location_t loc, tree type,
          return build_call_array_loc (loc, type, fn, n, argarray);
         if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
           {
-            tree arglist = NULL_TREE;
-           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;
+           ret = targetm.fold_builtin (fndecl, n, argarray, false);
+           if (ret)
+             return ret;
+
            return build_call_array_loc (loc, type, fn, n, argarray);
           }
         else if (n <= MAX_ARGS_TO_FOLD_BUILTIN)
@@ -11280,42 +10984,75 @@ fold_builtin_call_array (location_t loc, tree type,
   return build_call_array_loc (loc, type, fn, n, argarray);
 }
 
-/* Construct a new CALL_EXPR using the tail of the argument list of EXP
-   along with N new arguments specified as the "..." parameters.  SKIP
-   is the number of arguments in EXP to be omitted.  This function is used
-   to do varargs-to-varargs transformations.  */
+/* Construct a new CALL_EXPR to FNDECL using the tail of the argument
+   list ARGS along with N new arguments in NEWARGS.  SKIP is the number
+   of arguments in ARGS to be omitted.  OLDNARGS is the number of
+   elements in ARGS.  */
 
 static tree
-rewrite_call_expr (location_t loc, tree exp, int skip, tree fndecl, int n, ...)
+rewrite_call_expr_valist (location_t loc, int oldnargs, tree *args,
+                         int skip, tree fndecl, int n, va_list newargs)
 {
-  int oldnargs = call_expr_nargs (exp);
   int nargs = oldnargs - skip + n;
-  tree fntype = TREE_TYPE (fndecl);
-  tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
   tree *buffer;
 
   if (n > 0)
     {
       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);
+       buffer[i] = va_arg (newargs, tree);
       for (j = skip; j < oldnargs; j++, i++)
-       buffer[i] = CALL_EXPR_ARG (exp, j);
+       buffer[i] = args[j];
     }
-  else 
-    buffer = CALL_EXPR_ARGP (exp) + skip;
+  else
+    buffer = args + skip;
+
+  return build_call_expr_loc_array (loc, fndecl, nargs, buffer);
+}
+
+/* Construct a new CALL_EXPR to FNDECL using the tail of the argument
+   list ARGS along with N new arguments specified as the "..."
+   parameters.  SKIP is the number of arguments in ARGS to be omitted.
+   OLDNARGS is the number of elements in ARGS.  */
+
+static tree
+rewrite_call_expr_array (location_t loc, int oldnargs, tree *args,
+                        int skip, tree fndecl, int n, ...)
+{
+  va_list ap;
+  tree t;
+
+  va_start (ap, n);
+  t = rewrite_call_expr_valist (loc, oldnargs, args, skip, fndecl, n, ap);
+  va_end (ap);
+
+  return t;
+}
+
+/* Construct a new CALL_EXPR using the tail of the argument list of EXP
+   along with N new arguments specified as the "..." parameters.  SKIP
+   is the number of arguments in EXP to be omitted.  This function is used
+   to do varargs-to-varargs transformations.  */
+
+static tree
+rewrite_call_expr (location_t loc, tree exp, int skip, tree fndecl, int n, ...)
+{
+  va_list ap;
+  tree t;
+
+  va_start (ap, n);
+  t = rewrite_call_expr_valist (loc, call_expr_nargs (exp),
+                               CALL_EXPR_ARGP (exp), skip, fndecl, n, ap);
+  va_end (ap);
 
-  return fold (build_call_array_loc (loc, TREE_TYPE (exp), fn, nargs, buffer));
+  return t;
 }
 
 /* Validate a single argument ARG against a tree code CODE representing
    a type.  */
-  
+
 static bool
 validate_arg (const_tree arg, enum tree_code code)
 {
@@ -11756,6 +11493,42 @@ fold_builtin_strcat (location_t loc ATTRIBUTE_UNUSED, tree dst, tree src)
       if (p && *p == '\0')
        return dst;
 
+      if (optimize_insn_for_speed_p ())
+       {
+         /* See if we can store by pieces into (dst + strlen(dst)).  */
+         tree newdst, call;
+         tree strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN];
+         tree strcpy_fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+
+         if (!strlen_fn || !strcpy_fn)
+           return NULL_TREE;
+
+         /* If we don't have a movstr we don't want to emit an strcpy
+            call.  We have to do that if the length of the source string
+            isn't computable (in that case we can use memcpy probably
+            later expanding to a sequence of mov instructions).  If we
+            have movstr instructions we can emit strcpy calls.  */
+         if (!HAVE_movstr)
+           {
+             tree len = c_strlen (src, 1);
+             if (! len || TREE_SIDE_EFFECTS (len))
+               return NULL_TREE;
+           }
+
+         /* Stabilize the argument list.  */
+         dst = builtin_save_expr (dst);
+
+         /* Create strlen (dst).  */
+         newdst = build_call_expr_loc (loc, strlen_fn, 1, dst);
+         /* Create (dst p+ strlen (dst)).  */
+
+         newdst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
+                               TREE_TYPE (dst), dst, newdst);
+         newdst = builtin_save_expr (newdst);
+
+         call = build_call_expr_loc (loc, strcpy_fn, 2, newdst, src);
+         return build2 (COMPOUND_EXPR, TREE_TYPE (dst), call, dst);
+       }
       return NULL_TREE;
     }
 }
@@ -12003,9 +11776,7 @@ fold_builtin_next_arg (tree exp, bool va_start_p)
   int nargs = call_expr_nargs (exp);
   tree arg;
 
-  if (TYPE_ARG_TYPES (fntype) == 0
-      || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
-         == void_type_node))
+  if (!stdarg_p (fntype))
     {
       error ("%<va_start%> used in function with fixed args");
       return true;
@@ -12043,7 +11814,7 @@ fold_builtin_next_arg (tree exp, bool va_start_p)
     arg = SSA_NAME_VAR (arg);
 
   /* We destructively modify the call to be __builtin_va_start (ap, 0)
-     or __builtin_next_arg (0) the first time we see it, after checking 
+     or __builtin_next_arg (0) the first time we see it, after checking
      the arguments and if needed issuing a warning.  */
   if (!integer_zerop (arg))
     {
@@ -12276,16 +12047,9 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
       if (! fn)
        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);
+      fn = build_call_nofold_loc (EXPR_LOCATION (exp), fn, 3, dest, src, len);
+      gcc_assert (TREE_CODE (fn) == CALL_EXPR);
+      CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
       return expand_expr (fn, target, mode, EXPAND_NORMAL);
     }
   else if (fcode == BUILT_IN_MEMSET_CHK)
@@ -12331,16 +12095,10 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
              tree fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
              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);
+             fn = build_call_nofold_loc (EXPR_LOCATION (exp), fn, 4,
+                                         dest, src, len, size);
+             gcc_assert (TREE_CODE (fn) == CALL_EXPR);
+             CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
              return expand_expr (fn, target, mode, EXPAND_NORMAL);
            }
        }
@@ -12422,16 +12180,14 @@ maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
 static void
 maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode)
 {
-  tree dest, size, len, fmt, flag;
+  tree size, len, fmt;
   const char *fmt_str;
   int nargs = call_expr_nargs (exp);
 
   /* Verify the required arguments in the original call.  */
-  
+
   if (nargs < 4)
     return;
-  dest = CALL_EXPR_ARG (exp, 0);
-  flag = CALL_EXPR_ARG (exp, 1);
   size = CALL_EXPR_ARG (exp, 2);
   fmt = CALL_EXPR_ARG (exp, 3);
 
@@ -12487,7 +12243,7 @@ maybe_emit_free_warning (tree exp)
     return;
 
   arg = get_base_address (TREE_OPERAND (arg, 0));
-  if (arg == NULL || INDIRECT_REF_P (arg))
+  if (arg == NULL || INDIRECT_REF_P (arg) || TREE_CODE (arg) == MEM_REF)
     return;
 
   if (SSA_VAR_P (arg))
@@ -12504,7 +12260,7 @@ maybe_emit_free_warning (tree exp)
 tree
 fold_builtin_object_size (tree ptr, tree ost)
 {
-  tree ret = NULL_TREE;
+  unsigned HOST_WIDE_INT bytes;
   int object_size_type;
 
   if (!validate_arg (ptr, POINTER_TYPE)
@@ -12527,31 +12283,25 @@ fold_builtin_object_size (tree ptr, tree ost)
     return build_int_cst_type (size_type_node, object_size_type < 2 ? -1 : 0);
 
   if (TREE_CODE (ptr) == ADDR_EXPR)
-    ret = build_int_cstu (size_type_node,
-                         compute_builtin_object_size (ptr, object_size_type));
-
+    {
+      bytes = compute_builtin_object_size (ptr, object_size_type);
+      if (double_int_fits_to_tree_p (size_type_node,
+                                    uhwi_to_double_int (bytes)))
+       return build_int_cstu (size_type_node, bytes);
+    }
   else if (TREE_CODE (ptr) == SSA_NAME)
     {
-      unsigned HOST_WIDE_INT bytes;
-
       /* If object size is not known yet, delay folding until
        later.  Maybe subsequent passes will help determining
        it.  */
       bytes = compute_builtin_object_size (ptr, object_size_type);
-      if (bytes != (unsigned HOST_WIDE_INT) (object_size_type < 2
-                                            ? -1 : 0))
-       ret = build_int_cstu (size_type_node, bytes);
+      if (bytes != (unsigned HOST_WIDE_INT) (object_size_type < 2 ? -1 : 0)
+          && double_int_fits_to_tree_p (size_type_node,
+                                       uhwi_to_double_int (bytes)))
+       return build_int_cstu (size_type_node, bytes);
     }
 
-  if (ret)
-    {
-      unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (ret);
-      HOST_WIDE_INT high = TREE_INT_CST_HIGH (ret);
-      if (fit_double_type (low, high, &low, &high, TREE_TYPE (ret)))
-       ret = NULL_TREE;
-    }
-
-  return ret;
+  return NULL_TREE;
 }
 
 /* Fold a call to the __mem{cpy,pcpy,move,set}_chk builtin.
@@ -12858,31 +12608,31 @@ fold_builtin_strncat_chk (location_t loc, tree fndecl,
   return build_call_expr_loc (loc, fn, 3, dest, src, len);
 }
 
-/* Fold a call EXP to __{,v}sprintf_chk.  Return NULL_TREE if
-   a normal call should be emitted rather than expanding the function
-   inline.  FCODE is either BUILT_IN_SPRINTF_CHK or BUILT_IN_VSPRINTF_CHK.  */
+/* Fold a call EXP to __{,v}sprintf_chk having NARGS passed as ARGS.
+   Return NULL_TREE if a normal call should be emitted rather than
+   expanding the function inline.  FCODE is either BUILT_IN_SPRINTF_CHK
+   or BUILT_IN_VSPRINTF_CHK.  */
 
 static tree
-fold_builtin_sprintf_chk (location_t loc, tree exp,
-                         enum built_in_function fcode)
+fold_builtin_sprintf_chk_1 (location_t loc, int nargs, tree *args,
+                           enum built_in_function fcode)
 {
   tree dest, size, len, fn, fmt, flag;
   const char *fmt_str;
-  int nargs = call_expr_nargs (exp);
 
   /* Verify the required arguments in the original call.  */
   if (nargs < 4)
     return NULL_TREE;
-  dest = CALL_EXPR_ARG (exp, 0);
+  dest = args[0];
   if (!validate_arg (dest, POINTER_TYPE))
     return NULL_TREE;
-  flag = CALL_EXPR_ARG (exp, 1);
+  flag = args[1];
   if (!validate_arg (flag, INTEGER_TYPE))
     return NULL_TREE;
-  size = CALL_EXPR_ARG (exp, 2);
+  size = args[2];
   if (!validate_arg (size, INTEGER_TYPE))
     return NULL_TREE;
-  fmt = CALL_EXPR_ARG (exp, 3);
+  fmt = args[3];
   if (!validate_arg (fmt, POINTER_TYPE))
     return NULL_TREE;
 
@@ -12913,7 +12663,7 @@ fold_builtin_sprintf_chk (location_t loc, tree exp,
 
          if (nargs == 5)
            {
-             arg = CALL_EXPR_ARG (exp, 4);
+             arg = args[4];
              if (validate_arg (arg, POINTER_TYPE))
                {
                  len = c_strlen (arg, 1);
@@ -12947,38 +12697,50 @@ fold_builtin_sprintf_chk (location_t loc, tree exp,
   if (!fn)
     return NULL_TREE;
 
-  return rewrite_call_expr (loc, exp, 4, fn, 2, dest, fmt);
+  return rewrite_call_expr_array (loc, nargs, args, 4, fn, 2, dest, fmt);
+}
+
+/* Fold a call EXP to __{,v}sprintf_chk.  Return NULL_TREE if
+   a normal call should be emitted rather than expanding the function
+   inline.  FCODE is either BUILT_IN_SPRINTF_CHK or BUILT_IN_VSPRINTF_CHK.  */
+
+static tree
+fold_builtin_sprintf_chk (location_t loc, tree exp,
+                         enum built_in_function fcode)
+{
+  return fold_builtin_sprintf_chk_1 (loc, call_expr_nargs (exp),
+                                    CALL_EXPR_ARGP (exp), fcode);
 }
 
-/* Fold a call EXP to {,v}snprintf.  Return NULL_TREE if
-   a normal call should be emitted rather than expanding the function
-   inline.  FCODE is either BUILT_IN_SNPRINTF_CHK or
+/* Fold a call EXP to {,v}snprintf having NARGS passed as ARGS.  Return
+   NULL_TREE if a normal call should be emitted rather than expanding
+   the function inline.  FCODE is either BUILT_IN_SNPRINTF_CHK or
    BUILT_IN_VSNPRINTF_CHK.  If MAXLEN is not NULL, it is maximum length
    passed as second argument.  */
 
-tree
-fold_builtin_snprintf_chk (location_t loc, tree exp, tree maxlen,
-                          enum built_in_function fcode)
+static tree
+fold_builtin_snprintf_chk_1 (location_t loc, int nargs, tree *args,
+                            tree maxlen, enum built_in_function fcode)
 {
   tree dest, size, len, fn, fmt, flag;
   const char *fmt_str;
 
   /* Verify the required arguments in the original call.  */
-  if (call_expr_nargs (exp) < 5)
+  if (nargs < 5)
     return NULL_TREE;
-  dest = CALL_EXPR_ARG (exp, 0);
+  dest = args[0];
   if (!validate_arg (dest, POINTER_TYPE))
     return NULL_TREE;
-  len = CALL_EXPR_ARG (exp, 1);
+  len = args[1];
   if (!validate_arg (len, INTEGER_TYPE))
     return NULL_TREE;
-  flag = CALL_EXPR_ARG (exp, 2);
+  flag = args[2];
   if (!validate_arg (flag, INTEGER_TYPE))
     return NULL_TREE;
-  size = CALL_EXPR_ARG (exp, 3);
+  size = args[3];
   if (!validate_arg (size, INTEGER_TYPE))
     return NULL_TREE;
-  fmt = CALL_EXPR_ARG (exp, 4);
+  fmt = args[4];
   if (!validate_arg (fmt, POINTER_TYPE))
     return NULL_TREE;
 
@@ -13024,7 +12786,21 @@ fold_builtin_snprintf_chk (location_t loc, tree exp, tree maxlen,
   if (!fn)
     return NULL_TREE;
 
-  return rewrite_call_expr (loc, exp, 5, fn, 3, dest, len, fmt);
+  return rewrite_call_expr_array (loc, nargs, args, 5, fn, 3, dest, len, fmt);
+}
+
+/* Fold a call EXP to {,v}snprintf.  Return NULL_TREE if
+   a normal call should be emitted rather than expanding the function
+   inline.  FCODE is either BUILT_IN_SNPRINTF_CHK or
+   BUILT_IN_VSNPRINTF_CHK.  If MAXLEN is not NULL, it is maximum length
+   passed as second argument.  */
+
+tree
+fold_builtin_snprintf_chk (location_t loc, tree exp, tree maxlen,
+                          enum built_in_function fcode)
+{
+  return fold_builtin_snprintf_chk_1 (loc, call_expr_nargs (exp),
+                                     CALL_EXPR_ARGP (exp), maxlen, fcode);
 }
 
 /* Fold a call to the {,v}printf{,_unlocked} and __{,v}printf_chk builtins.
@@ -13116,15 +12892,28 @@ fold_builtin_printf (location_t loc, tree fndecl, tree fmt,
        {
          /* If the string was "string\n", call puts("string").  */
          size_t len = strlen (str);
-         if ((unsigned char)str[len - 1] == target_newline)
+         if ((unsigned char)str[len - 1] == target_newline
+             && (size_t) (int) len == len
+             && (int) len > 0)
            {
+             char *newstr;
+             tree offset_node, string_cst;
+
              /* Create a NUL-terminated string that's one char shorter
                 than the original, stripping off the trailing '\n'.  */
-             char *newstr = XALLOCAVEC (char, len);
-             memcpy (newstr, str, len - 1);
-             newstr[len - 1] = 0;
-
-             newarg = build_string_literal (len, newstr);
+             newarg = build_string_literal (len, str);
+             string_cst = string_constant (newarg, &offset_node);
+             gcc_checking_assert (string_cst
+                                  && (TREE_STRING_LENGTH (string_cst)
+                                      == (int) len)
+                                  && integer_zerop (offset_node)
+                                  && (unsigned char)
+                                     TREE_STRING_POINTER (string_cst)[len - 1]
+                                     == target_newline);
+             /* build_string_literal creates a new STRING_CST,
+                modify it in place to avoid double copying.  */
+             newstr = CONST_CAST (char *, TREE_STRING_POINTER (string_cst));
+             newstr[len - 1] = '\0';
              if (fn_puts)
                call = build_call_expr_loc (loc, fn_puts, 1, newarg);
            }
@@ -13333,49 +13122,52 @@ do_mpfr_ckconv (mpfr_srcptr m, tree type, int inexact)
   return NULL_TREE;
 }
 
-#ifdef HAVE_mpc
 /* Helper function for do_mpc_arg*().  Ensure M is a normal complex
    number and no overflow/underflow occurred.  INEXACT is true if M
    was not exactly calculated.  TYPE is the tree type for the result.
    This function assumes that you cleared the MPFR flags and then
    calculated M to see if anything subsequently set a flag prior to
-   entering this function.  Return NULL_TREE if any checks fail.  */
+   entering this function.  Return NULL_TREE if any checks fail, if
+   FORCE_CONVERT is true, then bypass the checks.  */
 
 static tree
-do_mpc_ckconv (mpc_srcptr m, tree type, int inexact)
+do_mpc_ckconv (mpc_srcptr m, tree type, int inexact, int force_convert)
 {
   /* Proceed iff we get a normal number, i.e. not NaN or Inf and no
      overflow/underflow occurred.  If -frounding-math, proceed iff the
      result of calling FUNC was exact.  */
-  if (mpfr_number_p (mpc_realref (m)) && mpfr_number_p (mpc_imagref (m))
-      && !mpfr_overflow_p () && !mpfr_underflow_p ()
-      && (!flag_rounding_math || !inexact))
+  if (force_convert
+      || (mpfr_number_p (mpc_realref (m)) && mpfr_number_p (mpc_imagref (m))
+         && !mpfr_overflow_p () && !mpfr_underflow_p ()
+         && (!flag_rounding_math || !inexact)))
     {
       REAL_VALUE_TYPE re, im;
 
-      real_from_mpfr (&re, mpc_realref (m), type, GMP_RNDN);
-      real_from_mpfr (&im, mpc_imagref (m), type, GMP_RNDN);
+      real_from_mpfr (&re, mpc_realref (m), TREE_TYPE (type), GMP_RNDN);
+      real_from_mpfr (&im, mpc_imagref (m), TREE_TYPE (type), GMP_RNDN);
       /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR values,
         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_isfinite (&re) && real_isfinite (&im)
-         && (re.cl == rvc_zero) == (mpfr_zero_p (mpc_realref (m)) != 0)
-         && (im.cl == rvc_zero) == (mpfr_zero_p (mpc_imagref (m)) != 0))
+      if (force_convert
+         || (real_isfinite (&re) && real_isfinite (&im)
+             && (re.cl == rvc_zero) == (mpfr_zero_p (mpc_realref (m)) != 0)
+             && (im.cl == rvc_zero) == (mpfr_zero_p (mpc_imagref (m)) != 0)))
         {
          REAL_VALUE_TYPE re_mode, im_mode;
 
          real_convert (&re_mode, TYPE_MODE (TREE_TYPE (type)), &re);
          real_convert (&im_mode, TYPE_MODE (TREE_TYPE (type)), &im);
          /* Proceed iff the specified mode can hold the value.  */
-         if (real_identical (&re_mode, &re) && real_identical (&im_mode, &im))
+         if (force_convert
+             || (real_identical (&re_mode, &re)
+                 && real_identical (&im_mode, &im)))
            return build_complex (type, build_real (TREE_TYPE (type), re_mode),
                                  build_real (TREE_TYPE (type), im_mode));
        }
     }
   return NULL_TREE;
 }
-#endif /* HAVE_mpc */
 
 /* If argument ARG is a REAL_CST, call the one-argument mpfr function
    FUNC on it and return the resulting value as a tree with type TYPE.
@@ -13392,7 +13184,7 @@ do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t),
              bool inclusive)
 {
   tree result = NULL_TREE;
-  
+
   STRIP_NOPS (arg);
 
   /* To proceed, MPFR must exactly represent the target floating point
@@ -13420,7 +13212,7 @@ do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t),
          mpfr_clear (m);
        }
     }
-  
+
   return result;
 }
 
@@ -13435,7 +13227,7 @@ do_mpfr_arg2 (tree arg1, tree arg2, tree type,
              int (*func)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t))
 {
   tree result = NULL_TREE;
-  
+
   STRIP_NOPS (arg1);
   STRIP_NOPS (arg2);
 
@@ -13465,7 +13257,7 @@ do_mpfr_arg2 (tree arg1, tree arg2, tree type,
          mpfr_clears (m1, m2, NULL);
        }
     }
-  
+
   return result;
 }
 
@@ -13480,7 +13272,7 @@ do_mpfr_arg3 (tree arg1, tree arg2, tree arg3, tree type,
              int (*func)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t))
 {
   tree result = NULL_TREE;
-  
+
   STRIP_NOPS (arg1);
   STRIP_NOPS (arg2);
   STRIP_NOPS (arg3);
@@ -13514,7 +13306,7 @@ do_mpfr_arg3 (tree arg1, tree arg2, tree arg3, tree type,
          mpfr_clears (m1, m2, m3, NULL);
        }
     }
-  
+
   return result;
 }
 
@@ -13530,9 +13322,9 @@ do_mpfr_sincos (tree arg, tree arg_sinp, tree arg_cosp)
 {
   tree const type = TREE_TYPE (arg);
   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.  */
   if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
@@ -13631,7 +13423,7 @@ do_mpfr_bessel_n (tree arg1, tree arg2, tree type,
          mpfr_clear (m);
        }
     }
-  
+
   return result;
 }
 
@@ -13645,10 +13437,10 @@ 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
@@ -13722,7 +13514,7 @@ 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.  */
@@ -13773,7 +13565,6 @@ do_mpfr_lgamma_r (tree arg, tree arg_sg, tree type)
   return result;
 }
 
-#ifdef HAVE_mpc
 /* If argument ARG is a COMPLEX_CST, call the one-argument mpc
    function FUNC on it and return the resulting value as a tree with
    type TYPE.  The mpfr precision is set to the precision of TYPE.  We
@@ -13784,7 +13575,7 @@ static tree
 do_mpc_arg1 (tree arg, tree type, int (*func)(mpc_ptr, mpc_srcptr, mpc_rnd_t))
 {
   tree result = NULL_TREE;
-  
+
   STRIP_NOPS (arg);
 
   /* To proceed, MPFR must exactly represent the target floating point
@@ -13805,13 +13596,13 @@ do_mpc_arg1 (tree arg, tree type, int (*func)(mpc_ptr, mpc_srcptr, mpc_rnd_t))
          const mpc_rnd_t crnd = fmt->round_towards_zero ? MPC_RNDZZ : MPC_RNDNN;
          int inexact;
          mpc_t m;
-         
+
          mpc_init2 (m, prec);
          mpfr_from_real (mpc_realref(m), re, rnd);
          mpfr_from_real (mpc_imagref(m), im, rnd);
          mpfr_clear_flags ();
          inexact = func (m, m, crnd);
-         result = do_mpc_ckconv (m, type, inexact);
+         result = do_mpc_ckconv (m, type, inexact, /*force_convert=*/ 0);
          mpc_clear (m);
        }
     }
@@ -13823,15 +13614,16 @@ do_mpc_arg1 (tree arg, tree type, int (*func)(mpc_ptr, mpc_srcptr, mpc_rnd_t))
    mpc function FUNC 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 function FUNC returns zero if the result
-   could be calculated exactly within the requested precision.  */
+   could be calculated exactly within the requested precision.  If
+   DO_NONFINITE is true, then fold expressions containing Inf or NaN
+   in the arguments and/or results.  */
 
-#ifdef HAVE_mpc_pow
-static tree
-do_mpc_arg2 (tree arg0, tree arg1, tree type,
+tree
+do_mpc_arg2 (tree arg0, tree arg1, tree type, int do_nonfinite,
             int (*func)(mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t))
 {
   tree result = NULL_TREE;
-  
+
   STRIP_NOPS (arg0);
   STRIP_NOPS (arg1);
 
@@ -13848,8 +13640,9 @@ do_mpc_arg2 (tree arg0, tree arg1, tree type,
       const REAL_VALUE_TYPE *const re1 = TREE_REAL_CST_PTR (TREE_REALPART (arg1));
       const REAL_VALUE_TYPE *const im1 = TREE_REAL_CST_PTR (TREE_IMAGPART (arg1));
 
-      if (real_isfinite (re0) && real_isfinite (im0)
-         && real_isfinite (re1) && real_isfinite (im1))
+      if (do_nonfinite
+         || (real_isfinite (re0) && real_isfinite (im0)
+             && real_isfinite (re1) && real_isfinite (im1)))
         {
          const struct real_format *const fmt =
            REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (type)));
@@ -13858,7 +13651,7 @@ do_mpc_arg2 (tree arg0, tree arg1, tree type,
          const mpc_rnd_t crnd = fmt->round_towards_zero ? MPC_RNDZZ : MPC_RNDNN;
          int inexact;
          mpc_t m0, m1;
-         
+
          mpc_init2 (m0, prec);
          mpc_init2 (m1, prec);
          mpfr_from_real (mpc_realref(m0), re0, rnd);
@@ -13867,7 +13660,7 @@ do_mpc_arg2 (tree arg0, tree arg1, tree type,
          mpfr_from_real (mpc_imagref(m1), im1, rnd);
          mpfr_clear_flags ();
          inexact = func (m0, m0, m1, crnd);
-         result = do_mpc_ckconv (m0, type, inexact);
+         result = do_mpc_ckconv (m0, type, inexact, do_nonfinite);
          mpc_clear (m0);
          mpc_clear (m1);
        }
@@ -13875,45 +13668,6 @@ do_mpc_arg2 (tree arg0, tree arg1, tree type,
 
   return result;
 }
-# endif
-#endif /* HAVE_mpc */
-
-/* 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;
-  location_t loc = gimple_location (stmt);
-
-  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_loc (loc, 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
@@ -13922,88 +13676,12 @@ gimple_rewrite_call_expr (gimple stmt, int skip, tree fndecl, int n, ...)
 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);
+  return fold_builtin_sprintf_chk_1 (gimple_location (stmt), nargs,
+                                    (nargs > 0
+                                     ? gimple_call_arg_ptr (stmt, 0)
+                                     : &error_mark_node), fcode);
 }
 
 /* Fold a call STMT to {,v}snprintf.  Return NULL_TREE if
@@ -14016,71 +13694,12 @@ 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;
+  int nargs = gimple_call_num_args (stmt);
 
-  return gimple_rewrite_call_expr (stmt, 5, fn, 3, dest, len, fmt);
+  return fold_builtin_snprintf_chk_1 (gimple_location (stmt), nargs,
+                                     (nargs > 0
+                                      ? gimple_call_arg_ptr (stmt, 0)
+                                      : &error_mark_node), maxlen, fcode);
 }
 
 /* Builtins with folding operations that operate on "..." arguments
@@ -14136,28 +13755,20 @@ fold_call_stmt (gimple stmt, bool ignore)
       && !gimple_call_va_arg_pack_p (stmt))
     {
       int nargs = gimple_call_num_args (stmt);
+      tree *args = (nargs > 0
+                   ? gimple_call_arg_ptr (stmt, 0)
+                   : &error_mark_node);
 
       if (avoid_folding_inline_builtin (fndecl))
        return NULL_TREE;
-      /* 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);
+         return targetm.fold_builtin (fndecl, nargs, args, 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 (loc, fndecl, args, nargs, ignore);
-           }
+           ret = fold_builtin_n (loc, fndecl, args, nargs, ignore);
          if (!ret)
            ret = gimple_fold_builtin_varargs (fndecl, stmt, ignore);
          if (ret)
@@ -14182,3 +13793,168 @@ fold_call_stmt (gimple stmt, bool ignore)
     }
   return NULL_TREE;
 }
+
+/* Look up the function in built_in_decls that corresponds to DECL
+   and set ASMSPEC as its user assembler name.  DECL must be a
+   function decl that declares a builtin.  */
+
+void
+set_builtin_user_assembler_name (tree decl, const char *asmspec)
+{
+  tree builtin;
+  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
+             && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
+             && asmspec != 0);
+
+  builtin = built_in_decls [DECL_FUNCTION_CODE (decl)];
+  set_user_assembler_name (builtin, asmspec);
+  switch (DECL_FUNCTION_CODE (decl))
+    {
+    case BUILT_IN_MEMCPY:
+      init_block_move_fn (asmspec);
+      memcpy_libfunc = set_user_assembler_libfunc ("memcpy", asmspec);
+      break;
+    case BUILT_IN_MEMSET:
+      init_block_clear_fn (asmspec);
+      memset_libfunc = set_user_assembler_libfunc ("memset", asmspec);
+      break;
+    case BUILT_IN_MEMMOVE:
+      memmove_libfunc = set_user_assembler_libfunc ("memmove", asmspec);
+      break;
+    case BUILT_IN_MEMCMP:
+      memcmp_libfunc = set_user_assembler_libfunc ("memcmp", asmspec);
+      break;
+    case BUILT_IN_ABORT:
+      abort_libfunc = set_user_assembler_libfunc ("abort", asmspec);
+      break;
+    case BUILT_IN_FFS:
+      if (INT_TYPE_SIZE < BITS_PER_WORD)
+       {
+         set_user_assembler_libfunc ("ffs", asmspec);
+         set_optab_libfunc (ffs_optab, mode_for_size (INT_TYPE_SIZE,
+                                                      MODE_INT, 0), "ffs");
+       }
+      break;
+    default:
+      break;
+    }
+}
+
+/* Return true if DECL is a builtin that expands to a constant or similarly
+   simple code.  */
+bool
+is_simple_builtin (tree decl)
+{
+  if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
+    switch (DECL_FUNCTION_CODE (decl))
+      {
+       /* Builtins that expand to constants.  */
+      case BUILT_IN_CONSTANT_P:
+      case BUILT_IN_EXPECT:
+      case BUILT_IN_OBJECT_SIZE:
+      case BUILT_IN_UNREACHABLE:
+       /* Simple register moves or loads from stack.  */
+      case BUILT_IN_RETURN_ADDRESS:
+      case BUILT_IN_EXTRACT_RETURN_ADDR:
+      case BUILT_IN_FROB_RETURN_ADDR:
+      case BUILT_IN_RETURN:
+      case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
+      case BUILT_IN_FRAME_ADDRESS:
+      case BUILT_IN_VA_END:
+      case BUILT_IN_STACK_SAVE:
+      case BUILT_IN_STACK_RESTORE:
+       /* Exception state returns or moves registers around.  */
+      case BUILT_IN_EH_FILTER:
+      case BUILT_IN_EH_POINTER:
+      case BUILT_IN_EH_COPY_VALUES:
+       return true;
+
+      default:
+       return false;
+      }
+
+  return false;
+}
+
+/* Return true if DECL is a builtin that is not expensive, i.e., they are
+   most probably expanded inline into reasonably simple code.  This is a
+   superset of is_simple_builtin.  */
+bool
+is_inexpensive_builtin (tree decl)
+{
+  if (!decl)
+    return false;
+  else if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_MD)
+    return true;
+  else if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
+    switch (DECL_FUNCTION_CODE (decl))
+      {
+      case BUILT_IN_ABS:
+      case BUILT_IN_ALLOCA:
+      case BUILT_IN_BSWAP32:
+      case BUILT_IN_BSWAP64:
+      case BUILT_IN_CLZ:
+      case BUILT_IN_CLZIMAX:
+      case BUILT_IN_CLZL:
+      case BUILT_IN_CLZLL:
+      case BUILT_IN_CTZ:
+      case BUILT_IN_CTZIMAX:
+      case BUILT_IN_CTZL:
+      case BUILT_IN_CTZLL:
+      case BUILT_IN_FFS:
+      case BUILT_IN_FFSIMAX:
+      case BUILT_IN_FFSL:
+      case BUILT_IN_FFSLL:
+      case BUILT_IN_IMAXABS:
+      case BUILT_IN_FINITE:
+      case BUILT_IN_FINITEF:
+      case BUILT_IN_FINITEL:
+      case BUILT_IN_FINITED32:
+      case BUILT_IN_FINITED64:
+      case BUILT_IN_FINITED128:
+      case BUILT_IN_FPCLASSIFY:
+      case BUILT_IN_ISFINITE:
+      case BUILT_IN_ISINF_SIGN:
+      case BUILT_IN_ISINF:
+      case BUILT_IN_ISINFF:
+      case BUILT_IN_ISINFL:
+      case BUILT_IN_ISINFD32:
+      case BUILT_IN_ISINFD64:
+      case BUILT_IN_ISINFD128:
+      case BUILT_IN_ISNAN:
+      case BUILT_IN_ISNANF:
+      case BUILT_IN_ISNANL:
+      case BUILT_IN_ISNAND32:
+      case BUILT_IN_ISNAND64:
+      case BUILT_IN_ISNAND128:
+      case BUILT_IN_ISNORMAL:
+      case BUILT_IN_ISGREATER:
+      case BUILT_IN_ISGREATEREQUAL:
+      case BUILT_IN_ISLESS:
+      case BUILT_IN_ISLESSEQUAL:
+      case BUILT_IN_ISLESSGREATER:
+      case BUILT_IN_ISUNORDERED:
+      case BUILT_IN_VA_ARG_PACK:
+      case BUILT_IN_VA_ARG_PACK_LEN:
+      case BUILT_IN_VA_COPY:
+      case BUILT_IN_TRAP:
+      case BUILT_IN_SAVEREGS:
+      case BUILT_IN_POPCOUNTL:
+      case BUILT_IN_POPCOUNTLL:
+      case BUILT_IN_POPCOUNTIMAX:
+      case BUILT_IN_POPCOUNT:
+      case BUILT_IN_PARITYL:
+      case BUILT_IN_PARITYLL:
+      case BUILT_IN_PARITYIMAX:
+      case BUILT_IN_PARITY:
+      case BUILT_IN_LABS:
+      case BUILT_IN_LLABS:
+      case BUILT_IN_PREFETCH:
+       return true;
+
+      default:
+       return is_simple_builtin (decl);
+      }
+
+  return false;
+}