OSDN Git Service

* optabs.h (enum optab_index): Add new OTI_tan and OTI_atan.
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index c3e1477..efc808d 100644 (file)
@@ -79,93 +79,95 @@ tree built_in_decls[(int) END_BUILTINS];
    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));
-static const char *c_getstr            PARAMS ((tree));
-static rtx c_readstr                   PARAMS ((const char *,
-                                                enum machine_mode));
-static int target_char_cast            PARAMS ((tree, char *));
-static rtx get_memory_rtx              PARAMS ((tree));
-static int apply_args_size             PARAMS ((void));
-static int apply_result_size           PARAMS ((void));
+/* Trigonometric and mathematical constants used in builtin folding.  */
+static bool builtin_dconsts_init = 0;
+static REAL_VALUE_TYPE dconstpi;
+static REAL_VALUE_TYPE dconste;
+
+static int get_pointer_alignment (tree, unsigned int);
+static tree c_strlen (tree);
+static const char *c_getstr (tree);
+static rtx c_readstr (const char *, enum machine_mode);
+static int target_char_cast (tree, char *);
+static rtx get_memory_rtx (tree);
+static int apply_args_size (void);
+static int apply_result_size (void);
 #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
-static rtx result_vector               PARAMS ((int, rtx));
+static rtx result_vector (int, rtx);
 #endif
-static rtx expand_builtin_setjmp       PARAMS ((tree, rtx));
-static void expand_builtin_prefetch    PARAMS ((tree));
-static rtx expand_builtin_apply_args   PARAMS ((void));
-static rtx expand_builtin_apply_args_1 PARAMS ((void));
-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 ((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,
-                                                enum machine_mode));
-static rtx expand_builtin_strcmp       PARAMS ((tree, rtx,
-                                                enum machine_mode));
-static rtx expand_builtin_strncmp      PARAMS ((tree, rtx,
-                                                enum machine_mode));
-static rtx builtin_memcpy_read_str     PARAMS ((PTR, HOST_WIDE_INT,
-                                                enum machine_mode));
-static rtx expand_builtin_strcat       PARAMS ((tree, rtx,
-                                                enum machine_mode));
-static rtx expand_builtin_strncat      PARAMS ((tree, rtx,
-                                                enum machine_mode));
-static rtx expand_builtin_strspn       PARAMS ((tree, rtx,
-                                                enum machine_mode));
-static rtx expand_builtin_strcspn      PARAMS ((tree, rtx,
-                                                enum machine_mode));
-static rtx expand_builtin_memcpy       PARAMS ((tree, rtx,
-                                                enum machine_mode, int));
-static rtx expand_builtin_memmove      PARAMS ((tree, rtx,
-                                                enum machine_mode));
-static rtx expand_builtin_bcopy                PARAMS ((tree));
-static rtx expand_builtin_strcpy       PARAMS ((tree, rtx,
-                                                enum machine_mode));
-static rtx expand_builtin_stpcpy       PARAMS ((tree, rtx,
-                                                enum machine_mode));
-static rtx builtin_strncpy_read_str    PARAMS ((PTR, HOST_WIDE_INT,
-                                                enum machine_mode));
-static rtx expand_builtin_strncpy      PARAMS ((tree, rtx,
-                                                enum machine_mode));
-static rtx builtin_memset_read_str     PARAMS ((PTR, HOST_WIDE_INT,
-                                                enum machine_mode));
-static rtx builtin_memset_gen_str      PARAMS ((PTR, HOST_WIDE_INT,
-                                                enum machine_mode));
-static rtx expand_builtin_memset       PARAMS ((tree, rtx,
-                                                enum machine_mode));
-static rtx expand_builtin_bzero                PARAMS ((tree));
-static rtx expand_builtin_strlen       PARAMS ((tree, rtx));
-static rtx expand_builtin_strstr       PARAMS ((tree, rtx,
-                                                enum machine_mode));
-static rtx expand_builtin_strpbrk      PARAMS ((tree, rtx,
-                                                enum machine_mode));
-static rtx expand_builtin_strchr       PARAMS ((tree, rtx,
-                                                enum machine_mode));
-static rtx expand_builtin_strrchr      PARAMS ((tree, rtx,
-                                                enum machine_mode));
-static rtx expand_builtin_alloca       PARAMS ((tree, rtx));
-static rtx expand_builtin_unop         PARAMS ((enum machine_mode,
-                                                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 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));
+static rtx expand_builtin_setjmp (tree, rtx);
+static void expand_builtin_prefetch (tree);
+static rtx expand_builtin_apply_args (void);
+static rtx expand_builtin_apply_args_1 (void);
+static rtx expand_builtin_apply (rtx, rtx, rtx);
+static void expand_builtin_return (rtx);
+static enum type_class type_to_class (tree);
+static rtx expand_builtin_classify_type (tree);
+static void expand_errno_check (tree, rtx);
+static rtx expand_builtin_mathfn (tree, rtx, rtx);
+static rtx expand_builtin_mathfn_2 (tree, rtx, rtx);
+static rtx expand_builtin_constant_p (tree, enum machine_mode);
+static rtx expand_builtin_args_info (tree);
+static rtx expand_builtin_next_arg (tree);
+static rtx expand_builtin_va_start (tree);
+static rtx expand_builtin_va_end (tree);
+static rtx expand_builtin_va_copy (tree);
+static rtx expand_builtin_memcmp (tree, tree, rtx, enum machine_mode);
+static rtx expand_builtin_strcmp (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode);
+static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
+static rtx expand_builtin_strcat (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strncat (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strspn (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strcspn (tree, rtx, enum machine_mode);
+static rtx expand_builtin_memcpy (tree, rtx, enum machine_mode);
+static rtx expand_builtin_mempcpy (tree, rtx, enum machine_mode, int);
+static rtx expand_builtin_memmove (tree, rtx, enum machine_mode);
+static rtx expand_builtin_bcopy (tree);
+static rtx expand_builtin_strcpy (tree, rtx, enum machine_mode);
+static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode);
+static rtx builtin_strncpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
+static rtx expand_builtin_strncpy (tree, rtx, enum machine_mode);
+static rtx builtin_memset_read_str (void *, HOST_WIDE_INT, enum machine_mode);
+static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, enum machine_mode);
+static rtx expand_builtin_memset (tree, rtx, enum machine_mode);
+static rtx expand_builtin_bzero (tree);
+static rtx expand_builtin_strlen (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strstr (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strpbrk (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strchr (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strrchr (tree, rtx, enum machine_mode);
+static rtx expand_builtin_alloca (tree, rtx);
+static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab);
+static rtx expand_builtin_frame_address (tree, tree);
+static rtx expand_builtin_fputs (tree, int, int);
+static tree stabilize_va_list (tree, int);
+static rtx expand_builtin_expect (tree, rtx);
+static tree fold_builtin_constant_p (tree);
+static tree fold_builtin_classify_type (tree);
+static tree fold_builtin_inf (tree, int);
+static tree fold_builtin_nan (tree, tree, int);
+static int validate_arglist (tree, ...);
+static tree fold_trunc_transparent_mathfn (tree);
+static bool readonly_data_expr (tree);
+static rtx expand_builtin_fabs (tree, rtx, rtx);
+static rtx expand_builtin_cabs (tree, rtx);
+static void init_builtin_dconsts (void);
+static tree fold_builtin_cabs (tree, tree, tree);
+
+/* Initialize mathematical constants for constant folding builtins.
+   These constants need to be given to at least 160 bits precision.  */
+
+static void
+init_builtin_dconsts (void)
+{
+  real_from_string (&dconstpi,
+    "3.1415926535897932384626433832795028841971693993751058209749445923078");
+  real_from_string (&dconste,
+    "2.7182818284590452353602874713526624977572470936999595749669676277241");
+
+  builtin_dconsts_init = true;
+}
 
 /* Return the alignment in bits of EXP, a pointer valued expression.
    But don't return more than MAX_ALIGN no matter what.
@@ -176,9 +178,7 @@ static tree fold_trunc_transparent_mathfn PARAMS ((tree));
    expression is actually pointing at an object whose alignment is tighter.  */
 
 static int
-get_pointer_alignment (exp, max_align)
-     tree exp;
-     unsigned int max_align;
+get_pointer_alignment (tree exp, unsigned int max_align)
 {
   unsigned int align, inner;
 
@@ -247,8 +247,7 @@ get_pointer_alignment (exp, max_align)
    arrays with initializers, so neither can we do so here.  */
 
 static tree
-c_strlen (src)
-     tree src;
+c_strlen (tree src)
 {
   tree offset_node;
   HOST_WIDE_INT offset;
@@ -313,8 +312,7 @@ c_strlen (src)
    or sum of string constant and integer constant.  */
 
 static const char *
-c_getstr (src)
-     tree src;
+c_getstr (tree src)
 {
   tree offset_node;
 
@@ -335,9 +333,7 @@ c_getstr (src)
    GET_MODE_BITSIZE (MODE) bits from string constant STR.  */
 
 static rtx
-c_readstr (str, mode)
-     const char *str;
-     enum machine_mode mode;
+c_readstr (const char *str, enum machine_mode mode)
 {
   HOST_WIDE_INT c[2];
   HOST_WIDE_INT ch;
@@ -371,9 +367,7 @@ c_readstr (str, mode)
    P.  */
 
 static int
-target_char_cast (cst, p)
-     tree cst;
-     char *p;
+target_char_cast (tree cst, char *p)
 {
   unsigned HOST_WIDE_INT val, hostval;
 
@@ -401,10 +395,8 @@ target_char_cast (cst, p)
    address located within it (depending on FNDECL_CODE).  */
 
 rtx
-expand_builtin_return_addr (fndecl_code, count, tem)
-     enum built_in_function fndecl_code;
-     int count;
-     rtx tem;
+expand_builtin_return_addr (enum built_in_function fndecl_code, int count,
+                           rtx tem)
 {
   int i;
 
@@ -464,9 +456,7 @@ static HOST_WIDE_INT setjmp_alias_set = -1;
    handling code.  */
 
 void
-expand_builtin_setjmp_setup (buf_addr, receiver_label)
-     rtx buf_addr;
-     rtx receiver_label;
+expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
 {
   enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
   rtx stack_save;
@@ -527,8 +517,7 @@ expand_builtin_setjmp_setup (buf_addr, receiver_label)
    This is used directly by sjlj exception handling code.  */
 
 void
-expand_builtin_setjmp_receiver (receiver_label)
-     rtx receiver_label ATTRIBUTE_UNUSED;
+expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
 {
   /* Clobber the FP when we get here, so we have to make sure it's
      marked as used by this function.  */
@@ -600,9 +589,7 @@ expand_builtin_setjmp_receiver (receiver_label)
    them.  */
 
 static rtx
-expand_builtin_setjmp (arglist, target)
-     tree arglist;
-     rtx target;
+expand_builtin_setjmp (tree arglist, rtx target)
 {
   rtx buf_addr, next_lab, cont_lab;
 
@@ -653,8 +640,7 @@ expand_builtin_setjmp (arglist, target)
    them.  */
 
 void
-expand_builtin_longjmp (buf_addr, value)
-     rtx buf_addr, value;
+expand_builtin_longjmp (rtx buf_addr, rtx value)
 {
   rtx fp, lab, stack, insn, last;
   enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
@@ -743,8 +729,7 @@ expand_builtin_longjmp (buf_addr, value)
    effects.  */
 
 static void
-expand_builtin_prefetch (arglist)
-     tree arglist;
+expand_builtin_prefetch (tree arglist)
 {
   tree arg0, arg1, arg2;
   rtx op0, op1, op2;
@@ -830,8 +815,7 @@ expand_builtin_prefetch (arglist)
    to be used to be used in a string instruction (cmpstrsi, movstrsi, ..).  */
 
 static rtx
-get_memory_rtx (exp)
-     tree exp;
+get_memory_rtx (tree exp)
 {
   rtx addr = expand_expr (exp, NULL_RTX, ptr_mode, EXPAND_SUM);
   rtx mem;
@@ -893,8 +877,7 @@ static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER];
    needed in objc-act.c.  */
 
 int
-apply_args_register_offset (regno)
-     int regno;
+apply_args_register_offset (int regno)
 {
   apply_args_size ();
 
@@ -910,7 +893,7 @@ apply_args_register_offset (regno)
    and initialize apply_args_mode.  */
 
 static int
-apply_args_size ()
+apply_args_size (void)
 {
   static int size = -1;
   int align;
@@ -990,7 +973,7 @@ apply_args_size ()
    and initialize apply_result_mode.  */
 
 static int
-apply_result_size ()
+apply_result_size (void)
 {
   static int size = -1;
   int align, regno;
@@ -1066,9 +1049,7 @@ apply_result_size ()
    restore the values.  */
 
 static rtx
-result_vector (savep, result)
-     int savep;
-     rtx result;
+result_vector (int savep, rtx result)
 {
   int regno, size, align, nelts;
   enum machine_mode mode;
@@ -1097,7 +1078,7 @@ result_vector (savep, result)
    arguments as were passed to the current function.  */
 
 static rtx
-expand_builtin_apply_args_1 ()
+expand_builtin_apply_args_1 (void)
 {
   rtx registers;
   int size, align, regno;
@@ -1154,7 +1135,7 @@ expand_builtin_apply_args_1 ()
    saved.  */
 
 static rtx
-expand_builtin_apply_args ()
+expand_builtin_apply_args (void)
 {
   /* Don't do __builtin_apply_args more than once in a function.
      Save the result of the first call and reuse it.  */
@@ -1189,8 +1170,7 @@ expand_builtin_apply_args ()
    untyped return of whatever value was returned by the given function.  */
 
 static rtx
-expand_builtin_apply (function, arguments, argsize)
-     rtx function, arguments, argsize;
+expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
 {
   int size, align, regno;
   enum machine_mode mode;
@@ -1345,8 +1325,7 @@ expand_builtin_apply (function, arguments, argsize)
 /* Perform an untyped return.  */
 
 static void
-expand_builtin_return (result)
-     rtx result;
+expand_builtin_return (rtx result)
 {
   int size, align, regno;
   enum machine_mode mode;
@@ -1399,8 +1378,7 @@ expand_builtin_return (result)
 /* Used by expand_builtin_classify_type and fold_builtin_classify_type.  */
 
 static enum type_class
-type_to_class (type)
-     tree type;
+type_to_class (tree type)
 {
   switch (TREE_CODE (type))
     {
@@ -1432,8 +1410,7 @@ type_to_class (type)
    ARGLIST.  */
 
 static rtx
-expand_builtin_classify_type (arglist)
-     tree arglist;
+expand_builtin_classify_type (tree arglist)
 {
   if (arglist != 0)
     return GEN_INT (type_to_class (TREE_TYPE (TREE_VALUE (arglist))));
@@ -1443,11 +1420,8 @@ expand_builtin_classify_type (arglist)
 /* Expand expression EXP, which is a call to __builtin_constant_p.  */
 
 static rtx
-expand_builtin_constant_p (exp)
-     tree exp;
+expand_builtin_constant_p (tree arglist, enum machine_mode target_mode)
 {
-  tree arglist = TREE_OPERAND (exp, 1);
-  enum machine_mode value_mode = TYPE_MODE (TREE_TYPE (exp));
   rtx tmp;
 
   if (arglist == 0)
@@ -1461,16 +1435,14 @@ expand_builtin_constant_p (exp)
   current_function_calls_constant_p = 1;
 
   tmp = expand_expr (arglist, NULL_RTX, VOIDmode, 0);
-  tmp = gen_rtx_CONSTANT_P_RTX (value_mode, tmp);
+  tmp = gen_rtx_CONSTANT_P_RTX (target_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;
+mathfn_built_in (tree type, enum built_in_function fn)
 {
   enum built_in_function fcode = NOT_BUILT_IN;
   if (TYPE_MODE (type) == TYPE_MODE (double_type_node))
@@ -1501,6 +1473,16 @@ mathfn_built_in (type, fn)
       case BUILT_IN_LOGL:
        fcode = BUILT_IN_LOG;
        break;
+      case BUILT_IN_TAN:
+      case BUILT_IN_TANF:
+      case BUILT_IN_TANL:
+       fcode = BUILT_IN_TAN;
+       break;
+      case BUILT_IN_ATAN:
+      case BUILT_IN_ATANF:
+      case BUILT_IN_ATANL:
+       fcode = BUILT_IN_ATAN;
+       break;
       case BUILT_IN_FLOOR:
       case BUILT_IN_FLOORF:
       case BUILT_IN_FLOORL:
@@ -1557,6 +1539,16 @@ mathfn_built_in (type, fn)
       case BUILT_IN_LOGL:
        fcode = BUILT_IN_LOGF;
        break;
+      case BUILT_IN_TAN:
+      case BUILT_IN_TANF:
+      case BUILT_IN_TANL:
+       fcode = BUILT_IN_TANF;
+       break;
+      case BUILT_IN_ATAN:
+      case BUILT_IN_ATANF:
+      case BUILT_IN_ATANL:
+       fcode = BUILT_IN_ATANF;
+       break;
       case BUILT_IN_FLOOR:
       case BUILT_IN_FLOORF:
       case BUILT_IN_FLOORL:
@@ -1613,6 +1605,16 @@ mathfn_built_in (type, fn)
       case BUILT_IN_LOGL:
        fcode = BUILT_IN_LOGL;
        break;
+      case BUILT_IN_TAN:
+      case BUILT_IN_TANF:
+      case BUILT_IN_TANL:
+       fcode = BUILT_IN_TANL;
+       break;
+      case BUILT_IN_ATAN:
+      case BUILT_IN_ATANF:
+      case BUILT_IN_ATANL:
+       fcode = BUILT_IN_ATANL;
+       break;
       case BUILT_IN_FLOOR:
       case BUILT_IN_FLOORF:
       case BUILT_IN_FLOORL:
@@ -1649,9 +1651,7 @@ mathfn_built_in (type, fn)
    errno to EDOM.  */
 
 static void
-expand_errno_check (exp, target)
-     tree exp;
-     rtx target;
+expand_errno_check (tree exp, rtx target)
 {
   rtx lab;
 
@@ -1695,16 +1695,14 @@ expand_errno_check (exp, target)
    SUBTARGET may be used as the target for computing one of EXP's operands.  */
 
 static rtx
-expand_builtin_mathfn (exp, target, subtarget)
-     tree exp;
-     rtx target, subtarget;
+expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
 {
   optab builtin_optab;
   rtx op0, insns;
   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
   tree arglist = TREE_OPERAND (exp, 1);
   enum machine_mode argmode;
-  bool errno_set = true;
+  bool errno_set = false;
 
   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
     return 0;
@@ -1746,35 +1744,43 @@ expand_builtin_mathfn (exp, target, subtarget)
     case BUILT_IN_SQRT:
     case BUILT_IN_SQRTF:
     case BUILT_IN_SQRTL:
-      builtin_optab = sqrt_optab; break;
+      errno_set = true; builtin_optab = sqrt_optab; break;
     case BUILT_IN_EXP:
     case BUILT_IN_EXPF:
     case BUILT_IN_EXPL:
-      builtin_optab = exp_optab; break;
+      errno_set = true; builtin_optab = exp_optab; break;
     case BUILT_IN_LOG:
     case BUILT_IN_LOGF:
     case BUILT_IN_LOGL:
-      builtin_optab = log_optab; break;
+      errno_set = true; builtin_optab = log_optab; break;
+    case BUILT_IN_TAN:
+    case BUILT_IN_TANF:
+    case BUILT_IN_TANL:
+      builtin_optab = tan_optab; break;
+    case BUILT_IN_ATAN:
+    case BUILT_IN_ATANF:
+    case BUILT_IN_ATANL:
+      builtin_optab = atan_optab; break;
     case BUILT_IN_FLOOR:
     case BUILT_IN_FLOORF:
     case BUILT_IN_FLOORL:
-      errno_set = false ; builtin_optab = floor_optab; break;
+      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;
+      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;
+      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;
+      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;
+      builtin_optab = nearbyint_optab; break;
     default:
       abort ();
     }
@@ -1812,9 +1818,7 @@ expand_builtin_mathfn (exp, target, subtarget)
    operands.  */
 
 static rtx
-expand_builtin_mathfn_2 (exp, target, subtarget)
-     tree exp;
-     rtx target, subtarget;
+expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
 {
   optab builtin_optab;
   rtx op0, op1, insns;
@@ -1907,13 +1911,9 @@ expand_builtin_mathfn_2 (exp, target, subtarget)
    try to get the result in TARGET, if convenient.  */
 
 static rtx
-expand_builtin_strlen (exp, target)
-     tree exp;
-     rtx target;
+expand_builtin_strlen (tree arglist, rtx target,
+                      enum machine_mode target_mode)
 {
-  tree arglist = TREE_OPERAND (exp, 1);
-  enum machine_mode value_mode = TYPE_MODE (TREE_TYPE (exp));
-
   if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
     return 0;
   else
@@ -1921,14 +1921,14 @@ expand_builtin_strlen (exp, target)
       rtx pat;
       tree len, src = TREE_VALUE (arglist);
       rtx result, src_reg, char_rtx, before_strlen;
-      enum machine_mode insn_mode = value_mode, char_mode;
+      enum machine_mode insn_mode = target_mode, char_mode;
       enum insn_code icode = CODE_FOR_nothing;
       int align;
 
       /* If the length can be computed at compile-time, return it.  */
       len = c_strlen (src);
       if (len)
-       return expand_expr (len, target, value_mode, EXPAND_NORMAL);
+       return expand_expr (len, target, target_mode, EXPAND_NORMAL);
 
       align = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
 
@@ -1992,12 +1992,12 @@ expand_builtin_strlen (exp, target)
        emit_insn_before (pat, get_insns ());
 
       /* Return the value in the proper mode for this function.  */
-      if (GET_MODE (result) == value_mode)
+      if (GET_MODE (result) == target_mode)
        target = result;
       else if (target != 0)
        convert_move (target, result, 0);
       else
-       target = convert_to_mode (value_mode, result, 0);
+       target = convert_to_mode (target_mode, result, 0);
 
       return target;
     }
@@ -2008,10 +2008,7 @@ expand_builtin_strlen (exp, target)
    in TARGET, if convenient (and in mode MODE if that's convenient).  */
 
 static rtx
-expand_builtin_strstr (arglist, target, mode)
-     tree arglist;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_strstr (tree arglist, rtx target, enum machine_mode mode)
 {
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
@@ -2064,10 +2061,7 @@ expand_builtin_strstr (arglist, target, mode)
    in TARGET, if convenient (and in mode MODE if that's convenient).  */
 
 static rtx
-expand_builtin_strchr (arglist, target, mode)
-     tree arglist;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_strchr (tree arglist, rtx target, enum machine_mode mode)
 {
   if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
@@ -2110,10 +2104,7 @@ expand_builtin_strchr (arglist, target, mode)
    in TARGET, if convenient (and in mode MODE if that's convenient).  */
 
 static rtx
-expand_builtin_strrchr (arglist, target, mode)
-     tree arglist;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_strrchr (tree arglist, rtx target, enum machine_mode mode)
 {
   if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
@@ -2164,10 +2155,7 @@ expand_builtin_strrchr (arglist, target, mode)
    in TARGET, if convenient (and in mode MODE if that's convenient).  */
 
 static rtx
-expand_builtin_strpbrk (arglist, target, mode)
-     tree arglist;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_strpbrk (tree arglist, rtx target, enum machine_mode mode)
 {
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
@@ -2226,10 +2214,8 @@ expand_builtin_strpbrk (arglist, target, mode)
    constant.  */
 
 static rtx
-builtin_memcpy_read_str (data, offset, mode)
-     PTR data;
-     HOST_WIDE_INT offset;
-     enum machine_mode mode;
+builtin_memcpy_read_str (void *data, HOST_WIDE_INT offset,
+                        enum machine_mode mode)
 {
   const char *str = (const char *) data;
 
@@ -2244,16 +2230,9 @@ builtin_memcpy_read_str (data, offset, mode)
 /* Expand a call to the memcpy builtin, with arguments in ARGLIST.
    Return 0 if we failed, the caller should emit a normal call,
    otherwise try to get the result in TARGET, if convenient (and in
-   mode MODE if that's convenient).  If ENDP is 0 return the
-   destination pointer, if ENDP is 1 return the end pointer ala
-   mempcpy, and if ENDP is 2 return the end pointer minus one ala
-   stpcpy.  */
+   mode MODE if that's convenient).  */
 static rtx
-expand_builtin_memcpy (arglist, target, mode, endp)
-     tree arglist;
-     rtx target;
-     enum machine_mode mode;
-     int endp;
+expand_builtin_memcpy (tree arglist, rtx target, enum machine_mode mode)
 {
   if (!validate_arglist (arglist,
                         POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
@@ -2264,7 +2243,6 @@ expand_builtin_memcpy (arglist, target, mode, endp)
       tree src = TREE_VALUE (TREE_CHAIN (arglist));
       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
       const char *src_str;
-
       unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
       unsigned int dest_align
        = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
@@ -2301,23 +2279,15 @@ expand_builtin_memcpy (arglist, target, mode, endp)
          && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
                                  (PTR) src_str, dest_align))
        {
-         store_by_pieces (dest_mem, INTVAL (len_rtx),
-                          builtin_memcpy_read_str,
-                          (PTR) src_str, dest_align);
+         dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
+                                     builtin_memcpy_read_str,
+                                     (PTR) src_str, dest_align, 0);
          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
-         if (endp)
-           {
-             rtx result = gen_rtx_PLUS (GET_MODE (dest_mem), dest_mem, len_rtx);
-             if (endp == 2)
-               result = simplify_gen_binary (MINUS, GET_MODE (result), result, const1_rtx);
-             return result;
-           }
-         else
-           return dest_mem;
+         return dest_mem;
        }
 
       src_mem = get_memory_rtx (src);
@@ -2335,16 +2305,109 @@ expand_builtin_memcpy (arglist, target, mode, endp)
            dest_addr = convert_memory_address (ptr_mode, dest_addr);
 #endif
        }
+      return dest_addr;
+    }
+}
 
-      if (endp)
-        {
-         rtx result = gen_rtx_PLUS (GET_MODE (dest_addr), dest_addr, len_rtx);
-         if (endp == 2)
-           result = simplify_gen_binary (MINUS, GET_MODE (result), result, const1_rtx);
-         return result;
+/* Expand a call to the mempcpy builtin, with arguments in ARGLIST.
+   Return 0 if we failed the caller should emit a normal call,
+   otherwise try to get the result in TARGET, if convenient (and in
+   mode MODE if that's convenient).  If ENDP is 0 return the
+   destination pointer, if ENDP is 1 return the end pointer ala
+   mempcpy, and if ENDP is 2 return the end pointer minus one ala
+   stpcpy.  */
+
+static rtx
+expand_builtin_mempcpy (tree arglist, rtx target, enum machine_mode mode,
+                       int endp)
+{
+  if (!validate_arglist (arglist,
+                        POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+    return 0;
+  /* If return value is ignored, transform mempcpy into memcpy.  */
+  else if (target == const0_rtx)
+    {
+      tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+
+      if (!fn)
+       return 0;
+
+      return expand_expr (build_function_call_expr (fn, arglist),
+                         target, mode, EXPAND_NORMAL);
+    }
+  else
+    {
+      tree dest = TREE_VALUE (arglist);
+      tree src = TREE_VALUE (TREE_CHAIN (arglist));
+      tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+      const char *src_str;
+      unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
+      unsigned int dest_align
+       = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+      rtx dest_mem, src_mem, len_rtx;
+
+      /* If DEST is not a pointer type or LEN is not constant,
+        call the normal function.  */
+      if (dest_align == 0 || !host_integerp (len, 1))
+       return 0;
+
+      /* If the LEN parameter is zero, return DEST.  */
+      if (tree_low_cst (len, 1) == 0)
+       {
+         /* Evaluate and ignore SRC in case it has side-effects.  */
+         expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
+         return expand_expr (dest, target, mode, EXPAND_NORMAL);
        }
-      else
-       return dest_addr;
+
+      /* If either SRC is not a pointer type, don't do this
+         operation in-line.  */
+      if (src_align == 0)
+       return 0;
+
+      len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+      src_str = c_getstr (src);
+
+      /* If SRC is a string constant and block move would be done
+        by pieces, we can avoid loading the string from memory
+        and only stored the computed constants.  */
+      if (src_str
+         && GET_CODE (len_rtx) == CONST_INT
+         && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
+         && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
+                                 (PTR) src_str, dest_align))
+       {
+         dest_mem = get_memory_rtx (dest);
+         set_mem_align (dest_mem, dest_align);
+         dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
+                                     builtin_memcpy_read_str,
+                                     (PTR) src_str, dest_align, endp);
+         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 (GET_CODE (len_rtx) == CONST_INT
+         && can_move_by_pieces (INTVAL (len_rtx),
+                                MIN (dest_align, src_align)))
+       {
+         dest_mem = get_memory_rtx (dest);
+         set_mem_align (dest_mem, dest_align);
+         src_mem = get_memory_rtx (src);
+         set_mem_align (src_mem, src_align);
+         dest_mem = move_by_pieces (dest_mem, src_mem, INTVAL (len_rtx),
+                                    MIN (dest_align, src_align), endp);
+         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;
+       }
+
+      return 0;
     }
 }
 
@@ -2352,10 +2415,7 @@ expand_builtin_memcpy (arglist, target, mode, endp)
    if we failed the caller should emit a normal call.  */
 
 static rtx
-expand_builtin_memmove (arglist, target, mode)
-     tree arglist;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_memmove (tree arglist, rtx target, enum machine_mode mode)
 {
   if (!validate_arglist (arglist,
                         POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
@@ -2387,10 +2447,16 @@ expand_builtin_memmove (arglist, target, mode)
       if (src_align == 0)
        return 0;
 
-      /* If src is a string constant and strings are not writable,
-        we can use normal memcpy.  */
-      if (!flag_writable_strings && c_getstr (src))
-       return expand_builtin_memcpy (arglist, target, mode, 0);
+      /* If src is categorized for a readonly section we can use
+        normal memcpy.  */
+      if (readonly_data_expr (src))
+        {
+         tree const fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+         if (!fn)
+           return 0;
+         return expand_expr (build_function_call_expr (fn, arglist),
+                             target, mode, EXPAND_NORMAL);
+       }
 
       /* Otherwise, call the normal function.  */
       return 0;
@@ -2401,8 +2467,7 @@ expand_builtin_memmove (arglist, target, mode)
    if we failed the caller should emit a normal call.  */
 
 static rtx
-expand_builtin_bcopy (arglist)
-     tree arglist;
+expand_builtin_bcopy (tree arglist)
 {
   tree src, dest, size, newarglist;
 
@@ -2432,12 +2497,8 @@ expand_builtin_bcopy (arglist)
    convenient).  */
 
 static rtx
-expand_builtin_strcpy (exp, target, mode)
-     tree exp;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_strcpy (tree arglist, rtx target, enum machine_mode mode)
 {
-  tree arglist = TREE_OPERAND (exp, 1);
   tree fn, len;
 
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
@@ -2463,24 +2524,38 @@ expand_builtin_strcpy (exp, target, mode)
    mode MODE if that's convenient).  */
 
 static rtx
-expand_builtin_stpcpy (arglist, target, mode)
-     tree arglist;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_stpcpy (tree arglist, rtx target, enum machine_mode mode)
 {
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
   else
     {
       tree newarglist;
-      tree len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
-      if (len == 0)
+      tree src, len;
+
+      /* If return value is ignored, transform stpcpy into strcpy.  */
+      if (target == const0_rtx)
+       {
+         tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+         if (!fn)
+           return 0;
+
+         return expand_expr (build_function_call_expr (fn, arglist),
+                             target, mode, EXPAND_NORMAL);
+       }
+
+      /* Ensure we get an actual string whose length can be evaluated at
+         compile-time, not an expression containing a string.  This is
+         because the latter will potentially produce pessimized code
+         when used to produce the return value.  */
+      src = TREE_VALUE (TREE_CHAIN (arglist));
+      if (! c_getstr (src) || ! (len = c_strlen (src)))
        return 0;
 
       len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
       newarglist = copy_list (arglist);
       chainon (newarglist, build_tree_list (NULL_TREE, len));
-      return expand_builtin_memcpy (newarglist, target, mode, /*endp=*/2);
+      return expand_builtin_mempcpy (newarglist, target, mode, /*endp=*/2);
     }
 }
 
@@ -2489,10 +2564,8 @@ expand_builtin_stpcpy (arglist, target, mode)
    constant.  */
 
 static rtx
-builtin_strncpy_read_str (data, offset, mode)
-     PTR data;
-     HOST_WIDE_INT offset;
-     enum machine_mode mode;
+builtin_strncpy_read_str (void *data, HOST_WIDE_INT offset,
+                         enum machine_mode mode)
 {
   const char *str = (const char *) data;
 
@@ -2506,10 +2579,7 @@ builtin_strncpy_read_str (data, offset, mode)
    if we failed the caller should emit a normal call.  */
 
 static rtx
-expand_builtin_strncpy (arglist, target, mode)
-     tree arglist;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_strncpy (tree arglist, rtx target, enum machine_mode mode)
 {
   if (!validate_arglist (arglist,
                         POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
@@ -2562,7 +2632,7 @@ expand_builtin_strncpy (arglist, target, mode)
          dest_mem = get_memory_rtx (dest);
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_strncpy_read_str,
-                          (PTR) p, dest_align);
+                          (PTR) p, dest_align, 0);
          dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (dest_mem) != ptr_mode)
@@ -2585,10 +2655,8 @@ expand_builtin_strncpy (arglist, target, mode)
    constant.  */
 
 static rtx
-builtin_memset_read_str (data, offset, mode)
-     PTR data;
-     HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
-     enum machine_mode mode;
+builtin_memset_read_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
+                        enum machine_mode mode)
 {
   const char *c = (const char *) data;
   char *p = alloca (GET_MODE_SIZE (mode));
@@ -2604,10 +2672,8 @@ builtin_memset_read_str (data, offset, mode)
    4 bytes wide, return the RTL for 0x01010101*data.  */
 
 static rtx
-builtin_memset_gen_str (data, offset, mode)
-     PTR data;
-     HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
-     enum machine_mode mode;
+builtin_memset_gen_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
+                       enum machine_mode mode)
 {
   rtx target, coeff;
   size_t size;
@@ -2632,13 +2698,8 @@ builtin_memset_gen_str (data, offset, mode)
    convenient).  */
 
 static rtx
-expand_builtin_memset (exp, target, mode)
-     tree exp;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode)
 {
-  tree arglist = TREE_OPERAND (exp, 1);
-
   if (!validate_arglist (arglist,
                         POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
@@ -2692,7 +2753,7 @@ 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);
+                          (PTR) val_rtx, dest_align, 0);
          dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (dest_mem) != ptr_mode)
@@ -2716,7 +2777,7 @@ expand_builtin_memset (exp, target, mode)
          dest_mem = get_memory_rtx (dest);
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_memset_read_str,
-                          (PTR) &c, dest_align);
+                          (PTR) &c, dest_align, 0);
          dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (dest_mem) != ptr_mode)
@@ -2748,12 +2809,9 @@ expand_builtin_memset (exp, target, mode)
    if we failed the caller should emit a normal call.  */
 
 static rtx
-expand_builtin_bzero (exp)
-     tree exp;
+expand_builtin_bzero (tree arglist)
 {
-  tree arglist = TREE_OPERAND (exp, 1);
   tree dest, size, newarglist;
-  rtx result;
 
   if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return NULL_RTX;
@@ -2770,13 +2828,7 @@ expand_builtin_bzero (exp)
   newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
   newarglist = tree_cons (NULL_TREE, dest, newarglist);
 
-  TREE_OPERAND (exp, 1) = newarglist;
-  result = expand_builtin_memset (exp, const0_rtx, VOIDmode);
-
-  /* Always restore the original arguments.  */
-  TREE_OPERAND (exp, 1) = arglist;
-
-  return result;
+  return expand_builtin_memset (newarglist, const0_rtx, VOIDmode);
 }
 
 /* Expand expression EXP, which is a call to the memcmp built-in function.
@@ -2785,11 +2837,8 @@ expand_builtin_bzero (exp)
    TARGET, if convenient (and in mode MODE, if that's convenient).  */
 
 static rtx
-expand_builtin_memcmp (exp, arglist, target, mode)
-     tree exp ATTRIBUTE_UNUSED;
-     tree arglist;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target,
+                      enum machine_mode mode)
 {
   tree arg1, arg2, len;
   const char *p1, *p2;
@@ -2910,10 +2959,7 @@ expand_builtin_memcmp (exp, arglist, target, mode)
    the result in TARGET, if convenient.  */
 
 static rtx
-expand_builtin_strcmp (exp, target, mode)
-     tree exp;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
 {
   tree arglist = TREE_OPERAND (exp, 1);
   tree arg1, arg2;
@@ -3041,10 +3087,7 @@ expand_builtin_strcmp (exp, target, mode)
    the result in TARGET, if convenient.  */
 
 static rtx
-expand_builtin_strncmp (exp, target, mode)
-     tree exp;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
 {
   tree arglist = TREE_OPERAND (exp, 1);
   tree arg1, arg2, arg3;
@@ -3194,10 +3237,7 @@ expand_builtin_strncmp (exp, target, mode)
    otherwise try to get the result in TARGET, if convenient.  */
 
 static rtx
-expand_builtin_strcat (arglist, target, mode)
-     tree arglist;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_strcat (tree arglist, rtx target, enum machine_mode mode)
 {
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
@@ -3220,10 +3260,7 @@ expand_builtin_strcat (arglist, target, mode)
    otherwise try to get the result in TARGET, if convenient.  */
 
 static rtx
-expand_builtin_strncat (arglist, target, mode)
-     tree arglist;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_strncat (tree arglist, rtx target, enum machine_mode mode)
 {
   if (!validate_arglist (arglist,
                         POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
@@ -3272,10 +3309,7 @@ expand_builtin_strncat (arglist, target, mode)
    otherwise try to get the result in TARGET, if convenient.  */
 
 static rtx
-expand_builtin_strspn (arglist, target, mode)
-     tree arglist;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_strspn (tree arglist, rtx target, enum machine_mode mode)
 {
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
@@ -3309,10 +3343,7 @@ expand_builtin_strspn (arglist, target, mode)
    otherwise try to get the result in TARGET, if convenient.  */
 
 static rtx
-expand_builtin_strcspn (arglist, target, mode)
-     tree arglist;
-     rtx target;
-     enum machine_mode mode;
+expand_builtin_strcspn (tree arglist, rtx target, enum machine_mode mode)
 {
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
@@ -3359,7 +3390,7 @@ expand_builtin_strcspn (arglist, target, mode)
    if that's convenient.  */
 
 rtx
-expand_builtin_saveregs ()
+expand_builtin_saveregs (void)
 {
   rtx val, seq;
 
@@ -3410,10 +3441,8 @@ expand_builtin_saveregs ()
    is controlled by the definition of CUMULATIVE_ARGS.  */
 
 static rtx
-expand_builtin_args_info (exp)
-     tree exp;
+expand_builtin_args_info (tree arglist)
 {
-  tree arglist = TREE_OPERAND (exp, 1);
   int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
   int *word_ptr = (int *) &current_function_args_info;
 
@@ -3443,8 +3472,7 @@ expand_builtin_args_info (exp)
 /* Expand ARGLIST, from a call to __builtin_next_arg.  */
 
 static rtx
-expand_builtin_next_arg (arglist)
-     tree arglist;
+expand_builtin_next_arg (tree arglist)
 {
   tree fntype = TREE_TYPE (current_function_decl);
 
@@ -3488,9 +3516,7 @@ expand_builtin_next_arg (arglist)
    from multiple evaluations.  */
 
 static tree
-stabilize_va_list (valist, needs_lvalue)
-     tree valist;
-     int needs_lvalue;
+stabilize_va_list (tree valist, int needs_lvalue)
 {
   if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
     {
@@ -3537,9 +3563,7 @@ stabilize_va_list (valist, needs_lvalue)
    the variable.  */
 
 void
-std_expand_builtin_va_start (valist, nextarg)
-     tree valist;
-     rtx nextarg;
+std_expand_builtin_va_start (tree valist, rtx nextarg)
 {
   tree t;
 
@@ -3553,8 +3577,7 @@ std_expand_builtin_va_start (valist, nextarg)
 /* Expand ARGLIST, from a call to __builtin_va_start.  */
 
 static rtx
-expand_builtin_va_start (arglist)
-     tree arglist;
+expand_builtin_va_start (tree arglist)
 {
   rtx nextarg;
   tree chain, valist;
@@ -3580,8 +3603,7 @@ expand_builtin_va_start (arglist)
    current (padded) address and increment by the (padded) size.  */
 
 rtx
-std_expand_builtin_va_arg (valist, type)
-     tree valist, type;
+std_expand_builtin_va_arg (tree valist, tree type)
 {
   tree addr_tree, t, type_size = NULL;
   tree align, alignm1;
@@ -3639,8 +3661,7 @@ std_expand_builtin_va_arg (valist, type)
    a very special sort of operator.  */
 
 rtx
-expand_builtin_va_arg (valist, type)
-     tree valist, type;
+expand_builtin_va_arg (tree valist, tree type)
 {
   rtx addr, result;
   tree promoted_type, want_va_type, have_va_type;
@@ -3740,8 +3761,7 @@ expand_builtin_va_arg (valist, type)
 /* Expand ARGLIST, from a call to __builtin_va_end.  */
 
 static rtx
-expand_builtin_va_end (arglist)
-     tree arglist;
+expand_builtin_va_end (tree arglist)
 {
   tree valist = TREE_VALUE (arglist);
 
@@ -3763,8 +3783,7 @@ expand_builtin_va_end (arglist)
    nastiness of array-type va_list types.  */
 
 static rtx
-expand_builtin_va_copy (arglist)
-     tree arglist;
+expand_builtin_va_copy (tree arglist)
 {
   tree dst, src, t;
 
@@ -3817,12 +3836,8 @@ expand_builtin_va_copy (arglist)
    __builtin_return_address.  */
 
 static rtx
-expand_builtin_frame_address (exp)
-     tree exp;
+expand_builtin_frame_address (tree fndecl, tree arglist)
 {
-  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
-  tree arglist = TREE_OPERAND (exp, 1);
-
   /* The argument must be a nonnegative integer constant.
      It counts the number of frames to scan up the stack.
      The value is the return address saved in that frame.  */
@@ -3870,9 +3885,7 @@ expand_builtin_frame_address (exp)
    the result in TARGET, if convenient.  */
 
 static rtx
-expand_builtin_alloca (arglist, target)
-     tree arglist;
-     rtx target;
+expand_builtin_alloca (tree arglist, rtx target)
 {
   rtx op0;
   rtx result;
@@ -3900,11 +3913,8 @@ expand_builtin_alloca (arglist, target)
    SUBTARGET may be used as the target for computing one of EXP's operands.  */
 
 static rtx
-expand_builtin_unop (target_mode, arglist, target, subtarget, op_optab)
-     enum machine_mode target_mode;
-     tree arglist;
-     rtx target, subtarget;
-     optab op_optab;
+expand_builtin_unop (enum machine_mode target_mode, tree arglist, rtx target,
+                    rtx subtarget, optab op_optab)
 {
   rtx op0;
   if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
@@ -3926,10 +3936,7 @@ expand_builtin_unop (target_mode, arglist, target, subtarget, op_optab)
    long, we attempt to transform this call into __builtin_fputc().  */
 
 static rtx
-expand_builtin_fputs (arglist, ignore, unlocked)
-     tree arglist;
-     int ignore;
-     int unlocked;
+expand_builtin_fputs (tree arglist, int ignore, int unlocked)
 {
   tree len, fn;
   tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
@@ -4010,9 +4017,7 @@ expand_builtin_fputs (arglist, ignore, unlocked)
    a non-jump context.  */
 
 static rtx
-expand_builtin_expect (arglist, target)
-     tree arglist;
-     rtx target;
+expand_builtin_expect (tree arglist, rtx target)
 {
   tree exp, c;
   rtx note, rtx_c;
@@ -4056,10 +4061,7 @@ expand_builtin_expect (arglist, target)
    based on the test being 0/1.  */
 
 rtx
-expand_builtin_expect_jump (exp, if_false_label, if_true_label)
-     tree exp;
-     rtx if_false_label;
-     rtx if_true_label;
+expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label)
 {
   tree arglist = TREE_OPERAND (exp, 1);
   tree arg0 = TREE_VALUE (arglist);
@@ -4104,18 +4106,13 @@ expand_builtin_expect_jump (exp, if_false_label, if_true_label)
       while (insn != NULL_RTX)
        {
          rtx next = NEXT_INSN (insn);
-         rtx pattern;
 
-         if (GET_CODE (insn) == JUMP_INSN && any_condjump_p (insn)
-             && (pattern = pc_set (insn)) != NULL_RTX)
+         if (GET_CODE (insn) == JUMP_INSN && any_condjump_p (insn))
            {
-             rtx ifelse = SET_SRC (pattern);
+             rtx ifelse = SET_SRC (pc_set (insn));
              rtx label;
              int taken;
 
-             if (GET_CODE (ifelse) != IF_THEN_ELSE)
-               goto do_next_insn;
-
              if (GET_CODE (XEXP (ifelse, 1)) == LABEL_REF)
                {
                  taken = 1;
@@ -4175,7 +4172,7 @@ expand_builtin_expect_jump (exp, if_false_label, if_true_label)
 }
 
 void
-expand_builtin_trap ()
+expand_builtin_trap (void)
 {
 #ifdef HAVE_trap
   if (HAVE_trap)
@@ -4185,6 +4182,53 @@ expand_builtin_trap ()
     emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0);
   emit_barrier ();
 }
+
+/* Expand a call to fabs, fabsf or fabsl with arguments ARGLIST.
+   Return 0 if a normal call should be emitted rather than expanding
+   the function inline.  If convenient, the result should be placed
+   in TARGET.  SUBTARGET may be used as the target for computing
+   the operand.  */
+
+static rtx
+expand_builtin_fabs (tree arglist, rtx target, rtx subtarget)
+{
+  enum machine_mode mode;
+  tree arg;
+  rtx op0;
+
+  if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+    return 0;
+
+  arg = TREE_VALUE (arglist);
+  mode = TYPE_MODE (TREE_TYPE (arg));
+  op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+  return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1));
+}
+
+/* Expand a call to cabs, cabsf or cabsl with arguments ARGLIST.
+   Return 0 if a normal call should be emitted rather than expanding
+   the function inline.  If convenient, the result should be placed
+   in target.  */
+
+static rtx
+expand_builtin_cabs (tree arglist, rtx target)
+{
+  enum machine_mode mode;
+  tree arg;
+  rtx op0;
+
+  if (arglist == 0 || TREE_CHAIN (arglist))
+    return 0;
+  arg = TREE_VALUE (arglist);
+  if (TREE_CODE (TREE_TYPE (arg)) != COMPLEX_TYPE
+      || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
+    return 0;
+
+  mode = TYPE_MODE (TREE_TYPE (arg));
+  op0 = expand_expr (arg, NULL_RTX, VOIDmode, 0);
+  return expand_complex_abs (mode, op0, target, 0);
+}
+
 \f
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
@@ -4193,12 +4237,8 @@ expand_builtin_trap ()
    IGNORE is nonzero if the value is to be ignored.  */
 
 rtx
-expand_builtin (exp, target, subtarget, mode, ignore)
-     tree exp;
-     rtx target;
-     rtx subtarget;
-     enum machine_mode mode;
-     int ignore;
+expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
+               int ignore)
 {
   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
   tree arglist = TREE_OPERAND (exp, 1);
@@ -4231,6 +4271,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       case BUILT_IN_LOG:
       case BUILT_IN_LOGF:
       case BUILT_IN_LOGL:
+      case BUILT_IN_TAN:
+      case BUILT_IN_TANF:
+      case BUILT_IN_TANL:
+      case BUILT_IN_ATAN:
+      case BUILT_IN_ATANF:
+      case BUILT_IN_ATANL:
       case BUILT_IN_POW:
       case BUILT_IN_POWF:
       case BUILT_IN_POWL:
@@ -4331,11 +4377,27 @@ expand_builtin (exp, target, subtarget, mode, ignore)
     case BUILT_IN_LABS:
     case BUILT_IN_LLABS:
     case BUILT_IN_IMAXABS:
+      /* build_function_call changes these into ABS_EXPR.  */
+      abort ();
+
     case BUILT_IN_FABS:
     case BUILT_IN_FABSF:
     case BUILT_IN_FABSL:
-      /* build_function_call changes these into ABS_EXPR.  */
-      abort ();
+      target = expand_builtin_fabs (arglist, target, subtarget);
+      if (target)
+        return target;
+      break;
+
+    case BUILT_IN_CABS:
+    case BUILT_IN_CABSF:
+    case BUILT_IN_CABSL:
+      if (flag_unsafe_math_optimizations)
+       {
+         target = expand_builtin_cabs (arglist, target);
+         if (target)
+           return target;
+       }
+      break;
 
     case BUILT_IN_CONJ:
     case BUILT_IN_CONJF:
@@ -4362,6 +4424,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
     case BUILT_IN_LOG:
     case BUILT_IN_LOGF:
     case BUILT_IN_LOGL:
+    case BUILT_IN_TAN:
+    case BUILT_IN_TANF:
+    case BUILT_IN_TANL:
+    case BUILT_IN_ATAN:
+    case BUILT_IN_ATANF:
+    case BUILT_IN_ATANL:
       /* Treat these like sqrt only if unsafe math optimizations are allowed,
         because of possible accuracy problems.  */
       if (! flag_unsafe_math_optimizations)
@@ -4446,7 +4514,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       return expand_builtin_saveregs ();
 
     case BUILT_IN_ARGS_INFO:
-      return expand_builtin_args_info (exp);
+      return expand_builtin_args_info (arglist);
 
       /* Return the address of the first anonymous stack arg.  */
     case BUILT_IN_NEXT_ARG:
@@ -4456,11 +4524,11 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       return expand_builtin_classify_type (arglist);
 
     case BUILT_IN_CONSTANT_P:
-      return expand_builtin_constant_p (exp);
+      return expand_builtin_constant_p (arglist, target_mode);
 
     case BUILT_IN_FRAME_ADDRESS:
     case BUILT_IN_RETURN_ADDRESS:
-      return expand_builtin_frame_address (exp);
+      return expand_builtin_frame_address (fndecl, arglist);
 
     /* Returns the address of the area where the structure is returned.
        0 otherwise.  */
@@ -4524,13 +4592,13 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       break;
 
     case BUILT_IN_STRLEN:
-      target = expand_builtin_strlen (exp, target);
+      target = expand_builtin_strlen (arglist, target, target_mode);
       if (target)
        return target;
       break;
 
     case BUILT_IN_STRCPY:
-      target = expand_builtin_strcpy (exp, target, mode);
+      target = expand_builtin_strcpy (arglist, target, mode);
       if (target)
        return target;
       break;
@@ -4598,13 +4666,13 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       break;
 
     case BUILT_IN_MEMCPY:
-      target = expand_builtin_memcpy (arglist, target, mode, /*endp=*/0);
+      target = expand_builtin_memcpy (arglist, target, mode);
       if (target)
        return target;
       break;
 
     case BUILT_IN_MEMPCPY:
-      target = expand_builtin_memcpy (arglist, target, mode, /*endp=*/1);
+      target = expand_builtin_mempcpy (arglist, target, mode, /*endp=*/ 1);
       if (target)
        return target;
       break;
@@ -4622,13 +4690,13 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       break;
 
     case BUILT_IN_MEMSET:
-      target = expand_builtin_memset (exp, target, mode);
+      target = expand_builtin_memset (arglist, target, mode);
       if (target)
        return target;
       break;
 
     case BUILT_IN_BZERO:
-      target = expand_builtin_bzero (exp);
+      target = expand_builtin_bzero (arglist);
       if (target)
        return target;
       break;
@@ -4751,10 +4819,9 @@ expand_builtin (exp, target, subtarget, mode, ignore)
    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;
+builtin_mathfn_code (tree t)
 {
   tree fndecl, arglist;
 
@@ -4801,8 +4868,7 @@ builtin_mathfn_code (t)
    constant.  ARGLIST is the argument list of the call.  */
 
 static tree
-fold_builtin_constant_p (arglist)
-     tree arglist;
+fold_builtin_constant_p (tree arglist)
 {
   if (arglist == 0)
     return 0;
@@ -4842,8 +4908,7 @@ fold_builtin_constant_p (arglist)
 /* Fold a call to __builtin_classify_type.  */
 
 static tree
-fold_builtin_classify_type (arglist)
-     tree arglist;
+fold_builtin_classify_type (tree arglist)
 {
   if (arglist == 0)
     return build_int_2 (no_type_class, 0);
@@ -4854,9 +4919,7 @@ fold_builtin_classify_type (arglist)
 /* Fold a call to __builtin_inf or __builtin_huge_val.  */
 
 static tree
-fold_builtin_inf (type, warn)
-     tree type;
-     int warn;
+fold_builtin_inf (tree type, int warn)
 {
   REAL_VALUE_TYPE real;
 
@@ -4870,9 +4933,7 @@ fold_builtin_inf (type, warn)
 /* Fold a call to __builtin_nan or __builtin_nans.  */
 
 static tree
-fold_builtin_nan (arglist, type, quiet)
-     tree arglist, type;
-     int quiet;
+fold_builtin_nan (tree arglist, tree type, int quiet)
 {
   REAL_VALUE_TYPE real;
   const char *str;
@@ -4893,8 +4954,7 @@ fold_builtin_nan (arglist, type, quiet)
    across (for instance floor((double)f) == (double)floorf (f).
    Do the transformation.  */
 static tree
-fold_trunc_transparent_mathfn (exp)
-     tree exp;
+fold_trunc_transparent_mathfn (tree exp)
 {
   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
   tree arglist = TREE_OPERAND (exp, 1);
@@ -4919,12 +4979,96 @@ fold_trunc_transparent_mathfn (exp)
   return 0;
 }
 
+/* Fold function call to builtin cabs, cabsf or cabsl.  FNDECL is the
+   function's DECL, ARGLIST is the argument list and TYPE is the return
+   type.  Return NULL_TREE if no simplification can be made.  */
+
+static tree
+fold_builtin_cabs (tree fndecl, tree arglist, tree type)
+{
+  tree arg;
+
+  if (!arglist || TREE_CHAIN (arglist))
+    return NULL_TREE;
+
+  arg = TREE_VALUE (arglist);
+  if (TREE_CODE (TREE_TYPE (arg)) != COMPLEX_TYPE
+      || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
+    return NULL_TREE;
+
+  /* Evaluate cabs of a constant at compile-time.  */
+  if (flag_unsafe_math_optimizations
+      && TREE_CODE (arg) == COMPLEX_CST
+      && TREE_CODE (TREE_REALPART (arg)) == REAL_CST
+      && TREE_CODE (TREE_IMAGPART (arg)) == REAL_CST
+      && ! TREE_CONSTANT_OVERFLOW (TREE_REALPART (arg))
+      && ! TREE_CONSTANT_OVERFLOW (TREE_IMAGPART (arg)))
+    {
+      REAL_VALUE_TYPE r, i;
+
+      r = TREE_REAL_CST (TREE_REALPART (arg));
+      i = TREE_REAL_CST (TREE_IMAGPART (arg));
+
+      real_arithmetic (&r, MULT_EXPR, &r, &r);
+      real_arithmetic (&i, MULT_EXPR, &i, &i);
+      real_arithmetic (&r, PLUS_EXPR, &r, &i);
+      if (real_sqrt (&r, TYPE_MODE (type), &r)
+         || ! flag_trapping_math)
+       return build_real (type, r);
+    }
+
+  /* If either part is zero, cabs is fabs of the other.  */
+  if (TREE_CODE (arg) == COMPLEX_EXPR
+      && real_zerop (TREE_OPERAND (arg, 0)))
+    return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg, 1)));
+  if (TREE_CODE (arg) == COMPLEX_EXPR
+      && real_zerop (TREE_OPERAND (arg, 1)))
+    return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg, 0)));
+
+  if (flag_unsafe_math_optimizations)
+    {
+      enum built_in_function fcode;
+      tree sqrtfn;
+
+      fcode = DECL_FUNCTION_CODE (fndecl);
+      if (fcode == BUILT_IN_CABS)
+       sqrtfn = implicit_built_in_decls[BUILT_IN_SQRT];
+      else if (fcode == BUILT_IN_CABSF)
+       sqrtfn = implicit_built_in_decls[BUILT_IN_SQRTF];
+      else if (fcode == BUILT_IN_CABSL)
+       sqrtfn = implicit_built_in_decls[BUILT_IN_SQRTL];
+      else
+       sqrtfn = NULL_TREE;
+
+      if (sqrtfn != NULL_TREE)
+       {
+         tree rpart, ipart, result, arglist;
+
+         rpart = fold (build1 (REALPART_EXPR, type, arg));
+         ipart = fold (build1 (IMAGPART_EXPR, type, arg));
+
+         rpart = save_expr (rpart);
+         ipart = save_expr (ipart);
+
+         result = fold (build (PLUS_EXPR, type,
+                               fold (build (MULT_EXPR, type,
+                                            rpart, rpart)),
+                               fold (build (MULT_EXPR, type,
+                                            ipart, ipart))));
+
+         arglist = build_tree_list (NULL_TREE, result);
+         return build_function_call_expr (sqrtfn, arglist);
+       }
+    }
+
+  return NULL_TREE;
+}
+
 /* Used by constant folding to eliminate some builtin calls early.  EXP is
    the CALL_EXPR of a call to a builtin function.  */
 
 tree
-fold_builtin (exp)
-     tree exp;
+fold_builtin (tree exp)
 {
   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
   tree arglist = TREE_OPERAND (exp, 1);
@@ -4955,6 +5099,18 @@ fold_builtin (exp)
        }
       break;
 
+    case BUILT_IN_FABS:
+    case BUILT_IN_FABSF:
+    case BUILT_IN_FABSL:
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       return fold (build1 (ABS_EXPR, type, TREE_VALUE (arglist)));
+      break;
+
+    case BUILT_IN_CABS:
+    case BUILT_IN_CABSF:
+    case BUILT_IN_CABSL:
+      return fold_builtin_cabs (fndecl, arglist, type);
+
     case BUILT_IN_SQRT:
     case BUILT_IN_SQRTF:
     case BUILT_IN_SQRTL:
@@ -4967,12 +5123,10 @@ fold_builtin (exp)
          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)
+             if (real_sqrt (&r, TYPE_MODE (type), &x)
                  || (!flag_trapping_math && !flag_errno_math))
                return build_real (type, r);
            }
@@ -5019,7 +5173,7 @@ fold_builtin (exp)
 
          /* Optimize sin(0.0) = 0.0.  */
          if (real_zerop (arg))
-           return build_real (type, dconst0);
+           return arg;
        }
       break;
 
@@ -5033,6 +5187,14 @@ fold_builtin (exp)
          /* Optimize cos(0.0) = 1.0.  */
          if (real_zerop (arg))
            return build_real (type, dconst1);
+
+         /* Optimize cos(-x) into cos(x).  */
+         if (TREE_CODE (arg) == NEGATE_EXPR)
+           {
+             tree arglist = build_tree_list (NULL_TREE,
+                                             TREE_OPERAND (arg, 0));
+             return build_function_call_expr (fndecl, arglist);
+           }
        }
       break;
 
@@ -5048,6 +5210,41 @@ fold_builtin (exp)
          if (real_zerop (arg))
            return build_real (type, dconst1);
 
+         /* Optimize exp(1.0) = e.  */
+         if (real_onep (arg))
+           {
+             REAL_VALUE_TYPE cst;
+
+             if (! builtin_dconsts_init)
+               init_builtin_dconsts ();
+             real_convert (&cst, TYPE_MODE (type), &dconste);
+             return build_real (type, cst);
+           }
+
+         /* Attempt to evaluate exp at compile-time.  */
+         if (flag_unsafe_math_optimizations
+             && TREE_CODE (arg) == REAL_CST
+             && ! TREE_CONSTANT_OVERFLOW (arg))
+           {
+             REAL_VALUE_TYPE cint;
+             REAL_VALUE_TYPE c;
+             HOST_WIDE_INT n;
+
+             c = TREE_REAL_CST (arg);
+             n = real_to_integer (&c);
+             real_from_integer (&cint, VOIDmode, n,
+                                n < 0 ? -1 : 0, 0);
+             if (real_identical (&c, &cint))
+               {
+                 REAL_VALUE_TYPE x;
+
+                 if (! builtin_dconsts_init)
+                   init_builtin_dconsts ();
+                 real_powi (&x, TYPE_MODE (type), &dconste, n);
+                 return build_real (type, x);
+               }
+           }
+
          /* Optimize exp(log(x)) = x.  */
          fcode = builtin_mathfn_code (arg);
          if (flag_unsafe_math_optimizations
@@ -5107,6 +5304,53 @@ fold_builtin (exp)
        }
       break;
 
+    case BUILT_IN_TAN:
+    case BUILT_IN_TANF:
+    case BUILT_IN_TANL:
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       {
+         enum built_in_function fcode;
+         tree arg = TREE_VALUE (arglist);
+
+         /* Optimize tan(0.0) = 0.0.  */
+         if (real_zerop (arg))
+           return arg;
+
+         /* Optimize tan(atan(x)) = x.  */
+         fcode = builtin_mathfn_code (arg);
+         if (flag_unsafe_math_optimizations
+             && (fcode == BUILT_IN_ATAN
+                 || fcode == BUILT_IN_ATANF
+                 || fcode == BUILT_IN_ATANL))
+           return TREE_VALUE (TREE_OPERAND (arg, 1));
+       }
+      break;
+
+    case BUILT_IN_ATAN:
+    case BUILT_IN_ATANF:
+    case BUILT_IN_ATANL:
+      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+       {
+         tree arg = TREE_VALUE (arglist);
+
+         /* Optimize atan(0.0) = 0.0.  */
+         if (real_zerop (arg))
+           return arg;
+
+         /* Optimize atan(1.0) = pi/4.  */
+         if (real_onep (arg))
+           {
+             REAL_VALUE_TYPE cst;
+
+             if (! builtin_dconsts_init)
+               init_builtin_dconsts ();
+             real_convert (&cst, TYPE_MODE (type), &dconstpi);
+             cst.exp -= 2;
+             return build_real (type, cst);
+           }
+       }
+      break;
+
     case BUILT_IN_POW:
     case BUILT_IN_POWF:
     case BUILT_IN_POWL:
@@ -5144,7 +5388,7 @@ fold_builtin (exp)
              /* Optimize pow(x,2.0) = x*x.  */
              if (REAL_VALUES_EQUAL (c, dconst2)
                  && (*lang_hooks.decls.global_bindings_p) () == 0
-                 && ! contains_placeholder_p (arg0))
+                 && ! CONTAINS_PLACEHOLDER_P (arg0))
                {
                  arg0 = save_expr (arg0);
                  return fold (build (MULT_EXPR, type, arg0, arg0));
@@ -5154,7 +5398,7 @@ fold_builtin (exp)
              if (flag_unsafe_math_optimizations
                  && REAL_VALUES_EQUAL (c, dconstm2)
                  && (*lang_hooks.decls.global_bindings_p) () == 0
-                 && ! contains_placeholder_p (arg0))
+                 && ! CONTAINS_PLACEHOLDER_P (arg0))
                {
                  arg0 = save_expr (arg0);
                  return fold (build (RDIV_EXPR, type,
@@ -5185,6 +5429,28 @@ fold_builtin (exp)
                      return build_function_call_expr (sqrtfn, arglist);
                    }
                }
+
+             /* Attempt to evaluate pow at compile-time.  */
+             if (TREE_CODE (arg0) == REAL_CST
+                 && ! TREE_CONSTANT_OVERFLOW (arg0))
+               {
+                 REAL_VALUE_TYPE cint;
+                 HOST_WIDE_INT n;
+
+                 n = real_to_integer (&c);
+                 real_from_integer (&cint, VOIDmode, n,
+                                    n < 0 ? -1 : 0, 0);
+                 if (real_identical (&c, &cint))
+                   {
+                     REAL_VALUE_TYPE x;
+                     bool inexact;
+
+                     x = TREE_REAL_CST (arg0);
+                     inexact = real_powi (&x, TYPE_MODE (type), &x, n);
+                     if (flag_unsafe_math_optimizations || !inexact)
+                       return build_real (type, x);
+                   }
+               }
            }
 
          /* Optimize pow(exp(x),y) = exp(x*y).  */
@@ -5279,8 +5545,7 @@ fold_builtin (exp)
 /* Conveniently construct a function call expression.  */
 
 tree
-build_function_call_expr (fn, arglist)
-     tree fn, arglist;
+build_function_call_expr (tree fn, tree arglist)
 {
   tree call_expr;
 
@@ -5297,13 +5562,13 @@ build_function_call_expr (fn, arglist)
    ellipses, otherwise the last specifier must be a VOID_TYPE.  */
 
 static int
-validate_arglist VPARAMS ((tree arglist, ...))
+validate_arglist (tree arglist, ...)
 {
   enum tree_code code;
   int res = 0;
+  va_list ap;
 
-  VA_OPEN (ap, arglist);
-  VA_FIXEDARG (ap, tree, arglist);
+  va_start (ap, arglist);
 
   do
     {
@@ -5335,7 +5600,7 @@ validate_arglist VPARAMS ((tree arglist, ...))
   /* We need gotos here since we can only have one VA_CLOSE in a
      function.  */
  end: ;
-  VA_CLOSE (ap);
+  va_end (ap);
 
   return res;
 }
@@ -5343,19 +5608,18 @@ validate_arglist VPARAMS ((tree arglist, ...))
 /* Default version of target-specific builtin setup that does nothing.  */
 
 void
-default_init_builtins ()
+default_init_builtins (void)
 {
 }
 
 /* Default target-specific builtin expander that does nothing.  */
 
 rtx
-default_expand_builtin (exp, target, subtarget, mode, ignore)
-     tree exp ATTRIBUTE_UNUSED;
-     rtx target ATTRIBUTE_UNUSED;
-     rtx subtarget ATTRIBUTE_UNUSED;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-     int ignore ATTRIBUTE_UNUSED;
+default_expand_builtin (tree exp ATTRIBUTE_UNUSED,
+                       rtx target ATTRIBUTE_UNUSED,
+                       rtx subtarget ATTRIBUTE_UNUSED,
+                       enum machine_mode mode ATTRIBUTE_UNUSED,
+                       int ignore ATTRIBUTE_UNUSED)
 {
   return NULL_RTX;
 }
@@ -5363,7 +5627,7 @@ default_expand_builtin (exp, target, subtarget, mode, ignore)
 /* Instantiate all remaining CONSTANT_P_RTX nodes.  */
 
 void
-purge_builtin_constant_p ()
+purge_builtin_constant_p (void)
 {
   rtx insn, set, arg, new, note;
 
@@ -5385,3 +5649,16 @@ purge_builtin_constant_p ()
       }
 }
 
+/* Returns true is EXP represents data that would potentially reside
+   in a readonly section.  */
+
+static bool
+readonly_data_expr (tree exp)
+{
+  STRIP_NOPS (exp);
+
+  if (TREE_CODE (exp) == ADDR_EXPR)
+    return decl_readonly_section (TREE_OPERAND (exp, 0), 0);
+  else
+    return false;
+}