OSDN Git Service

IA64 uses // instead of # for comments in its assembly file.
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index b7be275..40327e0 100644 (file)
@@ -26,6 +26,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "machmode.h"
 #include "rtl.h"
 #include "tree.h"
+#include "realmpfr.h"
 #include "gimple.h"
 #include "flags.h"
 #include "regs.h"
@@ -48,7 +49,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-mudflap.h"
 #include "tree-flow.h"
 #include "value-prof.h"
-#include "diagnostic.h"
+#include "diagnostic-core.h"
+#include "builtins.h"
 
 #ifndef SLOW_UNALIGNED_ACCESS
 #define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) STRICT_ALIGNMENT
@@ -59,6 +61,11 @@ along with GCC; see the file COPYING3.  If not see
 #endif
 static tree do_mpc_arg1 (tree, tree, int (*)(mpc_ptr, mpc_srcptr, mpc_rnd_t));
 
+struct target_builtins default_target_builtins;
+#if SWITCHABLE_TARGET
+struct target_builtins *this_target_builtins = &default_target_builtins;
+#endif
+
 /* Define the names of the builtin function types and codes.  */
 const char *const built_in_class_names[4]
   = {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
@@ -1055,7 +1062,7 @@ expand_builtin_prefetch (tree exp)
   if (nargs > 2)
     arg2 = CALL_EXPR_ARG (exp, 2);
   else
-    arg2 = build_int_cst (NULL_TREE, 3);
+    arg2 = integer_three_node;
 
   /* Argument 0 is an address.  */
   op0 = expand_expr (arg0, NULL_RTX, Pmode, EXPAND_NORMAL);
@@ -1248,19 +1255,10 @@ get_memory_rtx (tree exp, tree len)
 \f
 /* Built-in functions to perform an untyped call and return.  */
 
-/* For each register that may be used for calling a function, this
-   gives a mode used to copy the register's value.  VOIDmode indicates
-   the register is not used for calling a function.  If the machine
-   has register windows, this gives only the outbound registers.
-   INCOMING_REGNO gives the corresponding inbound register.  */
-static enum machine_mode apply_args_mode[FIRST_PSEUDO_REGISTER];
-
-/* For each register that may be used for returning values, this gives
-   a mode used to copy the register's value.  VOIDmode indicates the
-   register is not used for returning values.  If the machine has
-   register windows, this gives only the outbound registers.
-   INCOMING_REGNO gives the corresponding inbound register.  */
-static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER];
+#define apply_args_mode \
+  (this_target_builtins->x_apply_args_mode)
+#define apply_result_mode \
+  (this_target_builtins->x_apply_result_mode)
 
 /* Return the size required for the block returned by __builtin_apply_args,
    and initialize apply_args_mode.  */
@@ -1993,7 +1991,7 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
     errno_set = false;
 
   /* Before working hard, check whether the instruction is available.  */
-  if (optab_handler (builtin_optab, mode)->insn_code != CODE_FOR_nothing)
+  if (optab_handler (builtin_optab, mode) != CODE_FOR_nothing)
     {
       target = gen_reg_rtx (mode);
 
@@ -2095,7 +2093,7 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
   mode = TYPE_MODE (TREE_TYPE (exp));
 
   /* Before working hard, check whether the instruction is available.  */
-  if (optab_handler (builtin_optab, mode)->insn_code == CODE_FOR_nothing)
+  if (optab_handler (builtin_optab, mode) == CODE_FOR_nothing)
     return NULL_RTX;
 
   target = gen_reg_rtx (mode);
@@ -2172,7 +2170,7 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
 
   /* Check if sincos insn is available, otherwise fallback
      to sin or cos insn.  */
-  if (optab_handler (builtin_optab, mode)->insn_code == CODE_FOR_nothing)
+  if (optab_handler (builtin_optab, mode) == CODE_FOR_nothing)
     switch (DECL_FUNCTION_CODE (fndecl))
       {
       CASE_FLT_FN (BUILT_IN_SIN):
@@ -2184,7 +2182,7 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
       }
 
   /* Before working hard, check whether the instruction is available.  */
-  if (optab_handler (builtin_optab, mode)->insn_code != CODE_FOR_nothing)
+  if (optab_handler (builtin_optab, mode) != CODE_FOR_nothing)
     {
       target = gen_reg_rtx (mode);
 
@@ -2281,7 +2279,7 @@ interclass_mathfn_icode (tree arg, tree fndecl)
   mode = TYPE_MODE (TREE_TYPE (arg));
 
   if (builtin_optab)
-    return optab_handler (builtin_optab, mode)->insn_code;
+    return optab_handler (builtin_optab, mode);
   return CODE_FOR_nothing;
 }
 
@@ -2369,7 +2367,7 @@ expand_builtin_sincos (tree exp)
   mode = TYPE_MODE (TREE_TYPE (arg));
 
   /* Check if sincos insn is available, otherwise emit the call.  */
-  if (optab_handler (sincos_optab, mode)->insn_code == CODE_FOR_nothing)
+  if (optab_handler (sincos_optab, mode) == CODE_FOR_nothing)
     return NULL_RTX;
 
   target1 = gen_reg_rtx (mode);
@@ -2416,7 +2414,7 @@ expand_builtin_cexpi (tree exp, rtx target, rtx subtarget)
   /* Try expanding via a sincos optab, fall back to emitting a libcall
      to sincos or cexp.  We are sure we have sincos or cexp because cexpi
      is only generated from sincos, cexp or if we have either of them.  */
-  if (optab_handler (sincos_optab, mode)->insn_code != CODE_FOR_nothing)
+  if (optab_handler (sincos_optab, mode) != CODE_FOR_nothing)
     {
       op1 = gen_reg_rtx (mode);
       op2 = gen_reg_rtx (mode);
@@ -2520,8 +2518,6 @@ build_call_nofold_loc (location_t loc, tree fndecl, int n, ...)
   SET_EXPR_LOCATION (fn, loc);
   return fn;
 }
-#define build_call_nofold(...) \
-  build_call_nofold_loc (UNKNOWN_LOCATION, __VA_ARGS__)
 
 /* Expand a call to one of the builtin rounding functions gcc defines
    as an extension (lfloor and lceil).  As these are gcc extensions we
@@ -2639,7 +2635,7 @@ expand_builtin_int_roundingfn (tree exp, rtx target)
       fallback_fndecl = build_fn_decl (name, fntype);
     }
 
-  exp = build_call_nofold (fallback_fndecl, 1, arg);
+  exp = build_call_nofold_loc (EXPR_LOCATION (exp), fallback_fndecl, 1, arg);
 
   tmp = expand_normal (exp);
 
@@ -3081,10 +3077,10 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
                 smaller than pow (x, 1.5) if sqrt will not be expanded
                 as a call.  */
              || (n == 3
-                 && (optab_handler (sqrt_optab, mode)->insn_code
-                     != CODE_FOR_nothing))))
+                 && optab_handler (sqrt_optab, mode) != CODE_FOR_nothing)))
        {
-         tree call_expr = build_call_nofold (fn, 1, narg0);
+         tree call_expr = build_call_nofold_loc (EXPR_LOCATION (exp), fn, 1,
+                                                 narg0);
          /* Use expand_expr in case the newly built call expression
             was folded to a non-call.  */
          op = expand_expr (call_expr, subtarget, mode, EXPAND_NORMAL);
@@ -3136,7 +3132,8 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
               && powi_cost (n/3) <= POWI_MAX_MULTS)
              || n == 1))
        {
-         tree call_expr = build_call_nofold (fn, 1,narg0);
+         tree call_expr = build_call_nofold_loc (EXPR_LOCATION (exp), fn, 1,
+                                                 narg0);
          op = expand_builtin (call_expr, NULL_RTX, subtarget, mode, 0);
          if (abs (n) % 3 == 2)
            op = expand_simple_binop (mode, MULT, op, op, op,
@@ -3271,7 +3268,7 @@ expand_builtin_strlen (tree exp, rtx target,
       /* Bail out if we can't compute strlen in the right mode.  */
       while (insn_mode != VOIDmode)
        {
-         icode = optab_handler (strlen_optab, insn_mode)->insn_code;
+         icode = optab_handler (strlen_optab, insn_mode);
          if (icode != CODE_FOR_nothing)
            break;
 
@@ -3470,7 +3467,8 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len,
   if (target == const0_rtx && implicit_built_in_decls[BUILT_IN_MEMCPY])
     {
       tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
-      tree result = build_call_nofold (fn, 3, dest, src, len);
+      tree result = build_call_nofold_loc (UNKNOWN_LOCATION, fn, 3,
+                                          dest, src, len);
       return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
   else
@@ -3552,13 +3550,14 @@ expand_movstr (tree dest, tree src, rtx target, int endp)
   rtx dest_mem;
   rtx src_mem;
   rtx insn;
-  const struct insn_data * data;
+  const struct insn_data_d * data;
 
   if (!HAVE_movstr)
     return NULL_RTX;
 
   dest_mem = get_memory_rtx (dest, NULL);
   src_mem = get_memory_rtx (src, NULL);
+  data = insn_data + CODE_FOR_movstr;
   if (!endp)
     {
       target = force_reg (Pmode, XEXP (dest_mem, 0));
@@ -3567,18 +3566,18 @@ expand_movstr (tree dest, tree src, rtx target, int endp)
     }
   else
     {
-      if (target == 0 || target == const0_rtx)
+      if (target == 0
+         || target == const0_rtx
+         || ! (*data->operand[0].predicate) (target, Pmode))
        {
          end = gen_reg_rtx (Pmode);
-         if (target == 0)
+         if (target != const0_rtx)
            target = end;
        }
       else
        end = target;
     }
 
-  data = insn_data + CODE_FOR_movstr;
-
   if (data->operand[0].mode != VOIDmode)
     end = gen_lowpart (data->operand[0].mode, end);
 
@@ -3650,7 +3649,7 @@ expand_builtin_stpcpy (tree exp, rtx target, enum machine_mode mode)
   if (target == const0_rtx && implicit_built_in_decls[BUILT_IN_STRCPY])
     {
       tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
-      tree result = build_call_nofold (fn, 2, dst, src);
+      tree result = build_call_nofold_loc (loc, fn, 2, dst, src);
       return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
   else
@@ -3953,9 +3952,11 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
   fndecl = get_callee_fndecl (orig_exp);
   fcode = DECL_FUNCTION_CODE (fndecl);
   if (fcode == BUILT_IN_MEMSET)
-    fn = build_call_nofold (fndecl, 3, dest, val, len);
+    fn = build_call_nofold_loc (EXPR_LOCATION (orig_exp), fndecl, 3,
+                               dest, val, len);
   else if (fcode == BUILT_IN_BZERO)
-    fn = build_call_nofold (fndecl, 2, dest, len);
+    fn = build_call_nofold_loc (EXPR_LOCATION (orig_exp), fndecl, 2,
+                               dest, len);
   else
     gcc_unreachable ();
   gcc_assert (TREE_CODE (fn) == CALL_EXPR);
@@ -4105,8 +4106,8 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
     return NULL_RTX;
 
 #if defined HAVE_cmpstrsi || defined HAVE_cmpstrnsi
-  if (cmpstr_optab[SImode] != CODE_FOR_nothing
-      || cmpstrn_optab[SImode] != CODE_FOR_nothing)
+  if (direct_optab_handler (cmpstr_optab, SImode) != CODE_FOR_nothing
+      || direct_optab_handler (cmpstrn_optab, SImode) != CODE_FOR_nothing)
     {
       rtx arg1_rtx, arg2_rtx;
       rtx result, insn = NULL_RTX;
@@ -4228,7 +4229,7 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
     do_libcall:
 #endif
       fndecl = get_callee_fndecl (exp);
-      fn = build_call_nofold (fndecl, 2, arg1, arg2);
+      fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 2, arg1, arg2);
       gcc_assert (TREE_CODE (fn) == CALL_EXPR);
       CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
       return expand_call (fn, target, target == const0_rtx);
@@ -4350,7 +4351,8 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
     /* Expand the library call ourselves using a stabilized argument
        list to avoid re-evaluating the function's arguments twice.  */
     fndecl = get_callee_fndecl (exp);
-    fn = build_call_nofold (fndecl, 3, arg1, arg2, len);
+    fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 3,
+                               arg1, arg2, len);
     gcc_assert (TREE_CODE (fn) == CALL_EXPR);
     CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
     return expand_call (fn, target, target == const0_rtx);
@@ -4449,7 +4451,10 @@ stabilize_va_list_loc (location_t loc, tree valist, int needs_lvalue)
 {
   tree vatype = targetm.canonical_va_list_type (TREE_TYPE (valist));
 
-  gcc_assert (vatype != NULL_TREE);
+  /* The current way of determining the type of valist is completely
+     bogus.  We should have the information on the va builtin instead.  */
+  if (!vatype)
+    vatype = targetm.fn_abi_va_list (cfun->decl);
 
   if (TREE_CODE (vatype) == ARRAY_TYPE)
     {
@@ -4468,21 +4473,21 @@ stabilize_va_list_loc (location_t loc, tree valist, int needs_lvalue)
     }
   else
     {
-      tree pt;
+      tree pt = build_pointer_type (vatype);
 
       if (! needs_lvalue)
        {
          if (! TREE_SIDE_EFFECTS (valist))
            return valist;
 
-         pt = build_pointer_type (vatype);
          valist = fold_build1_loc (loc, ADDR_EXPR, pt, valist);
          TREE_SIDE_EFFECTS (valist) = 1;
        }
 
       if (TREE_SIDE_EFFECTS (valist))
        valist = save_expr (valist);
-      valist = build_fold_indirect_ref_loc (loc, valist);
+      valist = fold_build2_loc (loc, MEM_REF,
+                               vatype, valist, build_int_cst (pt, 0));
     }
 
   return valist;
@@ -5002,7 +5007,7 @@ expand_builtin_expect (tree exp, rtx target)
   target = expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
   /* When guessing was done, the hints should be already stripped away.  */
   gcc_assert (!flag_guess_branch_prob
-             || optimize == 0 || errorcount || sorrycount);
+             || optimize == 0 || seen_error ());
   return target;
 }
 
@@ -5245,6 +5250,10 @@ expand_builtin_init_trampoline (tree exp)
   targetm.calls.trampoline_init (m_tramp, t_func, r_chain);
 
   trampolines_created = 1;
+
+  warning_at (DECL_SOURCE_LOCATION (t_func), OPT_Wtrampolines,
+              "trampoline generated for nested function %qD", t_func);
+
   return const0_rtx;
 }
 
@@ -5299,7 +5308,7 @@ expand_builtin_signbit (tree exp, rtx target)
 
   /* Check if the back end provides an insn that handles signbit for the
      argument's mode. */
-  icode = signbit_optab->handlers [(int) fmode].insn_code;
+  icode = optab_handler (signbit_optab, fmode);
   if (icode != CODE_FOR_nothing)
     {
       rtx last = get_last_insn ();
@@ -5669,7 +5678,7 @@ expand_builtin_lock_release (enum machine_mode mode, tree exp)
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
 
   /* If there is an explicit operation in the md file, use it.  */
-  icode = sync_lock_release[mode];
+  icode = direct_optab_handler (sync_lock_release_optab, mode);
   if (icode != CODE_FOR_nothing)
     {
       if (!insn_data[icode].operand[1].predicate (val, mode))
@@ -7618,8 +7627,7 @@ fold_builtin_int_roundingfn (location_t loc, tree fndecl, tree arg)
        {
          tree itype = TREE_TYPE (TREE_TYPE (fndecl));
          tree ftype = TREE_TYPE (arg);
-         unsigned HOST_WIDE_INT lo2;
-         HOST_WIDE_INT hi, lo;
+         double_int val;
          REAL_VALUE_TYPE r;
 
          switch (DECL_FUNCTION_CODE (fndecl))
@@ -7643,9 +7651,9 @@ fold_builtin_int_roundingfn (location_t loc, tree fndecl, tree arg)
              gcc_unreachable ();
            }
 
-         REAL_VALUE_TO_INT (&lo, &hi, r);
-         if (!fit_double_type (lo, hi, &lo2, &hi, itype))
-           return build_int_cst_wide (itype, lo2, hi);
+         real_to_integer2 ((HOST_WIDE_INT *)&val.low, &val.high, &r);
+         if (double_int_fits_to_tree_p (itype, val))
+           return double_int_to_tree (itype, val);
        }
     }
 
@@ -8340,6 +8348,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
     {
       tree srctype, desttype;
       int src_align, dest_align;
+      tree off0;
 
       if (endp == 3)
        {
@@ -8365,37 +8374,26 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
            }
 
          /* If *src and *dest can't overlap, optimize into memcpy as well.  */
-         srcvar = build_fold_indirect_ref_loc (loc, src);
-         destvar = build_fold_indirect_ref_loc (loc, dest);
-         if (srcvar
-             && !TREE_THIS_VOLATILE (srcvar)
-             && destvar
-             && !TREE_THIS_VOLATILE (destvar))
+         if (TREE_CODE (src) == ADDR_EXPR
+             && TREE_CODE (dest) == ADDR_EXPR)
            {
              tree src_base, dest_base, fn;
              HOST_WIDE_INT src_offset = 0, dest_offset = 0;
              HOST_WIDE_INT size = -1;
              HOST_WIDE_INT maxsize = -1;
 
-             src_base = srcvar;
-             if (handled_component_p (src_base))
-               src_base = get_ref_base_and_extent (src_base, &src_offset,
-                                                   &size, &maxsize);
-             dest_base = destvar;
-             if (handled_component_p (dest_base))
-               dest_base = get_ref_base_and_extent (dest_base, &dest_offset,
-                                                    &size, &maxsize);
+             srcvar = TREE_OPERAND (src, 0);
+             src_base = get_ref_base_and_extent (srcvar, &src_offset,
+                                                 &size, &maxsize);
+             destvar = TREE_OPERAND (dest, 0);
+             dest_base = get_ref_base_and_extent (destvar, &dest_offset,
+                                                  &size, &maxsize);
              if (host_integerp (len, 1))
-               {
-                 maxsize = tree_low_cst (len, 1);
-                 if (maxsize
-                     > INTTYPE_MAXIMUM (HOST_WIDE_INT) / BITS_PER_UNIT)
-                   maxsize = -1;
-                 else
-                   maxsize *= BITS_PER_UNIT;
-               }
+               maxsize = tree_low_cst (len, 1);
              else
                maxsize = -1;
+             src_offset /= BITS_PER_UNIT;
+             dest_offset /= BITS_PER_UNIT;
              if (SSA_VAR_P (src_base)
                  && SSA_VAR_P (dest_base))
                {
@@ -8404,13 +8402,25 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
                                           dest_offset, maxsize))
                    return NULL_TREE;
                }
-             else if (TREE_CODE (src_base) == INDIRECT_REF
-                      && TREE_CODE (dest_base) == INDIRECT_REF)
+             else if (TREE_CODE (src_base) == MEM_REF
+                      && TREE_CODE (dest_base) == MEM_REF)
                {
+                 double_int off;
                  if (! operand_equal_p (TREE_OPERAND (src_base, 0),
-                                        TREE_OPERAND (dest_base, 0), 0)
-                     || ranges_overlap_p (src_offset, maxsize,
-                                          dest_offset, maxsize))
+                                        TREE_OPERAND (dest_base, 0), 0))
+                   return NULL_TREE;
+                 off = double_int_add (mem_ref_offset (src_base),
+                                       shwi_to_double_int (src_offset));
+                 if (!double_int_fits_in_shwi_p (off))
+                   return NULL_TREE;
+                 src_offset = off.low;
+                 off = double_int_add (mem_ref_offset (dest_base),
+                                       shwi_to_double_int (dest_offset));
+                 if (!double_int_fits_in_shwi_p (off))
+                   return NULL_TREE;
+                 dest_offset = off.low;
+                 if (ranges_overlap_p (src_offset, maxsize,
+                                       dest_offset, maxsize))
                    return NULL_TREE;
                }
              else
@@ -8466,12 +8476,12 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
          dest = build1 (NOP_EXPR, build_pointer_type (desttype), dest);
        }
       if (!srctype || !desttype
+         || TREE_ADDRESSABLE (srctype)
+         || TREE_ADDRESSABLE (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
-         || TYPE_VOLATILE (srctype)
-         || TYPE_VOLATILE (desttype))
+         || TREE_CODE (TYPE_SIZE_UNIT (desttype)) != INTEGER_CST)
        return NULL_TREE;
 
       src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
@@ -8483,97 +8493,44 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
       if (!ignore)
         dest = builtin_save_expr (dest);
 
-      srcvar = NULL_TREE;
-      if (tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len))
-       {
-         srcvar = build_fold_indirect_ref_loc (loc, src);
-         if (TREE_THIS_VOLATILE (srcvar))
-           return NULL_TREE;
-         else if (!tree_int_cst_equal (tree_expr_size (srcvar), len))
-           srcvar = NULL_TREE;
-         /* 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 unnecessary with
-            -fno-strict-aliasing.  Similarly for destvar.  See also
-            PR29286.  */
-         else if (!var_decl_component_p (srcvar))
-           srcvar = NULL_TREE;
-       }
-
-      destvar = NULL_TREE;
-      if (tree_int_cst_equal (TYPE_SIZE_UNIT (desttype), len))
-       {
-         destvar = build_fold_indirect_ref_loc (loc, dest);
-         if (TREE_THIS_VOLATILE (destvar))
-           return NULL_TREE;
-         else if (!tree_int_cst_equal (tree_expr_size (destvar), len))
-           destvar = NULL_TREE;
-         else if (!var_decl_component_p (destvar))
-           destvar = NULL_TREE;
-       }
+      /* Build accesses at offset zero with a ref-all character type.  */
+      off0 = build_int_cst (build_pointer_type_for_mode (char_type_node,
+                                                        ptr_mode, true), 0);
+
+      destvar = dest;
+      STRIP_NOPS (destvar);
+      if (TREE_CODE (destvar) == ADDR_EXPR
+         && var_decl_component_p (TREE_OPERAND (destvar, 0))
+         && tree_int_cst_equal (TYPE_SIZE_UNIT (desttype), len))
+       destvar = fold_build2 (MEM_REF, desttype, destvar, off0);
+      else
+       destvar = NULL_TREE;
+
+      srcvar = src;
+      STRIP_NOPS (srcvar);
+      if (TREE_CODE (srcvar) == ADDR_EXPR
+         && var_decl_component_p (TREE_OPERAND (srcvar, 0))
+         && tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len))
+       srcvar = fold_build2 (MEM_REF, destvar ? desttype : srctype,
+                             srcvar, off0);
+      else
+       srcvar = NULL_TREE;
 
       if (srcvar == NULL_TREE && destvar == NULL_TREE)
        return NULL_TREE;
 
       if (srcvar == NULL_TREE)
        {
-         tree srcptype;
-         if (TREE_ADDRESSABLE (TREE_TYPE (destvar)))
-           return NULL_TREE;
-
-         srctype = build_qualified_type (desttype, 0);
-         if (src_align < (int) TYPE_ALIGN (srctype))
-           {
-             if (AGGREGATE_TYPE_P (srctype)
-                 || SLOW_UNALIGNED_ACCESS (TYPE_MODE (srctype), src_align))
-               return NULL_TREE;
-
-             srctype = build_variant_type_copy (srctype);
-             TYPE_ALIGN (srctype) = src_align;
-             TYPE_USER_ALIGN (srctype) = 1;
-             TYPE_PACKED (srctype) = 1;
-           }
-         srcptype = build_pointer_type_for_mode (srctype, ptr_mode, true);
-         src = fold_convert_loc (loc, srcptype, src);
-         srcvar = build_fold_indirect_ref_loc (loc, src);
+         STRIP_NOPS (src);
+         srcvar = fold_build2 (MEM_REF, desttype, src, off0);
        }
       else if (destvar == NULL_TREE)
        {
-         tree destptype;
-         if (TREE_ADDRESSABLE (TREE_TYPE (srcvar)))
-           return NULL_TREE;
-
-         desttype = build_qualified_type (srctype, 0);
-         if (dest_align < (int) TYPE_ALIGN (desttype))
-           {
-             if (AGGREGATE_TYPE_P (desttype)
-                 || SLOW_UNALIGNED_ACCESS (TYPE_MODE (desttype), dest_align))
-               return NULL_TREE;
+         STRIP_NOPS (dest);
+         destvar = fold_build2 (MEM_REF, srctype, dest, off0);
+       }
 
-             desttype = build_variant_type_copy (desttype);
-             TYPE_ALIGN (desttype) = dest_align;
-             TYPE_USER_ALIGN (desttype) = 1;
-             TYPE_PACKED (desttype) = 1;
-           }
-         destptype = build_pointer_type_for_mode (desttype, ptr_mode, true);
-         dest = fold_convert_loc (loc, destptype, dest);
-         destvar = build_fold_indirect_ref_loc (loc, dest);
-       }
-
-      if (srctype == desttype
-         || (gimple_in_ssa_p (cfun)
-             && useless_type_conversion_p (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_loc (loc, TREE_TYPE (destvar), srcvar);
-      else
-       expr = fold_build1_loc (loc, VIEW_CONVERT_EXPR,
-                           TREE_TYPE (destvar), srcvar);
-      expr = build2 (MODIFY_EXPR, TREE_TYPE (destvar), destvar, expr);
+      expr = build2 (MODIFY_EXPR, TREE_TYPE (destvar), destvar, srcvar);
     }
 
   if (ignore)
@@ -10720,23 +10677,31 @@ fold_call_expr (location_t loc, tree exp, bool ignore)
 }
 
 /* Conveniently construct a function call expression.  FNDECL names the
-    function to be called and ARGLIST is a TREE_LIST of arguments.  */
+   function to be called and N arguments are passed in the array
+   ARGARRAY.  */
 
 tree
-build_function_call_expr (location_t loc, tree fndecl, tree arglist)
+build_call_expr_loc_array (location_t loc, tree fndecl, int n, tree *argarray)
 {
   tree fntype = TREE_TYPE (fndecl);
   tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
-  int n = list_length (arglist);
-  tree *argarray = (tree *) alloca (n * sizeof (tree));
-  int i;
-
-  for (i = 0; i < n; i++, arglist = TREE_CHAIN (arglist))
-    argarray[i] = TREE_VALUE (arglist);
   return fold_builtin_call_array (loc, TREE_TYPE (fntype), fn, n, argarray);
 }
 
 /* Conveniently construct a function call expression.  FNDECL names the
+   function to be called and the arguments are passed in the vector
+   VEC.  */
+
+tree
+build_call_expr_loc_vec (location_t loc, tree fndecl, VEC(tree,gc) *vec)
+{
+  return build_call_expr_loc_array (loc, fndecl, VEC_length (tree, vec),
+                                   VEC_address (tree, vec));
+}
+
+
+/* Conveniently construct a function call expression.  FNDECL names the
    function to be called, N is the number of arguments, and the "..."
    parameters are the argument expressions.  */
 
@@ -10744,16 +10709,31 @@ tree
 build_call_expr_loc (location_t loc, tree fndecl, int n, ...)
 {
   va_list ap;
-  tree fntype = TREE_TYPE (fndecl);
-  tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
-  tree *argarray = (tree *) alloca (n * sizeof (tree));
+  tree *argarray = XALLOCAVEC (tree, n);
   int i;
 
   va_start (ap, n);
   for (i = 0; i < n; i++)
     argarray[i] = va_arg (ap, tree);
   va_end (ap);
-  return fold_builtin_call_array (loc, TREE_TYPE (fntype), fn, n, argarray);
+  return build_call_expr_loc_array (loc, fndecl, n, argarray);
+}
+
+/* Like build_call_expr_loc (UNKNOWN_LOCATION, ...).  Duplicated because
+   varargs macros aren't supported by all bootstrap compilers.  */
+
+tree
+build_call_expr (tree fndecl, int n, ...)
+{
+  va_list ap;
+  tree *argarray = XALLOCAVEC (tree, n);
+  int i;
+
+  va_start (ap, n);
+  for (i = 0; i < n; i++)
+    argarray[i] = va_arg (ap, tree);
+  va_end (ap);
+  return build_call_expr_loc_array (UNKNOWN_LOCATION, fndecl, n, argarray);
 }
 
 /* Construct a CALL_EXPR with type TYPE with FN as the function expression.
@@ -11846,7 +11826,7 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
       if (! fn)
        return NULL_RTX;
 
-      fn = build_call_nofold (fn, 3, dest, src, len);
+      fn = build_call_nofold_loc (EXPR_LOCATION (exp), fn, 3, dest, src, len);
       gcc_assert (TREE_CODE (fn) == CALL_EXPR);
       CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
       return expand_expr (fn, target, mode, EXPAND_NORMAL);
@@ -11894,7 +11874,8 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
              tree fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
              if (!fn)
                return NULL_RTX;
-             fn = build_call_nofold (fn, 4, dest, src, len, size);
+             fn = build_call_nofold_loc (EXPR_LOCATION (exp), fn, 4,
+                                         dest, src, len, size);
              gcc_assert (TREE_CODE (fn) == CALL_EXPR);
              CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
              return expand_expr (fn, target, mode, EXPAND_NORMAL);
@@ -12041,7 +12022,7 @@ maybe_emit_free_warning (tree exp)
     return;
 
   arg = get_base_address (TREE_OPERAND (arg, 0));
-  if (arg == NULL || INDIRECT_REF_P (arg))
+  if (arg == NULL || INDIRECT_REF_P (arg) || TREE_CODE (arg) == MEM_REF)
     return;
 
   if (SSA_VAR_P (arg))
@@ -12058,7 +12039,7 @@ maybe_emit_free_warning (tree exp)
 tree
 fold_builtin_object_size (tree ptr, tree ost)
 {
-  tree ret = NULL_TREE;
+  unsigned HOST_WIDE_INT bytes;
   int object_size_type;
 
   if (!validate_arg (ptr, POINTER_TYPE)
@@ -12081,31 +12062,25 @@ fold_builtin_object_size (tree ptr, tree ost)
     return build_int_cst_type (size_type_node, object_size_type < 2 ? -1 : 0);
 
   if (TREE_CODE (ptr) == ADDR_EXPR)
-    ret = build_int_cstu (size_type_node,
-                         compute_builtin_object_size (ptr, object_size_type));
-
+    {
+      bytes = compute_builtin_object_size (ptr, object_size_type);
+      if (double_int_fits_to_tree_p (size_type_node,
+                                    uhwi_to_double_int (bytes)))
+       return build_int_cstu (size_type_node, bytes);
+    }
   else if (TREE_CODE (ptr) == SSA_NAME)
     {
-      unsigned HOST_WIDE_INT bytes;
-
       /* If object size is not known yet, delay folding until
        later.  Maybe subsequent passes will help determining
        it.  */
       bytes = compute_builtin_object_size (ptr, object_size_type);
-      if (bytes != (unsigned HOST_WIDE_INT) (object_size_type < 2
-                                            ? -1 : 0))
-       ret = build_int_cstu (size_type_node, bytes);
-    }
-
-  if (ret)
-    {
-      unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (ret);
-      HOST_WIDE_INT high = TREE_INT_CST_HIGH (ret);
-      if (fit_double_type (low, high, &low, &high, TREE_TYPE (ret)))
-       ret = NULL_TREE;
+      if (bytes != (unsigned HOST_WIDE_INT) (object_size_type < 2 ? -1 : 0)
+          && double_int_fits_to_tree_p (size_type_node,
+                                       uhwi_to_double_int (bytes)))
+       return build_int_cstu (size_type_node, bytes);
     }
 
-  return ret;
+  return NULL_TREE;
 }
 
 /* Fold a call to the __mem{cpy,pcpy,move,set}_chk builtin.
@@ -13782,3 +13757,123 @@ set_builtin_user_assembler_name (tree decl, const char *asmspec)
       break;
     }
 }
+
+/* Return true if DECL is a builtin that expands to a constant or similarly
+   simple code.  */
+bool
+is_simple_builtin (tree decl)
+{
+  if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
+    switch (DECL_FUNCTION_CODE (decl))
+      {
+       /* Builtins that expand to constants.  */
+      case BUILT_IN_CONSTANT_P:
+      case BUILT_IN_EXPECT:
+      case BUILT_IN_OBJECT_SIZE:
+      case BUILT_IN_UNREACHABLE:
+       /* Simple register moves or loads from stack.  */
+      case BUILT_IN_RETURN_ADDRESS:
+      case BUILT_IN_EXTRACT_RETURN_ADDR:
+      case BUILT_IN_FROB_RETURN_ADDR:
+      case BUILT_IN_RETURN:
+      case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
+      case BUILT_IN_FRAME_ADDRESS:
+      case BUILT_IN_VA_END:
+      case BUILT_IN_STACK_SAVE:
+      case BUILT_IN_STACK_RESTORE:
+       /* Exception state returns or moves registers around.  */
+      case BUILT_IN_EH_FILTER:
+      case BUILT_IN_EH_POINTER:
+      case BUILT_IN_EH_COPY_VALUES:
+       return true;
+
+      default:
+       return false;
+      }
+
+  return false;
+}
+
+/* Return true if DECL is a builtin that is not expensive, i.e., they are
+   most probably expanded inline into reasonably simple code.  This is a
+   superset of is_simple_builtin.  */
+bool
+is_inexpensive_builtin (tree decl)
+{
+  if (!decl)
+    return false;
+  else if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_MD)
+    return true;
+  else if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
+    switch (DECL_FUNCTION_CODE (decl))
+      {
+      case BUILT_IN_ABS:
+      case BUILT_IN_ALLOCA:
+      case BUILT_IN_BSWAP32:
+      case BUILT_IN_BSWAP64:
+      case BUILT_IN_CLZ:
+      case BUILT_IN_CLZIMAX:
+      case BUILT_IN_CLZL:
+      case BUILT_IN_CLZLL:
+      case BUILT_IN_CTZ:
+      case BUILT_IN_CTZIMAX:
+      case BUILT_IN_CTZL:
+      case BUILT_IN_CTZLL:
+      case BUILT_IN_FFS:
+      case BUILT_IN_FFSIMAX:
+      case BUILT_IN_FFSL:
+      case BUILT_IN_FFSLL:
+      case BUILT_IN_IMAXABS:
+      case BUILT_IN_FINITE:
+      case BUILT_IN_FINITEF:
+      case BUILT_IN_FINITEL:
+      case BUILT_IN_FINITED32:
+      case BUILT_IN_FINITED64:
+      case BUILT_IN_FINITED128:
+      case BUILT_IN_FPCLASSIFY:
+      case BUILT_IN_ISFINITE:
+      case BUILT_IN_ISINF_SIGN:
+      case BUILT_IN_ISINF:
+      case BUILT_IN_ISINFF:
+      case BUILT_IN_ISINFL:
+      case BUILT_IN_ISINFD32:
+      case BUILT_IN_ISINFD64:
+      case BUILT_IN_ISINFD128:
+      case BUILT_IN_ISNAN:
+      case BUILT_IN_ISNANF:
+      case BUILT_IN_ISNANL:
+      case BUILT_IN_ISNAND32:
+      case BUILT_IN_ISNAND64:
+      case BUILT_IN_ISNAND128:
+      case BUILT_IN_ISNORMAL:
+      case BUILT_IN_ISGREATER:
+      case BUILT_IN_ISGREATEREQUAL:
+      case BUILT_IN_ISLESS:
+      case BUILT_IN_ISLESSEQUAL:
+      case BUILT_IN_ISLESSGREATER:
+      case BUILT_IN_ISUNORDERED:
+      case BUILT_IN_VA_ARG_PACK:
+      case BUILT_IN_VA_ARG_PACK_LEN:
+      case BUILT_IN_VA_COPY:
+      case BUILT_IN_TRAP:
+      case BUILT_IN_SAVEREGS:
+      case BUILT_IN_POPCOUNTL:
+      case BUILT_IN_POPCOUNTLL:
+      case BUILT_IN_POPCOUNTIMAX:
+      case BUILT_IN_POPCOUNT:
+      case BUILT_IN_PARITYL:
+      case BUILT_IN_PARITYLL:
+      case BUILT_IN_PARITYIMAX:
+      case BUILT_IN_PARITY:
+      case BUILT_IN_LABS:
+      case BUILT_IN_LLABS:
+      case BUILT_IN_PREFETCH:
+       return true;
+
+      default:
+       return is_simple_builtin (decl);
+      }
+
+  return false;
+}
+