OSDN Git Service

* toplev.c (rest_of_compilation): Avoid cfg_cleanup calls when not
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index a686c8d..d2505cd 100644 (file)
@@ -1,6 +1,6 @@
 /* Expand builtin functions.
-   Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -21,11 +21,12 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "machmode.h"
 #include "real.h"
 #include "rtl.h"
 #include "tree.h"
-#include "obstack.h"
 #include "flags.h"
 #include "regs.h"
 #include "hard-reg-set.h"
@@ -63,7 +64,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 const char *const built_in_class_names[4]
   = {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
 
-#define DEF_BUILTIN(X, N, C, T, LT, B, F, NA) STRINGX(X),
+#define DEF_BUILTIN(X, N, C, T, LT, B, F, NA, AT, IM) STRINGX(X),
 const char *const built_in_names[(int) END_BUILTINS] =
 {
 #include "builtins.def"
@@ -73,6 +74,10 @@ const char *const built_in_names[(int) END_BUILTINS] =
 /* Setup an array of _DECL trees, make sure each element is
    initialized to NULL_TREE.  */
 tree built_in_decls[(int) END_BUILTINS];
+/* Declarations used when constructing the builtin implicitly in the compiler.
+   It may be NULL_TREE when this is invalid (for instance runtime is not
+   required to implement the function call in all cases.  */
+tree implicit_built_in_decls[(int) END_BUILTINS];
 
 static int get_pointer_alignment       PARAMS ((tree, unsigned int));
 static tree c_strlen                   PARAMS ((tree));
@@ -94,11 +99,13 @@ static rtx expand_builtin_apply             PARAMS ((rtx, rtx, rtx));
 static void expand_builtin_return      PARAMS ((rtx));
 static enum type_class type_to_class   PARAMS ((tree));
 static rtx expand_builtin_classify_type        PARAMS ((tree));
+static void expand_errno_check         PARAMS ((tree, rtx));
 static rtx expand_builtin_mathfn       PARAMS ((tree, rtx, rtx));
+static rtx expand_builtin_mathfn_2     PARAMS ((tree, rtx, rtx));
 static rtx expand_builtin_constant_p   PARAMS ((tree));
 static rtx expand_builtin_args_info    PARAMS ((tree));
 static rtx expand_builtin_next_arg     PARAMS ((tree));
-static rtx expand_builtin_va_start     PARAMS ((int, tree));
+static rtx expand_builtin_va_start     PARAMS ((tree));
 static rtx expand_builtin_va_end       PARAMS ((tree));
 static rtx expand_builtin_va_copy      PARAMS ((tree));
 static rtx expand_builtin_memcmp       PARAMS ((tree, tree, rtx,
@@ -142,15 +149,17 @@ static rtx expand_builtin_strchr  PARAMS ((tree, rtx,
 static rtx expand_builtin_strrchr      PARAMS ((tree, rtx,
                                                 enum machine_mode));
 static rtx expand_builtin_alloca       PARAMS ((tree, rtx));
-static rtx expand_builtin_ffs          PARAMS ((tree, rtx, rtx));
+static rtx expand_builtin_unop         PARAMS ((tree, rtx, rtx, optab));
 static rtx expand_builtin_frame_address        PARAMS ((tree));
 static rtx expand_builtin_fputs                PARAMS ((tree, int, int));
 static tree stabilize_va_list          PARAMS ((tree, int));
 static rtx expand_builtin_expect       PARAMS ((tree, rtx));
 static tree fold_builtin_constant_p    PARAMS ((tree));
 static tree fold_builtin_classify_type PARAMS ((tree));
-static tree build_function_call_expr   PARAMS ((tree, tree));
+static tree fold_builtin_inf           PARAMS ((tree, int));
+static tree fold_builtin_nan           PARAMS ((tree, tree, int));
 static int validate_arglist            PARAMS ((tree, ...));
+static tree fold_trunc_transparent_mathfn PARAMS ((tree));
 
 /* Return the alignment in bits of EXP, a pointer valued expression.
    But don't return more than MAX_ALIGN no matter what.
@@ -789,10 +798,10 @@ expand_builtin_prefetch (arglist)
 #ifdef HAVE_prefetch
   if (HAVE_prefetch)
     {
-      if ((! (*insn_data[(int)CODE_FOR_prefetch].operand[0].predicate)
+      if ((! (*insn_data[(int) CODE_FOR_prefetch].operand[0].predicate)
             (op0,
-             insn_data[(int)CODE_FOR_prefetch].operand[0].mode)) ||
-         (GET_MODE(op0) != Pmode))
+             insn_data[(int) CODE_FOR_prefetch].operand[0].mode))
+         || (GET_MODE(op0) != Pmode))
        {
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE(op0) != Pmode)
@@ -805,10 +814,10 @@ expand_builtin_prefetch (arglist)
   else
 #endif
     op0 = protect_from_queue (op0, 0);
-    /* Don't do anything with direct references to volatile memory, but
-       generate code to handle other side effects.  */
-    if (GET_CODE (op0) != MEM && side_effects_p (op0))
-      emit_insn (op0);
+  /* Don't do anything with direct references to volatile memory, but
+     generate code to handle other side effects.  */
+  if (GET_CODE (op0) != MEM && side_effects_p (op0))
+    emit_insn (op0);
 }
 
 /* Get a MEM rtx for expression EXP which is the address of an operand
@@ -832,7 +841,7 @@ get_memory_rtx (exp)
      If it is an ADDR_EXPR, use the operand.  Otherwise, dereference it if
      we can.  First remove any nops.  */
   while ((TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
-        || TREE_CODE (exp) == NON_LVALUE_EXPR)
+         || TREE_CODE (exp) == NON_LVALUE_EXPR)
         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
     exp = TREE_OPERAND (exp, 0);
 
@@ -886,7 +895,7 @@ apply_args_register_offset (regno)
   /* Arguments are always put in outgoing registers (in the argument
      block) if such make sense.  */
 #ifdef OUTGOING_REGNO
-  regno = OUTGOING_REGNO(regno);
+  regno = OUTGOING_REGNO (regno);
 #endif
   return apply_args_reg_offset[regno];
 }
@@ -1013,7 +1022,7 @@ apply_result_size ()
                   mode = GET_MODE_WIDER_MODE (mode))
                if (HARD_REGNO_MODE_OK (regno, mode)
                    && have_insn_for (SET, mode))
-                     best_mode = mode;
+                 best_mode = mode;
 
            if (best_mode == VOIDmode)
              for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
@@ -1159,12 +1168,12 @@ expand_builtin_apply_args ()
 
     apply_args_value = temp;
 
-    /* Put the sequence after the NOTE that starts the function.
-       If this is inside a SEQUENCE, make the outer-level insn
+    /* Put the insns after the NOTE that starts the function.
+       If this is inside a start_sequence, make the outer-level insn
        chain current, so the code is placed at the start of the
        function.  */
     push_topmost_sequence ();
-    emit_insns_before (seq, NEXT_INSN (get_insns ()));
+    emit_insn_before (seq, NEXT_INSN (get_insns ()));
     pop_topmost_sequence ();
     return temp;
   }
@@ -1226,7 +1235,7 @@ expand_builtin_apply (function, arguments, argsize)
   set_mem_align (dest, PARM_BOUNDARY);
   src = gen_rtx_MEM (BLKmode, incoming_args);
   set_mem_align (src, PARM_BOUNDARY);
-  emit_block_move (dest, src, argsize);
+  emit_block_move (dest, src, argsize, BLOCK_OP_NORMAL);
 
   /* Refer to the argument block.  */
   apply_args_size ();
@@ -1261,7 +1270,7 @@ expand_builtin_apply (function, arguments, argsize)
       emit_move_insn (value, adjust_address (arguments, Pmode, size));
       emit_move_insn (struct_value_rtx, value);
       if (GET_CODE (struct_value_rtx) == REG)
-         use_reg (&call_fusage, struct_value_rtx);
+       use_reg (&call_fusage, struct_value_rtx);
       size += GET_MODE_SIZE (Pmode);
     }
 
@@ -1393,7 +1402,7 @@ expand_builtin_return (result)
       }
 
   /* Put the USE insns before the return.  */
-  emit_insns (call_fusage);
+  emit_insn (call_fusage);
 
   /* Return whatever values was restored by jumping directly to the end
      of the function.  */
@@ -1459,14 +1468,239 @@ expand_builtin_constant_p (exp)
   arglist = TREE_VALUE (arglist);
 
   /* We have taken care of the easy cases during constant folding.  This
-     case is not obvious, so emit (constant_p_rtx (ARGLIST)) and let CSE get a
-     chance to see if it can deduce whether ARGLIST is constant.  */
+     case is not obvious, so emit (constant_p_rtx (ARGLIST)) and let CSE
+     get a chance to see if it can deduce whether ARGLIST is constant.  */
+
+  current_function_calls_constant_p = 1;
 
   tmp = expand_expr (arglist, NULL_RTX, VOIDmode, 0);
   tmp = gen_rtx_CONSTANT_P_RTX (value_mode, tmp);
   return tmp;
 }
 
+/* Return mathematic function equivalent to FN but operating directly on TYPE,
+   if available.  */
+tree
+mathfn_built_in (type, fn)
+     tree type;
+     enum built_in_function fn;
+{
+  enum built_in_function fcode = NOT_BUILT_IN;
+  if (TYPE_MODE (type) == TYPE_MODE (double_type_node))
+    switch (fn)
+      {
+      case BUILT_IN_SQRT:
+      case BUILT_IN_SQRTF:
+      case BUILT_IN_SQRTL:
+       fcode = BUILT_IN_SQRT;
+       break;
+      case BUILT_IN_SIN:
+      case BUILT_IN_SINF:
+      case BUILT_IN_SINL:
+       fcode = BUILT_IN_SIN;
+       break;
+      case BUILT_IN_COS:
+      case BUILT_IN_COSF:
+      case BUILT_IN_COSL:
+       fcode = BUILT_IN_COS;
+       break;
+      case BUILT_IN_EXP:
+      case BUILT_IN_EXPF:
+      case BUILT_IN_EXPL:
+       fcode = BUILT_IN_EXP;
+       break;
+      case BUILT_IN_LOG:
+      case BUILT_IN_LOGF:
+      case BUILT_IN_LOGL:
+       fcode = BUILT_IN_LOG;
+       break;
+      case BUILT_IN_FLOOR:
+      case BUILT_IN_FLOORF:
+      case BUILT_IN_FLOORL:
+       fcode = BUILT_IN_FLOOR;
+       break;
+      case BUILT_IN_CEIL:
+      case BUILT_IN_CEILF:
+      case BUILT_IN_CEILL:
+       fcode = BUILT_IN_CEIL;
+       break;
+      case BUILT_IN_TRUNC:
+      case BUILT_IN_TRUNCF:
+      case BUILT_IN_TRUNCL:
+       fcode = BUILT_IN_TRUNC;
+       break;
+      case BUILT_IN_ROUND:
+      case BUILT_IN_ROUNDF:
+      case BUILT_IN_ROUNDL:
+       fcode = BUILT_IN_ROUND;
+       break;
+      case BUILT_IN_NEARBYINT:
+      case BUILT_IN_NEARBYINTF:
+      case BUILT_IN_NEARBYINTL:
+       fcode = BUILT_IN_NEARBYINT;
+       break;
+      default:
+       abort ();
+      }
+  else if (TYPE_MODE (type) == TYPE_MODE (float_type_node))
+    switch (fn)
+      {
+      case BUILT_IN_SQRT:
+      case BUILT_IN_SQRTF:
+      case BUILT_IN_SQRTL:
+       fcode = BUILT_IN_SQRTF;
+       break;
+      case BUILT_IN_SIN:
+      case BUILT_IN_SINF:
+      case BUILT_IN_SINL:
+       fcode = BUILT_IN_SINF;
+       break;
+      case BUILT_IN_COS:
+      case BUILT_IN_COSF:
+      case BUILT_IN_COSL:
+       fcode = BUILT_IN_COSF;
+       break;
+      case BUILT_IN_EXP:
+      case BUILT_IN_EXPF:
+      case BUILT_IN_EXPL:
+       fcode = BUILT_IN_EXPF;
+       break;
+      case BUILT_IN_LOG:
+      case BUILT_IN_LOGF:
+      case BUILT_IN_LOGL:
+       fcode = BUILT_IN_LOGF;
+       break;
+      case BUILT_IN_FLOOR:
+      case BUILT_IN_FLOORF:
+      case BUILT_IN_FLOORL:
+       fcode = BUILT_IN_FLOORF;
+       break;
+      case BUILT_IN_CEIL:
+      case BUILT_IN_CEILF:
+      case BUILT_IN_CEILL:
+       fcode = BUILT_IN_CEILF;
+       break;
+      case BUILT_IN_TRUNC:
+      case BUILT_IN_TRUNCF:
+      case BUILT_IN_TRUNCL:
+       fcode = BUILT_IN_TRUNCF;
+       break;
+      case BUILT_IN_ROUND:
+      case BUILT_IN_ROUNDF:
+      case BUILT_IN_ROUNDL:
+       fcode = BUILT_IN_ROUNDF;
+       break;
+      case BUILT_IN_NEARBYINT:
+      case BUILT_IN_NEARBYINTF:
+      case BUILT_IN_NEARBYINTL:
+       fcode = BUILT_IN_NEARBYINTF;
+       break;
+      default:
+       abort ();
+      }
+  else if (TYPE_MODE (type) == TYPE_MODE (long_double_type_node))
+    switch (fn)
+      {
+      case BUILT_IN_SQRT:
+      case BUILT_IN_SQRTF:
+      case BUILT_IN_SQRTL:
+       fcode = BUILT_IN_SQRTL;
+       break;
+      case BUILT_IN_SIN:
+      case BUILT_IN_SINF:
+      case BUILT_IN_SINL:
+       fcode = BUILT_IN_SINL;
+       break;
+      case BUILT_IN_COS:
+      case BUILT_IN_COSF:
+      case BUILT_IN_COSL:
+       fcode = BUILT_IN_COSL;
+       break;
+      case BUILT_IN_EXP:
+      case BUILT_IN_EXPF:
+      case BUILT_IN_EXPL:
+       fcode = BUILT_IN_EXPL;
+       break;
+      case BUILT_IN_LOG:
+      case BUILT_IN_LOGF:
+      case BUILT_IN_LOGL:
+       fcode = BUILT_IN_LOGL;
+       break;
+      case BUILT_IN_FLOOR:
+      case BUILT_IN_FLOORF:
+      case BUILT_IN_FLOORL:
+       fcode = BUILT_IN_FLOORL;
+       break;
+      case BUILT_IN_CEIL:
+      case BUILT_IN_CEILF:
+      case BUILT_IN_CEILL:
+       fcode = BUILT_IN_CEILL;
+       break;
+      case BUILT_IN_TRUNC:
+      case BUILT_IN_TRUNCF:
+      case BUILT_IN_TRUNCL:
+       fcode = BUILT_IN_TRUNCL;
+       break;
+      case BUILT_IN_ROUND:
+      case BUILT_IN_ROUNDF:
+      case BUILT_IN_ROUNDL:
+       fcode = BUILT_IN_ROUNDL;
+       break;
+      case BUILT_IN_NEARBYINT:
+      case BUILT_IN_NEARBYINTF:
+      case BUILT_IN_NEARBYINTL:
+       fcode = BUILT_IN_NEARBYINTL;
+       break;
+      default:
+       abort ();
+      }
+  return implicit_built_in_decls[fcode];
+}
+
+/* If errno must be maintained, expand the RTL to check if the result,
+   TARGET, of a built-in function call, EXP, is NaN, and if so set
+   errno to EDOM.  */
+
+static void
+expand_errno_check (exp, target)
+     tree exp;
+     rtx target;
+{
+  rtx lab;
+
+  if (flag_errno_math && HONOR_NANS (GET_MODE (target)))
+    {
+      lab = gen_label_rtx ();
+
+      /* Test the result; if it is NaN, set errno=EDOM because
+        the argument was not in the domain.  */
+      emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
+                              0, lab);
+
+#ifdef TARGET_EDOM
+      {
+#ifdef GEN_ERRNO_RTX
+       rtx errno_rtx = GEN_ERRNO_RTX;
+#else
+       rtx errno_rtx
+         = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
+#endif
+
+       emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
+      }
+#else
+      /* We can't set errno=EDOM directly; let the library call do it.
+        Pop the arguments right away in case the call gets deleted.  */
+      NO_DEFER_POP;
+      expand_call (exp, target, 0);
+      OK_DEFER_POP;
+#endif
+
+      emit_label (lab);
+    }
+}
+
+
 /* Expand a call to one of the builtin math functions (sin, cos, or sqrt).
    Return 0 if a normal call should be emitted rather than expanding the
    function in-line.  EXP is the expression that is a call to the builtin
@@ -1483,6 +1717,7 @@ expand_builtin_mathfn (exp, target, subtarget)
   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
   tree arglist = TREE_OPERAND (exp, 1);
   enum machine_mode argmode;
+  bool errno_set = true;
 
   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
     return 0;
@@ -1525,7 +1760,35 @@ expand_builtin_mathfn (exp, target, subtarget)
     case BUILT_IN_SQRTF:
     case BUILT_IN_SQRTL:
       builtin_optab = sqrt_optab; break;
-     default:
+    case BUILT_IN_EXP:
+    case BUILT_IN_EXPF:
+    case BUILT_IN_EXPL:
+      builtin_optab = exp_optab; break;
+    case BUILT_IN_LOG:
+    case BUILT_IN_LOGF:
+    case BUILT_IN_LOGL:
+      builtin_optab = log_optab; break;
+    case BUILT_IN_FLOOR:
+    case BUILT_IN_FLOORF:
+    case BUILT_IN_FLOORL:
+      errno_set = false ; builtin_optab = floor_optab; break;
+    case BUILT_IN_CEIL:
+    case BUILT_IN_CEILF:
+    case BUILT_IN_CEILL:
+      errno_set = false ; builtin_optab = ceil_optab; break;
+    case BUILT_IN_TRUNC:
+    case BUILT_IN_TRUNCF:
+    case BUILT_IN_TRUNCL:
+      errno_set = false ; builtin_optab = trunc_optab; break;
+    case BUILT_IN_ROUND:
+    case BUILT_IN_ROUNDF:
+    case BUILT_IN_ROUNDL:
+      errno_set = false ; builtin_optab = round_optab; break;
+    case BUILT_IN_NEARBYINT:
+    case BUILT_IN_NEARBYINTF:
+    case BUILT_IN_NEARBYINTL:
+      errno_set = false ; builtin_optab = nearbyint_optab; break;
+    default:
       abort ();
     }
 
@@ -1543,45 +1806,111 @@ expand_builtin_mathfn (exp, target, subtarget)
       return 0;
     }
 
-  /* If errno must be maintained, we must set it to EDOM for NaN results.  */
+  if (errno_set)
+    expand_errno_check (exp, target);
+
+  /* Output the entire sequence.  */
+  insns = get_insns ();
+  end_sequence ();
+  emit_insn (insns);
+
+  return target;
+}
+
+/* Expand a call to the builtin binary math functions (pow and atan2).
+   Return 0 if a normal call should be emitted rather than expanding the
+   function in-line.  EXP is the expression that is a call to the builtin
+   function; if convenient, the result should be placed in TARGET.
+   SUBTARGET may be used as the target for computing one of EXP's
+   operands.  */
+
+static rtx
+expand_builtin_mathfn_2 (exp, target, subtarget)
+     tree exp;
+     rtx target, subtarget;
+{
+  optab builtin_optab;
+  rtx op0, op1, insns;
+  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  tree arglist = TREE_OPERAND (exp, 1);
+  tree arg0, arg1;
+  enum machine_mode argmode;
+  bool errno_set = true;
+  bool stable = true;
+
+  if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
+    return 0;
+
+  arg0 = TREE_VALUE (arglist);
+  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
 
-  if (flag_errno_math && HONOR_NANS (argmode))
+  /* Stabilize the arguments.  */
+  if (TREE_CODE (arg0) != VAR_DECL && TREE_CODE (arg0) != PARM_DECL)
+    {
+      arg0 = save_expr (arg0);
+      TREE_VALUE (arglist) = arg0;
+      stable = false;
+    }
+  if (TREE_CODE (arg1) != VAR_DECL && TREE_CODE (arg1) != PARM_DECL)
     {
-      rtx lab1;
+      arg1 = save_expr (arg1);
+      TREE_VALUE (TREE_CHAIN (arglist)) = arg1;
+      stable = false;
+    }
 
-      lab1 = gen_label_rtx ();
+  if (! stable)
+    {
+      exp = copy_node (exp);
+      arglist = tree_cons (NULL_TREE, arg0,
+                          build_tree_list (NULL_TREE, arg1));
+      TREE_OPERAND (exp, 1) = arglist;
+    }
 
-      /* Test the result; if it is NaN, set errno=EDOM because
-        the argument was not in the domain.  */
-      emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
-                              0, lab1);
+  op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
+  op1 = expand_expr (arg1, 0, VOIDmode, 0);
 
-#ifdef TARGET_EDOM
-      {
-#ifdef GEN_ERRNO_RTX
-       rtx errno_rtx = GEN_ERRNO_RTX;
-#else
-       rtx errno_rtx
-         = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
-#endif
+  /* Make a suitable register to place result in.  */
+  target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
 
-       emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
-      }
-#else
-      /* We can't set errno=EDOM directly; let the library call do it.
-        Pop the arguments right away in case the call gets deleted.  */
-      NO_DEFER_POP;
-      expand_call (exp, target, 0);
-      OK_DEFER_POP;
-#endif
+  emit_queue ();
+  start_sequence ();
 
-      emit_label (lab1);
+  switch (DECL_FUNCTION_CODE (fndecl))
+    {
+    case BUILT_IN_POW:
+    case BUILT_IN_POWF:
+    case BUILT_IN_POWL:
+      builtin_optab = pow_optab; break;
+    case BUILT_IN_ATAN2:
+    case BUILT_IN_ATAN2F:
+    case BUILT_IN_ATAN2L:
+      builtin_optab = atan2_optab; break;
+    default:
+      abort ();
     }
 
+  /* Compute into TARGET.
+     Set TARGET to wherever the result comes back.  */
+  argmode = TYPE_MODE (TREE_TYPE (arg0));
+  target = expand_binop (argmode, builtin_optab, op0, op1,
+                        target, 0, OPTAB_DIRECT);
+
+  /* If we were unable to expand via the builtin, stop the
+     sequence (without outputting the insns) and return 0, causing
+     a call to the library function.  */
+  if (target == 0)
+    {
+      end_sequence ();
+      return 0;
+    }
+
+  if (errno_set)
+    expand_errno_check (exp, target);
+
   /* Output the entire sequence.  */
   insns = get_insns ();
   end_sequence ();
-  emit_insns (insns);
+  emit_insn (insns);
 
   return target;
 }
@@ -1643,7 +1972,7 @@ expand_builtin_strlen (exp, target)
 
       /* Mark the beginning of the strlen sequence so we can emit the
         source operand later.  */
-      before_strlen = get_last_insn();
+      before_strlen = get_last_insn ();
 
       char_rtx = const0_rtx;
       char_mode = insn_data[(int) icode].operand[2].mode;
@@ -1663,7 +1992,7 @@ expand_builtin_strlen (exp, target)
                            expand_expr (src, src_reg, ptr_mode, EXPAND_SUM));
       if (pat != src_reg)
        emit_move_insn (src_reg, pat);
-      pat = gen_sequence ();
+      pat = get_insns ();
       end_sequence ();
 
       if (before_strlen)
@@ -1725,7 +2054,7 @@ expand_builtin_strstr (arglist, target, mode)
       if (p2[1] != '\0')
        return 0;
 
-      fn = built_in_decls[BUILT_IN_STRCHR];
+      fn = implicit_built_in_decls[BUILT_IN_STRCHR];
       if (!fn)
        return 0;
 
@@ -1829,7 +2158,7 @@ expand_builtin_strrchr (arglist, target, mode)
       if (! integer_zerop (s2))
        return 0;
 
-      fn = built_in_decls[BUILT_IN_STRCHR];
+      fn = implicit_built_in_decls[BUILT_IN_STRCHR];
       if (!fn)
        return 0;
 
@@ -1887,7 +2216,7 @@ expand_builtin_strpbrk (arglist, target, mode)
       if (p2[1] != '\0')
        return 0;  /* Really call strpbrk.  */
 
-      fn = built_in_decls[BUILT_IN_STRCHR];
+      fn = implicit_built_in_decls[BUILT_IN_STRCHR];
       if (!fn)
        return 0;
 
@@ -1981,17 +2310,29 @@ expand_builtin_memcpy (arglist, target, mode)
          store_by_pieces (dest_mem, INTVAL (len_rtx),
                           builtin_memcpy_read_str,
                           (PTR) src_str, dest_align);
-         return force_operand (XEXP (dest_mem, 0), NULL_RTX);
+         dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (dest_mem) != ptr_mode)
+           dest_mem = convert_memory_address (ptr_mode, dest_mem);
+#endif
+         return dest_mem;
        }
 
       src_mem = get_memory_rtx (src);
       set_mem_align (src_mem, src_align);
 
       /* Copy word part most expediently.  */
-      dest_addr = emit_block_move (dest_mem, src_mem, len_rtx);
+      dest_addr = emit_block_move (dest_mem, src_mem, len_rtx,
+                                  BLOCK_OP_NORMAL);
 
       if (dest_addr == 0)
-       dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+       {
+         dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (dest_addr) != ptr_mode)
+           dest_addr = convert_memory_address (ptr_mode, dest_addr);
+#endif
+       }
 
       return dest_addr;
     }
@@ -2014,7 +2355,7 @@ expand_builtin_strcpy (exp, target, mode)
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
 
-  fn = built_in_decls[BUILT_IN_MEMCPY];
+  fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
   if (!fn)
     return 0;
 
@@ -2107,11 +2448,16 @@ expand_builtin_strncpy (arglist, target, mode)
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_strncpy_read_str,
                           (PTR) p, dest_align);
-         return force_operand (XEXP (dest_mem, 0), NULL_RTX);
+         dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (dest_mem) != ptr_mode)
+           dest_mem = convert_memory_address (ptr_mode, dest_mem);
+#endif
+         return dest_mem;
        }
 
       /* OK transform into builtin memcpy.  */
-      fn = built_in_decls[BUILT_IN_MEMCPY];
+      fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
       if (!fn)
        return 0;
       return expand_expr (build_function_call_expr (fn, arglist),
@@ -2153,14 +2499,14 @@ builtin_memset_gen_str (data, offset, mode)
   char *p;
 
   size = GET_MODE_SIZE (mode);
-  if (size==1)
-    return (rtx)data;
+  if (size == 1)
+    return (rtx) data;
 
   p = alloca (size);
   memset (p, 1, size);
   coeff = c_readstr (p, mode);
 
-  target = convert_to_mode (mode, (rtx)data, 1);
+  target = convert_to_mode (mode, (rtx) data, 1);
   target = expand_mult (mode, target, coeff, NULL_RTX, 1);
   return force_reg (mode, target);
 }
@@ -2231,8 +2577,13 @@ expand_builtin_memset (exp, target, mode)
          dest_mem = get_memory_rtx (dest);
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_memset_gen_str,
-                          (PTR)val_rtx, dest_align);
-         return force_operand (XEXP (dest_mem, 0), NULL_RTX);
+                          (PTR) val_rtx, dest_align);
+         dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (dest_mem) != ptr_mode)
+           dest_mem = convert_memory_address (ptr_mode, dest_mem);
+#endif
+         return dest_mem;
        }
 
       if (target_char_cast (val, &c))
@@ -2251,7 +2602,12 @@ expand_builtin_memset (exp, target, mode)
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_memset_read_str,
                           (PTR) &c, dest_align);
-         return force_operand (XEXP (dest_mem, 0), NULL_RTX);
+         dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (dest_mem) != ptr_mode)
+           dest_mem = convert_memory_address (ptr_mode, dest_mem);
+#endif
+         return dest_mem;
        }
 
       len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
@@ -2261,7 +2617,13 @@ expand_builtin_memset (exp, target, mode)
       dest_addr = clear_storage (dest_mem, len_rtx);
 
       if (dest_addr == 0)
-       dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+       {
+         dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (dest_addr) != ptr_mode)
+           dest_addr = convert_memory_address (ptr_mode, dest_addr);
+#endif
+       }
 
       return dest_addr;
     }
@@ -2511,7 +2873,7 @@ expand_builtin_strcmp (exp, target, mode)
   if (TREE_SIDE_EFFECTS (len))
     return 0;
 
-  fn = built_in_decls[BUILT_IN_MEMCMP];
+  fn = implicit_built_in_decls[BUILT_IN_MEMCMP];
   if (!fn)
     return 0;
 
@@ -2605,7 +2967,7 @@ expand_builtin_strncmp (exp, target, mode)
   if (!len)
     return 0;
 
-  fn = built_in_decls[BUILT_IN_MEMCMP];
+  fn = implicit_built_in_decls[BUILT_IN_MEMCMP];
   if (!fn)
     return 0;
 
@@ -2686,7 +3048,7 @@ expand_builtin_strncat (arglist, target, mode)
        {
          tree newarglist
            = tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src));
-         tree fn = built_in_decls[BUILT_IN_STRCAT];
+         tree fn = implicit_built_in_decls[BUILT_IN_STRCAT];
 
          /* If the replacement _DECL isn't initialized, don't do the
             transformation.  */
@@ -2774,7 +3136,7 @@ expand_builtin_strcspn (arglist, target, mode)
       if (p2 && *p2 == '\0')
        {
          tree newarglist = build_tree_list (NULL_TREE, s1),
-           fn = built_in_decls[BUILT_IN_STRLEN];
+           fn = implicit_built_in_decls[BUILT_IN_STRLEN];
 
          /* If the replacement _DECL isn't initialized, don't do the
             transformation.  */
@@ -2828,11 +3190,11 @@ expand_builtin_saveregs ()
 
   saveregs_value = val;
 
-  /* Put the sequence after the NOTE that starts the function.  If this
-     is inside a SEQUENCE, make the outer-level insn chain current, so
+  /* Put the insns after the NOTE that starts the function.  If this
+     is inside a start_sequence, make the outer-level insn chain current, so
      the code is placed at the start of the function.  */
   push_topmost_sequence ();
-  emit_insns_after (seq, get_insns ());
+  emit_insn_after (seq, get_insns ());
   pop_topmost_sequence ();
 
   return val;
@@ -2900,10 +3262,9 @@ expand_builtin_next_arg (arglist)
 {
   tree fntype = TREE_TYPE (current_function_decl);
 
-  if ((TYPE_ARG_TYPES (fntype) == 0
-       || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
-          == void_type_node))
-      && ! current_function_varargs)
+  if (TYPE_ARG_TYPES (fntype) == 0
+      || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
+         == void_type_node))
     {
       error ("`va_start' used in function with fixed args");
       return const0_rtx;
@@ -2926,7 +3287,7 @@ expand_builtin_next_arg (arglist)
       if (arg != last_parm)
        warning ("second parameter of `va_start' not last named argument");
     }
-  else if (! current_function_varargs)
+  else
     /* Evidently an out of date version of <stdarg.h>; can't validate
        va_start's second argument, but can still work as intended.  */
     warning ("`__builtin_next_arg' called without an argument");
@@ -2990,25 +3351,12 @@ stabilize_va_list (valist, needs_lvalue)
    the variable.  */
 
 void
-std_expand_builtin_va_start (stdarg_p, valist, nextarg)
-     int stdarg_p;
+std_expand_builtin_va_start (valist, nextarg)
      tree valist;
      rtx nextarg;
 {
   tree t;
 
-  if (! stdarg_p)
-    {
-      /* The dummy named parameter is declared as a 'word' sized
-        object, but if a 'word' is smaller than an 'int', it would
-        have been promoted to int when it was added to the arglist.  */
-      int align = PARM_BOUNDARY / BITS_PER_UNIT;
-      int size = MAX (UNITS_PER_WORD,
-                     GET_MODE_SIZE (TYPE_MODE (integer_type_node)));
-      int offset = ((size + align - 1) / align) * align;
-      nextarg = plus_constant (nextarg, -offset);
-    }
-
   t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
             make_tree (ptr_type_node, nextarg));
   TREE_SIDE_EFFECTS (t) = 1;
@@ -3016,31 +3364,27 @@ std_expand_builtin_va_start (stdarg_p, valist, nextarg)
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 }
 
-/* Expand ARGLIST, which from a call to __builtin_stdarg_va_start or
-   __builtin_varargs_va_start, depending on STDARG_P.  */
+/* Expand ARGLIST, from a call to __builtin_va_start.  */
 
 static rtx
-expand_builtin_va_start (stdarg_p, arglist)
-     int stdarg_p;
+expand_builtin_va_start (arglist)
      tree arglist;
 {
   rtx nextarg;
-  tree chain = arglist, valist;
+  tree chain, valist;
 
-  if (stdarg_p)
-    nextarg = expand_builtin_next_arg (chain = TREE_CHAIN (arglist));
-  else
-    nextarg = expand_builtin_next_arg (NULL_TREE);
+  chain = TREE_CHAIN (arglist);
 
   if (TREE_CHAIN (chain))
     error ("too many arguments to function `va_start'");
 
+  nextarg = expand_builtin_next_arg (chain);
   valist = stabilize_va_list (TREE_VALUE (arglist), 1);
 
 #ifdef EXPAND_BUILTIN_VA_START
-  EXPAND_BUILTIN_VA_START (stdarg_p, valist, nextarg);
+  EXPAND_BUILTIN_VA_START (valist, nextarg);
 #else
-  std_expand_builtin_va_start (stdarg_p, valist, nextarg);
+  std_expand_builtin_va_start (valist, nextarg);
 #endif
 
   return const0_rtx;
@@ -3217,7 +3561,7 @@ expand_builtin_va_end (arglist)
 
 #ifdef EXPAND_BUILTIN_VA_END
   valist = stabilize_va_list (valist, 0);
-  EXPAND_BUILTIN_VA_END(arglist);
+  EXPAND_BUILTIN_VA_END (arglist);
 #else
   /* Evaluate for side effects, if needed.  I hate macros that don't
      do that.  */
@@ -3277,7 +3621,7 @@ expand_builtin_va_copy (arglist)
       set_mem_align (srcb, TYPE_ALIGN (va_list_type_node));
 
       /* Copy.  */
-      emit_block_move (dstb, srcb, size);
+      emit_block_move (dstb, srcb, size, BLOCK_OP_NORMAL);
     }
 
   return const0_rtx;
@@ -3364,15 +3708,16 @@ expand_builtin_alloca (arglist, target)
   return result;
 }
 
-/* Expand a call to the ffs builtin.  The arguments are in ARGLIST.
+/* Expand a call to a unary builtin.  The arguments are in ARGLIST.
    Return 0 if a normal call should be emitted rather than expanding the
    function in-line.  If convenient, the result should be placed in TARGET.
    SUBTARGET may be used as the target for computing one of EXP's operands.  */
 
 static rtx
-expand_builtin_ffs (arglist, target, subtarget)
+expand_builtin_unop (arglist, target, subtarget, op_optab)
      tree arglist;
      rtx target, subtarget;
+     optab op_optab;
 {
   rtx op0;
   if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
@@ -3380,10 +3725,10 @@ expand_builtin_ffs (arglist, target, subtarget)
 
   /* Compute the argument.  */
   op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
-  /* Compute ffs, into TARGET if possible.
+  /* Compute op, into TARGET if possible.
      Set TARGET to wherever the result comes back.  */
   target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
-                       ffs_optab, op0, target, 1);
+                       op_optab, op0, target, 1);
   if (target == 0)
     abort ();
   return target;
@@ -3399,10 +3744,10 @@ expand_builtin_fputs (arglist, ignore, unlocked)
      int unlocked;
 {
   tree len, fn;
-  tree fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
-    : built_in_decls[BUILT_IN_FPUTC];
-  tree fn_fwrite = unlocked ? built_in_decls[BUILT_IN_FWRITE_UNLOCKED]
-    : built_in_decls[BUILT_IN_FWRITE];
+  tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
+    : implicit_built_in_decls[BUILT_IN_FPUTC];
+  tree fn_fwrite = unlocked ? implicit_built_in_decls[BUILT_IN_FWRITE_UNLOCKED]
+    : implicit_built_in_decls[BUILT_IN_FWRITE];
 
   /* If the return value is used, or the replacement _DECL isn't
      initialized, don't do the transformation.  */
@@ -3495,7 +3840,7 @@ expand_builtin_expect (arglist, target)
   target = expand_expr (exp, target, VOIDmode, EXPAND_NORMAL);
 
   /* Don't bother with expected value notes for integral constants.  */
-  if (GET_CODE (target) != CONST_INT)
+  if (flag_guess_branch_prob && GET_CODE (target) != CONST_INT)
     {
       /* We do need to force this into a register so that we can be
         moderately sure to be able to correctly interpret the branch
@@ -3513,7 +3858,7 @@ expand_builtin_expect (arglist, target)
 
 /* Like expand_builtin_expect, except do this in a jump context.  This is
    called from do_jump if the conditional is a __builtin_expect.  Return either
-   a SEQUENCE of insns to emit the jump or NULL if we cannot optimize
+   a list of insns to emit the jump or NULL if we cannot optimize
    __builtin_expect.  We need to optimize this at jump time so that machines
    like the PowerPC don't turn the test into a SCC operation, and then jump
    based on the test being 0/1.  */
@@ -3534,8 +3879,8 @@ expand_builtin_expect_jump (exp, if_false_label, if_true_label)
   if (TREE_CODE (TREE_TYPE (arg1)) == INTEGER_TYPE
       && (integer_zerop (arg1) || integer_onep (arg1)))
     {
-      int j;
       int num_jumps = 0;
+      rtx insn;
 
       /* If we fail to locate an appropriate conditional jump, we'll
         fall back to normal evaluation.  Ensure that the expression
@@ -3556,16 +3901,17 @@ expand_builtin_expect_jump (exp, if_false_label, if_true_label)
       /* Expand the jump insns.  */
       start_sequence ();
       do_jump (arg0, if_false_label, if_true_label);
-      ret = gen_sequence ();
+      ret = get_insns ();
       end_sequence ();
 
       /* Now that the __builtin_expect has been validated, go through and add
         the expect's to each of the conditional jumps.  If we run into an
         error, just give up and generate the 'safe' code of doing a SCC
         operation and then doing a branch on that.  */
-      for (j = 0; j < XVECLEN (ret, 0); j++)
+      insn = ret;
+      while (insn != NULL_RTX)
        {
-         rtx insn = XVECEXP (ret, 0, j);
+         rtx next = NEXT_INSN (insn);
          rtx pattern;
 
          if (GET_CODE (insn) == JUMP_INSN && any_condjump_p (insn)
@@ -3576,7 +3922,7 @@ expand_builtin_expect_jump (exp, if_false_label, if_true_label)
              int taken;
 
              if (GET_CODE (ifelse) != IF_THEN_ELSE)
-               continue;
+               goto do_next_insn;
 
              if (GET_CODE (XEXP (ifelse, 1)) == LABEL_REF)
                {
@@ -3603,7 +3949,7 @@ expand_builtin_expect_jump (exp, if_false_label, if_true_label)
                  label = NULL_RTX;
                }
              else
-               continue;
+               goto do_next_insn;
 
              /* If the test is expected to fail, reverse the
                 probabilities.  */
@@ -3617,11 +3963,14 @@ expand_builtin_expect_jump (exp, if_false_label, if_true_label)
              else if (label == if_false_label)
                taken = 1 - taken;
              else if (label != if_true_label)
-               continue;
+               goto do_next_insn;
 
              num_jumps++;
              predict_insn_def (insn, PRED_BUILTIN_EXPECT, taken);
            }
+
+       do_next_insn:
+         insn = next;
        }
 
       /* If no jumps were modified, fail and do __builtin_expect the normal
@@ -3663,6 +4012,9 @@ expand_builtin (exp, target, subtarget, mode, ignore)
   tree arglist = TREE_OPERAND (exp, 1);
   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
 
+  /* Perform postincrements before expanding builtin functions. Â */
+  emit_queue ();
+
   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
     return (*targetm.expand_builtin) (exp, target, subtarget, mode, ignore);
 
@@ -3671,11 +4023,27 @@ expand_builtin (exp, target, subtarget, mode, ignore)
   if (!optimize && !CALLED_AS_BUILT_IN (fndecl))
     switch (fcode)
       {
-      case BUILT_IN_SIN:
-      case BUILT_IN_COS:
       case BUILT_IN_SQRT:
       case BUILT_IN_SQRTF:
       case BUILT_IN_SQRTL:
+      case BUILT_IN_SIN:
+      case BUILT_IN_SINF:
+      case BUILT_IN_SINL:
+      case BUILT_IN_COS:
+      case BUILT_IN_COSF:
+      case BUILT_IN_COSL:
+      case BUILT_IN_EXP:
+      case BUILT_IN_EXPF:
+      case BUILT_IN_EXPL:
+      case BUILT_IN_LOG:
+      case BUILT_IN_LOGF:
+      case BUILT_IN_LOGL:
+      case BUILT_IN_POW:
+      case BUILT_IN_POWF:
+      case BUILT_IN_POWL:
+      case BUILT_IN_ATAN2:
+      case BUILT_IN_ATAN2F:
+      case BUILT_IN_ATAN2L:
       case BUILT_IN_MEMSET:
       case BUILT_IN_MEMCPY:
       case BUILT_IN_MEMCMP:
@@ -3709,6 +4077,21 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       case BUILT_IN_FPUTC_UNLOCKED:
       case BUILT_IN_FPUTS_UNLOCKED:
       case BUILT_IN_FWRITE_UNLOCKED:
+      case BUILT_IN_FLOOR:
+      case BUILT_IN_FLOORF:
+      case BUILT_IN_FLOORL:
+      case BUILT_IN_CEIL:
+      case BUILT_IN_CEILF:
+      case BUILT_IN_CEILL:
+      case BUILT_IN_TRUNC:
+      case BUILT_IN_TRUNCF:
+      case BUILT_IN_TRUNCL:
+      case BUILT_IN_ROUND:
+      case BUILT_IN_ROUNDF:
+      case BUILT_IN_ROUNDL:
+      case BUILT_IN_NEARBYINT:
+      case BUILT_IN_NEARBYINTF:
+      case BUILT_IN_NEARBYINTL:
        return expand_call (exp, target, ignore);
 
       default:
@@ -3746,6 +4129,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
     case BUILT_IN_COS:
     case BUILT_IN_COSF:
     case BUILT_IN_COSL:
+    case BUILT_IN_EXP:
+    case BUILT_IN_EXPF:
+    case BUILT_IN_EXPL:
+    case BUILT_IN_LOG:
+    case BUILT_IN_LOGF:
+    case BUILT_IN_LOGL:
       /* Treat these like sqrt only if unsafe math optimizations are allowed,
         because of possible accuracy problems.  */
       if (! flag_unsafe_math_optimizations)
@@ -3753,12 +4142,37 @@ expand_builtin (exp, target, subtarget, mode, ignore)
     case BUILT_IN_SQRT:
     case BUILT_IN_SQRTF:
     case BUILT_IN_SQRTL:
+    case BUILT_IN_FLOOR:
+    case BUILT_IN_FLOORF:
+    case BUILT_IN_FLOORL:
+    case BUILT_IN_CEIL:
+    case BUILT_IN_CEILF:
+    case BUILT_IN_CEILL:
+    case BUILT_IN_TRUNC:
+    case BUILT_IN_TRUNCF:
+    case BUILT_IN_TRUNCL:
+    case BUILT_IN_ROUND:
+    case BUILT_IN_ROUNDF:
+    case BUILT_IN_ROUNDL:
+    case BUILT_IN_NEARBYINT:
+    case BUILT_IN_NEARBYINTF:
+    case BUILT_IN_NEARBYINTL:
       target = expand_builtin_mathfn (exp, target, subtarget);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_FMOD:
+    case BUILT_IN_POW:
+    case BUILT_IN_POWF:
+    case BUILT_IN_POWL:
+    case BUILT_IN_ATAN2:
+    case BUILT_IN_ATAN2F:
+    case BUILT_IN_ATAN2L:
+      if (! flag_unsafe_math_optimizations)
+       break;
+      target = expand_builtin_mathfn_2 (exp, target, subtarget);
+      if (target)
+       return target;
       break;
 
     case BUILT_IN_APPLY_ARGS:
@@ -3838,7 +4252,42 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       break;
 
     case BUILT_IN_FFS:
-      target = expand_builtin_ffs (arglist, target, subtarget);
+    case BUILT_IN_FFSL:
+    case BUILT_IN_FFSLL:
+      target = expand_builtin_unop (arglist, target, subtarget, ffs_optab);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_CLZ:
+    case BUILT_IN_CLZL:
+    case BUILT_IN_CLZLL:
+      target = expand_builtin_unop (arglist, target, subtarget, clz_optab);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_CTZ:
+    case BUILT_IN_CTZL:
+    case BUILT_IN_CTZLL:
+      target = expand_builtin_unop (arglist, target, subtarget, ctz_optab);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_POPCOUNT:
+    case BUILT_IN_POPCOUNTL:
+    case BUILT_IN_POPCOUNTLL:
+      target = expand_builtin_unop (arglist, target, subtarget,
+                                   popcount_optab);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_PARITY:
+    case BUILT_IN_PARITYL:
+    case BUILT_IN_PARITYLL:
+      target = expand_builtin_unop (arglist, target, subtarget, parity_optab);
       if (target)
        return target;
       break;
@@ -3981,15 +4430,6 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       expand_builtin_trap ();
       return const0_rtx;
 
-    case BUILT_IN_PUTCHAR:
-    case BUILT_IN_PUTS:
-    case BUILT_IN_FPUTC:
-    case BUILT_IN_FWRITE:
-    case BUILT_IN_PUTCHAR_UNLOCKED:
-    case BUILT_IN_PUTS_UNLOCKED:
-    case BUILT_IN_FPUTC_UNLOCKED:
-    case BUILT_IN_FWRITE_UNLOCKED:
-      break;
     case BUILT_IN_FPUTS:
       target = expand_builtin_fputs (arglist, ignore,/*unlocked=*/ 0);
       if (target)
@@ -4026,10 +4466,9 @@ expand_builtin (exp, target, subtarget, mode, ignore)
     case BUILT_IN_EH_RETURN_DATA_REGNO:
       return expand_builtin_eh_return_data_regno (arglist);
 #endif
-    case BUILT_IN_VARARGS_START:
-      return expand_builtin_va_start (0, arglist);
+    case BUILT_IN_VA_START:
     case BUILT_IN_STDARG_START:
-      return expand_builtin_va_start (1, arglist);
+      return expand_builtin_va_start (arglist);
     case BUILT_IN_VA_END:
       return expand_builtin_va_end (arglist);
     case BUILT_IN_VA_COPY:
@@ -4041,9 +4480,10 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       return const0_rtx;
 
 
-    default:                   /* just do library call, if unknown builtin */
-      error ("built-in function `%s' not currently supported",
-            IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+    default:   /* just do library call, if unknown builtin */
+      if (!DECL_ASSEMBLER_NAME_SET_P (fndecl))
+       error ("built-in function `%s' not currently supported",
+              IDENTIFIER_POINTER (DECL_NAME (fndecl)));
     }
 
   /* The switch statement above can drop through to cause the function
@@ -4051,6 +4491,57 @@ expand_builtin (exp, target, subtarget, mode, ignore)
   return expand_call (exp, target, ignore);
 }
 
+/* Determine whether a tree node represents a call to a built-in
+   math function.  If the tree T is a call to a built-in function
+   taking a single real argument, then the return value is the
+   DECL_FUNCTION_CODE of the call, e.g. BUILT_IN_SQRT.  Otherwise
+   the return value is END_BUILTINS.  */
+   
+enum built_in_function
+builtin_mathfn_code (t)
+     tree t;
+{
+  tree fndecl, arglist;
+
+  if (TREE_CODE (t) != CALL_EXPR
+      || TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR)
+    return END_BUILTINS;
+
+  fndecl = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
+  if (TREE_CODE (fndecl) != FUNCTION_DECL
+      || ! DECL_BUILT_IN (fndecl)
+      || DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
+    return END_BUILTINS;
+
+  arglist = TREE_OPERAND (t, 1);
+  if (! arglist
+      || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != REAL_TYPE)
+    return END_BUILTINS;
+
+  arglist = TREE_CHAIN (arglist);
+  switch (DECL_FUNCTION_CODE (fndecl))
+    {
+    case BUILT_IN_POW:
+    case BUILT_IN_POWF:
+    case BUILT_IN_POWL:
+    case BUILT_IN_ATAN2:
+    case BUILT_IN_ATAN2F:
+    case BUILT_IN_ATAN2L:
+      if (! arglist
+         || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != REAL_TYPE
+         || TREE_CHAIN (arglist))
+       return END_BUILTINS;
+      break;
+
+    default:
+      if (arglist)
+       return END_BUILTINS;
+      break;
+    }
+
+  return DECL_FUNCTION_CODE (fndecl);
+}
+
 /* Fold a call to __builtin_constant_p, if we know it will evaluate to a
    constant.  ARGLIST is the argument list of the call.  */
 
@@ -4105,6 +4596,74 @@ fold_builtin_classify_type (arglist)
   return build_int_2 (type_to_class (TREE_TYPE (TREE_VALUE (arglist))), 0);
 }
 
+/* Fold a call to __builtin_inf or __builtin_huge_val.  */
+
+static tree
+fold_builtin_inf (type, warn)
+     tree type;
+     int warn;
+{
+  REAL_VALUE_TYPE real;
+
+  if (!MODE_HAS_INFINITIES (TYPE_MODE (type)) && warn)
+    warning ("target format does not support infinity");
+
+  real_inf (&real);
+  return build_real (type, real);
+}
+
+/* Fold a call to __builtin_nan or __builtin_nans.  */
+
+static tree
+fold_builtin_nan (arglist, type, quiet)
+     tree arglist, type;
+     int quiet;
+{
+  REAL_VALUE_TYPE real;
+  const char *str;
+
+  if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
+    return 0;
+  str = c_getstr (TREE_VALUE (arglist));
+  if (!str)
+    return 0;
+
+  if (!real_nan (&real, str, quiet, TYPE_MODE (type)))
+    return 0;
+
+  return build_real (type, real);
+}
+
+/* EXP is assumed to me builtin call where truncation can be propagated
+   across (for instance floor((double)f) == (double)floorf (f).
+   Do the transformation.  */
+static tree
+fold_trunc_transparent_mathfn (exp)
+     tree exp;
+{
+  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  tree arglist = TREE_OPERAND (exp, 1);
+  enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+
+  if (optimize && validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+    {
+      tree arg0 = strip_float_extensions (TREE_VALUE (arglist));
+      tree ftype = TREE_TYPE (exp);
+      tree newtype = TREE_TYPE (arg0);
+      tree decl;
+
+      if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype)
+         && (decl = mathfn_built_in (newtype, fcode)))
+       {
+         arglist =
+           build_tree_list (NULL_TREE, fold (convert (newtype, arg0)));
+         return convert (ftype,
+                         build_function_call_expr (decl, arglist));
+       }
+    }
+  return 0;
+}
+
 /* Used by constant folding to eliminate some builtin calls early.  EXP is
    the CALL_EXPR of a call to a builtin function.  */
 
@@ -4114,6 +4673,7 @@ fold_builtin (exp)
 {
   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
   tree arglist = TREE_OPERAND (exp, 1);
+  tree type = TREE_TYPE (TREE_TYPE (fndecl));
   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
 
   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
@@ -4131,11 +4691,166 @@ fold_builtin (exp)
       if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
        {
          tree len = c_strlen (TREE_VALUE (arglist));
-         if (len != 0)
-           return len;
+         if (len)
+           {
+             /* Convert from the internal "sizetype" type to "size_t".  */
+             if (size_type_node)
+               len = convert (size_type_node, len);
+             return len;
+           }
+       }
+      break;
+
+    case BUILT_IN_SQRT:
+    case BUILT_IN_SQRTF:
+    case BUILT_IN_SQRTL:
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       {
+         enum built_in_function fcode;
+         tree arg = TREE_VALUE (arglist);
+
+         /* Optimize sqrt of constant value.  */
+         if (TREE_CODE (arg) == REAL_CST
+             && ! TREE_CONSTANT_OVERFLOW (arg))
+           {
+             enum machine_mode mode;
+             REAL_VALUE_TYPE r, x;
+
+             x = TREE_REAL_CST (arg);
+             mode = TYPE_MODE (type);
+             if (real_sqrt (&r, mode, &x)
+                 || (!flag_trapping_math && !flag_errno_math))
+               return build_real (type, r);
+           }
+
+         /* Optimize sqrt(exp(x)) = exp(x/2.0).  */
+         fcode = builtin_mathfn_code (arg);
+         if (flag_unsafe_math_optimizations
+             && (fcode == BUILT_IN_EXP
+                 || fcode == BUILT_IN_EXPF
+                 || fcode == BUILT_IN_EXPL))
+           {
+             tree expfn = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+             arg = build (RDIV_EXPR, type,
+                          TREE_VALUE (TREE_OPERAND (arg, 1)),
+                          build_real (type, dconst2));
+             arglist = build_tree_list (NULL_TREE, arg);
+             return build_function_call_expr (expfn, arglist);
+           }
+       }
+      break;
+
+    case BUILT_IN_EXP:
+    case BUILT_IN_EXPF:
+    case BUILT_IN_EXPL:
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       {
+         enum built_in_function fcode;
+         tree arg = TREE_VALUE (arglist);
+
+         /* Optimize exp(0.0) = 1.0.  */
+         if (real_zerop (arg))
+           return build_real (type, dconst1);
+
+         /* Optimize exp(log(x)) = x.  */
+         fcode = builtin_mathfn_code (arg);
+         if (flag_unsafe_math_optimizations
+             && (fcode == BUILT_IN_LOG
+                 || fcode == BUILT_IN_LOGF
+                 || fcode == BUILT_IN_LOGL))
+           return TREE_VALUE (TREE_OPERAND (arg, 1));
+       }
+      break;
+
+    case BUILT_IN_LOG:
+    case BUILT_IN_LOGF:
+    case BUILT_IN_LOGL:
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       {
+         enum built_in_function fcode;
+         tree arg = TREE_VALUE (arglist);
+
+         /* Optimize log(1.0) = 0.0.  */
+         if (real_onep (arg))
+           return build_real (type, dconst0);
+
+         /* Optimize log(exp(x)) = x.  */
+         fcode = builtin_mathfn_code (arg);
+         if (flag_unsafe_math_optimizations
+             && (fcode == BUILT_IN_EXP
+                 || fcode == BUILT_IN_EXPF
+                 || fcode == BUILT_IN_EXPL))
+           return TREE_VALUE (TREE_OPERAND (arg, 1));
+
+         /* Optimize log(sqrt(x)) = log(x)/2.0.  */
+         if (flag_unsafe_math_optimizations
+             && (fcode == BUILT_IN_SQRT
+                 || fcode == BUILT_IN_SQRTF
+                 || fcode == BUILT_IN_SQRTL))
+           {
+             tree logfn = build_function_call_expr (fndecl,
+                                                    TREE_OPERAND (arg, 1));
+             return fold (build (RDIV_EXPR, type, logfn,
+                                 build_real (type, dconst2)));
+           }
+       }
+      break;
+
+    case BUILT_IN_POW:
+    case BUILT_IN_POWF:
+    case BUILT_IN_POWL:
+      if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
+       {
+         tree arg0 = TREE_VALUE (arglist);
+         tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+
+         /* Optimize pow(x,0.0) = 1.0.  */
+         if (real_zerop (arg1))
+           return omit_one_operand (type, build_real (type, dconst1), arg0);
+
+         /* Optimize pow(1.0,y) = 1.0.  */
+         if (real_onep (arg0))
+           return omit_one_operand (type, build_real (type, dconst1), arg1);
        }
       break;
 
+    case BUILT_IN_INF:
+    case BUILT_IN_INFF:
+    case BUILT_IN_INFL:
+      return fold_builtin_inf (type, true);
+
+    case BUILT_IN_HUGE_VAL:
+    case BUILT_IN_HUGE_VALF:
+    case BUILT_IN_HUGE_VALL:
+      return fold_builtin_inf (type, false);
+
+    case BUILT_IN_NAN:
+    case BUILT_IN_NANF:
+    case BUILT_IN_NANL:
+      return fold_builtin_nan (arglist, type, true);
+
+    case BUILT_IN_NANS:
+    case BUILT_IN_NANSF:
+    case BUILT_IN_NANSL:
+      return fold_builtin_nan (arglist, type, false);
+
+    case BUILT_IN_FLOOR:
+    case BUILT_IN_FLOORF:
+    case BUILT_IN_FLOORL:
+    case BUILT_IN_CEIL:
+    case BUILT_IN_CEILF:
+    case BUILT_IN_CEILL:
+    case BUILT_IN_TRUNC:
+    case BUILT_IN_TRUNCF:
+    case BUILT_IN_TRUNCL:
+    case BUILT_IN_ROUND:
+    case BUILT_IN_ROUNDF:
+    case BUILT_IN_ROUNDL:
+    case BUILT_IN_NEARBYINT:
+    case BUILT_IN_NEARBYINTF:
+    case BUILT_IN_NEARBYINTL:
+      return fold_trunc_transparent_mathfn (exp);
+
     default:
       break;
     }
@@ -4143,7 +4858,9 @@ fold_builtin (exp)
   return 0;
 }
 
-static tree
+/* Conveniently construct a function call expression.  */
+
+tree
 build_function_call_expr (fn, arglist)
      tree fn, arglist;
 {
@@ -4170,29 +4887,32 @@ validate_arglist VPARAMS ((tree arglist, ...))
   VA_OPEN (ap, arglist);
   VA_FIXEDARG (ap, tree, arglist);
 
-  do {
-    code = va_arg (ap, enum tree_code);
-    switch (code)
+  do
     {
-    case 0:
-      /* This signifies an ellipses, any further arguments are all ok.  */
-      res = 1;
-      goto end;
-    case VOID_TYPE:
-      /* This signifies an endlink, if no arguments remain, return
-         true, otherwise return false.  */
-      res = arglist == 0;
-      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.  */
-      if (arglist == 0 || code != TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))))
-       goto end;
-      break;
+      code = va_arg (ap, enum tree_code);
+      switch (code)
+       {
+       case 0:
+         /* This signifies an ellipses, any further arguments are all ok.  */
+         res = 1;
+         goto end;
+       case VOID_TYPE:
+         /* This signifies an endlink, if no arguments remain, return
+            true, otherwise return false.  */
+         res = arglist == 0;
+         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.  */
+         if (arglist == 0
+             || code != TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))))
+           goto end;
+         break;
+       }
+      arglist = TREE_CHAIN (arglist);
     }
-    arglist = TREE_CHAIN (arglist);
-  } while (1);
+  while (1);
 
   /* We need gotos here since we can only have one VA_CLOSE in a
      function.  */
@@ -4221,3 +4941,29 @@ default_expand_builtin (exp, target, subtarget, mode, ignore)
 {
   return NULL_RTX;
 }
+
+/* Instantiate all remaining CONSTANT_P_RTX nodes.  */
+
+void
+purge_builtin_constant_p ()
+{
+  rtx insn, set, arg, new, note;
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    if (INSN_P (insn)
+       && (set = single_set (insn)) != NULL_RTX
+       && (GET_CODE (arg = SET_SRC (set)) == CONSTANT_P_RTX
+           || (GET_CODE (arg) == SUBREG
+               && (GET_CODE (arg = SUBREG_REG (arg))
+                   == CONSTANT_P_RTX))))
+      {
+       arg = XEXP (arg, 0);
+       new = CONSTANT_P (arg) ? const1_rtx : const0_rtx;
+       validate_change (insn, &SET_SRC (set), new, 0);
+
+       /* Remove the REG_EQUAL note from the insn.  */
+       if ((note = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0)
+         remove_note (insn, note);
+      }
+}
+