OSDN Git Service

gcc/ChangeLog:
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index df38f5e..871d670 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"
@@ -58,9 +58,7 @@ 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));
-#endif
 
 /* Define the names of the builtin function types and codes.  */
 const char *const built_in_class_names[4]
@@ -137,7 +135,7 @@ 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, ...);
@@ -325,7 +323,10 @@ get_object_alignment (tree exp, unsigned int align, unsigned int max_align)
          offset = next_offset;
        }
     }
-  if (DECL_P (exp))
+  if (TREE_CODE (exp) == CONST_DECL)
+    exp = DECL_INITIAL (exp);
+  if (DECL_P (exp)
+      && TREE_CODE (exp) != LABEL_DECL)
     align = MIN (inner, DECL_ALIGN (exp));
 #ifdef CONSTANT_ALIGNMENT
   else if (CONSTANT_CLASS_P (exp))
@@ -432,6 +433,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
@@ -449,6 +451,11 @@ 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);
 
+  if (EXPR_HAS_LOCATION (src))
+    loc = EXPR_LOCATION (src);
+  else
+    loc = input_location;
+
   src = string_constant (src, &offset_node);
   if (src == 0)
     return NULL_TREE;
@@ -474,7 +481,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
@@ -493,7 +500,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;
@@ -553,7 +560,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];
@@ -1315,7 +1322,7 @@ 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];
 
@@ -1874,7 +1881,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.  */
@@ -2303,9 +2312,12 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
 
   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
@@ -2323,8 +2335,10 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
 
       /* 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;
     }
 
   return NULL_RTX;
@@ -2909,6 +2923,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
@@ -2971,7 +3074,16 @@ 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))
+             /* 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)->insn_code
+                     != CODE_FOR_nothing))))
        {
          tree call_expr = build_call_nofold (fn, 1, narg0);
          /* Use expand_expr in case the newly built call expression
@@ -2994,6 +3106,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
@@ -5160,7 +5279,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;
@@ -5185,9 +5303,11 @@ expand_builtin_signbit (tree exp, rtx target)
   icode = signbit_optab->handlers [(int) fmode].insn_code;
   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
@@ -5234,21 +5354,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
@@ -6616,7 +6727,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;
@@ -6625,12 +6736,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;
     }
@@ -6936,6 +7042,77 @@ fold_builtin_cabs (location_t loc, tree arg, tree type, tree fndecl)
   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;
+
+  /* If there are no infinities, return arg.  */
+  if (! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (type))))
+    return non_lvalue_loc (loc, arg);
+
+  /* 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);
+
+      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;
+}
+
 /* Fold a builtin function call to sqrt, sqrtf, or sqrtl with argument ARG.
    Return NULL_TREE if no simplification can be made.  */
 
@@ -7152,20 +7329,17 @@ 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)))
@@ -7250,19 +7424,15 @@ 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)
     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));
 
@@ -9647,7 +9817,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);
@@ -9665,7 +9834,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);
@@ -9700,7 +9869,9 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore)
     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)
@@ -9737,7 +9908,6 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore)
        return do_mpc_arg1 (arg0, type, mpc_sqrt);
     break;
 
-#ifdef HAVE_mpc_arc
     CASE_FLT_FN (BUILT_IN_CASIN):
       if (validate_arg (arg0, COMPLEX_TYPE)
          && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
@@ -9773,8 +9943,6 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore)
          && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
        return do_mpc_arg1 (arg0, type, mpc_atanh);
     break;
-#endif /* HAVE_mpc_arc */
-#endif /* HAVE_mpc */
 
     CASE_FLT_FN (BUILT_IN_CABS):
       return fold_builtin_cabs (loc, arg0, type, fndecl);
@@ -10030,6 +10198,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;
     }
@@ -10092,7 +10265,6 @@ 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
@@ -10100,7 +10272,6 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1, bool ignore)
          && 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);
@@ -10530,9 +10701,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)
@@ -10596,7 +10767,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)
@@ -10620,12 +10790,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)
@@ -12720,7 +12888,6 @@ 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.
@@ -12742,8 +12909,8 @@ do_mpc_ckconv (mpc_srcptr m, tree type, int inexact, int force_convert)
     {
       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
@@ -12767,7 +12934,6 @@ do_mpc_ckconv (mpc_srcptr m, tree type, int inexact, int force_convert)
     }
   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.
@@ -13165,7 +13331,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
@@ -13219,7 +13384,6 @@ do_mpc_arg1 (tree arg, tree type, int (*func)(mpc_ptr, mpc_srcptr, mpc_rnd_t))
    DO_NONFINITE is true, then fold expressions containing Inf or NaN
    in the arguments and/or results.  */
 
-#ifdef HAVE_mpc
 tree
 do_mpc_arg2 (tree arg0, tree arg1, tree type, int do_nonfinite,
             int (*func)(mpc_ptr, mpc_srcptr, mpc_srcptr, mpc_rnd_t))
@@ -13270,8 +13434,6 @@ do_mpc_arg2 (tree arg0, tree arg1, tree type, int do_nonfinite,
 
   return result;
 }
-# endif
-#endif /* HAVE_mpc */
 
 /* FIXME tuples.
    The functions below provide an alternate interface for folding
@@ -13534,14 +13696,12 @@ fold_call_stmt (gimple stmt, 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)
         {
-          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,
+                                      (nargs > 0
+                                       ? gimple_call_arg_ptr (stmt, 0)
+                                       : &error_mark_node), ignore);
         }
       else
        {
@@ -13611,6 +13771,14 @@ set_builtin_user_assembler_name (tree decl, const char *asmspec)
     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;
     }