OSDN Git Service

2007-08-06 Christopher D. Rickett <crickett@lanl.gov>
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index 5c6dd4d..39b4fcc 100644 (file)
@@ -7,7 +7,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -16,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
 
 #include "config.h"
 #include "system.h"
@@ -50,6 +49,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "tree-mudflap.h"
 #include "tree-flow.h"
 #include "value-prof.h"
 #include "tree-mudflap.h"
 #include "tree-flow.h"
 #include "value-prof.h"
+#include "diagnostic.h"
 
 #ifndef PAD_VARARGS_DOWN
 #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
 
 #ifndef PAD_VARARGS_DOWN
 #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
@@ -105,6 +105,7 @@ 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_va_start (tree);
 static rtx expand_builtin_va_end (tree);
 static rtx expand_builtin_va_copy (tree);
+static rtx expand_builtin_memchr (tree, rtx, enum machine_mode);
 static rtx expand_builtin_memcmp (tree, rtx, enum machine_mode);
 static rtx expand_builtin_strcmp (tree, rtx, enum machine_mode);
 static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode);
 static rtx expand_builtin_memcmp (tree, rtx, enum machine_mode);
 static rtx expand_builtin_strcmp (tree, rtx, enum machine_mode);
 static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode);
@@ -151,7 +152,7 @@ static tree fold_builtin_strlen (tree);
 static tree fold_builtin_inf (tree, int);
 static tree fold_builtin_nan (tree, tree, int);
 static tree rewrite_call_expr (tree, int, tree, int, ...);
 static tree fold_builtin_inf (tree, int);
 static tree fold_builtin_nan (tree, tree, int);
 static tree rewrite_call_expr (tree, int, tree, int, ...);
-static bool validate_arg (tree, enum tree_code code);
+static bool validate_arg (const_tree, enum tree_code code);
 static bool integer_valued_real_p (tree);
 static tree fold_trunc_transparent_mathfn (tree, tree);
 static bool readonly_data_expr (tree);
 static bool integer_valued_real_p (tree);
 static tree fold_trunc_transparent_mathfn (tree, tree);
 static bool readonly_data_expr (tree);
@@ -172,6 +173,7 @@ static tree fold_builtin_int_roundingfn (tree, tree);
 static tree fold_builtin_bitop (tree, tree);
 static tree fold_builtin_memory_op (tree, tree, tree, tree, bool, int);
 static tree fold_builtin_strchr (tree, tree, tree);
 static tree fold_builtin_bitop (tree, tree);
 static tree fold_builtin_memory_op (tree, tree, tree, tree, bool, int);
 static tree fold_builtin_strchr (tree, tree, tree);
+static tree fold_builtin_memchr (tree, tree, tree, tree);
 static tree fold_builtin_memcmp (tree, tree, tree);
 static tree fold_builtin_strcmp (tree, tree);
 static tree fold_builtin_strncmp (tree, tree, tree);
 static tree fold_builtin_memcmp (tree, tree, tree);
 static tree fold_builtin_strcmp (tree, tree);
 static tree fold_builtin_strncmp (tree, tree, tree);
@@ -229,6 +231,13 @@ static tree do_mpfr_arg2 (tree, tree, tree,
 static tree do_mpfr_arg3 (tree, tree, tree, tree,
                          int (*)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t));
 static tree do_mpfr_sincos (tree, tree, tree);
 static tree do_mpfr_arg3 (tree, tree, tree, tree,
                          int (*)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t));
 static tree do_mpfr_sincos (tree, tree, tree);
+#if MPFR_VERSION >= MPFR_VERSION_NUM(2,3,0)
+static tree do_mpfr_bessel_n (tree, tree, tree,
+                             int (*)(mpfr_ptr, long, mpfr_srcptr, mp_rnd_t),
+                             const REAL_VALUE_TYPE *, bool);
+static tree do_mpfr_remquo (tree, tree, tree);
+static tree do_mpfr_lgamma_r (tree, tree, tree);
+#endif
 
 /* Return true if NODE should be considered for inline expansion regardless
    of the optimization level.  This means whenever a function is invoked with
 
 /* Return true if NODE should be considered for inline expansion regardless
    of the optimization level.  This means whenever a function is invoked with
@@ -282,7 +291,7 @@ get_pointer_alignment (tree exp, unsigned int max_align)
          align = MIN (inner, max_align);
          break;
 
          align = MIN (inner, max_align);
          break;
 
-       case PLUS_EXPR:
+       case POINTER_PLUS_EXPR:
          /* If sum of pointer + int, restrict our maximum alignment to that
             imposed by the integer.  If not, we can't do any better than
             ALIGN.  */
          /* If sum of pointer + int, restrict our maximum alignment to that
             imposed by the integer.  If not, we can't do any better than
             ALIGN.  */
@@ -340,9 +349,7 @@ get_pointer_alignment (tree exp, unsigned int max_align)
              else if (offset)
                inner = MIN (inner, BITS_PER_UNIT);
            }
              else if (offset)
                inner = MIN (inner, BITS_PER_UNIT);
            }
-         if (TREE_CODE (exp) == FUNCTION_DECL)
-           align = FUNCTION_BOUNDARY;
-         else if (DECL_P (exp))
+         if (DECL_P (exp))
            align = MIN (inner, DECL_ALIGN (exp));
 #ifdef CONSTANT_ALIGNMENT
          else if (CONSTANT_CLASS_P (exp))
            align = MIN (inner, DECL_ALIGN (exp));
 #ifdef CONSTANT_ALIGNMENT
          else if (CONSTANT_CLASS_P (exp))
@@ -687,8 +694,7 @@ expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
      need to go on during alloca.  */
   current_function_calls_setjmp = 1;
 
      need to go on during alloca.  */
   current_function_calls_setjmp = 1;
 
-  /* Set this so all the registers get saved in our frame; we need to be
-     able to copy the saved values for any registers from frames we unwind.  */
+  /* We have a nonlocal label.   */
   current_function_has_nonlocal_label = 1;
 }
 
   current_function_has_nonlocal_label = 1;
 }
 
@@ -753,12 +759,10 @@ expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
 #endif
       { /* Nothing */ }
 
 #endif
       { /* Nothing */ }
 
-  /* @@@ This is a kludge.  Not all machine descriptions define a blockage
-     insn, but we must not allow the code we just generated to be reordered
-     by scheduling.  Specifically, the update of the frame pointer must
-     happen immediately, not later.  So emit an ASM_INPUT to act as blockage
-     insn.  */
-  emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
+  /* We must not allow the code we just generated to be reordered by
+     scheduling.  Specifically, the update of the frame pointer must
+     happen immediately, not later.  */
+  emit_insn (gen_blockage ());
 }
 
 /* __builtin_longjmp is passed a pointer to an array of five words (not
 }
 
 /* __builtin_longjmp is passed a pointer to an array of five words (not
@@ -1645,6 +1649,11 @@ expand_builtin_classify_type (tree exp)
   case BUILT_IN_MATHFN: case BUILT_IN_MATHFN##F: case BUILT_IN_MATHFN##L: \
   fcode = BUILT_IN_MATHFN; fcodef = BUILT_IN_MATHFN##F ; \
   fcodel = BUILT_IN_MATHFN##L ; break;
   case BUILT_IN_MATHFN: case BUILT_IN_MATHFN##F: case BUILT_IN_MATHFN##L: \
   fcode = BUILT_IN_MATHFN; fcodef = BUILT_IN_MATHFN##F ; \
   fcodel = BUILT_IN_MATHFN##L ; break;
+/* Similar to above, but appends _R after any F/L suffix.  */
+#define CASE_MATHFN_REENT(BUILT_IN_MATHFN) \
+  case BUILT_IN_MATHFN##_R: case BUILT_IN_MATHFN##F_R: case BUILT_IN_MATHFN##L_R: \
+  fcode = BUILT_IN_MATHFN##_R; fcodef = BUILT_IN_MATHFN##F_R ; \
+  fcodel = BUILT_IN_MATHFN##L_R ; break;
 
 /* Return mathematic function equivalent to FN but operating directly
    on TYPE, if available.  If we can't do the conversion, return zero.  */
 
 /* Return mathematic function equivalent to FN but operating directly
    on TYPE, if available.  If we can't do the conversion, return zero.  */
@@ -1684,6 +1693,7 @@ mathfn_built_in (tree type, enum built_in_function fn)
       CASE_MATHFN (BUILT_IN_FMOD)
       CASE_MATHFN (BUILT_IN_FREXP)
       CASE_MATHFN (BUILT_IN_GAMMA)
       CASE_MATHFN (BUILT_IN_FMOD)
       CASE_MATHFN (BUILT_IN_FREXP)
       CASE_MATHFN (BUILT_IN_GAMMA)
+      CASE_MATHFN_REENT (BUILT_IN_GAMMA) /* GAMMA_R */
       CASE_MATHFN (BUILT_IN_HUGE_VAL)
       CASE_MATHFN (BUILT_IN_HYPOT)
       CASE_MATHFN (BUILT_IN_ILOGB)
       CASE_MATHFN (BUILT_IN_HUGE_VAL)
       CASE_MATHFN (BUILT_IN_HYPOT)
       CASE_MATHFN (BUILT_IN_ILOGB)
@@ -1696,6 +1706,7 @@ mathfn_built_in (tree type, enum built_in_function fn)
       CASE_MATHFN (BUILT_IN_LDEXP)
       CASE_MATHFN (BUILT_IN_LFLOOR)
       CASE_MATHFN (BUILT_IN_LGAMMA)
       CASE_MATHFN (BUILT_IN_LDEXP)
       CASE_MATHFN (BUILT_IN_LFLOOR)
       CASE_MATHFN (BUILT_IN_LGAMMA)
+      CASE_MATHFN_REENT (BUILT_IN_LGAMMA) /* LGAMMA_R */
       CASE_MATHFN (BUILT_IN_LLCEIL)
       CASE_MATHFN (BUILT_IN_LLFLOOR)
       CASE_MATHFN (BUILT_IN_LLRINT)
       CASE_MATHFN (BUILT_IN_LLCEIL)
       CASE_MATHFN (BUILT_IN_LLFLOOR)
       CASE_MATHFN (BUILT_IN_LLRINT)
@@ -1882,7 +1893,7 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
          exp = build_call_expr (fndecl, 1, arg);
        }
 
          exp = build_call_expr (fndecl, 1, arg);
        }
 
-      op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+      op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
 
       start_sequence ();
 
 
       start_sequence ();
 
@@ -2135,7 +2146,7 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
          exp = build_call_expr (fndecl, 1, arg);
        }
 
          exp = build_call_expr (fndecl, 1, arg);
        }
 
-      op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+      op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
 
       start_sequence ();
 
 
       start_sequence ();
 
@@ -2194,8 +2205,8 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
 static rtx
 expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
 {
 static rtx
 expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
 {
-  optab builtin_optab;
-  enum insn_code icode;
+  optab builtin_optab = 0;
+  enum insn_code icode = CODE_FOR_nothing;
   rtx op0;
   tree fndecl = get_callee_fndecl (exp);
   enum machine_mode mode;
   rtx op0;
   tree fndecl = get_callee_fndecl (exp);
   enum machine_mode mode;
@@ -2213,6 +2224,11 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
       errno_set = true; builtin_optab = ilogb_optab; break;
     CASE_FLT_FN (BUILT_IN_ISINF):
       builtin_optab = isinf_optab; break;
       errno_set = true; builtin_optab = ilogb_optab; break;
     CASE_FLT_FN (BUILT_IN_ISINF):
       builtin_optab = isinf_optab; break;
+    case BUILT_IN_ISNORMAL:
+    case BUILT_IN_ISFINITE:
+    CASE_FLT_FN (BUILT_IN_FINITE):
+      /* These builtins have no optabs (yet).  */
+      break;
     default:
       gcc_unreachable ();
     }
     default:
       gcc_unreachable ();
     }
@@ -2224,7 +2240,8 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
   /* Optab mode depends on the mode of the input argument.  */
   mode = TYPE_MODE (TREE_TYPE (arg));
 
   /* Optab mode depends on the mode of the input argument.  */
   mode = TYPE_MODE (TREE_TYPE (arg));
 
-  icode = builtin_optab->handlers[(int) mode].insn_code;
+  if (builtin_optab)
+    icode = builtin_optab->handlers[(int) mode].insn_code;
  
   /* Before working hard, check whether the instruction is available.  */
   if (icode != CODE_FOR_nothing)
  
   /* Before working hard, check whether the instruction is available.  */
   if (icode != CODE_FOR_nothing)
@@ -2247,7 +2264,7 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
          exp = build_call_expr (fndecl, 1, arg);
        }
 
          exp = build_call_expr (fndecl, 1, arg);
        }
 
-      op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+      op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
 
       if (mode != GET_MODE (op0))
        op0 = convert_to_mode (mode, op0, 0);
 
       if (mode != GET_MODE (op0))
        op0 = convert_to_mode (mode, op0, 0);
@@ -2258,6 +2275,68 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
       return target;
     }
 
       return target;
     }
 
+  /* If there is no optab, try generic code.  */
+  switch (DECL_FUNCTION_CODE (fndecl))
+    {
+      tree result;
+
+    CASE_FLT_FN (BUILT_IN_ISINF):
+      {
+       /* isinf(x) -> isgreater(fabs(x),DBL_MAX).  */
+       tree const isgr_fn = built_in_decls[BUILT_IN_ISGREATER];
+       tree const type = TREE_TYPE (arg);
+       REAL_VALUE_TYPE r;
+       char buf[128];
+
+       get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
+       real_from_string (&r, buf);
+       result = build_call_expr (isgr_fn, 2,
+                                 fold_build1 (ABS_EXPR, type, arg),
+                                 build_real (type, r));
+       return expand_expr (result, target, VOIDmode, EXPAND_NORMAL);
+      }
+    CASE_FLT_FN (BUILT_IN_FINITE):
+    case BUILT_IN_ISFINITE:
+      {
+       /* isfinite(x) -> islessequal(fabs(x),DBL_MAX).  */
+       tree const isle_fn = built_in_decls[BUILT_IN_ISLESSEQUAL];
+       tree const type = TREE_TYPE (arg);
+       REAL_VALUE_TYPE r;
+       char buf[128];
+
+       get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
+       real_from_string (&r, buf);
+       result = build_call_expr (isle_fn, 2,
+                                 fold_build1 (ABS_EXPR, type, arg),
+                                 build_real (type, r));
+       return expand_expr (result, target, VOIDmode, EXPAND_NORMAL);
+      }
+    case BUILT_IN_ISNORMAL:
+      {
+       /* isnormal(x) -> isgreaterequal(fabs(x),DBL_MIN) &
+          islessequal(fabs(x),DBL_MAX).  */
+       tree const isle_fn = built_in_decls[BUILT_IN_ISLESSEQUAL];
+       tree const isge_fn = built_in_decls[BUILT_IN_ISGREATEREQUAL];
+       tree const type = TREE_TYPE (arg);
+       REAL_VALUE_TYPE rmax, rmin;
+       char buf[128];
+
+       get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
+       real_from_string (&rmax, buf);
+       sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (mode)->emin - 1);
+       real_from_string (&rmin, buf);
+       arg = builtin_save_expr (fold_build1 (ABS_EXPR, type, arg));
+       result = build_call_expr (isle_fn, 2, arg,
+                                 build_real (type, rmax));
+       result = fold_build2 (BIT_AND_EXPR, integer_type_node, result,
+                             build_call_expr (isge_fn, 2, arg,
+                                              build_real (type, rmin)));
+       return expand_expr (result, target, VOIDmode, EXPAND_NORMAL);
+      }
+    default:
+      break;
+    }
+
   target = expand_call (exp, target, target == const0_rtx);
 
   return target;
   target = expand_call (exp, target, target == const0_rtx);
 
   return target;
@@ -2339,7 +2418,7 @@ expand_builtin_cexpi (tree exp, rtx target, rtx subtarget)
       op1 = gen_reg_rtx (mode);
       op2 = gen_reg_rtx (mode);
 
       op1 = gen_reg_rtx (mode);
       op2 = gen_reg_rtx (mode);
 
-      op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+      op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
 
       /* Compute into op1 and op2.  */
       expand_twoval_unop (sincos_optab, op0, op2, op1, 0);
 
       /* Compute into op1 and op2.  */
       expand_twoval_unop (sincos_optab, op0, op2, op1, 0);
@@ -2376,9 +2455,6 @@ expand_builtin_cexpi (tree exp, rtx target, rtx subtarget)
       tree call, fn = NULL_TREE, narg;
       tree ctype = build_complex_type (type);
 
       tree call, fn = NULL_TREE, narg;
       tree ctype = build_complex_type (type);
 
-      /* We can expand via the C99 cexp function.  */
-      gcc_assert (TARGET_C99_FUNCTIONS);
-
       if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIF)
        fn = built_in_decls[BUILT_IN_CEXPF];
       else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPI)
       if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIF)
        fn = built_in_decls[BUILT_IN_CEXPF];
       else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPI)
@@ -2387,20 +2463,40 @@ expand_builtin_cexpi (tree exp, rtx target, rtx subtarget)
        fn = built_in_decls[BUILT_IN_CEXPL];
       else
        gcc_unreachable ();
        fn = built_in_decls[BUILT_IN_CEXPL];
       else
        gcc_unreachable ();
+
+      /* If we don't have a decl for cexp create one.  This is the
+        friendliest fallback if the user calls __builtin_cexpi
+        without full target C99 function support.  */
+      if (fn == NULL_TREE)
+       {
+         tree fntype;
+         const char *name = NULL;
+
+         if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIF)
+           name = "cexpf";
+         else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPI)
+           name = "cexp";
+         else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIL)
+           name = "cexpl";
+
+         fntype = build_function_type_list (ctype, ctype, NULL_TREE);
+         fn = build_fn_decl (name, fntype);
+       }
+
       narg = fold_build2 (COMPLEX_EXPR, ctype,
                          build_real (type, dconst0), arg);
 
       /* Make sure not to fold the cexp call again.  */
       call = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
       narg = fold_build2 (COMPLEX_EXPR, ctype,
                          build_real (type, dconst0), arg);
 
       /* Make sure not to fold the cexp call again.  */
       call = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
-      return expand_expr (build_call_nary (ctype, call, 1, arg), 
-                         target, VOIDmode, 0);
+      return expand_expr (build_call_nary (ctype, call, 1, narg), 
+                         target, VOIDmode, EXPAND_NORMAL);
     }
 
   /* Now build the proper return type.  */
   return expand_expr (build2 (COMPLEX_EXPR, build_complex_type (type),
                              make_tree (TREE_TYPE (arg), op2),
                              make_tree (TREE_TYPE (arg), op1)),
     }
 
   /* Now build the proper return type.  */
   return expand_expr (build2 (COMPLEX_EXPR, build_complex_type (type),
                              make_tree (TREE_TYPE (arg), op2),
                              make_tree (TREE_TYPE (arg), op1)),
-                     target, VOIDmode, 0);
+                     target, VOIDmode, EXPAND_NORMAL);
 }
 
 /* Expand a call to one of the builtin rounding functions gcc defines
 }
 
 /* Expand a call to one of the builtin rounding functions gcc defines
@@ -2460,7 +2556,7 @@ expand_builtin_int_roundingfn (tree exp, rtx target, rtx subtarget)
       exp = build_call_expr (fndecl, 1, arg);
     }
 
       exp = build_call_expr (fndecl, 1, arg);
     }
 
-  op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+  op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
 
   start_sequence ();
 
 
   start_sequence ();
 
@@ -2480,9 +2576,51 @@ expand_builtin_int_roundingfn (tree exp, rtx target, rtx subtarget)
 
   /* Fall back to floating point rounding optab.  */
   fallback_fndecl = mathfn_built_in (TREE_TYPE (arg), fallback_fn);
 
   /* Fall back to floating point rounding optab.  */
   fallback_fndecl = mathfn_built_in (TREE_TYPE (arg), fallback_fn);
-  /* We shouldn't get here on targets without TARGET_C99_FUNCTIONS.
-     ??? Perhaps convert (int)floorf(x) into (int)floor((double)x).  */
-  gcc_assert (fallback_fndecl != NULL_TREE);
+
+  /* For non-C99 targets we may end up without a fallback fndecl here
+     if the user called __builtin_lfloor directly.  In this case emit
+     a call to the floor/ceil variants nevertheless.  This should result
+     in the best user experience for not full C99 targets.  */
+  if (fallback_fndecl == NULL_TREE)
+    {
+      tree fntype;
+      const char *name = NULL;
+
+      switch (DECL_FUNCTION_CODE (fndecl))
+       {
+       case BUILT_IN_LCEIL:
+       case BUILT_IN_LLCEIL:
+         name = "ceil";
+         break;
+       case BUILT_IN_LCEILF:
+       case BUILT_IN_LLCEILF:
+         name = "ceilf";
+         break;
+       case BUILT_IN_LCEILL:
+       case BUILT_IN_LLCEILL:
+         name = "ceill";
+         break;
+       case BUILT_IN_LFLOOR:
+       case BUILT_IN_LLFLOOR:
+         name = "floor";
+         break;
+       case BUILT_IN_LFLOORF:
+       case BUILT_IN_LLFLOORF:
+         name = "floorf";
+         break;
+       case BUILT_IN_LFLOORL:
+       case BUILT_IN_LLFLOORL:
+         name = "floorl";
+         break;
+       default:
+         gcc_unreachable ();
+       }
+
+      fntype = build_function_type_list (TREE_TYPE (arg),
+                                        TREE_TYPE (arg), NULL_TREE);
+      fallback_fndecl = build_fn_decl (name, fntype);
+    }
+
   exp = build_call_expr (fallback_fndecl, 1, arg);
 
   tmp = expand_normal (exp);
   exp = build_call_expr (fallback_fndecl, 1, arg);
 
   tmp = expand_normal (exp);
@@ -2547,7 +2685,7 @@ expand_builtin_int_roundingfn_2 (tree exp, rtx target, rtx subtarget)
       exp = build_call_expr (fndecl, 1, arg);
     }
 
       exp = build_call_expr (fndecl, 1, arg);
     }
 
-  op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+  op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
 
   start_sequence ();
 
 
   start_sequence ();
 
@@ -2814,7 +2952,7 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
              && !optimize_size
              && powi_cost (n) <= POWI_MAX_MULTS)))
     {
              && !optimize_size
              && powi_cost (n) <= POWI_MAX_MULTS)))
     {
-      op = expand_expr (arg0, subtarget, VOIDmode, 0);
+      op = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
       if (n != 1)
        {
          op = force_reg (mode, op);
       if (n != 1)
        {
          op = force_reg (mode, op);
@@ -2843,7 +2981,7 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
          op = expand_builtin (call_expr, NULL_RTX, subtarget, mode, 0);
          if (n != 1)
            {
          op = expand_builtin (call_expr, NULL_RTX, subtarget, mode, 0);
          if (n != 1)
            {
-             op2 = expand_expr (narg0, subtarget, VOIDmode, 0);
+             op2 = expand_expr (narg0, subtarget, VOIDmode, EXPAND_NORMAL);
              op2 = force_reg (mode, op2);
              op2 = expand_powi (op2, mode, abs (n / 2));
              op = expand_simple_binop (mode, MULT, op, op2, NULL_RTX,
              op2 = force_reg (mode, op2);
              op2 = expand_powi (op2, mode, abs (n / 2));
              op = expand_simple_binop (mode, MULT, op, op2, NULL_RTX,
@@ -2887,7 +3025,7 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
                                      0, OPTAB_LIB_WIDEN);
          if (n != 1)
            {
                                      0, OPTAB_LIB_WIDEN);
          if (n != 1)
            {
-             op2 = expand_expr (narg0, subtarget, VOIDmode, 0);
+             op2 = expand_expr (narg0, subtarget, VOIDmode, EXPAND_NORMAL);
              op2 = force_reg (mode, op2);
              op2 = expand_powi (op2, mode, abs (n / 3));
              op = expand_simple_binop (mode, MULT, op, op2, NULL_RTX,
              op2 = force_reg (mode, op2);
              op2 = expand_powi (op2, mode, abs (n / 3));
              op = expand_simple_binop (mode, MULT, op, op2, NULL_RTX,
@@ -2941,7 +3079,7 @@ expand_builtin_powi (tree exp, rtx target, rtx subtarget)
              || (! optimize_size
                  && powi_cost (n) <= POWI_MAX_MULTS)))
        {
              || (! optimize_size
                  && powi_cost (n) <= POWI_MAX_MULTS)))
        {
-         op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
+         op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
          op0 = force_reg (mode, op0);
          return expand_powi (op0, mode, n);
        }
          op0 = force_reg (mode, op0);
          return expand_powi (op0, mode, n);
        }
@@ -2955,10 +3093,10 @@ expand_builtin_powi (tree exp, rtx target, rtx subtarget)
   if (target == NULL_RTX)
     target = gen_reg_rtx (mode);
 
   if (target == NULL_RTX)
     target = gen_reg_rtx (mode);
 
-  op0 = expand_expr (arg0, subtarget, mode, 0);
+  op0 = expand_expr (arg0, subtarget, mode, EXPAND_NORMAL);
   if (GET_MODE (op0) != mode)
     op0 = convert_to_mode (mode, op0, 0);
   if (GET_MODE (op0) != mode)
     op0 = convert_to_mode (mode, op0, 0);
-  op1 = expand_expr (arg1, 0, mode2, 0);
+  op1 = expand_expr (arg1, NULL_RTX, mode2, EXPAND_NORMAL);
   if (GET_MODE (op1) != mode2)
     op1 = convert_to_mode (mode2, op1, 0);
 
   if (GET_MODE (op1) != mode2)
     op1 = convert_to_mode (mode2, op1, 0);
 
@@ -3411,6 +3549,7 @@ expand_builtin_memmove_args (tree dest, tree src, tree len,
 
   if (result)
     {
 
   if (result)
     {
+      STRIP_TYPE_NOPS (result);
       while (TREE_CODE (result) == COMPOUND_EXPR)
        {
          expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
       while (TREE_CODE (result) == COMPOUND_EXPR)
        {
          expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
@@ -3919,6 +4058,26 @@ expand_builtin_bzero (tree exp)
                                     const0_rtx, VOIDmode, exp);
 }
 
                                     const0_rtx, VOIDmode, exp);
 }
 
+/* Expand a call to the memchr builtin.  Return NULL_RTX if we failed the
+   caller should emit a normal call, otherwise try to get the result
+   in TARGET, if convenient (and in mode MODE if that's convenient).  */
+
+static rtx
+expand_builtin_memchr (tree exp, rtx target, enum machine_mode mode)
+{
+  if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE,
+                       INTEGER_TYPE, VOID_TYPE))
+    {
+      tree type = TREE_TYPE (exp);
+      tree result = fold_builtin_memchr (CALL_EXPR_ARG (exp, 0),
+                                        CALL_EXPR_ARG (exp, 1),
+                                        CALL_EXPR_ARG (exp, 2), type);
+      if (result)
+       return expand_expr (result, target, mode, EXPAND_NORMAL);
+    }
+  return NULL_RTX;
+}
+
 /* Expand expression EXP, which is a call to the memcmp built-in function.
    Return NULL_RTX if we failed and the
    caller should emit a normal call, otherwise try to get the result in
 /* 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
@@ -4340,10 +4499,9 @@ expand_builtin_strcat (tree fndecl, tree exp, rtx target, enum machine_mode mode
 
          /* Create strlen (dst).  */
          newdst = build_call_expr (strlen_fn, 1, dst);
 
          /* Create strlen (dst).  */
          newdst = build_call_expr (strlen_fn, 1, dst);
-         /* Create (dst + (cast) strlen (dst)).  */
-         newdst = fold_convert (TREE_TYPE (dst), newdst);
-         newdst = fold_build2 (PLUS_EXPR, TREE_TYPE (dst), dst, newdst);
+         /* Create (dst p+ strlen (dst)).  */
 
 
+         newdst = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (dst), dst, newdst);
          newdst = builtin_save_expr (newdst);
 
          if (!expand_builtin_strcpy_args (fndecl, newdst, newsrc, target, mode))
          newdst = builtin_save_expr (newdst);
 
          if (!expand_builtin_strcpy_args (fndecl, newdst, newsrc, target, mode))
@@ -4493,7 +4651,7 @@ expand_builtin_next_arg (void)
 {
   /* Checking arguments is already done in fold_builtin_next_arg
      that must be called before this function.  */
 {
   /* Checking arguments is already done in fold_builtin_next_arg
      that must be called before this function.  */
-  return expand_binop (Pmode, add_optab,
+  return expand_binop (ptr_mode, add_optab,
                       current_function_internal_arg_pointer,
                       current_function_arg_offset_rtx,
                       NULL_RTX, 0, OPTAB_LIB_WIDEN);
                       current_function_internal_arg_pointer,
                       current_function_arg_offset_rtx,
                       NULL_RTX, 0, OPTAB_LIB_WIDEN);
@@ -4556,13 +4714,8 @@ std_build_builtin_va_list (void)
 void
 std_expand_builtin_va_start (tree valist, rtx nextarg)
 {
 void
 std_expand_builtin_va_start (tree valist, rtx nextarg)
 {
-  tree t;
-
-  t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist,
-             make_tree (ptr_type_node, nextarg));
-  TREE_SIDE_EFFECTS (t) = 1;
-
-  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+  rtx va_r = expand_expr (valist, NULL_RTX, VOIDmode, EXPAND_WRITE);
+  convert_move (va_r, nextarg, 0);
 }
 
 /* Expand EXP, a call to __builtin_va_start.  */
 }
 
 /* Expand EXP, a call to __builtin_va_start.  */
@@ -4626,14 +4779,16 @@ std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
   if (boundary > align
       && !integer_zerop (TYPE_SIZE (type)))
     {
   if (boundary > align
       && !integer_zerop (TYPE_SIZE (type)))
     {
-      t = fold_convert (TREE_TYPE (valist), size_int (boundary - 1));
       t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
       t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
-                 build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t));
+                 fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (valist),
+                              valist_tmp, size_int (boundary - 1)));
       gimplify_and_add (t, pre_p);
 
       gimplify_and_add (t, pre_p);
 
-      t = fold_convert (TREE_TYPE (valist), size_int (-boundary));
+      t = fold_convert (sizetype, valist_tmp);
       t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
       t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
-                 build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist_tmp, t));
+                 fold_convert (TREE_TYPE (valist),
+                               fold_build2 (BIT_AND_EXPR, sizetype, t,
+                                            size_int (-boundary))));
       gimplify_and_add (t, pre_p);
     }
   else
       gimplify_and_add (t, pre_p);
     }
   else
@@ -4664,13 +4819,11 @@ std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
       t = fold_build2 (GT_EXPR, sizetype, rounded_size, size_int (align));
       t = fold_build3 (COND_EXPR, sizetype, t, size_zero_node,
                       size_binop (MINUS_EXPR, rounded_size, type_size));
       t = fold_build2 (GT_EXPR, sizetype, rounded_size, size_int (align));
       t = fold_build3 (COND_EXPR, sizetype, t, size_zero_node,
                       size_binop (MINUS_EXPR, rounded_size, type_size));
-      t = fold_convert (TREE_TYPE (addr), t);
-      addr = fold_build2 (PLUS_EXPR, TREE_TYPE (addr), addr, t);
+      addr = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (addr), addr, t);
     }
 
   /* Compute new value for AP.  */
     }
 
   /* Compute new value for AP.  */
-  t = fold_convert (TREE_TYPE (valist), rounded_size);
-  t = build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t);
+  t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (valist), valist_tmp, rounded_size);
   t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
   gimplify_and_add (t, pre_p);
 
   t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
   gimplify_and_add (t, pre_p);
 
@@ -4958,7 +5111,7 @@ expand_builtin_bswap (tree exp, rtx target, rtx subtarget)
 
   arg = CALL_EXPR_ARG (exp, 0);
   mode = TYPE_MODE (TREE_TYPE (arg));
 
   arg = CALL_EXPR_ARG (exp, 0);
   mode = TYPE_MODE (TREE_TYPE (arg));
-  op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+  op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
 
   target = expand_unop (mode, bswap_optab, op0, target, 1);
 
 
   target = expand_unop (mode, bswap_optab, op0, target, 1);
 
@@ -4982,7 +5135,8 @@ expand_builtin_unop (enum machine_mode target_mode, tree exp, rtx target,
     return NULL_RTX;
 
   /* Compute the argument.  */
     return NULL_RTX;
 
   /* Compute the argument.  */
-  op0 = expand_expr (CALL_EXPR_ARG (exp, 0), subtarget, VOIDmode, 0);
+  op0 = expand_expr (CALL_EXPR_ARG (exp, 0), subtarget,
+                    VOIDmode, EXPAND_NORMAL);
   /* Compute op, into TARGET if possible.
      Set TARGET to wherever the result comes back.  */
   target = expand_unop (TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 0))),
   /* Compute op, into TARGET if possible.
      Set TARGET to wherever the result comes back.  */
   target = expand_unop (TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 0))),
@@ -5027,7 +5181,8 @@ expand_builtin_expect (tree exp, rtx target)
 
   target = expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
   /* When guessing was done, the hints should be already stripped away.  */
 
   target = expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
   /* When guessing was done, the hints should be already stripped away.  */
-  gcc_assert (!flag_guess_branch_prob);
+  gcc_assert (!flag_guess_branch_prob
+             || optimize == 0 || errorcount || sorrycount);
   return target;
 }
 
   return target;
 }
 
@@ -5061,7 +5216,7 @@ expand_builtin_fabs (tree exp, rtx target, rtx subtarget)
 
   arg = CALL_EXPR_ARG (exp, 0);
   mode = TYPE_MODE (TREE_TYPE (arg));
 
   arg = CALL_EXPR_ARG (exp, 0);
   mode = TYPE_MODE (TREE_TYPE (arg));
-  op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+  op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
   return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1));
 }
 
   return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1));
 }
 
@@ -5417,6 +5572,59 @@ expand_builtin_profile_func (bool exitp)
   return const0_rtx;
 }
 
   return const0_rtx;
 }
 
+/* Expand a call to __builtin___clear_cache.  */
+
+static rtx
+expand_builtin___clear_cache (tree exp ATTRIBUTE_UNUSED)
+{
+#ifndef HAVE_clear_cache
+#ifdef CLEAR_INSN_CACHE
+  /* There is no "clear_cache" insn, and __clear_cache() in libgcc
+     does something.  Just do the default expansion to a call to
+     __clear_cache().  */
+  return NULL_RTX;
+#else
+  /* There is no "clear_cache" insn, and __clear_cache() in libgcc
+     does nothing.  There is no need to call it.  Do nothing.  */
+  return const0_rtx;
+#endif /* CLEAR_INSN_CACHE */
+#else
+  /* We have a "clear_cache" insn, and it will handle everything.  */
+  tree begin, end;
+  rtx begin_rtx, end_rtx;
+  enum insn_code icode;
+
+  /* We must not expand to a library call.  If we did, any
+     fallback library function in libgcc that might contain a call to
+     __builtin___clear_cache() would recurse infinitely.  */
+  if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
+    {
+      error ("both arguments to %<__builtin___clear_cache%> must be pointers");
+      return const0_rtx;
+    }
+
+  if (HAVE_clear_cache)
+    {
+      icode = CODE_FOR_clear_cache;
+
+      begin = CALL_EXPR_ARG (exp, 0);
+      begin_rtx = expand_expr (begin, NULL_RTX, Pmode, EXPAND_NORMAL);
+      begin_rtx = convert_memory_address (Pmode, begin_rtx);
+      if (!insn_data[icode].operand[0].predicate (begin_rtx, Pmode))
+       begin_rtx = copy_to_mode_reg (Pmode, begin_rtx);
+
+      end = CALL_EXPR_ARG (exp, 1);
+      end_rtx = expand_expr (end, NULL_RTX, Pmode, EXPAND_NORMAL);
+      end_rtx = convert_memory_address (Pmode, end_rtx);
+      if (!insn_data[icode].operand[1].predicate (end_rtx, Pmode))
+       end_rtx = copy_to_mode_reg (Pmode, end_rtx);
+
+      emit_insn (gen_clear_cache (begin_rtx, end_rtx));
+    }
+  return const0_rtx;
+#endif /* HAVE_clear_cache */
+}
+
 /* Given a trampoline address, make sure it satisfies TRAMPOLINE_ALIGNMENT.  */
 
 static rtx
 /* Given a trampoline address, make sure it satisfies TRAMPOLINE_ALIGNMENT.  */
 
 static rtx
@@ -5494,11 +5702,15 @@ expand_builtin_adjust_trampoline (tree exp)
   return tramp;
 }
 
   return tramp;
 }
 
-/* Expand a call to the built-in signbit, signbitf or signbitl function.
-   Return NULL_RTX if a normal call should be emitted rather than expanding
-   the function in-line.  EXP is the expression that is a call to the builtin
-   function; if convenient, the result should be placed in TARGET.  */
-
+/* Expand the call EXP to the built-in signbit, signbitf or signbitl
+   function.  The function first checks whether the back end provides
+   an insn to implement signbit for the respective mode.  If not, it
+   checks whether the floating point format of the value is such that
+   the sign bit can be extracted.  If that is not the case, the
+   function returns NULL_RTX to indicate that a normal call should be
+   emitted rather than expanding the function in-line.  EXP is the
+   expression that is a call to the builtin function; if convenient,
+   the result should be placed in TARGET.  */
 static rtx
 expand_builtin_signbit (tree exp, rtx target)
 {
 static rtx
 expand_builtin_signbit (tree exp, rtx target)
 {
@@ -5507,6 +5719,7 @@ expand_builtin_signbit (tree exp, rtx target)
   HOST_WIDE_INT hi, lo;
   tree arg;
   int word, bitpos;
   HOST_WIDE_INT hi, lo;
   tree arg;
   int word, bitpos;
+  enum insn_code icode;
   rtx temp;
 
   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
   rtx temp;
 
   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
@@ -5517,6 +5730,21 @@ expand_builtin_signbit (tree exp, rtx target)
   rmode = TYPE_MODE (TREE_TYPE (exp));
   fmt = REAL_MODE_FORMAT (fmode);
 
   rmode = TYPE_MODE (TREE_TYPE (exp));
   fmt = REAL_MODE_FORMAT (fmode);
 
+  arg = builtin_save_expr (arg);
+
+  /* Expand the argument yielding a RTX expression. */
+  temp = expand_normal (arg);
+
+  /* Check if the back end provides an insn that handles signbit for the
+     argument's mode. */
+  icode = signbit_optab->handlers [(int) fmode].insn_code;
+  if (icode != CODE_FOR_nothing)
+    {
+      target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
+      emit_unop_insn (icode, target, temp, UNKNOWN);
+      return target;
+    }
+
   /* For floating point formats without a sign bit, implement signbit
      as "ARG < 0.0".  */
   bitpos = fmt->signbit_ro;
   /* For floating point formats without a sign bit, implement signbit
      as "ARG < 0.0".  */
   bitpos = fmt->signbit_ro;
@@ -5531,7 +5759,6 @@ expand_builtin_signbit (tree exp, rtx target)
     return expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
   }
 
     return expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
   }
 
-  temp = expand_normal (arg);
   if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD)
     {
       imode = int_mode_for_mode (fmode);
   if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD)
     {
       imode = int_mode_for_mode (fmode);
@@ -5684,7 +5911,7 @@ get_builtin_sync_mem (tree loc, enum machine_mode mode)
 {
   rtx addr, mem;
 
 {
   rtx addr, mem;
 
-  addr = expand_expr (loc, NULL, Pmode, EXPAND_SUM);
+  addr = expand_expr (loc, NULL_RTX, Pmode, EXPAND_SUM);
 
   /* Note that we explicitly do not want any alias information for this
      memory, so that we kill all other live memories.  Otherwise we don't
 
   /* Note that we explicitly do not want any alias information for this
      memory, so that we kill all other live memories.  Otherwise we don't
@@ -5712,13 +5939,18 @@ expand_builtin_sync_operation (enum machine_mode mode, tree exp,
                               rtx target, bool ignore)
 {
   rtx val, mem;
                               rtx target, bool ignore)
 {
   rtx val, mem;
+  enum machine_mode old_mode;
 
   /* Expand the operands.  */
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
 
 
   /* Expand the operands.  */
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
 
-  val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL, mode, EXPAND_NORMAL);
-  /* If VAL is promoted to a wider mode, convert it back to MODE.  */
-  val = convert_to_mode (mode, val, 1);
+  val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL_RTX, mode, EXPAND_NORMAL);
+  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
+     of CONST_INTs, where we know the old_mode only from the call argument.  */
+  old_mode = GET_MODE (val);
+  if (old_mode == VOIDmode)
+    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1)));
+  val = convert_modes (mode, old_mode, val, 1);
 
   if (ignore)
     return expand_sync_operation (mem, val, code);
 
   if (ignore)
     return expand_sync_operation (mem, val, code);
@@ -5736,18 +5968,29 @@ expand_builtin_compare_and_swap (enum machine_mode mode, tree exp,
                                 bool is_bool, rtx target)
 {
   rtx old_val, new_val, mem;
                                 bool is_bool, rtx target)
 {
   rtx old_val, new_val, mem;
+  enum machine_mode old_mode;
 
   /* Expand the operands.  */
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
 
 
 
   /* Expand the operands.  */
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
 
 
-  old_val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL, mode, EXPAND_NORMAL);
-  /* If OLD_VAL is promoted to a wider mode, convert it back to MODE.  */
-  old_val = convert_to_mode (mode, old_val, 1);
-
-  new_val = expand_expr (CALL_EXPR_ARG (exp, 2), NULL, mode, EXPAND_NORMAL);
-  /* If NEW_VAL is promoted to a wider mode, convert it back to MODE.  */
-  new_val = convert_to_mode (mode, new_val, 1);
+  old_val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL_RTX,
+                        mode, EXPAND_NORMAL);
+  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
+     of CONST_INTs, where we know the old_mode only from the call argument.  */
+  old_mode = GET_MODE (old_val);
+  if (old_mode == VOIDmode)
+    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1)));
+  old_val = convert_modes (mode, old_mode, old_val, 1);
+
+  new_val = expand_expr (CALL_EXPR_ARG (exp, 2), NULL_RTX,
+                        mode, EXPAND_NORMAL);
+  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
+     of CONST_INTs, where we know the old_mode only from the call argument.  */
+  old_mode = GET_MODE (new_val);
+  if (old_mode == VOIDmode)
+    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 2)));
+  new_val = convert_modes (mode, old_mode, new_val, 1);
 
   if (is_bool)
     return expand_bool_compare_and_swap (mem, old_val, new_val, target);
 
   if (is_bool)
     return expand_bool_compare_and_swap (mem, old_val, new_val, target);
@@ -5766,12 +6009,17 @@ expand_builtin_lock_test_and_set (enum machine_mode mode, tree exp,
                                  rtx target)
 {
   rtx val, mem;
                                  rtx target)
 {
   rtx val, mem;
+  enum machine_mode old_mode;
 
   /* Expand the operands.  */
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
 
   /* Expand the operands.  */
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
-  val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL, mode, EXPAND_NORMAL);
-  /* If VAL is promoted to a wider mode, convert it back to MODE.  */
-  val = convert_to_mode (mode, val, 1);
+  val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL_RTX, mode, EXPAND_NORMAL);
+  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
+     of CONST_INTs, where we know the old_mode only from the call argument.  */
+  old_mode = GET_MODE (val);
+  if (old_mode == VOIDmode)
+    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1)));
+  val = convert_modes (mode, old_mode, val, 1);
 
   return expand_sync_lock_test_and_set (mem, val, target);
 }
 
   return expand_sync_lock_test_and_set (mem, val, target);
 }
@@ -5940,6 +6188,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       if (! flag_unsafe_math_optimizations)
        break;
     CASE_FLT_FN (BUILT_IN_ISINF):
       if (! flag_unsafe_math_optimizations)
        break;
     CASE_FLT_FN (BUILT_IN_ISINF):
+    CASE_FLT_FN (BUILT_IN_FINITE):
+    case BUILT_IN_ISFINITE:
+    case BUILT_IN_ISNORMAL:
       target = expand_builtin_interclass_mathfn (exp, target, subtarget);
       if (target)
        return target;
       target = expand_builtin_interclass_mathfn (exp, target, subtarget);
       if (target)
        return target;
@@ -6063,6 +6314,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return const0_rtx;
       return expand_builtin_next_arg ();
 
        return const0_rtx;
       return expand_builtin_next_arg ();
 
+    case BUILT_IN_CLEAR_CACHE:
+      target = expand_builtin___clear_cache (exp);
+      if (target)
+        return target;
+      break;
+
     case BUILT_IN_CLASSIFY_TYPE:
       return expand_builtin_classify_type (exp);
 
     case BUILT_IN_CLASSIFY_TYPE:
       return expand_builtin_classify_type (exp);
 
@@ -6266,6 +6523,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
        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);
     case BUILT_IN_BCMP:
     case BUILT_IN_MEMCMP:
       target = expand_builtin_memcmp (exp, target, mode);
@@ -6412,6 +6675,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       break;
 
     CASE_FLT_FN (BUILT_IN_SIGNBIT):
       break;
 
     CASE_FLT_FN (BUILT_IN_SIGNBIT):
+    case BUILT_IN_SIGNBITD32:
+    case BUILT_IN_SIGNBITD64:
+    case BUILT_IN_SIGNBITD128:
       target = expand_builtin_signbit (exp, target);
       if (target)
        return target;
       target = expand_builtin_signbit (exp, target);
       if (target)
        return target;
@@ -6718,11 +6984,11 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
    Otherwise the return value is END_BUILTINS.  */
 
 enum built_in_function
    Otherwise the return value is END_BUILTINS.  */
 
 enum built_in_function
-builtin_mathfn_code (tree t)
+builtin_mathfn_code (const_tree t)
 {
 {
-  tree fndecl, arg, parmlist;
-  tree argtype, parmtype;
-  call_expr_arg_iterator iter;
+  const_tree fndecl, arg, parmlist;
+  const_tree argtype, parmtype;
+  const_call_expr_arg_iterator iter;
 
   if (TREE_CODE (t) != CALL_EXPR
       || TREE_CODE (CALL_EXPR_FN (t)) != ADDR_EXPR)
 
   if (TREE_CODE (t) != CALL_EXPR
       || TREE_CODE (CALL_EXPR_FN (t)) != ADDR_EXPR)
@@ -6736,7 +7002,7 @@ builtin_mathfn_code (tree t)
     return END_BUILTINS;
 
   parmlist = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
     return END_BUILTINS;
 
   parmlist = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
-  init_call_expr_arg_iterator (t, &iter);
+  init_const_call_expr_arg_iterator (t, &iter);
   for (; parmlist; parmlist = TREE_CHAIN (parmlist))
     {
       /* If a function doesn't take a variable number of arguments,
   for (; parmlist; parmlist = TREE_CHAIN (parmlist))
     {
       /* If a function doesn't take a variable number of arguments,
@@ -6744,15 +7010,15 @@ builtin_mathfn_code (tree t)
       parmtype = TREE_VALUE (parmlist);
       if (VOID_TYPE_P (parmtype))
        {
       parmtype = TREE_VALUE (parmlist);
       if (VOID_TYPE_P (parmtype))
        {
-         if (more_call_expr_args_p (&iter))
+         if (more_const_call_expr_args_p (&iter))
            return END_BUILTINS;
          return DECL_FUNCTION_CODE (fndecl);
        }
 
            return END_BUILTINS;
          return DECL_FUNCTION_CODE (fndecl);
        }
 
-      if (! more_call_expr_args_p (&iter))
+      if (! more_const_call_expr_args_p (&iter))
        return END_BUILTINS;
       
        return END_BUILTINS;
       
-      arg = next_call_expr_arg (&iter);
+      arg = next_const_call_expr_arg (&iter);
       argtype = TREE_TYPE (arg);
 
       if (SCALAR_FLOAT_TYPE_P (parmtype))
       argtype = TREE_TYPE (arg);
 
       if (SCALAR_FLOAT_TYPE_P (parmtype))
@@ -7649,7 +7915,7 @@ fold_builtin_int_roundingfn (tree fndecl, tree arg)
     {
       const REAL_VALUE_TYPE x = TREE_REAL_CST (arg);
 
     {
       const REAL_VALUE_TYPE x = TREE_REAL_CST (arg);
 
-      if (! REAL_VALUE_ISNAN (x) && ! REAL_VALUE_ISINF (x))
+      if (real_isfinite (&x))
        {
          tree itype = TREE_TYPE (TREE_TYPE (fndecl));
          tree ftype = TREE_TYPE (arg);
        {
          tree itype = TREE_TYPE (TREE_TYPE (fndecl));
          tree ftype = TREE_TYPE (arg);
@@ -8457,7 +8723,7 @@ fold_builtin_memory_op (tree dest, tree src, tree len, tree type, bool ignore, i
 
       if (srctype == desttype
          || (gimple_in_ssa_p (cfun)
 
       if (srctype == desttype
          || (gimple_in_ssa_p (cfun)
-             && tree_ssa_useless_type_conversion_1 (desttype, srctype)))
+             && useless_type_conversion_p (desttype, srctype)))
        expr = srcvar;
       else if ((INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
           || POINTER_TYPE_P (TREE_TYPE (srcvar)))
        expr = srcvar;
       else if ((INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
           || POINTER_TYPE_P (TREE_TYPE (srcvar)))
@@ -8482,8 +8748,7 @@ fold_builtin_memory_op (tree dest, tree src, tree len, tree type, bool ignore, i
     len = fold_build2 (MINUS_EXPR, TREE_TYPE (len), len,
                       ssize_int (1));
 
     len = fold_build2 (MINUS_EXPR, TREE_TYPE (len), len,
                       ssize_int (1));
 
-  len = fold_convert (TREE_TYPE (dest), len);
-  dest = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, len);
+  dest = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (dest), dest, len);
   dest = fold_convert (type, dest);
   if (expr)
     dest = omit_one_operand (type, dest, expr);
   dest = fold_convert (type, dest);
   if (expr)
     dest = omit_one_operand (type, dest, expr);
@@ -8572,6 +8837,48 @@ fold_builtin_strncpy (tree fndecl, tree dest, tree src, tree len, tree slen)
                       build_call_expr (fn, 3, dest, src, len));
 }
 
                       build_call_expr (fn, 3, dest, src, len));
 }
 
+/* Fold function call to builtin memchr.  ARG1, ARG2 and LEN are the
+   arguments to the call, and TYPE is its return type.
+   Return NULL_TREE if no simplification can be made.  */
+
+static tree
+fold_builtin_memchr (tree arg1, tree arg2, tree len, tree type)
+{
+  if (!validate_arg (arg1, POINTER_TYPE)
+      || !validate_arg (arg2, INTEGER_TYPE)
+      || !validate_arg (len, INTEGER_TYPE))
+    return NULL_TREE;
+  else
+    {
+      const char *p1;
+
+      if (TREE_CODE (arg2) != INTEGER_CST
+         || !host_integerp (len, 1))
+       return NULL_TREE;
+
+      p1 = c_getstr (arg1);
+      if (p1 && compare_tree_int (len, strlen (p1) + 1) <= 0)
+       {
+         char c;
+         const char *r;
+         tree tem;
+
+         if (target_char_cast (arg2, &c))
+           return NULL_TREE;
+
+         r = memchr (p1, c, tree_low_cst (len, 1));
+
+         if (r == NULL)
+           return build_int_cst (TREE_TYPE (arg1), 0);
+
+         tem = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (arg1), arg1,
+                            size_int (r - p1));
+         return fold_convert (type, tem);
+       }
+      return NULL_TREE;
+    }
+}
+
 /* Fold function call to builtin memcmp with arguments ARG1 and ARG2.
    Return NULL_TREE if no simplification can be made.  */
 
 /* Fold function call to builtin memcmp with arguments ARG1 and ARG2.
    Return NULL_TREE if no simplification can be made.  */
 
@@ -9017,6 +9324,86 @@ fold_builtin_carg (tree arg, tree type)
   return NULL_TREE;
 }
 
   return NULL_TREE;
 }
 
+/* Fold a call to builtin logb/ilogb.  */
+
+static tree
+fold_builtin_logb (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:
+      case rvc_inf:
+       /* If arg is Inf or NaN and we're logb, return it.  */
+       if (TREE_CODE (rettype) == REAL_TYPE)
+         return fold_convert (rettype, arg);
+       /* Fall through... */
+      case rvc_zero:
+       /* Zero may set errno and/or raise an exception for logb, also
+          for ilogb we don't know FP_ILOGB0.  */
+       return NULL_TREE;
+      case rvc_normal:
+       /* For normal numbers, proceed iff radix == 2.  In GCC,
+          normalized significands are in the range [0.5, 1.0).  We
+          want the exponent as if they were [1.0, 2.0) so get the
+          exponent and subtract 1.  */
+       if (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (arg)))->b == 2)
+         return fold_convert (rettype, build_int_cst (NULL_TREE,
+                                                      REAL_EXP (value)-1));
+       break;
+      }
+    }
+  
+  return NULL_TREE;
+}
+
+/* Fold a call to builtin significand, if radix == 2.  */
+
+static tree
+fold_builtin_significand (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:
+      case rvc_nan:
+      case rvc_inf:
+       /* If arg is +-0, +-Inf or +-NaN, then return it.  */
+       return fold_convert (rettype, arg);
+      case rvc_normal:
+       /* For normal numbers, proceed iff radix == 2.  */
+       if (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (arg)))->b == 2)
+         {
+           REAL_VALUE_TYPE result = *value;
+           /* In GCC, normalized significands are in the range [0.5,
+              1.0).  We want them to be [1.0, 2.0) so set the
+              exponent to 1.  */
+           SET_REAL_EXP (&result, 1);
+           return build_real (rettype, result);
+         }
+       break;
+      }
+    }
+  
+  return NULL_TREE;
+}
+
 /* Fold a call to builtin frexp, we can assume the base is 2.  */
 
 static tree
 /* Fold a call to builtin frexp, we can assume the base is 2.  */
 
 static tree
@@ -9088,8 +9475,7 @@ fold_builtin_load_exponent (tree arg0, tree arg1, tree type, bool ldexp)
       /* If arg0 is 0, Inf or NaN, or if arg1 is 0, then return arg0.  */
       if (real_zerop (arg0) || integer_zerop (arg1)
          || (TREE_CODE (arg0) == REAL_CST
       /* If arg0 is 0, Inf or NaN, or if arg1 is 0, then return arg0.  */
       if (real_zerop (arg0) || integer_zerop (arg1)
          || (TREE_CODE (arg0) == REAL_CST
-             && (real_isnan (&TREE_REAL_CST (arg0))
-                 || real_isinf (&TREE_REAL_CST (arg0)))))
+             && !real_isfinite (&TREE_REAL_CST (arg0))))
        return omit_one_operand (type, arg0, arg1);
       
       /* If both arguments are constant, then try to evaluate it.  */
        return omit_one_operand (type, arg0, arg1);
       
       /* If both arguments are constant, then try to evaluate it.  */
@@ -9134,6 +9520,62 @@ fold_builtin_load_exponent (tree arg0, tree arg1, tree type, bool ldexp)
   return NULL_TREE;
 }
 
   return NULL_TREE;
 }
 
+/* Fold a call to builtin modf.  */
+
+static tree
+fold_builtin_modf (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 (arg1);
+
+  /* Proceed if a valid pointer type was passed in.  */
+  if (TYPE_MAIN_VARIANT (TREE_TYPE (arg1)) == TYPE_MAIN_VARIANT (rettype))
+    {
+      const REAL_VALUE_TYPE *const value = TREE_REAL_CST_PTR (arg0);
+      REAL_VALUE_TYPE trunc, frac;
+
+      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;
+      }
+             
+      /* Create the COMPOUND_EXPR (*arg1 = trunc, frac). */
+      arg1 = fold_build2 (MODIFY_EXPR, rettype, arg1,
+                         build_real (rettype, trunc));
+      TREE_SIDE_EFFECTS (arg1) = 1;
+      return fold_build2 (COMPOUND_EXPR, rettype, arg1,
+                         build_real (rettype, frac));
+    }
+  
+  return NULL_TREE;
+}
+
 /* Fold a call to __builtin_isnan(), __builtin_isinf, __builtin_finite.
    ARG is the argument for the call.  */
 
 /* Fold a call to __builtin_isnan(), __builtin_isinf, __builtin_finite.
    ARG is the argument for the call.  */
 
@@ -9168,7 +9610,7 @@ fold_builtin_classify (tree fndecl, tree arg, int builtin_index)
 
       return NULL_TREE;
 
 
       return NULL_TREE;
 
-    case BUILT_IN_FINITE:
+    case BUILT_IN_ISFINITE:
       if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg)))
          && !HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg))))
        return omit_one_operand (type, integer_one_node, arg);
       if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg)))
          && !HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg))))
        return omit_one_operand (type, integer_one_node, arg);
@@ -9176,8 +9618,7 @@ fold_builtin_classify (tree fndecl, tree arg, int builtin_index)
       if (TREE_CODE (arg) == REAL_CST)
        {
          r = TREE_REAL_CST (arg);
       if (TREE_CODE (arg) == REAL_CST)
        {
          r = TREE_REAL_CST (arg);
-         return real_isinf (&r) || real_isnan (&r)
-                ? integer_zero_node : integer_one_node;
+         return real_isfinite (&r) ? integer_one_node : integer_zero_node;
        }
 
       return NULL_TREE;
        }
 
       return NULL_TREE;
@@ -9475,6 +9916,32 @@ fold_builtin_1 (tree fndecl, tree arg0, bool ignore)
                             &dconstm1, NULL, false);
     break;
 
                             &dconstm1, NULL, false);
     break;
 
+#if MPFR_VERSION >= MPFR_VERSION_NUM(2,3,0)
+    CASE_FLT_FN (BUILT_IN_J0):
+      if (validate_arg (arg0, REAL_TYPE))
+       return do_mpfr_arg1 (arg0, type, mpfr_j0,
+                            NULL, NULL, 0);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_J1):
+      if (validate_arg (arg0, REAL_TYPE))
+       return do_mpfr_arg1 (arg0, type, mpfr_j1,
+                            NULL, NULL, 0);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_Y0):
+      if (validate_arg (arg0, REAL_TYPE))
+       return do_mpfr_arg1 (arg0, type, mpfr_y0,
+                            &dconst0, NULL, false);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_Y1):
+      if (validate_arg (arg0, REAL_TYPE))
+       return do_mpfr_arg1 (arg0, type, mpfr_y1,
+                            &dconst0, NULL, false);
+    break;
+#endif
+
     CASE_FLT_FN (BUILT_IN_NAN):
     case BUILT_IN_NAND32:
     case BUILT_IN_NAND64:
     CASE_FLT_FN (BUILT_IN_NAN):
     case BUILT_IN_NAND32:
     case BUILT_IN_NAND64:
@@ -9526,6 +9993,13 @@ fold_builtin_1 (tree fndecl, tree arg0, bool ignore)
     CASE_FLT_FN (BUILT_IN_SIGNBIT):
       return fold_builtin_signbit (arg0, type);
 
     CASE_FLT_FN (BUILT_IN_SIGNBIT):
       return fold_builtin_signbit (arg0, type);
 
+    CASE_FLT_FN (BUILT_IN_SIGNIFICAND):
+      return fold_builtin_significand (arg0, type);
+
+    CASE_FLT_FN (BUILT_IN_ILOGB):
+    CASE_FLT_FN (BUILT_IN_LOGB):
+      return fold_builtin_logb (arg0, type);
+
     case BUILT_IN_ISASCII:
       return fold_builtin_isascii (arg0);
 
     case BUILT_IN_ISASCII:
       return fold_builtin_isascii (arg0);
 
@@ -9539,7 +10013,8 @@ fold_builtin_1 (tree fndecl, tree arg0, bool ignore)
     case BUILT_IN_FINITED32:
     case BUILT_IN_FINITED64:
     case BUILT_IN_FINITED128:
     case BUILT_IN_FINITED32:
     case BUILT_IN_FINITED64:
     case BUILT_IN_FINITED128:
-      return fold_builtin_classify (fndecl, arg0, BUILT_IN_FINITE);
+    case BUILT_IN_ISFINITE:
+      return fold_builtin_classify (fndecl, arg0, BUILT_IN_ISFINITE);
 
     CASE_FLT_FN (BUILT_IN_ISINF):
     case BUILT_IN_ISINFD32:
 
     CASE_FLT_FN (BUILT_IN_ISINF):
     case BUILT_IN_ISINFD32:
@@ -9578,6 +10053,34 @@ fold_builtin_2 (tree fndecl, tree arg0, tree arg1, bool ignore)
 
   switch (fcode)
     {
 
   switch (fcode)
     {
+#if MPFR_VERSION >= MPFR_VERSION_NUM(2,3,0)
+    CASE_FLT_FN (BUILT_IN_JN):
+      if (validate_arg (arg0, INTEGER_TYPE)
+         && validate_arg (arg1, REAL_TYPE))
+       return do_mpfr_bessel_n (arg0, arg1, type, mpfr_jn, NULL, 0);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_YN):
+      if (validate_arg (arg0, INTEGER_TYPE)
+         && validate_arg (arg1, REAL_TYPE))
+       return do_mpfr_bessel_n (arg0, arg1, type, mpfr_yn,
+                                &dconst0, false);
+    break;
+
+    CASE_FLT_FN (BUILT_IN_DREM):
+    CASE_FLT_FN (BUILT_IN_REMAINDER):
+      if (validate_arg (arg0, REAL_TYPE)
+          && validate_arg(arg1, REAL_TYPE))
+        return do_mpfr_arg2 (arg0, arg1, type, mpfr_remainder);
+    break;
+
+    CASE_FLT_FN_REENT (BUILT_IN_GAMMA): /* GAMMA_R */
+    CASE_FLT_FN_REENT (BUILT_IN_LGAMMA): /* LGAMMA_R */
+      if (validate_arg (arg0, REAL_TYPE)
+         && validate_arg(arg1, POINTER_TYPE))
+       return do_mpfr_lgamma_r (arg0, arg1, type);
+    break;
+#endif
 
     CASE_FLT_FN (BUILT_IN_ATAN2):
       if (validate_arg (arg0, REAL_TYPE)
 
     CASE_FLT_FN (BUILT_IN_ATAN2):
       if (validate_arg (arg0, REAL_TYPE)
@@ -9603,6 +10106,9 @@ fold_builtin_2 (tree fndecl, tree arg0, tree arg1, bool ignore)
     CASE_FLT_FN (BUILT_IN_FREXP):
       return fold_builtin_frexp (arg0, arg1, type);
 
     CASE_FLT_FN (BUILT_IN_FREXP):
       return fold_builtin_frexp (arg0, arg1, type);
 
+    CASE_FLT_FN (BUILT_IN_MODF):
+      return fold_builtin_modf (arg0, arg1, type);
+
     case BUILT_IN_BZERO:
       return fold_builtin_bzero (arg0, arg1, ignore);
 
     case BUILT_IN_BZERO:
       return fold_builtin_bzero (arg0, arg1, ignore);
 
@@ -9731,6 +10237,15 @@ fold_builtin_3 (tree fndecl, tree arg0, tree arg1, tree arg2, bool ignore)
        return do_mpfr_arg3 (arg0, arg1, arg2, type, mpfr_fma);
     break;
 
        return do_mpfr_arg3 (arg0, arg1, arg2, type, mpfr_fma);
     break;
 
+#if MPFR_VERSION >= MPFR_VERSION_NUM(2,3,0)
+    CASE_FLT_FN (BUILT_IN_REMQUO):
+      if (validate_arg (arg0, REAL_TYPE)
+         && validate_arg(arg1, REAL_TYPE)
+         && validate_arg(arg2, POINTER_TYPE))
+       return do_mpfr_remquo (arg0, arg1, arg2);
+    break;
+#endif
+
     case BUILT_IN_MEMSET:
       return fold_builtin_memset (arg0, arg1, arg2, type, ignore);
 
     case BUILT_IN_MEMSET:
       return fold_builtin_memset (arg0, arg1, arg2, type, ignore);
 
@@ -9755,6 +10270,9 @@ fold_builtin_3 (tree fndecl, tree arg0, tree arg1, tree arg2, bool ignore)
     case BUILT_IN_STRNCMP:
       return fold_builtin_strncmp (arg0, arg1, arg2);
 
     case BUILT_IN_STRNCMP:
       return fold_builtin_strncmp (arg0, arg1, arg2);
 
+    case BUILT_IN_MEMCHR:
+      return fold_builtin_memchr (arg0, arg1, arg2, type);
+
     case BUILT_IN_BCMP:
     case BUILT_IN_MEMCMP:
       return fold_builtin_memcmp (arg0, arg1, arg2);;
     case BUILT_IN_BCMP:
     case BUILT_IN_MEMCMP:
       return fold_builtin_memcmp (arg0, arg1, arg2);;
@@ -9978,56 +10496,13 @@ build_function_call_expr (tree fndecl, tree arglist)
 {
   tree fntype = TREE_TYPE (fndecl);
   tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
 {
   tree fntype = TREE_TYPE (fndecl);
   tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
-  return fold_builtin_call_list (TREE_TYPE (fntype), fn, arglist);
-}
-
-/* Construct a CALL_EXPR with type TYPE with FN as the function expression.
-   ARGLIST is a TREE_LIST of arguments.  */
-
-tree
-fold_builtin_call_list (tree type, tree fn, tree arglist)
-{
-  tree ret = NULL_TREE;
-  if (TREE_CODE (fn) == ADDR_EXPR)
-    {
-      tree fndecl = TREE_OPERAND (fn, 0);
-      if (TREE_CODE (fndecl) == FUNCTION_DECL
-         && DECL_BUILT_IN (fndecl))
-       {
-         /* FIXME: Don't use a list in this interface.  */
-         if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
-           {
-             ret = targetm.fold_builtin (fndecl, arglist, false);
-             if (ret)
-               return ret;
-           }
-         else
-           {
-             tree tail = arglist;
-             tree args[MAX_ARGS_TO_FOLD_BUILTIN];
-             int nargs;
-             tree exp;
-
-             for (nargs = 0; nargs < MAX_ARGS_TO_FOLD_BUILTIN; nargs++)
-               {
-                 if (!tail)
-                   break;
-                 args[nargs] = TREE_VALUE (tail);
-                 tail = TREE_CHAIN (tail);
-               }
-             if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN)
-               {
-                 ret = fold_builtin_n (fndecl, args, nargs, false);
-                 if (ret)
-                   return ret;
-               }
-             exp = build_call_list (type, fn, arglist);
-             ret = fold_builtin_varargs (fndecl, exp, false);
-             return ret ? ret : exp;
-           }
-       }
-    }
-  return build_call_list (type, fn, arglist);
+  int n = list_length (arglist);
+  tree *argarray = (tree *) alloca (n * sizeof (tree));
+  int i;
+  
+  for (i = 0; i < n; i++, arglist = TREE_CHAIN (arglist))
+    argarray[i] = TREE_VALUE (arglist);
+  return fold_builtin_call_array (TREE_TYPE (fntype), fn, n, argarray);
 }
 
 /* Conveniently construct a function call expression.  FNDECL names the
 }
 
 /* Conveniently construct a function call expression.  FNDECL names the
@@ -10038,24 +10513,26 @@ tree
 build_call_expr (tree fndecl, int n, ...)
 {
   va_list ap;
 build_call_expr (tree fndecl, int n, ...)
 {
   va_list ap;
-  tree ret;
   tree fntype = TREE_TYPE (fndecl);
   tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
   tree fntype = TREE_TYPE (fndecl);
   tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
+  tree *argarray = (tree *) alloca (n * sizeof (tree));
+  int i;
 
   va_start (ap, n);
 
   va_start (ap, n);
-  ret = fold_builtin_call_valist (TREE_TYPE (fntype), fn, n, ap);
+  for (i = 0; i < n; i++)
+    argarray[i] = va_arg (ap, tree);
   va_end (ap);
   va_end (ap);
-  return ret;
+  return fold_builtin_call_array (TREE_TYPE (fntype), fn, n, argarray);
 }
 
 /* Construct a CALL_EXPR with type TYPE with FN as the function expression.
 }
 
 /* Construct a CALL_EXPR with type TYPE with FN as the function expression.
-   N arguments are passed in the va_list AP.  */
+   N arguments are passed in the array ARGARRAY.  */
 
 tree
 
 tree
-fold_builtin_call_valist (tree type,
-                         tree fn,
-                         int n,
-                         va_list ap)
+fold_builtin_call_array (tree type,
+                        tree fn,
+                        int n,
+                        tree *argarray)
 {
   tree ret = NULL_TREE;
   int i;
 {
   tree ret = NULL_TREE;
   int i;
@@ -10070,15 +10547,8 @@ fold_builtin_call_valist (tree type,
         if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
           {
             tree arglist = NULL_TREE;
         if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
           {
             tree arglist = NULL_TREE;
-            va_list ap0;
-            va_copy (ap0, ap);
-            for (i = 0; i < n; i++)
-              {
-                tree arg = va_arg (ap0, tree);
-                arglist = tree_cons (NULL_TREE, arg, arglist);
-              }
-            va_end (ap0);
-            arglist = nreverse (arglist);
+           for (i = n - 1; i >= 0; i--)
+             arglist = tree_cons (NULL_TREE, argarray[i], arglist);
             ret = targetm.fold_builtin (fndecl, arglist, false);
             if (ret)
               return ret;
             ret = targetm.fold_builtin (fndecl, arglist, false);
             if (ret)
               return ret;
@@ -10087,25 +10557,19 @@ fold_builtin_call_valist (tree type,
           {
             /* First try the transformations that don't require consing up
                an exp.  */
           {
             /* First try the transformations that don't require consing up
                an exp.  */
-            tree args[MAX_ARGS_TO_FOLD_BUILTIN];
-            va_list ap0;
-            va_copy (ap0, ap);
-            for (i = 0; i < n; i++)
-              args[i] = va_arg (ap0, tree);
-            va_end (ap0);
-            ret = fold_builtin_n (fndecl, args, n, false);
+            ret = fold_builtin_n (fndecl, argarray, n, false);
             if (ret)
               return ret;
           }
 
         /* If we got this far, we need to build an exp.  */
             if (ret)
               return ret;
           }
 
         /* If we got this far, we need to build an exp.  */
-        exp = build_call_valist (type, fn, n, ap);
+        exp = build_call_array (type, fn, n, argarray);
         ret = fold_builtin_varargs (fndecl, exp, false);
         return ret ? ret : exp;
       }
   }
 
         ret = fold_builtin_varargs (fndecl, exp, false);
         return ret ? ret : exp;
       }
   }
 
-  return build_call_valist (type, fn, n, ap);
+  return build_call_array (type, fn, n, argarray);
 }
 
 /* Construct a new CALL_EXPR using the tail of the argument list of EXP
 }
 
 /* Construct a new CALL_EXPR using the tail of the argument list of EXP
@@ -10145,7 +10609,7 @@ rewrite_call_expr (tree exp, int skip, tree fndecl, int n, ...)
    a type.  */
   
 static bool
    a type.  */
   
 static bool
-validate_arg (tree arg, enum tree_code code)
+validate_arg (const_tree arg, enum tree_code code)
 {
   if (!arg)
     return false;
 {
   if (!arg)
     return false;
@@ -10160,16 +10624,16 @@ validate_arg (tree arg, enum tree_code code)
    VOID_TYPE.  */
 
 bool
    VOID_TYPE.  */
 
 bool
-validate_arglist (tree callexpr, ...)
+validate_arglist (const_tree callexpr, ...)
 {
   enum tree_code code;
   bool res = 0;
   va_list ap;
 {
   enum tree_code code;
   bool res = 0;
   va_list ap;
-  call_expr_arg_iterator iter;
-  tree arg;
+  const_call_expr_arg_iterator iter;
+  const_tree arg;
 
   va_start (ap, callexpr);
 
   va_start (ap, callexpr);
-  init_call_expr_arg_iterator (callexpr, &iter);
+  init_const_call_expr_arg_iterator (callexpr, &iter);
 
   do
     {
 
   do
     {
@@ -10183,13 +10647,13 @@ validate_arglist (tree callexpr, ...)
        case VOID_TYPE:
          /* This signifies an endlink, if no arguments remain, return
             true, otherwise return false.  */
        case VOID_TYPE:
          /* This signifies an endlink, if no arguments remain, return
             true, otherwise return false.  */
-         res = !more_call_expr_args_p (&iter);
+         res = !more_const_call_expr_args_p (&iter);
          goto end;
        default:
          /* If no parameters remain or the parameter's code does not
             match the specified code, return false.  Otherwise continue
             checking any remaining arguments.  */
          goto end;
        default:
          /* If no parameters remain or the parameter's code does not
             match the specified code, return false.  Otherwise continue
             checking any remaining arguments.  */
-         arg = next_call_expr_arg (&iter);
+         arg = next_const_call_expr_arg (&iter);
          if (!validate_arg (arg, code))
            goto end;
          break;
          if (!validate_arg (arg, code))
            goto end;
          break;
@@ -10286,8 +10750,8 @@ fold_builtin_strstr (tree s1, tree s2, tree type)
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
-         tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1),
-                            s1, build_int_cst (TREE_TYPE (s1), r - p1));
+         tem = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (s1),
+                            s1, size_int (r - p1));
          return fold_convert (type, tem);
        }
 
          return fold_convert (type, tem);
        }
 
@@ -10356,8 +10820,8 @@ fold_builtin_strchr (tree s1, tree s2, tree type)
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
-         tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1),
-                            s1, build_int_cst (TREE_TYPE (s1), r - p1));
+         tem = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (s1),
+                            s1, size_int (r - p1));
          return fold_convert (type, tem);
        }
       return NULL_TREE;
          return fold_convert (type, tem);
        }
       return NULL_TREE;
@@ -10412,8 +10876,8 @@ fold_builtin_strrchr (tree s1, tree s2, tree type)
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
-         tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1),
-                            s1, build_int_cst (TREE_TYPE (s1), r - p1));
+         tem = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (s1),
+                            s1, size_int (r - p1));
          return fold_convert (type, tem);
        }
 
          return fold_convert (type, tem);
        }
 
@@ -10472,8 +10936,8 @@ fold_builtin_strpbrk (tree s1, tree s2, tree type)
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
-         tem = fold_build2 (PLUS_EXPR, TREE_TYPE (s1),
-                            s1, build_int_cst (TREE_TYPE (s1), r - p1));
+         tem = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (s1),
+                            s1, size_int (r - p1));
          return fold_convert (type, tem);
        }
 
          return fold_convert (type, tem);
        }
 
@@ -11059,8 +11523,7 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
              return expand_expr (dest, target, mode, EXPAND_NORMAL);
            }
 
              return expand_expr (dest, target, mode, EXPAND_NORMAL);
            }
 
-         len = fold_convert (TREE_TYPE (dest), len);
-         expr = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, len);
+         expr = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (dest), dest, len);
          return expand_expr (expr, target, mode, EXPAND_NORMAL);
        }
 
          return expand_expr (expr, target, mode, EXPAND_NORMAL);
        }
 
@@ -11307,8 +11770,7 @@ fold_builtin_memory_chk (tree fndecl,
        return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, len);
       else
        {
        return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, len);
       else
        {
-         tree temp = fold_convert (TREE_TYPE (dest), len);
-         temp = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, temp);
+         tree temp = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (dest), dest, len);
          return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), temp);
        }
     }
          return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), temp);
        }
     }
@@ -12031,12 +12493,12 @@ do_mpfr_ckconv (mpfr_srcptr m, tree type, int inexact)
     {
       REAL_VALUE_TYPE rr;
 
     {
       REAL_VALUE_TYPE rr;
 
-      real_from_mpfr (&rr, m);
+      real_from_mpfr (&rr, m, type, GMP_RNDN);
       /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR value,
         check for overflow/underflow.  If the REAL_VALUE_TYPE is zero
         but the mpft_t is not, then we underflowed in the
         conversion.  */
       /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR value,
         check for overflow/underflow.  If the REAL_VALUE_TYPE is zero
         but the mpft_t is not, then we underflowed in the
         conversion.  */
-      if (!real_isnan (&rr) && !real_isinf (&rr)
+      if (real_isfinite (&rr)
          && (rr.cl == rvc_zero) == (mpfr_zero_p (m) != 0))
         {
          REAL_VALUE_TYPE rmode;
          && (rr.cl == rvc_zero) == (mpfr_zero_p (m) != 0))
         {
          REAL_VALUE_TYPE rmode;
@@ -12075,7 +12537,7 @@ do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t),
     {
       const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg);
 
     {
       const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg);
 
-      if (!real_isnan (ra) && !real_isinf (ra)
+      if (real_isfinite (ra)
          && (!min || real_compare (inclusive ? GE_EXPR: GT_EXPR , ra, min))
          && (!max || real_compare (inclusive ? LE_EXPR: LT_EXPR , ra, max)))
         {
          && (!min || real_compare (inclusive ? GE_EXPR: GT_EXPR , ra, min))
          && (!max || real_compare (inclusive ? LE_EXPR: LT_EXPR , ra, max)))
         {
@@ -12084,7 +12546,7 @@ do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t),
          mpfr_t m;
 
          mpfr_init2 (m, prec);
          mpfr_t m;
 
          mpfr_init2 (m, prec);
-         mpfr_from_real (m, ra);
+         mpfr_from_real (m, ra, GMP_RNDN);
          mpfr_clear_flags ();
          inexact = func (m, m, GMP_RNDN);
          result = do_mpfr_ckconv (m, type, inexact);
          mpfr_clear_flags ();
          inexact = func (m, m, GMP_RNDN);
          result = do_mpfr_ckconv (m, type, inexact);
@@ -12119,16 +12581,15 @@ do_mpfr_arg2 (tree arg1, tree arg2, tree type,
       const REAL_VALUE_TYPE *const ra1 = &TREE_REAL_CST (arg1);
       const REAL_VALUE_TYPE *const ra2 = &TREE_REAL_CST (arg2);
 
       const REAL_VALUE_TYPE *const ra1 = &TREE_REAL_CST (arg1);
       const REAL_VALUE_TYPE *const ra2 = &TREE_REAL_CST (arg2);
 
-      if (!real_isnan (ra1) && !real_isinf (ra1)
-         && !real_isnan (ra2) && !real_isinf (ra2))
+      if (real_isfinite (ra1) && real_isfinite (ra2))
         {
          const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
          int inexact;
          mpfr_t m1, m2;
 
          mpfr_inits2 (prec, m1, m2, NULL);
         {
          const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
          int inexact;
          mpfr_t m1, m2;
 
          mpfr_inits2 (prec, m1, m2, NULL);
-         mpfr_from_real (m1, ra1);
-         mpfr_from_real (m2, ra2);
+         mpfr_from_real (m1, ra1, GMP_RNDN);
+         mpfr_from_real (m2, ra2, GMP_RNDN);
          mpfr_clear_flags ();
          inexact = func (m1, m1, m2, GMP_RNDN);
          result = do_mpfr_ckconv (m1, type, inexact);
          mpfr_clear_flags ();
          inexact = func (m1, m1, m2, GMP_RNDN);
          result = do_mpfr_ckconv (m1, type, inexact);
@@ -12166,18 +12627,16 @@ do_mpfr_arg3 (tree arg1, tree arg2, tree arg3, tree type,
       const REAL_VALUE_TYPE *const ra2 = &TREE_REAL_CST (arg2);
       const REAL_VALUE_TYPE *const ra3 = &TREE_REAL_CST (arg3);
 
       const REAL_VALUE_TYPE *const ra2 = &TREE_REAL_CST (arg2);
       const REAL_VALUE_TYPE *const ra3 = &TREE_REAL_CST (arg3);
 
-      if (!real_isnan (ra1) && !real_isinf (ra1)
-         && !real_isnan (ra2) && !real_isinf (ra2)
-         && !real_isnan (ra3) && !real_isinf (ra3))
+      if (real_isfinite (ra1) && real_isfinite (ra2) && real_isfinite (ra3))
         {
          const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
          int inexact;
          mpfr_t m1, m2, m3;
 
          mpfr_inits2 (prec, m1, m2, m3, NULL);
         {
          const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
          int inexact;
          mpfr_t m1, m2, m3;
 
          mpfr_inits2 (prec, m1, m2, m3, NULL);
-         mpfr_from_real (m1, ra1);
-         mpfr_from_real (m2, ra2);
-         mpfr_from_real (m3, ra3);
+         mpfr_from_real (m1, ra1, GMP_RNDN);
+         mpfr_from_real (m2, ra2, GMP_RNDN);
+         mpfr_from_real (m3, ra3, GMP_RNDN);
          mpfr_clear_flags ();
          inexact = func (m1, m1, m2, m3, GMP_RNDN);
          result = do_mpfr_ckconv (m1, type, inexact);
          mpfr_clear_flags ();
          inexact = func (m1, m1, m2, m3, GMP_RNDN);
          result = do_mpfr_ckconv (m1, type, inexact);
@@ -12211,7 +12670,7 @@ do_mpfr_sincos (tree arg, tree arg_sinp, tree arg_cosp)
     {
       const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg);
 
     {
       const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg);
 
-      if (!real_isnan (ra) && !real_isinf (ra))
+      if (real_isfinite (ra))
         {
          const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
          tree result_s, result_c;
         {
          const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
          tree result_s, result_c;
@@ -12219,7 +12678,7 @@ do_mpfr_sincos (tree arg, tree arg_sinp, tree arg_cosp)
          mpfr_t m, ms, mc;
 
          mpfr_inits2 (prec, m, ms, mc, NULL);
          mpfr_t m, ms, mc;
 
          mpfr_inits2 (prec, m, ms, mc, NULL);
-         mpfr_from_real (m, ra);
+         mpfr_from_real (m, ra, GMP_RNDN);
          mpfr_clear_flags ();
          inexact = mpfr_sin_cos (ms, mc, m, GMP_RNDN);
          result_s = do_mpfr_ckconv (ms, type, inexact);
          mpfr_clear_flags ();
          inexact = mpfr_sin_cos (ms, mc, m, GMP_RNDN);
          result_s = do_mpfr_ckconv (ms, type, inexact);
@@ -12255,3 +12714,184 @@ do_mpfr_sincos (tree arg, tree arg_sinp, tree arg_cosp)
     }
   return result;
 }
     }
   return result;
 }
+
+#if MPFR_VERSION >= MPFR_VERSION_NUM(2,3,0)
+/* If argument ARG1 is an INTEGER_CST and ARG2 is a REAL_CST, call the
+   two-argument mpfr order N Bessel function FUNC on them and return
+   the resulting value as a tree with type TYPE.  The mpfr precision
+   is set to the precision of TYPE.  We assume that function FUNC
+   returns zero if the result could be calculated exactly within the
+   requested precision.  */
+static tree
+do_mpfr_bessel_n (tree arg1, tree arg2, tree type,
+                 int (*func)(mpfr_ptr, long, mpfr_srcptr, mp_rnd_t),
+                 const REAL_VALUE_TYPE *min, bool inclusive)
+{
+  tree result = NULL_TREE;
+
+  STRIP_NOPS (arg1);
+  STRIP_NOPS (arg2);
+
+  /* To proceed, MPFR must exactly represent the target floating point
+     format, which only happens when the target base equals two.  */
+  if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
+      && host_integerp (arg1, 0)
+      && TREE_CODE (arg2) == REAL_CST && !TREE_OVERFLOW (arg2))
+    {
+      const HOST_WIDE_INT n = tree_low_cst(arg1, 0);
+      const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg2);
+
+      if (n == (long)n
+         && real_isfinite (ra)
+         && (!min || real_compare (inclusive ? GE_EXPR: GT_EXPR , ra, min)))
+        {
+         const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+         int inexact;
+         mpfr_t m;
+
+         mpfr_init2 (m, prec);
+         mpfr_from_real (m, ra, GMP_RNDN);
+         mpfr_clear_flags ();
+         inexact = func (m, n, m, GMP_RNDN);
+         result = do_mpfr_ckconv (m, type, inexact);
+         mpfr_clear (m);
+       }
+    }
+  
+  return result;
+}
+
+/* If arguments ARG0 and ARG1 are REAL_CSTs, call mpfr_remquo() to set
+   the pointer *(ARG_QUO) and return the result.  The type is taken
+   from the type of ARG0 and is used for setting the precision of the
+   calculation and results.  */
+
+static tree
+do_mpfr_remquo (tree arg0, tree arg1, tree arg_quo)
+{
+  tree const type = TREE_TYPE (arg0);
+  tree result = NULL_TREE;
+  
+  STRIP_NOPS (arg0);
+  STRIP_NOPS (arg1);
+  
+  /* To proceed, MPFR must exactly represent the target floating point
+     format, which only happens when the target base equals two.  */
+  if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
+      && TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0)
+      && TREE_CODE (arg1) == REAL_CST && !TREE_OVERFLOW (arg1))
+    {
+      const REAL_VALUE_TYPE *const ra0 = TREE_REAL_CST_PTR (arg0);
+      const REAL_VALUE_TYPE *const ra1 = TREE_REAL_CST_PTR (arg1);
+
+      if (real_isfinite (ra0) && real_isfinite (ra1))
+        {
+         const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+         tree result_rem;
+         long integer_quo;
+         mpfr_t m0, m1;
+
+         mpfr_inits2 (prec, m0, m1, NULL);
+         mpfr_from_real (m0, ra0, GMP_RNDN);
+         mpfr_from_real (m1, ra1, GMP_RNDN);
+         mpfr_clear_flags ();
+         mpfr_remquo (m0, &integer_quo, m0, m1, GMP_RNDN);
+         /* Remquo is independent of the rounding mode, so pass
+            inexact=0 to do_mpfr_ckconv().  */
+         result_rem = do_mpfr_ckconv (m0, type, /*inexact=*/ 0);
+         mpfr_clears (m0, m1, NULL);
+         if (result_rem)
+           {
+             /* MPFR calculates quo in the host's long so it may
+                return more bits in quo than the target int can hold
+                if sizeof(host long) > sizeof(target int).  This can
+                happen even for native compilers in LP64 mode.  In
+                these cases, modulo the quo value with the largest
+                number that the target int can hold while leaving one
+                bit for the sign.  */
+             if (sizeof (integer_quo) * CHAR_BIT > INT_TYPE_SIZE)
+               integer_quo %= (long)(1UL << (INT_TYPE_SIZE - 1));
+
+             /* Dereference the quo pointer argument.  */
+             arg_quo = build_fold_indirect_ref (arg_quo);
+             /* Proceed iff a valid pointer type was passed in.  */
+             if (TYPE_MAIN_VARIANT (TREE_TYPE (arg_quo)) == integer_type_node)
+               {
+                 /* Set the value. */
+                 tree result_quo = fold_build2 (MODIFY_EXPR,
+                                                TREE_TYPE (arg_quo), arg_quo,
+                                                build_int_cst (NULL, integer_quo));
+                 TREE_SIDE_EFFECTS (result_quo) = 1;
+                 /* Combine the quo assignment with the rem.  */
+                 result = non_lvalue (fold_build2 (COMPOUND_EXPR, type,
+                                                   result_quo, result_rem));
+               }
+           }
+       }
+    }
+  return result;
+}
+
+/* If ARG is a REAL_CST, call mpfr_lgamma() on it and return the
+   resulting value as a tree with type TYPE.  The mpfr precision is
+   set to the precision of TYPE.  We assume that this mpfr function
+   returns zero if the result could be calculated exactly within the
+   requested precision.  In addition, the integer pointer represented
+   by ARG_SG will be dereferenced and set to the appropriate signgam
+   (-1,1) value.  */
+
+static tree
+do_mpfr_lgamma_r (tree arg, tree arg_sg, tree type)
+{
+  tree result = NULL_TREE;
+
+  STRIP_NOPS (arg);
+  
+  /* To proceed, MPFR must exactly represent the target floating point
+     format, which only happens when the target base equals two.  Also
+     verify ARG is a constant and that ARG_SG is an int pointer.  */
+  if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
+      && TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg)
+      && TREE_CODE (TREE_TYPE (arg_sg)) == POINTER_TYPE
+      && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (arg_sg))) == integer_type_node)
+    {
+      const REAL_VALUE_TYPE *const ra = TREE_REAL_CST_PTR (arg);
+
+      /* In addition to NaN and Inf, the argument cannot be zero or a
+        negative integer.  */
+      if (real_isfinite (ra)
+         && ra->cl != rvc_zero
+         && !(real_isneg(ra) && real_isinteger(ra, TYPE_MODE (type))))
+        {
+         const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+         int inexact, sg;
+         mpfr_t m;
+         tree result_lg;
+
+         mpfr_init2 (m, prec);
+         mpfr_from_real (m, ra, GMP_RNDN);
+         mpfr_clear_flags ();
+         inexact = mpfr_lgamma (m, &sg, m, GMP_RNDN);
+         result_lg = do_mpfr_ckconv (m, type, inexact);
+         mpfr_clear (m);
+         if (result_lg)
+           {
+             tree result_sg;
+
+             /* Dereference the arg_sg pointer argument.  */
+             arg_sg = build_fold_indirect_ref (arg_sg);
+             /* Assign the signgam value into *arg_sg. */
+             result_sg = fold_build2 (MODIFY_EXPR,
+                                      TREE_TYPE (arg_sg), arg_sg,
+                                      build_int_cst (NULL, sg));
+             TREE_SIDE_EFFECTS (result_sg) = 1;
+             /* Combine the signgam assignment with the lgamma result.  */
+             result = non_lvalue (fold_build2 (COMPOUND_EXPR, type,
+                                               result_sg, result_lg));
+           }
+       }
+    }
+
+  return result;
+}
+#endif