OSDN Git Service

* gdbinit.in: Set complaints to 0.
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index f1fa123..fa7ed01 100644 (file)
@@ -47,6 +47,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "langhooks.h"
 #include "basic-block.h"
 #include "tree-mudflap.h"
+#include "tree-flow.h"
 
 #ifndef PAD_VARARGS_DOWN
 #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
@@ -151,6 +152,7 @@ static tree fold_builtin_cbrt (tree, tree);
 static tree fold_builtin_pow (tree, tree, tree);
 static tree fold_builtin_powi (tree, tree, tree);
 static tree fold_builtin_cos (tree, tree, tree);
+static tree fold_builtin_cosh (tree, tree, tree);
 static tree fold_builtin_tan (tree, tree);
 static tree fold_builtin_trunc (tree, tree);
 static tree fold_builtin_floor (tree, tree);
@@ -552,7 +554,7 @@ expand_builtin_return_addr (enum built_in_function fndecl_code, int count)
      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,
+     For a nonzero 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.  */
@@ -2600,8 +2602,13 @@ expand_powi (rtx x, enum machine_mode mode, HOST_WIDE_INT n)
 static rtx
 expand_builtin_pow (tree exp, rtx target, rtx subtarget)
 {
+  tree arg0, arg1, fn, narg0, narglist;
   tree arglist = TREE_OPERAND (exp, 1);
-  tree arg0, arg1;
+  tree type = TREE_TYPE (exp);
+  REAL_VALUE_TYPE cint, c, c2;
+  HOST_WIDE_INT n;
+  rtx op, op2;
+  enum machine_mode mode = TYPE_MODE (type);
 
   if (! validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
     return 0;
@@ -2609,36 +2616,108 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
   arg0 = TREE_VALUE (arglist);
   arg1 = TREE_VALUE (TREE_CHAIN (arglist));
 
-  if (TREE_CODE (arg1) == REAL_CST
-      && ! TREE_CONSTANT_OVERFLOW (arg1))
+  if (TREE_CODE (arg1) != REAL_CST
+      || TREE_CONSTANT_OVERFLOW (arg1))
+    return expand_builtin_mathfn_2 (exp, target, subtarget);
+
+  /* Handle constant exponents.  */
+
+  /* For integer valued exponents we can expand to an optimal multiplication
+     sequence using expand_powi.  */
+  c = TREE_REAL_CST (arg1);
+  n = real_to_integer (&c);
+  real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
+  if (real_identical (&c, &cint)
+      && ((n >= -1 && n <= 2)
+         || (flag_unsafe_math_optimizations
+             && !optimize_size
+             && powi_cost (n) <= POWI_MAX_MULTS)))
     {
-      REAL_VALUE_TYPE cint;
-      REAL_VALUE_TYPE c;
-      HOST_WIDE_INT n;
+      op = expand_expr (arg0, subtarget, VOIDmode, 0);
+      if (n != 1)
+       {
+         op = force_reg (mode, op);
+         op = expand_powi (op, mode, n);
+       }
+      return op;
+    }
 
-      c = TREE_REAL_CST (arg1);
-      n = real_to_integer (&c);
+  narg0 = builtin_save_expr (arg0);
+  narglist = build_tree_list (NULL_TREE, narg0);
+
+  /* If the exponent is not integer valued, check if it is half of an integer.
+     In this case we can expand to sqrt (x) * x**(n/2).  */
+  fn = mathfn_built_in (type, BUILT_IN_SQRT);
+  if (fn != NULL_TREE)
+    {
+      real_arithmetic (&c2, MULT_EXPR, &c, &dconst2);
+      n = real_to_integer (&c2);
       real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
-      if (real_identical (&c, &cint))
-       {
-         /* If the exponent is -1, 0, 1 or 2, then expand_powi is exact.
-            Otherwise, check the number of multiplications required.
-            Note that pow never sets errno for an integer exponent.  */
-         if ((n >= -1 && n <= 2)
-             || (flag_unsafe_math_optimizations
-                 && ! optimize_size
-                 && powi_cost (n) <= POWI_MAX_MULTS))
+      if (real_identical (&c2, &cint)
+         && ((flag_unsafe_math_optimizations
+              && !optimize_size
+              && powi_cost (n/2) <= POWI_MAX_MULTS)
+             || n == 1))
+       {
+         tree call_expr = build_function_call_expr (fn, narglist);
+         op = expand_builtin (call_expr, NULL_RTX, subtarget, mode, 0);
+         if (n != 1)
            {
-             enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
-             rtx op = expand_expr (arg0, subtarget, VOIDmode, 0);
-             op = force_reg (mode, op);
-             return expand_powi (op, mode, n);
+             op2 = expand_expr (narg0, subtarget, VOIDmode, 0);
+             op2 = force_reg (mode, op2);
+             op2 = expand_powi (op2, mode, abs (n / 2));
+             op = expand_simple_binop (mode, MULT, op, op2, NULL_RTX,
+                                       0, OPTAB_LIB_WIDEN);
+             /* If the original exponent was negative, reciprocate the
+                result.  */
+             if (n < 0)
+               op = expand_binop (mode, sdiv_optab, CONST1_RTX (mode),
+                                  op, NULL_RTX, 0, OPTAB_LIB_WIDEN);
            }
+         return op;
        }
     }
 
-  if (! flag_unsafe_math_optimizations)
-    return NULL_RTX;
+  /* Try if the exponent is a third of an integer.  In this case
+     we can expand to x**(n/3) * cbrt(x)**(n%3).  */
+  fn = mathfn_built_in (type, BUILT_IN_CBRT);
+  if (fn != NULL_TREE)
+    {
+      real_arithmetic (&c2, MULT_EXPR, &c, &dconst3);
+      real_round (&c2, mode, &c2);
+      n = real_to_integer (&c2);
+      real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
+      real_arithmetic (&c2, RDIV_EXPR, &cint, &dconst3);
+      real_convert (&c2, mode, &c2);
+      if (real_identical (&c2, &c)
+         && ((!optimize_size
+              && flag_unsafe_math_optimizations
+              && powi_cost (n/3) <= POWI_MAX_MULTS)
+             || n == 1))
+       {
+         tree call_expr = build_function_call_expr (fn, narglist);
+         op = expand_builtin (call_expr, NULL_RTX, subtarget, mode, 0);
+         if (abs (n) % 3 == 2)
+           op = expand_simple_binop (mode, MULT, op, op, op,
+                                     0, OPTAB_LIB_WIDEN);
+         if (n != 1)
+           {
+             op2 = expand_expr (narg0, subtarget, VOIDmode, 0);
+             op2 = force_reg (mode, op2);
+             op2 = expand_powi (op2, mode, abs (n / 3));
+             op = expand_simple_binop (mode, MULT, op, op2, NULL_RTX,
+                                       0, OPTAB_LIB_WIDEN);
+             /* If the original exponent was negative, reciprocate the
+                result.  */
+             if (n < 0)
+               op = expand_binop (mode, sdiv_optab, CONST1_RTX (mode),
+                                  op, NULL_RTX, 0, OPTAB_LIB_WIDEN);
+           }
+         return op;
+       }
+    }
+
+  /* Fall back to optab expansion.  */
   return expand_builtin_mathfn_2 (exp, target, subtarget);
 }
 
@@ -4240,7 +4319,7 @@ std_expand_builtin_va_start (tree valist, rtx nextarg)
 {
   tree t;
 
-  t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist,
+  t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (valist), valist,
              make_tree (ptr_type_node, nextarg));
   TREE_SIDE_EFFECTS (t) = 1;
 
@@ -4311,12 +4390,12 @@ std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
       && !integer_zerop (TYPE_SIZE (type)))
     {
       t = fold_convert (TREE_TYPE (valist), size_int (boundary - 1));
-      t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
+      t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (valist), valist_tmp,
                  build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t));
       gimplify_and_add (t, pre_p);
 
       t = fold_convert (TREE_TYPE (valist), size_int (-boundary));
-      t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
+      t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (valist), valist_tmp,
                  build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist_tmp, t));
       gimplify_and_add (t, pre_p);
     }
@@ -4355,7 +4434,7 @@ std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
   /* Compute new value for AP.  */
   t = fold_convert (TREE_TYPE (valist), rounded_size);
   t = build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t);
-  t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
+  t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (valist), valist, t);
   gimplify_and_add (t, pre_p);
 
   addr = fold_convert (build_pointer_type (type), addr);
@@ -4520,7 +4599,7 @@ expand_builtin_va_copy (tree arglist)
 
   if (TREE_CODE (va_list_type_node) != ARRAY_TYPE)
     {
-      t = build2 (MODIFY_EXPR, va_list_type_node, dst, src);
+      t = build2 (GIMPLE_MODIFY_STMT, va_list_type_node, dst, src);
       TREE_SIDE_EFFECTS (t) = 1;
       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
     }
@@ -4693,15 +4772,14 @@ expand_builtin_fputs (tree arglist, rtx target, bool unlocked)
   return 0;
 }
 
-/* Expand a call to __builtin_expect.  We return our argument and emit a
-   NOTE_INSN_EXPECTED_VALUE note.  This is the expansion of __builtin_expect in
-   a non-jump context.  */
+/* Expand a call to __builtin_expect.  We just return our argument 
+   as the builtin_expect semantic should've been already executed by
+   tree branch prediction pass. */
 
 static rtx
 expand_builtin_expect (tree arglist, rtx target)
 {
   tree exp, c;
-  rtx note, rtx_c;
 
   if (arglist == NULL_TREE
       || TREE_CHAIN (arglist) == NULL_TREE)
@@ -4709,149 +4787,12 @@ expand_builtin_expect (tree arglist, rtx target)
   exp = TREE_VALUE (arglist);
   c = TREE_VALUE (TREE_CHAIN (arglist));
 
-  if (TREE_CODE (c) != INTEGER_CST)
-    {
-      error ("second argument to %<__builtin_expect%> must be a constant");
-      c = integer_zero_node;
-    }
-
   target = expand_expr (exp, target, VOIDmode, EXPAND_NORMAL);
-
-  /* Don't bother with expected value notes for integral constants.  */
-  if (flag_guess_branch_prob && GET_CODE (target) != CONST_INT)
-    {
-      /* We do need to force this into a register so that we can be
-        moderately sure to be able to correctly interpret the branch
-        condition later.  */
-      target = force_reg (GET_MODE (target), target);
-
-      rtx_c = expand_expr (c, NULL_RTX, GET_MODE (target), EXPAND_NORMAL);
-
-      note = emit_note (NOTE_INSN_EXPECTED_VALUE);
-      NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, target, rtx_c);
-    }
-
+  /* When guessing was done, the hints should be already stripped away.  */
+  gcc_assert (!flag_guess_branch_prob);
   return target;
 }
 
-/* Like expand_builtin_expect, except do this in a jump context.  This is
-   called from do_jump if the conditional is a __builtin_expect.  Return either
-   a list of insns to emit the jump or NULL if we cannot optimize
-   __builtin_expect.  We need to optimize this at jump time so that machines
-   like the PowerPC don't turn the test into a SCC operation, and then jump
-   based on the test being 0/1.  */
-
-rtx
-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);
-  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-  rtx ret = NULL_RTX;
-
-  /* Only handle __builtin_expect (test, 0) and
-     __builtin_expect (test, 1).  */
-  if (TREE_CODE (TREE_TYPE (arg1)) == INTEGER_TYPE
-      && (integer_zerop (arg1) || integer_onep (arg1)))
-    {
-      rtx insn, drop_through_label, temp;
-
-      /* Expand the jump insns.  */
-      start_sequence ();
-      do_jump (arg0, if_false_label, if_true_label);
-      ret = get_insns ();
-
-      drop_through_label = get_last_insn ();
-      if (drop_through_label && NOTE_P (drop_through_label))
-       drop_through_label = prev_nonnote_insn (drop_through_label);
-      if (drop_through_label && !LABEL_P (drop_through_label))
-       drop_through_label = NULL_RTX;
-      end_sequence ();
-
-      if (! if_true_label)
-       if_true_label = drop_through_label;
-      if (! if_false_label)
-       if_false_label = drop_through_label;
-
-      /* Go through and add the expect's to each of the conditional jumps.  */
-      insn = ret;
-      while (insn != NULL_RTX)
-       {
-         rtx next = NEXT_INSN (insn);
-
-         if (JUMP_P (insn) && any_condjump_p (insn))
-           {
-             rtx ifelse = SET_SRC (pc_set (insn));
-             rtx then_dest = XEXP (ifelse, 1);
-             rtx else_dest = XEXP (ifelse, 2);
-             int taken = -1;
-
-             /* First check if we recognize any of the labels.  */
-             if (GET_CODE (then_dest) == LABEL_REF
-                 && XEXP (then_dest, 0) == if_true_label)
-               taken = 1;
-             else if (GET_CODE (then_dest) == LABEL_REF
-                      && XEXP (then_dest, 0) == if_false_label)
-               taken = 0;
-             else if (GET_CODE (else_dest) == LABEL_REF
-                      && XEXP (else_dest, 0) == if_false_label)
-               taken = 1;
-             else if (GET_CODE (else_dest) == LABEL_REF
-                      && XEXP (else_dest, 0) == if_true_label)
-               taken = 0;
-             /* Otherwise check where we drop through.  */
-             else if (else_dest == pc_rtx)
-               {
-                 if (next && NOTE_P (next))
-                   next = next_nonnote_insn (next);
-
-                 if (next && JUMP_P (next)
-                     && any_uncondjump_p (next))
-                   temp = XEXP (SET_SRC (pc_set (next)), 0);
-                 else
-                   temp = next;
-
-                 /* TEMP is either a CODE_LABEL, NULL_RTX or something
-                    else that can't possibly match either target label.  */
-                 if (temp == if_false_label)
-                   taken = 1;
-                 else if (temp == if_true_label)
-                   taken = 0;
-               }
-             else if (then_dest == pc_rtx)
-               {
-                 if (next && NOTE_P (next))
-                   next = next_nonnote_insn (next);
-
-                 if (next && JUMP_P (next)
-                     && any_uncondjump_p (next))
-                   temp = XEXP (SET_SRC (pc_set (next)), 0);
-                 else
-                   temp = next;
-
-                 if (temp == if_false_label)
-                   taken = 0;
-                 else if (temp == if_true_label)
-                   taken = 1;
-               }
-
-             if (taken != -1)
-               {
-                 /* If the test is expected to fail, reverse the
-                    probabilities.  */
-                 if (integer_zerop (arg1))
-                   taken = 1 - taken;
-                 predict_insn_def (insn, PRED_BUILTIN_EXPECT, taken);
-               }
-           }
-
-         insn = next;
-       }
-    }
-
-  return ret;
-}
-
 void
 expand_builtin_trap (void)
 {
@@ -6797,9 +6738,9 @@ integer_valued_real_p (tree t)
       return integer_valued_real_p (TREE_OPERAND (t, 0));
 
     case COMPOUND_EXPR:
-    case MODIFY_EXPR:
+    case GIMPLE_MODIFY_STMT:
     case BIND_EXPR:
-      return integer_valued_real_p (TREE_OPERAND (t, 1));
+      return integer_valued_real_p (GENERIC_TREE_OPERAND (t, 1));
 
     case PLUS_EXPR:
     case MINUS_EXPR:
@@ -6814,15 +6755,7 @@ integer_valued_real_p (tree t)
             && integer_valued_real_p (TREE_OPERAND (t, 2));
 
     case REAL_CST:
-      if (! TREE_CONSTANT_OVERFLOW (t))
-      {
-       REAL_VALUE_TYPE c, cint;
-
-       c = TREE_REAL_CST (t);
-       real_trunc (&cint, TYPE_MODE (TREE_TYPE (t)), &c);
-       return real_identical (&c, &cint);
-      }
-      break;
+      return real_isinteger (TREE_REAL_CST_PTR (t), TYPE_MODE (TREE_TYPE (t)));
 
     case NOP_EXPR:
       {
@@ -6845,6 +6778,11 @@ integer_valued_real_p (tree t)
        CASE_FLT_FN (BUILT_IN_TRUNC):
          return true;
 
+       CASE_FLT_FN (BUILT_IN_FMIN):
+       CASE_FLT_FN (BUILT_IN_FMAX):
+         return integer_valued_real_p (TREE_VALUE (TREE_OPERAND (t, 1)))
+           && integer_valued_real_p (TREE_VALUE (TREE_CHAIN (TREE_OPERAND (t, 1))));
+
        default:
          break;
        }
@@ -7259,6 +7197,29 @@ fold_builtin_cos (tree arglist, tree type, tree fndecl)
   return NULL_TREE;
 }
 
+/* Fold function call to builtin cosh, coshf, or coshl.  Return
+   NULL_TREE if no simplification can be made.  */
+static tree
+fold_builtin_cosh (tree arglist, tree type, tree fndecl)
+{
+  if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+    {
+      tree arg = TREE_VALUE (arglist);
+      tree res, narg;
+
+      /* Calculate the result when the argument is a constant.  */
+      if ((res = do_mpfr_arg1 (arg, type, mpfr_cosh, NULL, NULL, 0)))
+       return res;
+  
+      /* Optimize cosh(-x) into cosh (x).  */
+      if ((narg = fold_strip_sign_ops (arg)))
+       return build_function_call_expr (fndecl, 
+                                        build_tree_list (NULL_TREE, narg));
+    }
+  
+  return NULL_TREE;
+}
+
 /* Fold function call to builtin tan, tanf, or tanl.  Return
    NULL_TREE if no simplification can be made.  */
 static tree
@@ -8135,7 +8096,7 @@ fold_builtin_memset (tree arglist, tree type, bool ignore)
     }
 
   ret = build_int_cst_type (TREE_TYPE (var), cval);
-  ret = build2 (MODIFY_EXPR, TREE_TYPE (var), var, ret);
+  ret = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (var), var, ret);
   if (ignore)
     return ret;
 
@@ -8182,7 +8143,6 @@ static tree
 fold_builtin_memory_op (tree arglist, tree type, bool ignore, int endp)
 {
   tree dest, src, len, destvar, srcvar, expr;
-  unsigned HOST_WIDE_INT length;
 
   if (! validate_arglist (arglist,
                          POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
@@ -8202,12 +8162,12 @@ fold_builtin_memory_op (tree arglist, tree type, bool ignore, int endp)
     expr = len;
   else
     {
+      tree srctype, desttype;
       if (endp == 3)
        {
-          unsigned int src_align
-            = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
-          unsigned int dest_align
-            = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+          int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
+          int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+
          /* Both DEST and SRC must be pointer types. 
             ??? This is what old code did.  Is the testing for pointer types
             really mandatory?
@@ -8215,71 +8175,83 @@ fold_builtin_memory_op (tree arglist, tree type, bool ignore, int endp)
             If either SRC is readonly or length is 1, we can use memcpy.  */
          if (dest_align && src_align
              && (readonly_data_expr (src)
-                 || integer_onep (len)))
+                 || (host_integerp (len, 1)
+                     && (MIN (src_align, dest_align) / BITS_PER_UNIT >=
+                         tree_low_cst (len, 1)))))
            {
              tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
              if (!fn)
                return 0;
              return build_function_call_expr (fn, arglist);
            }
+         return 0;
        }
-      if (! host_integerp (len, 1))
-       return 0;
 
-      if (TREE_SIDE_EFFECTS (dest) || TREE_SIDE_EFFECTS (src))
+      if (!host_integerp (len, 0))
        return 0;
-
-      destvar = dest;
-      STRIP_NOPS (destvar);
-      if (TREE_CODE (destvar) != ADDR_EXPR)
+      /* FIXME:
+         This logic lose for arguments like (type *)malloc (sizeof (type)),
+         since we strip the casts of up to VOID return value from malloc.
+        Perhaps we ought to inherit type from non-VOID argument here?  */
+      STRIP_NOPS (src);
+      STRIP_NOPS (dest);
+      srctype = TREE_TYPE (TREE_TYPE (src));
+      desttype = TREE_TYPE (TREE_TYPE (dest));
+      if (!srctype || !desttype
+         || !TYPE_SIZE_UNIT (srctype)
+         || !TYPE_SIZE_UNIT (desttype)
+         || TREE_CODE (TYPE_SIZE_UNIT (srctype)) != INTEGER_CST
+         || TREE_CODE (TYPE_SIZE_UNIT (desttype)) != INTEGER_CST
+         || !tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len)
+         || !tree_int_cst_equal (TYPE_SIZE_UNIT (desttype), len))
        return 0;
 
-      destvar = TREE_OPERAND (destvar, 0);
-      if (TREE_THIS_VOLATILE (destvar))
+      if (get_pointer_alignment (dest, BIGGEST_ALIGNMENT) 
+         < (int) TYPE_ALIGN (desttype)
+         || (get_pointer_alignment (src, BIGGEST_ALIGNMENT) 
+             < (int) TYPE_ALIGN (srctype)))
        return 0;
 
-      if (!INTEGRAL_TYPE_P (TREE_TYPE (destvar))
-         && !POINTER_TYPE_P (TREE_TYPE (destvar))
-         && !SCALAR_FLOAT_TYPE_P (TREE_TYPE (destvar)))
-       return 0;
+      if (!ignore)
+        dest = builtin_save_expr (dest);
 
-      if (! var_decl_component_p (destvar))
+      srcvar = build_fold_indirect_ref (src);
+      if (TREE_THIS_VOLATILE (srcvar))
        return 0;
-
-      srcvar = src;
-      STRIP_NOPS (srcvar);
-      if (TREE_CODE (srcvar) != ADDR_EXPR)
+      if (!tree_int_cst_equal (lang_hooks.expr_size (srcvar), len))
        return 0;
-
-      srcvar = TREE_OPERAND (srcvar, 0);
-      if (TREE_THIS_VOLATILE (srcvar))
+      /* With memcpy, it is possible to bypass aliasing rules, so without
+         this check i. e. execute/20060930-2.c would be misoptimized, because
+        it use conflicting alias set to hold argument for the memcpy call.
+        This check is probably unnecesary with -fno-strict-aliasing. 
+        Similarly for destvar.  See also PR29286.  */
+      if (!var_decl_component_p (srcvar)
+         /* Accept: memcpy (*char_var, "test", 1); that simplify
+            to char_var='t';  */
+         || is_gimple_min_invariant (srcvar)
+         || readonly_data_expr (src))
        return 0;
 
-      if (!INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
-         && !POINTER_TYPE_P (TREE_TYPE (srcvar))
-         && !SCALAR_FLOAT_TYPE_P (TREE_TYPE (srcvar)))
+      destvar = build_fold_indirect_ref (dest);
+      if (TREE_THIS_VOLATILE (destvar))
        return 0;
-
-      if (! var_decl_component_p (srcvar))
+      if (!tree_int_cst_equal (lang_hooks.expr_size (destvar), len))
        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)
+      if (!var_decl_component_p (destvar))
        return 0;
 
-      if ((INTEGRAL_TYPE_P (TREE_TYPE (srcvar))
+      if (srctype == desttype
+         || (gimple_in_ssa_p (cfun)
+             && tree_ssa_useless_type_conversion_1 (desttype, srctype)))
+       expr = srcvar;
+      else 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);
+      expr = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (destvar), destvar, expr);
     }
 
   if (ignore)
@@ -8836,6 +8808,52 @@ fold_builtin_abs (tree arglist, tree type)
   return fold_build1 (ABS_EXPR, type, arg);
 }
 
+/* Fold a call to builtin fmin or fmax.  */
+
+static tree
+fold_builtin_fmin_fmax (tree arglist, tree type, bool max)
+{
+  if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
+    {
+      tree arg0 = TREE_VALUE (arglist);
+      tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      /* Calculate the result when the argument is a constant.  */
+      tree res = do_mpfr_arg2 (arg0, arg1, type, (max ? mpfr_max : mpfr_min));
+
+      if (res)
+       return res;
+
+      /* If either argument is NaN, return the other one.  Avoid the
+        transformation if we get (and honor) a signalling NaN.  Using
+        omit_one_operand() ensures we create a non-lvalue.  */
+      if (TREE_CODE (arg0) == REAL_CST
+         && real_isnan (&TREE_REAL_CST (arg0))
+         && (! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0)))
+             || ! TREE_REAL_CST (arg0).signalling))
+       return omit_one_operand (type, arg1, arg0);
+      if (TREE_CODE (arg1) == REAL_CST
+         && real_isnan (&TREE_REAL_CST (arg1))
+         && (! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1)))
+             || ! TREE_REAL_CST (arg1).signalling))
+       return omit_one_operand (type, arg0, arg1);
+
+      /* Transform fmin/fmax(x,x) -> x.  */
+      if (operand_equal_p (arg0, arg1, OEP_PURE_SAME))
+       return omit_one_operand (type, arg0, arg1);
+      
+      /* Convert fmin/fmax to MIN_EXPR/MAX_EXPR.  C99 requires these
+        functions to return the numeric arg if the other one is NaN.
+        These tree codes don't honor that, so only transform if
+        -ffinite-math-only is set.  C99 doesn't require -0.0 to be
+        handled, so we don't have to worry about it either.  */
+      if (flag_finite_math_only)
+       return fold_build2 ((max ? MAX_EXPR : MIN_EXPR), type,
+                           fold_convert (type, arg0),
+                           fold_convert (type, arg1));
+    }
+  return NULL_TREE;
+}
+
 /* Fold a call to __builtin_isnan(), __builtin_isinf, __builtin_finite.
    EXP is the CALL_EXPR for the call.  */
 
@@ -9184,10 +9202,7 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
     break;
 
     CASE_FLT_FN (BUILT_IN_COSH):
-      if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
-       return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_cosh,
-                            NULL, NULL, 0);
-    break;
+      return fold_builtin_cosh (arglist, type, fndecl);
 
     CASE_FLT_FN (BUILT_IN_TANH):
       if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
@@ -9260,18 +9275,10 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
     break;
 
     CASE_FLT_FN (BUILT_IN_FMIN):
-      if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
-       return do_mpfr_arg2 (TREE_VALUE (arglist),
-                            TREE_VALUE (TREE_CHAIN (arglist)),
-                            type, mpfr_min);
-    break;
+      return fold_builtin_fmin_fmax (arglist, type, /*max=*/false);
 
     CASE_FLT_FN (BUILT_IN_FMAX):
-      if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
-       return do_mpfr_arg2 (TREE_VALUE (arglist),
-                            TREE_VALUE (TREE_CHAIN (arglist)),
-                            type, mpfr_max);
-    break;
+      return fold_builtin_fmin_fmax (arglist, type, /*max=*/true);
 
     CASE_FLT_FN (BUILT_IN_HYPOT):
       return fold_builtin_hypot (fndecl, arglist, type);
@@ -9467,7 +9474,7 @@ fold_builtin (tree fndecl, tree arglist, bool ignore)
   tree exp = fold_builtin_1 (fndecl, arglist, ignore);
   if (exp && !ignore)
     {
-      exp = build1 (NOP_EXPR, TREE_TYPE (exp), exp);
+      exp = build1 (NOP_EXPR, GENERIC_TREE_TYPE (exp), exp);
       TREE_NO_WARNING (exp) = 1;
     }
 
@@ -11492,7 +11499,7 @@ init_target_chars (void)
 
 /* Helper function for do_mpfr_arg*().  Ensure M is a normal number
    and no overflow/underflow occurred.  INEXACT is true if M was not
-   exacly calculated.  TYPE is the tree type for the result.  This
+   exactly calculated.  TYPE is the tree type for the result.  This
    function assumes that you cleared the MPFR flags and then
    calculated M to see if anything subsequently set a flag prior to
    entering this function.  Return NULL_TREE if any checks fail.  */
@@ -11697,9 +11704,11 @@ do_mpfr_sincos (tree arg, tree arg_sinp, tree arg_cosp)
                  && TYPE_MAIN_VARIANT (TREE_TYPE (arg_cosp)) == TYPE_MAIN_VARIANT (type))
                {
                  /* Set the values. */
-                 result_s = fold_build2 (MODIFY_EXPR, type, arg_sinp, result_s);
+                 result_s = fold_build2 (GIMPLE_MODIFY_STMT, type, arg_sinp,
+                                         result_s);
                  TREE_SIDE_EFFECTS (result_s) = 1;
-                 result_c = fold_build2 (MODIFY_EXPR, type, arg_cosp, result_c);
+                 result_c = fold_build2 (GIMPLE_MODIFY_STMT, type, arg_cosp,
+                                         result_c);
                  TREE_SIDE_EFFECTS (result_c) = 1;
                  /* Combine the assignments into a compound expr.  */
                  result = non_lvalue (fold_build2 (COMPOUND_EXPR, type,