gimple-fold.h (get_range_strlen): Update prototype.
[gcc.git] / gcc / builtins.c
index 2deef725620b69ae855f21037e0dfb5fbf0336cc..28155b8c0aa8678bd252685143479042da6f7728 100644 (file)
@@ -1,5 +1,5 @@
 /* Expand builtin functions.
-   Copyright (C) 1988-2017 Free Software Foundation, Inc.
+   Copyright (C) 1988-2019 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "memmodel.h"
 #include "gimple.h"
 #include "predict.h"
+#include "params.h"
 #include "tm_p.h"
 #include "stringpool.h"
 #include "tree-vrp.h"
@@ -43,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "alias.h"
 #include "fold-const.h"
 #include "fold-const-call.h"
+#include "gimple-ssa-warn-restrict.h"
 #include "stor-layout.h"
 #include "calls.h"
 #include "varasm.h"
@@ -60,14 +62,16 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "value-prof.h"
 #include "builtins.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
-#include "cilk.h"
-#include "tree-chkp.h"
-#include "rtl-chkp.h"
 #include "internal-fn.h"
 #include "case-cfn-macros.h"
 #include "gimple-fold.h"
 #include "intl.h"
+#include "file-prefix-map.h" /* remap_macro_filename()  */
+#include "gomp-constants.h"
+#include "omp-general.h"
 
 struct target_builtins default_target_builtins;
 #if SWITCHABLE_TARGET
@@ -91,7 +95,7 @@ builtin_info_type builtin_info[(int)END_BUILTINS];
 /* Non-zero if __builtin_constant_p should be folded right away.  */
 bool force_folding_builtin_constant_p;
 
-static rtx c_readstr (const char *, machine_mode);
+static rtx c_readstr (const char *, scalar_int_mode);
 static int target_char_cast (tree, char *);
 static rtx get_memory_rtx (tree, tree);
 static int apply_args_size (void);
@@ -115,36 +119,37 @@ static rtx expand_builtin_next_arg (void);
 static rtx expand_builtin_va_start (tree);
 static rtx expand_builtin_va_end (tree);
 static rtx expand_builtin_va_copy (tree);
+static rtx inline_expand_builtin_string_cmp (tree, rtx);
 static rtx expand_builtin_strcmp (tree, rtx);
 static rtx expand_builtin_strncmp (tree, rtx, machine_mode);
-static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, machine_mode);
+static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, scalar_int_mode);
 static rtx expand_builtin_memchr (tree, rtx);
 static rtx expand_builtin_memcpy (tree, rtx);
-static rtx expand_builtin_memcpy_with_bounds (tree, rtx);
-static rtx expand_builtin_memcpy_args (tree, tree, tree, rtx, tree);
+static rtx expand_builtin_memory_copy_args (tree dest, tree src, tree len,
+                                           rtx target, tree exp,
+                                           memop_ret retmode);
 static rtx expand_builtin_memmove (tree, rtx);
-static rtx expand_builtin_mempcpy (tree, rtx, machine_mode);
-static rtx expand_builtin_mempcpy_with_bounds (tree, rtx, machine_mode);
-static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx,
-                                       machine_mode, int, tree);
+static rtx expand_builtin_mempcpy (tree, rtx);
+static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx, tree, memop_ret);
 static rtx expand_builtin_strcat (tree, rtx);
 static rtx expand_builtin_strcpy (tree, rtx);
-static rtx expand_builtin_strcpy_args (tree, tree, rtx);
+static rtx expand_builtin_strcpy_args (tree, tree, tree, rtx);
 static rtx expand_builtin_stpcpy (tree, rtx, machine_mode);
 static rtx expand_builtin_stpncpy (tree, rtx);
 static rtx expand_builtin_strncat (tree, rtx);
 static rtx expand_builtin_strncpy (tree, rtx);
-static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, machine_mode);
+static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, scalar_int_mode);
 static rtx expand_builtin_memset (tree, rtx, machine_mode);
-static rtx expand_builtin_memset_with_bounds (tree, rtx, machine_mode);
 static rtx expand_builtin_memset_args (tree, tree, tree, rtx, machine_mode, tree);
 static rtx expand_builtin_bzero (tree);
 static rtx expand_builtin_strlen (tree, rtx, machine_mode);
+static rtx expand_builtin_strnlen (tree, rtx, machine_mode);
 static rtx expand_builtin_alloca (tree);
 static rtx expand_builtin_unop (machine_mode, tree, rtx, rtx, optab);
 static rtx expand_builtin_frame_address (tree, tree);
 static tree stabilize_va_list_loc (location_t, tree, int);
 static rtx expand_builtin_expect (tree, rtx);
+static rtx expand_builtin_expect_with_probability (tree, rtx);
 static tree fold_builtin_constant_p (tree);
 static tree fold_builtin_classify_type (tree);
 static tree fold_builtin_strlen (location_t, tree, tree);
@@ -201,22 +206,9 @@ is_builtin_name (const char *name)
     return true;
   if (strncmp (name, "__atomic_", 9) == 0)
     return true;
-  if (flag_cilkplus 
-      && (!strcmp (name, "__cilkrts_detach")   
-         || !strcmp (name, "__cilkrts_pop_frame")))
-    return true;
   return false;
 }
 
-
-/* Return true if DECL is a function symbol representing a built-in.  */
-
-bool
-is_builtin_fn (tree decl)
-{
-  return TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl);
-}
-
 /* Return true if NODE should be considered for inline expansion regardless
    of the optimization level.  This means whenever a function is invoked with
    its "internal" name, which normally contains the prefix "__builtin".  */
@@ -250,7 +242,7 @@ static bool
 get_object_alignment_2 (tree exp, unsigned int *alignp,
                        unsigned HOST_WIDE_INT *bitposp, bool addr_p)
 {
-  HOST_WIDE_INT bitsize, bitpos;
+  poly_int64 bitsize, bitpos;
   tree offset;
   machine_mode mode;
   int unsignedp, reversep, volatilep;
@@ -281,7 +273,7 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
       exp = DECL_INITIAL (exp);
       align = TYPE_ALIGN (TREE_TYPE (exp));
       if (CONSTANT_CLASS_P (exp))
-       align = (unsigned) CONSTANT_ALIGNMENT (exp, align);
+       align = targetm.constant_alignment (exp, align);
 
       known_alignment = true;
     }
@@ -348,7 +340,7 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
          bitpos += ptr_bitpos;
          if (TREE_CODE (exp) == MEM_REF
              || TREE_CODE (exp) == TARGET_MEM_REF)
-           bitpos += mem_ref_offset (exp).to_short_addr () * BITS_PER_UNIT;
+           bitpos += mem_ref_offset (exp).force_shwi () * BITS_PER_UNIT;
        }
     }
   else if (TREE_CODE (exp) == STRING_CST)
@@ -357,7 +349,7 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
          wrapped inside a CONST_DECL.  */
       align = TYPE_ALIGN (TREE_TYPE (exp));
       if (CONSTANT_CLASS_P (exp))
-       align = (unsigned) CONSTANT_ALIGNMENT (exp, align);
+       align = targetm.constant_alignment (exp, align);
 
       known_alignment = true;
     }
@@ -375,8 +367,17 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
        }
     }
 
+  /* Account for the alignment of runtime coefficients, so that the constant
+     bitpos is guaranteed to be accurate.  */
+  unsigned int alt_align = ::known_alignment (bitpos - bitpos.coeffs[0]);
+  if (alt_align != 0 && alt_align < align)
+    {
+      align = alt_align;
+      known_alignment = false;
+    }
+
   *alignp = align;
-  *bitposp = bitpos & (*alignp - 1);
+  *bitposp = bitpos.coeffs[0] & (align - 1);
   return known_alignment;
 }
 
@@ -509,11 +510,11 @@ get_pointer_alignment (tree exp)
   return align;
 }
 
-/* Return the number of non-zero elements in the sequence
+/* Return the number of leading non-zero elements in the sequence
    [ PTR, PTR + MAXELTS ) where each element's size is ELTSIZE bytes.
    ELTSIZE must be a power of 2 less than 8.  Used by c_strlen.  */
 
-static unsigned
+unsigned
 string_length (const void *ptr, unsigned eltsize, unsigned maxelts)
 {
   gcc_checking_assert (eltsize == 1 || eltsize == 2 || eltsize == 4);
@@ -542,6 +543,74 @@ string_length (const void *ptr, unsigned eltsize, unsigned maxelts)
   return n;
 }
 
+/* For a call at LOC to a function FN that expects a string in the argument
+   ARG, issue a diagnostic due to it being a called with an argument
+   declared at NONSTR that is a character array with no terminating NUL.  */
+
+void
+warn_string_no_nul (location_t loc, const char *fn, tree arg, tree decl)
+{
+  if (TREE_NO_WARNING (arg))
+    return;
+
+  loc = expansion_point_location_if_in_system_header (loc);
+
+  if (warning_at (loc, OPT_Wstringop_overflow_,
+                 "%qs argument missing terminating nul", fn))
+    {
+      inform (DECL_SOURCE_LOCATION (decl),
+             "referenced argument declared here");
+      TREE_NO_WARNING (arg) = 1;
+    }
+}
+
+/* If EXP refers to an unterminated constant character array return
+   the declaration of the object of which the array is a member or
+   element and if SIZE is not null, set *SIZE to the size of
+   the unterminated array and set *EXACT if the size is exact or
+   clear it otherwise.  Otherwise return null.  */
+
+tree
+unterminated_array (tree exp, tree *size /* = NULL */, bool *exact /* = NULL */)
+{
+  /* C_STRLEN will return NULL and set DECL in the info
+     structure if EXP references a unterminated array.  */
+  c_strlen_data lendata = { };
+  tree len = c_strlen (exp, 1, &lendata);
+  if (len == NULL_TREE && lendata.minlen && lendata.decl)
+     {
+       if (size)
+       {
+         len = lendata.minlen;
+         if (lendata.off)
+           {
+             /* Constant offsets are already accounted for in LENDATA.MINLEN,
+                but not in a SSA_NAME + CST expression.  */
+             if (TREE_CODE (lendata.off) == INTEGER_CST)
+               *exact = true;
+             else if (TREE_CODE (lendata.off) == PLUS_EXPR
+                      && TREE_CODE (TREE_OPERAND (lendata.off, 1)) == INTEGER_CST)
+               {
+                 /* Subtract the offset from the size of the array.  */
+                 *exact = false;
+                 tree temp = TREE_OPERAND (lendata.off, 1);
+                 temp = fold_convert (ssizetype, temp);
+                 len = fold_build2 (MINUS_EXPR, ssizetype, len, temp);
+               }
+             else
+               *exact = false;
+           }
+         else
+           *exact = true;
+
+         *size = len;
+       }
+       return lendata.decl;
+     }
+
+  return NULL_TREE;
+}
+
 /* Compute the length of a null-terminated character string or wide
    character string handling character sizes of 1, 2, and 4 bytes.
    TREE_STRING_LENGTH is not the right way because it evaluates to
@@ -559,45 +628,72 @@ string_length (const void *ptr, unsigned eltsize, unsigned maxelts)
    accesses.  Note that this implies the result is not going to be emitted
    into the instruction stream.
 
-   The value returned is of type `ssizetype'.
+   Additional information about the string accessed may be recorded
+   in DATA.  For example, if SRC references an unterminated string,
+   then the declaration will be stored in the DECL field.   If the
+   length of the unterminated string can be determined, it'll be
+   stored in the LEN field.  Note this length could well be different
+   than what a C strlen call would return.
 
-   Unfortunately, string_constant can't access the values of const char
-   arrays with initializers, so neither can we do so here.  */
+   ELTSIZE is 1 for normal single byte character strings, and 2 or
+   4 for wide characer strings.  ELTSIZE is by default 1.
+
+   The value returned is of type `ssizetype'.  */
 
 tree
-c_strlen (tree src, int only_value)
+c_strlen (tree src, int only_value, c_strlen_data *data, unsigned eltsize)
 {
+  /* If we were not passed a DATA pointer, then get one to a local
+     structure.  That avoids having to check DATA for NULL before
+     each time we want to use it.  */
+  c_strlen_data local_strlen_data = { };
+  if (!data)
+    data = &local_strlen_data;
+
+  gcc_checking_assert (eltsize == 1 || eltsize == 2 || eltsize == 4);
   STRIP_NOPS (src);
   if (TREE_CODE (src) == COND_EXPR
       && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
     {
       tree len1, len2;
 
-      len1 = c_strlen (TREE_OPERAND (src, 1), only_value);
-      len2 = c_strlen (TREE_OPERAND (src, 2), only_value);
+      len1 = c_strlen (TREE_OPERAND (src, 1), only_value, data, eltsize);
+      len2 = c_strlen (TREE_OPERAND (src, 2), only_value, data, eltsize);
       if (tree_int_cst_equal (len1, len2))
        return len1;
     }
 
   if (TREE_CODE (src) == COMPOUND_EXPR
       && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
-    return c_strlen (TREE_OPERAND (src, 1), only_value);
+    return c_strlen (TREE_OPERAND (src, 1), only_value, data, eltsize);
 
   location_t loc = EXPR_LOC_OR_LOC (src, input_location);
 
   /* Offset from the beginning of the string in bytes.  */
   tree byteoff;
-  src = string_constant (src, &byteoff);
+  tree memsize;
+  tree decl;
+  src = string_constant (src, &byteoff, &memsize, &decl);
   if (src == 0)
     return NULL_TREE;
 
   /* Determine the size of the string element.  */
-  unsigned eltsize
-    = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (src))));
+  if (eltsize != tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (src)))))
+    return NULL_TREE;
 
   /* Set MAXELTS to sizeof (SRC) / sizeof (*SRC) - 1, the maximum possible
-     length of SRC.  */
-  unsigned maxelts = TREE_STRING_LENGTH (src) / eltsize - 1;
+     length of SRC.  Prefer TYPE_SIZE() to TREE_STRING_LENGTH() if possible
+     in case the latter is less than the size of the array, such as when
+     SRC refers to a short string literal used to initialize a large array.
+     In that case, the elements of the array after the terminating NUL are
+     all NUL.  */
+  HOST_WIDE_INT strelts = TREE_STRING_LENGTH (src);
+  strelts = strelts / eltsize;
+
+  if (!tree_fits_uhwi_p (memsize))
+    return NULL_TREE;
+
+  HOST_WIDE_INT maxelts = tree_to_uhwi (memsize) / eltsize;
 
   /* PTR can point to the byte representation of any string type, including
      char* and wchar_t*.  */
@@ -605,23 +701,48 @@ c_strlen (tree src, int only_value)
 
   if (byteoff && TREE_CODE (byteoff) != INTEGER_CST)
     {
-      /* If the string has an internal zero byte (e.g., "foo\0bar"), we can't
-        compute the offset to the following null if we don't know where to
+      /* The code below works only for single byte character types.  */
+      if (eltsize != 1)
+       return NULL_TREE;
+
+      /* If the string has an internal NUL character followed by any
+        non-NUL characters (e.g., "foo\0bar"), we can't compute
+        the offset to the following NUL if we don't know where to
         start searching for it.  */
-      if (string_length (ptr, eltsize, maxelts) < maxelts)
+      unsigned len = string_length (ptr, eltsize, strelts);
+
+      /* Return when an embedded null character is found or none at all.
+        In the latter case, set the DECL/LEN field in the DATA structure
+        so that callers may examine them.  */
+      if (len + 1 < strelts)
+       return NULL_TREE;
+      else if (len >= maxelts)
        {
-         /* Return when an embedded null character is found.  */
+         data->decl = decl;
+         data->off = byteoff;
+         data->minlen = ssize_int (len);
          return NULL_TREE;
        }
 
-      /* We don't know the starting offset, but we do know that the string
-        has no internal zero bytes.  We can assume that the offset falls
-        within the bounds of the string; otherwise, the programmer deserves
-        what he gets.  Subtract the offset from the length of the string,
-        and return that.  This would perhaps not be valid if we were dealing
-        with named arrays in addition to literal string constants.  */
+      /* For empty strings the result should be zero.  */
+      if (len == 0)
+       return ssize_int (0);
 
-      return size_diffop_loc (loc, size_int (maxelts * eltsize), byteoff);
+      /* We don't know the starting offset, but we do know that the string
+        has no internal zero bytes.  If the offset falls within the bounds
+        of the string subtract the offset from the length of the string,
+        and return that.  Otherwise the length is zero.  Take care to
+        use SAVE_EXPR in case the OFFSET has side-effects.  */
+      tree offsave = TREE_SIDE_EFFECTS (byteoff) ? save_expr (byteoff)
+                                                : byteoff;
+      offsave = fold_convert_loc (loc, sizetype, offsave);
+      tree condexp = fold_build2_loc (loc, LE_EXPR, boolean_type_node, offsave,
+                                     size_int (len));
+      tree lenexp = fold_build2_loc (loc, MINUS_EXPR, sizetype, size_int (len),
+                                    offsave);
+      lenexp = fold_convert_loc (loc, ssizetype, lenexp);
+      return fold_build3_loc (loc, COND_EXPR, ssizetype, condexp, lenexp,
+                             build_zero_cst (ssizetype));
     }
 
   /* Offset from the beginning of the string in elements.  */
@@ -631,26 +752,32 @@ c_strlen (tree src, int only_value)
      a null character if we can represent it as a single HOST_WIDE_INT.  */
   if (byteoff == 0)
     eltoff = 0;
-  else if (! tree_fits_shwi_p (byteoff))
+  else if (! tree_fits_uhwi_p (byteoff) || tree_to_uhwi (byteoff) % eltsize)
     eltoff = -1;
   else
-    eltoff = tree_to_shwi (byteoff) / eltsize;
+    eltoff = tree_to_uhwi (byteoff) / eltsize;
 
   /* If the offset is known to be out of bounds, warn, and call strlen at
      runtime.  */
-  if (eltoff < 0 || eltoff > maxelts)
+  if (eltoff < 0 || eltoff >= maxelts)
     {
      /* Suppress multiple warnings for propagated constant strings.  */
       if (only_value != 2
          && !TREE_NO_WARNING (src))
         {
-         warning_at (loc, 0, "offset %qwi outside bounds of constant string",
+         warning_at (loc, OPT_Warray_bounds,
+                     "offset %qwi outside bounds of constant string",
                      eltoff);
           TREE_NO_WARNING (src) = 1;
         }
       return NULL_TREE;
     }
 
+  /* If eltoff is larger than strelts but less than maxelts the
+     string length is zero, since the excess memory will be zero.  */
+  if (eltoff > strelts)
+    return ssize_int (0);
+
   /* Use strlen to search for the first zero byte.  Since any strings
      constructed with build_string will have nulls appended, we win even
      if we get handed something like (char[4])"abcd".
@@ -658,7 +785,18 @@ c_strlen (tree src, int only_value)
      Since ELTOFF is our starting index into the string, no further
      calculation is needed.  */
   unsigned len = string_length (ptr + eltoff * eltsize, eltsize,
-                               maxelts - eltoff);
+                               strelts - eltoff);
+
+  /* Don't know what to return if there was no zero termination.
+     Ideally this would turn into a gcc_checking_assert over time.
+     Set DECL/LEN so callers can examine them.  */
+  if (len >= maxelts - eltoff)
+    {
+      data->decl = decl;
+      data->off = byteoff;
+      data->minlen = ssize_int (len);
+      return NULL_TREE;
+    }
 
   return ssize_int (len);
 }
@@ -667,7 +805,7 @@ c_strlen (tree src, int only_value)
    GET_MODE_BITSIZE (MODE) bits from string constant STR.  */
 
 static rtx
-c_readstr (const char *str, machine_mode mode)
+c_readstr (const char *str, scalar_int_mode mode)
 {
   HOST_WIDE_INT ch;
   unsigned int i, j;
@@ -880,7 +1018,7 @@ expand_builtin_setjmp_receiver (rtx receiver_label)
 
   /* Mark the static chain as clobbered here so life information
      doesn't get messed up for it.  */
-  chain = targetm.calls.static_chain (current_function_decl, true);
+  chain = rtx_for_static_chain (current_function_decl, true);
   if (chain && REG_P (chain))
     emit_clobber (chain);
 
@@ -898,7 +1036,7 @@ expand_builtin_setjmp_receiver (rtx receiver_label)
         to the underlying register (fp in this case) that makes
         the original assignment true.
         So the following insn will actually be decrementing fp by
-        STARTING_FRAME_OFFSET.  */
+        TARGET_STARTING_FRAME_OFFSET.  */
       emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
 
       /* Restoring the frame pointer also modifies the hard frame pointer.
@@ -1003,8 +1141,11 @@ expand_builtin_longjmp (rtx buf_addr, rtx value)
          emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
          emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
 
-         emit_move_insn (hard_frame_pointer_rtx, fp);
+         /* Restore the frame pointer and stack pointer.  We must use a
+            temporary since the setjmp buffer may be a local.  */
+         fp = copy_to_reg (fp);
          emit_stack_restore (SAVE_NONLOCAL, stack);
+         emit_move_insn (hard_frame_pointer_rtx, fp);
 
          emit_use (hard_frame_pointer_rtx);
          emit_use (stack_pointer_rtx);
@@ -1147,9 +1288,11 @@ 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.  */
-      emit_move_insn (hard_frame_pointer_rtx, r_fp);
+      /* Restore the frame pointer and stack pointer.  We must use a
+        temporary since the setjmp buffer may be a local.  */
+      r_fp = copy_to_reg (r_fp);
       emit_stack_restore (SAVE_NONLOCAL, r_sp);
+      emit_move_insn (hard_frame_pointer_rtx, r_fp);
 
       /* USE of hard_frame_pointer_rtx added for consistency;
         not clear if really needed.  */
@@ -1197,6 +1340,7 @@ void
 expand_builtin_update_setjmp_buf (rtx buf_addr)
 {
   machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
+  buf_addr = convert_memory_address (Pmode, buf_addr);
   rtx stack_save
     = gen_rtx_MEM (sa_mode,
                   memory_address
@@ -1356,7 +1500,6 @@ apply_args_size (void)
   static int size = -1;
   int align;
   unsigned int regno;
-  machine_mode mode;
 
   /* The values computed by this function never change.  */
   if (size < 0)
@@ -1372,7 +1515,7 @@ apply_args_size (void)
       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
        if (FUNCTION_ARG_REGNO_P (regno))
          {
-           mode = targetm.calls.get_raw_arg_mode (regno);
+           fixed_size_mode mode = targetm.calls.get_raw_arg_mode (regno);
 
            gcc_assert (mode != VOIDmode);
 
@@ -1384,7 +1527,7 @@ apply_args_size (void)
          }
        else
          {
-           apply_args_mode[regno] = VOIDmode;
+           apply_args_mode[regno] = as_a <fixed_size_mode> (VOIDmode);
          }
     }
   return size;
@@ -1398,7 +1541,6 @@ apply_result_size (void)
 {
   static int size = -1;
   int align, regno;
-  machine_mode mode;
 
   /* The values computed by this function never change.  */
   if (size < 0)
@@ -1408,7 +1550,7 @@ apply_result_size (void)
       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
        if (targetm.calls.function_value_regno_p (regno))
          {
-           mode = targetm.calls.get_raw_result_mode (regno);
+           fixed_size_mode mode = targetm.calls.get_raw_result_mode (regno);
 
            gcc_assert (mode != VOIDmode);
 
@@ -1419,7 +1561,7 @@ apply_result_size (void)
            apply_result_mode[regno] = mode;
          }
        else
-         apply_result_mode[regno] = VOIDmode;
+         apply_result_mode[regno] = as_a <fixed_size_mode> (VOIDmode);
 
       /* Allow targets that use untyped_call and untyped_return to override
         the size so that machine-specific information can be stored here.  */
@@ -1438,7 +1580,7 @@ static rtx
 result_vector (int savep, rtx result)
 {
   int regno, size, align, nelts;
-  machine_mode mode;
+  fixed_size_mode mode;
   rtx reg, mem;
   rtx *savevec = XALLOCAVEC (rtx, FIRST_PSEUDO_REGISTER);
 
@@ -1467,7 +1609,7 @@ expand_builtin_apply_args_1 (void)
 {
   rtx registers, tem;
   int size, align, regno;
-  machine_mode mode;
+  fixed_size_mode mode;
   rtx struct_incoming_value = targetm.calls.struct_value_rtx (cfun ? TREE_TYPE (cfun->decl) : 0, 1);
 
   /* Create a block where the arg-pointer, structure value address,
@@ -1571,7 +1713,7 @@ static rtx
 expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
 {
   int size, align, regno;
-  machine_mode mode;
+  fixed_size_mode mode;
   rtx incoming_args, result, reg, dest, src;
   rtx_call_insn *call_insn;
   rtx old_stack_level = 0;
@@ -1606,7 +1748,7 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
      arguments to the outgoing arguments address.  We can pass TRUE
      as the 4th argument because we just saved the stack pointer
      and will restore it right after the call.  */
-  allocate_dynamic_stack_space (argsize, 0, BIGGEST_ALIGNMENT, true);
+  allocate_dynamic_stack_space (argsize, 0, BIGGEST_ALIGNMENT, -1, true);
 
   /* Set DRAP flag to true, even though allocate_dynamic_stack_space
      may have already set current_function_calls_alloca to true.
@@ -1732,7 +1874,7 @@ static void
 expand_builtin_return (rtx result)
 {
   int size, align, regno;
-  machine_mode mode;
+  fixed_size_mode mode;
   rtx reg;
   rtx_insn *call_fusage = 0;
 
@@ -1813,14 +1955,26 @@ expand_builtin_classify_type (tree exp)
   return GEN_INT (no_type_class);
 }
 
-/* This helper macro, meant to be used in mathfn_built_in below,
-   determines which among a set of three builtin math functions is
-   appropriate for a given type mode.  The `F' and `L' cases are
-   automatically generated from the `double' case.  */
+/* This helper macro, meant to be used in mathfn_built_in below, determines
+   which among a set of builtin math functions is appropriate for a given type
+   mode.  The `F' (float) and `L' (long double) are automatically generated
+   from the 'double' case.  If a function supports the _Float<N> and _Float<N>X
+   types, there are additional types that are considered with 'F32', 'F64',
+   'F128', etc. suffixes.  */
 #define CASE_MATHFN(MATHFN) \
   CASE_CFN_##MATHFN: \
   fcode = BUILT_IN_##MATHFN; fcodef = BUILT_IN_##MATHFN##F ; \
   fcodel = BUILT_IN_##MATHFN##L ; break;
+/* Similar to the above, but also add support for the _Float<N> and _Float<N>X
+   types.  */
+#define CASE_MATHFN_FLOATN(MATHFN) \
+  CASE_CFN_##MATHFN: \
+  fcode = BUILT_IN_##MATHFN; fcodef = BUILT_IN_##MATHFN##F ; \
+  fcodel = BUILT_IN_##MATHFN##L ; fcodef16 = BUILT_IN_##MATHFN##F16 ; \
+  fcodef32 = BUILT_IN_##MATHFN##F32; fcodef64 = BUILT_IN_##MATHFN##F64 ; \
+  fcodef128 = BUILT_IN_##MATHFN##F128 ; fcodef32x = BUILT_IN_##MATHFN##F32X ; \
+  fcodef64x = BUILT_IN_##MATHFN##F64X ; fcodef128x = BUILT_IN_##MATHFN##F128X ;\
+  break;
 /* Similar to above, but appends _R after any F/L suffix.  */
 #define CASE_MATHFN_REENT(MATHFN) \
   case CFN_BUILT_IN_##MATHFN##_R: \
@@ -1837,7 +1991,15 @@ expand_builtin_classify_type (tree exp)
 static built_in_function
 mathfn_built_in_2 (tree type, combined_fn fn)
 {
+  tree mtype;
   built_in_function fcode, fcodef, fcodel;
+  built_in_function fcodef16 = END_BUILTINS;
+  built_in_function fcodef32 = END_BUILTINS;
+  built_in_function fcodef64 = END_BUILTINS;
+  built_in_function fcodef128 = END_BUILTINS;
+  built_in_function fcodef32x = END_BUILTINS;
+  built_in_function fcodef64x = END_BUILTINS;
+  built_in_function fcodef128x = END_BUILTINS;
 
   switch (fn)
     {
@@ -1849,9 +2011,9 @@ mathfn_built_in_2 (tree type, combined_fn fn)
     CASE_MATHFN (ATAN2)
     CASE_MATHFN (ATANH)
     CASE_MATHFN (CBRT)
-    CASE_MATHFN (CEIL)
+    CASE_MATHFN_FLOATN (CEIL)
     CASE_MATHFN (CEXPI)
-    CASE_MATHFN (COPYSIGN)
+    CASE_MATHFN_FLOATN (COPYSIGN)
     CASE_MATHFN (COS)
     CASE_MATHFN (COSH)
     CASE_MATHFN (DREM)
@@ -1863,10 +2025,10 @@ mathfn_built_in_2 (tree type, combined_fn fn)
     CASE_MATHFN (EXPM1)
     CASE_MATHFN (FABS)
     CASE_MATHFN (FDIM)
-    CASE_MATHFN (FLOOR)
-    CASE_MATHFN (FMA)
-    CASE_MATHFN (FMAX)
-    CASE_MATHFN (FMIN)
+    CASE_MATHFN_FLOATN (FLOOR)
+    CASE_MATHFN_FLOATN (FMA)
+    CASE_MATHFN_FLOATN (FMAX)
+    CASE_MATHFN_FLOATN (FMIN)
     CASE_MATHFN (FMOD)
     CASE_MATHFN (FREXP)
     CASE_MATHFN (GAMMA)
@@ -1902,7 +2064,7 @@ mathfn_built_in_2 (tree type, combined_fn fn)
     CASE_MATHFN (MODF)
     CASE_MATHFN (NAN)
     CASE_MATHFN (NANS)
-    CASE_MATHFN (NEARBYINT)
+    CASE_MATHFN_FLOATN (NEARBYINT)
     CASE_MATHFN (NEXTAFTER)
     CASE_MATHFN (NEXTTOWARD)
     CASE_MATHFN (POW)
@@ -1910,8 +2072,8 @@ mathfn_built_in_2 (tree type, combined_fn fn)
     CASE_MATHFN (POW10)
     CASE_MATHFN (REMAINDER)
     CASE_MATHFN (REMQUO)
-    CASE_MATHFN (RINT)
-    CASE_MATHFN (ROUND)
+    CASE_MATHFN_FLOATN (RINT)
+    CASE_MATHFN_FLOATN (ROUND)
     CASE_MATHFN (SCALB)
     CASE_MATHFN (SCALBLN)
     CASE_MATHFN (SCALBN)
@@ -1920,11 +2082,11 @@ mathfn_built_in_2 (tree type, combined_fn fn)
     CASE_MATHFN (SIN)
     CASE_MATHFN (SINCOS)
     CASE_MATHFN (SINH)
-    CASE_MATHFN (SQRT)
+    CASE_MATHFN_FLOATN (SQRT)
     CASE_MATHFN (TAN)
     CASE_MATHFN (TANH)
     CASE_MATHFN (TGAMMA)
-    CASE_MATHFN (TRUNC)
+    CASE_MATHFN_FLOATN (TRUNC)
     CASE_MATHFN (Y0)
     CASE_MATHFN (Y1)
     CASE_MATHFN (YN)
@@ -1933,12 +2095,27 @@ mathfn_built_in_2 (tree type, combined_fn fn)
       return END_BUILTINS;
     }
 
-  if (TYPE_MAIN_VARIANT (type) == double_type_node)
+  mtype = TYPE_MAIN_VARIANT (type);
+  if (mtype == double_type_node)
     return fcode;
-  else if (TYPE_MAIN_VARIANT (type) == float_type_node)
+  else if (mtype == float_type_node)
     return fcodef;
-  else if (TYPE_MAIN_VARIANT (type) == long_double_type_node)
+  else if (mtype == long_double_type_node)
     return fcodel;
+  else if (mtype == float16_type_node)
+    return fcodef16;
+  else if (mtype == float32_type_node)
+    return fcodef32;
+  else if (mtype == float64_type_node)
+    return fcodef64;
+  else if (mtype == float128_type_node)
+    return fcodef128;
+  else if (mtype == float32x_type_node)
+    return fcodef32x;
+  else if (mtype == float64x_type_node)
+    return fcodef64x;
+  else if (mtype == float128x_type_node)
+    return fcodef128x;
   else
     return END_BUILTINS;
 }
@@ -1992,6 +2169,9 @@ associated_internal_fn (tree fndecl)
     {
 #define DEF_INTERNAL_FLT_FN(NAME, FLAGS, OPTAB, TYPE) \
     CASE_FLT_FN (BUILT_IN_##NAME): return IFN_##NAME;
+#define DEF_INTERNAL_FLT_FLOATN_FN(NAME, FLAGS, OPTAB, TYPE) \
+    CASE_FLT_FN (BUILT_IN_##NAME): return IFN_##NAME; \
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_##NAME): return IFN_##NAME;
 #define DEF_INTERNAL_INT_FN(NAME, FLAGS, OPTAB, TYPE) \
     CASE_INT_FN (BUILT_IN_##NAME): return IFN_##NAME;
 #include "internal-fn.def"
@@ -2065,6 +2245,7 @@ expand_builtin_mathfn_ternary (tree exp, rtx target, rtx subtarget)
   switch (DECL_FUNCTION_CODE (fndecl))
     {
     CASE_FLT_FN (BUILT_IN_FMA):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_FMA):
       builtin_optab = fma_optab; break;
     default:
       gcc_unreachable ();
@@ -2753,7 +2934,7 @@ expand_builtin_powi (tree exp, rtx target)
   /* Emit a libcall to libgcc.  */
 
   /* Mode of the 2nd argument must match that of an int.  */
-  mode2 = mode_for_size (INT_TYPE_SIZE, MODE_INT, 0);
+  mode2 = int_mode_for_size (INT_TYPE_SIZE, 0).require ();
 
   if (target == NULL_RTX)
     target = gen_reg_rtx (mode);
@@ -2766,14 +2947,14 @@ expand_builtin_powi (tree exp, rtx target)
     op1 = convert_to_mode (mode2, op1, 0);
 
   target = emit_library_call_value (optab_libfunc (powi_optab, mode),
-                                   target, LCT_CONST, mode, 2,
+                                   target, LCT_CONST, mode,
                                    op0, mode, op1, mode2);
 
   return target;
 }
 
 /* Expand expression EXP which is a call to the strlen builtin.  Return
-   NULL_RTX if we failed the caller should emit a normal call, otherwise
+   NULL_RTX if we failed and the caller should emit a normal call, otherwise
    try to get the result in TARGET, if convenient.  */
 
 static rtx
@@ -2782,99 +2963,238 @@ expand_builtin_strlen (tree exp, rtx target,
 {
   if (!validate_arglist (exp, POINTER_TYPE, VOID_TYPE))
     return NULL_RTX;
+
+  struct expand_operand ops[4];
+  rtx pat;
+  tree len;
+  tree src = CALL_EXPR_ARG (exp, 0);
+  rtx src_reg;
+  rtx_insn *before_strlen;
+  machine_mode insn_mode;
+  enum insn_code icode = CODE_FOR_nothing;
+  unsigned int align;
+
+  /* If the length can be computed at compile-time, return it.  */
+  len = c_strlen (src, 0);
+  if (len)
+    return expand_expr (len, target, target_mode, EXPAND_NORMAL);
+
+  /* If the length can be computed at compile-time and is constant
+     integer, but there are side-effects in src, evaluate
+     src for side-effects, then return len.
+     E.g. x = strlen (i++ ? "xfoo" + 1 : "bar");
+     can be optimized into: i++; x = 3;  */
+  len = c_strlen (src, 1);
+  if (len && TREE_CODE (len) == INTEGER_CST)
+    {
+      expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
+      return expand_expr (len, target, target_mode, EXPAND_NORMAL);
+    }
+
+  align = get_pointer_alignment (src) / BITS_PER_UNIT;
+
+  /* If SRC is not a pointer type, don't do this operation inline.  */
+  if (align == 0)
+    return NULL_RTX;
+
+  /* Bail out if we can't compute strlen in the right mode.  */
+  FOR_EACH_MODE_FROM (insn_mode, target_mode)
+    {
+      icode = optab_handler (strlen_optab, insn_mode);
+      if (icode != CODE_FOR_nothing)
+       break;
+    }
+  if (insn_mode == VOIDmode)
+    return NULL_RTX;
+
+  /* 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.  */
+  src_reg = gen_reg_rtx (Pmode);
+
+  /* Mark the beginning of the strlen sequence so we can emit the
+     source operand later.  */
+  before_strlen = get_last_insn ();
+
+  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;
+
+  /* Check to see if the argument was declared attribute nonstring
+     and if so, issue a warning since at this point it's not known
+     to be nul-terminated.  */
+  maybe_warn_nonstring_arg (get_callee_fndecl (exp), exp);
+
+  /* Now that we are assured of success, expand the source.  */
+  start_sequence ();
+  pat = expand_expr (src, src_reg, Pmode, EXPAND_NORMAL);
+  if (pat != src_reg)
+    {
+#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 ();
+
+  if (before_strlen)
+    emit_insn_after (pat, before_strlen);
+  else
+    emit_insn_before (pat, get_insns ());
+
+  /* Return the value in the proper mode for this function.  */
+  if (GET_MODE (ops[0].value) == target_mode)
+    target = ops[0].value;
+  else if (target != 0)
+    convert_move (target, ops[0].value, 0);
   else
+    target = convert_to_mode (target_mode, ops[0].value, 0);
+
+  return target;
+}
+
+/* Expand call EXP to the strnlen built-in, returning the result
+   and setting it in TARGET.  Otherwise return NULL_RTX on failure.  */
+
+static rtx
+expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
+{
+  if (!validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+    return NULL_RTX;
+
+  tree src = CALL_EXPR_ARG (exp, 0);
+  tree bound = CALL_EXPR_ARG (exp, 1);
+
+  if (!bound)
+    return NULL_RTX;
+
+  location_t loc = UNKNOWN_LOCATION;
+  if (EXPR_HAS_LOCATION (exp))
+    loc = EXPR_LOCATION (exp);
+
+  tree maxobjsize = max_object_size ();
+  tree func = get_callee_fndecl (exp);
+
+  /* FIXME: Change c_strlen() to return sizetype instead of ssizetype
+     so these conversions aren't necessary.  */
+  c_strlen_data lendata = { };
+  tree len = c_strlen (src, 0, &lendata, 1);
+  if (len)
+    len = fold_convert_loc (loc, TREE_TYPE (bound), len);
+
+  if (TREE_CODE (bound) == INTEGER_CST)
     {
-      struct expand_operand ops[4];
-      rtx pat;
-      tree len;
-      tree src = CALL_EXPR_ARG (exp, 0);
-      rtx src_reg;
-      rtx_insn *before_strlen;
-      machine_mode insn_mode = target_mode;
-      enum insn_code icode = CODE_FOR_nothing;
-      unsigned int align;
+      if (!TREE_NO_WARNING (exp)
+         && tree_int_cst_lt (maxobjsize, bound)
+         && warning_at (loc, OPT_Wstringop_overflow_,
+                        "%K%qD specified bound %E "
+                        "exceeds maximum object size %E",
+                        exp, func, bound, maxobjsize))
+         TREE_NO_WARNING (exp) = true;
 
-      /* If the length can be computed at compile-time, return it.  */
-      len = c_strlen (src, 0);
-      if (len)
-       return expand_expr (len, target, target_mode, EXPAND_NORMAL);
-
-      /* If the length can be computed at compile-time and is constant
-        integer, but there are side-effects in src, evaluate
-        src for side-effects, then return len.
-        E.g. x = strlen (i++ ? "xfoo" + 1 : "bar");
-        can be optimized into: i++; x = 3;  */
-      len = c_strlen (src, 1);
-      if (len && TREE_CODE (len) == INTEGER_CST)
+      bool exact = true;
+      if (!len || TREE_CODE (len) != INTEGER_CST)
        {
-         expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
-         return expand_expr (len, target, target_mode, EXPAND_NORMAL);
+         /* Clear EXACT if LEN may be less than SRC suggests,
+            such as in
+              strnlen (&a[i], sizeof a)
+            where the value of i is unknown.  Unless i's value is
+            zero, the call is unsafe because the bound is greater. */
+         lendata.decl = unterminated_array (src, &len, &exact);
+         if (!lendata.decl)
+           return NULL_RTX;
        }
 
-      align = get_pointer_alignment (src) / BITS_PER_UNIT;
+      if (lendata.decl
+         && !TREE_NO_WARNING (exp)
+         && ((tree_int_cst_lt (len, bound))
+             || !exact))
+       {
+         location_t warnloc
+           = expansion_point_location_if_in_system_header (loc);
+
+         if (warning_at (warnloc, OPT_Wstringop_overflow_,
+                         exact
+                         ? G_("%K%qD specified bound %E exceeds the size %E "
+                              "of unterminated array")
+                         : G_("%K%qD specified bound %E may exceed the size "
+                              "of at most %E of unterminated array"),
+                         exp, func, bound, len))
+           {
+             inform (DECL_SOURCE_LOCATION (lendata.decl),
+                     "referenced argument declared here");
+             TREE_NO_WARNING (exp) = true;
+             return NULL_RTX;
+           }
+       }
 
-      /* If SRC is not a pointer type, don't do this operation inline.  */
-      if (align == 0)
+      if (!len)
        return NULL_RTX;
 
-      /* Bail out if we can't compute strlen in the right mode.  */
-      while (insn_mode != VOIDmode)
-       {
-         icode = optab_handler (strlen_optab, insn_mode);
-         if (icode != CODE_FOR_nothing)
-           break;
+      len = fold_build2_loc (loc, MIN_EXPR, size_type_node, len, bound);
+      return expand_expr (len, target, target_mode, EXPAND_NORMAL);
+    }
 
-         insn_mode = GET_MODE_WIDER_MODE (insn_mode);
-       }
-      if (insn_mode == VOIDmode)
-       return NULL_RTX;
+  if (TREE_CODE (bound) != SSA_NAME)
+    return NULL_RTX;
 
-      /* 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.  */
-      src_reg = gen_reg_rtx (Pmode);
+  wide_int min, max;
+  enum value_range_kind rng = get_range_info (bound, &min, &max);
+  if (rng != VR_RANGE)
+    return NULL_RTX;
 
-      /* Mark the beginning of the strlen sequence so we can emit the
-        source operand later.  */
-      before_strlen = get_last_insn ();
+  if (!TREE_NO_WARNING (exp)
+      && wi::ltu_p (wi::to_wide (maxobjsize), min)
+      && warning_at (loc, OPT_Wstringop_overflow_,
+                    "%K%qD specified bound [%wu, %wu] "
+                    "exceeds maximum object size %E",
+                    exp, func, min.to_uhwi (), max.to_uhwi (), maxobjsize))
+      TREE_NO_WARNING (exp) = true;
 
-      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))
+  bool exact = true;
+  if (!len || TREE_CODE (len) != INTEGER_CST)
+    {
+      lendata.decl = unterminated_array (src, &len, &exact);
+      if (!lendata.decl)
        return NULL_RTX;
+    }
 
-      /* Now that we are assured of success, expand the source.  */
-      start_sequence ();
-      pat = expand_expr (src, src_reg, Pmode, EXPAND_NORMAL);
-      if (pat != src_reg)
+  if (lendata.decl
+      && !TREE_NO_WARNING (exp)
+      && (wi::ltu_p (wi::to_wide (len), min)
+         || !exact))
+    {
+      location_t warnloc
+       = expansion_point_location_if_in_system_header (loc);
+
+      if (warning_at (warnloc, OPT_Wstringop_overflow_,
+                     exact
+                     ? G_("%K%qD specified bound [%wu, %wu] exceeds "
+                          "the size %E of unterminated array")
+                     : G_("%K%qD specified bound [%wu, %wu] may exceed "
+                          "the size of at most %E of unterminated array"),
+                     exp, func, min.to_uhwi (), max.to_uhwi (), len))
        {
-#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);
+         inform (DECL_SOURCE_LOCATION (lendata.decl),
+                 "referenced argument declared here");
+         TREE_NO_WARNING (exp) = true;
        }
-      pat = get_insns ();
-      end_sequence ();
+    }
 
-      if (before_strlen)
-       emit_insn_after (pat, before_strlen);
-      else
-       emit_insn_before (pat, get_insns ());
+  if (lendata.decl)
+    return NULL_RTX;
 
-      /* Return the value in the proper mode for this function.  */
-      if (GET_MODE (ops[0].value) == target_mode)
-       target = ops[0].value;
-      else if (target != 0)
-       convert_move (target, ops[0].value, 0);
-      else
-       target = convert_to_mode (target_mode, ops[0].value, 0);
+  if (wi::gtu_p (min, wi::to_wide (len)))
+    return expand_expr (len, target, target_mode, EXPAND_NORMAL);
 
-      return target;
-    }
+  len = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (len), len, bound);
+  return expand_expr (len, target, target_mode, EXPAND_NORMAL);
 }
 
 /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
@@ -2883,7 +3203,7 @@ expand_builtin_strlen (tree exp, rtx target,
 
 static rtx
 builtin_memcpy_read_str (void *data, HOST_WIDE_INT offset,
-                        machine_mode mode)
+                        scalar_int_mode mode)
 {
   const char *str = (const char *) data;
 
@@ -2913,7 +3233,7 @@ determine_block_size (tree len, rtx len_rtx,
   else
     {
       wide_int min, max;
-      enum value_range_type range_type = VR_UNDEFINED;
+      enum value_range_kind range_type = VR_UNDEFINED;
 
       /* Determine bounds from the type.  */
       if (tree_fits_uhwi_p (TYPE_MIN_VALUE (TREE_TYPE (len))))
@@ -2961,114 +3281,47 @@ determine_block_size (tree len, rtx len_rtx,
                          GET_MODE_MASK (GET_MODE (len_rtx)));
 }
 
-/* Helper function to do the actual work for expand_builtin_memcpy.  */
-
-static rtx
-expand_builtin_memcpy_args (tree dest, tree src, tree len, rtx target, tree exp)
-{
-  const char *src_str;
-  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;
-  unsigned HOST_WIDE_INT min_size;
-  unsigned HOST_WIDE_INT max_size;
-  unsigned HOST_WIDE_INT probable_max_size;
-
-  /* If DEST is not a pointer type, call the normal function.  */
-  if (dest_align == 0)
-    return NULL_RTX;
-
-  /* If either SRC is not a pointer type, don't do this
-     operation in-line.  */
-  if (src_align == 0)
-    return NULL_RTX;
-
-  if (currently_expanding_gimple_stmt)
-    stringop_block_profile (currently_expanding_gimple_stmt,
-                           &expected_align, &expected_size);
-
-  if (expected_align < dest_align)
-    expected_align = dest_align;
-  dest_mem = get_memory_rtx (dest, len);
-  set_mem_align (dest_mem, dest_align);
-  len_rtx = expand_normal (len);
-  determine_block_size (len, len_rtx, &min_size, &max_size,
-                       &probable_max_size);
-  src_str = c_getstr (src);
-
-  /* If SRC is a string constant and block move would be done
-     by pieces, we can avoid loading the string from memory
-     and only stored the computed constants.  */
-  if (src_str
-      && CONST_INT_P (len_rtx)
-      && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
-      && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
-                             CONST_CAST (char *, src_str),
-                             dest_align, false))
-    {
-      dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
-                                 builtin_memcpy_read_str,
-                                 CONST_CAST (char *, src_str),
-                                 dest_align, false, 0);
-      dest_mem = force_operand (XEXP (dest_mem, 0), target);
-      dest_mem = convert_memory_address (ptr_mode, dest_mem);
-      return dest_mem;
-    }
-
-  src_mem = get_memory_rtx (src, len);
-  set_mem_align (src_mem, src_align);
-
-  /* Copy word part most expediently.  */
-  dest_addr = emit_block_move_hints (dest_mem, src_mem, len_rtx,
-                                    CALL_EXPR_TAILCALL (exp)
-                                    ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL,
-                                    expected_align, expected_size,
-                                    min_size, max_size, probable_max_size);
-
-  if (dest_addr == 0)
-    {
-      dest_addr = force_operand (XEXP (dest_mem, 0), target);
-      dest_addr = convert_memory_address (ptr_mode, dest_addr);
-    }
-
-  return dest_addr;
-}
-
 /* Try to verify that the sizes and lengths of the arguments to a string
    manipulation function given by EXP are within valid bounds and that
-   the operation does not lead to buffer overflow.  Arguments other than
-   EXP may be null.  When non-null, the arguments have the following
-   meaning:
-   SIZE is the user-supplied size argument to the function (such as in
-   memcpy(d, s, SIZE) or strncpy(d, s, SIZE).  It specifies the exact
-   number of bytes to write.
-   MAXLEN is the user-supplied bound on the length of the source sequence
+   the operation does not lead to buffer overflow or read past the end.
+   Arguments other than EXP may be null.  When non-null, the arguments
+   have the following meaning:
+   DST is the destination of a copy call or NULL otherwise.
+   SRC is the source of a copy call or NULL otherwise.
+   DSTWRITE is the number of bytes written into the destination obtained
+   from the user-supplied size argument to the function (such as in
+   memcpy(DST, SRCs, DSTWRITE) or strncpy(DST, DRC, DSTWRITE).
+   MAXREAD is the user-supplied bound on the length of the source sequence
    (such as in strncat(d, s, N).  It specifies the upper limit on the number
-   of bytes to write.
-   SRC is the source string (such as in strcpy(d, s)) when the expression
-   EXP is a string function call (as opposed to a memory call like memcpy).
-   As an exception, SRC can also be an integer denoting the precomputed
-   size of the source string or object (for functions like memcpy).
-   OBJSIZE is the size of the destination object specified by the last
+   of bytes to write.  If NULL, it's taken to be the same as DSTWRITE.
+   SRCSTR is the source string (such as in strcpy(DST, SRC)) when the
+   expression EXP is a string function call (as opposed to a memory call
+   like memcpy).  As an exception, SRCSTR can also be an integer denoting
+   the precomputed size of the source string or object (for functions like
+   memcpy).
+   DSTSIZE is the size of the destination object specified by the last
    argument to the _chk builtins, typically resulting from the expansion
-   of __builtin_object_size (such as in __builtin___strcpy_chk(d, s,
-   OBJSIZE).
+   of __builtin_object_size (such as in __builtin___strcpy_chk(DST, SRC,
+   DSTSIZE).
 
-   When SIZE is null LEN is checked to verify that it doesn't exceed
+   When DSTWRITE is null LEN is checked to verify that it doesn't exceed
    SIZE_MAX.
 
-   If the call is successfully verified as safe from buffer overflow
-   the function returns true, otherwise false..  */
+   If the call is successfully verified as safe return true, otherwise
+   return false.  */
 
 static bool
-check_sizes (int opt, tree exp, tree size, tree maxlen, tree src, tree objsize)
+check_access (tree exp, tree, tree, tree dstwrite,
+             tree maxread, tree srcstr, tree dstsize)
 {
+  int opt = OPT_Wstringop_overflow_;
+
   /* The size of the largest object is half the address space, or
-     SSIZE_MAX.  (This is way too permissive.)  */
-  tree maxobjsize = TYPE_MAX_VALUE (ssizetype);
+     PTRDIFF_MAX.  (This is way too permissive.)  */
+  tree maxobjsize = max_object_size ();
 
+  /* Either the length of the source string for string functions or
+     the size of the source object for raw memory functions.  */
   tree slen = NULL_TREE;
 
   tree range[2] = { NULL_TREE, NULL_TREE };
@@ -3077,28 +3330,31 @@ check_sizes (int opt, tree exp, tree size, tree maxlen, tree src, tree objsize)
      function like strcpy is not known and the only thing that is
      known is that it must be at least one (for the terminating nul).  */
   bool at_least_one = false;
-  if (src)
+  if (srcstr)
     {
-      /* SRC is normally a pointer to string but as a special case
+      /* SRCSTR is normally a pointer to string but as a special case
         it can be an integer denoting the length of a string.  */
-      if (POINTER_TYPE_P (TREE_TYPE (src)))
+      if (POINTER_TYPE_P (TREE_TYPE (srcstr)))
        {
          /* Try to determine the range of lengths the source string
             refers to.  If it can be determined and is less than
-            the upper bound given by MAXLEN add one to it for
+            the upper bound given by MAXREAD add one to it for
             the terminating nul.  Otherwise, set it to one for
-            the same reason, or to MAXLEN as appropriate.  */
-         get_range_strlen (src, range);
-         if (range[0] && (!maxlen || TREE_CODE (maxlen) == INTEGER_CST))
+            the same reason, or to MAXREAD as appropriate.  */
+         c_strlen_data lendata = { };
+         get_range_strlen (srcstr, &lendata, /* eltsize = */ 1);
+         range[0] = lendata.minlen;
+         range[1] = lendata.maxbound;
+         if (range[0] && (!maxread || TREE_CODE (maxread) == INTEGER_CST))
            {
-             if (maxlen && tree_int_cst_le (maxlen, range[0]))
-               range[0] = range[1] = maxlen;
+             if (maxread && tree_int_cst_le (maxread, range[0]))
+               range[0] = range[1] = maxread;
              else
                range[0] = fold_build2 (PLUS_EXPR, size_type_node,
                                        range[0], size_one_node);
 
-             if (maxlen && tree_int_cst_le (maxlen, range[1]))
-               range[1] = maxlen;
+             if (maxread && tree_int_cst_le (maxread, range[1]))
+               range[1] = maxread;
              else if (!integer_all_onesp (range[1]))
                range[1] = fold_build2 (PLUS_EXPR, size_type_node,
                                        range[1], size_one_node);
@@ -3112,10 +3368,10 @@ check_sizes (int opt, tree exp, tree size, tree maxlen, tree src, tree objsize)
            }
        }
       else
-       slen = src;
+       slen = srcstr;
     }
 
-  if (!size && !maxlen)
+  if (!dstwrite && !maxread)
     {
       /* When the only available piece of data is the object size
         there is nothing to do.  */
@@ -3123,56 +3379,72 @@ check_sizes (int opt, tree exp, tree size, tree maxlen, tree src, tree objsize)
        return true;
 
       /* Otherwise, when the length of the source sequence is known
-        (as with with strlen), set SIZE to it.  */
+        (as with strlen), set DSTWRITE to it.  */
       if (!range[0])
-       size = slen;
+       dstwrite = slen;
     }
 
-  if (!objsize)
-    objsize = maxobjsize;
+  if (!dstsize)
+    dstsize = maxobjsize;
 
-  /* The SIZE is exact if it's non-null, constant, and in range of
-     unsigned HOST_WIDE_INT.  */
-  bool exactsize = size && tree_fits_uhwi_p (size);
+  if (dstwrite)
+    get_size_range (dstwrite, range);
 
-  if (size)
-    get_size_range (size, range);
+  tree func = get_callee_fndecl (exp);
 
   /* First check the number of bytes to be written against the maximum
      object size.  */
-  if (range[0] && tree_int_cst_lt (maxobjsize, range[0]))
+  if (range[0]
+      && TREE_CODE (range[0]) == INTEGER_CST
+      && tree_int_cst_lt (maxobjsize, range[0]))
     {
+      if (TREE_NO_WARNING (exp))
+       return false;
+
       location_t loc = tree_nonartificial_location (exp);
       loc = expansion_point_location_if_in_system_header (loc);
 
+      bool warned;
       if (range[0] == range[1])
-       warning_at (loc, opt,
-                   "%K%qD specified size %E "
-                   "exceeds maximum object size %E",
-                   exp, get_callee_fndecl (exp), range[0], maxobjsize);
-         else
-           warning_at (loc, opt,
-                       "%K%qD specified size between %E and %E "
-                       "exceeds maximum object size %E",
-                       exp, get_callee_fndecl (exp),
-                       range[0], range[1], maxobjsize);
+       warned = warning_at (loc, opt,
+                            "%K%qD specified size %E "
+                            "exceeds maximum object size %E",
+                            exp, func, range[0], maxobjsize);
+      else
+       warned = warning_at (loc, opt,
+                            "%K%qD specified size between %E and %E "
+                            "exceeds maximum object size %E",
+                            exp, func,
+                            range[0], range[1], maxobjsize);
+      if (warned)
+       TREE_NO_WARNING (exp) = true;
+
       return false;
     }
 
+  /* The number of bytes to write is "exact" if DSTWRITE is non-null,
+     constant, and in range of unsigned HOST_WIDE_INT.  */
+  bool exactwrite = dstwrite && tree_fits_uhwi_p (dstwrite);
+
   /* Next check the number of bytes to be written against the destination
      object size.  */
-  if (range[0] || !exactsize || integer_all_onesp (size))
+  if (range[0] || !exactwrite || integer_all_onesp (dstwrite))
     {
       if (range[0]
-         && ((tree_fits_uhwi_p (objsize)
-              && tree_int_cst_lt (objsize, range[0]))
-             || (tree_fits_uhwi_p (size)
-                 && tree_int_cst_lt (size, range[0]))))
+         && TREE_CODE (range[0]) == INTEGER_CST
+         && ((tree_fits_uhwi_p (dstsize)
+              && tree_int_cst_lt (dstsize, range[0]))
+             || (dstwrite
+                 && tree_fits_uhwi_p (dstwrite)
+                 && tree_int_cst_lt (dstwrite, range[0]))))
        {
+         if (TREE_NO_WARNING (exp))
+           return false;
+
          location_t loc = tree_nonartificial_location (exp);
          loc = expansion_point_location_if_in_system_header (loc);
 
-         if (size == slen && at_least_one)
+         if (dstwrite == slen && at_least_one)
            {
              /* This is a call to strcpy with a destination of 0 size
                 and a source of unknown length.  The call will write
@@ -3180,30 +3452,29 @@ check_sizes (int opt, tree exp, tree size, tree maxlen, tree src, tree objsize)
              warning_at (loc, opt,
                          "%K%qD writing %E or more bytes into a region "
                          "of size %E overflows the destination",
-                         exp, get_callee_fndecl (exp), range[0], objsize);
+                         exp, func, range[0], dstsize);
            }
          else if (tree_int_cst_equal (range[0], range[1]))
-           warning_at (loc, opt,
-                       (integer_onep (range[0])
-                        ? G_("%K%qD writing %E byte into a region "
-                             "of size %E overflows the destination")
-                        : G_("%K%qD writing %E bytes into a region "
-                             "of size %E overflows the destination")),
-                       exp, get_callee_fndecl (exp), range[0], objsize);
+           warning_n (loc, opt, tree_to_uhwi (range[0]),
+                      "%K%qD writing %E byte into a region "
+                      "of size %E overflows the destination",
+                      "%K%qD writing %E bytes into a region "
+                      "of size %E overflows the destination",
+                      exp, func, range[0], dstsize);
          else if (tree_int_cst_sign_bit (range[1]))
            {
              /* Avoid printing the upper bound if it's invalid.  */
              warning_at (loc, opt,
                          "%K%qD writing %E or more bytes into a region "
                          "of size %E overflows the destination",
-                         exp, get_callee_fndecl (exp), range[0], objsize);
+                         exp, func, range[0], dstsize);
            }
          else
            warning_at (loc, opt,
                        "%K%qD writing between %E and %E bytes into "
                        "a region of size %E overflows the destination",
-                       exp, get_callee_fndecl (exp), range[0], range[1],
-                       objsize);
+                       exp, func, range[0], range[1],
+                       dstsize);
 
          /* Return error when an overflow has been detected.  */
          return false;
@@ -3213,17 +3484,24 @@ check_sizes (int opt, tree exp, tree size, tree maxlen, tree src, tree objsize)
   /* Check the maximum length of the source sequence against the size
      of the destination object if known, or against the maximum size
      of an object.  */
-  if (maxlen)
+  if (maxread)
     {
-      get_size_range (maxlen, range);
+      get_size_range (maxread, range);
 
-      if (range[0] && objsize && tree_fits_uhwi_p (objsize))
+      /* Use the lower end for MAXREAD from now on.  */
+      if (range[0])
+       maxread = range[0];
+
+      if (range[0] && dstsize && tree_fits_uhwi_p (dstsize))
        {
          location_t loc = tree_nonartificial_location (exp);
          loc = expansion_point_location_if_in_system_header (loc);
 
          if (tree_int_cst_lt (maxobjsize, range[0]))
            {
+             if (TREE_NO_WARNING (exp))
+               return false;
+
              /* Warn about crazy big sizes first since that's more
                 likely to be meaningful than saying that the bound
                 is greater than the object size if both are big.  */
@@ -3231,63 +3509,69 @@ check_sizes (int opt, tree exp, tree size, tree maxlen, tree src, tree objsize)
                warning_at (loc, opt,
                            "%K%qD specified bound %E "
                            "exceeds maximum object size %E",
-                           exp, get_callee_fndecl (exp),
+                           exp, func,
                            range[0], maxobjsize);
              else
                warning_at (loc, opt,
                            "%K%qD specified bound between %E and %E "
                            "exceeds maximum object size %E",
-                           exp, get_callee_fndecl (exp),
+                           exp, func,
                            range[0], range[1], maxobjsize);
 
              return false;
            }
 
-         if (objsize != maxobjsize && tree_int_cst_lt (objsize, range[0]))
+         if (dstsize != maxobjsize && tree_int_cst_lt (dstsize, range[0]))
            {
+             if (TREE_NO_WARNING (exp))
+               return false;
+
              if (tree_int_cst_equal (range[0], range[1]))
                warning_at (loc, opt,
                            "%K%qD specified bound %E "
                            "exceeds destination size %E",
-                           exp, get_callee_fndecl (exp),
-                           range[0], objsize);
+                           exp, func,
+                           range[0], dstsize);
              else
                warning_at (loc, opt,
                            "%K%qD specified bound between %E and %E "
                            "exceeds destination size %E",
-                           exp, get_callee_fndecl (exp),
-                           range[0], range[1], objsize);
+                           exp, func,
+                           range[0], range[1], dstsize);
              return false;
            }
        }
     }
 
+  /* Check for reading past the end of SRC.  */
   if (slen
-      && slen == src
-      && size && range[0]
+      && slen == srcstr
+      && dstwrite && range[0]
       && tree_int_cst_lt (slen, range[0]))
     {
+      if (TREE_NO_WARNING (exp))
+       return false;
+
       location_t loc = tree_nonartificial_location (exp);
 
       if (tree_int_cst_equal (range[0], range[1]))
-       warning_at (loc, opt,
-                   (tree_int_cst_equal (range[0], integer_one_node)
-                    ? G_("%K%qD reading %E byte from a region of size %E")
-                    : G_("%K%qD reading %E bytes from a region of size %E")),
-                   exp, get_callee_fndecl (exp), range[0], slen);
+       warning_n (loc, opt, tree_to_uhwi (range[0]),
+                  "%K%qD reading %E byte from a region of size %E",
+                  "%K%qD reading %E bytes from a region of size %E",
+                   exp, func, range[0], slen);
       else if (tree_int_cst_sign_bit (range[1]))
        {
          /* Avoid printing the upper bound if it's invalid.  */
          warning_at (loc, opt,
                      "%K%qD reading %E or more bytes from a region "
                      "of size %E",
-                     exp, get_callee_fndecl (exp), range[0], slen);
+                     exp, func, range[0], slen);
        }
       else
        warning_at (loc, opt,
                    "%K%qD reading between %E and %E bytes from a region "
                    "of size %E",
-                   exp, get_callee_fndecl (exp), range[0], range[1], slen);
+                   exp, func, range[0], range[1], slen);
       return false;
     }
 
@@ -3295,18 +3579,116 @@ check_sizes (int opt, tree exp, tree size, tree maxlen, tree src, tree objsize)
 }
 
 /* Helper to compute the size of the object referenced by the DEST
-   expression which must of of pointer type, using Object Size type
+   expression which must have pointer type, using Object Size type
    OSTYPE (only the least significant 2 bits are used).  Return
-   the size of the object if successful or NULL when the size cannot
-   be determined.  */
+   an estimate of the size of the object if successful or NULL when
+   the size cannot be determined.  When the referenced object involves
+   a non-constant offset in some range the returned value represents
+   the largest size given the smallest non-negative offset in the
+   range.  The function is intended for diagnostics and should not
+   be used to influence code generation or optimization.  */
 
-static inline tree
+tree
 compute_objsize (tree dest, int ostype)
 {
   unsigned HOST_WIDE_INT size;
-  if (compute_builtin_object_size (dest, ostype & 3, &size))
+
+  /* Only the two least significant bits are meaningful.  */
+  ostype &= 3;
+
+  if (compute_builtin_object_size (dest, ostype, &size))
     return build_int_cst (sizetype, size);
 
+  if (TREE_CODE (dest) == SSA_NAME)
+    {
+      gimple *stmt = SSA_NAME_DEF_STMT (dest);
+      if (!is_gimple_assign (stmt))
+       return NULL_TREE;
+
+      dest = gimple_assign_rhs1 (stmt);
+
+      tree_code code = gimple_assign_rhs_code (stmt);
+      if (code == POINTER_PLUS_EXPR)
+       {
+         /* compute_builtin_object_size fails for addresses with
+            non-constant offsets.  Try to determine the range of
+            such an offset here and use it to adjust the constant
+            size.  */
+         tree off = gimple_assign_rhs2 (stmt);
+         if (TREE_CODE (off) == INTEGER_CST)
+           {
+             if (tree size = compute_objsize (dest, ostype))
+               {
+                 wide_int wioff = wi::to_wide (off);
+                 wide_int wisiz = wi::to_wide (size);
+
+                 /* Ignore negative offsets for now.  For others,
+                    use the lower bound as the most optimistic
+                    estimate of the (remaining) size.  */
+                 if (wi::sign_mask (wioff))
+                   ;
+                 else if (wi::ltu_p (wioff, wisiz))
+                   return wide_int_to_tree (TREE_TYPE (size),
+                                            wi::sub (wisiz, wioff));
+                 else
+                   return size_zero_node;
+               }
+           }
+         else if (TREE_CODE (off) == SSA_NAME
+             && INTEGRAL_TYPE_P (TREE_TYPE (off)))
+           {
+             wide_int min, max;
+             enum value_range_kind rng = get_range_info (off, &min, &max);
+
+             if (rng == VR_RANGE)
+               {
+                 if (tree size = compute_objsize (dest, ostype))
+                   {
+                     wide_int wisiz = wi::to_wide (size);
+
+                     /* Ignore negative offsets for now.  For others,
+                        use the lower bound as the most optimistic
+                        estimate of the (remaining)size.  */
+                     if (wi::sign_mask (min))
+                       ;
+                     else if (wi::ltu_p (min, wisiz))
+                       return wide_int_to_tree (TREE_TYPE (size),
+                                                wi::sub (wisiz, min));
+                     else
+                       return size_zero_node;
+                   }
+               }
+           }
+       }
+      else if (code != ADDR_EXPR)
+       return NULL_TREE;
+    }
+
+  /* Unless computing the largest size (for memcpy and other raw memory
+     functions), try to determine the size of the object from its type.  */
+  if (!ostype)
+    return NULL_TREE;
+
+  if (TREE_CODE (dest) != ADDR_EXPR)
+    return NULL_TREE;
+
+  tree type = TREE_TYPE (dest);
+  if (TREE_CODE (type) == POINTER_TYPE)
+    type = TREE_TYPE (type);
+
+  type = TYPE_MAIN_VARIANT (type);
+
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && !array_at_struct_end_p (TREE_OPERAND (dest, 0)))
+    {
+      /* Return the constant size unless it's zero (that's a zero-length
+        array likely at the end of a struct).  */
+      tree size = TYPE_SIZE_UNIT (type);
+      if (size && TREE_CODE (size) == INTEGER_CST
+         && !integer_zerop (size))
+       return size;
+    }
+
   return NULL_TREE;
 }
 
@@ -3318,11 +3700,8 @@ compute_objsize (tree dest, int ostype)
    (no overflow or invalid sizes), false otherwise.  */
 
 static bool
-check_memop_sizes (tree exp, tree dest, tree src, tree size)
+check_memop_access (tree exp, tree dest, tree src, tree size)
 {
-  if (!warn_stringop_overflow)
-    return true;
-
   /* For functions like memset and memcpy that operate on raw memory
      try to determine the size of the largest source and destination
      object using type-0 Object Size regardless of the object size
@@ -3330,8 +3709,8 @@ check_memop_sizes (tree exp, tree dest, tree src, tree size)
   tree srcsize = src ? compute_objsize (src, 0) : NULL_TREE;
   tree dstsize = compute_objsize (dest, 0);
 
-  return check_sizes (OPT_Wstringop_overflow_, exp,
-                     size, /*maxlen=*/NULL_TREE, srcsize, dstsize);
+  return check_access (exp, dest, src, size, /*maxread=*/NULL_TREE,
+                      srcsize, dstsize);
 }
 
 /* Validate memchr arguments without performing any expansion.
@@ -3352,9 +3731,8 @@ expand_builtin_memchr (tree exp, rtx)
   if (warn_stringop_overflow)
     {
       tree size = compute_objsize (arg1, 0);
-      check_sizes (OPT_Wstringop_overflow_,
-                  exp, len, /*maxlen=*/NULL_TREE,
-                  size, /*objsize=*/NULL_TREE);
+      check_access (exp, /*dst=*/NULL_TREE, /*src=*/NULL_TREE, len,
+                   /*maxread=*/NULL_TREE, size, /*objsize=*/NULL_TREE);
     }
 
   return NULL_RTX;
@@ -3376,9 +3754,10 @@ expand_builtin_memcpy (tree exp, rtx target)
   tree src = CALL_EXPR_ARG (exp, 1);
   tree len = CALL_EXPR_ARG (exp, 2);
 
-  check_memop_sizes (exp, dest, src, len);
+  check_memop_access (exp, dest, src, len);
 
-  return expand_builtin_memcpy_args (dest, src, len, target, exp);
+  return expand_builtin_memory_copy_args (dest, src, len, target, exp,
+                                         /*retmode=*/ RETURN_BEGIN);
 }
 
 /* Check a call EXP to the memmove built-in for validity.
@@ -3395,52 +3774,18 @@ expand_builtin_memmove (tree exp, rtx)
   tree src = CALL_EXPR_ARG (exp, 1);
   tree len = CALL_EXPR_ARG (exp, 2);
 
-  check_memop_sizes (exp, dest, src, len);
+  check_memop_access (exp, dest, src, len);
 
   return NULL_RTX;
 }
 
-/* Expand an instrumented call EXP to the memcpy builtin.
-   Return NULL_RTX if we failed, the caller should emit a normal call,
-   otherwise try to get the result in TARGET, if convenient (and in
-   mode MODE if that's convenient).  */
-
-static rtx
-expand_builtin_memcpy_with_bounds (tree exp, rtx target)
-{
-  if (!validate_arglist (exp,
-                        POINTER_TYPE, POINTER_BOUNDS_TYPE,
-                        POINTER_TYPE, POINTER_BOUNDS_TYPE,
-                        INTEGER_TYPE, VOID_TYPE))
-    return NULL_RTX;
-  else
-    {
-      tree dest = CALL_EXPR_ARG (exp, 0);
-      tree src = CALL_EXPR_ARG (exp, 2);
-      tree len = CALL_EXPR_ARG (exp, 4);
-      rtx res = expand_builtin_memcpy_args (dest, src, len, target, exp);
-
-      /* Return src bounds with the result.  */
-      if (res)
-       {
-         rtx bnd = force_reg (targetm.chkp_bound_mode (),
-                              expand_normal (CALL_EXPR_ARG (exp, 1)));
-         res = chkp_join_splitted_slot (res, bnd);
-       }
-      return res;
-    }
-}
-
 /* Expand a call EXP to the mempcpy builtin.
    Return NULL_RTX if we failed; the caller should emit a normal call,
    otherwise try to get the result in TARGET, if convenient (and in
-   mode MODE if that's convenient).  If ENDP is 0 return the
-   destination pointer, if ENDP is 1 return the end pointer ala
-   mempcpy, and if ENDP is 2 return the end pointer minus one ala
-   stpcpy.  */
+   mode MODE if that's convenient).  */
 
 static rtx
-expand_builtin_mempcpy (tree exp, rtx target, machine_mode mode)
+expand_builtin_mempcpy (tree exp, rtx target)
 {
   if (!validate_arglist (exp,
                         POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
@@ -3450,148 +3795,137 @@ expand_builtin_mempcpy (tree exp, rtx target, machine_mode mode)
   tree src = CALL_EXPR_ARG (exp, 1);
   tree len = CALL_EXPR_ARG (exp, 2);
 
+  /* Policy does not generally allow using compute_objsize (which
+     is used internally by check_memop_size) to change code generation
+     or drive optimization decisions.
+
+     In this instance it is safe because the code we generate has
+     the same semantics regardless of the return value of
+     check_memop_sizes.   Exactly the same amount of data is copied
+     and the return value is exactly the same in both cases.
+
+     Furthermore, check_memop_size always uses mode 0 for the call to
+     compute_objsize, so the imprecise nature of compute_objsize is
+     avoided.  */
+
   /* Avoid expanding mempcpy into memcpy when the call is determined
      to overflow the buffer.  This also prevents the same overflow
      from being diagnosed again when expanding memcpy.  */
-  if (!check_memop_sizes (exp, dest, src, len))
+  if (!check_memop_access (exp, dest, src, len))
     return NULL_RTX;
 
   return expand_builtin_mempcpy_args (dest, src, len,
-                                     target, mode, /*endp=*/ 1,
-                                     exp);
+                                     target, exp, /*retmode=*/ RETURN_END);
 }
 
-/* Expand an instrumented call EXP to the mempcpy builtin.
-   Return NULL_RTX if we failed, the caller should emit a normal call,
-   otherwise try to get the result in TARGET, if convenient (and in
-   mode MODE if that's convenient).  */
+/* Helper function to do the actual work for expand of memory copy family
+   functions (memcpy, mempcpy, stpcpy).  Expansing should assign LEN bytes
+   of memory from SRC to DEST and assign to TARGET if convenient.  Return
+   value is based on RETMODE argument.  */
 
 static rtx
-expand_builtin_mempcpy_with_bounds (tree exp, rtx target, machine_mode mode)
+expand_builtin_memory_copy_args (tree dest, tree src, tree len,
+                                rtx target, tree exp, memop_ret retmode)
 {
-  if (!validate_arglist (exp,
-                        POINTER_TYPE, POINTER_BOUNDS_TYPE,
-                        POINTER_TYPE, POINTER_BOUNDS_TYPE,
-                        INTEGER_TYPE, VOID_TYPE))
+  const char *src_str;
+  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;
+  unsigned HOST_WIDE_INT min_size;
+  unsigned HOST_WIDE_INT max_size;
+  unsigned HOST_WIDE_INT probable_max_size;
+
+  /* If DEST is not a pointer type, call the normal function.  */
+  if (dest_align == 0)
     return NULL_RTX;
-  else
-    {
-      tree dest = CALL_EXPR_ARG (exp, 0);
-      tree src = CALL_EXPR_ARG (exp, 2);
-      tree len = CALL_EXPR_ARG (exp, 4);
-      rtx res = expand_builtin_mempcpy_args (dest, src, len, target,
-                                            mode, 1, exp);
 
-      /* Return src bounds with the result.  */
-      if (res)
-       {
-         rtx bnd = force_reg (targetm.chkp_bound_mode (),
-                              expand_normal (CALL_EXPR_ARG (exp, 1)));
-         res = chkp_join_splitted_slot (res, bnd);
-       }
-      return res;
-    }
-}
+  /* If either SRC is not a pointer type, don't do this
+     operation in-line.  */
+  if (src_align == 0)
+    return NULL_RTX;
 
-/* Helper function to do the actual work for expand_builtin_mempcpy.  The
-   arguments to the builtin_mempcpy call DEST, SRC, and LEN are broken out
-   so that this can also be called without constructing an actual CALL_EXPR.
-   The other arguments and return value are the same as for
-   expand_builtin_mempcpy.  */
+  if (currently_expanding_gimple_stmt)
+    stringop_block_profile (currently_expanding_gimple_stmt,
+                           &expected_align, &expected_size);
 
-static rtx
-expand_builtin_mempcpy_args (tree dest, tree src, tree len,
-                            rtx target, machine_mode mode, int endp,
-                            tree orig_exp)
-{
-  tree fndecl = get_callee_fndecl (orig_exp);
+  if (expected_align < dest_align)
+    expected_align = dest_align;
+  dest_mem = get_memory_rtx (dest, len);
+  set_mem_align (dest_mem, dest_align);
+  len_rtx = expand_normal (len);
+  determine_block_size (len, len_rtx, &min_size, &max_size,
+                       &probable_max_size);
+  src_str = c_getstr (src);
 
-    /* If return value is ignored, transform mempcpy into memcpy.  */
-  if (target == const0_rtx
-      && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK_CHKP
-      && builtin_decl_implicit_p (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK_CHKP))
-    {
-      tree fn = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK_CHKP);
-      tree result = build_call_nofold_loc (UNKNOWN_LOCATION, fn, 3,
-                                          dest, src, len);
-      return expand_expr (result, target, mode, EXPAND_NORMAL);
-    }
-  else if (target == const0_rtx
-          && builtin_decl_implicit_p (BUILT_IN_MEMCPY))
+  /* If SRC is a string constant and block move would be done
+     by pieces, we can avoid loading the string from memory
+     and only stored the computed constants.  */
+  if (src_str
+      && CONST_INT_P (len_rtx)
+      && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
+      && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
+                             CONST_CAST (char *, src_str),
+                             dest_align, false))
     {
-      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);
+      dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
+                                 builtin_memcpy_read_str,
+                                 CONST_CAST (char *, src_str),
+                                 dest_align, false, retmode);
+      dest_mem = force_operand (XEXP (dest_mem, 0), target);
+      dest_mem = convert_memory_address (ptr_mode, dest_mem);
+      return dest_mem;
     }
-  else
-    {
-      const char *src_str;
-      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
-        operation in-line.  */
-      if (dest_align == 0 || src_align == 0)
-       return NULL_RTX;
+  src_mem = get_memory_rtx (src, len);
+  set_mem_align (src_mem, src_align);
 
-      /* If LEN is not constant, call the normal function.  */
-      if (! tree_fits_uhwi_p (len))
-       return NULL_RTX;
+  /* Copy word part most expediently.  */
+  enum block_op_methods method = BLOCK_OP_NORMAL;
+  if (CALL_EXPR_TAILCALL (exp)
+      && (retmode == RETURN_BEGIN || target == const0_rtx))
+    method = BLOCK_OP_TAILCALL;
+  if (retmode == RETURN_END && target != const0_rtx)
+    method = BLOCK_OP_NO_LIBCALL_RET;
+  dest_addr = emit_block_move_hints (dest_mem, src_mem, len_rtx, method,
+                                    expected_align, expected_size,
+                                    min_size, max_size, probable_max_size);
+  if (dest_addr == pc_rtx)
+    return NULL_RTX;
 
-      len_rtx = expand_normal (len);
-      src_str = c_getstr (src);
+  if (dest_addr == 0)
+    {
+      dest_addr = force_operand (XEXP (dest_mem, 0), target);
+      dest_addr = convert_memory_address (ptr_mode, dest_addr);
+    }
 
-      /* If SRC is a string constant and block move would be done
-        by pieces, we can avoid loading the string from memory
-        and only stored the computed constants.  */
-      if (src_str
-         && CONST_INT_P (len_rtx)
-         && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
-         && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
-                                 CONST_CAST (char *, src_str),
-                                 dest_align, false))
-       {
-         dest_mem = get_memory_rtx (dest, len);
-         set_mem_align (dest_mem, dest_align);
-         dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
-                                     builtin_memcpy_read_str,
-                                     CONST_CAST (char *, src_str),
-                                     dest_align, false, endp);
-         dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
-         dest_mem = convert_memory_address (ptr_mode, dest_mem);
-         return dest_mem;
-       }
+  if (retmode != RETURN_BEGIN && target != const0_rtx)
+    {
+      dest_addr = gen_rtx_PLUS (ptr_mode, dest_addr, len_rtx);
+      /* stpcpy pointer to last byte.  */
+      if (retmode == RETURN_END_MINUS_ONE)
+       dest_addr = gen_rtx_MINUS (ptr_mode, dest_addr, const1_rtx);
+    }
 
-      if (CONST_INT_P (len_rtx)
-         && can_move_by_pieces (INTVAL (len_rtx),
-                                MIN (dest_align, src_align)))
-       {
-         dest_mem = get_memory_rtx (dest, len);
-         set_mem_align (dest_mem, dest_align);
-         src_mem = get_memory_rtx (src, len);
-         set_mem_align (src_mem, src_align);
-         dest_mem = move_by_pieces (dest_mem, src_mem, INTVAL (len_rtx),
-                                    MIN (dest_align, src_align), endp);
-         dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
-         dest_mem = convert_memory_address (ptr_mode, dest_mem);
-         return dest_mem;
-       }
+  return dest_addr;
+}
 
-      return NULL_RTX;
-    }
+static rtx
+expand_builtin_mempcpy_args (tree dest, tree src, tree len,
+                            rtx target, tree orig_exp, memop_ret retmode)
+{
+  return expand_builtin_memory_copy_args (dest, src, len, target, orig_exp,
+                                         retmode);
 }
 
 /* Expand into a movstr instruction, if one is available.  Return NULL_RTX if
    we failed, the caller should emit a normal call, otherwise try to
-   get the result in TARGET, if convenient.  If ENDP is 0 return the
-   destination pointer, if ENDP is 1 return the end pointer ala
-   mempcpy, and if ENDP is 2 return the end pointer minus one ala
-   stpcpy.  */
+   get the result in TARGET, if convenient.
+   Return value is based on RETMODE argument.  */
 
 static rtx
-expand_movstr (tree dest, tree src, rtx target, int endp)
+expand_movstr (tree dest, tree src, rtx target, memop_ret retmode)
 {
   struct expand_operand ops[3];
   rtx dest_mem;
@@ -3602,25 +3936,26 @@ expand_movstr (tree dest, tree src, rtx target, int endp)
 
   dest_mem = get_memory_rtx (dest, NULL);
   src_mem = get_memory_rtx (src, NULL);
-  if (!endp)
+  if (retmode == RETURN_BEGIN)
     {
       target = force_reg (Pmode, XEXP (dest_mem, 0));
       dest_mem = replace_equiv_address (dest_mem, target);
     }
 
-  create_output_operand (&ops[0], endp ? target : NULL_RTX, Pmode);
+  create_output_operand (&ops[0],
+                        retmode != RETURN_BEGIN ? target : NULL_RTX, Pmode);
   create_fixed_operand (&ops[1], dest_mem);
   create_fixed_operand (&ops[2], src_mem);
   if (!maybe_expand_insn (targetm.code_for_movstr, 3, ops))
     return NULL_RTX;
 
-  if (endp && target != const0_rtx)
+  if (retmode != RETURN_BEGIN && target != const0_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)
+      if (retmode == RETURN_END)
        {
          rtx tem = plus_constant (GET_MODE (target),
                                   gen_lowpart (GET_MODE (target), target), 1);
@@ -3651,8 +3986,8 @@ expand_builtin_strcat (tree exp, rtx)
 
   tree destsize = compute_objsize (dest, warn_stringop_overflow - 1);
 
-  check_sizes (OPT_Wstringop_overflow_,
-              exp, /*size=*/NULL_TREE, /*maxlen=*/NULL_TREE, src, destsize);
+  check_access (exp, dest, src, /*size=*/NULL_TREE, /*maxread=*/NULL_TREE, src,
+               destsize);
 
   return NULL_RTX;
 }
@@ -3674,11 +4009,21 @@ expand_builtin_strcpy (tree exp, rtx target)
   if (warn_stringop_overflow)
     {
       tree destsize = compute_objsize (dest, warn_stringop_overflow - 1);
-      check_sizes (OPT_Wstringop_overflow_,
-                  exp, /*size=*/NULL_TREE, /*maxlen=*/NULL_TREE, src, destsize);
+      check_access (exp, dest, src, /*size=*/NULL_TREE, /*maxread=*/NULL_TREE,
+                   src, destsize);
+    }
+
+  if (rtx ret = expand_builtin_strcpy_args (exp, dest, src, target))
+    {
+      /* Check to see if the argument was declared attribute nonstring
+        and if so, issue a warning since at this point it's not known
+        to be nul-terminated.  */
+      tree fndecl = get_callee_fndecl (exp);
+      maybe_warn_nonstring_arg (fndecl, exp);
+      return ret;
     }
 
-  return expand_builtin_strcpy_args (dest, src, target);
+  return NULL_RTX;
 }
 
 /* Helper function to do the actual work for expand_builtin_strcpy.  The
@@ -3688,9 +4033,18 @@ expand_builtin_strcpy (tree exp, rtx target)
    expand_builtin_strcpy.  */
 
 static rtx
-expand_builtin_strcpy_args (tree dest, tree src, rtx target)
+expand_builtin_strcpy_args (tree exp, tree dest, tree src, rtx target)
 {
-  return expand_movstr (dest, src, target, /*endp=*/0);
+  /* Detect strcpy calls with unterminated arrays..  */
+  if (tree nonstr = unterminated_array (src))
+    {
+      /* NONSTR refers to the non-nul terminated constant array.  */
+      if (!TREE_NO_WARNING (exp))
+       warn_string_no_nul (EXPR_LOCATION (exp), "strcpy", src, nonstr);
+      return NULL_RTX;
+    }
+
+  return expand_movstr (dest, src, target, /*retmode=*/ RETURN_BEGIN);
 }
 
 /* Expand a call EXP to the stpcpy builtin.
@@ -3699,7 +4053,7 @@ expand_builtin_strcpy_args (tree dest, tree src, rtx target)
    mode MODE if that's convenient).  */
 
 static rtx
-expand_builtin_stpcpy (tree exp, rtx target, machine_mode mode)
+expand_builtin_stpcpy_1 (tree exp, rtx target, machine_mode mode)
 {
   tree dst, src;
   location_t loc = EXPR_LOCATION (exp);
@@ -3713,8 +4067,8 @@ expand_builtin_stpcpy (tree exp, rtx target, machine_mode mode)
   if (warn_stringop_overflow)
     {
       tree destsize = compute_objsize (dst, warn_stringop_overflow - 1);
-      check_sizes (OPT_Wstringop_overflow_,
-                  exp, /*size=*/NULL_TREE, /*maxlen=*/NULL_TREE, src, destsize);
+      check_access (exp, dst, src, /*size=*/NULL_TREE, /*maxread=*/NULL_TREE,
+                   src, destsize);
     }
 
   /* If return value is ignored, transform stpcpy into strcpy.  */
@@ -3733,13 +4087,19 @@ expand_builtin_stpcpy (tree exp, rtx target, machine_mode mode)
         compile-time, not an expression containing a string.  This is
         because the latter will potentially produce pessimized code
         when used to produce the return value.  */
-      if (! c_getstr (src) || ! (len = c_strlen (src, 0)))
-       return expand_movstr (dst, src, target, /*endp=*/2);
+      c_strlen_data lendata = { };
+      if (!c_getstr (src, NULL)
+         || !(len = c_strlen (src, 0, &lendata, 1)))
+       return expand_movstr (dst, src, target,
+                             /*retmode=*/ RETURN_END_MINUS_ONE);
+
+      if (lendata.decl && !TREE_NO_WARNING (exp))
+       warn_string_no_nul (EXPR_LOCATION (exp), "stpcpy", src, lendata.decl);
 
       lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1));
       ret = expand_builtin_mempcpy_args (dst, src, lenp1,
-                                        target, mode, /*endp=*/2,
-                                        exp);
+                                        target, exp,
+                                        /*retmode=*/ RETURN_END_MINUS_ONE);
 
       if (ret)
        return ret;
@@ -3750,7 +4110,7 @@ expand_builtin_stpcpy (tree exp, rtx target, machine_mode mode)
 
          if (CONST_INT_P (len_rtx))
            {
-             ret = expand_builtin_strcpy_args (dst, src, target);
+             ret = expand_builtin_strcpy_args (exp, dst, src, target);
 
              if (ret)
                {
@@ -3773,10 +4133,30 @@ expand_builtin_stpcpy (tree exp, rtx target, machine_mode mode)
            }
        }
 
-      return expand_movstr (dst, src, target, /*endp=*/2);
+      return expand_movstr (dst, src, target,
+                           /*retmode=*/ RETURN_END_MINUS_ONE);
     }
 }
 
+/* Expand a call EXP to the stpcpy builtin and diagnose uses of nonstring
+   arguments while being careful to avoid duplicate warnings (which could
+   be issued if the expander were to expand the call, resulting in it
+   being emitted in expand_call().  */
+
+static rtx
+expand_builtin_stpcpy (tree exp, rtx target, machine_mode mode)
+{
+  if (rtx ret = expand_builtin_stpcpy_1 (exp, target, mode))
+    {
+      /* The call has been successfully expanded.  Check for nonstring
+        arguments and issue warnings as appropriate.  */
+      maybe_warn_nonstring_arg (get_callee_fndecl (exp), exp);
+      return ret;
+    }
+
+  return NULL_RTX;
+}
+
 /* Check a call EXP to the stpncpy built-in for validity.
    Return NULL_RTX on both success and failure.  */
 
@@ -3798,8 +4178,7 @@ expand_builtin_stpncpy (tree exp, rtx)
   /* The size of the destination object.  */
   tree destsize = compute_objsize (dest, warn_stringop_overflow - 1);
 
-  check_sizes (OPT_Wstringop_overflow_,
-              exp, len, /*maxlen=*/NULL_TREE, src, destsize);
+  check_access (exp, dest, src, len, /*maxread=*/NULL_TREE, src, destsize);
 
   return NULL_RTX;
 }
@@ -3810,7 +4189,7 @@ expand_builtin_stpncpy (tree exp, rtx)
 
 rtx
 builtin_strncpy_read_str (void *data, HOST_WIDE_INT offset,
-                         machine_mode mode)
+                         scalar_int_mode mode)
 {
   const char *str = (const char *) data;
 
@@ -3829,12 +4208,12 @@ check_strncat_sizes (tree exp, tree objsize)
 {
   tree dest = CALL_EXPR_ARG (exp, 0);
   tree src = CALL_EXPR_ARG (exp, 1);
-  tree maxlen = CALL_EXPR_ARG (exp, 2);
+  tree maxread = CALL_EXPR_ARG (exp, 2);
 
   /* Try to determine the range of lengths that the source expression
      refers to.  */
-  tree lenrange[2];
-  get_range_strlen (src, lenrange);
+  c_strlen_data lendata = { };
+  get_range_strlen (src, &lendata, /* eltsize = */ 1);
 
   /* Try to verify that the destination is big enough for the shortest
      string.  */
@@ -3848,37 +4227,37 @@ check_strncat_sizes (tree exp, tree objsize)
     }
 
   /* Add one for the terminating nul.  */
-  tree srclen = (lenrange[0]
-                ? fold_build2 (PLUS_EXPR, size_type_node, lenrange[0],
+  tree srclen = (lendata.minlen
+                ? fold_build2 (PLUS_EXPR, size_type_node, lendata.minlen,
                                size_one_node)
                 : NULL_TREE);
 
-  /* Strncat copies at most MAXLEN bytes and always appends the terminating
-     nul so the specified upper bound should never be equal to (or greater
-     than) the size of the destination.  */
-  if (tree_fits_uhwi_p (maxlen) && tree_fits_uhwi_p (objsize)
-      && tree_int_cst_equal (objsize, maxlen))
+  /* The strncat function copies at most MAXREAD bytes and always appends
+     the terminating nul so the specified upper bound should never be equal
+     to (or greater than) the size of the destination.  */
+  if (tree_fits_uhwi_p (maxread) && tree_fits_uhwi_p (objsize)
+      && tree_int_cst_equal (objsize, maxread))
     {
       location_t loc = tree_nonartificial_location (exp);
       loc = expansion_point_location_if_in_system_header (loc);
 
       warning_at (loc, OPT_Wstringop_overflow_,
                  "%K%qD specified bound %E equals destination size",
-                 exp, get_callee_fndecl (exp), maxlen);
+                 exp, get_callee_fndecl (exp), maxread);
 
       return false;
     }
 
   if (!srclen
-      || (maxlen && tree_fits_uhwi_p (maxlen)
+      || (maxread && tree_fits_uhwi_p (maxread)
          && tree_fits_uhwi_p (srclen)
-         && tree_int_cst_lt (maxlen, srclen)))
-    srclen = maxlen;
+         && tree_int_cst_lt (maxread, srclen)))
+    srclen = maxread;
 
-  /* The number of bytes to write is LEN but check_sizes will also
+  /* The number of bytes to write is LEN but check_access will also
      check SRCLEN if LEN's value isn't known.  */
-  return check_sizes (OPT_Wstringop_overflow_,
-                     exp, /*size=*/NULL_TREE, maxlen, srclen, objsize);
+  return check_access (exp, dest, src, /*size=*/NULL_TREE, maxread, srclen,
+                      objsize);
 }
 
 /* Similar to expand_builtin_strcat, do some very basic size validation
@@ -3896,17 +4275,20 @@ expand_builtin_strncat (tree exp, rtx)
   tree dest = CALL_EXPR_ARG (exp, 0);
   tree src = CALL_EXPR_ARG (exp, 1);
   /* The upper bound on the number of bytes to write.  */
-  tree maxlen = CALL_EXPR_ARG (exp, 2);
+  tree maxread = CALL_EXPR_ARG (exp, 2);
   /* The length of the source sequence.  */
   tree slen = c_strlen (src, 1);
 
   /* Try to determine the range of lengths that the source expression
-     refers to.  */
-  tree lenrange[2];
-  if (slen)
-    lenrange[0] = lenrange[1] = slen;
-  else
-    get_range_strlen (src, lenrange);
+     refers to.  Since the lengths are only used for warning and not
+     for code generation disable strict mode below.  */
+  tree maxlen = slen;
+  if (!maxlen)
+    {
+      c_strlen_data lendata = { };
+      get_range_strlen (src, &lendata, /* eltsize = */ 1);
+      maxlen = lendata.maxbound;
+    }
 
   /* Try to verify that the destination is big enough for the shortest
      string.  First try to determine the size of the destination object
@@ -3914,37 +4296,35 @@ expand_builtin_strncat (tree exp, rtx)
   tree destsize = compute_objsize (dest, warn_stringop_overflow - 1);
 
   /* Add one for the terminating nul.  */
-  tree srclen = (lenrange[0]
-                ? fold_build2 (PLUS_EXPR, size_type_node, lenrange[0],
+  tree srclen = (maxlen
+                ? fold_build2 (PLUS_EXPR, size_type_node, maxlen,
                                size_one_node)
                 : NULL_TREE);
 
-  /* Strncat copies at most MAXLEN bytes and always appends the terminating
-     nul so the specified upper bound should never be equal to (or greater
-     than) the size of the destination.  */
-  if (tree_fits_uhwi_p (maxlen) && tree_fits_uhwi_p (destsize)
-      && tree_int_cst_equal (destsize, maxlen))
+  /* The strncat function copies at most MAXREAD bytes and always appends
+     the terminating nul so the specified upper bound should never be equal
+     to (or greater than) the size of the destination.  */
+  if (tree_fits_uhwi_p (maxread) && tree_fits_uhwi_p (destsize)
+      && tree_int_cst_equal (destsize, maxread))
     {
       location_t loc = tree_nonartificial_location (exp);
       loc = expansion_point_location_if_in_system_header (loc);
 
       warning_at (loc, OPT_Wstringop_overflow_,
                  "%K%qD specified bound %E equals destination size",
-                 exp, get_callee_fndecl (exp), maxlen);
+                 exp, get_callee_fndecl (exp), maxread);
 
       return NULL_RTX;
     }
 
   if (!srclen
-      || (maxlen && tree_fits_uhwi_p (maxlen)
+      || (maxread && tree_fits_uhwi_p (maxread)
          && tree_fits_uhwi_p (srclen)
-         && tree_int_cst_lt (maxlen, srclen)))
-    srclen = maxlen;
+         && tree_int_cst_lt (maxread, srclen)))
+    srclen = maxread;
 
-  /* The number of bytes to write is LEN but check_sizes will also
-     check SRCLEN if LEN's value isn't known.  */
-  check_sizes (OPT_Wstringop_overflow_,
-              exp, /*size=*/NULL_TREE, maxlen, srclen, destsize);
+  /* The number of bytes to write is SRCLEN.  */
+  check_access (exp, dest, src, NULL_TREE, maxread, srclen, destsize);
 
   return NULL_RTX;
 }
@@ -3972,10 +4352,10 @@ expand_builtin_strncpy (tree exp, rtx target)
          tree destsize = compute_objsize (dest,
                                           warn_stringop_overflow - 1);
 
-         /* The number of bytes to write is LEN but check_sizes will also
+         /* The number of bytes to write is LEN but check_access will also
             check SLEN if LEN's value isn't known.  */
-         check_sizes (OPT_Wstringop_overflow_,
-                      exp, len, /*maxlen=*/NULL_TREE, src, destsize);
+         check_access (exp, dest, src, len, /*maxread=*/NULL_TREE, src,
+                       destsize);
        }
 
       /* We must be passed a constant len and src parameter.  */
@@ -4003,7 +4383,8 @@ expand_builtin_strncpy (tree exp, rtx target)
          dest_mem = get_memory_rtx (dest, len);
          store_by_pieces (dest_mem, tree_to_uhwi (len),
                           builtin_strncpy_read_str,
-                          CONST_CAST (char *, p), dest_align, false, 0);
+                          CONST_CAST (char *, p), dest_align, false,
+                          RETURN_BEGIN);
          dest_mem = force_operand (XEXP (dest_mem, 0), target);
          dest_mem = convert_memory_address (ptr_mode, dest_mem);
          return dest_mem;
@@ -4018,7 +4399,7 @@ expand_builtin_strncpy (tree exp, rtx target)
 
 rtx
 builtin_memset_read_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
-                        machine_mode mode)
+                        scalar_int_mode mode)
 {
   const char *c = (const char *) data;
   char *p = XALLOCAVEC (char, GET_MODE_SIZE (mode));
@@ -4035,7 +4416,7 @@ builtin_memset_read_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
 
 static rtx
 builtin_memset_gen_str (void *data, HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
-                       machine_mode mode)
+                       scalar_int_mode mode)
 {
   rtx target, coeff;
   size_t size;
@@ -4070,41 +4451,11 @@ expand_builtin_memset (tree exp, rtx target, machine_mode mode)
   tree val = CALL_EXPR_ARG (exp, 1);
   tree len = CALL_EXPR_ARG (exp, 2);
 
-  check_memop_sizes (exp, dest, NULL_TREE, len);
+  check_memop_access (exp, dest, NULL_TREE, len);
 
   return expand_builtin_memset_args (dest, val, len, target, mode, exp);
 }
 
-/* Expand expression EXP, which is an instrumented call to the memset builtin.
-   Return NULL_RTX if we failed the caller should emit a normal call, otherwise
-   try to get the result in TARGET, if convenient (and in mode MODE if that's
-   convenient).  */
-
-static rtx
-expand_builtin_memset_with_bounds (tree exp, rtx target, machine_mode mode)
-{
-  if (!validate_arglist (exp,
-                        POINTER_TYPE, POINTER_BOUNDS_TYPE,
-                        INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
-    return NULL_RTX;
-  else
-    {
-      tree dest = CALL_EXPR_ARG (exp, 0);
-      tree val = CALL_EXPR_ARG (exp, 2);
-      tree len = CALL_EXPR_ARG (exp, 3);
-      rtx res = expand_builtin_memset_args (dest, val, len, target, mode, exp);
-
-      /* Return src bounds with the result.  */
-      if (res)
-       {
-         rtx bnd = force_reg (targetm.chkp_bound_mode (),
-                              expand_normal (CALL_EXPR_ARG (exp, 1)));
-         res = chkp_join_splitted_slot (res, bnd);
-       }
-      return res;
-    }
-}
-
 /* Helper function to do the actual work for expand_builtin_memset.  The
    arguments to the builtin_memset call DEST, VAL, and LEN are broken out
    so that this can also be called without constructing an actual CALL_EXPR.
@@ -4178,7 +4529,7 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
          val_rtx = force_reg (val_mode, val_rtx);
          store_by_pieces (dest_mem, tree_to_uhwi (len),
                           builtin_memset_gen_str, val_rtx, dest_align,
-                          true, 0);
+                          true, RETURN_BEGIN);
        }
       else if (!set_storage_via_setmem (dest_mem, len_rtx, val_rtx,
                                        dest_align, expected_align,
@@ -4201,7 +4552,8 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
                                  builtin_memset_read_str, &c, dest_align,
                                  true))
        store_by_pieces (dest_mem, tree_to_uhwi (len),
-                        builtin_memset_read_str, &c, dest_align, true, 0);
+                        builtin_memset_read_str, &c, dest_align, true,
+                        RETURN_BEGIN);
       else if (!set_storage_via_setmem (dest_mem, len_rtx,
                                        gen_int_mode (c, val_mode),
                                        dest_align, expected_align,
@@ -4233,8 +4585,7 @@ expand_builtin_memset_args (tree dest, tree val, tree len,
  do_libcall:
   fndecl = get_callee_fndecl (orig_exp);
   fcode = DECL_FUNCTION_CODE (fndecl);
-  if (fcode == BUILT_IN_MEMSET
-      || fcode == BUILT_IN_CHKP_MEMSET_NOBND_NOCHK_CHKP)
+  if (fcode == BUILT_IN_MEMSET)
     fn = build_call_nofold_loc (EXPR_LOCATION (orig_exp), fndecl, 3,
                                dest, val, len);
   else if (fcode == BUILT_IN_BZERO)
@@ -4259,7 +4610,7 @@ expand_builtin_bzero (tree exp)
   tree dest = CALL_EXPR_ARG (exp, 0);
   tree size = CALL_EXPR_ARG (exp, 1);
 
-  check_memop_sizes (exp, dest, NULL_TREE, size);
+  check_memop_access (exp, dest, NULL_TREE, size);
 
   /* New argument list transforming bzero(ptr x, int y) to
      memset(ptr x, int 0, size_t y).   This is done this way
@@ -4312,21 +4663,37 @@ expand_builtin_memcmp (tree exp, rtx target, bool result_eq)
   tree arg1 = CALL_EXPR_ARG (exp, 0);
   tree arg2 = CALL_EXPR_ARG (exp, 1);
   tree len = CALL_EXPR_ARG (exp, 2);
+  enum built_in_function fcode = DECL_FUNCTION_CODE (get_callee_fndecl (exp));
+  bool no_overflow = true;
 
   /* Diagnose calls where the specified length exceeds the size of either
      object.  */
-  if (warn_stringop_overflow)
+  tree size = compute_objsize (arg1, 0);
+  no_overflow = check_access (exp, /*dst=*/NULL_TREE, /*src=*/NULL_TREE,
+                             len, /*maxread=*/NULL_TREE, size,
+                             /*objsize=*/NULL_TREE);
+  if (no_overflow)
     {
-      tree size = compute_objsize (arg1, 0);
-      if (check_sizes (OPT_Wstringop_overflow_,
-                      exp, len, /*maxlen=*/NULL_TREE,
-                      size, /*objsize=*/NULL_TREE))
-       {
-         size = compute_objsize (arg2, 0);
-         check_sizes (OPT_Wstringop_overflow_,
-                      exp, len, /*maxlen=*/NULL_TREE,
-                      size, /*objsize=*/NULL_TREE);
-       }
+      size = compute_objsize (arg2, 0);
+      no_overflow = check_access (exp, /*dst=*/NULL_TREE, /*src=*/NULL_TREE,
+                                 len,  /*maxread=*/NULL_TREE, size,
+                                 /*objsize=*/NULL_TREE);
+    }
+
+  /* If the specified length exceeds the size of either object, 
+     call the function.  */
+  if (!no_overflow)
+    return NULL_RTX;
+
+  /* Due to the performance benefit, always inline the calls first
+     when result_eq is false.  */
+  rtx result = NULL_RTX;
+
+  if (!result_eq && fcode != BUILT_IN_BCMP)
+    {
+      result = inline_expand_builtin_string_cmp (exp, target);
+      if (result)
+       return result;
     }
 
   machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
@@ -4368,10 +4735,10 @@ expand_builtin_memcmp (tree exp, rtx target, bool result_eq)
       && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1)
     constfn = builtin_memcpy_read_str;
 
-  rtx result = emit_block_cmp_hints (arg1_rtx, arg2_rtx, len_rtx,
-                                    TREE_TYPE (len), target,
-                                    result_eq, constfn,
-                                    CONST_CAST (char *, src_str));
+  result = emit_block_cmp_hints (arg1_rtx, arg2_rtx, len_rtx,
+                                TREE_TYPE (len), target,
+                                result_eq, constfn,
+                                CONST_CAST (char *, src_str));
 
   if (result)
     {
@@ -4401,104 +4768,111 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return NULL_RTX;
 
+  /* Due to the performance benefit, always inline the calls first.  */
+  rtx result = NULL_RTX;
+  result = inline_expand_builtin_string_cmp (exp, target);
+  if (result)
+    return result;
+
   insn_code cmpstr_icode = direct_optab_handler (cmpstr_optab, SImode);
   insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
-  if (cmpstr_icode != CODE_FOR_nothing || cmpstrn_icode != CODE_FOR_nothing)
-    {
-      rtx arg1_rtx, arg2_rtx;
-      tree fndecl, fn;
-      tree arg1 = CALL_EXPR_ARG (exp, 0);
-      tree arg2 = CALL_EXPR_ARG (exp, 1);
-      rtx result = NULL_RTX;
+  if (cmpstr_icode == CODE_FOR_nothing && cmpstrn_icode == CODE_FOR_nothing)
+    return NULL_RTX;
 
-      unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
-      unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
+  tree arg1 = CALL_EXPR_ARG (exp, 0);
+  tree arg2 = CALL_EXPR_ARG (exp, 1);
 
-      /* If we don't have POINTER_TYPE, call the function.  */
-      if (arg1_align == 0 || arg2_align == 0)
-       return NULL_RTX;
+  unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
+  unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
 
-      /* Stabilize the arguments in case gen_cmpstr(n)si fail.  */
-      arg1 = builtin_save_expr (arg1);
-      arg2 = builtin_save_expr (arg2);
+  /* If we don't have POINTER_TYPE, call the function.  */
+  if (arg1_align == 0 || arg2_align == 0)
+    return NULL_RTX;
 
-      arg1_rtx = get_memory_rtx (arg1, NULL);
-      arg2_rtx = get_memory_rtx (arg2, NULL);
+  /* Stabilize the arguments in case gen_cmpstr(n)si fail.  */
+  arg1 = builtin_save_expr (arg1);
+  arg2 = builtin_save_expr (arg2);
 
-      /* Try to call cmpstrsi.  */
-      if (cmpstr_icode != CODE_FOR_nothing)
-       result = expand_cmpstr (cmpstr_icode, target, arg1_rtx, arg2_rtx,
-                               MIN (arg1_align, arg2_align));
+  rtx arg1_rtx = get_memory_rtx (arg1, NULL);
+  rtx arg2_rtx = get_memory_rtx (arg2, NULL);
 
-      /* Try to determine at least one length and call cmpstrnsi.  */
-      if (!result && cmpstrn_icode != CODE_FOR_nothing)
-       {
-         tree len;
-         rtx arg3_rtx;
-
-         tree len1 = c_strlen (arg1, 1);
-         tree len2 = c_strlen (arg2, 1);
-
-         if (len1)
-           len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
-         if (len2)
-           len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
-
-         /* If we don't have a constant length for the first, use the length
-            of the second, if we know it.  We don't require a constant for
-            this case; some cost analysis could be done if both are available
-            but neither is constant.  For now, assume they're equally cheap,
-            unless one has side effects.  If both strings have constant lengths,
-            use the smaller.  */
-
-         if (!len1)
-           len = len2;
-         else if (!len2)
-           len = len1;
-         else if (TREE_SIDE_EFFECTS (len1))
-           len = len2;
-         else if (TREE_SIDE_EFFECTS (len2))
-           len = len1;
-         else if (TREE_CODE (len1) != INTEGER_CST)
-           len = len2;
-         else if (TREE_CODE (len2) != INTEGER_CST)
-           len = len1;
-         else if (tree_int_cst_lt (len1, len2))
-           len = len1;
-         else
-           len = len2;
+  /* Try to call cmpstrsi.  */
+  if (cmpstr_icode != CODE_FOR_nothing)
+    result = expand_cmpstr (cmpstr_icode, target, arg1_rtx, arg2_rtx,
+                           MIN (arg1_align, arg2_align));
 
-         /* If both arguments have side effects, we cannot optimize.  */
-         if (len && !TREE_SIDE_EFFECTS (len))
-           {
-             arg3_rtx = expand_normal (len);
-             result = expand_cmpstrn_or_cmpmem
-               (cmpstrn_icode, target, arg1_rtx, arg2_rtx, TREE_TYPE (len),
-                arg3_rtx, MIN (arg1_align, arg2_align));
-           }
-       }
+  /* Try to determine at least one length and call cmpstrnsi.  */
+  if (!result && cmpstrn_icode != CODE_FOR_nothing)
+    {
+      tree len;
+      rtx arg3_rtx;
+
+      tree len1 = c_strlen (arg1, 1);
+      tree len2 = c_strlen (arg2, 1);
+
+      if (len1)
+       len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
+      if (len2)
+       len2 = size_binop (PLUS_EXPR, ssize_int (1), len2);
+
+      /* If we don't have a constant length for the first, use the length
+        of the second, if we know it.  We don't require a constant for
+        this case; some cost analysis could be done if both are available
+        but neither is constant.  For now, assume they're equally cheap,
+        unless one has side effects.  If both strings have constant lengths,
+        use the smaller.  */
+
+      if (!len1)
+       len = len2;
+      else if (!len2)
+       len = len1;
+      else if (TREE_SIDE_EFFECTS (len1))
+       len = len2;
+      else if (TREE_SIDE_EFFECTS (len2))
+       len = len1;
+      else if (TREE_CODE (len1) != INTEGER_CST)
+       len = len2;
+      else if (TREE_CODE (len2) != INTEGER_CST)
+       len = len1;
+      else if (tree_int_cst_lt (len1, len2))
+       len = len1;
+      else
+       len = len2;
 
-      if (result)
+      /* If both arguments have side effects, we cannot optimize.  */
+      if (len && !TREE_SIDE_EFFECTS (len))
        {
-         /* Return the value in the proper mode for this function.  */
-         machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
-         if (GET_MODE (result) == mode)
-           return result;
-         if (target == 0)
-           return convert_to_mode (mode, result, 0);
-         convert_move (target, result, 0);
-         return target;
+         arg3_rtx = expand_normal (len);
+         result = expand_cmpstrn_or_cmpmem
+           (cmpstrn_icode, target, arg1_rtx, arg2_rtx, TREE_TYPE (len),
+            arg3_rtx, MIN (arg1_align, arg2_align));
        }
+    }
 
-      /* Expand the library call ourselves using a stabilized argument
-        list to avoid re-evaluating the function's arguments twice.  */
-      fndecl = get_callee_fndecl (exp);
-      fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 2, arg1, arg2);
-      gcc_assert (TREE_CODE (fn) == CALL_EXPR);
-      CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
-      return expand_call (fn, target, target == const0_rtx);
+  tree fndecl = get_callee_fndecl (exp);
+  if (result)
+    {
+      /* Check to see if the argument was declared attribute nonstring
+        and if so, issue a warning since at this point it's not known
+        to be nul-terminated.  */
+      maybe_warn_nonstring_arg (fndecl, exp);
+
+      /* Return the value in the proper mode for this function.  */
+      machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
+      if (GET_MODE (result) == mode)
+       return result;
+      if (target == 0)
+       return convert_to_mode (mode, result, 0);
+      convert_move (target, result, 0);
+      return target;
     }
-  return NULL_RTX;
+
+  /* Expand the library call ourselves using a stabilized argument
+     list to avoid re-evaluating the function's arguments twice.  */
+  tree fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 2, arg1, arg2);
+  gcc_assert (TREE_CODE (fn) == CALL_EXPR);
+  CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
+  return expand_call (fn, target, target == const0_rtx);
 }
 
 /* Expand expression EXP, which is a call to the strncmp builtin. Return
@@ -4509,98 +4883,109 @@ static rtx
 expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
                        ATTRIBUTE_UNUSED machine_mode mode)
 {
-  location_t loc ATTRIBUTE_UNUSED = EXPR_LOCATION (exp);
+  if (!validate_arglist (exp,
+                        POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+    return NULL_RTX;
+
+  /* Due to the performance benefit, always inline the calls first.  */
+  rtx result = NULL_RTX;
+  result = inline_expand_builtin_string_cmp (exp, target);
+  if (result)
+    return result;
+
+  /* If c_strlen can determine an expression for one of the string
+     lengths, and it doesn't have side effects, then emit cmpstrnsi
+     using length MIN(strlen(string)+1, arg3).  */
+  insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
+  if (cmpstrn_icode == CODE_FOR_nothing)
+    return NULL_RTX;
+
+  tree len;
+
+  tree arg1 = CALL_EXPR_ARG (exp, 0);
+  tree arg2 = CALL_EXPR_ARG (exp, 1);
+  tree arg3 = CALL_EXPR_ARG (exp, 2);
+
+  unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
+  unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
+
+  tree len1 = c_strlen (arg1, 1);
+  tree len2 = c_strlen (arg2, 1);
 
-  if (!validate_arglist (exp,
-                        POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
-    return NULL_RTX;
+  location_t loc = EXPR_LOCATION (exp);
 
-  /* If c_strlen can determine an expression for one of the string
-     lengths, and it doesn't have side effects, then emit cmpstrnsi
-     using length MIN(strlen(string)+1, arg3).  */
-  insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
-  if (cmpstrn_icode != CODE_FOR_nothing)
-  {
-    tree len, len1, len2, len3;
-    rtx arg1_rtx, arg2_rtx, arg3_rtx;
-    rtx result;
-    tree fndecl, fn;
-    tree arg1 = CALL_EXPR_ARG (exp, 0);
-    tree arg2 = CALL_EXPR_ARG (exp, 1);
-    tree arg3 = CALL_EXPR_ARG (exp, 2);
-
-    unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
-    unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
-
-    len1 = c_strlen (arg1, 1);
-    len2 = c_strlen (arg2, 1);
-
-    if (len1)
-      len1 = size_binop_loc (loc, PLUS_EXPR, ssize_int (1), len1);
-    if (len2)
-      len2 = size_binop_loc (loc, PLUS_EXPR, ssize_int (1), len2);
-
-    len3 = fold_convert_loc (loc, sizetype, arg3);
-
-    /* If we don't have a constant length for the first, use the length
-       of the second, if we know it.  If neither string is constant length,
-       use the given length argument.  We don't require a constant for
-       this case; some cost analysis could be done if both are available
-       but neither is constant.  For now, assume they're equally cheap,
-       unless one has side effects.  If both strings have constant lengths,
-       use the smaller.  */
-
-    if (!len1 && !len2)
-      len = len3;
-    else if (!len1)
-      len = len2;
-    else if (!len2)
-      len = len1;
-    else if (TREE_SIDE_EFFECTS (len1))
-      len = len2;
-    else if (TREE_SIDE_EFFECTS (len2))
-      len = len1;
-    else if (TREE_CODE (len1) != INTEGER_CST)
-      len = len2;
-    else if (TREE_CODE (len2) != INTEGER_CST)
-      len = len1;
-    else if (tree_int_cst_lt (len1, len2))
-      len = len1;
-    else
-      len = len2;
+  if (len1)
+    len1 = size_binop_loc (loc, PLUS_EXPR, ssize_int (1), len1);
+  if (len2)
+    len2 = size_binop_loc (loc, PLUS_EXPR, ssize_int (1), len2);
+
+  tree len3 = fold_convert_loc (loc, sizetype, arg3);
+
+  /* If we don't have a constant length for the first, use the length
+     of the second, if we know it.  If neither string is constant length,
+     use the given length argument.  We don't require a constant for
+     this case; some cost analysis could be done if both are available
+     but neither is constant.  For now, assume they're equally cheap,
+     unless one has side effects.  If both strings have constant lengths,
+     use the smaller.  */
+
+  if (!len1 && !len2)
+    len = len3;
+  else if (!len1)
+    len = len2;
+  else if (!len2)
+    len = len1;
+  else if (TREE_SIDE_EFFECTS (len1))
+    len = len2;
+  else if (TREE_SIDE_EFFECTS (len2))
+    len = len1;
+  else if (TREE_CODE (len1) != INTEGER_CST)
+    len = len2;
+  else if (TREE_CODE (len2) != INTEGER_CST)
+    len = len1;
+  else if (tree_int_cst_lt (len1, len2))
+    len = len1;
+  else
+    len = len2;
 
-    /* If we are not using the given length, we must incorporate it here.
-       The actual new length parameter will be MIN(len,arg3) in this case.  */
-    if (len != len3)
+  /* If we are not using the given length, we must incorporate it here.
+     The actual new length parameter will be MIN(len,arg3) in this case.  */
+  if (len != len3)
+    {
+      len = fold_convert_loc (loc, sizetype, len);
       len = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (len), len, len3);
-    arg1_rtx = get_memory_rtx (arg1, len);
-    arg2_rtx = get_memory_rtx (arg2, len);
-    arg3_rtx = expand_normal (len);
-    result = expand_cmpstrn_or_cmpmem (cmpstrn_icode, target, arg1_rtx,
-                                      arg2_rtx, TREE_TYPE (len), arg3_rtx,
-                                      MIN (arg1_align, arg2_align));
-    if (result)
-      {
-       /* Return the value in the proper mode for this function.  */
-       mode = TYPE_MODE (TREE_TYPE (exp));
-       if (GET_MODE (result) == mode)
-         return result;
-       if (target == 0)
-         return convert_to_mode (mode, result, 0);
-       convert_move (target, result, 0);
-       return target;
-      }
+    }
+  rtx arg1_rtx = get_memory_rtx (arg1, len);
+  rtx arg2_rtx = get_memory_rtx (arg2, len);
+  rtx arg3_rtx = expand_normal (len);
+  result = expand_cmpstrn_or_cmpmem (cmpstrn_icode, target, arg1_rtx,
+                                    arg2_rtx, TREE_TYPE (len), arg3_rtx,
+                                    MIN (arg1_align, arg2_align));
 
-    /* Expand the library call ourselves using a stabilized argument
-       list to avoid re-evaluating the function's arguments twice.  */
-    fndecl = get_callee_fndecl (exp);
-    fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 3,
-                               arg1, arg2, len);
-    gcc_assert (TREE_CODE (fn) == CALL_EXPR);
-    CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
-    return expand_call (fn, target, target == const0_rtx);
-  }
-  return NULL_RTX;
+  tree fndecl = get_callee_fndecl (exp);
+  if (result)
+    {
+      /* Check to see if the argument was declared attribute nonstring
+        and if so, issue a warning since at this point it's not known
+        to be nul-terminated.  */
+      maybe_warn_nonstring_arg (fndecl, exp);
+
+      /* Return the value in the proper mode for this function.  */
+      mode = TYPE_MODE (TREE_TYPE (exp));
+      if (GET_MODE (result) == mode)
+       return result;
+      if (target == 0)
+       return convert_to_mode (mode, result, 0);
+      convert_move (target, result, 0);
+      return target;
+    }
+
+  /* Expand the library call ourselves using a stabilized argument
+     list to avoid re-evaluating the function's arguments twice.  */
+  tree fn = build_call_nofold_loc (loc, fndecl, 3, arg1, arg2, len);
+  gcc_assert (TREE_CODE (fn) == CALL_EXPR);
+  CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
+  return expand_call (fn, target, target == const0_rtx);
 }
 
 /* Expand a call to __builtin_saveregs, generating the result in TARGET,
@@ -4757,13 +5142,6 @@ std_expand_builtin_va_start (tree valist, rtx nextarg)
 {
   rtx va_r = expand_expr (valist, NULL_RTX, VOIDmode, EXPAND_WRITE);
   convert_move (va_r, nextarg, 0);
-
-  /* We do not have any valid bounds for the pointer, so
-     just store zero bounds for it.  */
-  if (chkp_function_instrumented_p (current_function_decl))
-    chkp_expand_bounds_reset_for_mem (valist,
-                                     make_tree (TREE_TYPE (valist),
-                                                nextarg));
 }
 
 /* Expand EXP, a call to __builtin_va_start.  */
@@ -4923,24 +5301,34 @@ expand_builtin_alloca (tree exp)
   rtx result;
   unsigned int align;
   tree fndecl = get_callee_fndecl (exp);
-  bool alloca_with_align = (DECL_FUNCTION_CODE (fndecl)
-                           == BUILT_IN_ALLOCA_WITH_ALIGN);
+  HOST_WIDE_INT max_size;
+  enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
   bool alloca_for_var = CALL_ALLOCA_FOR_VAR_P (exp);
   bool valid_arglist
-    = (alloca_with_align
-       ? validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)
-       : validate_arglist (exp, INTEGER_TYPE, VOID_TYPE));
+    = (fcode == BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX
+       ? validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE,
+                          VOID_TYPE)
+       : fcode == BUILT_IN_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;
 
-  if ((alloca_with_align && !warn_vla_limit)
-      || (!alloca_with_align && !warn_alloca_limit))
-    {
-      /* -Walloca-larger-than and -Wvla-larger-than settings override
-        the more general -Walloc-size-larger-than so unless either of
-        the former options is specified check the alloca arguments for
-        overflow.  */
+  if ((alloca_for_var
+       && warn_vla_limit >= HOST_WIDE_INT_MAX
+       && warn_alloc_size_limit < warn_vla_limit)
+      || (!alloca_for_var
+         && warn_alloca_limit >= HOST_WIDE_INT_MAX
+         && warn_alloc_size_limit < warn_alloca_limit
+         ))
+    {
+      /* -Walloca-larger-than and -Wvla-larger-than settings of
+        less than HOST_WIDE_INT_MAX override the more general
+        -Walloc-size-larger-than so unless either of the former
+        options is smaller than the last one (wchich would imply
+        that the call was already checked), check the alloca
+        arguments for overflow.  */
       tree args[] = { CALL_EXPR_ARG (exp, 0), NULL_TREE };
       int idx[] = { 0, -1 };
       maybe_warn_alloc_args_overflow (fndecl, exp, args, idx);
@@ -4950,33 +5338,45 @@ expand_builtin_alloca (tree exp)
   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);
+  align = (fcode == BUILT_IN_ALLOCA
+          ? BIGGEST_ALIGNMENT
+          : TREE_INT_CST_LOW (CALL_EXPR_ARG (exp, 1)));
+
+  /* Compute the maximum size.  */
+  max_size = (fcode == BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX
+              ? TREE_INT_CST_LOW (CALL_EXPR_ARG (exp, 2))
+              : -1);
 
   /* Allocate the desired space.  If the allocation stems from the declaration
      of a variable-sized object, it cannot accumulate.  */
-  result = allocate_dynamic_stack_space (op0, 0, align, alloca_for_var);
+  result
+    = allocate_dynamic_stack_space (op0, 0, align, max_size, alloca_for_var);
   result = convert_memory_address (ptr_mode, result);
 
   return result;
 }
 
-/* Emit a call to __asan_allocas_unpoison call in EXP.  Replace second argument
-   of the call with virtual_stack_dynamic_rtx because in asan pass we emit a
-   dummy value into second parameter relying on this function to perform the
-   change.  See motivation for this in comment to handle_builtin_stack_restore
-   function.  */
+/* Emit a call to __asan_allocas_unpoison call in EXP.  Add to second argument
+   of the call virtual_stack_dynamic_rtx - stack_pointer_rtx, which is the
+   STACK_DYNAMIC_OFFSET value.  See motivation for this in comment to
+   handle_builtin_stack_restore function.  */
 
 static rtx
 expand_asan_emit_allocas_unpoison (tree exp)
 {
   tree arg0 = CALL_EXPR_ARG (exp, 0);
+  tree arg1 = CALL_EXPR_ARG (exp, 1);
   rtx top = expand_expr (arg0, NULL_RTX, ptr_mode, EXPAND_NORMAL);
-  rtx bot = convert_memory_address (ptr_mode, virtual_stack_dynamic_rtx);
+  rtx bot = expand_expr (arg1, NULL_RTX, ptr_mode, EXPAND_NORMAL);
+  rtx off = expand_simple_binop (Pmode, MINUS, virtual_stack_dynamic_rtx,
+                                stack_pointer_rtx, NULL_RTX, 0,
+                                OPTAB_LIB_WIDEN);
+  off = convert_modes (ptr_mode, Pmode, off, 0);
+  bot = expand_simple_binop (ptr_mode, PLUS, bot, off, NULL_RTX, 0,
+                            OPTAB_LIB_WIDEN);
   rtx ret = init_one_libfunc ("__asan_allocas_unpoison");
-  ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode, 2, top,
-                                ptr_mode, bot, ptr_mode);
+  ret = emit_library_call_value (ret, NULL_RTX, LCT_NORMAL, ptr_mode,
+                                top, ptr_mode, bot, ptr_mode);
   return ret;
 }
 
@@ -5059,6 +5459,27 @@ expand_builtin_expect (tree exp, rtx target)
   return target;
 }
 
+/* Expand a call to __builtin_expect_with_probability.  We just return our
+   argument as the builtin_expect semantic should've been already executed by
+   tree branch prediction pass.  */
+
+static rtx
+expand_builtin_expect_with_probability (tree exp, rtx target)
+{
+  tree arg;
+
+  if (call_expr_nargs (exp) < 3)
+    return const0_rtx;
+  arg = CALL_EXPR_ARG (exp, 0);
+
+  target = expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
+  /* When guessing was done, the hints should be already stripped away.  */
+  gcc_assert (!flag_guess_branch_prob
+             || optimize == 0 || seen_error ());
+  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.  */
@@ -5086,7 +5507,7 @@ expand_builtin_trap (void)
         REG_ARGS_SIZE note to prevent crossjumping of calls with
         different args sizes.  */
       if (!ACCUMULATE_OUTGOING_ARGS)
-       add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta));
+       add_args_size_note (insn, stack_pointer_delta);
     }
   else
     {
@@ -5367,7 +5788,8 @@ static rtx
 expand_builtin_signbit (tree exp, rtx target)
 {
   const struct real_format *fmt;
-  machine_mode fmode, imode, rmode;
+  scalar_float_mode fmode;
+  scalar_int_mode rmode, imode;
   tree arg;
   int word, bitpos;
   enum insn_code icode;
@@ -5378,8 +5800,8 @@ expand_builtin_signbit (tree exp, rtx target)
     return NULL_RTX;
 
   arg = CALL_EXPR_ARG (exp, 0);
-  fmode = TYPE_MODE (TREE_TYPE (arg));
-  rmode = TYPE_MODE (TREE_TYPE (exp));
+  fmode = SCALAR_FLOAT_TYPE_MODE (TREE_TYPE (arg));
+  rmode = SCALAR_INT_TYPE_MODE (TREE_TYPE (exp));
   fmt = REAL_MODE_FORMAT (fmode);
 
   arg = builtin_save_expr (arg);
@@ -5414,8 +5836,7 @@ expand_builtin_signbit (tree exp, rtx target)
 
   if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD)
     {
-      imode = int_mode_for_mode (fmode);
-      gcc_assert (imode != BLKmode);
+      imode = int_mode_for_mode (fmode).require ();
       temp = gen_lowpart (imode, temp);
     }
   else
@@ -5543,7 +5964,7 @@ get_builtin_sync_mode (int fcode_diff)
 {
   /* The size is not negotiable, so ask not to get BLKmode in return
      if the target indicates that a smaller size would be better.  */
-  return mode_for_size (BITS_PER_UNIT << fcode_diff, MODE_INT, 0);
+  return int_mode_for_size (BITS_PER_UNIT << fcode_diff, 0).require ();
 }
 
 /* Expand the memory expression LOC and return the appropriate memory operand
@@ -5553,14 +5974,22 @@ static rtx
 get_builtin_sync_mem (tree loc, machine_mode mode)
 {
   rtx addr, mem;
+  int addr_space = TYPE_ADDR_SPACE (POINTER_TYPE_P (TREE_TYPE (loc))
+                                   ? TREE_TYPE (TREE_TYPE (loc))
+                                   : TREE_TYPE (loc));
+  scalar_int_mode addr_mode = targetm.addr_space.address_mode (addr_space);
 
-  addr = expand_expr (loc, NULL_RTX, ptr_mode, EXPAND_SUM);
-  addr = convert_memory_address (Pmode, addr);
+  addr = expand_expr (loc, NULL_RTX, addr_mode, EXPAND_SUM);
+  addr = convert_memory_address (addr_mode, addr);
 
   /* Note that we explicitly do not want any alias information for this
      memory, so that we kill all other live memories.  Otherwise we don't
      satisfy the full barrier semantics of the intrinsic.  */
-  mem = validize_mem (gen_rtx_MEM (mode, addr));
+  mem = gen_rtx_MEM (mode, addr);
+
+  set_mem_addr_space (mem, addr_space);
+
+  mem = validize_mem (mem);
 
   /* The alignment needs to be at least according to that of the mode.  */
   set_mem_align (mem, MAX (GET_MODE_ALIGNMENT (mode),
@@ -5729,7 +6158,7 @@ get_memmodel (tree exp)
 {
   rtx op;
   unsigned HOST_WIDE_INT val;
-  source_location loc
+  location_t loc
     = expansion_point_location_if_in_system_header (input_location);
 
   /* If the parameter is not a constant, it's a run time value so we'll just
@@ -5805,7 +6234,7 @@ expand_builtin_atomic_compare_exchange (machine_mode mode, tree exp,
   enum memmodel success, failure;
   tree weak;
   bool is_weak;
-  source_location loc
+  location_t loc
     = expansion_point_location_if_in_system_header (input_location);
 
   success = get_memmodel (CALL_EXPR_ARG (exp, 4));
@@ -5897,9 +6326,12 @@ expand_ifn_atomic_compare_exchange_into_call (gcall *call, machine_mode mode)
   /* Skip the boolean weak parameter.  */
   for (z = 4; z < 6; z++)
     vec->quick_push (gimple_call_arg (call, z));
+  /* At present we only have BUILT_IN_ATOMIC_COMPARE_EXCHANGE_{1,2,4,8,16}.  */
+  unsigned int bytes_log2 = exact_log2 (GET_MODE_SIZE (mode).to_constant ());
+  gcc_assert (bytes_log2 < 5);
   built_in_function fncode
     = (built_in_function) ((int) BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1
-                          + exact_log2 (GET_MODE_SIZE (mode)));
+                          + bytes_log2);
   tree fndecl = builtin_decl_explicit (fncode);
   tree fn = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fndecl)),
                    fndecl);
@@ -5924,12 +6356,12 @@ expand_ifn_atomic_compare_exchange (gcall *call)
 {
   int size = tree_to_shwi (gimple_call_arg (call, 3)) & 255;
   gcc_assert (size == 1 || size == 2 || size == 4 || size == 8 || size == 16);
-  machine_mode mode = mode_for_size (BITS_PER_UNIT * size, MODE_INT, 0);
+  machine_mode mode = int_mode_for_size (BITS_PER_UNIT * size, 0).require ();
   rtx expect, desired, mem, oldval, boolret;
   enum memmodel success, failure;
   tree lhs;
   bool is_weak;
-  source_location loc
+  location_t loc
     = expansion_point_location_if_in_system_header (gimple_location (call));
 
   success = get_memmodel (gimple_call_arg (call, 4));
@@ -6001,7 +6433,7 @@ expand_builtin_atomic_load (machine_mode mode, tree exp, rtx target)
   model = get_memmodel (CALL_EXPR_ARG (exp, 1));
   if (is_mm_release (model) || is_mm_acq_rel (model))
     {
-      source_location loc
+      location_t loc
        = expansion_point_location_if_in_system_header (input_location);
       warning_at (loc, OPT_Winvalid_memory_model,
                  "invalid memory model for %<__atomic_load%>");
@@ -6033,7 +6465,7 @@ expand_builtin_atomic_store (machine_mode mode, tree exp)
   if (!(is_mm_relaxed (model) || is_mm_seq_cst (model)
        || is_mm_release (model)))
     {
-      source_location loc
+      location_t loc
        = expansion_point_location_if_in_system_header (input_location);
       warning_at (loc, OPT_Winvalid_memory_model,
                  "invalid memory model for %<__atomic_store%>");
@@ -6220,13 +6652,13 @@ expand_builtin_atomic_clear (tree exp)
   rtx mem, ret;
   enum memmodel model;
 
-  mode = mode_for_size (BOOL_TYPE_SIZE, MODE_INT, 0);
+  mode = int_mode_for_size (BOOL_TYPE_SIZE, 0).require ();
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
   model = get_memmodel (CALL_EXPR_ARG (exp, 1));
 
   if (is_mm_consume (model) || is_mm_acquire (model) || is_mm_acq_rel (model))
     {
-      source_location loc
+      location_t loc
        = expansion_point_location_if_in_system_header (input_location);
       warning_at (loc, OPT_Winvalid_memory_model,
                  "invalid memory model for %<__atomic_store%>");
@@ -6255,7 +6687,7 @@ expand_builtin_atomic_test_and_set (tree exp, rtx target)
   enum memmodel model;
   machine_mode mode;
 
-  mode = mode_for_size (BOOL_TYPE_SIZE, MODE_INT, 0);
+  mode = int_mode_for_size (BOOL_TYPE_SIZE, 0).require ();
   mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
   model = get_memmodel (CALL_EXPR_ARG (exp, 1));
 
@@ -6276,8 +6708,11 @@ fold_builtin_atomic_always_lock_free (tree arg0, tree arg1)
   if (TREE_CODE (arg0) != INTEGER_CST)
     return NULL_TREE;
 
+  /* We need a corresponding integer mode for the access to be lock-free.  */
   size = INTVAL (expand_normal (arg0)) * BITS_PER_UNIT;
-  mode = mode_for_size (size, MODE_INT, 0);
+  if (!int_mode_for_size (size, 0).exists (&mode))
+    return boolean_false_node;
+
   mode_align = GET_MODE_ALIGNMENT (mode);
 
   if (TREE_CODE (arg1) == INTEGER_CST)
@@ -6506,6 +6941,268 @@ expand_stack_save (void)
   return ret;
 }
 
+/* Emit code to get the openacc gang, worker or vector id or size.  */
+
+static rtx
+expand_builtin_goacc_parlevel_id_size (tree exp, rtx target, int ignore)
+{
+  const char *name;
+  rtx fallback_retval;
+  rtx_insn *(*gen_fn) (rtx, rtx);
+  switch (DECL_FUNCTION_CODE (get_callee_fndecl (exp)))
+    {
+    case BUILT_IN_GOACC_PARLEVEL_ID:
+      name = "__builtin_goacc_parlevel_id";
+      fallback_retval = const0_rtx;
+      gen_fn = targetm.gen_oacc_dim_pos;
+      break;
+    case BUILT_IN_GOACC_PARLEVEL_SIZE:
+      name = "__builtin_goacc_parlevel_size";
+      fallback_retval = const1_rtx;
+      gen_fn = targetm.gen_oacc_dim_size;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (oacc_get_fn_attrib (current_function_decl) == NULL_TREE)
+    {
+      error ("%qs only supported in OpenACC code", name);
+      return const0_rtx;
+    }
+
+  tree arg = CALL_EXPR_ARG (exp, 0);
+  if (TREE_CODE (arg) != INTEGER_CST)
+    {
+      error ("non-constant argument 0 to %qs", name);
+      return const0_rtx;
+    }
+
+  int dim = TREE_INT_CST_LOW (arg);
+  switch (dim)
+    {
+    case GOMP_DIM_GANG:
+    case GOMP_DIM_WORKER:
+    case GOMP_DIM_VECTOR:
+      break;
+    default:
+      error ("illegal argument 0 to %qs", name);
+      return const0_rtx;
+    }
+
+  if (ignore)
+    return target;
+
+  if (target == NULL_RTX)
+    target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
+
+  if (!targetm.have_oacc_dim_size ())
+    {
+      emit_move_insn (target, fallback_retval);
+      return target;
+    }
+
+  rtx reg = MEM_P (target) ? gen_reg_rtx (GET_MODE (target)) : target;
+  emit_insn (gen_fn (reg, GEN_INT (dim)));
+  if (reg != target)
+    emit_move_insn (target, reg);
+
+  return target;
+}
+
+/* Expand a string compare operation using a sequence of char comparison
+   to get rid of the calling overhead, with result going to TARGET if
+   that's convenient.
+
+   VAR_STR is the variable string source;
+   CONST_STR is the constant string source;
+   LENGTH is the number of chars to compare;
+   CONST_STR_N indicates which source string is the constant string;
+   IS_MEMCMP indicates whether it's a memcmp or strcmp.
+  
+   to: (assume const_str_n is 2, i.e., arg2 is a constant string)
+
+   target = (int) (unsigned char) var_str[0]
+           - (int) (unsigned char) const_str[0];
+   if (target != 0)
+     goto ne_label;
+     ...
+   target = (int) (unsigned char) var_str[length - 2]
+           - (int) (unsigned char) const_str[length - 2];
+   if (target != 0)
+     goto ne_label;
+   target = (int) (unsigned char) var_str[length - 1]
+           - (int) (unsigned char) const_str[length - 1];
+   ne_label:
+  */
+
+static rtx
+inline_string_cmp (rtx target, tree var_str, const char *const_str,
+                  unsigned HOST_WIDE_INT length,
+                  int const_str_n, machine_mode mode)
+{
+  HOST_WIDE_INT offset = 0;
+  rtx var_rtx_array
+    = get_memory_rtx (var_str, build_int_cst (unsigned_type_node,length));
+  rtx var_rtx = NULL_RTX;
+  rtx const_rtx = NULL_RTX;
+  rtx result = target ? target : gen_reg_rtx (mode);
+  rtx_code_label *ne_label = gen_label_rtx ();
+  tree unit_type_node = unsigned_char_type_node;
+  scalar_int_mode unit_mode
+    = as_a <scalar_int_mode> TYPE_MODE (unit_type_node);
+
+  start_sequence ();
+
+  for (unsigned HOST_WIDE_INT i = 0; i < length; i++)
+    {
+      var_rtx
+       = adjust_address (var_rtx_array, TYPE_MODE (unit_type_node), offset);
+      const_rtx = c_readstr (const_str + offset, unit_mode);
+      rtx op0 = (const_str_n == 1) ? const_rtx : var_rtx;
+      rtx op1 = (const_str_n == 1) ? var_rtx : const_rtx;
+
+      op0 = convert_modes (mode, unit_mode, op0, 1);
+      op1 = convert_modes (mode, unit_mode, op1, 1);
+      result = expand_simple_binop (mode, MINUS, op0, op1,
+                                   result, 1, OPTAB_WIDEN);
+      if (i < length - 1)
+       emit_cmp_and_jump_insns (result, CONST0_RTX (mode), NE, NULL_RTX,
+                                mode, true, ne_label);
+      offset += GET_MODE_SIZE (unit_mode);
+    }
+
+  emit_label (ne_label);
+  rtx_insn *insns = get_insns ();
+  end_sequence ();
+  emit_insn (insns);
+
+  return result;
+}
+
+/* Inline expansion a call to str(n)cmp, with result going to
+   TARGET if that's convenient.
+   If the call is not been inlined, return NULL_RTX.  */
+static rtx
+inline_expand_builtin_string_cmp (tree exp, rtx target)
+{
+  tree fndecl = get_callee_fndecl (exp);
+  enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+  unsigned HOST_WIDE_INT length = 0;
+  bool is_ncmp = (fcode == BUILT_IN_STRNCMP || fcode == BUILT_IN_MEMCMP);
+
+  /* Do NOT apply this inlining expansion when optimizing for size or 
+     optimization level below 2.  */
+  if (optimize < 2 || optimize_insn_for_size_p ())
+    return NULL_RTX;
+
+  gcc_checking_assert (fcode == BUILT_IN_STRCMP
+                      || fcode == BUILT_IN_STRNCMP
+                      || fcode == BUILT_IN_MEMCMP);
+
+  /* On a target where the type of the call (int) has same or narrower presicion
+     than unsigned char, give up the inlining expansion.  */
+  if (TYPE_PRECISION (unsigned_char_type_node)
+      >= TYPE_PRECISION (TREE_TYPE (exp)))
+    return NULL_RTX;
+
+  tree arg1 = CALL_EXPR_ARG (exp, 0);
+  tree arg2 = CALL_EXPR_ARG (exp, 1);
+  tree len3_tree = is_ncmp ? CALL_EXPR_ARG (exp, 2) : NULL_TREE;
+
+  unsigned HOST_WIDE_INT len1 = 0;
+  unsigned HOST_WIDE_INT len2 = 0;
+  unsigned HOST_WIDE_INT len3 = 0;
+
+  const char *src_str1 = c_getstr (arg1, &len1);
+  const char *src_str2 = c_getstr (arg2, &len2);
+
+  /* If neither strings is constant string, the call is not qualify.  */
+  if (!src_str1 && !src_str2)
+    return NULL_RTX;
+
+  /* For strncmp, if the length is not a const, not qualify.  */
+  if (is_ncmp && !tree_fits_uhwi_p (len3_tree))
+    return NULL_RTX;
+
+  int const_str_n = 0;
+  if (!len1)
+    const_str_n = 2;
+  else if (!len2)
+    const_str_n = 1;
+  else if (len2 > len1)
+    const_str_n = 1;
+  else
+    const_str_n = 2;
+
+  gcc_checking_assert (const_str_n > 0);
+  length = (const_str_n == 1) ? len1 : len2;
+
+  if (is_ncmp && (len3 = tree_to_uhwi (len3_tree)) < length)
+    length = len3;
+
+  /* If the length of the comparision is larger than the threshold,
+     do nothing.  */
+  if (length > (unsigned HOST_WIDE_INT)
+              PARAM_VALUE (BUILTIN_STRING_CMP_INLINE_LENGTH))
+    return NULL_RTX;
+
+  machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
+
+  /* Now, start inline expansion the call.  */
+  return inline_string_cmp (target, (const_str_n == 1) ? arg2 : arg1,
+                           (const_str_n == 1) ? src_str1 : src_str2, length,
+                           const_str_n, mode);
+}
+
+/* Expand a call to __builtin_speculation_safe_value_<N>.  MODE
+   represents the size of the first argument to that call, or VOIDmode
+   if the argument is a pointer.  IGNORE will be true if the result
+   isn't used.  */
+static rtx
+expand_speculation_safe_value (machine_mode mode, tree exp, rtx target,
+                              bool ignore)
+{
+  rtx val, failsafe;
+  unsigned nargs = call_expr_nargs (exp);
+
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+
+  if (mode == VOIDmode)
+    {
+      mode = TYPE_MODE (TREE_TYPE (arg0));
+      gcc_assert (GET_MODE_CLASS (mode) == MODE_INT);
+    }
+
+  val = expand_expr (arg0, NULL_RTX, mode, EXPAND_NORMAL);
+
+  /* An optional second argument can be used as a failsafe value on
+     some machines.  If it isn't present, then the failsafe value is
+     assumed to be 0.  */
+  if (nargs > 1)
+    {
+      tree arg1 = CALL_EXPR_ARG (exp, 1);
+      failsafe = expand_expr (arg1, NULL_RTX, mode, EXPAND_NORMAL);
+    }
+  else
+    failsafe = const0_rtx;
+
+  /* If the result isn't used, the behavior is undefined.  It would be
+     nice to emit a warning here, but path splitting means this might
+     happen with legitimate code.  So simply drop the builtin
+     expansion in that case; we've handled any side-effects above.  */
+  if (ignore)
+    return const0_rtx;
+
+  /* If we don't have a suitable target, create one to hold the result.  */
+  if (target == NULL || GET_MODE (target) != mode)
+    target = gen_reg_rtx (mode);
+
+  if (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode)
+    val = convert_modes (mode, VOIDmode, val, false);
+
+  return targetm.speculation_safe_value (mode, target, val, failsafe);
+}
 
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
@@ -6544,21 +7241,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
       && fcode != BUILT_IN_EXECLE
       && fcode != BUILT_IN_EXECVP
       && fcode != BUILT_IN_EXECVE
-      && fcode != BUILT_IN_ALLOCA
-      && fcode != BUILT_IN_ALLOCA_WITH_ALIGN
-      && fcode != BUILT_IN_FREE
-      && fcode != BUILT_IN_CHKP_SET_PTR_BOUNDS
-      && fcode != BUILT_IN_CHKP_INIT_PTR_BOUNDS
-      && fcode != BUILT_IN_CHKP_NULL_PTR_BOUNDS
-      && fcode != BUILT_IN_CHKP_COPY_PTR_BOUNDS
-      && fcode != BUILT_IN_CHKP_NARROW_PTR_BOUNDS
-      && fcode != BUILT_IN_CHKP_STORE_PTR_BOUNDS
-      && fcode != BUILT_IN_CHKP_CHECK_PTR_LBOUNDS
-      && fcode != BUILT_IN_CHKP_CHECK_PTR_UBOUNDS
-      && fcode != BUILT_IN_CHKP_CHECK_PTR_BOUNDS
-      && fcode != BUILT_IN_CHKP_GET_PTR_LBOUND
-      && fcode != BUILT_IN_CHKP_GET_PTR_UBOUND
-      && fcode != BUILT_IN_CHKP_BNDRET)
+      && !ALLOCA_FUNCTION_CODE_P (fcode)
+      && fcode != BUILT_IN_FREE)
     return expand_call (exp, target, ignore);
 
   /* The built-in function expanders test for target == const0_rtx
@@ -6592,10 +7276,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
        }
     }
 
-  /* expand_builtin_with_bounds is supposed to be used for
-     instrumented builtin calls.  */
-  gcc_assert (!CALL_WITH_BOUNDS_P (exp));
-
   switch (fcode)
     {
     CASE_FLT_FN (BUILT_IN_FABS):
@@ -6621,6 +7301,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
       break;
 
     CASE_FLT_FN (BUILT_IN_FMA):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_FMA):
       target = expand_builtin_mathfn_ternary (exp, target, subtarget);
       if (target)
        return target;
@@ -6774,8 +7455,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
       else
        return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
 
-    case BUILT_IN_ALLOCA:
-    case BUILT_IN_ALLOCA_WITH_ALIGN:
+    CASE_BUILT_IN_ALLOCA:
       target = expand_builtin_alloca (exp);
       if (target)
        return target;
@@ -6847,6 +7527,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
        return target;
       break;
 
+    case BUILT_IN_STRNLEN:
+      target = expand_builtin_strnlen (exp, target, target_mode);
+      if (target)
+       return target;
+      break;
+
     case BUILT_IN_STRCAT:
       target = expand_builtin_strcat (exp, target);
       if (target)
@@ -6902,7 +7588,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
       break;
 
     case BUILT_IN_MEMPCPY:
-      target = expand_builtin_mempcpy (exp, target, mode);
+      target = expand_builtin_mempcpy (exp, target);
       if (target)
        return target;
       break;
@@ -6919,12 +7605,45 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
        return target;
       break;
 
+    /* Expand it as BUILT_IN_MEMCMP_EQ first. If not successful, change it
+       back to a BUILT_IN_STRCMP. Remember to delete the 3rd paramater
+       when changing it to a strcmp call.  */
+    case BUILT_IN_STRCMP_EQ:
+      target = expand_builtin_memcmp (exp, target, true);
+      if (target)
+       return target;
+
+      /* Change this call back to a BUILT_IN_STRCMP.  */
+      TREE_OPERAND (exp, 1)
+       = build_fold_addr_expr (builtin_decl_explicit (BUILT_IN_STRCMP));
+
+      /* Delete the last parameter.  */
+      unsigned int i;
+      vec<tree, va_gc> *arg_vec;
+      vec_alloc (arg_vec, 2);
+      for (i = 0; i < 2; i++)
+       arg_vec->quick_push (CALL_EXPR_ARG (exp, i));
+      exp = build_call_vec (TREE_TYPE (exp), CALL_EXPR_FN (exp), arg_vec);
+      /* FALLTHROUGH */
+
     case BUILT_IN_STRCMP:
       target = expand_builtin_strcmp (exp, target);
       if (target)
        return target;
       break;
 
+    /* Expand it as BUILT_IN_MEMCMP_EQ first. If not successful, change it
+       back to a BUILT_IN_STRNCMP.  */
+    case BUILT_IN_STRNCMP_EQ:
+      target = expand_builtin_memcmp (exp, target, true);
+      if (target)
+       return target;
+
+      /* Change it back to a BUILT_IN_STRNCMP.  */
+      TREE_OPERAND (exp, 1)
+       = build_fold_addr_expr (builtin_decl_explicit (BUILT_IN_STRNCMP));
+      /* FALLTHROUGH */
+
     case BUILT_IN_STRNCMP:
       target = expand_builtin_strncmp (exp, target, mode);
       if (target)
@@ -7080,6 +7799,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
       return expand_builtin_va_copy (exp);
     case BUILT_IN_EXPECT:
       return expand_builtin_expect (exp, target);
+    case BUILT_IN_EXPECT_WITH_PROBABILITY:
+      return expand_builtin_expect_with_probability (exp, target);
     case BUILT_IN_ASSUME_ALIGNED:
       return expand_builtin_assume_aligned (exp, target);
     case BUILT_IN_PREFETCH:
@@ -7587,119 +8308,34 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
       expand_builtin_set_thread_pointer (exp);
       return const0_rtx;
 
-    case BUILT_IN_CILK_DETACH:
-      expand_builtin_cilk_detach (exp);
-      return const0_rtx;
-      
-    case BUILT_IN_CILK_POP_FRAME:
-      expand_builtin_cilk_pop_frame (exp);
-      return const0_rtx;
-
-    case BUILT_IN_CHKP_INIT_PTR_BOUNDS:
-    case BUILT_IN_CHKP_NULL_PTR_BOUNDS:
-    case BUILT_IN_CHKP_COPY_PTR_BOUNDS:
-    case BUILT_IN_CHKP_CHECK_PTR_LBOUNDS:
-    case BUILT_IN_CHKP_CHECK_PTR_UBOUNDS:
-    case BUILT_IN_CHKP_CHECK_PTR_BOUNDS:
-    case BUILT_IN_CHKP_SET_PTR_BOUNDS:
-    case BUILT_IN_CHKP_NARROW_PTR_BOUNDS:
-    case BUILT_IN_CHKP_STORE_PTR_BOUNDS:
-    case BUILT_IN_CHKP_GET_PTR_LBOUND:
-    case BUILT_IN_CHKP_GET_PTR_UBOUND:
-      /* We allow user CHKP builtins if Pointer Bounds
-        Checker is off.  */
-      if (!chkp_function_instrumented_p (current_function_decl))
-       {
-         if (fcode == BUILT_IN_CHKP_SET_PTR_BOUNDS
-             || fcode == BUILT_IN_CHKP_NARROW_PTR_BOUNDS
-             || fcode == BUILT_IN_CHKP_INIT_PTR_BOUNDS
-             || fcode == BUILT_IN_CHKP_NULL_PTR_BOUNDS
-             || fcode == BUILT_IN_CHKP_COPY_PTR_BOUNDS)
-           return expand_normal (CALL_EXPR_ARG (exp, 0));
-         else if (fcode == BUILT_IN_CHKP_GET_PTR_LBOUND)
-           return expand_normal (size_zero_node);
-         else if (fcode == BUILT_IN_CHKP_GET_PTR_UBOUND)
-           return expand_normal (size_int (-1));
-         else
-           return const0_rtx;
-       }
-      /* FALLTHROUGH */
-
-    case BUILT_IN_CHKP_BNDMK:
-    case BUILT_IN_CHKP_BNDSTX:
-    case BUILT_IN_CHKP_BNDCL:
-    case BUILT_IN_CHKP_BNDCU:
-    case BUILT_IN_CHKP_BNDLDX:
-    case BUILT_IN_CHKP_BNDRET:
-    case BUILT_IN_CHKP_INTERSECT:
-    case BUILT_IN_CHKP_NARROW:
-    case BUILT_IN_CHKP_EXTRACT_LOWER:
-    case BUILT_IN_CHKP_EXTRACT_UPPER:
-      /* Software implementation of Pointer Bounds Checker is NYI.
-        Target support is required.  */
-      error ("Your target platform does not support -fcheck-pointer-bounds");
-      break;
-
     case BUILT_IN_ACC_ON_DEVICE:
       /* Do library call, if we failed to expand the builtin when
         folding.  */
       break;
 
-    default:   /* just do library call, if unknown builtin */
-      break;
-    }
-
-  /* The switch statement above can drop through to cause the function
-     to be called normally.  */
-  return expand_call (exp, target, ignore);
-}
-
-/* Similar to expand_builtin but is used for instrumented calls.  */
-
-rtx
-expand_builtin_with_bounds (tree exp, rtx target,
-                           rtx subtarget ATTRIBUTE_UNUSED,
-                           machine_mode mode, int ignore)
-{
-  tree fndecl = get_callee_fndecl (exp);
-  enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
-
-  gcc_assert (CALL_WITH_BOUNDS_P (exp));
-
-  if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
-    return targetm.expand_builtin (exp, target, subtarget, mode, ignore);
-
-  gcc_assert (fcode > BEGIN_CHKP_BUILTINS
-             && fcode < END_CHKP_BUILTINS);
-
-  switch (fcode)
-    {
-    case BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK_CHKP:
-      target = expand_builtin_memcpy_with_bounds (exp, target);
-      if (target)
-       return target;
-      break;
+    case BUILT_IN_GOACC_PARLEVEL_ID:
+    case BUILT_IN_GOACC_PARLEVEL_SIZE:
+      return expand_builtin_goacc_parlevel_id_size (exp, target, ignore);
 
-    case BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK_CHKP:
-      target = expand_builtin_mempcpy_with_bounds (exp, target, mode);
-      if (target)
-       return target;
-      break;
+    case BUILT_IN_SPECULATION_SAFE_VALUE_PTR:
+      return expand_speculation_safe_value (VOIDmode, exp, target, ignore);
 
-    case BUILT_IN_CHKP_MEMSET_NOBND_NOCHK_CHKP:
-      target = expand_builtin_memset_with_bounds (exp, target, mode);
-      if (target)
-       return target;
-      break;
+    case BUILT_IN_SPECULATION_SAFE_VALUE_1:
+    case BUILT_IN_SPECULATION_SAFE_VALUE_2:
+    case BUILT_IN_SPECULATION_SAFE_VALUE_4:
+    case BUILT_IN_SPECULATION_SAFE_VALUE_8:
+    case BUILT_IN_SPECULATION_SAFE_VALUE_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SPECULATION_SAFE_VALUE_1);
+      return expand_speculation_safe_value (mode, exp, target, ignore);
 
-    default:
+    default:   /* just do library call, if unknown builtin */
       break;
     }
 
   /* The switch statement above can drop through to cause the function
      to be called normally.  */
   return expand_call (exp, target, ignore);
- }
+}
 
 /* Determine whether a tree node represents a call to a built-in
    function.  If the tree T is a call to a built-in function with
@@ -7714,16 +8350,12 @@ builtin_mathfn_code (const_tree t)
   const_tree argtype, parmtype;
   const_call_expr_arg_iterator iter;
 
-  if (TREE_CODE (t) != CALL_EXPR
-      || TREE_CODE (CALL_EXPR_FN (t)) != ADDR_EXPR)
+  if (TREE_CODE (t) != CALL_EXPR)
     return END_BUILTINS;
 
   fndecl = get_callee_fndecl (t);
-  if (fndecl == NULL_TREE
-      || TREE_CODE (fndecl) != FUNCTION_DECL
-      || ! DECL_BUILT_IN (fndecl)
-      || DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
-    return END_BUILTINS;
+  if (fndecl == NULL_TREE || !fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
+      return END_BUILTINS;
 
   parmlist = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
   init_const_call_expr_arg_iterator (t, &iter);
@@ -7817,16 +8449,20 @@ fold_builtin_constant_p (tree arg)
   return NULL_TREE;
 }
 
-/* Create builtin_expect with PRED and EXPECTED as its arguments and
-   return it as a truthvalue.  */
+/* Create builtin_expect or builtin_expect_with_probability
+   with PRED and EXPECTED as its arguments and return it as a truthvalue.
+   Fortran FE can also produce builtin_expect with PREDICTOR as third argument.
+   builtin_expect_with_probability instead uses third argument as PROBABILITY
+   value.  */
 
 static tree
 build_builtin_expect_predicate (location_t loc, tree pred, tree expected,
-                               tree predictor)
+                               tree predictor, tree probability)
 {
   tree fn, arg_types, pred_type, expected_type, call_expr, ret_type;
 
-  fn = builtin_decl_explicit (BUILT_IN_EXPECT);
+  fn = builtin_decl_explicit (probability == NULL_TREE ? BUILT_IN_EXPECT
+                             : BUILT_IN_EXPECT_WITH_PROBABILITY);
   arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
   ret_type = TREE_TYPE (TREE_TYPE (fn));
   pred_type = TREE_VALUE (arg_types);
@@ -7834,18 +8470,23 @@ build_builtin_expect_predicate (location_t loc, tree pred, tree expected,
 
   pred = fold_convert_loc (loc, pred_type, pred);
   expected = fold_convert_loc (loc, expected_type, expected);
-  call_expr = build_call_expr_loc (loc, fn, predictor ? 3 : 2, pred, expected,
-                                  predictor);
+
+  if (probability)
+    call_expr = build_call_expr_loc (loc, fn, 3, pred, expected, probability);
+  else
+    call_expr = build_call_expr_loc (loc, fn, predictor ? 3 : 2, pred, expected,
+                                    predictor);
 
   return build2 (NE_EXPR, TREE_TYPE (pred), call_expr,
                 build_int_cst (ret_type, 0));
 }
 
-/* Fold a call to builtin_expect with arguments ARG0 and ARG1.  Return
+/* Fold a call to builtin_expect with arguments ARG0, ARG1, ARG2, ARG3.  Return
    NULL_TREE if no simplification is possible.  */
 
 tree
-fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2)
+fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2,
+                    tree arg3)
 {
   tree inner, fndecl, inner_arg0;
   enum tree_code code;
@@ -7869,8 +8510,8 @@ fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2)
 
   if (TREE_CODE (inner) == CALL_EXPR
       && (fndecl = get_callee_fndecl (inner))
-      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
-      && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT)
+      && (fndecl_built_in_p (fndecl, BUILT_IN_EXPECT)
+         || fndecl_built_in_p (fndecl, BUILT_IN_EXPECT_WITH_PROBABILITY)))
     return arg0;
 
   inner = inner_arg0;
@@ -7879,9 +8520,10 @@ fold_builtin_expect (location_t loc, tree arg0, tree arg1, tree arg2)
     {
       tree op0 = TREE_OPERAND (inner, 0);
       tree op1 = TREE_OPERAND (inner, 1);
+      arg1 = save_expr (arg1);
 
-      op0 = build_builtin_expect_predicate (loc, op0, arg1, arg2);
-      op1 = build_builtin_expect_predicate (loc, op1, arg1, arg2);
+      op0 = build_builtin_expect_predicate (loc, op0, arg1, arg2, arg3);
+      op1 = build_builtin_expect_predicate (loc, op1, arg1, arg2, arg3);
       inner = build2 (code, TREE_TYPE (inner), op0, op1);
 
       return fold_convert_loc (loc, TREE_TYPE (arg0), inner);
@@ -7932,11 +8574,24 @@ fold_builtin_strlen (location_t loc, tree type, tree arg)
     return NULL_TREE;
   else
     {
-      tree len = c_strlen (arg, 0);
+      c_strlen_data lendata = { };
+      tree len = c_strlen (arg, 0, &lendata);
 
       if (len)
        return fold_convert_loc (loc, type, len);
 
+      if (!lendata.decl)
+       c_strlen (arg, 1, &lendata);
+
+      if (lendata.decl)
+       {
+         if (EXPR_HAS_LOCATION (arg))
+           loc = EXPR_LOCATION (arg);
+         else if (loc == UNKNOWN_LOCATION)
+           loc = input_location;
+         warn_string_no_nul (loc, "strlen", arg, lendata.decl);
+       }
+
       return NULL_TREE;
     }
 }
@@ -8000,6 +8655,9 @@ fold_builtin_sincos (location_t loc,
       call = builtin_save_expr (call);
     }
 
+  tree ptype = build_pointer_type (type);
+  arg1 = fold_convert (ptype, arg1);
+  arg2 = fold_convert (ptype, arg2);
   return build2 (COMPOUND_EXPR, void_type_node,
                 build2 (MODIFY_EXPR, void_type_node,
                         build_fold_indirect_ref_loc (loc, arg1),
@@ -8136,21 +8794,6 @@ fold_builtin_abs (location_t loc, tree arg, tree type)
   return fold_build1_loc (loc, ABS_EXPR, type, arg);
 }
 
-/* Fold a call to fma, fmaf, or fmal with arguments ARG[012].  */
-
-static tree
-fold_builtin_fma (location_t loc, tree arg0, tree arg1, tree arg2, tree type)
-{
-  /* ??? Only expand to FMA_EXPR if it's directly supported.  */
-  if (validate_arg (arg0, REAL_TYPE)
-      && validate_arg (arg1, REAL_TYPE)
-      && validate_arg (arg2, REAL_TYPE)
-      && optab_handler (fma_optab, TYPE_MODE (type)) != CODE_FOR_nothing)
-    return fold_build3_loc (loc, FMA_EXPR, type, arg0, arg1, arg2);
-
-  return NULL_TREE;
-}
-
 /* Fold a call to builtin carg(a+bi) -> atan2(b,a).  */
 
 static tree
@@ -8750,7 +9393,13 @@ static inline tree
 fold_builtin_FILE (location_t loc)
 {
   if (const char *fname = LOCATION_FILE (loc))
+    {
+      /* The documentation says this builtin is equivalent to the preprocessor
+        __FILE__ macro so it appears appropriate to use the same file prefix
+        mappings.  */
+      fname = remap_macro_filename (fname);
     return build_string_literal (strlen (fname) + 1, fname);
+    }
 
   return build_string_literal (1, "");
 }
@@ -8983,7 +9632,7 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1)
       return fold_builtin_strpbrk (loc, arg0, arg1, type);
 
     case BUILT_IN_EXPECT:
-      return fold_builtin_expect (loc, arg0, arg1, NULL_TREE);
+      return fold_builtin_expect (loc, arg0, arg1, NULL_TREE, NULL_TREE);
 
     case BUILT_IN_ISGREATER:
       return fold_builtin_unordered_cmp (loc, fndecl,
@@ -9050,9 +9699,6 @@ fold_builtin_3 (location_t loc, tree fndecl,
     CASE_FLT_FN (BUILT_IN_SINCOS):
       return fold_builtin_sincos (loc, arg0, arg1, arg2);
 
-    CASE_FLT_FN (BUILT_IN_FMA):
-      return fold_builtin_fma (loc, arg0, arg1, arg2, type);
-
     CASE_FLT_FN (BUILT_IN_REMQUO):
       if (validate_arg (arg0, REAL_TYPE)
          && validate_arg (arg1, REAL_TYPE)
@@ -9061,10 +9707,13 @@ fold_builtin_3 (location_t loc, tree fndecl,
     break;
 
     case BUILT_IN_MEMCMP:
-      return fold_builtin_memcmp (loc, arg0, arg1, arg2);;
+      return fold_builtin_memcmp (loc, arg0, arg1, arg2);
 
     case BUILT_IN_EXPECT:
-      return fold_builtin_expect (loc, arg0, arg1, arg2);
+      return fold_builtin_expect (loc, arg0, arg1, arg2, NULL_TREE);
+
+    case BUILT_IN_EXPECT_WITH_PROBABILITY:
+      return fold_builtin_expect (loc, arg0, arg1, NULL_TREE, arg2);
 
     case BUILT_IN_ADD_OVERFLOW:
     case BUILT_IN_SUB_OVERFLOW:
@@ -9130,7 +9779,6 @@ fold_builtin_n (location_t loc, tree fndecl, tree *args, int nargs, bool)
     {
       ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
       SET_EXPR_LOCATION (ret, loc);
-      TREE_NO_WARNING (ret) = 1;
       return ret;
     }
   return NULL_TREE;
@@ -9189,9 +9837,7 @@ fold_call_expr (location_t loc, tree exp, bool ignore)
 {
   tree ret = NULL_TREE;
   tree fndecl = get_callee_fndecl (exp);
-  if (fndecl
-      && TREE_CODE (fndecl) == FUNCTION_DECL
-      && DECL_BUILT_IN (fndecl)
+  if (fndecl && fndecl_built_in_p (fndecl)
       /* If CALL_EXPR_VA_ARG_PACK is set, the arguments aren't finalized
         yet.  Defer folding until we see all the arguments
         (after inlining).  */
@@ -9205,10 +9851,7 @@ fold_call_expr (location_t loc, tree exp, bool ignore)
       if (nargs && TREE_CODE (CALL_EXPR_ARG (exp, nargs - 1)) == CALL_EXPR)
        {
          tree fndecl2 = get_callee_fndecl (CALL_EXPR_ARG (exp, nargs - 1));
-         if (fndecl2
-             && TREE_CODE (fndecl2) == FUNCTION_DECL
-             && DECL_BUILT_IN_CLASS (fndecl2) == BUILT_IN_NORMAL
-             && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK)
+         if (fndecl2 && fndecl_built_in_p (fndecl2, BUILT_IN_VA_ARG_PACK))
            return NULL_TREE;
        }
 
@@ -9244,17 +9887,14 @@ fold_builtin_call_array (location_t loc, tree,
 
   tree fndecl = TREE_OPERAND (fn, 0);
   if (TREE_CODE (fndecl) == FUNCTION_DECL
-      && DECL_BUILT_IN (fndecl))
+      && fndecl_built_in_p (fndecl))
     {
       /* If last argument is __builtin_va_arg_pack (), arguments to this
         function are not finalized yet.  Defer folding until they are.  */
       if (n && TREE_CODE (argarray[n - 1]) == CALL_EXPR)
        {
          tree fndecl2 = get_callee_fndecl (argarray[n - 1]);
-         if (fndecl2
-             && TREE_CODE (fndecl2) == FUNCTION_DECL
-             && DECL_BUILT_IN_CLASS (fndecl2) == BUILT_IN_NORMAL
-             && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK)
+         if (fndecl2 && fndecl_built_in_p (fndecl2, BUILT_IN_VA_ARG_PACK))
            return NULL_TREE;
        }
       if (avoid_folding_inline_builtin (fndecl))
@@ -9445,7 +10085,7 @@ fold_builtin_strpbrk (location_t loc, tree s1, tree s2, tree type)
       if (p2[0] == '\0')
        /* strpbrk(x, "") == NULL.
           Evaluate and ignore s1 in case it had side-effects.  */
-       return omit_one_operand_loc (loc, TREE_TYPE (s1), integer_zero_node, s1);
+       return omit_one_operand_loc (loc, type, integer_zero_node, s1);
 
       if (p2[1] != '\0')
        return NULL_TREE;  /* Really call strpbrk.  */
@@ -9566,7 +10206,7 @@ fold_builtin_next_arg (tree exp, bool va_start_p)
      definition of the va_start macro (perhaps on the token for
      builtin) in a system header, so warnings will not be emitted.
      Use the location in real source code.  */
-  source_location current_location =
+  location_t current_location =
     linemap_unwind_to_first_non_reserved_loc (line_table, input_location,
                                              NULL);
 
@@ -9708,8 +10348,6 @@ static rtx
 expand_builtin_memory_chk (tree exp, rtx target, machine_mode mode,
                           enum built_in_function fcode)
 {
-  tree dest, src, len, size;
-
   if (!validate_arglist (exp,
                         POINTER_TYPE,
                         fcode == BUILT_IN_MEMSET_CHK
@@ -9717,14 +10355,13 @@ expand_builtin_memory_chk (tree exp, rtx target, machine_mode mode,
                         INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return NULL_RTX;
 
-  dest = CALL_EXPR_ARG (exp, 0);
-  src = CALL_EXPR_ARG (exp, 1);
-  len = CALL_EXPR_ARG (exp, 2);
-  size = CALL_EXPR_ARG (exp, 3);
+  tree dest = CALL_EXPR_ARG (exp, 0);
+  tree src = CALL_EXPR_ARG (exp, 1);
+  tree len = CALL_EXPR_ARG (exp, 2);
+  tree size = CALL_EXPR_ARG (exp, 3);
 
-  bool sizes_ok = check_sizes (OPT_Wstringop_overflow_,
-                              exp, len, /*maxlen=*/NULL_TREE,
-                              /*str=*/NULL_TREE, size);
+  bool sizes_ok = check_access (exp, dest, src, len, /*maxread=*/NULL_TREE,
+                               /*str=*/NULL_TREE, size);
 
   if (!tree_fits_uhwi_p (size))
     return NULL_RTX;
@@ -9833,7 +10470,9 @@ maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
   /* The maximum length of the source sequence in a bounded operation
      (such as __strncat_chk) or null if the operation isn't bounded
      (such as __strcat_chk).  */
-  tree maxlen = NULL_TREE;
+  tree maxread = NULL_TREE;
+  /* The exact size of the access (such as in __strncpy_chk).  */
+  tree size = NULL_TREE;
 
   switch (fcode)
     {
@@ -9854,27 +10493,27 @@ maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
     case BUILT_IN_STRNCAT_CHK:
       catstr = CALL_EXPR_ARG (exp, 0);
       srcstr = CALL_EXPR_ARG (exp, 1);
-      maxlen = CALL_EXPR_ARG (exp, 2);
+      maxread = CALL_EXPR_ARG (exp, 2);
       objsize = CALL_EXPR_ARG (exp, 3);
       break;
 
     case BUILT_IN_STRNCPY_CHK:
     case BUILT_IN_STPNCPY_CHK:
       srcstr = CALL_EXPR_ARG (exp, 1);
-      maxlen = CALL_EXPR_ARG (exp, 2);
+      size = CALL_EXPR_ARG (exp, 2);
       objsize = CALL_EXPR_ARG (exp, 3);
       break;
 
     case BUILT_IN_SNPRINTF_CHK:
     case BUILT_IN_VSNPRINTF_CHK:
-      maxlen = CALL_EXPR_ARG (exp, 1);
+      maxread = CALL_EXPR_ARG (exp, 1);
       objsize = CALL_EXPR_ARG (exp, 3);
       break;
     default:
       gcc_unreachable ();
     }
 
-  if (catstr && maxlen)
+  if (catstr && maxread)
     {
       /* Check __strncat_chk.  There is no way to determine the length
         of the string to which the source string is being appended so
@@ -9883,8 +10522,10 @@ maybe_emit_chk_warning (tree exp, enum built_in_function fcode)
       return;
     }
 
-  check_sizes (OPT_Wstringop_overflow_, exp,
-              /*size=*/NULL_TREE, maxlen, srcstr, objsize);
+  /* The destination argument is the first one for all built-ins above.  */
+  tree dst = CALL_EXPR_ARG (exp, 0);
+
+  check_access (exp, dst, srcstr, size, maxread, srcstr, objsize);
 }
 
 /* Emit warning if a buffer overflow is detected at compile time
@@ -9940,8 +10581,9 @@ maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode)
 
   /* Add one for the terminating nul.  */
   len = fold_build2 (PLUS_EXPR, TREE_TYPE (len), len, size_one_node);
-  check_sizes (OPT_Wstringop_overflow_,
-              exp, /*size=*/NULL_TREE, /*maxlen=*/NULL_TREE, len, size);
+
+  check_access (exp, /*dst=*/NULL_TREE, /*src=*/NULL_TREE, /*size=*/NULL_TREE,
+               /*maxread=*/NULL_TREE, len, size);
 }
 
 /* Emit warning if a free is called with address of a variable.  */
@@ -10371,9 +11013,7 @@ fold_call_stmt (gcall *stmt, bool ignore)
   tree ret = NULL_TREE;
   tree fndecl = gimple_call_fndecl (stmt);
   location_t loc = gimple_location (stmt);
-  if (fndecl
-      && TREE_CODE (fndecl) == FUNCTION_DECL
-      && DECL_BUILT_IN (fndecl)
+  if (fndecl && fndecl_built_in_p (fndecl)
       && !gimple_call_va_arg_pack_p (stmt))
     {
       int nargs = gimple_call_num_args (stmt);
@@ -10420,8 +11060,7 @@ fold_call_stmt (gcall *stmt, bool ignore)
 void
 set_builtin_user_assembler_name (tree decl, const char *asmspec)
 {
-  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
-             && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
+  gcc_assert (fndecl_built_in_p (decl, BUILT_IN_NORMAL)
              && asmspec != 0);
 
   tree builtin = builtin_decl_explicit (DECL_FUNCTION_CODE (decl));
@@ -10430,9 +11069,9 @@ set_builtin_user_assembler_name (tree decl, const char *asmspec)
   if (DECL_FUNCTION_CODE (decl) == BUILT_IN_FFS
       && INT_TYPE_SIZE < BITS_PER_WORD)
     {
+      scalar_int_mode mode = int_mode_for_size (INT_TYPE_SIZE, 0).require ();
       set_user_assembler_libfunc ("ffs", asmspec);
-      set_optab_libfunc (ffs_optab, mode_for_size (INT_TYPE_SIZE, MODE_INT, 0),
-                        "ffs");
+      set_optab_libfunc (ffs_optab, mode, "ffs");
     }
 }
 
@@ -10441,7 +11080,7 @@ set_builtin_user_assembler_name (tree decl, const char *asmspec)
 bool
 is_simple_builtin (tree decl)
 {
-  if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
+  if (decl && fndecl_built_in_p (decl, BUILT_IN_NORMAL))
     switch (DECL_FUNCTION_CODE (decl))
       {
        /* Builtins that expand to constants.  */
@@ -10487,8 +11126,7 @@ is_inexpensive_builtin (tree decl)
     switch (DECL_FUNCTION_CODE (decl))
       {
       case BUILT_IN_ABS:
-      case BUILT_IN_ALLOCA:
-      case BUILT_IN_ALLOCA_WITH_ALIGN:
+      CASE_BUILT_IN_ALLOCA:
       case BUILT_IN_BSWAP16:
       case BUILT_IN_BSWAP32:
       case BUILT_IN_BSWAP64:
@@ -10572,3 +11210,12 @@ target_char_cst_p (tree t, char *p)
   *p = (char)tree_to_uhwi (t);
   return true;
 }
+
+/* Return the maximum object size.  */
+
+tree
+max_object_size (void)
+{
+  /* To do: Make this a configurable parameter.  */
+  return TYPE_MAX_VALUE (ptrdiff_type_node);
+}