OSDN Git Service

PR middle-end/26983
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index 181f7c1..5bcba14 100644 (file)
@@ -146,7 +146,6 @@ static tree fold_trunc_transparent_mathfn (tree, tree);
 static bool readonly_data_expr (tree);
 static rtx expand_builtin_fabs (tree, rtx, rtx);
 static rtx expand_builtin_signbit (tree, rtx);
-static tree fold_builtin_cabs (tree, tree);
 static tree fold_builtin_sqrt (tree, tree);
 static tree fold_builtin_cbrt (tree, tree);
 static tree fold_builtin_pow (tree, tree, tree);
@@ -161,9 +160,7 @@ static tree fold_builtin_ceil (tree, tree);
 static tree fold_builtin_round (tree, tree);
 static tree fold_builtin_int_roundingfn (tree, tree);
 static tree fold_builtin_bitop (tree, tree);
-static tree fold_builtin_memcpy (tree, tree);
-static tree fold_builtin_mempcpy (tree, tree, int);
-static tree fold_builtin_memmove (tree, tree);
+static tree fold_builtin_memory_op (tree, tree, bool, int);
 static tree fold_builtin_strchr (tree, tree);
 static tree fold_builtin_memcmp (tree);
 static tree fold_builtin_strcmp (tree);
@@ -276,16 +273,44 @@ get_pointer_alignment (tree exp, unsigned int max_align)
          /* See what we are pointing at and look at its alignment.  */
          exp = TREE_OPERAND (exp, 0);
          inner = max_align;
-         while (handled_component_p (exp))
+         if (handled_component_p (exp))
            {
-             /* Fields in a structure can be packed, honor DECL_ALIGN
-                of the FIELD_DECL.  For all other references the conservative
-                alignment is the element type alignment.  */
-             if (TREE_CODE (exp) == COMPONENT_REF)
-               inner = MIN (inner, DECL_ALIGN (TREE_OPERAND (exp, 1)));
-             else
-               inner = MIN (inner, TYPE_ALIGN (TREE_TYPE (exp)));
-             exp = TREE_OPERAND (exp, 0);
+             HOST_WIDE_INT bitsize, bitpos;
+             tree offset;
+             enum machine_mode mode; 
+             int unsignedp, volatilep;
+
+             exp = get_inner_reference (exp, &bitsize, &bitpos, &offset,
+                                        &mode, &unsignedp, &volatilep, true);
+             if (bitpos)
+               inner = MIN (inner, (unsigned) (bitpos & -bitpos));
+             if (offset && TREE_CODE (offset) == PLUS_EXPR
+                 && host_integerp (TREE_OPERAND (offset, 1), 1))
+               {
+                 /* Any overflow in calculating offset_bits won't change
+                    the alignment.  */
+                 unsigned offset_bits
+                   = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1)
+                      * BITS_PER_UNIT);
+
+                 if (offset_bits)
+                   inner = MIN (inner, (offset_bits & -offset_bits));
+                 offset = TREE_OPERAND (offset, 0);
+               }
+             if (offset && TREE_CODE (offset) == MULT_EXPR
+                 && host_integerp (TREE_OPERAND (offset, 1), 1))
+               {
+                 /* Any overflow in calculating offset_factor won't change
+                    the alignment.  */
+                 unsigned offset_factor
+                   = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1)
+                      * BITS_PER_UNIT);
+
+                 if (offset_factor)
+                   inner = MIN (inner, (offset_factor & -offset_factor));
+               }
+             else if (offset)
+               inner = MIN (inner, BITS_PER_UNIT);
            }
          if (TREE_CODE (exp) == FUNCTION_DECL)
            align = FUNCTION_BOUNDARY;
@@ -295,6 +320,9 @@ get_pointer_alignment (tree exp, unsigned int max_align)
          else if (CONSTANT_CLASS_P (exp))
            align = MIN (inner, (unsigned)CONSTANT_ALIGNMENT (exp, align));
 #endif
+         else if (TREE_CODE (exp) == VIEW_CONVERT_EXPR
+                  || TREE_CODE (exp) == INDIRECT_REF)
+           align = MIN (TYPE_ALIGN (TREE_TYPE (exp)), inner);
          else
            align = MIN (align, inner);
          return MIN (align, max_align);
@@ -510,12 +538,16 @@ expand_builtin_return_addr (enum built_in_function fndecl_code, int count)
 #else
   rtx tem;
 
-  /* For a zero count, we don't care what frame address we return, so frame
-     pointer elimination is OK, and using the soft frame pointer is OK.
-     For a nonzero count, we require a stable offset from the current frame
-     pointer to the previous one, so we must use the hard frame pointer, and
+  /* For a zero count with __builtin_return_address, we don't care what
+     frame address we return, because target-specific definitions will
+     override us.  Therefore frame pointer elimination is OK, and using
+     the soft frame pointer is OK.
+
+     For a non-zero count, or a zero count with __builtin_frame_address,
+     we require a stable offset from the current frame pointer to the
+     previous one, so we must use the hard frame pointer, and
      we must disable frame pointer elimination.  */
-  if (count == 0)
+  if (count == 0 && fndecl_code == BUILT_IN_RETURN_ADDRESS)
     tem = frame_pointer_rtx;
   else
     {
@@ -728,6 +760,12 @@ expand_builtin_setjmp (tree arglist, rtx target)
 
   emit_label (next_lab);
 
+  /* Because setjmp and longjmp are not represented in the CFG, a cfgcleanup
+     may find that the basic block starting with NEXT_LAB is unreachable.
+     The whole block, along with NEXT_LAB, would be removed (see PR26983).
+     Make sure that never happens.  */
+  LABEL_PRESERVE_P (next_lab) = 1;
+     
   expand_builtin_setjmp_receiver (next_lab);
 
   /* Set TARGET to one.  */
@@ -2854,10 +2892,19 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
       unsigned int dest_align
        = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
       rtx dest_mem, src_mem, dest_addr, len_rtx;
-      tree result = fold_builtin_memcpy (fndecl, arglist);
+      tree result = fold_builtin_memory_op (arglist, TREE_TYPE (TREE_TYPE (fndecl)),
+                                           false, /*endp=*/0);
 
       if (result)
-       return expand_expr (result, target, mode, EXPAND_NORMAL);
+       {
+         while (TREE_CODE (result) == COMPOUND_EXPR)
+           {
+             expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
+                          EXPAND_NORMAL);
+             result = TREE_OPERAND (result, 1);
+           }
+         return expand_expr (result, target, mode, EXPAND_NORMAL);
+       }
 
       /* If DEST is not a pointer type, call the normal function.  */
       if (dest_align == 0)
@@ -2943,10 +2990,18 @@ expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode m
       unsigned int dest_align
        = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
       rtx dest_mem, src_mem, len_rtx;
-      tree result = fold_builtin_mempcpy (arglist, type, endp);
+      tree result = fold_builtin_memory_op (arglist, type, false, endp);
 
       if (result)
-       return expand_expr (result, target, mode, EXPAND_NORMAL);
+       {
+         while (TREE_CODE (result) == COMPOUND_EXPR)
+           {
+             expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
+                          EXPAND_NORMAL);
+             result = TREE_OPERAND (result, 1);
+           }
+         return expand_expr (result, target, mode, EXPAND_NORMAL);
+       }
 
       /* If either SRC or DEST is not a pointer type, don't do this
         operation in-line.  */
@@ -3017,10 +3072,18 @@ expand_builtin_memmove (tree arglist, tree type, rtx target,
       unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
       unsigned int dest_align
        = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
-      tree result = fold_builtin_memmove (arglist, type);
+      tree result = fold_builtin_memory_op (arglist, type, false, /*endp=*/3);
 
       if (result)
-       return expand_expr (result, target, mode, EXPAND_NORMAL);
+       {
+         while (TREE_CODE (result) == COMPOUND_EXPR)
+           {
+             expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
+                          EXPAND_NORMAL);
+             result = TREE_OPERAND (result, 1);
+           }
+         return expand_expr (result, target, mode, EXPAND_NORMAL);
+       }
 
       /* If DEST is not a pointer type, call the normal function.  */
       if (dest_align == 0)
@@ -3168,7 +3231,15 @@ expand_builtin_strcpy (tree fndecl, tree arglist, rtx target, enum machine_mode
     {
       tree result = fold_builtin_strcpy (fndecl, arglist, 0);
       if (result)
-       return expand_expr (result, target, mode, EXPAND_NORMAL);
+       {
+         while (TREE_CODE (result) == COMPOUND_EXPR)
+           {
+             expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
+                          EXPAND_NORMAL);
+             result = TREE_OPERAND (result, 1);
+           }
+         return expand_expr (result, target, mode, EXPAND_NORMAL);
+       }
 
       return expand_movstr (TREE_VALUE (arglist),
                            TREE_VALUE (TREE_CHAIN (arglist)),
@@ -3294,7 +3365,15 @@ expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode)
       tree result = fold_builtin_strncpy (fndecl, arglist, slen);
 
       if (result)
-       return expand_expr (result, target, mode, EXPAND_NORMAL);
+       {
+         while (TREE_CODE (result) == COMPOUND_EXPR)
+           {
+             expand_expr (TREE_OPERAND (result, 0), const0_rtx, VOIDmode,
+                          EXPAND_NORMAL);
+             result = TREE_OPERAND (result, 1);
+           }
+         return expand_expr (result, target, mode, EXPAND_NORMAL);
+       }
 
       /* We must be passed a constant len and src parameter.  */
       if (!host_integerp (len, 1) || !slen || !host_integerp (slen, 1))
@@ -5598,14 +5677,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
 
   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
     return targetm.expand_builtin (exp, target, subtarget, mode, ignore);
-  else
-    {
-      /* Try expanding the builtin via the generic target hook.  */
-      rtx tmp = targetm.expand_library_builtin (exp, target, subtarget,
-                                               mode, ignore);
-      if (tmp != NULL_RTX)
-       return tmp;
-    }
 
   /* When not optimizing, generate calls to library functions for a certain
      set of builtins.  */
@@ -6504,7 +6575,8 @@ fold_builtin_constant_p (tree arglist)
   if (TREE_SIDE_EFFECTS (arglist)
       || AGGREGATE_TYPE_P (TREE_TYPE (arglist))
       || POINTER_TYPE_P (TREE_TYPE (arglist))
-      || cfun == 0)
+      || cfun == 0
+      || folding_initializer)
     return integer_zero_node;
 
   return 0;
@@ -6776,15 +6848,52 @@ fold_fixed_mathfn (tree fndecl, tree arglist)
          return build_function_call_expr (decl, arglist);
        }
     }
+
+  /* Canonicalize llround (x) to lround (x) on LP64 targets where
+     sizeof (long long) == sizeof (long).  */
+  if (TYPE_PRECISION (long_long_integer_type_node)
+      == TYPE_PRECISION (long_integer_type_node))
+    {
+      tree newfn = NULL_TREE;
+      switch (fcode)
+       {
+       CASE_FLT_FN (BUILT_IN_LLCEIL):
+         newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LCEIL);
+         break;
+
+       CASE_FLT_FN (BUILT_IN_LLFLOOR):
+         newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LFLOOR);
+         break;
+
+       CASE_FLT_FN (BUILT_IN_LLROUND):
+         newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LROUND);
+         break;
+
+       CASE_FLT_FN (BUILT_IN_LLRINT):
+         newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LRINT);
+         break;
+
+       default:
+         break;
+       }
+
+      if (newfn)
+       {
+         tree newcall = build_function_call_expr (newfn, arglist);
+         return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), newcall);
+       }
+    }
+
   return 0;
 }
 
 /* Fold function call to builtin cabs, cabsf or cabsl.  ARGLIST
-   is the argument list and TYPE is the return type.  Return
-   NULL_TREE if no if no simplification can be made.  */
+   is the argument list, TYPE is the return type and FNDECL is the
+   original function DECL.  Return NULL_TREE if no if no simplification
+   can be made.  */
 
 static tree
-fold_builtin_cabs (tree arglist, tree type)
+fold_builtin_cabs (tree arglist, tree type, tree fndecl)
 {
   tree arg;
 
@@ -6825,6 +6934,14 @@ fold_builtin_cabs (tree arglist, tree type)
       && real_zerop (TREE_OPERAND (arg, 1)))
     return fold_build1 (ABS_EXPR, type, TREE_OPERAND (arg, 0));
 
+  /* Optimize cabs(-z) and cabs(conj(z)) as cabs(z).  */
+  if (TREE_CODE (arg) == NEGATE_EXPR
+      || TREE_CODE (arg) == CONJ_EXPR)
+    {
+      tree arglist = build_tree_list (NULL_TREE, TREE_OPERAND (arg, 0));
+      return build_function_call_expr (fndecl, arglist);
+    }
+
   /* Don't do this when optimizing for size.  */
   if (flag_unsafe_math_optimizations
       && optimize && !optimize_size)
@@ -7777,78 +7894,121 @@ fold_builtin_exponent (tree fndecl, tree arglist,
   return 0;
 }
 
-/* Fold function call to builtin memcpy.  Return
+/* Fold function call to builtin memset.  Return
    NULL_TREE if no simplification can be made.  */
 
 static tree
-fold_builtin_memcpy (tree fndecl, tree arglist)
+fold_builtin_memset (tree arglist, tree type, bool ignore)
 {
-  tree dest, src, len;
+  tree dest, c, len, var, ret;
+  unsigned HOST_WIDE_INT length, cval;
 
   if (!validate_arglist (arglist,
-                        POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+                        POINTER_TYPE, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
 
   dest = TREE_VALUE (arglist);
-  src = TREE_VALUE (TREE_CHAIN (arglist));
+  c = TREE_VALUE (TREE_CHAIN (arglist));
   len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
 
+  if (! host_integerp (len, 1))
+    return 0;
+
   /* If the LEN parameter is zero, return DEST.  */
   if (integer_zerop (len))
-    return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, src);
+    return omit_one_operand (type, dest, c);
 
-  /* If SRC and DEST are the same (and not volatile), return DEST.  */
-  if (operand_equal_p (src, dest, 0))
-    return omit_one_operand (TREE_TYPE (TREE_TYPE (fndecl)), dest, len);
+  if (! host_integerp (c, 1) || TREE_SIDE_EFFECTS (dest))
+    return 0;
 
-  return 0;
+  var = dest;
+  STRIP_NOPS (var);
+  if (TREE_CODE (var) != ADDR_EXPR)
+    return 0;
+
+  var = TREE_OPERAND (var, 0);
+  if (TREE_THIS_VOLATILE (var))
+    return 0;
+
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (var))
+      && !POINTER_TYPE_P (TREE_TYPE (var)))
+    return 0;
+
+  length = tree_low_cst (len, 1);
+  if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (var))) != length
+      || get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
+        < (int) length)
+    return 0;
+
+  if (length > HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT)
+    return 0;
+
+  if (integer_zerop (c))
+    cval = 0;
+  else
+    {
+      if (CHAR_BIT != 8 || BITS_PER_UNIT != 8 || HOST_BITS_PER_WIDE_INT > 64)
+       return 0;
+
+      cval = tree_low_cst (c, 1);
+      cval &= 0xff;
+      cval |= cval << 8;
+      cval |= cval << 16;
+      cval |= (cval << 31) << 1;
+    }
+
+  ret = build_int_cst_type (TREE_TYPE (var), cval);
+  ret = build2 (MODIFY_EXPR, TREE_TYPE (var), var, ret);
+  if (ignore)
+    return ret;
+
+  return omit_one_operand (type, dest, ret);
 }
 
-/* Fold function call to builtin mempcpy.  Return
+/* Fold function call to builtin memset.  Return
    NULL_TREE if no simplification can be made.  */
 
 static tree
-fold_builtin_mempcpy (tree arglist, tree type, int endp)
+fold_builtin_bzero (tree arglist, bool ignore)
 {
-  if (validate_arglist (arglist,
-                       POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
-    {
-      tree dest = TREE_VALUE (arglist);
-      tree src = TREE_VALUE (TREE_CHAIN (arglist));
-      tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+  tree dest, size, newarglist;
 
-      /* If the LEN parameter is zero, return DEST.  */
-      if (integer_zerop (len))
-       return omit_one_operand (type, dest, src);
+  if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+    return 0;
 
-      /* If SRC and DEST are the same (and not volatile), return DEST+LEN.  */
-      if (operand_equal_p (src, dest, 0))
-       {
-         if (endp == 0)
-           return omit_one_operand (type, dest, len);
+  if (!ignore)
+    return 0;
 
-         if (endp == 2)
-           len = fold_build2 (MINUS_EXPR, TREE_TYPE (len), len,
-                              ssize_int (1));
+  dest = TREE_VALUE (arglist);
+  size = TREE_VALUE (TREE_CHAIN (arglist));
 
-         len = fold_convert (TREE_TYPE (dest), len);
-         len = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, len);
-         return fold_convert (type, len);
-       }
-    }
-  return 0;
+  /* New argument list transforming bzero(ptr x, int y) to
+     memset(ptr x, int 0, size_t y).   This is done this way
+     so that if it isn't expanded inline, we fallback to
+     calling bzero instead of memset.  */
+
+  newarglist = build_tree_list (NULL_TREE, fold_convert (sizetype, size));
+  newarglist = tree_cons (NULL_TREE, integer_zero_node, newarglist);
+  newarglist = tree_cons (NULL_TREE, dest, newarglist);
+  return fold_builtin_memset (newarglist, void_type_node, ignore);
 }
 
-/* Fold function call to builtin memmove.  Return
-   NULL_TREE if no simplification can be made.  */
+/* Fold function call to builtin mem{{,p}cpy,move}.  Return
+   NULL_TREE if no simplification can be made.
+   If ENDP is 0, return DEST (like memcpy).
+   If ENDP is 1, return DEST+LEN (like mempcpy).
+   If ENDP is 2, return DEST+LEN-1 (like stpcpy).
+   If ENDP is 3, return DEST, additionally *SRC and *DEST may overlap
+   (memmove).   */
 
 static tree
-fold_builtin_memmove (tree arglist, tree type)
+fold_builtin_memory_op (tree arglist, tree type, bool ignore, int endp)
 {
-  tree dest, src, len;
+  tree dest, src, len, destvar, srcvar, expr;
+  unsigned HOST_WIDE_INT length;
 
-  if (!validate_arglist (arglist,
-                        POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+  if (! validate_arglist (arglist,
+                         POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
 
   dest = TREE_VALUE (arglist);
@@ -7859,11 +8019,115 @@ fold_builtin_memmove (tree arglist, tree type)
   if (integer_zerop (len))
     return omit_one_operand (type, dest, src);
 
-  /* If SRC and DEST are the same (and not volatile), return DEST.  */
+  /* If SRC and DEST are the same (and not volatile), return
+     DEST{,+LEN,+LEN-1}.  */
   if (operand_equal_p (src, dest, 0))
-    return omit_one_operand (type, dest, len);
+    expr = len;
+  else
+    {
+      if (! host_integerp (len, 1))
+       return 0;
 
-  return 0;
+      if (TREE_SIDE_EFFECTS (dest) || TREE_SIDE_EFFECTS (src))
+       return 0;
+
+      destvar = dest;
+      STRIP_NOPS (destvar);
+      if (TREE_CODE (destvar) != ADDR_EXPR)
+       return 0;
+
+      destvar = TREE_OPERAND (destvar, 0);
+      if (TREE_THIS_VOLATILE (destvar))
+       return 0;
+
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (destvar))
+         && !POINTER_TYPE_P (TREE_TYPE (destvar))
+         && !SCALAR_FLOAT_TYPE_P (TREE_TYPE (destvar)))
+       return 0;
+
+      srcvar = src;
+      STRIP_NOPS (srcvar);
+      if (TREE_CODE (srcvar) != ADDR_EXPR)
+       return 0;
+
+      srcvar = TREE_OPERAND (srcvar, 0);
+      if (TREE_THIS_VOLATILE (srcvar))
+       return 0;
+
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
+         && !POINTER_TYPE_P (TREE_TYPE (srcvar))
+         && !SCALAR_FLOAT_TYPE_P (TREE_TYPE (srcvar)))
+       return 0;
+
+      length = tree_low_cst (len, 1);
+      if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (destvar))) != length
+         || get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
+            < (int) length
+         || GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (srcvar))) != length
+         || get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
+            < (int) length)
+       return 0;
+
+      if ((INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
+          || POINTER_TYPE_P (TREE_TYPE (srcvar)))
+         && (INTEGRAL_TYPE_P (TREE_TYPE (destvar))
+             || POINTER_TYPE_P (TREE_TYPE (destvar))))
+       expr = fold_convert (TREE_TYPE (destvar), srcvar);
+      else
+       expr = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (destvar), srcvar);
+      expr = build2 (MODIFY_EXPR, TREE_TYPE (destvar), destvar, expr);
+    }
+
+  if (ignore)
+    return expr;
+
+  if (endp == 0 || endp == 3)
+    return omit_one_operand (type, dest, expr);
+
+  if (expr == len)
+    expr = 0;
+
+  if (endp == 2)
+    len = fold_build2 (MINUS_EXPR, TREE_TYPE (len), len,
+                      ssize_int (1));
+
+  len = fold_convert (TREE_TYPE (dest), len);
+  dest = fold_build2 (PLUS_EXPR, TREE_TYPE (dest), dest, len);
+  dest = fold_convert (type, dest);
+  if (expr)
+    dest = omit_one_operand (type, dest, expr);
+  return dest;
+}
+
+/* Fold function call to builtin bcopy.  Return NULL_TREE if no
+   simplification can be made.  */
+
+static tree
+fold_builtin_bcopy (tree arglist, bool ignore)
+{
+  tree src, dest, size, newarglist;
+
+  if (!validate_arglist (arglist,
+                        POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+    return 0;
+
+  if (! ignore)
+    return 0;
+
+  src = TREE_VALUE (arglist);
+  dest = TREE_VALUE (TREE_CHAIN (arglist));
+  size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+
+  /* New argument list transforming bcopy(ptr x, ptr y, int z) to
+     memmove(ptr y, ptr x, size_t z).   This is done this way
+     so that if it isn't expanded inline, we fallback to
+     calling bcopy instead of memmove.  */
+
+  newarglist = build_tree_list (NULL_TREE, fold_convert (sizetype, size));
+  newarglist = tree_cons (NULL_TREE, src, newarglist);
+  newarglist = tree_cons (NULL_TREE, dest, newarglist);
+
+  return fold_builtin_memory_op (newarglist, void_type_node, true, /*endp=*/3);
 }
 
 /* Fold function call to builtin strcpy.  If LEN is not NULL, it represents
@@ -8656,7 +8920,7 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
       break;
 
     CASE_FLT_FN (BUILT_IN_CABS):
-      return fold_builtin_cabs (arglist, type);
+      return fold_builtin_cabs (arglist, type, fndecl);
 
     CASE_FLT_FN (BUILT_IN_SQRT):
       return fold_builtin_sqrt (arglist, type);
@@ -8754,14 +9018,23 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
     CASE_INT_FN (BUILT_IN_PARITY):
       return fold_builtin_bitop (fndecl, arglist);
 
+    case BUILT_IN_MEMSET:
+      return fold_builtin_memset (arglist, type, ignore);
+
     case BUILT_IN_MEMCPY:
-      return fold_builtin_memcpy (fndecl, arglist);
+      return fold_builtin_memory_op (arglist, type, ignore, /*endp=*/0);
 
     case BUILT_IN_MEMPCPY:
-      return fold_builtin_mempcpy (arglist, type, /*endp=*/1);
+      return fold_builtin_memory_op (arglist, type, ignore, /*endp=*/1);
 
     case BUILT_IN_MEMMOVE:
-      return fold_builtin_memmove (arglist, type);
+      return fold_builtin_memory_op (arglist, type, ignore, /*endp=*/3);
+
+    case BUILT_IN_BZERO:
+      return fold_builtin_bzero (arglist, ignore);
+
+    case BUILT_IN_BCOPY:
+      return fold_builtin_bcopy (arglist, ignore);
 
     CASE_FLT_FN (BUILT_IN_SIGNBIT):
       return fold_builtin_signbit (fndecl, arglist);
@@ -8959,18 +9232,6 @@ default_expand_builtin (tree exp ATTRIBUTE_UNUSED,
   return NULL_RTX;
 }
 
-/* Default target-specific library builtin expander that does nothing.  */
-
-rtx
-default_expand_library_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;
-}
-
 /* Returns true is EXP represents data that would potentially reside
    in a readonly section.  */