OSDN Git Service

Reformat.
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index cfdf5d5..997c13a 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.
@@ -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]
@@ -132,15 +130,12 @@ static rtx expand_builtin_strlen (tree, rtx, enum machine_mode);
 static rtx expand_builtin_alloca (tree, rtx);
 static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab);
 static rtx expand_builtin_frame_address (tree, tree);
-static rtx expand_builtin_printf (tree, rtx, enum machine_mode, bool);
-static rtx expand_builtin_fprintf (tree, rtx, enum machine_mode, bool);
-static rtx expand_builtin_sprintf (tree, rtx, enum machine_mode);
 static tree stabilize_va_list_loc (location_t, tree, int);
 static rtx expand_builtin_expect (tree, rtx);
 static tree fold_builtin_constant_p (tree);
 static tree fold_builtin_expect (location_t, tree, tree);
 static tree fold_builtin_classify_type (tree);
-static tree fold_builtin_strlen (location_t, tree);
+static tree fold_builtin_strlen (location_t, tree, tree);
 static tree fold_builtin_inf (location_t, tree, int);
 static tree fold_builtin_nan (tree, tree, int);
 static tree rewrite_call_expr (location_t, tree, int, tree, int, ...);
@@ -328,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))
@@ -435,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
@@ -452,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;
@@ -477,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
@@ -496,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;
@@ -556,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];
@@ -1877,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.  */
@@ -2306,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
@@ -2326,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;
@@ -2912,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
@@ -2974,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
@@ -2997,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
@@ -4983,286 +5099,6 @@ build_string_literal (int len, const char *str)
   return t;
 }
 
-/* Expand EXP, a call to printf or printf_unlocked.
-   Return NULL_RTX if a normal call should be emitted rather than transforming
-   the function inline.  If convenient, the result should be placed in
-   TARGET with mode MODE.  UNLOCKED indicates this is a printf_unlocked
-   call.  */
-static rtx
-expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
-                      bool unlocked)
-{
-  /* If we're using an unlocked function, assume the other unlocked
-     functions exist explicitly.  */
-  tree const fn_putchar = unlocked ? built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED]
-    : implicit_built_in_decls[BUILT_IN_PUTCHAR];
-  tree const fn_puts = unlocked ? built_in_decls[BUILT_IN_PUTS_UNLOCKED]
-    : implicit_built_in_decls[BUILT_IN_PUTS];
-  const char *fmt_str;
-  tree fn = 0;
-  tree fmt, arg;
-  int nargs = call_expr_nargs (exp);
-
-  /* If the return value is used, don't do the transformation.  */
-  if (target != const0_rtx)
-    return NULL_RTX;
-
-  /* Verify the required arguments in the original call.  */
-  if (nargs == 0)
-    return NULL_RTX;
-  fmt = CALL_EXPR_ARG (exp, 0);
-  if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
-    return NULL_RTX;
-
-  /* Check whether the format is a literal string constant.  */
-  fmt_str = c_getstr (fmt);
-  if (fmt_str == NULL)
-    return NULL_RTX;
-
-  if (!init_target_chars ())
-    return NULL_RTX;
-
-  /* If the format specifier was "%s\n", call __builtin_puts(arg).  */
-  if (strcmp (fmt_str, target_percent_s_newline) == 0)
-    {
-      if ((nargs != 2)
-         || ! POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_ARG (exp, 1))))
-       return NULL_RTX;
-      if (fn_puts)
-       fn = build_call_nofold (fn_puts, 1, CALL_EXPR_ARG (exp, 1));
-    }
-  /* If the format specifier was "%c", call __builtin_putchar(arg).  */
-  else if (strcmp (fmt_str, target_percent_c) == 0)
-    {
-      if ((nargs != 2)
-         || TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1))) != INTEGER_TYPE)
-       return NULL_RTX;
-      if (fn_putchar)
-       fn = build_call_nofold (fn_putchar, 1, CALL_EXPR_ARG (exp, 1));
-    }
-  else
-    {
-      /* We can't handle anything else with % args or %% ... yet.  */
-      if (strchr (fmt_str, target_percent))
-       return NULL_RTX;
-
-      if (nargs > 1)
-       return NULL_RTX;
-
-      /* If the format specifier was "", printf does nothing.  */
-      if (fmt_str[0] == '\0')
-       return const0_rtx;
-      /* If the format specifier has length of 1, call putchar.  */
-      if (fmt_str[1] == '\0')
-       {
-         /* Given printf("c"), (where c is any one character,)
-            convert "c"[0] to an int and pass that to the replacement
-            function.  */
-         arg = build_int_cst (NULL_TREE, fmt_str[0]);
-         if (fn_putchar)
-           fn = build_call_nofold (fn_putchar, 1, arg);
-       }
-      else
-       {
-         /* If the format specifier was "string\n", call puts("string").  */
-         size_t len = strlen (fmt_str);
-         if ((unsigned char)fmt_str[len - 1] == target_newline)
-           {
-             /* Create a NUL-terminated string that's one char shorter
-                than the original, stripping off the trailing '\n'.  */
-             char *newstr = XALLOCAVEC (char, len);
-             memcpy (newstr, fmt_str, len - 1);
-             newstr[len - 1] = 0;
-             arg = build_string_literal (len, newstr);
-             if (fn_puts)
-               fn = build_call_nofold (fn_puts, 1, arg);
-           }
-         else
-           /* We'd like to arrange to call fputs(string,stdout) here,
-              but we need stdout and don't have a way to get it yet.  */
-           return NULL_RTX;
-       }
-    }
-
-  if (!fn)
-    return NULL_RTX;
-  gcc_assert (TREE_CODE (fn) == CALL_EXPR);
-  CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
-  return expand_expr (fn, target, mode, EXPAND_NORMAL);
-}
-
-/* Expand EXP, a call to fprintf or fprintf_unlocked.
-   Return NULL_RTX if a normal call should be emitted rather than transforming
-   the function inline.  If convenient, the result should be placed in
-   TARGET with mode MODE.  UNLOCKED indicates this is a fprintf_unlocked
-   call.  */
-static rtx
-expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode,
-                       bool unlocked)
-{
-  /* If we're using an unlocked function, assume the other unlocked
-     functions exist explicitly.  */
-  tree const fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
-    : implicit_built_in_decls[BUILT_IN_FPUTC];
-  tree const fn_fputs = unlocked ? built_in_decls[BUILT_IN_FPUTS_UNLOCKED]
-    : implicit_built_in_decls[BUILT_IN_FPUTS];
-  const char *fmt_str;
-  tree fn = 0;
-  tree fmt, fp, arg;
-  int nargs = call_expr_nargs (exp);
-
-  /* If the return value is used, don't do the transformation.  */
-  if (target != const0_rtx)
-    return NULL_RTX;
-
-  /* Verify the required arguments in the original call.  */
-  if (nargs < 2)
-    return NULL_RTX;
-  fp = CALL_EXPR_ARG (exp, 0);
-  if (! POINTER_TYPE_P (TREE_TYPE (fp)))
-    return NULL_RTX;
-  fmt = CALL_EXPR_ARG (exp, 1);
-  if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
-    return NULL_RTX;
-
-  /* Check whether the format is a literal string constant.  */
-  fmt_str = c_getstr (fmt);
-  if (fmt_str == NULL)
-    return NULL_RTX;
-
-  if (!init_target_chars ())
-    return NULL_RTX;
-
-  /* If the format specifier was "%s", call __builtin_fputs(arg,fp).  */
-  if (strcmp (fmt_str, target_percent_s) == 0)
-    {
-      if ((nargs != 3)
-         || ! POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_ARG (exp, 2))))
-       return NULL_RTX;
-      arg = CALL_EXPR_ARG (exp, 2);
-      if (fn_fputs)
-       fn = build_call_nofold (fn_fputs, 2, arg, fp);
-    }
-  /* If the format specifier was "%c", call __builtin_fputc(arg,fp).  */
-  else if (strcmp (fmt_str, target_percent_c) == 0)
-    {
-      if ((nargs != 3)
-         || TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (exp, 2))) != INTEGER_TYPE)
-       return NULL_RTX;
-      arg = CALL_EXPR_ARG (exp, 2);
-      if (fn_fputc)
-       fn = build_call_nofold (fn_fputc, 2, arg, fp);
-    }
-  else
-    {
-      /* We can't handle anything else with % args or %% ... yet.  */
-      if (strchr (fmt_str, target_percent))
-       return NULL_RTX;
-
-      if (nargs > 2)
-       return NULL_RTX;
-
-      /* If the format specifier was "", fprintf does nothing.  */
-      if (fmt_str[0] == '\0')
-       {
-         /* Evaluate and ignore FILE* argument for side-effects.  */
-         expand_expr (fp, const0_rtx, VOIDmode, EXPAND_NORMAL);
-         return const0_rtx;
-       }
-
-      /* When "string" doesn't contain %, replace all cases of
-        fprintf(stream,string) with fputs(string,stream).  The fputs
-        builtin will take care of special cases like length == 1.  */
-      if (fn_fputs)
-       fn = build_call_nofold (fn_fputs, 2, fmt, fp);
-    }
-
-  if (!fn)
-    return NULL_RTX;
-  gcc_assert (TREE_CODE (fn) == CALL_EXPR);
-  CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
-  return expand_expr (fn, target, mode, EXPAND_NORMAL);
-}
-
-/* Expand a call EXP to sprintf.  Return NULL_RTX if
-   a normal call should be emitted rather than expanding the function
-   inline.  If convenient, the result should be placed in TARGET with
-   mode MODE.  */
-
-static rtx
-expand_builtin_sprintf (tree exp, rtx target, enum machine_mode mode)
-{
-  tree dest, fmt;
-  const char *fmt_str;
-  int nargs = call_expr_nargs (exp);
-
-  /* Verify the required arguments in the original call.  */
-  if (nargs < 2)
-    return NULL_RTX;
-  dest = CALL_EXPR_ARG (exp, 0);
-  if (! POINTER_TYPE_P (TREE_TYPE (dest)))
-    return NULL_RTX;
-  fmt = CALL_EXPR_ARG (exp, 0);
-  if (! POINTER_TYPE_P (TREE_TYPE (fmt)))
-    return NULL_RTX;
-
-  /* Check whether the format is a literal string constant.  */
-  fmt_str = c_getstr (fmt);
-  if (fmt_str == NULL)
-    return NULL_RTX;
-
-  if (!init_target_chars ())
-    return NULL_RTX;
-
-  /* If the format doesn't contain % args or %%, use strcpy.  */
-  if (strchr (fmt_str, target_percent) == 0)
-    {
-      tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
-      tree exp;
-
-      if ((nargs > 2) || ! fn)
-       return NULL_RTX;
-      expand_expr (build_call_nofold (fn, 2, dest, fmt),
-                  const0_rtx, VOIDmode, EXPAND_NORMAL);
-      if (target == const0_rtx)
-       return const0_rtx;
-      exp = build_int_cst (NULL_TREE, strlen (fmt_str));
-      return expand_expr (exp, target, mode, EXPAND_NORMAL);
-    }
-  /* If the format is "%s", use strcpy if the result isn't used.  */
-  else if (strcmp (fmt_str, target_percent_s) == 0)
-    {
-      tree fn, arg, len;
-      fn = implicit_built_in_decls[BUILT_IN_STRCPY];
-
-      if (! fn)
-       return NULL_RTX;
-      if (nargs != 3)
-       return NULL_RTX;
-      arg = CALL_EXPR_ARG (exp, 2);
-      if (! POINTER_TYPE_P (TREE_TYPE (arg)))
-       return NULL_RTX;
-
-      if (target != const0_rtx)
-       {
-         len = c_strlen (arg, 1);
-         if (! len || TREE_CODE (len) != INTEGER_CST)
-           return NULL_RTX;
-       }
-      else
-       len = NULL_TREE;
-
-      expand_expr (build_call_nofold (fn, 2, dest, arg),
-                  const0_rtx, VOIDmode, EXPAND_NORMAL);
-
-      if (target == const0_rtx)
-       return const0_rtx;
-      return expand_expr (len, target, mode, EXPAND_NORMAL);
-    }
-
-  return NULL_RTX;
-}
-
 /* Expand a call to either the entry or exit function profiler.  */
 
 static rtx
@@ -5443,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;
@@ -5468,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
@@ -5517,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
@@ -6365,36 +6193,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       expand_builtin_unreachable ();
       return const0_rtx;
 
-    case BUILT_IN_PRINTF:
-      target = expand_builtin_printf (exp, target, mode, false);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_PRINTF_UNLOCKED:
-      target = expand_builtin_printf (exp, target, mode, true);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_FPRINTF:
-      target = expand_builtin_fprintf (exp, target, mode, false);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_FPRINTF_UNLOCKED:
-      target = expand_builtin_fprintf (exp, target, mode, true);
-      if (target)
-       return target;
-      break;
-
-    case BUILT_IN_SPRINTF:
-      target = expand_builtin_sprintf (exp, target, mode);
-      if (target)
-       return target;
-      break;
-
     CASE_FLT_FN (BUILT_IN_SIGNBIT):
     case BUILT_IN_SIGNBITD32:
     case BUILT_IN_SIGNBITD64:
@@ -6929,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;
@@ -6938,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;
     }
@@ -7249,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.  */
 
@@ -7465,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)))
@@ -7563,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));
 
@@ -9978,7 +9835,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);
@@ -10013,7 +9870,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)
@@ -10050,7 +9909,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)
@@ -10086,8 +9944,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);
@@ -10405,7 +10261,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
@@ -10413,7 +10268,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);
@@ -13033,7 +12887,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.
@@ -13055,8 +12908,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
@@ -13080,7 +12933,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.
@@ -13478,7 +13330,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
@@ -13532,7 +13383,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))
@@ -13583,8 +13433,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
@@ -13924,6 +13772,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;
     }