OSDN Git Service

* builtins.c (expand_builtin_compare_and_swap): If target is const0,
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index a90bf2f..9dc68cc 100644 (file)
@@ -1,6 +1,6 @@
 /* Expand builtin functions.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -40,7 +40,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "recog.h"
 #include "output.h"
 #include "typeclass.h"
-#include "toplev.h"
 #include "predict.h"
 #include "tm_p.h"
 #include "target.h"
@@ -52,9 +51,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-core.h"
 #include "builtins.h"
 
-#ifndef SLOW_UNALIGNED_ACCESS
-#define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) STRICT_ALIGNMENT
-#endif
 
 #ifndef PAD_VARARGS_DOWN
 #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
@@ -79,11 +75,7 @@ const char * built_in_names[(int) END_BUILTINS] =
 
 /* Setup an array of _DECL trees, make sure each element is
    initialized to NULL_TREE.  */
-tree built_in_decls[(int) END_BUILTINS];
-/* Declarations used when constructing the builtin implicitly in the compiler.
-   It may be NULL_TREE when this is invalid (for instance runtime is not
-   required to implement the function call in all cases).  */
-tree implicit_built_in_decls[(int) END_BUILTINS];
+builtin_info_type builtin_info;
 
 static const char *c_getstr (tree);
 static rtx c_readstr (const char *, enum machine_mode);
@@ -195,6 +187,7 @@ static tree fold_builtin_strncat (location_t, tree, tree, tree);
 static tree fold_builtin_strspn (location_t, tree, tree);
 static tree fold_builtin_strcspn (location_t, tree, tree);
 static tree fold_builtin_sprintf (location_t, tree, tree, tree, int);
+static tree fold_builtin_snprintf (location_t, tree, tree, tree, tree, int);
 
 static rtx expand_builtin_object_size (tree);
 static rtx expand_builtin_memory_chk (tree, rtx, enum machine_mode,
@@ -230,6 +223,7 @@ static tree do_mpfr_bessel_n (tree, tree, tree,
                              const REAL_VALUE_TYPE *, bool);
 static tree do_mpfr_remquo (tree, tree, tree);
 static tree do_mpfr_lgamma_r (tree, tree, tree);
+static void expand_builtin_sync_synchronize (void);
 
 /* Return true if NAME starts with __builtin_ or __sync_.  */
 
@@ -240,6 +234,8 @@ is_builtin_name (const char *name)
     return true;
   if (strncmp (name, "__sync_", 7) == 0)
     return true;
+  if (strncmp (name, "__atomic_", 9) == 0)
+    return true;
   return false;
 }
 
@@ -267,11 +263,18 @@ called_as_built_in (tree node)
   return is_builtin_name (name);
 }
 
-/* Return the alignment in bits of EXP, an object.
-   Don't return more than MAX_ALIGN no matter what.  */
+/* Compute values M and N such that M divides (address of EXP - N) and
+   such that N < M.  Store N in *BITPOSP and return M.
+
+   Note that the address (and thus the alignment) computed here is based
+   on the address to which a symbol resolves, whereas DECL_ALIGN is based
+   on the address at which an object is actually located.  These two
+   addresses are not always the same.  For example, on ARM targets,
+   the address &foo of a Thumb function foo() has the lowest bit set,
+   whereas foo() itself starts on an even address.  */
 
 unsigned int
-get_object_alignment (tree exp, unsigned int max_align)
+get_object_alignment_1 (tree exp, unsigned HOST_WIDE_INT *bitposp)
 {
   HOST_WIDE_INT bitsize, bitpos;
   tree offset;
@@ -290,7 +293,21 @@ get_object_alignment (tree exp, unsigned int max_align)
     exp = DECL_INITIAL (exp);
   if (DECL_P (exp)
       && TREE_CODE (exp) != LABEL_DECL)
-    align = DECL_ALIGN (exp);
+    {
+      if (TREE_CODE (exp) == FUNCTION_DECL)
+       {
+         /* Function addresses can encode extra information besides their
+            alignment.  However, if TARGET_PTRMEMFUNC_VBIT_LOCATION
+            allows the low bit to be used as a virtual bit, we know
+            that the address itself must be 2-byte aligned.  */
+         if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn)
+           align = 2 * BITS_PER_UNIT;
+         else
+           align = BITS_PER_UNIT;
+       }
+      else
+       align = DECL_ALIGN (exp);
+    }
   else if (CONSTANT_CLASS_P (exp))
     {
       align = TYPE_ALIGN (TREE_TYPE (exp));
@@ -323,8 +340,7 @@ get_object_alignment (tree exp, unsigned int max_align)
          align = MAX (pi->align * BITS_PER_UNIT, align);
        }
       else if (TREE_CODE (addr) == ADDR_EXPR)
-       align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0),
-                                                 max_align));
+       align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0)));
       bitpos += mem_ref_offset (exp).low * BITS_PER_UNIT;
     }
   else if (TREE_CODE (exp) == TARGET_MEM_REF)
@@ -348,8 +364,7 @@ get_object_alignment (tree exp, unsigned int max_align)
          align = MAX (pi->align * BITS_PER_UNIT, align);
        }
       else if (TREE_CODE (addr) == ADDR_EXPR)
-       align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0),
-                                                 max_align));
+       align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0)));
       if (TMR_OFFSET (exp))
        bitpos += TREE_INT_CST_LOW (TMR_OFFSET (exp)) * BITS_PER_UNIT;
       if (TMR_INDEX (exp) && TMR_STEP (exp))
@@ -367,7 +382,7 @@ get_object_alignment (tree exp, unsigned int max_align)
 
   /* If there is a non-constant offset part extract the maximum
      alignment that can prevail.  */
-  inner = max_align;
+  inner = ~0U;
   while (offset)
     {
       tree next_offset;
@@ -414,27 +429,30 @@ get_object_alignment (tree exp, unsigned int max_align)
   align = MIN (align, inner);
   bitpos = bitpos & (align - 1);
 
+  *bitposp = bitpos;
+  return align;
+}
+
+/* Return the alignment in bits of EXP, an object.  */
+
+unsigned int
+get_object_alignment (tree exp)
+{
+  unsigned HOST_WIDE_INT bitpos = 0;
+  unsigned int align;
+
+  align = get_object_alignment_1 (exp, &bitpos);
+
   /* align and bitpos now specify known low bits of the pointer.
      ptr & (align - 1) == bitpos.  */
 
   if (bitpos != 0)
     align = (bitpos & -bitpos);
 
-  return MIN (align, max_align);
-}
-
-/* Returns true iff we can trust that alignment information has been
-   calculated properly.  */
-
-bool
-can_trust_pointer_alignment (void)
-{
-  /* We rely on TER to compute accurate alignment information.  */
-  return (optimize && flag_tree_ter);
+  return align;
 }
 
 /* Return the alignment in bits of EXP, a pointer valued expression.
-   But don't return more than MAX_ALIGN no matter what.
    The alignment returned is, by default, the alignment of the thing that
    EXP points to.  If it is not a POINTER_TYPE, 0 is returned.
 
@@ -442,12 +460,12 @@ can_trust_pointer_alignment (void)
    expression is actually pointing at an object whose alignment is tighter.  */
 
 unsigned int
-get_pointer_alignment (tree exp, unsigned int max_align)
+get_pointer_alignment (tree exp)
 {
   STRIP_NOPS (exp);
 
   if (TREE_CODE (exp) == ADDR_EXPR)
-    return get_object_alignment (TREE_OPERAND (exp, 0), max_align);
+    return get_object_alignment (TREE_OPERAND (exp, 0));
   else if (TREE_CODE (exp) == SSA_NAME
           && POINTER_TYPE_P (TREE_TYPE (exp)))
     {
@@ -459,7 +477,7 @@ get_pointer_alignment (tree exp, unsigned int max_align)
        align = (pi->misalign & -pi->misalign);
       else
        align = pi->align;
-      return MIN (max_align, align * BITS_PER_UNIT);
+      return align * BITS_PER_UNIT;
     }
 
   return POINTER_TYPE_P (TREE_TYPE (exp)) ? BITS_PER_UNIT : 0;
@@ -609,7 +627,7 @@ c_readstr (const char *str, enum machine_mode mode)
       if (WORDS_BIG_ENDIAN)
        j = GET_MODE_SIZE (mode) - i - 1;
       if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN
-         && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+         && GET_MODE_SIZE (mode) >= UNITS_PER_WORD)
        j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
       j *= BITS_PER_UNIT;
       gcc_assert (j < 2 * HOST_BITS_PER_WIDE_INT);
@@ -656,9 +674,10 @@ target_char_cast (tree cst, char *p)
 static tree
 builtin_save_expr (tree exp)
 {
-  if (TREE_ADDRESSABLE (exp) == 0
-      && (TREE_CODE (exp) == PARM_DECL
-         || (TREE_CODE (exp) == VAR_DECL && !TREE_STATIC (exp))))
+  if (TREE_CODE (exp) == SSA_NAME
+      || (TREE_ADDRESSABLE (exp) == 0
+         && (TREE_CODE (exp) == PARM_DECL
+             || (TREE_CODE (exp) == VAR_DECL && !TREE_STATIC (exp)))))
     return exp;
 
   return save_expr (exp);
@@ -787,7 +806,7 @@ expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
                            plus_constant (buf_addr,
                                           2 * GET_MODE_SIZE (Pmode)));
   set_mem_alias_set (stack_save, setjmp_alias_set);
-  emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
+  emit_stack_save (SAVE_NONLOCAL, &stack_save);
 
   /* If there is further processing to do, do it.  */
 #ifdef HAVE_builtin_setjmp_setup
@@ -795,10 +814,6 @@ expand_builtin_setjmp_setup (rtx buf_addr, rtx receiver_label)
     emit_insn (gen_builtin_setjmp_setup (buf_addr));
 #endif
 
-  /* Tell optimize_save_area_alloca that extra work is going to
-     need to go on during alloca.  */
-  cfun->calls_setjmp = 1;
-
   /* We have a nonlocal label.   */
   cfun->has_nonlocal_label = 1;
 }
@@ -935,7 +950,7 @@ expand_builtin_longjmp (rtx buf_addr, rtx value)
          emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
 
          emit_move_insn (hard_frame_pointer_rtx, fp);
-         emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
+         emit_stack_restore (SAVE_NONLOCAL, stack);
 
          emit_use (hard_frame_pointer_rtx);
          emit_use (stack_pointer_rtx);
@@ -981,8 +996,8 @@ expand_builtin_nonlocal_goto (tree exp)
   r_label = convert_memory_address (Pmode, r_label);
   r_save_area = expand_normal (t_save_area);
   r_save_area = convert_memory_address (Pmode, r_save_area);
-  /* Copy the address of the save location to a register just in case it was based
-    on the frame pointer.   */
+  /* Copy the address of the save location to a register just in case it was
+     based on the frame pointer.   */
   r_save_area = copy_to_reg (r_save_area);
   r_fp = gen_rtx_MEM (Pmode, r_save_area);
   r_sp = gen_rtx_MEM (STACK_SAVEAREA_MODE (SAVE_NONLOCAL),
@@ -1002,13 +1017,9 @@ expand_builtin_nonlocal_goto (tree exp)
       emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
       emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
 
-      /* Restore frame pointer for containing function.
-        This sets the actual hard register used for the frame pointer
-        to the location of the function's incoming static chain info.
-        The non-local goto handler will then adjust it to contain the
-        proper value and reload the argument pointer, if needed.  */
+      /* Restore frame pointer for containing function.  */
       emit_move_insn (hard_frame_pointer_rtx, r_fp);
-      emit_stack_restore (SAVE_NONLOCAL, r_sp, NULL_RTX);
+      emit_stack_restore (SAVE_NONLOCAL, r_sp);
 
       /* USE of hard_frame_pointer_rtx added for consistency;
         not clear if really needed.  */
@@ -1055,30 +1066,14 @@ expand_builtin_nonlocal_goto (tree exp)
 static void
 expand_builtin_update_setjmp_buf (rtx buf_addr)
 {
-  enum machine_mode sa_mode = Pmode;
-  rtx stack_save;
-
-
-#ifdef HAVE_save_stack_nonlocal
-  if (HAVE_save_stack_nonlocal)
-    sa_mode = insn_data[(int) CODE_FOR_save_stack_nonlocal].operand[0].mode;
-#endif
-#ifdef STACK_SAVEAREA_MODE
-  sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
-#endif
-
-  stack_save
+  enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
+  rtx stack_save
     = gen_rtx_MEM (sa_mode,
                   memory_address
                   (sa_mode,
                    plus_constant (buf_addr, 2 * GET_MODE_SIZE (Pmode))));
 
-#ifdef HAVE_setjmp
-  if (HAVE_setjmp)
-    emit_insn (gen_setjmp ());
-#endif
-
-  emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
+  emit_stack_save (SAVE_NONLOCAL, &stack_save);
 }
 
 /* Expand a call to __builtin_prefetch.  For a target that does not support
@@ -1145,15 +1140,13 @@ expand_builtin_prefetch (tree exp)
 #ifdef HAVE_prefetch
   if (HAVE_prefetch)
     {
-      if ((! (*insn_data[(int) CODE_FOR_prefetch].operand[0].predicate)
-            (op0,
-             insn_data[(int) CODE_FOR_prefetch].operand[0].mode))
-         || (GET_MODE (op0) != Pmode))
-       {
-         op0 = convert_memory_address (Pmode, op0);
-         op0 = force_reg (Pmode, op0);
-       }
-      emit_insn (gen_prefetch (op0, op1, op2));
+      struct expand_operand ops[3];
+
+      create_address_operand (&ops[0], op0);
+      create_integer_operand (&ops[1], INTVAL (op1));
+      create_integer_operand (&ops[2], INTVAL (op2));
+      if (maybe_expand_insn (CODE_FOR_prefetch, 3, ops))
+       return;
     }
 #endif
 
@@ -1232,9 +1225,8 @@ get_memory_rtx (tree exp, tree len)
 
          gcc_assert (TREE_CODE (inner) == COMPONENT_REF);
 
-         if (MEM_OFFSET (mem)
-             && CONST_INT_P (MEM_OFFSET (mem)))
-           offset = INTVAL (MEM_OFFSET (mem));
+         if (MEM_OFFSET_KNOWN_P (mem))
+           offset = MEM_OFFSET (mem);
 
          if (offset >= 0 && len && host_integerp (len, 0))
            length = tree_low_cst (len, 0);
@@ -1289,11 +1281,14 @@ get_memory_rtx (tree exp, tree len)
          if (mem_expr != MEM_EXPR (mem))
            {
              set_mem_expr (mem, mem_expr);
-             set_mem_offset (mem, offset >= 0 ? GEN_INT (offset) : NULL_RTX);
+             if (offset >= 0)
+               set_mem_offset (mem, offset);
+             else
+               clear_mem_offset (mem);
            }
        }
       set_mem_alias_set (mem, 0);
-      set_mem_size (mem, NULL_RTX);
+      clear_mem_size (mem);
     }
 
   return mem;
@@ -1561,10 +1556,10 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
   /* Save the stack with nonlocal if available.  */
 #ifdef HAVE_save_stack_nonlocal
   if (HAVE_save_stack_nonlocal)
-    emit_stack_save (SAVE_NONLOCAL, &old_stack_level, NULL_RTX);
+    emit_stack_save (SAVE_NONLOCAL, &old_stack_level);
   else
 #endif
-    emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
+    emit_stack_save (SAVE_BLOCK, &old_stack_level);
 
   /* Allocate a block of memory onto the stack and copy the memory
      arguments to the outgoing arguments address.  We can pass TRUE
@@ -1680,10 +1675,11 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
   /* Restore the stack.  */
 #ifdef HAVE_save_stack_nonlocal
   if (HAVE_save_stack_nonlocal)
-    emit_stack_restore (SAVE_NONLOCAL, old_stack_level, NULL_RTX);
+    emit_stack_restore (SAVE_NONLOCAL, old_stack_level);
   else
 #endif
-    emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
+    emit_stack_restore (SAVE_BLOCK, old_stack_level);
+  fixup_args_size_notes (call_insn, get_last_insn(), 0);
 
   OK_DEFER_POP;
 
@@ -1794,17 +1790,15 @@ expand_builtin_classify_type (tree exp)
   fcode = BUILT_IN_MATHFN##_R; fcodef = BUILT_IN_MATHFN##F_R ; \
   fcodel = BUILT_IN_MATHFN##L_R ; break;
 
-/* Return mathematic function equivalent to FN but operating directly
-   on TYPE, if available.  If IMPLICIT is true find the function in
-   implicit_built_in_decls[], otherwise use built_in_decls[].  If we
-   can't do the conversion, return zero.  */
+/* Return mathematic function equivalent to FN but operating directly on TYPE,
+   if available.  If IMPLICIT is true use the implicit builtin declaration,
+   otherwise use the explicit declaration.  If we can't do the conversion,
+   return zero.  */
 
 static tree
-mathfn_built_in_1 (tree type, enum built_in_function fn, bool implicit)
+mathfn_built_in_1 (tree type, enum built_in_function fn, bool implicit_p)
 {
-  tree const *const fn_arr
-    = implicit ? implicit_built_in_decls : built_in_decls;
-  enum built_in_function fcode, fcodef, fcodel;
+  enum built_in_function fcode, fcodef, fcodel, fcode2;
 
   switch (fn)
     {
@@ -1841,7 +1835,11 @@ mathfn_built_in_1 (tree type, enum built_in_function fn, bool implicit)
       CASE_MATHFN (BUILT_IN_HUGE_VAL)
       CASE_MATHFN (BUILT_IN_HYPOT)
       CASE_MATHFN (BUILT_IN_ILOGB)
+      CASE_MATHFN (BUILT_IN_ICEIL)
+      CASE_MATHFN (BUILT_IN_IFLOOR)
       CASE_MATHFN (BUILT_IN_INF)
+      CASE_MATHFN (BUILT_IN_IRINT)
+      CASE_MATHFN (BUILT_IN_IROUND)
       CASE_MATHFN (BUILT_IN_ISINF)
       CASE_MATHFN (BUILT_IN_J0)
       CASE_MATHFN (BUILT_IN_J1)
@@ -1897,13 +1895,18 @@ mathfn_built_in_1 (tree type, enum built_in_function fn, bool implicit)
       }
 
   if (TYPE_MAIN_VARIANT (type) == double_type_node)
-    return fn_arr[fcode];
+    fcode2 = fcode;
   else if (TYPE_MAIN_VARIANT (type) == float_type_node)
-    return fn_arr[fcodef];
+    fcode2 = fcodef;
   else if (TYPE_MAIN_VARIANT (type) == long_double_type_node)
-    return fn_arr[fcodel];
+    fcode2 = fcodel;
   else
     return NULL_TREE;
+
+  if (implicit_p && !builtin_decl_implicit_p (fcode2))
+    return NULL_TREE;
+
+  return builtin_decl_explicit (fcode2);
 }
 
 /* Like mathfn_built_in_1(), but always use the implicit array.  */
@@ -2433,16 +2436,9 @@ expand_builtin_interclass_mathfn (tree exp, rtx target)
 
   if (icode != CODE_FOR_nothing)
     {
+      struct expand_operand ops[1];
       rtx last = get_last_insn ();
       tree orig_arg = arg;
-      /* Make a suitable register to place result in.  */
-      if (!target
-         || GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp))
-         || !insn_data[icode].operand[0].predicate (target, GET_MODE (target)))
-         target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
-
-      gcc_assert (insn_data[icode].operand[0].predicate
-                 (target, GET_MODE (target)));
 
       /* Wrap the computation of the argument in a SAVE_EXPR, as we may
         need to expand the argument again.  This way, we will not perform
@@ -2454,10 +2450,11 @@ expand_builtin_interclass_mathfn (tree exp, rtx target)
       if (mode != GET_MODE (op0))
        op0 = convert_to_mode (mode, op0, 0);
 
-      /* Compute into TARGET.
-        Set TARGET to wherever the result comes back.  */
-      if (maybe_emit_unop_insn (icode, target, op0, UNKNOWN))
-       return target;
+      create_output_operand (&ops[0], target, TYPE_MODE (TREE_TYPE (exp)));
+      if (maybe_legitimize_operands (icode, 0, 1, ops)
+         && maybe_emit_unop_insn (icode, ops[0].value, op0, UNKNOWN))
+       return ops[0].value;
+
       delete_insns_since (last);
       CALL_EXPR_ARG (exp, 0) = orig_arg;
     }
@@ -2559,11 +2556,11 @@ expand_builtin_cexpi (tree exp, rtx target)
       rtx op1a, op2a;
 
       if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIF)
-       fn = built_in_decls[BUILT_IN_SINCOSF];
+       fn = builtin_decl_explicit (BUILT_IN_SINCOSF);
       else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPI)
-       fn = built_in_decls[BUILT_IN_SINCOS];
+       fn = builtin_decl_explicit (BUILT_IN_SINCOS);
       else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIL)
-       fn = built_in_decls[BUILT_IN_SINCOSL];
+       fn = builtin_decl_explicit (BUILT_IN_SINCOSL);
       else
        gcc_unreachable ();
 
@@ -2585,11 +2582,11 @@ expand_builtin_cexpi (tree exp, rtx target)
       tree ctype = build_complex_type (type);
 
       if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIF)
-       fn = built_in_decls[BUILT_IN_CEXPF];
+       fn = builtin_decl_explicit (BUILT_IN_CEXPF);
       else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPI)
-       fn = built_in_decls[BUILT_IN_CEXP];
+       fn = builtin_decl_explicit (BUILT_IN_CEXP);
       else if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CEXPIL)
-       fn = built_in_decls[BUILT_IN_CEXPL];
+       fn = builtin_decl_explicit (BUILT_IN_CEXPL);
       else
        gcc_unreachable ();
 
@@ -2672,12 +2669,14 @@ expand_builtin_int_roundingfn (tree exp, rtx target)
 
   switch (DECL_FUNCTION_CODE (fndecl))
     {
+    CASE_FLT_FN (BUILT_IN_ICEIL):
     CASE_FLT_FN (BUILT_IN_LCEIL):
     CASE_FLT_FN (BUILT_IN_LLCEIL):
       builtin_optab = lceil_optab;
       fallback_fn = BUILT_IN_CEIL;
       break;
 
+    CASE_FLT_FN (BUILT_IN_IFLOOR):
     CASE_FLT_FN (BUILT_IN_LFLOOR):
     CASE_FLT_FN (BUILT_IN_LLFLOOR):
       builtin_optab = lfloor_optab;
@@ -2730,26 +2729,32 @@ expand_builtin_int_roundingfn (tree exp, rtx target)
 
       switch (DECL_FUNCTION_CODE (fndecl))
        {
+       case BUILT_IN_ICEIL:
        case BUILT_IN_LCEIL:
        case BUILT_IN_LLCEIL:
          name = "ceil";
          break;
+       case BUILT_IN_ICEILF:
        case BUILT_IN_LCEILF:
        case BUILT_IN_LLCEILF:
          name = "ceilf";
          break;
+       case BUILT_IN_ICEILL:
        case BUILT_IN_LCEILL:
        case BUILT_IN_LLCEILL:
          name = "ceill";
          break;
+       case BUILT_IN_IFLOOR:
        case BUILT_IN_LFLOOR:
        case BUILT_IN_LLFLOOR:
          name = "floor";
          break;
+       case BUILT_IN_IFLOORF:
        case BUILT_IN_LFLOORF:
        case BUILT_IN_LLFLOORF:
          name = "floorf";
          break;
+       case BUILT_IN_IFLOORL:
        case BUILT_IN_LFLOORL:
        case BUILT_IN_LLFLOORL:
          name = "floorl";
@@ -2801,12 +2806,16 @@ expand_builtin_int_roundingfn_2 (tree exp, rtx target)
 
   switch (DECL_FUNCTION_CODE (fndecl))
     {
+    CASE_FLT_FN (BUILT_IN_IRINT):
     CASE_FLT_FN (BUILT_IN_LRINT):
     CASE_FLT_FN (BUILT_IN_LLRINT):
       builtin_optab = lrint_optab; break;
+
+    CASE_FLT_FN (BUILT_IN_IROUND):
     CASE_FLT_FN (BUILT_IN_LROUND):
     CASE_FLT_FN (BUILT_IN_LLROUND):
       builtin_optab = lround_optab; break;
+
     default:
       gcc_unreachable ();
     }
@@ -2844,449 +2853,6 @@ expand_builtin_int_roundingfn_2 (tree exp, rtx target)
   return target;
 }
 
-/* To evaluate powi(x,n), the floating point value x raised to the
-   constant integer exponent n, we use a hybrid algorithm that
-   combines the "window method" with look-up tables.  For an
-   introduction to exponentiation algorithms and "addition chains",
-   see section 4.6.3, "Evaluation of Powers" of Donald E. Knuth,
-   "Seminumerical Algorithms", Vol. 2, "The Art of Computer Programming",
-   3rd Edition, 1998, and Daniel M. Gordon, "A Survey of Fast Exponentiation
-   Methods", Journal of Algorithms, Vol. 27, pp. 129-146, 1998.  */
-
-/* Provide a default value for POWI_MAX_MULTS, the maximum number of
-   multiplications to inline before calling the system library's pow
-   function.  powi(x,n) requires at worst 2*bits(n)-2 multiplications,
-   so this default never requires calling pow, powf or powl.  */
-
-#ifndef POWI_MAX_MULTS
-#define POWI_MAX_MULTS  (2*HOST_BITS_PER_WIDE_INT-2)
-#endif
-
-/* The size of the "optimal power tree" lookup table.  All
-   exponents less than this value are simply looked up in the
-   powi_table below.  This threshold is also used to size the
-   cache of pseudo registers that hold intermediate results.  */
-#define POWI_TABLE_SIZE 256
-
-/* The size, in bits of the window, used in the "window method"
-   exponentiation algorithm.  This is equivalent to a radix of
-   (1<<POWI_WINDOW_SIZE) in the corresponding "m-ary method".  */
-#define POWI_WINDOW_SIZE 3
-
-/* The following table is an efficient representation of an
-   "optimal power tree".  For each value, i, the corresponding
-   value, j, in the table states than an optimal evaluation
-   sequence for calculating pow(x,i) can be found by evaluating
-   pow(x,j)*pow(x,i-j).  An optimal power tree for the first
-   100 integers is given in Knuth's "Seminumerical algorithms".  */
-
-static const unsigned char powi_table[POWI_TABLE_SIZE] =
-  {
-      0,   1,   1,   2,   2,   3,   3,   4,  /*   0 -   7 */
-      4,   6,   5,   6,   6,  10,   7,   9,  /*   8 -  15 */
-      8,  16,   9,  16,  10,  12,  11,  13,  /*  16 -  23 */
-     12,  17,  13,  18,  14,  24,  15,  26,  /*  24 -  31 */
-     16,  17,  17,  19,  18,  33,  19,  26,  /*  32 -  39 */
-     20,  25,  21,  40,  22,  27,  23,  44,  /*  40 -  47 */
-     24,  32,  25,  34,  26,  29,  27,  44,  /*  48 -  55 */
-     28,  31,  29,  34,  30,  60,  31,  36,  /*  56 -  63 */
-     32,  64,  33,  34,  34,  46,  35,  37,  /*  64 -  71 */
-     36,  65,  37,  50,  38,  48,  39,  69,  /*  72 -  79 */
-     40,  49,  41,  43,  42,  51,  43,  58,  /*  80 -  87 */
-     44,  64,  45,  47,  46,  59,  47,  76,  /*  88 -  95 */
-     48,  65,  49,  66,  50,  67,  51,  66,  /*  96 - 103 */
-     52,  70,  53,  74,  54, 104,  55,  74,  /* 104 - 111 */
-     56,  64,  57,  69,  58,  78,  59,  68,  /* 112 - 119 */
-     60,  61,  61,  80,  62,  75,  63,  68,  /* 120 - 127 */
-     64,  65,  65, 128,  66, 129,  67,  90,  /* 128 - 135 */
-     68,  73,  69, 131,  70,  94,  71,  88,  /* 136 - 143 */
-     72, 128,  73,  98,  74, 132,  75, 121,  /* 144 - 151 */
-     76, 102,  77, 124,  78, 132,  79, 106,  /* 152 - 159 */
-     80,  97,  81, 160,  82,  99,  83, 134,  /* 160 - 167 */
-     84,  86,  85,  95,  86, 160,  87, 100,  /* 168 - 175 */
-     88, 113,  89,  98,  90, 107,  91, 122,  /* 176 - 183 */
-     92, 111,  93, 102,  94, 126,  95, 150,  /* 184 - 191 */
-     96, 128,  97, 130,  98, 133,  99, 195,  /* 192 - 199 */
-    100, 128, 101, 123, 102, 164, 103, 138,  /* 200 - 207 */
-    104, 145, 105, 146, 106, 109, 107, 149,  /* 208 - 215 */
-    108, 200, 109, 146, 110, 170, 111, 157,  /* 216 - 223 */
-    112, 128, 113, 130, 114, 182, 115, 132,  /* 224 - 231 */
-    116, 200, 117, 132, 118, 158, 119, 206,  /* 232 - 239 */
-    120, 240, 121, 162, 122, 147, 123, 152,  /* 240 - 247 */
-    124, 166, 125, 214, 126, 138, 127, 153,  /* 248 - 255 */
-  };
-
-
-/* Return the number of multiplications required to calculate
-   powi(x,n) where n is less than POWI_TABLE_SIZE.  This is a
-   subroutine of powi_cost.  CACHE is an array indicating
-   which exponents have already been calculated.  */
-
-static int
-powi_lookup_cost (unsigned HOST_WIDE_INT n, bool *cache)
-{
-  /* If we've already calculated this exponent, then this evaluation
-     doesn't require any additional multiplications.  */
-  if (cache[n])
-    return 0;
-
-  cache[n] = true;
-  return powi_lookup_cost (n - powi_table[n], cache)
-        + powi_lookup_cost (powi_table[n], cache) + 1;
-}
-
-/* Return the number of multiplications required to calculate
-   powi(x,n) for an arbitrary x, given the exponent N.  This
-   function needs to be kept in sync with expand_powi below.  */
-
-static int
-powi_cost (HOST_WIDE_INT n)
-{
-  bool cache[POWI_TABLE_SIZE];
-  unsigned HOST_WIDE_INT digit;
-  unsigned HOST_WIDE_INT val;
-  int result;
-
-  if (n == 0)
-    return 0;
-
-  /* Ignore the reciprocal when calculating the cost.  */
-  val = (n < 0) ? -n : n;
-
-  /* Initialize the exponent cache.  */
-  memset (cache, 0, POWI_TABLE_SIZE * sizeof (bool));
-  cache[1] = true;
-
-  result = 0;
-
-  while (val >= POWI_TABLE_SIZE)
-    {
-      if (val & 1)
-       {
-         digit = val & ((1 << POWI_WINDOW_SIZE) - 1);
-         result += powi_lookup_cost (digit, cache)
-                   + POWI_WINDOW_SIZE + 1;
-         val >>= POWI_WINDOW_SIZE;
-       }
-      else
-       {
-         val >>= 1;
-         result++;
-       }
-    }
-
-  return result + powi_lookup_cost (val, cache);
-}
-
-/* Recursive subroutine of expand_powi.  This function takes the array,
-   CACHE, of already calculated exponents and an exponent N and returns
-   an RTX that corresponds to CACHE[1]**N, as calculated in mode MODE.  */
-
-static rtx
-expand_powi_1 (enum machine_mode mode, unsigned HOST_WIDE_INT n, rtx *cache)
-{
-  unsigned HOST_WIDE_INT digit;
-  rtx target, result;
-  rtx op0, op1;
-
-  if (n < POWI_TABLE_SIZE)
-    {
-      if (cache[n])
-       return cache[n];
-
-      target = gen_reg_rtx (mode);
-      cache[n] = target;
-
-      op0 = expand_powi_1 (mode, n - powi_table[n], cache);
-      op1 = expand_powi_1 (mode, powi_table[n], cache);
-    }
-  else if (n & 1)
-    {
-      target = gen_reg_rtx (mode);
-      digit = n & ((1 << POWI_WINDOW_SIZE) - 1);
-      op0 = expand_powi_1 (mode, n - digit, cache);
-      op1 = expand_powi_1 (mode, digit, cache);
-    }
-  else
-    {
-      target = gen_reg_rtx (mode);
-      op0 = expand_powi_1 (mode, n >> 1, cache);
-      op1 = op0;
-    }
-
-  result = expand_mult (mode, op0, op1, target, 0);
-  if (result != target)
-    emit_move_insn (target, result);
-  return target;
-}
-
-/* Expand the RTL to evaluate powi(x,n) in mode MODE.  X is the
-   floating point operand in mode MODE, and N is the exponent.  This
-   function needs to be kept in sync with powi_cost above.  */
-
-static rtx
-expand_powi (rtx x, enum machine_mode mode, HOST_WIDE_INT n)
-{
-  rtx cache[POWI_TABLE_SIZE];
-  rtx result;
-
-  if (n == 0)
-    return CONST1_RTX (mode);
-
-  memset (cache, 0, sizeof (cache));
-  cache[1] = x;
-
-  result = expand_powi_1 (mode, (n < 0) ? -n : n, cache);
-
-  /* If the original exponent was negative, reciprocate the result.  */
-  if (n < 0)
-    result = expand_binop (mode, sdiv_optab, CONST1_RTX (mode),
-                          result, NULL_RTX, 0, OPTAB_LIB_WIDEN);
-
-  return result;
-}
-
-/* Fold a builtin function call to pow, powf, or powl into a series of sqrts or
-   cbrts.  Return NULL_RTX if no simplification can be made or expand the tree
-   if we can simplify it.  */
-static rtx
-expand_builtin_pow_root (location_t loc, tree arg0, tree arg1, tree type,
-                        rtx subtarget)
-{
-  if (TREE_CODE (arg1) == REAL_CST
-      && !TREE_OVERFLOW (arg1)
-      && flag_unsafe_math_optimizations)
-    {
-      enum machine_mode mode = TYPE_MODE (type);
-      tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
-      tree cbrtfn = mathfn_built_in (type, BUILT_IN_CBRT);
-      REAL_VALUE_TYPE c = TREE_REAL_CST (arg1);
-      tree op = NULL_TREE;
-
-      if (sqrtfn)
-       {
-         /* Optimize pow (x, 0.5) into sqrt.  */
-         if (REAL_VALUES_EQUAL (c, dconsthalf))
-           op = build_call_nofold_loc (loc, sqrtfn, 1, arg0);
-
-         else
-           {
-             REAL_VALUE_TYPE dconst1_4 = dconst1;
-             REAL_VALUE_TYPE dconst3_4;
-             SET_REAL_EXP (&dconst1_4, REAL_EXP (&dconst1_4) - 2);
-
-             real_from_integer (&dconst3_4, VOIDmode, 3, 0, 0);
-             SET_REAL_EXP (&dconst3_4, REAL_EXP (&dconst3_4) - 2);
-
-             /* Optimize pow (x, 0.25) into sqrt (sqrt (x)).  Assume on most
-                machines that a builtin sqrt instruction is smaller than a
-                call to pow with 0.25, so do this optimization even if
-                -Os.  */
-             if (REAL_VALUES_EQUAL (c, dconst1_4))
-               {
-                 op = build_call_nofold_loc (loc, sqrtfn, 1, arg0);
-                 op = build_call_nofold_loc (loc, sqrtfn, 1, op);
-               }
-
-             /* Optimize pow (x, 0.75) = sqrt (x) * sqrt (sqrt (x)) unless we
-                are optimizing for space.  */
-             else if (optimize_insn_for_speed_p ()
-                      && !TREE_SIDE_EFFECTS (arg0)
-                      && REAL_VALUES_EQUAL (c, dconst3_4))
-               {
-                 tree sqrt1 = build_call_expr_loc (loc, sqrtfn, 1, arg0);
-                 tree sqrt2 = builtin_save_expr (sqrt1);
-                 tree sqrt3 = build_call_expr_loc (loc, sqrtfn, 1, sqrt1);
-                 op = fold_build2_loc (loc, MULT_EXPR, type, sqrt2, sqrt3);
-               }
-           }
-       }
-
-      /* Check whether we can do cbrt insstead of pow (x, 1./3.) and
-        cbrt/sqrts instead of pow (x, 1./6.).  */
-      if (cbrtfn && ! op
-         && (tree_expr_nonnegative_p (arg0) || !HONOR_NANS (mode)))
-       {
-         /* First try 1/3.  */
-         REAL_VALUE_TYPE dconst1_3
-           = real_value_truncate (mode, dconst_third ());
-
-         if (REAL_VALUES_EQUAL (c, dconst1_3))
-           op = build_call_nofold_loc (loc, cbrtfn, 1, arg0);
-
-             /* Now try 1/6.  */
-         else if (optimize_insn_for_speed_p ())
-           {
-             REAL_VALUE_TYPE dconst1_6 = dconst1_3;
-             SET_REAL_EXP (&dconst1_6, REAL_EXP (&dconst1_6) - 1);
-
-             if (REAL_VALUES_EQUAL (c, dconst1_6))
-               {
-                 op = build_call_nofold_loc (loc, sqrtfn, 1, arg0);
-                 op = build_call_nofold_loc (loc, cbrtfn, 1, op);
-               }
-           }
-       }
-
-      if (op)
-       return expand_expr (op, subtarget, mode, EXPAND_NORMAL);
-    }
-
-  return NULL_RTX;
-}
-
-/* Expand a call to the pow built-in mathematical function.  Return NULL_RTX if
-   a normal call should be emitted rather than expanding the function
-   in-line.  EXP is the expression that is a call to the builtin
-   function; if convenient, the result should be placed in TARGET.  */
-
-static rtx
-expand_builtin_pow (tree exp, rtx target, rtx subtarget)
-{
-  tree arg0, arg1;
-  tree fn, narg0;
-  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 (exp, REAL_TYPE, REAL_TYPE, VOID_TYPE))
-    return NULL_RTX;
-
-  arg0 = CALL_EXPR_ARG (exp, 0);
-  arg1 = CALL_EXPR_ARG (exp, 1);
-
-  if (TREE_CODE (arg1) != REAL_CST
-      || TREE_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_insn_for_speed_p ()
-             && powi_cost (n) <= POWI_MAX_MULTS)))
-    {
-      op = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
-      if (n != 1)
-       {
-         op = force_reg (mode, op);
-         op = expand_powi (op, mode, n);
-       }
-      return op;
-    }
-
-  narg0 = builtin_save_expr (arg0);
-
-  /* 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 (&c2, &cint)
-         && ((flag_unsafe_math_optimizations
-              && optimize_insn_for_speed_p ()
-              && powi_cost (n/2) <= POWI_MAX_MULTS)
-             /* Even the c == 0.5 case cannot be done unconditionally
-                when we need to preserve signed zeros, as
-                pow (-0, 0.5) is +0, while sqrt(-0) is -0.  */
-             || (!HONOR_SIGNED_ZEROS (mode) && n == 1)
-             /* For c == 1.5 we can assume that x * sqrt (x) is always
-                smaller than pow (x, 1.5) if sqrt will not be expanded
-                as a call.  */
-             || (n == 3
-                 && optab_handler (sqrt_optab, mode) != CODE_FOR_nothing)))
-       {
-         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);
-         if (n != 1)
-           {
-             op2 = expand_expr (narg0, subtarget, VOIDmode, EXPAND_NORMAL);
-             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;
-       }
-    }
-
-  /* Check whether we can do a series of sqrt or cbrt's instead of the pow
-     call.  */
-  op = expand_builtin_pow_root (EXPR_LOCATION (exp), arg0, arg1, type,
-                               subtarget);
-  if (op)
-    return op;
-
-  /* Try if the exponent is a third of an integer.  In this case
-     we can expand to x**(n/3) * cbrt(x)**(n%3).  As cbrt (x) is
-     different from pow (x, 1./3.) due to rounding and behavior
-     with negative x we need to constrain this transformation to
-     unsafe math and positive x or finite math.  */
-  fn = mathfn_built_in (type, BUILT_IN_CBRT);
-  if (fn != NULL_TREE
-      && flag_unsafe_math_optimizations
-      && (tree_expr_nonnegative_p (arg0)
-         || !HONOR_NANS (mode)))
-    {
-      REAL_VALUE_TYPE dconst3;
-      real_from_integer (&dconst3, VOIDmode, 3, 0, 0);
-      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_insn_for_speed_p ()
-              && powi_cost (n/3) <= POWI_MAX_MULTS)
-             || n == 1))
-       {
-         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,
-                                     0, OPTAB_LIB_WIDEN);
-         if (n != 1)
-           {
-             op2 = expand_expr (narg0, subtarget, VOIDmode, EXPAND_NORMAL);
-             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);
-}
-
 /* Expand a call to the powi built-in mathematical function.  Return NULL_RTX if
    a normal call should be emitted rather than expanding the function
    in-line.  EXP is the expression that is a call to the builtin
@@ -3307,27 +2873,6 @@ expand_builtin_powi (tree exp, rtx target)
   arg1 = CALL_EXPR_ARG (exp, 1);
   mode = TYPE_MODE (TREE_TYPE (exp));
 
-  /* Handle constant power.  */
-
-  if (TREE_CODE (arg1) == INTEGER_CST
-      && !TREE_OVERFLOW (arg1))
-    {
-      HOST_WIDE_INT n = TREE_INT_CST_LOW (arg1);
-
-      /* If the exponent is -1, 0, 1 or 2, then expand_powi is exact.
-        Otherwise, check the number of multiplications required.  */
-      if ((TREE_INT_CST_HIGH (arg1) == 0
-          || TREE_INT_CST_HIGH (arg1) == -1)
-         && ((n >= -1 && n <= 2)
-             || (optimize_insn_for_speed_p ()
-                 && powi_cost (n) <= POWI_MAX_MULTS)))
-       {
-         op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
-         op0 = force_reg (mode, op0);
-         return expand_powi (op0, mode, n);
-       }
-    }
-
   /* Emit a libcall to libgcc.  */
 
   /* Mode of the 2nd argument must match that of an int.  */
@@ -3362,11 +2907,12 @@ expand_builtin_strlen (tree exp, rtx target,
     return NULL_RTX;
   else
     {
+      struct expand_operand ops[4];
       rtx pat;
       tree len;
       tree src = CALL_EXPR_ARG (exp, 0);
-      rtx result, src_reg, char_rtx, before_strlen;
-      enum machine_mode insn_mode = target_mode, char_mode;
+      rtx src_reg, before_strlen;
+      enum machine_mode insn_mode = target_mode;
       enum insn_code icode = CODE_FOR_nothing;
       unsigned int align;
 
@@ -3387,7 +2933,7 @@ expand_builtin_strlen (tree exp, rtx target,
          return expand_expr (len, target, target_mode, EXPAND_NORMAL);
        }
 
-      align = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
+      align = get_pointer_alignment (src) / BITS_PER_UNIT;
 
       /* If SRC is not a pointer type, don't do this operation inline.  */
       if (align == 0)
@@ -3405,14 +2951,6 @@ expand_builtin_strlen (tree exp, rtx target,
       if (insn_mode == VOIDmode)
        return NULL_RTX;
 
-      /* Make a place to write the result of the instruction.  */
-      result = target;
-      if (! (result != 0
-            && REG_P (result)
-            && GET_MODE (result) == insn_mode
-            && REGNO (result) >= FIRST_PSEUDO_REGISTER))
-       result = gen_reg_rtx (insn_mode);
-
       /* Make a place to hold the source address.  We will not expand
         the actual source until we are sure that the expansion will
         not fail -- there are trees that cannot be expanded twice.  */
@@ -3422,23 +2960,25 @@ expand_builtin_strlen (tree exp, rtx target,
         source operand later.  */
       before_strlen = get_last_insn ();
 
-      char_rtx = const0_rtx;
-      char_mode = insn_data[(int) icode].operand[2].mode;
-      if (! (*insn_data[(int) icode].operand[2].predicate) (char_rtx,
-                                                           char_mode))
-       char_rtx = copy_to_mode_reg (char_mode, char_rtx);
-
-      pat = GEN_FCN (icode) (result, gen_rtx_MEM (BLKmode, src_reg),
-                            char_rtx, GEN_INT (align));
-      if (! pat)
+      create_output_operand (&ops[0], target, insn_mode);
+      create_fixed_operand (&ops[1], gen_rtx_MEM (BLKmode, src_reg));
+      create_integer_operand (&ops[2], 0);
+      create_integer_operand (&ops[3], align);
+      if (!maybe_expand_insn (icode, 4, ops))
        return NULL_RTX;
-      emit_insn (pat);
 
       /* Now that we are assured of success, expand the source.  */
       start_sequence ();
-      pat = expand_expr (src, src_reg, ptr_mode, EXPAND_NORMAL);
+      pat = expand_expr (src, src_reg, Pmode, EXPAND_NORMAL);
       if (pat != src_reg)
-       emit_move_insn (src_reg, pat);
+       {
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE (pat) != Pmode)
+           pat = convert_to_mode (Pmode, pat,
+                                  POINTERS_EXTEND_UNSIGNED);
+#endif
+         emit_move_insn (src_reg, pat);
+       }
       pat = get_insns ();
       end_sequence ();
 
@@ -3448,12 +2988,12 @@ expand_builtin_strlen (tree exp, rtx target,
        emit_insn_before (pat, get_insns ());
 
       /* Return the value in the proper mode for this function.  */
-      if (GET_MODE (result) == target_mode)
-       target = result;
+      if (GET_MODE (ops[0].value) == target_mode)
+       target = ops[0].value;
       else if (target != 0)
-       convert_move (target, result, 0);
+       convert_move (target, ops[0].value, 0);
       else
-       target = convert_to_mode (target_mode, result, 0);
+       target = convert_to_mode (target_mode, ops[0].value, 0);
 
       return target;
     }
@@ -3493,9 +3033,8 @@ expand_builtin_memcpy (tree exp, rtx target)
       tree src = CALL_EXPR_ARG (exp, 1);
       tree len = CALL_EXPR_ARG (exp, 2);
       const char *src_str;
-      unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
-      unsigned int dest_align
-       = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+      unsigned int src_align = get_pointer_alignment (src);
+      unsigned int dest_align = get_pointer_alignment (dest);
       rtx dest_mem, src_mem, dest_addr, len_rtx;
       HOST_WIDE_INT expected_size = -1;
       unsigned int expected_align = 0;
@@ -3592,9 +3131,9 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len,
                             rtx target, enum machine_mode mode, int endp)
 {
     /* If return value is ignored, transform mempcpy into memcpy.  */
-  if (target == const0_rtx && implicit_built_in_decls[BUILT_IN_MEMCPY])
+  if (target == const0_rtx && builtin_decl_implicit_p (BUILT_IN_MEMCPY))
     {
-      tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+      tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
       tree result = build_call_nofold_loc (UNKNOWN_LOCATION, fn, 3,
                                           dest, src, len);
       return expand_expr (result, target, mode, EXPAND_NORMAL);
@@ -3602,9 +3141,8 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len,
   else
     {
       const char *src_str;
-      unsigned int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
-      unsigned int dest_align
-       = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+      unsigned int src_align = get_pointer_alignment (src);
+      unsigned int dest_align = get_pointer_alignment (dest);
       rtx dest_mem, src_mem, len_rtx;
 
       /* If either SRC or DEST is not a pointer type, don't do this
@@ -3674,56 +3212,38 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len,
 static rtx
 expand_movstr (tree dest, tree src, rtx target, int endp)
 {
-  rtx end;
+  struct expand_operand ops[3];
   rtx dest_mem;
   rtx src_mem;
-  rtx insn;
-  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));
       dest_mem = replace_equiv_address (dest_mem, target);
-      end = gen_reg_rtx (Pmode);
-    }
-  else
-    {
-      if (target == 0
-         || target == const0_rtx
-         || ! (*data->operand[0].predicate) (target, Pmode))
-       {
-         end = gen_reg_rtx (Pmode);
-         if (target != const0_rtx)
-           target = end;
-       }
-      else
-       end = target;
     }
 
-  if (data->operand[0].mode != VOIDmode)
-    end = gen_lowpart (data->operand[0].mode, end);
-
-  insn = data->genfun (end, dest_mem, src_mem);
+  create_output_operand (&ops[0], endp ? target : NULL_RTX, Pmode);
+  create_fixed_operand (&ops[1], dest_mem);
+  create_fixed_operand (&ops[2], src_mem);
+  expand_insn (CODE_FOR_movstr, 3, ops);
 
-  gcc_assert (insn);
-
-  emit_insn (insn);
-
-  /* movstr is supposed to set end to the address of the NUL
-     terminator.  If the caller requested a mempcpy-like return value,
-     adjust it.  */
-  if (endp == 1 && target != const0_rtx)
+  if (endp && target != const0_rtx)
     {
-      rtx tem = plus_constant (gen_lowpart (GET_MODE (target), end), 1);
-      emit_move_insn (target, force_operand (tem, NULL_RTX));
+      target = ops[0].value;
+      /* movstr is supposed to set end to the address of the NUL
+        terminator.  If the caller requested a mempcpy-like return value,
+        adjust it.  */
+      if (endp == 1)
+       {
+         rtx tem = plus_constant (gen_lowpart (GET_MODE (target), target), 1);
+         emit_move_insn (target, force_operand (tem, NULL_RTX));
+       }
     }
-
   return target;
 }
 
@@ -3774,9 +3294,9 @@ expand_builtin_stpcpy (tree exp, rtx target, enum machine_mode mode)
   src = CALL_EXPR_ARG (exp, 1);
 
   /* If return value is ignored, transform stpcpy into strcpy.  */
-  if (target == const0_rtx && implicit_built_in_decls[BUILT_IN_STRCPY])
+  if (target == const0_rtx && builtin_decl_implicit (BUILT_IN_STRCPY))
     {
-      tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+      tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
       tree result = build_call_nofold_loc (loc, fn, 2, dst, src);
       return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
@@ -3875,8 +3395,7 @@ expand_builtin_strncpy (tree exp, rtx target)
         use store_by_pieces, if it fails, punt.  */
       if (tree_int_cst_lt (slen, len))
        {
-         unsigned int dest_align
-           = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+         unsigned int dest_align = get_pointer_alignment (dest);
          const char *p = c_getstr (src);
          rtx dest_mem;
 
@@ -3973,13 +3492,14 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
 {
   tree fndecl, fn;
   enum built_in_function fcode;
+  enum machine_mode val_mode;
   char c;
   unsigned int dest_align;
   rtx dest_mem, dest_addr, len_rtx;
   HOST_WIDE_INT expected_size = -1;
   unsigned int expected_align = 0;
 
-  dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+  dest_align = get_pointer_alignment (dest);
 
   /* If DEST is not a pointer type, don't do this operation in-line.  */
   if (dest_align == 0)
@@ -4007,14 +3527,14 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
 
   len_rtx = expand_normal (len);
   dest_mem = get_memory_rtx (dest, len);
+  val_mode = TYPE_MODE (unsigned_char_type_node);
 
   if (TREE_CODE (val) != INTEGER_CST)
     {
       rtx val_rtx;
 
       val_rtx = expand_normal (val);
-      val_rtx = convert_to_mode (TYPE_MODE (unsigned_char_type_node),
-                                val_rtx, 0);
+      val_rtx = convert_to_mode (val_mode, val_rtx, 0);
 
       /* Assume that we can memset by pieces if we can store
        * the coefficients by pieces (in the required modes).
@@ -4025,8 +3545,7 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
                                  builtin_memset_read_str, &c, dest_align,
                                  true))
        {
-         val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
-                              val_rtx);
+         val_rtx = force_reg (val_mode, val_rtx);
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_memset_gen_str, val_rtx, dest_align,
                           true, 0);
@@ -4052,7 +3571,8 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
                                  true))
        store_by_pieces (dest_mem, tree_low_cst (len, 1),
                         builtin_memset_read_str, &c, dest_align, true, 0);
-      else if (!set_storage_via_setmem (dest_mem, len_rtx, GEN_INT (c),
+      else if (!set_storage_via_setmem (dest_mem, len_rtx,
+                                       gen_int_mode (c, val_mode),
                                        dest_align, expected_align,
                                        expected_size))
        goto do_libcall;
@@ -4113,14 +3633,15 @@ expand_builtin_bzero (tree exp)
      calling bzero instead of memset.  */
 
   return expand_builtin_memset_args (dest, integer_zero_node,
-                                    fold_convert_loc (loc, sizetype, size),
+                                    fold_convert_loc (loc,
+                                                      size_type_node, size),
                                     const0_rtx, VOIDmode, exp);
 }
 
 /* Expand expression EXP, which is a call to the memcmp built-in function.
-   Return NULL_RTX if we failed and 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).  */
+   Return NULL_RTX if we failed and 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).  */
 
 static rtx
 expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target,
@@ -4132,7 +3653,10 @@ expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target,
                         POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return NULL_RTX;
 
-#if defined HAVE_cmpmemsi || defined HAVE_cmpstrnsi
+  /* Note: The cmpstrnsi pattern, if it exists, is not suitable for
+     implementing memcmp because it will stop if it encounters two
+     zero bytes.  */
+#if defined HAVE_cmpmemsi
   {
     rtx arg1_rtx, arg2_rtx, arg3_rtx;
     rtx result;
@@ -4141,22 +3665,13 @@ expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target,
     tree arg2 = CALL_EXPR_ARG (exp, 1);
     tree len = CALL_EXPR_ARG (exp, 2);
 
-    unsigned int arg1_align
-      = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
-    unsigned int arg2_align
-      = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
+    unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
+    unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
     enum machine_mode insn_mode;
 
-#ifdef HAVE_cmpmemsi
     if (HAVE_cmpmemsi)
       insn_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode;
     else
-#endif
-#ifdef HAVE_cmpstrnsi
-    if (HAVE_cmpstrnsi)
-      insn_mode = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
-    else
-#endif
       return NULL_RTX;
 
     /* If we don't have POINTER_TYPE, call the function.  */
@@ -4177,22 +3692,14 @@ expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target,
     /* Set MEM_SIZE as appropriate.  */
     if (CONST_INT_P (arg3_rtx))
       {
-       set_mem_size (arg1_rtx, arg3_rtx);
-       set_mem_size (arg2_rtx, arg3_rtx);
+       set_mem_size (arg1_rtx, INTVAL (arg3_rtx));
+       set_mem_size (arg2_rtx, INTVAL (arg3_rtx));
       }
 
-#ifdef HAVE_cmpmemsi
     if (HAVE_cmpmemsi)
       insn = gen_cmpmemsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
                           GEN_INT (MIN (arg1_align, arg2_align)));
     else
-#endif
-#ifdef HAVE_cmpstrnsi
-    if (HAVE_cmpstrnsi)
-      insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
-                           GEN_INT (MIN (arg1_align, arg2_align)));
-    else
-#endif
       gcc_unreachable ();
 
     if (insn)
@@ -4218,7 +3725,7 @@ expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target,
     else
       return convert_to_mode (mode, result, 0);
   }
-#endif
+#endif /* HAVE_cmpmemsi.  */
 
   return NULL_RTX;
 }
@@ -4243,10 +3750,8 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
       tree arg1 = CALL_EXPR_ARG (exp, 0);
       tree arg2 = CALL_EXPR_ARG (exp, 1);
 
-      unsigned int arg1_align
-       = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
-      unsigned int arg2_align
-       = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
+      unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
+      unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
 
       /* If we don't have POINTER_TYPE, call the function.  */
       if (arg1_align == 0 || arg2_align == 0)
@@ -4394,10 +3899,8 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
     tree arg2 = CALL_EXPR_ARG (exp, 1);
     tree arg3 = CALL_EXPR_ARG (exp, 2);
 
-    unsigned int arg1_align
-      = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
-    unsigned int arg2_align
-      = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
+    unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
+    unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
     enum machine_mode insn_mode
       = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
 
@@ -4722,16 +4225,13 @@ std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
       && !integer_zerop (TYPE_SIZE (type)))
     {
       t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
-                 fold_build2 (POINTER_PLUS_EXPR,
-                              TREE_TYPE (valist),
-                              valist_tmp, size_int (boundary - 1)));
+                 fold_build_pointer_plus_hwi (valist_tmp, boundary - 1));
       gimplify_and_add (t, pre_p);
 
-      t = fold_convert (sizetype, valist_tmp);
       t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
-                 fold_convert (TREE_TYPE (valist),
-                               fold_build2 (BIT_AND_EXPR, sizetype, t,
-                                            size_int (-boundary))));
+                 fold_build2 (BIT_AND_EXPR, TREE_TYPE (valist),
+                              valist_tmp,
+                              build_int_cst (TREE_TYPE (valist), -boundary)));
       gimplify_and_add (t, pre_p);
     }
   else
@@ -4763,12 +4263,11 @@ std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
                       rounded_size, size_int (align));
       t = fold_build3 (COND_EXPR, sizetype, t, size_zero_node,
                       size_binop (MINUS_EXPR, rounded_size, type_size));
-      addr = fold_build2 (POINTER_PLUS_EXPR,
-                         TREE_TYPE (addr), addr, t);
+      addr = fold_build_pointer_plus (addr, t);
     }
 
   /* Compute new value for AP.  */
-  t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (valist), valist_tmp, rounded_size);
+  t = fold_build_pointer_plus (valist_tmp, rounded_size);
   t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
   gimplify_and_add (t, pre_p);
 
@@ -4785,7 +4284,7 @@ std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
 tree
 build_va_arg_indirect_ref (tree addr)
 {
-  addr = build_fold_indirect_ref_loc (EXPR_LOCATION (addr), addr);
+  addr = build_simple_mem_ref_loc (EXPR_LOCATION (addr), addr);
 
   if (flag_mudflap) /* Don't instrument va_arg INDIRECT_REF.  */
     mf_mark (addr);
@@ -4856,7 +4355,7 @@ gimplify_va_arg_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
         expression to exit or longjmp.  */
       gimplify_and_add (valist, pre_p);
       t = build_call_expr_loc (loc,
-                              implicit_built_in_decls[BUILT_IN_TRAP], 0);
+                              builtin_decl_implicit (BUILT_IN_TRAP), 0);
       gimplify_and_add (t, pre_p);
 
       /* This is dead code, but go ahead and finish so that the
@@ -5019,20 +4518,33 @@ expand_builtin_alloca (tree exp, bool cannot_accumulate)
 {
   rtx op0;
   rtx result;
+  bool valid_arglist;
+  unsigned int align;
+  bool alloca_with_align = (DECL_FUNCTION_CODE (get_callee_fndecl (exp))
+                           == BUILT_IN_ALLOCA_WITH_ALIGN);
 
   /* Emit normal call if marked not-inlineable.  */
   if (CALL_CANNOT_INLINE_P (exp))
     return NULL_RTX;
 
-  if (!validate_arglist (exp, INTEGER_TYPE, VOID_TYPE))
+  valid_arglist
+    = (alloca_with_align
+       ? validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)
+       : validate_arglist (exp, INTEGER_TYPE, VOID_TYPE));
+
+  if (!valid_arglist)
     return NULL_RTX;
 
   /* Compute the argument.  */
   op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
 
+  /* Compute the alignment.  */
+  align = (alloca_with_align
+          ? TREE_INT_CST_LOW (CALL_EXPR_ARG (exp, 1))
+          : BIGGEST_ALIGNMENT);
+
   /* Allocate the desired space.  */
-  result = allocate_dynamic_stack_space (op0, 0, BIGGEST_ALIGNMENT,
-                                        cannot_accumulate);
+  result = allocate_dynamic_stack_space (op0, 0, align, cannot_accumulate);
   result = convert_memory_address (ptr_mode, result);
 
   return result;
@@ -5085,7 +4597,7 @@ expand_builtin_unop (enum machine_mode target_mode, tree exp, rtx target,
   /* Compute op, into TARGET if possible.
      Set TARGET to wherever the result comes back.  */
   target = expand_unop (TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 0))),
-                       op_optab, op0, target, 1);
+                       op_optab, op0, target, op_optab != clrsb_optab);
   gcc_assert (target);
 
   return convert_to_mode (target_mode, target, 0);
@@ -5111,6 +4623,23 @@ expand_builtin_expect (tree exp, rtx target)
   return target;
 }
 
+/* Expand a call to __builtin_assume_aligned.  We just return our first
+   argument as the builtin_assume_aligned semantic should've been already
+   executed by CCP.  */
+
+static rtx
+expand_builtin_assume_aligned (tree exp, rtx target)
+{
+  if (call_expr_nargs (exp) < 2)
+    return const0_rtx;
+  target = expand_expr (CALL_EXPR_ARG (exp, 0), target, VOIDmode,
+                       EXPAND_NORMAL);
+  gcc_assert (!TREE_SIDE_EFFECTS (CALL_EXPR_ARG (exp, 1))
+             && (call_expr_nargs (exp) < 3
+                 || !TREE_SIDE_EFFECTS (CALL_EXPR_ARG (exp, 2))));
+  return target;
+}
+
 void
 expand_builtin_trap (void)
 {
@@ -5203,30 +4732,6 @@ build_string_literal (int len, const char *str)
   return t;
 }
 
-/* Expand a call to either the entry or exit function profiler.  */
-
-static rtx
-expand_builtin_profile_func (bool exitp)
-{
-  rtx this_rtx, which;
-
-  this_rtx = DECL_RTL (current_function_decl);
-  gcc_assert (MEM_P (this_rtx));
-  this_rtx = XEXP (this_rtx, 0);
-
-  if (exitp)
-    which = profile_function_exit_libfunc;
-  else
-    which = profile_function_entry_libfunc;
-
-  emit_library_call (which, LCT_NORMAL, VOIDmode, 2, this_rtx, Pmode,
-                    expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
-                                                0),
-                    Pmode);
-
-  return const0_rtx;
-}
-
 /* Expand a call to __builtin___clear_cache.  */
 
 static rtx
@@ -5247,7 +4752,6 @@ expand_builtin___clear_cache (tree exp ATTRIBUTE_UNUSED)
   /* We have a "clear_cache" insn, and it will handle everything.  */
   tree begin, end;
   rtx begin_rtx, end_rtx;
-  enum insn_code icode;
 
   /* We must not expand to a library call.  If we did, any
      fallback library function in libgcc that might contain a call to
@@ -5260,21 +4764,18 @@ expand_builtin___clear_cache (tree exp ATTRIBUTE_UNUSED)
 
   if (HAVE_clear_cache)
     {
-      icode = CODE_FOR_clear_cache;
+      struct expand_operand ops[2];
 
       begin = CALL_EXPR_ARG (exp, 0);
       begin_rtx = expand_expr (begin, NULL_RTX, Pmode, EXPAND_NORMAL);
-      begin_rtx = convert_memory_address (Pmode, begin_rtx);
-      if (!insn_data[icode].operand[0].predicate (begin_rtx, Pmode))
-       begin_rtx = copy_to_mode_reg (Pmode, begin_rtx);
 
       end = CALL_EXPR_ARG (exp, 1);
       end_rtx = expand_expr (end, NULL_RTX, Pmode, EXPAND_NORMAL);
-      end_rtx = convert_memory_address (Pmode, end_rtx);
-      if (!insn_data[icode].operand[1].predicate (end_rtx, Pmode))
-       end_rtx = copy_to_mode_reg (Pmode, end_rtx);
 
-      emit_insn (gen_clear_cache (begin_rtx, end_rtx));
+      create_address_operand (&ops[0], begin_rtx);
+      create_address_operand (&ops[1], end_rtx);
+      if (maybe_expand_insn (CODE_FOR_clear_cache, 2, ops))
+       return const0_rtx;
     }
   return const0_rtx;
 #endif /* HAVE_clear_cache */
@@ -5335,7 +4836,7 @@ expand_builtin_init_trampoline (tree exp)
     {
       m_tramp = change_address (m_tramp, BLKmode, tmp);
       set_mem_align (m_tramp, TRAMPOLINE_ALIGNMENT);
-      set_mem_size (m_tramp, GEN_INT (TRAMPOLINE_SIZE));
+      set_mem_size (m_tramp, TRAMPOLINE_SIZE);
     }
 
   /* The FUNC argument should be the address of the nested function.
@@ -5475,8 +4976,7 @@ expand_builtin_signbit (tree exp, rtx target)
       /* Perform a logical right shift to place the signbit in the least
         significant bit, then truncate the result to the desired mode
         and mask just this bit.  */
-      temp = expand_shift (RSHIFT_EXPR, imode, temp,
-                          build_int_cst (NULL_TREE, bitpos), NULL_RTX, 1);
+      temp = expand_shift (RSHIFT_EXPR, imode, temp, bitpos, NULL_RTX, 1);
       temp = gen_lowpart (rmode, temp);
       temp = expand_binop (rmode, and_optab, temp, const1_rtx,
                           NULL_RTX, 1, OPTAB_LIB_WIDEN);
@@ -5586,28 +5086,48 @@ get_builtin_sync_mem (tree loc, enum machine_mode mode)
 
   /* The alignment needs to be at least according to that of the mode.  */
   set_mem_align (mem, MAX (GET_MODE_ALIGNMENT (mode),
-                          get_pointer_alignment (loc, BIGGEST_ALIGNMENT)));
+                          get_pointer_alignment (loc)));
   set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER);
   MEM_VOLATILE_P (mem) = 1;
 
   return mem;
 }
 
+/* Make sure an argument is in the right mode.
+   EXP is the tree argument. 
+   MODE is the mode it should be in.  */
+
+static rtx
+expand_expr_force_mode (tree exp, enum machine_mode mode)
+{
+  rtx val;
+  enum machine_mode old_mode;
+
+  val = expand_expr (exp, NULL_RTX, mode, EXPAND_NORMAL);
+  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
+     of CONST_INTs, where we know the old_mode only from the call argument.  */
+
+  old_mode = GET_MODE (val);
+  if (old_mode == VOIDmode)
+    old_mode = TYPE_MODE (TREE_TYPE (exp));
+  val = convert_modes (mode, old_mode, val, 1);
+  return val;
+}
+
+
 /* Expand the __sync_xxx_and_fetch and __sync_fetch_and_xxx intrinsics.
    EXP is the CALL_EXPR.  CODE is the rtx code
    that corresponds to the arithmetic or logical operation from the name;
    an exception here is that NOT actually means NAND.  TARGET is an optional
    place for us to store the results; AFTER is true if this is the
-   fetch_and_xxx form.  IGNORE is true if we don't actually care about
-   the result of the operation at all.  */
+   fetch_and_xxx form.  */
 
 static rtx
 expand_builtin_sync_operation (enum machine_mode mode, tree exp,
                               enum rtx_code code, bool after,
-                              rtx target, bool ignore)
+                              rtx target)
 {
   rtx val, mem;
-  enum machine_mode old_mode;
   location_t loc = EXPR_LOCATION (exp);
 
   if (code == NOT && warn_sync_nand)
@@ -5619,30 +5139,28 @@ expand_builtin_sync_operation (enum machine_mode mode, tree exp,
 
       switch (fcode)
        {
-       case BUILT_IN_FETCH_AND_NAND_1:
-       case BUILT_IN_FETCH_AND_NAND_2:
-       case BUILT_IN_FETCH_AND_NAND_4:
-       case BUILT_IN_FETCH_AND_NAND_8:
-       case BUILT_IN_FETCH_AND_NAND_16:
-
+       case BUILT_IN_SYNC_FETCH_AND_NAND_1:
+       case BUILT_IN_SYNC_FETCH_AND_NAND_2:
+       case BUILT_IN_SYNC_FETCH_AND_NAND_4:
+       case BUILT_IN_SYNC_FETCH_AND_NAND_8:
+       case BUILT_IN_SYNC_FETCH_AND_NAND_16:
          if (warned_f_a_n)
            break;
 
-         fndecl = implicit_built_in_decls[BUILT_IN_FETCH_AND_NAND_N];
+         fndecl = builtin_decl_implicit (BUILT_IN_SYNC_FETCH_AND_NAND_N);
          inform (loc, "%qD changed semantics in GCC 4.4", fndecl);
          warned_f_a_n = true;
          break;
 
-       case BUILT_IN_NAND_AND_FETCH_1:
-       case BUILT_IN_NAND_AND_FETCH_2:
-       case BUILT_IN_NAND_AND_FETCH_4:
-       case BUILT_IN_NAND_AND_FETCH_8:
-       case BUILT_IN_NAND_AND_FETCH_16:
-
+       case BUILT_IN_SYNC_NAND_AND_FETCH_1:
+       case BUILT_IN_SYNC_NAND_AND_FETCH_2:
+       case BUILT_IN_SYNC_NAND_AND_FETCH_4:
+       case BUILT_IN_SYNC_NAND_AND_FETCH_8:
+       case BUILT_IN_SYNC_NAND_AND_FETCH_16:
          if (warned_n_a_f)
            break;
 
-         fndecl = implicit_built_in_decls[BUILT_IN_NAND_AND_FETCH_N];
+        fndecl = builtin_decl_implicit (BUILT_IN_SYNC_NAND_AND_FETCH_N);
          inform (loc, "%qD changed semantics in GCC 4.4", fndecl);
          warned_n_a_f = true;
          break;
@@ -5654,19 +5172,10 @@ expand_builtin_sync_operation (enum machine_mode mode, tree exp,
 
   /* Expand the operands.  */
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
+  val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
 
-  val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL_RTX, mode, EXPAND_NORMAL);
-  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
-     of CONST_INTs, where we know the old_mode only from the call argument.  */
-  old_mode = GET_MODE (val);
-  if (old_mode == VOIDmode)
-    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1)));
-  val = convert_modes (mode, old_mode, val, 1);
-
-  if (ignore)
-    return expand_sync_operation (mem, val, code);
-  else
-    return expand_sync_fetch_operation (mem, val, code, after, target);
+  return expand_atomic_fetch_op (target, mem, val, code, MEMMODEL_SEQ_CST,
+                                after);
 }
 
 /* Expand the __sync_val_compare_and_swap and __sync_bool_compare_and_swap
@@ -5679,66 +5188,573 @@ expand_builtin_compare_and_swap (enum machine_mode mode, tree exp,
                                 bool is_bool, rtx target)
 {
   rtx old_val, new_val, mem;
-  enum machine_mode old_mode;
+  rtx *pbool, *poval;
 
   /* Expand the operands.  */
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
+  old_val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
+  new_val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 2), mode);
 
+  pbool = poval = NULL;
+  if (target != const0_rtx)
+    {
+      if (is_bool)
+       pbool = &target;
+      else
+       poval = &target;
+    }
+  if (!expand_atomic_compare_and_swap (pbool, poval, mem, old_val, new_val,
+                                      false, MEMMODEL_SEQ_CST,
+                                      MEMMODEL_SEQ_CST))
+    return NULL_RTX;
 
-  old_val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL_RTX,
-                        mode, EXPAND_NORMAL);
-  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
-     of CONST_INTs, where we know the old_mode only from the call argument.  */
-  old_mode = GET_MODE (old_val);
-  if (old_mode == VOIDmode)
-    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1)));
-  old_val = convert_modes (mode, old_mode, old_val, 1);
+  return target;
+}
 
-  new_val = expand_expr (CALL_EXPR_ARG (exp, 2), NULL_RTX,
-                        mode, EXPAND_NORMAL);
-  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
-     of CONST_INTs, where we know the old_mode only from the call argument.  */
-  old_mode = GET_MODE (new_val);
-  if (old_mode == VOIDmode)
-    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 2)));
-  new_val = convert_modes (mode, old_mode, new_val, 1);
+/* Expand the __sync_lock_test_and_set intrinsic.  Note that the most
+   general form is actually an atomic exchange, and some targets only
+   support a reduced form with the second argument being a constant 1.
+   EXP is the CALL_EXPR; TARGET is an optional place for us to store
+   the results.  */
+
+static rtx
+expand_builtin_sync_lock_test_and_set (enum machine_mode mode, tree exp,
+                                      rtx target)
+{
+  rtx val, mem;
+
+  /* Expand the operands.  */
+  mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
+  val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
+
+  return expand_atomic_exchange (target, mem, val, MEMMODEL_ACQUIRE, true);
+}
+
+/* Expand the __sync_lock_release intrinsic.  EXP is the CALL_EXPR.  */
+
+static void
+expand_builtin_sync_lock_release (enum machine_mode mode, tree exp)
+{
+  rtx mem;
+
+  /* Expand the operands.  */
+  mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
+
+  expand_atomic_store (mem, const0_rtx, MEMMODEL_RELEASE, true);
+}
+
+/* Given an integer representing an ``enum memmodel'', verify its
+   correctness and return the memory model enum.  */
+
+static enum memmodel
+get_memmodel (tree exp)
+{
+  rtx op;
+
+  /* If the parameter is not a constant, it's a run time value so we'll just
+     convert it to MEMMODEL_SEQ_CST to avoid annoying runtime checking.  */
+  if (TREE_CODE (exp) != INTEGER_CST)
+    return MEMMODEL_SEQ_CST;
+
+  op = expand_normal (exp);
+  if (INTVAL (op) < 0 || INTVAL (op) >= MEMMODEL_LAST)
+    {
+      warning (OPT_Winvalid_memory_model,
+              "invalid memory model argument to builtin");
+      return MEMMODEL_SEQ_CST;
+    }
+  return (enum memmodel) INTVAL (op);
+}
+
+/* Expand the __atomic_exchange intrinsic:
+       TYPE __atomic_exchange (TYPE *object, TYPE desired, enum memmodel)
+   EXP is the CALL_EXPR.
+   TARGET is an optional place for us to store the results.  */
+
+static rtx
+expand_builtin_atomic_exchange (enum machine_mode mode, tree exp, rtx target)
+{
+  rtx val, mem;
+  enum memmodel model;
+
+  model = get_memmodel (CALL_EXPR_ARG (exp, 2));
+  if (model == MEMMODEL_CONSUME)
+    {
+      error ("invalid memory model for %<__atomic_exchange%>");
+      return NULL_RTX;
+    }
+
+  if (!flag_inline_atomics)
+    return NULL_RTX;
+
+  /* Expand the operands.  */
+  mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
+  val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
+
+  return expand_atomic_exchange (target, mem, val, model, false);
+}
+
+/* Expand the __atomic_compare_exchange intrinsic:
+       bool __atomic_compare_exchange (TYPE *object, TYPE *expect, 
+                                       TYPE desired, BOOL weak, 
+                                       enum memmodel success,
+                                       enum memmodel failure)
+   EXP is the CALL_EXPR.
+   TARGET is an optional place for us to store the results.  */
+
+static rtx
+expand_builtin_atomic_compare_exchange (enum machine_mode mode, tree exp, 
+                                       rtx target)
+{
+  rtx expect, desired, mem, oldval;
+  enum memmodel success, failure;
+  tree weak;
+  bool is_weak;
+
+  success = get_memmodel (CALL_EXPR_ARG (exp, 4));
+  failure = get_memmodel (CALL_EXPR_ARG (exp, 5));
+
+  if (failure == MEMMODEL_RELEASE || failure == MEMMODEL_ACQ_REL)
+    {
+      error ("invalid failure memory model for %<__atomic_compare_exchange%>");
+      return NULL_RTX;
+    }
+
+  if (failure > success)
+    {
+      error ("failure memory model cannot be stronger than success "
+            "memory model for %<__atomic_compare_exchange%>");
+      return NULL_RTX;
+    }
+  
+  if (!flag_inline_atomics)
+    return NULL_RTX;
+
+  /* Expand the operands.  */
+  mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
+
+  expect = expand_normal (CALL_EXPR_ARG (exp, 1));
+  expect = convert_memory_address (Pmode, expect);
+  desired = expand_expr_force_mode (CALL_EXPR_ARG (exp, 2), mode);
+
+  weak = CALL_EXPR_ARG (exp, 3);
+  is_weak = false;
+  if (host_integerp (weak, 0) && tree_low_cst (weak, 0) != 0)
+    is_weak = true;
+
+  oldval = copy_to_reg (gen_rtx_MEM (mode, expect));
+
+  if (!expand_atomic_compare_and_swap ((target == const0_rtx ? NULL : &target),
+                                      &oldval, mem, oldval, desired,
+                                      is_weak, success, failure))
+    return NULL_RTX;
+
+  emit_move_insn (gen_rtx_MEM (mode, expect), oldval);
+  return target;
+}
+
+/* Expand the __atomic_load intrinsic:
+       TYPE __atomic_load (TYPE *object, enum memmodel)
+   EXP is the CALL_EXPR.
+   TARGET is an optional place for us to store the results.  */
+
+static rtx
+expand_builtin_atomic_load (enum machine_mode mode, tree exp, rtx target)
+{
+  rtx mem;
+  enum memmodel model;
+
+  model = get_memmodel (CALL_EXPR_ARG (exp, 1));
+  if (model == MEMMODEL_RELEASE
+      || model == MEMMODEL_ACQ_REL)
+    {
+      error ("invalid memory model for %<__atomic_load%>");
+      return NULL_RTX;
+    }
+
+  if (!flag_inline_atomics)
+    return NULL_RTX;
+
+  /* Expand the operand.  */
+  mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
+
+  return expand_atomic_load (target, mem, model);
+}
+
+
+/* Expand the __atomic_store intrinsic:
+       void __atomic_store (TYPE *object, TYPE desired, enum memmodel)
+   EXP is the CALL_EXPR.
+   TARGET is an optional place for us to store the results.  */
+
+static rtx
+expand_builtin_atomic_store (enum machine_mode mode, tree exp)
+{
+  rtx mem, val;
+  enum memmodel model;
+
+  model = get_memmodel (CALL_EXPR_ARG (exp, 2));
+  if (model != MEMMODEL_RELAXED
+      && model != MEMMODEL_SEQ_CST
+      && model != MEMMODEL_RELEASE)
+    {
+      error ("invalid memory model for %<__atomic_store%>");
+      return NULL_RTX;
+    }
+
+  if (!flag_inline_atomics)
+    return NULL_RTX;
+
+  /* Expand the operands.  */
+  mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
+  val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
+
+  return expand_atomic_store (mem, val, model, false);
+}
+
+/* Expand the __atomic_fetch_XXX intrinsic:
+       TYPE __atomic_fetch_XXX (TYPE *object, TYPE val, enum memmodel)
+   EXP is the CALL_EXPR.
+   TARGET is an optional place for us to store the results.
+   CODE is the operation, PLUS, MINUS, ADD, XOR, or IOR.
+   FETCH_AFTER is true if returning the result of the operation.
+   FETCH_AFTER is false if returning the value before the operation.
+   IGNORE is true if the result is not used.
+   EXT_CALL is the correct builtin for an external call if this cannot be
+   resolved to an instruction sequence.  */
+
+static rtx
+expand_builtin_atomic_fetch_op (enum machine_mode mode, tree exp, rtx target,
+                               enum rtx_code code, bool fetch_after,
+                               bool ignore, enum built_in_function ext_call)
+{
+  rtx val, mem, ret;
+  enum memmodel model;
+  tree fndecl;
+  tree addr;
+
+  model = get_memmodel (CALL_EXPR_ARG (exp, 2));
+
+  /* Expand the operands.  */
+  mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
+  val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
+
+  /* Only try generating instructions if inlining is turned on.  */
+  if (flag_inline_atomics)
+    {
+      ret = expand_atomic_fetch_op (target, mem, val, code, model, fetch_after);
+      if (ret)
+       return ret;
+    }
+
+  /* Return if a different routine isn't needed for the library call.  */
+  if (ext_call == BUILT_IN_NONE)
+    return NULL_RTX;
+
+  /* Change the call to the specified function.  */
+  fndecl = get_callee_fndecl (exp);
+  addr = CALL_EXPR_FN (exp);
+  STRIP_NOPS (addr);
+
+  gcc_assert (TREE_OPERAND (addr, 0) == fndecl);
+  TREE_OPERAND (addr, 0) = builtin_decl_explicit(ext_call);
+
+  /* Expand the call here so we can emit trailing code.  */
+  ret = expand_call (exp, target, ignore);
+
+  /* Replace the original function just in case it matters.  */
+  TREE_OPERAND (addr, 0) = fndecl;
+
+  /* Then issue the arithmetic correction to return the right result.  */
+  if (!ignore)
+    {
+      if (code == NOT)
+       {
+         ret = expand_simple_binop (mode, AND, ret, val, NULL_RTX, true,
+                                    OPTAB_LIB_WIDEN);
+         ret = expand_simple_unop (mode, NOT, ret, target, true);
+       }
+      else
+       ret = expand_simple_binop (mode, code, ret, val, target, true,
+                                  OPTAB_LIB_WIDEN);
+    }
+  return ret;
+}
+
+
+/* Expand an atomic clear operation.
+       void _atomic_clear (BOOL *obj, enum memmodel)
+   EXP is the call expression.  */
+
+static rtx
+expand_builtin_atomic_clear (tree exp) 
+{
+  enum machine_mode mode;
+  rtx mem, ret;
+  enum memmodel model;
+
+  mode = mode_for_size (BOOL_TYPE_SIZE, MODE_INT, 0);
+  mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
+  model = get_memmodel (CALL_EXPR_ARG (exp, 1));
+
+  if (model == MEMMODEL_ACQUIRE || model == MEMMODEL_ACQ_REL)
+    {
+      error ("invalid memory model for %<__atomic_store%>");
+      return const0_rtx;
+    }
+
+  /* Try issuing an __atomic_store, and allow fallback to __sync_lock_release.
+     Failing that, a store is issued by __atomic_store.  The only way this can
+     fail is if the bool type is larger than a word size.  Unlikely, but
+     handle it anyway for completeness.  Assume a single threaded model since
+     there is no atomic support in this case, and no barriers are required.  */
+  ret = expand_atomic_store (mem, const0_rtx, model, true);
+  if (!ret)
+    emit_move_insn (mem, const0_rtx);
+  return const0_rtx;
+}
+
+/* Expand an atomic test_and_set operation.
+       bool _atomic_test_and_set (BOOL *obj, enum memmodel)
+   EXP is the call expression.  */
+
+static rtx
+expand_builtin_atomic_test_and_set (tree exp)
+{
+  rtx mem, ret;
+  enum memmodel model;
+  enum machine_mode mode;
+
+  mode = mode_for_size (BOOL_TYPE_SIZE, MODE_INT, 0);
+  mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
+  model = get_memmodel (CALL_EXPR_ARG (exp, 1));
+
+  /* Try issuing an exchange.  If it is lock free, or if there is a limited
+     functionality __sync_lock_test_and_set, this will utilize it.  */
+  ret = expand_atomic_exchange (NULL_RTX, mem, const1_rtx, model, true);
+  if (ret)
+    return ret;
+
+  /* Otherwise, there is no lock free support for test and set.  Simply
+     perform a load and a store.  Since this presumes a non-atomic architecture,
+     also assume single threadedness and don't issue barriers either. */
+
+  ret = gen_reg_rtx (mode);
+  emit_move_insn (ret, mem);
+  emit_move_insn (mem, const1_rtx);
+  return ret;
+}
+
+
+/* Return true if (optional) argument ARG1 of size ARG0 is always lock free on
+   this architecture.  If ARG1 is NULL, use typical alignment for size ARG0.  */
+
+static tree
+fold_builtin_atomic_always_lock_free (tree arg0, tree arg1)
+{
+  int size;
+  enum machine_mode mode;
+  unsigned int mode_align, type_align;
+
+  if (TREE_CODE (arg0) != INTEGER_CST)
+    return NULL_TREE;
+
+  size = INTVAL (expand_normal (arg0)) * BITS_PER_UNIT;
+  mode = mode_for_size (size, MODE_INT, 0);
+  mode_align = GET_MODE_ALIGNMENT (mode);
+
+  if (TREE_CODE (arg1) == INTEGER_CST && INTVAL (expand_normal (arg1)) == 0)
+    type_align = mode_align;
+  else
+    {
+      tree ttype = TREE_TYPE (arg1);
+
+      /* This function is usually invoked and folded immediately by the front
+        end before anything else has a chance to look at it.  The pointer
+        parameter at this point is usually cast to a void *, so check for that
+        and look past the cast.  */
+      if (TREE_CODE (arg1) == NOP_EXPR && POINTER_TYPE_P (ttype)
+         && VOID_TYPE_P (TREE_TYPE (ttype)))
+       arg1 = TREE_OPERAND (arg1, 0);
+
+      ttype = TREE_TYPE (arg1);
+      gcc_assert (POINTER_TYPE_P (ttype));
+
+      /* Get the underlying type of the object.  */
+      ttype = TREE_TYPE (ttype);
+      type_align = TYPE_ALIGN (ttype);
+    }
+
+  /* If the object has smaller alignment, the the lock free routines cannot
+     be used.  */
+  if (type_align < mode_align)
+    return integer_zero_node;
+
+  /* Check if a compare_and_swap pattern exists for the mode which represents
+     the required size.  The pattern is not allowed to fail, so the existence
+     of the pattern indicates support is present.  */
+  if (can_compare_and_swap_p (mode, true))
+    return integer_one_node;
+  else
+    return integer_zero_node;
+}
+
+/* Return true if the parameters to call EXP represent an object which will
+   always generate lock free instructions.  The first argument represents the
+   size of the object, and the second parameter is a pointer to the object 
+   itself.  If NULL is passed for the object, then the result is based on 
+   typical alignment for an object of the specified size.  Otherwise return 
+   false.  */
+
+static rtx
+expand_builtin_atomic_always_lock_free (tree exp)
+{
+  tree size;
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  tree arg1 = CALL_EXPR_ARG (exp, 1);
+
+  if (TREE_CODE (arg0) != INTEGER_CST)
+    {
+      error ("non-constant argument 1 to __atomic_always_lock_free");
+      return const0_rtx;
+    }
+
+  size = fold_builtin_atomic_always_lock_free (arg0, arg1);
+  if (size == integer_one_node)
+    return const1_rtx;
+  return const0_rtx;
+}
+
+/* Return a one or zero if it can be determined that object ARG1 of size ARG 
+   is lock free on this architecture.  */
+
+static tree
+fold_builtin_atomic_is_lock_free (tree arg0, tree arg1)
+{
+  if (!flag_inline_atomics)
+    return NULL_TREE;
+  
+  /* If it isn't always lock free, don't generate a result.  */
+  if (fold_builtin_atomic_always_lock_free (arg0, arg1) == integer_one_node)
+    return integer_one_node;
+
+  return NULL_TREE;
+}
+
+/* Return true if the parameters to call EXP represent an object which will
+   always generate lock free instructions.  The first argument represents the
+   size of the object, and the second parameter is a pointer to the object 
+   itself.  If NULL is passed for the object, then the result is based on 
+   typical alignment for an object of the specified size.  Otherwise return 
+   NULL*/
+
+static rtx
+expand_builtin_atomic_is_lock_free (tree exp)
+{
+  tree size;
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  tree arg1 = CALL_EXPR_ARG (exp, 1);
+
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (arg0)))
+    {
+      error ("non-integer argument 1 to __atomic_is_lock_free");
+      return NULL_RTX;
+    }
+
+  if (!flag_inline_atomics)
+    return NULL_RTX; 
+
+  /* If the value is known at compile time, return the RTX for it.  */
+  size = fold_builtin_atomic_is_lock_free (arg0, arg1);
+  if (size == integer_one_node)
+    return const1_rtx;
+
+  return NULL_RTX;
+}
+
+/* This routine will either emit the mem_thread_fence pattern or issue a 
+   sync_synchronize to generate a fence for memory model MEMMODEL.  */
+
+#ifndef HAVE_mem_thread_fence
+# define HAVE_mem_thread_fence 0
+# define gen_mem_thread_fence(x) (gcc_unreachable (), NULL_RTX)
+#endif
+
+void
+expand_builtin_mem_thread_fence (enum memmodel model)
+{
+  if (HAVE_mem_thread_fence)
+    emit_insn (gen_mem_thread_fence (GEN_INT (model)));
+  else if (model != MEMMODEL_RELAXED)
+    expand_builtin_sync_synchronize ();
+}
+
+/* Expand the __atomic_thread_fence intrinsic:
+       void __atomic_thread_fence (enum memmodel)
+   EXP is the CALL_EXPR.  */
+
+static void
+expand_builtin_atomic_thread_fence (tree exp)
+{
+  enum memmodel model;
+  
+  model = get_memmodel (CALL_EXPR_ARG (exp, 0));
+  expand_builtin_mem_thread_fence (model);
+}
+
+/* This routine will either emit the mem_signal_fence pattern or issue a 
+   sync_synchronize to generate a fence for memory model MEMMODEL.  */
+
+#ifndef HAVE_mem_signal_fence
+# define HAVE_mem_signal_fence 0
+# define gen_mem_signal_fence(x) (gcc_unreachable (), NULL_RTX)
+#endif
+
+static void
+expand_builtin_mem_signal_fence (enum memmodel model)
+{
+  if (HAVE_mem_signal_fence)
+    emit_insn (gen_mem_signal_fence (GEN_INT (model)));
+  else if (model != MEMMODEL_RELAXED)
+    {
+      rtx asm_op, clob;
+
+      /* By default targets are coherent between a thread and the signal
+        handler running on the same thread.  Thus this really becomes a
+        compiler barrier, in that stores must not be sunk past
+        (or raised above) a given point.  */
 
-  if (is_bool)
-    return expand_bool_compare_and_swap (mem, old_val, new_val, target);
-  else
-    return expand_val_compare_and_swap (mem, old_val, new_val, target);
+      /* Generate asm volatile("" : : : "memory") as the memory barrier.  */
+      asm_op = gen_rtx_ASM_OPERANDS (VOIDmode, empty_string, empty_string, 0,
+                                    rtvec_alloc (0), rtvec_alloc (0),
+                                    rtvec_alloc (0), UNKNOWN_LOCATION);
+      MEM_VOLATILE_P (asm_op) = 1;
+
+      clob = gen_rtx_SCRATCH (VOIDmode);
+      clob = gen_rtx_MEM (BLKmode, clob);
+      clob = gen_rtx_CLOBBER (VOIDmode, clob);
+
+      emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, asm_op, clob)));
+    }
 }
 
-/* Expand the __sync_lock_test_and_set intrinsic.  Note that the most
-   general form is actually an atomic exchange, and some targets only
-   support a reduced form with the second argument being a constant 1.
-   EXP is the CALL_EXPR; TARGET is an optional place for us to store
-   the results.  */
+/* Expand the __atomic_signal_fence intrinsic:
+       void __atomic_signal_fence (enum memmodel)
+   EXP is the CALL_EXPR.  */
 
-static rtx
-expand_builtin_lock_test_and_set (enum machine_mode mode, tree exp,
-                                 rtx target)
+static void
+expand_builtin_atomic_signal_fence (tree exp)
 {
-  rtx val, mem;
-  enum machine_mode old_mode;
-
-  /* Expand the operands.  */
-  mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
-  val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL_RTX, mode, EXPAND_NORMAL);
-  /* If VAL is promoted to a wider mode, convert it back to MODE.  Take care
-     of CONST_INTs, where we know the old_mode only from the call argument.  */
-  old_mode = GET_MODE (val);
-  if (old_mode == VOIDmode)
-    old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1)));
-  val = convert_modes (mode, old_mode, val, 1);
+  enum memmodel model;
 
-  return expand_sync_lock_test_and_set (mem, val, target);
+  model = get_memmodel (CALL_EXPR_ARG (exp, 0));
+  expand_builtin_mem_signal_fence (model);
 }
 
 /* Expand the __sync_synchronize intrinsic.  */
 
 static void
-expand_builtin_synchronize (void)
+expand_builtin_sync_synchronize (void)
 {
   gimple x;
   VEC (tree, gc) *v_clobbers;
@@ -5767,38 +5783,6 @@ expand_builtin_synchronize (void)
   expand_asm_stmt (x);
 }
 
-/* Expand the __sync_lock_release intrinsic.  EXP is the CALL_EXPR.  */
-
-static void
-expand_builtin_lock_release (enum machine_mode mode, tree exp)
-{
-  enum insn_code icode;
-  rtx mem, insn;
-  rtx val = const0_rtx;
-
-  /* Expand the operands.  */
-  mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
-
-  /* If there is an explicit operation in the md file, use it.  */
-  icode = direct_optab_handler (sync_lock_release_optab, mode);
-  if (icode != CODE_FOR_nothing)
-    {
-      if (!insn_data[icode].operand[1].predicate (val, mode))
-       val = force_reg (mode, val);
-
-      insn = GEN_FCN (icode) (mem, val);
-      if (insn)
-       {
-         emit_insn (insn);
-         return;
-       }
-    }
-
-  /* Otherwise we can implement this operation by emitting a barrier
-     followed by a store of zero.  */
-  expand_builtin_synchronize ();
-  emit_move_insn (mem, val);
-}
 \f
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
@@ -5824,6 +5808,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       && !called_as_built_in (fndecl)
       && DECL_ASSEMBLER_NAME_SET_P (fndecl)
       && fcode != BUILT_IN_ALLOCA
+      && fcode != BUILT_IN_ALLOCA_WITH_ALIGN
       && fcode != BUILT_IN_FREE)
     return expand_call (exp, target, ignore);
 
@@ -5926,17 +5911,21 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
+    CASE_FLT_FN (BUILT_IN_ICEIL):
     CASE_FLT_FN (BUILT_IN_LCEIL):
     CASE_FLT_FN (BUILT_IN_LLCEIL):
     CASE_FLT_FN (BUILT_IN_LFLOOR):
+    CASE_FLT_FN (BUILT_IN_IFLOOR):
     CASE_FLT_FN (BUILT_IN_LLFLOOR):
       target = expand_builtin_int_roundingfn (exp, target);
       if (target)
        return target;
       break;
 
+    CASE_FLT_FN (BUILT_IN_IRINT):
     CASE_FLT_FN (BUILT_IN_LRINT):
     CASE_FLT_FN (BUILT_IN_LLRINT):
+    CASE_FLT_FN (BUILT_IN_IROUND):
     CASE_FLT_FN (BUILT_IN_LROUND):
     CASE_FLT_FN (BUILT_IN_LLROUND):
       target = expand_builtin_int_roundingfn_2 (exp, target);
@@ -5944,12 +5933,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
-    CASE_FLT_FN (BUILT_IN_POW):
-      target = expand_builtin_pow (exp, target, subtarget);
-      if (target)
-       return target;
-      break;
-
     CASE_FLT_FN (BUILT_IN_POWI):
       target = expand_builtin_powi (exp, target);
       if (target)
@@ -5967,6 +5950,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     CASE_FLT_FN (BUILT_IN_FMOD):
     CASE_FLT_FN (BUILT_IN_REMAINDER):
     CASE_FLT_FN (BUILT_IN_DREM):
+    CASE_FLT_FN (BUILT_IN_POW):
       target = expand_builtin_mathfn_2 (exp, target, subtarget);
       if (target)
        return target;
@@ -6080,9 +6064,10 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
 
     case BUILT_IN_ALLOCA:
+    case BUILT_IN_ALLOCA_WITH_ALIGN:
       /* If the allocation stems from the declaration of a variable-sized
         object, it cannot accumulate.  */
-      target = expand_builtin_alloca (exp, ALLOCA_FOR_VAR_P (exp));
+      target = expand_builtin_alloca (exp, CALL_ALLOCA_FOR_VAR_P (exp));
       if (target)
        return target;
       break;
@@ -6126,6 +6111,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
+    CASE_INT_FN (BUILT_IN_CLRSB):
+    case BUILT_IN_CLRSBIMAX:
+      target = expand_builtin_unop (target_mode, exp, target,
+                                   subtarget, clrsb_optab);
+      if (target)
+       return target;
+      break;
+
     CASE_INT_FN (BUILT_IN_POPCOUNT):
     case BUILT_IN_POPCOUNTIMAX:
       target = expand_builtin_unop (target_mode, exp, target,
@@ -6361,15 +6354,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       return expand_builtin_va_copy (exp);
     case BUILT_IN_EXPECT:
       return expand_builtin_expect (exp, target);
+    case BUILT_IN_ASSUME_ALIGNED:
+      return expand_builtin_assume_aligned (exp, target);
     case BUILT_IN_PREFETCH:
       expand_builtin_prefetch (exp);
       return const0_rtx;
 
-    case BUILT_IN_PROFILE_FUNC_ENTER:
-      return expand_builtin_profile_func (false);
-    case BUILT_IN_PROFILE_FUNC_EXIT:
-      return expand_builtin_profile_func (true);
-
     case BUILT_IN_INIT_TRAMPOLINE:
       return expand_builtin_init_trampoline (exp);
     case BUILT_IN_ADJUST_TRAMPOLINE:
@@ -6387,199 +6377,425 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
-    case BUILT_IN_FETCH_AND_ADD_1:
-    case BUILT_IN_FETCH_AND_ADD_2:
-    case BUILT_IN_FETCH_AND_ADD_4:
-    case BUILT_IN_FETCH_AND_ADD_8:
-    case BUILT_IN_FETCH_AND_ADD_16:
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_ADD_1);
-      target = expand_builtin_sync_operation (mode, exp, PLUS,
-                                             false, target, ignore);
+    case BUILT_IN_SYNC_FETCH_AND_ADD_1:
+    case BUILT_IN_SYNC_FETCH_AND_ADD_2:
+    case BUILT_IN_SYNC_FETCH_AND_ADD_4:
+    case BUILT_IN_SYNC_FETCH_AND_ADD_8:
+    case BUILT_IN_SYNC_FETCH_AND_ADD_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_ADD_1);
+      target = expand_builtin_sync_operation (mode, exp, PLUS, false, target);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_FETCH_AND_SUB_1:
-    case BUILT_IN_FETCH_AND_SUB_2:
-    case BUILT_IN_FETCH_AND_SUB_4:
-    case BUILT_IN_FETCH_AND_SUB_8:
-    case BUILT_IN_FETCH_AND_SUB_16:
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_SUB_1);
-      target = expand_builtin_sync_operation (mode, exp, MINUS,
-                                             false, target, ignore);
+    case BUILT_IN_SYNC_FETCH_AND_SUB_1:
+    case BUILT_IN_SYNC_FETCH_AND_SUB_2:
+    case BUILT_IN_SYNC_FETCH_AND_SUB_4:
+    case BUILT_IN_SYNC_FETCH_AND_SUB_8:
+    case BUILT_IN_SYNC_FETCH_AND_SUB_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_SUB_1);
+      target = expand_builtin_sync_operation (mode, exp, MINUS, false, target);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_FETCH_AND_OR_1:
-    case BUILT_IN_FETCH_AND_OR_2:
-    case BUILT_IN_FETCH_AND_OR_4:
-    case BUILT_IN_FETCH_AND_OR_8:
-    case BUILT_IN_FETCH_AND_OR_16:
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_OR_1);
-      target = expand_builtin_sync_operation (mode, exp, IOR,
-                                             false, target, ignore);
+    case BUILT_IN_SYNC_FETCH_AND_OR_1:
+    case BUILT_IN_SYNC_FETCH_AND_OR_2:
+    case BUILT_IN_SYNC_FETCH_AND_OR_4:
+    case BUILT_IN_SYNC_FETCH_AND_OR_8:
+    case BUILT_IN_SYNC_FETCH_AND_OR_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_OR_1);
+      target = expand_builtin_sync_operation (mode, exp, IOR, false, target);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_FETCH_AND_AND_1:
-    case BUILT_IN_FETCH_AND_AND_2:
-    case BUILT_IN_FETCH_AND_AND_4:
-    case BUILT_IN_FETCH_AND_AND_8:
-    case BUILT_IN_FETCH_AND_AND_16:
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_AND_1);
-      target = expand_builtin_sync_operation (mode, exp, AND,
-                                             false, target, ignore);
+    case BUILT_IN_SYNC_FETCH_AND_AND_1:
+    case BUILT_IN_SYNC_FETCH_AND_AND_2:
+    case BUILT_IN_SYNC_FETCH_AND_AND_4:
+    case BUILT_IN_SYNC_FETCH_AND_AND_8:
+    case BUILT_IN_SYNC_FETCH_AND_AND_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_AND_1);
+      target = expand_builtin_sync_operation (mode, exp, AND, false, target);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_FETCH_AND_XOR_1:
-    case BUILT_IN_FETCH_AND_XOR_2:
-    case BUILT_IN_FETCH_AND_XOR_4:
-    case BUILT_IN_FETCH_AND_XOR_8:
-    case BUILT_IN_FETCH_AND_XOR_16:
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_XOR_1);
-      target = expand_builtin_sync_operation (mode, exp, XOR,
-                                             false, target, ignore);
+    case BUILT_IN_SYNC_FETCH_AND_XOR_1:
+    case BUILT_IN_SYNC_FETCH_AND_XOR_2:
+    case BUILT_IN_SYNC_FETCH_AND_XOR_4:
+    case BUILT_IN_SYNC_FETCH_AND_XOR_8:
+    case BUILT_IN_SYNC_FETCH_AND_XOR_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_XOR_1);
+      target = expand_builtin_sync_operation (mode, exp, XOR, false, target);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_FETCH_AND_NAND_1:
-    case BUILT_IN_FETCH_AND_NAND_2:
-    case BUILT_IN_FETCH_AND_NAND_4:
-    case BUILT_IN_FETCH_AND_NAND_8:
-    case BUILT_IN_FETCH_AND_NAND_16:
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_NAND_1);
-      target = expand_builtin_sync_operation (mode, exp, NOT,
-                                             false, target, ignore);
+    case BUILT_IN_SYNC_FETCH_AND_NAND_1:
+    case BUILT_IN_SYNC_FETCH_AND_NAND_2:
+    case BUILT_IN_SYNC_FETCH_AND_NAND_4:
+    case BUILT_IN_SYNC_FETCH_AND_NAND_8:
+    case BUILT_IN_SYNC_FETCH_AND_NAND_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_NAND_1);
+      target = expand_builtin_sync_operation (mode, exp, NOT, false, target);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_ADD_AND_FETCH_1:
-    case BUILT_IN_ADD_AND_FETCH_2:
-    case BUILT_IN_ADD_AND_FETCH_4:
-    case BUILT_IN_ADD_AND_FETCH_8:
-    case BUILT_IN_ADD_AND_FETCH_16:
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_ADD_AND_FETCH_1);
-      target = expand_builtin_sync_operation (mode, exp, PLUS,
-                                             true, target, ignore);
+    case BUILT_IN_SYNC_ADD_AND_FETCH_1:
+    case BUILT_IN_SYNC_ADD_AND_FETCH_2:
+    case BUILT_IN_SYNC_ADD_AND_FETCH_4:
+    case BUILT_IN_SYNC_ADD_AND_FETCH_8:
+    case BUILT_IN_SYNC_ADD_AND_FETCH_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_ADD_AND_FETCH_1);
+      target = expand_builtin_sync_operation (mode, exp, PLUS, true, target);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_SUB_AND_FETCH_1:
-    case BUILT_IN_SUB_AND_FETCH_2:
-    case BUILT_IN_SUB_AND_FETCH_4:
-    case BUILT_IN_SUB_AND_FETCH_8:
-    case BUILT_IN_SUB_AND_FETCH_16:
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_SUB_AND_FETCH_1);
-      target = expand_builtin_sync_operation (mode, exp, MINUS,
-                                             true, target, ignore);
+    case BUILT_IN_SYNC_SUB_AND_FETCH_1:
+    case BUILT_IN_SYNC_SUB_AND_FETCH_2:
+    case BUILT_IN_SYNC_SUB_AND_FETCH_4:
+    case BUILT_IN_SYNC_SUB_AND_FETCH_8:
+    case BUILT_IN_SYNC_SUB_AND_FETCH_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_SUB_AND_FETCH_1);
+      target = expand_builtin_sync_operation (mode, exp, MINUS, true, target);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_OR_AND_FETCH_1:
-    case BUILT_IN_OR_AND_FETCH_2:
-    case BUILT_IN_OR_AND_FETCH_4:
-    case BUILT_IN_OR_AND_FETCH_8:
-    case BUILT_IN_OR_AND_FETCH_16:
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_OR_AND_FETCH_1);
-      target = expand_builtin_sync_operation (mode, exp, IOR,
-                                             true, target, ignore);
+    case BUILT_IN_SYNC_OR_AND_FETCH_1:
+    case BUILT_IN_SYNC_OR_AND_FETCH_2:
+    case BUILT_IN_SYNC_OR_AND_FETCH_4:
+    case BUILT_IN_SYNC_OR_AND_FETCH_8:
+    case BUILT_IN_SYNC_OR_AND_FETCH_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_OR_AND_FETCH_1);
+      target = expand_builtin_sync_operation (mode, exp, IOR, true, target);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_AND_AND_FETCH_1:
-    case BUILT_IN_AND_AND_FETCH_2:
-    case BUILT_IN_AND_AND_FETCH_4:
-    case BUILT_IN_AND_AND_FETCH_8:
-    case BUILT_IN_AND_AND_FETCH_16:
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_AND_AND_FETCH_1);
-      target = expand_builtin_sync_operation (mode, exp, AND,
-                                             true, target, ignore);
+    case BUILT_IN_SYNC_AND_AND_FETCH_1:
+    case BUILT_IN_SYNC_AND_AND_FETCH_2:
+    case BUILT_IN_SYNC_AND_AND_FETCH_4:
+    case BUILT_IN_SYNC_AND_AND_FETCH_8:
+    case BUILT_IN_SYNC_AND_AND_FETCH_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_AND_AND_FETCH_1);
+      target = expand_builtin_sync_operation (mode, exp, AND, true, target);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_XOR_AND_FETCH_1:
-    case BUILT_IN_XOR_AND_FETCH_2:
-    case BUILT_IN_XOR_AND_FETCH_4:
-    case BUILT_IN_XOR_AND_FETCH_8:
-    case BUILT_IN_XOR_AND_FETCH_16:
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_XOR_AND_FETCH_1);
-      target = expand_builtin_sync_operation (mode, exp, XOR,
-                                             true, target, ignore);
+    case BUILT_IN_SYNC_XOR_AND_FETCH_1:
+    case BUILT_IN_SYNC_XOR_AND_FETCH_2:
+    case BUILT_IN_SYNC_XOR_AND_FETCH_4:
+    case BUILT_IN_SYNC_XOR_AND_FETCH_8:
+    case BUILT_IN_SYNC_XOR_AND_FETCH_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_XOR_AND_FETCH_1);
+      target = expand_builtin_sync_operation (mode, exp, XOR, true, target);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_NAND_AND_FETCH_1:
-    case BUILT_IN_NAND_AND_FETCH_2:
-    case BUILT_IN_NAND_AND_FETCH_4:
-    case BUILT_IN_NAND_AND_FETCH_8:
-    case BUILT_IN_NAND_AND_FETCH_16:
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_NAND_AND_FETCH_1);
-      target = expand_builtin_sync_operation (mode, exp, NOT,
-                                             true, target, ignore);
+    case BUILT_IN_SYNC_NAND_AND_FETCH_1:
+    case BUILT_IN_SYNC_NAND_AND_FETCH_2:
+    case BUILT_IN_SYNC_NAND_AND_FETCH_4:
+    case BUILT_IN_SYNC_NAND_AND_FETCH_8:
+    case BUILT_IN_SYNC_NAND_AND_FETCH_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_NAND_AND_FETCH_1);
+      target = expand_builtin_sync_operation (mode, exp, NOT, true, target);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_BOOL_COMPARE_AND_SWAP_1:
-    case BUILT_IN_BOOL_COMPARE_AND_SWAP_2:
-    case BUILT_IN_BOOL_COMPARE_AND_SWAP_4:
-    case BUILT_IN_BOOL_COMPARE_AND_SWAP_8:
-    case BUILT_IN_BOOL_COMPARE_AND_SWAP_16:
+    case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1:
+    case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_2:
+    case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4:
+    case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8:
+    case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_16:
       if (mode == VOIDmode)
        mode = TYPE_MODE (boolean_type_node);
       if (!target || !register_operand (target, mode))
        target = gen_reg_rtx (mode);
 
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_BOOL_COMPARE_AND_SWAP_1);
+      mode = get_builtin_sync_mode 
+                               (fcode - BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1);
       target = expand_builtin_compare_and_swap (mode, exp, true, target);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_VAL_COMPARE_AND_SWAP_1:
-    case BUILT_IN_VAL_COMPARE_AND_SWAP_2:
-    case BUILT_IN_VAL_COMPARE_AND_SWAP_4:
-    case BUILT_IN_VAL_COMPARE_AND_SWAP_8:
-    case BUILT_IN_VAL_COMPARE_AND_SWAP_16:
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_VAL_COMPARE_AND_SWAP_1);
+    case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_1:
+    case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_2:
+    case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_4:
+    case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_8:
+    case BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_16:
+      mode = get_builtin_sync_mode 
+                               (fcode - BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_1);
       target = expand_builtin_compare_and_swap (mode, exp, false, target);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_LOCK_TEST_AND_SET_1:
-    case BUILT_IN_LOCK_TEST_AND_SET_2:
-    case BUILT_IN_LOCK_TEST_AND_SET_4:
-    case BUILT_IN_LOCK_TEST_AND_SET_8:
-    case BUILT_IN_LOCK_TEST_AND_SET_16:
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_TEST_AND_SET_1);
-      target = expand_builtin_lock_test_and_set (mode, exp, target);
+    case BUILT_IN_SYNC_LOCK_TEST_AND_SET_1:
+    case BUILT_IN_SYNC_LOCK_TEST_AND_SET_2:
+    case BUILT_IN_SYNC_LOCK_TEST_AND_SET_4:
+    case BUILT_IN_SYNC_LOCK_TEST_AND_SET_8:
+    case BUILT_IN_SYNC_LOCK_TEST_AND_SET_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_LOCK_TEST_AND_SET_1);
+      target = expand_builtin_sync_lock_test_and_set (mode, exp, target);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_SYNC_LOCK_RELEASE_1:
+    case BUILT_IN_SYNC_LOCK_RELEASE_2:
+    case BUILT_IN_SYNC_LOCK_RELEASE_4:
+    case BUILT_IN_SYNC_LOCK_RELEASE_8:
+    case BUILT_IN_SYNC_LOCK_RELEASE_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_LOCK_RELEASE_1);
+      expand_builtin_sync_lock_release (mode, exp);
+      return const0_rtx;
+
+    case BUILT_IN_SYNC_SYNCHRONIZE:
+      expand_builtin_sync_synchronize ();
+      return const0_rtx;
+
+    case BUILT_IN_ATOMIC_EXCHANGE_1:
+    case BUILT_IN_ATOMIC_EXCHANGE_2:
+    case BUILT_IN_ATOMIC_EXCHANGE_4:
+    case BUILT_IN_ATOMIC_EXCHANGE_8:
+    case BUILT_IN_ATOMIC_EXCHANGE_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_EXCHANGE_1);
+      target = expand_builtin_atomic_exchange (mode, exp, target);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1:
+    case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_2:
+    case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4:
+    case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8:
+    case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16:
+      mode = 
+         get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1);
+      target = expand_builtin_atomic_compare_exchange (mode, exp, target);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_ATOMIC_LOAD_1:
+    case BUILT_IN_ATOMIC_LOAD_2:
+    case BUILT_IN_ATOMIC_LOAD_4:
+    case BUILT_IN_ATOMIC_LOAD_8:
+    case BUILT_IN_ATOMIC_LOAD_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_LOAD_1);
+      target = expand_builtin_atomic_load (mode, exp, target);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_ATOMIC_STORE_1:
+    case BUILT_IN_ATOMIC_STORE_2:
+    case BUILT_IN_ATOMIC_STORE_4:
+    case BUILT_IN_ATOMIC_STORE_8:
+    case BUILT_IN_ATOMIC_STORE_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_STORE_1);
+      target = expand_builtin_atomic_store (mode, exp);
+      if (target)
+       return const0_rtx;
+      break;
+
+    case BUILT_IN_ATOMIC_ADD_FETCH_1:
+    case BUILT_IN_ATOMIC_ADD_FETCH_2:
+    case BUILT_IN_ATOMIC_ADD_FETCH_4:
+    case BUILT_IN_ATOMIC_ADD_FETCH_8:
+    case BUILT_IN_ATOMIC_ADD_FETCH_16:
+      {
+       enum built_in_function lib;
+       mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_ADD_FETCH_1);
+       lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_ADD_1 + 
+                                      (fcode - BUILT_IN_ATOMIC_ADD_FETCH_1));
+       target = expand_builtin_atomic_fetch_op (mode, exp, target, PLUS, true,
+                                                ignore, lib);
+       if (target)
+         return target;
+       break;
+      }
+    case BUILT_IN_ATOMIC_SUB_FETCH_1:
+    case BUILT_IN_ATOMIC_SUB_FETCH_2:
+    case BUILT_IN_ATOMIC_SUB_FETCH_4:
+    case BUILT_IN_ATOMIC_SUB_FETCH_8:
+    case BUILT_IN_ATOMIC_SUB_FETCH_16:
+      {
+       enum built_in_function lib;
+       mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_SUB_FETCH_1);
+       lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_SUB_1 + 
+                                      (fcode - BUILT_IN_ATOMIC_SUB_FETCH_1));
+       target = expand_builtin_atomic_fetch_op (mode, exp, target, MINUS, true,
+                                                ignore, lib);
+       if (target)
+         return target;
+       break;
+      }
+    case BUILT_IN_ATOMIC_AND_FETCH_1:
+    case BUILT_IN_ATOMIC_AND_FETCH_2:
+    case BUILT_IN_ATOMIC_AND_FETCH_4:
+    case BUILT_IN_ATOMIC_AND_FETCH_8:
+    case BUILT_IN_ATOMIC_AND_FETCH_16:
+      {
+       enum built_in_function lib;
+       mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_AND_FETCH_1);
+       lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_AND_1 + 
+                                      (fcode - BUILT_IN_ATOMIC_AND_FETCH_1));
+       target = expand_builtin_atomic_fetch_op (mode, exp, target, AND, true,
+                                                ignore, lib);
+       if (target)
+         return target;
+       break;
+      }
+    case BUILT_IN_ATOMIC_NAND_FETCH_1:
+    case BUILT_IN_ATOMIC_NAND_FETCH_2:
+    case BUILT_IN_ATOMIC_NAND_FETCH_4:
+    case BUILT_IN_ATOMIC_NAND_FETCH_8:
+    case BUILT_IN_ATOMIC_NAND_FETCH_16:
+      {
+       enum built_in_function lib;
+       mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_NAND_FETCH_1);
+       lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_NAND_1 + 
+                                      (fcode - BUILT_IN_ATOMIC_NAND_FETCH_1));
+       target = expand_builtin_atomic_fetch_op (mode, exp, target, NOT, true,
+                                                ignore, lib);
+       if (target)
+         return target;
+       break;
+      }
+    case BUILT_IN_ATOMIC_XOR_FETCH_1:
+    case BUILT_IN_ATOMIC_XOR_FETCH_2:
+    case BUILT_IN_ATOMIC_XOR_FETCH_4:
+    case BUILT_IN_ATOMIC_XOR_FETCH_8:
+    case BUILT_IN_ATOMIC_XOR_FETCH_16:
+      {
+       enum built_in_function lib;
+       mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_XOR_FETCH_1);
+       lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_XOR_1 + 
+                                      (fcode - BUILT_IN_ATOMIC_XOR_FETCH_1));
+       target = expand_builtin_atomic_fetch_op (mode, exp, target, XOR, true,
+                                                ignore, lib);
+       if (target)
+         return target;
+       break;
+      }
+    case BUILT_IN_ATOMIC_OR_FETCH_1:
+    case BUILT_IN_ATOMIC_OR_FETCH_2:
+    case BUILT_IN_ATOMIC_OR_FETCH_4:
+    case BUILT_IN_ATOMIC_OR_FETCH_8:
+    case BUILT_IN_ATOMIC_OR_FETCH_16:
+      {
+       enum built_in_function lib;
+       mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_OR_FETCH_1);
+       lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_OR_1 + 
+                                      (fcode - BUILT_IN_ATOMIC_OR_FETCH_1));
+       target = expand_builtin_atomic_fetch_op (mode, exp, target, IOR, true,
+                                                ignore, lib);
+       if (target)
+         return target;
+       break;
+      }
+    case BUILT_IN_ATOMIC_FETCH_ADD_1:
+    case BUILT_IN_ATOMIC_FETCH_ADD_2:
+    case BUILT_IN_ATOMIC_FETCH_ADD_4:
+    case BUILT_IN_ATOMIC_FETCH_ADD_8:
+    case BUILT_IN_ATOMIC_FETCH_ADD_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_ADD_1);
+      target = expand_builtin_atomic_fetch_op (mode, exp, target, PLUS, false,
+                                              ignore, BUILT_IN_NONE);
+      if (target)
+       return target;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_SUB_1:
+    case BUILT_IN_ATOMIC_FETCH_SUB_2:
+    case BUILT_IN_ATOMIC_FETCH_SUB_4:
+    case BUILT_IN_ATOMIC_FETCH_SUB_8:
+    case BUILT_IN_ATOMIC_FETCH_SUB_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_SUB_1);
+      target = expand_builtin_atomic_fetch_op (mode, exp, target, MINUS, false,
+                                              ignore, BUILT_IN_NONE);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_ATOMIC_FETCH_AND_1:
+    case BUILT_IN_ATOMIC_FETCH_AND_2:
+    case BUILT_IN_ATOMIC_FETCH_AND_4:
+    case BUILT_IN_ATOMIC_FETCH_AND_8:
+    case BUILT_IN_ATOMIC_FETCH_AND_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_AND_1);
+      target = expand_builtin_atomic_fetch_op (mode, exp, target, AND, false,
+                                              ignore, BUILT_IN_NONE);
+      if (target)
+       return target;
+      break;
+  
+    case BUILT_IN_ATOMIC_FETCH_NAND_1:
+    case BUILT_IN_ATOMIC_FETCH_NAND_2:
+    case BUILT_IN_ATOMIC_FETCH_NAND_4:
+    case BUILT_IN_ATOMIC_FETCH_NAND_8:
+    case BUILT_IN_ATOMIC_FETCH_NAND_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_NAND_1);
+      target = expand_builtin_atomic_fetch_op (mode, exp, target, NOT, false,
+                                              ignore, BUILT_IN_NONE);
+      if (target)
+       return target;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_XOR_1:
+    case BUILT_IN_ATOMIC_FETCH_XOR_2:
+    case BUILT_IN_ATOMIC_FETCH_XOR_4:
+    case BUILT_IN_ATOMIC_FETCH_XOR_8:
+    case BUILT_IN_ATOMIC_FETCH_XOR_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_XOR_1);
+      target = expand_builtin_atomic_fetch_op (mode, exp, target, XOR, false,
+                                              ignore, BUILT_IN_NONE);
+      if (target)
+       return target;
+      break;
+    case BUILT_IN_ATOMIC_FETCH_OR_1:
+    case BUILT_IN_ATOMIC_FETCH_OR_2:
+    case BUILT_IN_ATOMIC_FETCH_OR_4:
+    case BUILT_IN_ATOMIC_FETCH_OR_8:
+    case BUILT_IN_ATOMIC_FETCH_OR_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_OR_1);
+      target = expand_builtin_atomic_fetch_op (mode, exp, target, IOR, false,
+                                              ignore, BUILT_IN_NONE);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_LOCK_RELEASE_1:
-    case BUILT_IN_LOCK_RELEASE_2:
-    case BUILT_IN_LOCK_RELEASE_4:
-    case BUILT_IN_LOCK_RELEASE_8:
-    case BUILT_IN_LOCK_RELEASE_16:
-      mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_RELEASE_1);
-      expand_builtin_lock_release (mode, exp);
+    case BUILT_IN_ATOMIC_TEST_AND_SET:
+      return expand_builtin_atomic_test_and_set (exp);
+
+    case BUILT_IN_ATOMIC_CLEAR:
+      return expand_builtin_atomic_clear (exp);
+    case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
+      return expand_builtin_atomic_always_lock_free (exp);
+
+    case BUILT_IN_ATOMIC_IS_LOCK_FREE:
+      target = expand_builtin_atomic_is_lock_free (exp);
+      if (target)
+        return target;
+      break;
+
+    case BUILT_IN_ATOMIC_THREAD_FENCE:
+      expand_builtin_atomic_thread_fence (exp);
       return const0_rtx;
 
-    case BUILT_IN_SYNCHRONIZE:
-      expand_builtin_synchronize ();
+    case BUILT_IN_ATOMIC_SIGNAL_FENCE:
+      expand_builtin_atomic_signal_fence (exp);
       return const0_rtx;
 
     case BUILT_IN_OBJECT_SIZE:
@@ -6610,7 +6826,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       break;
 
     case BUILT_IN_FREE:
-      maybe_emit_free_warning (exp);
+      if (warn_free_nonheap_object)
+       maybe_emit_free_warning (exp);
       break;
 
     default:   /* just do library call, if unknown builtin */
@@ -6745,7 +6962,7 @@ build_builtin_expect_predicate (location_t loc, tree pred, tree expected)
 {
   tree fn, arg_types, pred_type, expected_type, call_expr, ret_type;
 
-  fn = built_in_decls[BUILT_IN_EXPECT];
+  fn = builtin_decl_explicit (BUILT_IN_EXPECT);
   arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
   ret_type = TREE_TYPE (TREE_TYPE (fn));
   pred_type = TREE_VALUE (arg_types);
@@ -6765,13 +6982,22 @@ build_builtin_expect_predicate (location_t loc, tree pred, tree expected)
 static tree
 fold_builtin_expect (location_t loc, tree arg0, tree arg1)
 {
-  tree inner, fndecl;
+  tree inner, fndecl, inner_arg0;
   enum tree_code code;
 
+  /* Distribute the expected value over short-circuiting operators.
+     See through the cast from truthvalue_type_node to long.  */
+  inner_arg0 = arg0;
+  while (TREE_CODE (inner_arg0) == NOP_EXPR
+        && INTEGRAL_TYPE_P (TREE_TYPE (inner_arg0))
+        && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (inner_arg0, 0))))
+    inner_arg0 = TREE_OPERAND (inner_arg0, 0);
+
   /* If this is a builtin_expect within a builtin_expect keep the
      inner one.  See through a comparison against a constant.  It
      might have been added to create a thruthvalue.  */
-  inner = arg0;
+  inner = inner_arg0;
+
   if (COMPARISON_CLASS_P (inner)
       && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST)
     inner = TREE_OPERAND (inner, 0);
@@ -6782,14 +7008,7 @@ fold_builtin_expect (location_t loc, tree arg0, tree arg1)
       && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT)
     return arg0;
 
-  /* Distribute the expected value over short-circuiting operators.
-     See through the cast from truthvalue_type_node to long.  */
-  inner = arg0;
-  while (TREE_CODE (inner) == NOP_EXPR
-        && INTEGRAL_TYPE_P (TREE_TYPE (inner))
-        && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (inner, 0))))
-    inner = TREE_OPERAND (inner, 0);
-
+  inner = inner_arg0;
   code = TREE_CODE (inner);
   if (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
     {
@@ -6804,13 +7023,13 @@ fold_builtin_expect (location_t loc, tree arg0, tree arg1)
     }
 
   /* If the argument isn't invariant then there's nothing else we can do.  */
-  if (!TREE_CONSTANT (arg0))
+  if (!TREE_CONSTANT (inner_arg0))
     return NULL_TREE;
 
   /* If we expect that a comparison against the argument will fold to
      a constant return the constant.  In practice, this means a true
      constant or the address of a non-weak symbol.  */
-  inner = arg0;
+  inner = inner_arg0;
   STRIP_NOPS (inner);
   if (TREE_CODE (inner) == ADDR_EXPR)
     {
@@ -6836,9 +7055,9 @@ static tree
 fold_builtin_classify_type (tree arg)
 {
   if (arg == 0)
-    return build_int_cst (NULL_TREE, no_type_class);
+    return build_int_cst (integer_type_node, no_type_class);
 
-  return build_int_cst (NULL_TREE, type_to_class (TREE_TYPE (arg)));
+  return build_int_cst (integer_type_node, type_to_class (TREE_TYPE (arg)));
 }
 
 /* Fold a call to __builtin_strlen with argument ARG.  */
@@ -7042,6 +7261,42 @@ fold_fixed_mathfn (location_t loc, tree fndecl, tree arg)
                                fold_convert_loc (loc, newtype, arg0));
     }
 
+  /* Canonicalize iround (x) to lround (x) on ILP32 targets where
+     sizeof (int) == sizeof (long).  */
+  if (TYPE_PRECISION (integer_type_node)
+      == TYPE_PRECISION (long_integer_type_node))
+    {
+      tree newfn = NULL_TREE;
+      switch (fcode)
+       {
+       CASE_FLT_FN (BUILT_IN_ICEIL):
+         newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LCEIL);
+         break;
+
+       CASE_FLT_FN (BUILT_IN_IFLOOR):
+         newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LFLOOR);
+         break;
+
+       CASE_FLT_FN (BUILT_IN_IROUND):
+         newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LROUND);
+         break;
+
+       CASE_FLT_FN (BUILT_IN_IRINT):
+         newfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_LRINT);
+         break;
+
+       default:
+         break;
+       }
+
+      if (newfn)
+       {
+         tree newcall = build_call_expr_loc (loc, newfn, 1, arg);
+         return fold_convert_loc (loc,
+                                  TREE_TYPE (TREE_TYPE (fndecl)), newcall);
+       }
+    }
+
   /* Canonicalize llround (x) to lround (x) on LP64 targets where
      sizeof (long long) == sizeof (long).  */
   if (TYPE_PRECISION (long_long_integer_type_node)
@@ -7741,16 +7996,19 @@ fold_builtin_int_roundingfn (location_t loc, tree fndecl, tree arg)
 
          switch (DECL_FUNCTION_CODE (fndecl))
            {
+           CASE_FLT_FN (BUILT_IN_IFLOOR):
            CASE_FLT_FN (BUILT_IN_LFLOOR):
            CASE_FLT_FN (BUILT_IN_LLFLOOR):
              real_floor (&r, TYPE_MODE (ftype), &x);
              break;
 
+           CASE_FLT_FN (BUILT_IN_ICEIL):
            CASE_FLT_FN (BUILT_IN_LCEIL):
            CASE_FLT_FN (BUILT_IN_LLCEIL):
              real_ceil (&r, TYPE_MODE (ftype), &x);
              break;
 
+           CASE_FLT_FN (BUILT_IN_IROUND):
            CASE_FLT_FN (BUILT_IN_LROUND):
            CASE_FLT_FN (BUILT_IN_LLROUND):
              real_round (&r, TYPE_MODE (ftype), &x);
@@ -7808,7 +8066,8 @@ fold_builtin_bitop (tree fndecl, tree arg)
        {
          hi = TREE_INT_CST_HIGH (arg);
          if (width < 2 * HOST_BITS_PER_WIDE_INT)
-           hi &= ~((HOST_WIDE_INT) (-1) >> (width - HOST_BITS_PER_WIDE_INT));
+           hi &= ~((unsigned HOST_WIDE_INT) (-1)
+                   << (width - HOST_BITS_PER_WIDE_INT));
        }
       else
        {
@@ -7846,6 +8105,26 @@ fold_builtin_bitop (tree fndecl, tree arg)
            result = width;
          break;
 
+       CASE_INT_FN (BUILT_IN_CLRSB):
+         if (width > HOST_BITS_PER_WIDE_INT
+             && (hi & ((unsigned HOST_WIDE_INT) 1
+                       << (width - HOST_BITS_PER_WIDE_INT - 1))) != 0)
+           {
+             hi = ~hi & ~((unsigned HOST_WIDE_INT) (-1)
+                          << (width - HOST_BITS_PER_WIDE_INT - 1));
+             lo = ~lo;
+           }
+         else if (width <= HOST_BITS_PER_WIDE_INT
+                  && (lo & ((unsigned HOST_WIDE_INT) 1 << (width - 1))) != 0)
+           lo = ~lo & ~((unsigned HOST_WIDE_INT) (-1) << (width - 1));
+         if (hi != 0)
+           result = width - floor_log2 (hi) - 2 - HOST_BITS_PER_WIDE_INT;
+         else if (lo != 0)
+           result = width - floor_log2 (lo) - 2;
+         else
+           result = width - 1;
+         break;
+
        CASE_INT_FN (BUILT_IN_POPCOUNT):
          result = 0;
          while (lo)
@@ -8345,7 +8624,7 @@ fold_builtin_memset (location_t loc, tree dest, tree c, tree len,
   if (integer_zerop (len))
     return omit_one_operand_loc (loc, type, dest, c);
 
-  if (! host_integerp (c, 1) || TREE_SIDE_EFFECTS (dest))
+  if (TREE_CODE (c) != INTEGER_CST || TREE_SIDE_EFFECTS (dest))
     return NULL_TREE;
 
   var = dest;
@@ -8370,8 +8649,7 @@ fold_builtin_memset (location_t loc, tree dest, tree c, tree len,
 
   length = tree_low_cst (len, 1);
   if (GET_MODE_SIZE (TYPE_MODE (etype)) != length
-      || get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
-        < length)
+      || get_pointer_alignment (dest) / BITS_PER_UNIT < length)
     return NULL_TREE;
 
   if (length > HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT)
@@ -8384,7 +8662,7 @@ fold_builtin_memset (location_t loc, tree dest, tree c, tree len,
       if (CHAR_BIT != 8 || BITS_PER_UNIT != 8 || HOST_BITS_PER_WIDE_INT > 64)
        return NULL_TREE;
 
-      cval = tree_low_cst (c, 1);
+      cval = TREE_INT_CST_LOW (c);
       cval &= 0xff;
       cval |= cval << 8;
       cval |= cval << 16;
@@ -8422,7 +8700,7 @@ fold_builtin_bzero (location_t loc, tree dest, tree size, bool ignore)
      calling bzero instead of memset.  */
 
   return fold_builtin_memset (loc, dest, integer_zero_node,
-                             fold_convert_loc (loc, sizetype, size),
+                             fold_convert_loc (loc, size_type_node, size),
                              void_type_node, ignore);
 }
 
@@ -8461,8 +8739,8 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
 
       if (endp == 3)
        {
-         src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
-         dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+         src_align = get_pointer_alignment (src);
+         dest_align = get_pointer_alignment (dest);
 
          /* Both DEST and SRC must be pointer types.
             ??? This is what old code did.  Is the testing for pointer types
@@ -8476,7 +8754,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
                  && (MIN (src_align, dest_align) / BITS_PER_UNIT
                      >= (unsigned HOST_WIDE_INT) tree_low_cst (len, 1))))
            {
-             tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+             tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
              if (!fn)
                return NULL_TREE;
               return build_call_expr_loc (loc, fn, 3, dest, src, len);
@@ -8535,7 +8813,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
              else
                return NULL_TREE;
 
-             fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+             fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
              if (!fn)
                return NULL_TREE;
              return build_call_expr_loc (loc, fn, 3, dest, src, len);
@@ -8554,7 +8832,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
              if (!refs_may_alias_p_1 (&destr, &srcr, false))
                {
                  tree fn;
-                 fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+                 fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
                  if (!fn)
                    return NULL_TREE;
                  return build_call_expr_loc (loc, fn, 3, dest, src, len);
@@ -8572,6 +8850,9 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
         Perhaps we ought to inherit type from non-VOID argument here?  */
       STRIP_NOPS (src);
       STRIP_NOPS (dest);
+      if (!POINTER_TYPE_P (TREE_TYPE (src))
+         || !POINTER_TYPE_P (TREE_TYPE (dest)))
+       return NULL_TREE;
       /* As we fold (void *)(p + CST) to (void *)p + CST undo this here.  */
       if (TREE_CODE (src) == POINTER_PLUS_EXPR)
        {
@@ -8588,8 +8869,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
            dest = build1 (NOP_EXPR, TREE_TYPE (tem), dest);
        }
       srctype = TREE_TYPE (TREE_TYPE (src));
-      if (srctype
-         && TREE_CODE (srctype) == ARRAY_TYPE
+      if (TREE_CODE (srctype) == ARRAY_TYPE
          && !tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len))
        {
          srctype = TREE_TYPE (srctype);
@@ -8597,25 +8877,19 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
          src = build1 (NOP_EXPR, build_pointer_type (srctype), src);
        }
       desttype = TREE_TYPE (TREE_TYPE (dest));
-      if (desttype
-         && TREE_CODE (desttype) == ARRAY_TYPE
+      if (TREE_CODE (desttype) == ARRAY_TYPE
          && !tree_int_cst_equal (TYPE_SIZE_UNIT (desttype), len))
        {
          desttype = TREE_TYPE (desttype);
          STRIP_NOPS (dest);
          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)
+      if (TREE_ADDRESSABLE (srctype)
+         || TREE_ADDRESSABLE (desttype))
        return NULL_TREE;
 
-      src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
-      dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+      src_align = get_pointer_alignment (src);
+      dest_align = get_pointer_alignment (dest);
       if (dest_align < TYPE_ALIGN (desttype)
          || src_align < TYPE_ALIGN (srctype))
        return NULL_TREE;
@@ -8706,8 +8980,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
     len = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (len), len,
                       ssize_int (1));
 
-  len = fold_convert_loc (loc, sizetype, len);
-  dest = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (dest), dest, len);
+  dest = fold_build_pointer_plus_loc (loc, dest, len);
   dest = fold_convert_loc (loc, type, dest);
   if (expr)
     dest = omit_one_operand_loc (loc, type, dest, expr);
@@ -8734,7 +9007,7 @@ fold_builtin_strcpy (location_t loc, tree fndecl, tree dest, tree src, tree len)
   if (optimize_function_for_size_p (cfun))
     return NULL_TREE;
 
-  fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+  fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
   if (!fn)
     return NULL_TREE;
 
@@ -8745,7 +9018,8 @@ fold_builtin_strcpy (location_t loc, tree fndecl, tree dest, tree src, tree len)
        return NULL_TREE;
     }
 
-  len = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1));
+  len = fold_convert_loc (loc, size_type_node, len);
+  len = size_binop_loc (loc, PLUS_EXPR, len, build_int_cst (size_type_node, 1));
   return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)),
                           build_call_expr_loc (loc, fn, 3, dest, src, len));
 }
@@ -8772,19 +9046,20 @@ fold_builtin_stpcpy (location_t loc, tree fndecl, tree dest, tree src)
       && !integer_zerop (len))
     return NULL_TREE;
 
-  fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+  fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
   if (!fn)
     return NULL_TREE;
 
-  lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1));
+  lenp1 = size_binop_loc (loc, PLUS_EXPR,
+                         fold_convert_loc (loc, size_type_node, len),
+                         build_int_cst (size_type_node, 1));
   /* We use dest twice in building our expression.  Save it from
      multiple expansions.  */
   dest = builtin_save_expr (dest);
   call = build_call_expr_loc (loc, fn, 3, dest, src, lenp1);
 
   type = TREE_TYPE (TREE_TYPE (fndecl));
-  len = fold_convert_loc (loc, sizetype, len);
-  dest = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (dest), dest, len);
+  dest = fold_build_pointer_plus_loc (loc, dest, len);
   dest = fold_convert_loc (loc, type, dest);
   dest = omit_one_operand_loc (loc, type, dest, call);
   return dest;
@@ -8830,9 +9105,11 @@ fold_builtin_strncpy (location_t loc, tree fndecl, tree dest,
     return NULL_TREE;
 
   /* OK transform into builtin memcpy.  */
-  fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+  fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
   if (!fn)
     return NULL_TREE;
+
+  len = fold_convert_loc (loc, size_type_node, len);
   return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)),
                           build_call_expr_loc (loc, fn, 3, dest, src, len));
 }
@@ -8866,13 +9143,12 @@ fold_builtin_memchr (location_t loc, tree arg1, tree arg2, tree len, tree type)
          if (target_char_cast (arg2, &c))
            return NULL_TREE;
 
-         r = (char *) memchr (p1, c, tree_low_cst (len, 1));
+         r = (const char *) memchr (p1, c, tree_low_cst (len, 1));
 
          if (r == NULL)
            return build_int_cst (TREE_TYPE (arg1), 0);
 
-         tem = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (arg1), arg1,
-                            size_int (r - p1));
+         tem = fold_build_pointer_plus_hwi_loc (loc, arg1, r - p1);
          return fold_convert_loc (loc, type, tem);
        }
       return NULL_TREE;
@@ -9131,8 +9407,9 @@ fold_builtin_signbit (location_t loc, tree arg, tree type)
 
   /* If ARG's format doesn't have signed zeros, return "arg < 0.0".  */
   if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg))))
-    return fold_build2_loc (loc, LT_EXPR, type, arg,
-                       build_real (TREE_TYPE (arg), dconst0));
+    return fold_convert (type,
+                        fold_build2_loc (loc, LT_EXPR, boolean_type_node, arg,
+                       build_real (TREE_TYPE (arg), dconst0)));
 
   return NULL_TREE;
 }
@@ -9196,10 +9473,10 @@ fold_builtin_isascii (location_t loc, tree arg)
     {
       /* Transform isascii(c) -> ((c & ~0x7f) == 0).  */
       arg = fold_build2 (BIT_AND_EXPR, integer_type_node, arg,
-                        build_int_cst (NULL_TREE,
+                        build_int_cst (integer_type_node,
                                        ~ (unsigned HOST_WIDE_INT) 0x7f));
       return fold_build2_loc (loc, EQ_EXPR, integer_type_node,
-                         arg, integer_zero_node);
+                             arg, integer_zero_node);
     }
 }
 
@@ -9213,7 +9490,7 @@ fold_builtin_toascii (location_t loc, tree arg)
 
   /* Transform toascii(c) -> (c & 0x7f).  */
   return fold_build2_loc (loc, BIT_AND_EXPR, integer_type_node, arg,
-                     build_int_cst (NULL_TREE, 0x7f));
+                         build_int_cst (integer_type_node, 0x7f));
 }
 
 /* Fold a call to builtin isdigit with argument ARG.  */
@@ -9404,7 +9681,7 @@ fold_builtin_logb (location_t loc, tree arg, tree rettype)
           exponent and subtract 1.  */
        if (REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (arg)))->b == 2)
          return fold_convert_loc (loc, rettype,
-                                  build_int_cst (NULL_TREE,
+                                  build_int_cst (integer_type_node,
                                                  REAL_EXP (value)-1));
        break;
       }
@@ -9492,7 +9769,7 @@ fold_builtin_frexp (location_t loc, tree arg0, tree arg1, tree rettype)
          REAL_VALUE_TYPE frac_rvt = *value;
          SET_REAL_EXP (&frac_rvt, 0);
          frac = build_real (rettype, frac_rvt);
-         exp = build_int_cst (NULL_TREE, REAL_EXP (value));
+         exp = build_int_cst (integer_type_node, REAL_EXP (value));
        }
        break;
       default:
@@ -9651,7 +9928,7 @@ fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg)
     CASE_FLT_FN (BUILT_IN_ISINF):
       {
        /* isinf(x) -> isgreater(fabs(x),DBL_MAX).  */
-       tree const isgr_fn = built_in_decls[BUILT_IN_ISGREATER];
+       tree const isgr_fn = builtin_decl_explicit (BUILT_IN_ISGREATER);
        tree const type = TREE_TYPE (arg);
        REAL_VALUE_TYPE r;
        char buf[128];
@@ -9667,7 +9944,7 @@ fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg)
     case BUILT_IN_ISFINITE:
       {
        /* isfinite(x) -> islessequal(fabs(x),DBL_MAX).  */
-       tree const isle_fn = built_in_decls[BUILT_IN_ISLESSEQUAL];
+       tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL);
        tree const type = TREE_TYPE (arg);
        REAL_VALUE_TYPE r;
        char buf[128];
@@ -9690,8 +9967,8 @@ fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg)
       {
        /* isnormal(x) -> isgreaterequal(fabs(x),DBL_MIN) &
           islessequal(fabs(x),DBL_MAX).  */
-       tree const isle_fn = built_in_decls[BUILT_IN_ISLESSEQUAL];
-       tree const isge_fn = built_in_decls[BUILT_IN_ISGREATEREQUAL];
+       tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL);
+       tree const isge_fn = builtin_decl_explicit (BUILT_IN_ISGREATEREQUAL);
        tree const type = TREE_TYPE (arg);
        REAL_VALUE_TYPE rmax, rmin;
        char buf[128];
@@ -9752,7 +10029,7 @@ fold_builtin_classify (location_t loc, tree fndecl, tree arg, int builtin_index)
           1.  So e.g. "if (isinf_sign(x))" would be folded to just
           "if (isinf(x) ? 1 : 0)" which becomes "if (isinf(x))". */
        tree signbit_fn = mathfn_built_in_1 (TREE_TYPE (arg), BUILT_IN_SIGNBIT, 0);
-       tree isinf_fn = built_in_decls[BUILT_IN_ISINF];
+       tree isinf_fn = builtin_decl_explicit (BUILT_IN_ISINF);
        tree tmp = NULL_TREE;
 
        arg = builtin_save_expr (arg);
@@ -10265,14 +10542,18 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore)
     CASE_FLT_FN (BUILT_IN_RINT):
       return fold_trunc_transparent_mathfn (loc, fndecl, arg0);
 
+    CASE_FLT_FN (BUILT_IN_ICEIL):
     CASE_FLT_FN (BUILT_IN_LCEIL):
     CASE_FLT_FN (BUILT_IN_LLCEIL):
     CASE_FLT_FN (BUILT_IN_LFLOOR):
+    CASE_FLT_FN (BUILT_IN_IFLOOR):
     CASE_FLT_FN (BUILT_IN_LLFLOOR):
+    CASE_FLT_FN (BUILT_IN_IROUND):
     CASE_FLT_FN (BUILT_IN_LROUND):
     CASE_FLT_FN (BUILT_IN_LLROUND):
       return fold_builtin_int_roundingfn (loc, fndecl, arg0);
 
+    CASE_FLT_FN (BUILT_IN_IRINT):
     CASE_FLT_FN (BUILT_IN_LRINT):
     CASE_FLT_FN (BUILT_IN_LLRINT):
       return fold_fixed_mathfn (loc, fndecl, arg0);
@@ -10284,6 +10565,7 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore)
     CASE_INT_FN (BUILT_IN_FFS):
     CASE_INT_FN (BUILT_IN_CLZ):
     CASE_INT_FN (BUILT_IN_CTZ):
+    CASE_INT_FN (BUILT_IN_CLRSB):
     CASE_INT_FN (BUILT_IN_POPCOUNT):
     CASE_INT_FN (BUILT_IN_PARITY):
       return fold_builtin_bitop (fndecl, arg0);
@@ -10470,7 +10752,7 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1, bool ignore)
     case BUILT_IN_STPCPY:
       if (ignore)
        {
-         tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+         tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
          if (!fn)
            break;
 
@@ -10555,6 +10837,12 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1, bool ignore)
       return fold_builtin_fprintf (loc, fndecl, arg0, arg1, NULL_TREE,
                                   ignore, fcode);
 
+    case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
+      return fold_builtin_atomic_always_lock_free (arg0, arg1);
+
+    case BUILT_IN_ATOMIC_IS_LOCK_FREE:
+      return fold_builtin_atomic_is_lock_free (arg0, arg1);
+
     default:
       break;
     }
@@ -10626,6 +10914,9 @@ fold_builtin_3 (location_t loc, tree fndecl,
     case BUILT_IN_SPRINTF:
       return fold_builtin_sprintf (loc, arg0, arg1, arg2, ignore);
 
+    case BUILT_IN_SNPRINTF:
+      return fold_builtin_snprintf (loc, arg0, arg1, arg2, NULL_TREE, ignore);
+
     case BUILT_IN_STRCPY_CHK:
     case BUILT_IN_STPCPY_CHK:
       return fold_builtin_stxcpy_chk (loc, fndecl, arg0, arg1, arg2, NULL_TREE,
@@ -10691,6 +10982,9 @@ fold_builtin_4 (location_t loc, tree fndecl,
     case BUILT_IN_STRNCAT_CHK:
       return fold_builtin_strncat_chk (loc, fndecl, arg0, arg1, arg2, arg3);
 
+    case BUILT_IN_SNPRINTF:
+      return fold_builtin_snprintf (loc, arg0, arg1, arg2, arg3, ignore);
+
     case BUILT_IN_FPRINTF_CHK:
     case BUILT_IN_VFPRINTF_CHK:
       if (!validate_arg (arg1, INTEGER_TYPE)
@@ -10802,7 +11096,7 @@ fold_builtin_varargs (location_t loc, tree fndecl, tree exp,
    been inlined, otherwise e.g. -D_FORTIFY_SOURCE checking
    might not be performed.  */
 
-static bool
+bool
 avoid_folding_inline_builtin (tree fndecl)
 {
   return (DECL_DECLARED_INLINE_P (fndecl)
@@ -11252,8 +11546,7 @@ fold_builtin_strstr (location_t loc, tree s1, tree s2, tree type)
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
-         tem = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (s1),
-                            s1, size_int (r - p1));
+         tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
          return fold_convert_loc (loc, type, tem);
        }
 
@@ -11265,13 +11558,14 @@ fold_builtin_strstr (location_t loc, tree s1, tree s2, tree type)
       if (p2[1] != '\0')
        return NULL_TREE;
 
-      fn = implicit_built_in_decls[BUILT_IN_STRCHR];
+      fn = builtin_decl_implicit (BUILT_IN_STRCHR);
       if (!fn)
        return NULL_TREE;
 
       /* New argument list transforming strstr(s1, s2) to
         strchr(s1, s2[0]).  */
-      return build_call_expr_loc (loc, fn, 2, s1, build_int_cst (NULL_TREE, p2[0]));
+      return build_call_expr_loc (loc, fn, 2, s1,
+                                 build_int_cst (integer_type_node, p2[0]));
     }
 }
 
@@ -11322,8 +11616,7 @@ fold_builtin_strchr (location_t loc, tree s1, tree s2, tree type)
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
-         tem = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (s1),
-                            s1, size_int (r - p1));
+         tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
          return fold_convert_loc (loc, type, tem);
        }
       return NULL_TREE;
@@ -11378,15 +11671,14 @@ fold_builtin_strrchr (location_t loc, tree s1, tree s2, tree type)
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
-         tem = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (s1),
-                            s1, size_int (r - p1));
+         tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
          return fold_convert_loc (loc, type, tem);
        }
 
       if (! integer_zerop (s2))
        return NULL_TREE;
 
-      fn = implicit_built_in_decls[BUILT_IN_STRCHR];
+      fn = builtin_decl_implicit (BUILT_IN_STRCHR);
       if (!fn)
        return NULL_TREE;
 
@@ -11438,8 +11730,7 @@ fold_builtin_strpbrk (location_t loc, tree s1, tree s2, tree type)
            return build_int_cst (TREE_TYPE (s1), 0);
 
          /* Return an offset into the constant string argument.  */
-         tem = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (s1),
-                            s1, size_int (r - p1));
+         tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
          return fold_convert_loc (loc, type, tem);
        }
 
@@ -11451,13 +11742,14 @@ fold_builtin_strpbrk (location_t loc, tree s1, tree s2, tree type)
       if (p2[1] != '\0')
        return NULL_TREE;  /* Really call strpbrk.  */
 
-      fn = implicit_built_in_decls[BUILT_IN_STRCHR];
+      fn = builtin_decl_implicit (BUILT_IN_STRCHR);
       if (!fn)
        return NULL_TREE;
 
       /* New argument list transforming strpbrk(s1, s2) to
         strchr(s1, s2[0]).  */
-      return build_call_expr_loc (loc, fn, 2, s1, build_int_cst (NULL_TREE, p2[0]));
+      return build_call_expr_loc (loc, fn, 2, s1,
+                                 build_int_cst (integer_type_node, p2[0]));
     }
 }
 
@@ -11497,8 +11789,8 @@ fold_builtin_strcat (location_t loc ATTRIBUTE_UNUSED, tree dst, tree src)
        {
          /* See if we can store by pieces into (dst + strlen(dst)).  */
          tree newdst, call;
-         tree strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN];
-         tree strcpy_fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+         tree strlen_fn = builtin_decl_implicit (BUILT_IN_STRLEN);
+         tree strcpy_fn = builtin_decl_implicit (BUILT_IN_STRCPY);
 
          if (!strlen_fn || !strcpy_fn)
            return NULL_TREE;
@@ -11522,8 +11814,7 @@ fold_builtin_strcat (location_t loc ATTRIBUTE_UNUSED, tree dst, tree src)
          newdst = build_call_expr_loc (loc, strlen_fn, 1, dst);
          /* Create (dst p+ strlen (dst)).  */
 
-         newdst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
-                               TREE_TYPE (dst), dst, newdst);
+         newdst = fold_build_pointer_plus_loc (loc, dst, newdst);
          newdst = builtin_save_expr (newdst);
 
          call = build_call_expr_loc (loc, strcpy_fn, 2, newdst, src);
@@ -11572,7 +11863,7 @@ fold_builtin_strncat (location_t loc, tree dst, tree src, tree len)
       if (TREE_CODE (len) == INTEGER_CST && p
          && compare_tree_int (len, strlen (p)) >= 0)
        {
-         tree fn = implicit_built_in_decls[BUILT_IN_STRCAT];
+         tree fn = builtin_decl_implicit (BUILT_IN_STRCAT);
 
          /* If the replacement _DECL isn't initialized, don't do the
             transformation.  */
@@ -11677,7 +11968,7 @@ fold_builtin_strcspn (location_t loc, tree s1, tree s2)
       /* If the second argument is "", return __builtin_strlen(s1).  */
       if (p2 && *p2 == '\0')
        {
-         tree fn = implicit_built_in_decls[BUILT_IN_STRLEN];
+         tree fn = builtin_decl_implicit (BUILT_IN_STRLEN);
 
          /* If the replacement _DECL isn't initialized, don't do the
             transformation.  */
@@ -11703,10 +11994,12 @@ fold_builtin_fputs (location_t loc, tree arg0, tree arg1,
 {
   /* If we're using an unlocked function, assume the other unlocked
      functions exist explicitly.  */
-  tree const fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
-    : implicit_built_in_decls[BUILT_IN_FPUTC];
-  tree const fn_fwrite = unlocked ? built_in_decls[BUILT_IN_FWRITE_UNLOCKED]
-    : implicit_built_in_decls[BUILT_IN_FWRITE];
+  tree const fn_fputc = (unlocked
+                        ? builtin_decl_explicit (BUILT_IN_FPUTC_UNLOCKED)
+                        : builtin_decl_implicit (BUILT_IN_FPUTC));
+  tree const fn_fwrite = (unlocked
+                         ? builtin_decl_explicit (BUILT_IN_FWRITE_UNLOCKED)
+                         : builtin_decl_implicit (BUILT_IN_FWRITE));
 
   /* If the return value is used, don't do the transformation.  */
   if (!ignore)
@@ -11740,7 +12033,8 @@ fold_builtin_fputs (location_t loc, tree arg0, tree arg1,
          {
            if (fn_fputc)
              return build_call_expr_loc (loc, fn_fputc, 2,
-                                     build_int_cst (NULL_TREE, p[0]), arg1);
+                                         build_int_cst
+                                           (integer_type_node, p[0]), arg1);
            else
              return NULL_TREE;
          }
@@ -11899,7 +12193,7 @@ fold_builtin_sprintf (location_t loc, tree dest, tree fmt,
   /* If the format doesn't contain % args or %%, use strcpy.  */
   if (strchr (fmt_str, target_percent) == NULL)
     {
-      tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+      tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
 
       if (!fn)
        return NULL_TREE;
@@ -11912,14 +12206,14 @@ fold_builtin_sprintf (location_t loc, tree dest, tree fmt,
         'format' is known to contain no % formats.  */
       call = build_call_expr_loc (loc, fn, 2, dest, fmt);
       if (!ignored)
-       retval = build_int_cst (NULL_TREE, strlen (fmt_str));
+       retval = build_int_cst (integer_type_node, strlen (fmt_str));
     }
 
   /* If the format is "%s", use strcpy if the result isn't used.  */
   else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
     {
       tree fn;
-      fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+      fn = builtin_decl_implicit (BUILT_IN_STRCPY);
 
       if (!fn)
        return NULL_TREE;
@@ -11941,7 +12235,7 @@ fold_builtin_sprintf (location_t loc, tree dest, tree fmt,
   if (call && retval)
     {
       retval = fold_convert_loc
-       (loc, TREE_TYPE (TREE_TYPE (implicit_built_in_decls[BUILT_IN_SPRINTF])),
+       (loc, TREE_TYPE (TREE_TYPE (builtin_decl_implicit (BUILT_IN_SPRINTF))),
         retval);
       return build2 (COMPOUND_EXPR, TREE_TYPE (retval), call, retval);
     }
@@ -11949,6 +12243,126 @@ fold_builtin_sprintf (location_t loc, tree dest, tree fmt,
     return call;
 }
 
+/* Simplify a call to the snprintf builtin with arguments DEST, DESTSIZE,
+   FMT, and ORIG.  ORIG may be null if this is a 3-argument call.  We don't
+   attempt to simplify calls with more than 4 arguments.
+
+   Return NULL_TREE if no simplification was possible, otherwise return the
+   simplified form of the call as a tree.  If IGNORED is true, it means that
+   the caller does not use the returned value of the function.  */
+
+static tree
+fold_builtin_snprintf (location_t loc, tree dest, tree destsize, tree fmt,
+                      tree orig, int ignored)
+{
+  tree call, retval;
+  const char *fmt_str = NULL;
+  unsigned HOST_WIDE_INT destlen;
+
+  /* Verify the required arguments in the original call.  We deal with two
+     types of snprintf() calls: 'snprintf (str, cst, fmt)' and
+     'snprintf (dest, cst, "%s", orig)'.  */
+  if (!validate_arg (dest, POINTER_TYPE)
+      || !validate_arg (destsize, INTEGER_TYPE)
+      || !validate_arg (fmt, POINTER_TYPE))
+    return NULL_TREE;
+  if (orig && !validate_arg (orig, POINTER_TYPE))
+    return NULL_TREE;
+
+  if (!host_integerp (destsize, 1))
+    return NULL_TREE;
+
+  /* Check whether the format is a literal string constant.  */
+  fmt_str = c_getstr (fmt);
+  if (fmt_str == NULL)
+    return NULL_TREE;
+
+  call = NULL_TREE;
+  retval = NULL_TREE;
+
+  if (!init_target_chars ())
+    return NULL_TREE;
+
+  destlen = tree_low_cst (destsize, 1);
+
+  /* If the format doesn't contain % args or %%, use strcpy.  */
+  if (strchr (fmt_str, target_percent) == NULL)
+    {
+      tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+      size_t len = strlen (fmt_str);
+
+      /* Don't optimize snprintf (buf, 4, "abc", ptr++).  */
+      if (orig)
+       return NULL_TREE;
+
+      /* We could expand this as
+        memcpy (str, fmt, cst - 1); str[cst - 1] = '\0';
+        or to
+        memcpy (str, fmt_with_nul_at_cstm1, cst);
+        but in the former case that might increase code size
+        and in the latter case grow .rodata section too much.
+        So punt for now.  */
+      if (len >= destlen)
+       return NULL_TREE;
+
+      if (!fn)
+       return NULL_TREE;
+
+      /* Convert snprintf (str, cst, fmt) into strcpy (str, fmt) when
+        'format' is known to contain no % formats and
+        strlen (fmt) < cst.  */
+      call = build_call_expr_loc (loc, fn, 2, dest, fmt);
+
+      if (!ignored)
+       retval = build_int_cst (integer_type_node, strlen (fmt_str));
+    }
+
+  /* If the format is "%s", use strcpy if the result isn't used.  */
+  else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
+    {
+      tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+      unsigned HOST_WIDE_INT origlen;
+
+      /* Don't crash on snprintf (str1, cst, "%s").  */
+      if (!orig)
+       return NULL_TREE;
+
+      retval = c_strlen (orig, 1);
+      if (!retval || !host_integerp (retval, 1))  
+       return NULL_TREE;
+
+      origlen = tree_low_cst (retval, 1);
+      /* We could expand this as
+        memcpy (str1, str2, cst - 1); str1[cst - 1] = '\0';
+        or to
+        memcpy (str1, str2_with_nul_at_cstm1, cst);
+        but in the former case that might increase code size
+        and in the latter case grow .rodata section too much.
+        So punt for now.  */
+      if (origlen >= destlen)
+       return NULL_TREE;
+
+      /* Convert snprintf (str1, cst, "%s", str2) into
+        strcpy (str1, str2) if strlen (str2) < cst.  */
+      if (!fn)
+       return NULL_TREE;
+
+      call = build_call_expr_loc (loc, fn, 2, dest, orig);
+
+      if (ignored)
+       retval = NULL_TREE;
+    }
+
+  if (call && retval)
+    {
+      tree fn = builtin_decl_explicit (BUILT_IN_SNPRINTF);
+      retval = fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fn)), retval);
+      return build2 (COMPOUND_EXPR, TREE_TYPE (retval), call, retval);
+    }
+  else
+    return call;
+}
+
 /* Expand a call EXP to __builtin_object_size.  */
 
 rtx
@@ -12029,16 +12443,16 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
       switch (fcode)
        {
        case BUILT_IN_MEMCPY_CHK:
-         fn = built_in_decls[BUILT_IN_MEMCPY];
+         fn = builtin_decl_explicit (BUILT_IN_MEMCPY);
          break;
        case BUILT_IN_MEMPCPY_CHK:
-         fn = built_in_decls[BUILT_IN_MEMPCPY];
+         fn = builtin_decl_explicit (BUILT_IN_MEMPCPY);
          break;
        case BUILT_IN_MEMMOVE_CHK:
-         fn = built_in_decls[BUILT_IN_MEMMOVE];
+         fn = builtin_decl_explicit (BUILT_IN_MEMMOVE);
          break;
        case BUILT_IN_MEMSET_CHK:
-         fn = built_in_decls[BUILT_IN_MEMSET];
+         fn = builtin_decl_explicit (BUILT_IN_MEMSET);
          break;
        default:
          break;
@@ -12056,8 +12470,7 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
     return NULL_RTX;
   else
     {
-      unsigned int dest_align
-       = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
+      unsigned int dest_align = get_pointer_alignment (dest);
 
       /* If DEST is not a pointer type, call the normal function.  */
       if (dest_align == 0)
@@ -12075,15 +12488,14 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
              return expand_expr (dest, target, mode, EXPAND_NORMAL);
            }
 
-         expr = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (dest), dest, len);
+         expr = fold_build_pointer_plus (dest, len);
          return expand_expr (expr, target, mode, EXPAND_NORMAL);
        }
 
       /* __memmove_chk special case.  */
       if (fcode == BUILT_IN_MEMMOVE_CHK)
        {
-         unsigned int src_align
-           = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
+         unsigned int src_align = get_pointer_alignment (src);
 
          if (src_align == 0)
            return NULL_RTX;
@@ -12092,7 +12504,7 @@ expand_builtin_memory_chk (tree exp, rtx target, enum machine_mode mode,
             normal __memcpy_chk.  */
          if (readonly_data_expr (src))
            {
-             tree fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
+             tree fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
              if (!fn)
                return NULL_RTX;
              fn = build_call_nofold_loc (EXPR_LOCATION (exp), fn, 4,
@@ -12247,11 +12659,11 @@ maybe_emit_free_warning (tree exp)
     return;
 
   if (SSA_VAR_P (arg))
-    warning_at (tree_nonartificial_location (exp),
-               0, "%Kattempt to free a non-heap object %qD", exp, arg);
+    warning_at (tree_nonartificial_location (exp), OPT_Wfree_nonheap_object,
+               "%Kattempt to free a non-heap object %qD", exp, arg);
   else
-    warning_at (tree_nonartificial_location (exp),
-               0, "%Kattempt to free a non-heap object", exp);
+    warning_at (tree_nonartificial_location (exp), OPT_Wfree_nonheap_object,
+               "%Kattempt to free a non-heap object", exp);
 }
 
 /* Fold a call to __builtin_object_size with arguments PTR and OST,
@@ -12335,8 +12747,7 @@ fold_builtin_memory_chk (location_t loc, tree fndecl,
                                 dest, len);
       else
        {
-         tree temp = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (dest),
-                                  dest, len);
+         tree temp = fold_build_pointer_plus_loc (loc, dest, len);
          return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)), temp);
        }
     }
@@ -12357,7 +12768,7 @@ fold_builtin_memory_chk (location_t loc, tree fndecl,
                {
                  /* (void) __mempcpy_chk () can be optimized into
                     (void) __memcpy_chk ().  */
-                 fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
+                 fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
                  if (!fn)
                    return NULL_TREE;
 
@@ -12379,16 +12790,16 @@ fold_builtin_memory_chk (location_t loc, tree fndecl,
   switch (fcode)
     {
     case BUILT_IN_MEMCPY_CHK:
-      fn = built_in_decls[BUILT_IN_MEMCPY];
+      fn = builtin_decl_explicit (BUILT_IN_MEMCPY);
       break;
     case BUILT_IN_MEMPCPY_CHK:
-      fn = built_in_decls[BUILT_IN_MEMPCPY];
+      fn = builtin_decl_explicit (BUILT_IN_MEMPCPY);
       break;
     case BUILT_IN_MEMMOVE_CHK:
-      fn = built_in_decls[BUILT_IN_MEMMOVE];
+      fn = builtin_decl_explicit (BUILT_IN_MEMMOVE);
       break;
     case BUILT_IN_MEMSET_CHK:
-      fn = built_in_decls[BUILT_IN_MEMSET];
+      fn = builtin_decl_explicit (BUILT_IN_MEMSET);
       break;
     default:
       break;
@@ -12443,7 +12854,7 @@ fold_builtin_stxcpy_chk (location_t loc, tree fndecl, tree dest,
 
                  /* If return value of __stpcpy_chk is ignored,
                     optimize into __strcpy_chk.  */
-                 fn = built_in_decls[BUILT_IN_STRCPY_CHK];
+                 fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
                  if (!fn)
                    return NULL_TREE;
 
@@ -12455,11 +12866,13 @@ fold_builtin_stxcpy_chk (location_t loc, tree fndecl, tree dest,
 
              /* If c_strlen returned something, but not a constant,
                 transform __strcpy_chk into __memcpy_chk.  */
-             fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
+             fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
              if (!fn)
                return NULL_TREE;
 
-             len = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1));
+             len = fold_convert_loc (loc, size_type_node, len);
+             len = size_binop_loc (loc, PLUS_EXPR, len,
+                                   build_int_cst (size_type_node, 1));
              return fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fndecl)),
                                       build_call_expr_loc (loc, fn, 4,
                                                        dest, src, len, size));
@@ -12473,8 +12886,8 @@ fold_builtin_stxcpy_chk (location_t loc, tree fndecl, tree dest,
     }
 
   /* If __builtin_st{r,p}cpy_chk is used, assume st{r,p}cpy is available.  */
-  fn = built_in_decls[fcode == BUILT_IN_STPCPY_CHK
-                     ? BUILT_IN_STPCPY : BUILT_IN_STRCPY];
+  fn = builtin_decl_explicit (fcode == BUILT_IN_STPCPY_CHK
+                             ? BUILT_IN_STPCPY : BUILT_IN_STRCPY);
   if (!fn)
     return NULL_TREE;
 
@@ -12518,7 +12931,7 @@ fold_builtin_strncpy_chk (location_t loc, tree dest, tree src,
     }
 
   /* If __builtin_strncpy_chk is used, assume strncpy is available.  */
-  fn = built_in_decls[BUILT_IN_STRNCPY];
+  fn = builtin_decl_explicit (BUILT_IN_STRNCPY);
   if (!fn)
     return NULL_TREE;
 
@@ -12549,7 +12962,7 @@ fold_builtin_strcat_chk (location_t loc, tree fndecl, tree dest,
     return NULL_TREE;
 
   /* If __builtin_strcat_chk is used, assume strcat is available.  */
-  fn = built_in_decls[BUILT_IN_STRCAT];
+  fn = builtin_decl_explicit (BUILT_IN_STRCAT);
   if (!fn)
     return NULL_TREE;
 
@@ -12591,7 +13004,7 @@ fold_builtin_strncat_chk (location_t loc, tree fndecl,
          && ! tree_int_cst_lt (len, src_len))
        {
          /* If LEN >= strlen (SRC), optimize into __strcat_chk.  */
-         fn = built_in_decls[BUILT_IN_STRCAT_CHK];
+         fn = builtin_decl_explicit (BUILT_IN_STRCAT_CHK);
          if (!fn)
            return NULL_TREE;
 
@@ -12601,7 +13014,7 @@ fold_builtin_strncat_chk (location_t loc, tree fndecl,
     }
 
   /* If __builtin_strncat_chk is used, assume strncat is available.  */
-  fn = built_in_decls[BUILT_IN_STRNCAT];
+  fn = builtin_decl_explicit (BUILT_IN_STRNCAT);
   if (!fn)
     return NULL_TREE;
 
@@ -12692,8 +13105,8 @@ fold_builtin_sprintf_chk_1 (location_t loc, int nargs, tree *args,
     }
 
   /* If __builtin_{,v}sprintf_chk is used, assume {,v}sprintf is available.  */
-  fn = built_in_decls[fcode == BUILT_IN_VSPRINTF_CHK
-                     ? BUILT_IN_VSPRINTF : BUILT_IN_SPRINTF];
+  fn = builtin_decl_explicit (fcode == BUILT_IN_VSPRINTF_CHK
+                             ? BUILT_IN_VSPRINTF : BUILT_IN_SPRINTF);
   if (!fn)
     return NULL_TREE;
 
@@ -12781,8 +13194,8 @@ fold_builtin_snprintf_chk_1 (location_t loc, int nargs, tree *args,
 
   /* If __builtin_{,v}snprintf_chk is used, assume {,v}snprintf is
      available.  */
-  fn = built_in_decls[fcode == BUILT_IN_VSNPRINTF_CHK
-                     ? BUILT_IN_VSNPRINTF : BUILT_IN_SNPRINTF];
+  fn = builtin_decl_explicit (fcode == BUILT_IN_VSNPRINTF_CHK
+                             ? BUILT_IN_VSNPRINTF : BUILT_IN_SNPRINTF);
   if (!fn)
     return NULL_TREE;
 
@@ -12836,13 +13249,13 @@ fold_builtin_printf (location_t loc, tree fndecl, tree fmt,
     {
       /* If we're using an unlocked function, assume the other
         unlocked functions exist explicitly.  */
-      fn_putchar = built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED];
-      fn_puts = built_in_decls[BUILT_IN_PUTS_UNLOCKED];
+      fn_putchar = builtin_decl_explicit (BUILT_IN_PUTCHAR_UNLOCKED);
+      fn_puts = builtin_decl_explicit (BUILT_IN_PUTS_UNLOCKED);
     }
   else
     {
-      fn_putchar = implicit_built_in_decls[BUILT_IN_PUTCHAR];
-      fn_puts = implicit_built_in_decls[BUILT_IN_PUTS];
+      fn_putchar = builtin_decl_implicit (BUILT_IN_PUTCHAR);
+      fn_puts = builtin_decl_implicit (BUILT_IN_PUTS);
     }
 
   if (!init_target_chars ())
@@ -12884,7 +13297,7 @@ fold_builtin_printf (location_t loc, tree fndecl, tree fmt,
          /* Given printf("c"), (where c is any one character,)
             convert "c"[0] to an int and pass that to the replacement
             function.  */
-         newarg = build_int_cst (NULL_TREE, str[0]);
+         newarg = build_int_cst (integer_type_node, str[0]);
          if (fn_putchar)
            call = build_call_expr_loc (loc, fn_putchar, 1, newarg);
        }
@@ -12987,13 +13400,13 @@ fold_builtin_fprintf (location_t loc, tree fndecl, tree fp,
     {
       /* If we're using an unlocked function, assume the other
         unlocked functions exist explicitly.  */
-      fn_fputc = built_in_decls[BUILT_IN_FPUTC_UNLOCKED];
-      fn_fputs = built_in_decls[BUILT_IN_FPUTS_UNLOCKED];
+      fn_fputc = builtin_decl_explicit (BUILT_IN_FPUTC_UNLOCKED);
+      fn_fputs = builtin_decl_explicit (BUILT_IN_FPUTS_UNLOCKED);
     }
   else
     {
-      fn_fputc = implicit_built_in_decls[BUILT_IN_FPUTC];
-      fn_fputs = implicit_built_in_decls[BUILT_IN_FPUTS];
+      fn_fputc = builtin_decl_implicit (BUILT_IN_FPUTC);
+      fn_fputs = builtin_decl_implicit (BUILT_IN_FPUTS);
     }
 
   if (!init_target_chars ())
@@ -13486,9 +13899,10 @@ do_mpfr_remquo (tree arg0, tree arg1, tree arg_quo)
              if (TYPE_MAIN_VARIANT (TREE_TYPE (arg_quo)) == integer_type_node)
                {
                  /* Set the value. */
-                 tree result_quo = fold_build2 (MODIFY_EXPR,
-                                                TREE_TYPE (arg_quo), arg_quo,
-                                                build_int_cst (NULL, integer_quo));
+                 tree result_quo
+                   = fold_build2 (MODIFY_EXPR, TREE_TYPE (arg_quo), arg_quo,
+                                  build_int_cst (TREE_TYPE (arg_quo),
+                                                 integer_quo));
                  TREE_SIDE_EFFECTS (result_quo) = 1;
                  /* Combine the quo assignment with the rem.  */
                  result = non_lvalue (fold_build2 (COMPOUND_EXPR, type,
@@ -13553,7 +13967,7 @@ do_mpfr_lgamma_r (tree arg, tree arg_sg, tree type)
              /* Assign the signgam value into *arg_sg. */
              result_sg = fold_build2 (MODIFY_EXPR,
                                       TREE_TYPE (arg_sg), arg_sg,
-                                      build_int_cst (NULL, sg));
+                                      build_int_cst (TREE_TYPE (arg_sg), sg));
              TREE_SIDE_EFFECTS (result_sg) = 1;
              /* Combine the signgam assignment with the lgamma result.  */
              result = non_lvalue (fold_build2 (COMPOUND_EXPR, type,
@@ -13794,7 +14208,7 @@ fold_call_stmt (gimple stmt, bool ignore)
   return NULL_TREE;
 }
 
-/* Look up the function in built_in_decls that corresponds to DECL
+/* Look up the function in builtin_decl that corresponds to DECL
    and set ASMSPEC as its user assembler name.  DECL must be a
    function decl that declares a builtin.  */
 
@@ -13806,7 +14220,7 @@ set_builtin_user_assembler_name (tree decl, const char *asmspec)
              && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
              && asmspec != 0);
 
-  builtin = built_in_decls [DECL_FUNCTION_CODE (decl)];
+  builtin = builtin_decl_explicit (DECL_FUNCTION_CODE (decl));
   set_user_assembler_name (builtin, asmspec);
   switch (DECL_FUNCTION_CODE (decl))
     {
@@ -13854,6 +14268,7 @@ is_simple_builtin (tree decl)
       case BUILT_IN_OBJECT_SIZE:
       case BUILT_IN_UNREACHABLE:
        /* Simple register moves or loads from stack.  */
+      case BUILT_IN_ASSUME_ALIGNED:
       case BUILT_IN_RETURN_ADDRESS:
       case BUILT_IN_EXTRACT_RETURN_ADDR:
       case BUILT_IN_FROB_RETURN_ADDR:
@@ -13891,6 +14306,7 @@ is_inexpensive_builtin (tree decl)
       {
       case BUILT_IN_ABS:
       case BUILT_IN_ALLOCA:
+      case BUILT_IN_ALLOCA_WITH_ALIGN:
       case BUILT_IN_BSWAP32:
       case BUILT_IN_BSWAP64:
       case BUILT_IN_CLZ: