re PR debug/66691 (ICE on valid code at -O3 with -g enabled in simplify_subreg, at...
[gcc.git] / gcc / gimple-fold.c
index dc2c9428893303823c58afb1f3f3dd9cfeae3068..ee9abe710cced8bd9252b1f81607da81b817edaf 100644 (file)
@@ -1,5 +1,5 @@
 /* Statement simplification on GIMPLE.
-   Copyright (C) 2010-2014 Free Software Foundation, Inc.
+   Copyright (C) 2010-2015 Free Software Foundation, Inc.
    Split out from tree-ssa-ccp.c.
 
 This file is part of GCC.
@@ -22,21 +22,34 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
+#include "alias.h"
+#include "symtab.h"
 #include "tree.h"
+#include "fold-const.h"
 #include "stringpool.h"
-#include "expr.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "rtl.h"
+#include "flags.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
 #include "stmt.h"
+#include "expr.h"
 #include "stor-layout.h"
-#include "flags.h"
-#include "function.h"
 #include "dumpfile.h"
 #include "bitmap.h"
+#include "predict.h"
+#include "dominance.h"
 #include "basic-block.h"
 #include "tree-ssa-alias.h"
 #include "internal-fn.h"
 #include "gimple-fold.h"
 #include "gimple-expr.h"
-#include "is-a.h"
 #include "gimple.h"
 #include "gimplify.h"
 #include "gimple-iterator.h"
@@ -47,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "tree-ssa-propagate.h"
 #include "target.h"
+#include "cgraph.h"
 #include "ipa-utils.h"
 #include "gimple-pretty-print.h"
 #include "tree-ssa-address.h"
@@ -55,6 +69,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "builtins.h"
 #include "output.h"
+#include "tree-eh.h"
+#include "gimple-match.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
 
 /* Return true when DECL can be referenced from current unit.
    FROM_DECL (if non-null) specify constructor of variable DECL was taken from.
@@ -85,7 +103,7 @@ can_refer_decl_in_current_unit_p (tree decl, tree from_decl)
   struct cgraph_node *node;
   symtab_node *snode;
 
-  if (DECL_ABSTRACT (decl))
+  if (DECL_ABSTRACT_P (decl))
     return false;
 
   /* We are concerned only about static/external vars and functions.  */
@@ -238,8 +256,7 @@ get_symbol_constant_value (tree sym)
         have zero as the initializer if they may not be
         overridden at link or run time.  */
       if (!val
-          && (INTEGRAL_TYPE_P (TREE_TYPE (sym))
-              || SCALAR_FLOAT_TYPE_P (TREE_TYPE (sym))))
+          && is_gimple_reg_type (TREE_TYPE (sym)))
        return build_zero_cst (TREE_TYPE (sym));
     }
 
@@ -304,6 +321,9 @@ fold_gimple_assign (gimple_stmt_iterator *si)
       {
         tree rhs = gimple_assign_rhs1 (stmt);
 
+       if (TREE_CLOBBER_P (rhs))
+         return NULL_TREE;
+
        if (REFERENCE_CLASS_P (rhs))
          return maybe_fold_reference (rhs, false);
 
@@ -401,27 +421,6 @@ fold_gimple_assign (gimple_stmt_iterator *si)
       break;
 
     case GIMPLE_UNARY_RHS:
-      {
-       tree rhs = gimple_assign_rhs1 (stmt);
-
-       result = fold_unary_loc (loc, subcode, gimple_expr_type (stmt), rhs);
-       if (result)
-         {
-           /* If the operation was a conversion do _not_ mark a
-              resulting constant with TREE_OVERFLOW if the original
-              constant was not.  These conversions have implementation
-              defined behavior and retaining the TREE_OVERFLOW flag
-              here would confuse later passes such as VRP.  */
-           if (CONVERT_EXPR_CODE_P (subcode)
-               && TREE_CODE (result) == INTEGER_CST
-               && TREE_CODE (rhs) == INTEGER_CST)
-             TREE_OVERFLOW (result) = TREE_OVERFLOW (rhs);
-
-           STRIP_USELESS_TYPE_CONVERSION (result);
-           if (valid_gimple_rhs_p (result))
-             return result;
-         }
-      }
       break;
 
     case GIMPLE_BINARY_RHS:
@@ -547,7 +546,7 @@ fold_gimple_assign (gimple_stmt_iterator *si)
    assumed that the operands have been previously folded.  */
 
 static bool
-fold_gimple_cond (gimple stmt)
+fold_gimple_cond (gcond *stmt)
 {
   tree result = fold_binary_loc (gimple_location (stmt),
                             gimple_cond_code (stmt),
@@ -755,7 +754,7 @@ var_decl_component_p (tree var)
 }
 
 /* Fold function call to builtin mem{{,p}cpy,move}.  Return
-   NULL_TREE if no simplification can be made.
+   false if no simplification can be made.
    If ENDP is 0, return DEST (like memcpy).
    If ENDP is 1, return DEST+LEN (like mempcpy).
    If ENDP is 2, return DEST+LEN-1 (like stpcpy).
@@ -863,8 +862,7 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
                            srcmem = make_ssa_name (TREE_TYPE (srcmem),
                                                    new_stmt);
                          else
-                           srcmem = create_tmp_reg (TREE_TYPE (srcmem),
-                                                    NULL);
+                           srcmem = create_tmp_reg (TREE_TYPE (srcmem));
                          gimple_assign_set_lhs (new_stmt, srcmem);
                          gimple_set_vuse (new_stmt, gimple_vuse (stmt));
                          gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
@@ -1149,7 +1147,7 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
          if (gimple_in_ssa_p (cfun))
            srcvar = make_ssa_name (TREE_TYPE (srcvar), new_stmt);
          else
-           srcvar = create_tmp_reg (TREE_TYPE (srcvar), NULL);
+           srcvar = create_tmp_reg (TREE_TYPE (srcvar));
          gimple_assign_set_lhs (new_stmt, srcvar);
          gimple_set_vuse (new_stmt, gimple_vuse (stmt));
          gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
@@ -1557,9 +1555,9 @@ gimple_fold_builtin_strcat (gimple_stmt_iterator *gsi, tree dst, tree src)
   gimple repl = gimple_build_call (strlen_fn, 1, dst);
   gimple_set_location (repl, loc);
   if (gimple_in_ssa_p (cfun))
-    newdst = make_ssa_name (size_type_node, NULL);
+    newdst = make_ssa_name (size_type_node);
   else
-    newdst = create_tmp_reg (size_type_node, NULL);
+    newdst = create_tmp_reg (size_type_node);
   gimple_call_set_lhs (repl, newdst);
   gimple_seq_add_stmt_without_update (&stmts, repl);
 
@@ -1632,6 +1630,102 @@ gimple_fold_builtin_strcat_chk (gimple_stmt_iterator *gsi)
   return true;
 }
 
+/* Simplify a call to the strncat builtin.  */
+
+static bool
+gimple_fold_builtin_strncat (gimple_stmt_iterator *gsi)
+{
+  gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
+  tree dst = gimple_call_arg (stmt, 0);
+  tree src = gimple_call_arg (stmt, 1);
+  tree len = gimple_call_arg (stmt, 2);
+
+  const char *p = c_getstr (src);
+
+  /* If the requested length is zero, or the src parameter string
+     length is zero, return the dst parameter.  */
+  if (integer_zerop (len) || (p && *p == '\0'))
+    {
+      replace_call_with_value (gsi, dst);
+      return true;
+    }
+
+  /* If the requested len is greater than or equal to the string
+     length, call strcat.  */
+  if (TREE_CODE (len) == INTEGER_CST && p
+      && compare_tree_int (len, strlen (p)) >= 0)
+    {
+      tree fn = builtin_decl_implicit (BUILT_IN_STRCAT);
+
+      /* If the replacement _DECL isn't initialized, don't do the
+        transformation.  */
+      if (!fn)
+       return false;
+
+      gcall *repl = gimple_build_call (fn, 2, dst, src);
+      replace_call_with_call_and_fold (gsi, repl);
+      return true;
+    }
+
+  return false;
+}
+
+/* Fold a call to the __strncat_chk builtin with arguments DEST, SRC,
+   LEN, and SIZE.  */
+
+static bool 
+gimple_fold_builtin_strncat_chk (gimple_stmt_iterator *gsi)
+{
+  gimple stmt = gsi_stmt (*gsi);
+  tree dest = gimple_call_arg (stmt, 0);
+  tree src = gimple_call_arg (stmt, 1);
+  tree len = gimple_call_arg (stmt, 2);
+  tree size = gimple_call_arg (stmt, 3);
+  tree fn;
+  const char *p;
+
+  p = c_getstr (src);
+  /* If the SRC parameter is "" or if LEN is 0, return DEST.  */
+  if ((p && *p == '\0')
+      || integer_zerop (len))
+    {
+      replace_call_with_value (gsi, dest);
+      return true;
+    }
+
+  if (! tree_fits_uhwi_p (size))
+    return false;
+
+  if (! integer_all_onesp (size))
+    {
+      tree src_len = c_strlen (src, 1);
+      if (src_len
+         && tree_fits_uhwi_p (src_len)
+         && tree_fits_uhwi_p (len)
+         && ! tree_int_cst_lt (len, src_len))
+       {
+         /* If LEN >= strlen (SRC), optimize into __strcat_chk.  */
+         fn = builtin_decl_explicit (BUILT_IN_STRCAT_CHK);
+         if (!fn)
+           return false;
+
+         gimple repl = gimple_build_call (fn, 3, dest, src, size);
+         replace_call_with_call_and_fold (gsi, repl);
+         return true;
+       }
+      return false;
+    }
+
+  /* If __builtin_strncat_chk is used, assume strncat is available.  */
+  fn = builtin_decl_explicit (BUILT_IN_STRNCAT);
+  if (!fn)
+    return false;
+
+  gimple repl = gimple_build_call (fn, 3, dest, src, len);
+  replace_call_with_call_and_fold (gsi, repl);
+  return true;
+}
+
 /* Fold a call to the fputs builtin.  ARG0 and ARG1 are the arguments
    to the call.  IGNORE is true if the value returned
    by the builtin will be ignored.  UNLOCKED is true is true if this
@@ -1960,6 +2054,70 @@ gimple_fold_builtin_stxncpy_chk (gimple_stmt_iterator *gsi,
   return true;
 }
 
+/* Fold function call to builtin stpcpy with arguments DEST and SRC.
+   Return NULL_TREE if no simplification can be made.  */
+
+static bool
+gimple_fold_builtin_stpcpy (gimple_stmt_iterator *gsi)
+{
+  gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
+  location_t loc = gimple_location (stmt);
+  tree dest = gimple_call_arg (stmt, 0);
+  tree src = gimple_call_arg (stmt, 1);
+  tree fn, len, lenp1;
+
+  /* If the result is unused, replace stpcpy with strcpy.  */
+  if (gimple_call_lhs (stmt) == NULL_TREE)
+    {
+      tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+      if (!fn)
+       return false;
+      gimple_call_set_fndecl (stmt, fn);
+      fold_stmt (gsi);
+      return true;
+    }
+
+  len = c_strlen (src, 1);
+  if (!len
+      || TREE_CODE (len) != INTEGER_CST)
+    return false;
+
+  if (optimize_function_for_size_p (cfun)
+      /* If length is zero it's small enough.  */
+      && !integer_zerop (len))
+    return false;
+
+  /* If the source has a known length replace stpcpy with memcpy.  */
+  fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
+  if (!fn)
+    return false;
+
+  gimple_seq stmts = NULL;
+  tree tem = gimple_convert (&stmts, loc, size_type_node, len);
+  lenp1 = gimple_build (&stmts, loc, PLUS_EXPR, size_type_node,
+                       tem, build_int_cst (size_type_node, 1));
+  gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+  gcall *repl = gimple_build_call (fn, 3, dest, src, lenp1);
+  gimple_set_vuse (repl, gimple_vuse (stmt));
+  gimple_set_vdef (repl, gimple_vdef (stmt));
+  if (gimple_vdef (repl)
+      && TREE_CODE (gimple_vdef (repl)) == SSA_NAME)
+    SSA_NAME_DEF_STMT (gimple_vdef (repl)) = repl;
+  gsi_insert_before (gsi, repl, GSI_SAME_STMT);
+  /* Replace the result with dest + len.  */
+  stmts = NULL;
+  tem = gimple_convert (&stmts, loc, sizetype, len);
+  gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+  gassign *ret = gimple_build_assign (gimple_call_lhs (stmt),
+                                     POINTER_PLUS_EXPR, dest, tem);
+  gsi_replace (gsi, ret, true);
+  /* Finally fold the memcpy call.  */
+  gimple_stmt_iterator gsi2 = *gsi;
+  gsi_prev (&gsi2);
+  fold_stmt (&gsi2);
+  return true;
+}
+
 /* Fold a call EXP to {,v}snprintf having NARGS passed as ARGS.  Return
    NULL_TREE if a normal call should be emitted rather than expanding
    the function inline.  FCODE is either BUILT_IN_SNPRINTF_CHK or
@@ -1970,7 +2128,7 @@ static bool
 gimple_fold_builtin_snprintf_chk (gimple_stmt_iterator *gsi,
                                  enum built_in_function fcode)
 {
-  gimple stmt = gsi_stmt (*gsi);
+  gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
   tree dest, size, len, fn, fmt, flag;
   const char *fmt_str;
 
@@ -2050,7 +2208,7 @@ static bool
 gimple_fold_builtin_sprintf_chk (gimple_stmt_iterator *gsi,
                                 enum built_in_function fcode)
 {
-  gimple stmt = gsi_stmt (*gsi);
+  gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
   tree dest, size, len, fn, fmt, flag;
   const char *fmt_str;
   unsigned nargs = gimple_call_num_args (stmt);
@@ -2273,7 +2431,7 @@ gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi)
 static bool
 gimple_fold_builtin_snprintf (gimple_stmt_iterator *gsi)
 {
-  gimple stmt = gsi_stmt (*gsi);
+  gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
   tree dest = gimple_call_arg (stmt, 0);
   tree destsize = gimple_call_arg (stmt, 1);
   tree fmt = gimple_call_arg (stmt, 2);
@@ -2357,7 +2515,7 @@ gimple_fold_builtin_snprintf (gimple_stmt_iterator *gsi)
        return false;
 
       tree orig_len = get_maxval_strlen (orig, 0);
-      if (!orig_len)
+      if (!orig_len || TREE_CODE (orig_len) != INTEGER_CST)
        return false;
 
       /* We could expand this as
@@ -2401,6 +2559,270 @@ gimple_fold_builtin_snprintf (gimple_stmt_iterator *gsi)
   return false;
 }
 
+/* Fold a call to the {,v}fprintf{,_unlocked} and __{,v}printf_chk builtins.
+   FP, FMT, and ARG are the arguments to the call.  We don't fold calls with
+   more than 3 arguments, and ARG may be null in the 2-argument case.
+
+   Return NULL_TREE if no simplification was possible, otherwise return the
+   simplified form of the call as a tree.  FCODE is the BUILT_IN_*
+   code of the function to be simplified.  */
+
+static bool 
+gimple_fold_builtin_fprintf (gimple_stmt_iterator *gsi,
+                            tree fp, tree fmt, tree arg,
+                            enum built_in_function fcode)
+{
+  gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
+  tree fn_fputc, fn_fputs;
+  const char *fmt_str = NULL;
+
+  /* If the return value is used, don't do the transformation.  */
+  if (gimple_call_lhs (stmt) != NULL_TREE)
+    return false;
+
+  /* Check whether the format is a literal string constant.  */
+  fmt_str = c_getstr (fmt);
+  if (fmt_str == NULL)
+    return false;
+
+  if (fcode == BUILT_IN_FPRINTF_UNLOCKED)
+    {
+      /* If we're using an unlocked function, assume the other
+        unlocked functions exist explicitly.  */
+      fn_fputc = builtin_decl_explicit (BUILT_IN_FPUTC_UNLOCKED);
+      fn_fputs = builtin_decl_explicit (BUILT_IN_FPUTS_UNLOCKED);
+    }
+  else
+    {
+      fn_fputc = builtin_decl_implicit (BUILT_IN_FPUTC);
+      fn_fputs = builtin_decl_implicit (BUILT_IN_FPUTS);
+    }
+
+  if (!init_target_chars ())
+    return false;
+
+  /* If the format doesn't contain % args or %%, use strcpy.  */
+  if (strchr (fmt_str, target_percent) == NULL)
+    {
+      if (fcode != BUILT_IN_VFPRINTF && fcode != BUILT_IN_VFPRINTF_CHK
+         && arg)
+       return false;
+
+      /* If the format specifier was "", fprintf does nothing.  */
+      if (fmt_str[0] == '\0')
+       {
+         replace_call_with_value (gsi, NULL_TREE);
+         return true;
+       }
+
+      /* When "string" doesn't contain %, replace all cases of
+        fprintf (fp, string) with fputs (string, fp).  The fputs
+        builtin will take care of special cases like length == 1.  */
+      if (fn_fputs)
+       {
+         gcall *repl = gimple_build_call (fn_fputs, 2, fmt, fp);
+         replace_call_with_call_and_fold (gsi, repl);
+         return true;
+       }
+    }
+
+  /* The other optimizations can be done only on the non-va_list variants.  */
+  else if (fcode == BUILT_IN_VFPRINTF || fcode == BUILT_IN_VFPRINTF_CHK)
+    return false;
+
+  /* If the format specifier was "%s", call __builtin_fputs (arg, fp).  */
+  else if (strcmp (fmt_str, target_percent_s) == 0)
+    {
+      if (!arg || ! POINTER_TYPE_P (TREE_TYPE (arg)))
+       return false;
+      if (fn_fputs)
+       {
+         gcall *repl = gimple_build_call (fn_fputs, 2, arg, fp);
+         replace_call_with_call_and_fold (gsi, repl);
+         return true;
+       }
+    }
+
+  /* If the format specifier was "%c", call __builtin_fputc (arg, fp).  */
+  else if (strcmp (fmt_str, target_percent_c) == 0)
+    {
+      if (!arg
+         || ! useless_type_conversion_p (integer_type_node, TREE_TYPE (arg)))
+       return false;
+      if (fn_fputc)
+       {
+         gcall *repl = gimple_build_call (fn_fputc, 2, arg, fp);
+         replace_call_with_call_and_fold (gsi, repl);
+         return true;
+       }
+    }
+
+  return false;
+}
+
+/* Fold a call to the {,v}printf{,_unlocked} and __{,v}printf_chk builtins.
+   FMT and ARG are the arguments to the call; we don't fold cases with
+   more than 2 arguments, and ARG may be null if this is a 1-argument case.
+
+   Return NULL_TREE if no simplification was possible, otherwise return the
+   simplified form of the call as a tree.  FCODE is the BUILT_IN_*
+   code of the function to be simplified.  */
+
+static bool
+gimple_fold_builtin_printf (gimple_stmt_iterator *gsi, tree fmt,
+                           tree arg, enum built_in_function fcode)
+{
+  gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
+  tree fn_putchar, fn_puts, newarg;
+  const char *fmt_str = NULL;
+
+  /* If the return value is used, don't do the transformation.  */
+  if (gimple_call_lhs (stmt) != NULL_TREE)
+    return false;
+
+  /* Check whether the format is a literal string constant.  */
+  fmt_str = c_getstr (fmt);
+  if (fmt_str == NULL)
+    return false;
+
+  if (fcode == BUILT_IN_PRINTF_UNLOCKED)
+    {
+      /* If we're using an unlocked function, assume the other
+        unlocked functions exist explicitly.  */
+      fn_putchar = builtin_decl_explicit (BUILT_IN_PUTCHAR_UNLOCKED);
+      fn_puts = builtin_decl_explicit (BUILT_IN_PUTS_UNLOCKED);
+    }
+  else
+    {
+      fn_putchar = builtin_decl_implicit (BUILT_IN_PUTCHAR);
+      fn_puts = builtin_decl_implicit (BUILT_IN_PUTS);
+    }
+
+  if (!init_target_chars ())
+    return false;
+
+  if (strcmp (fmt_str, target_percent_s) == 0
+      || strchr (fmt_str, target_percent) == NULL)
+    {
+      const char *str;
+
+      if (strcmp (fmt_str, target_percent_s) == 0)
+       {
+         if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK)
+           return false;
+
+         if (!arg || ! POINTER_TYPE_P (TREE_TYPE (arg)))
+           return false;
+
+         str = c_getstr (arg);
+         if (str == NULL)
+           return false;
+       }
+      else
+       {
+         /* The format specifier doesn't contain any '%' characters.  */
+         if (fcode != BUILT_IN_VPRINTF && fcode != BUILT_IN_VPRINTF_CHK
+             && arg)
+           return false;
+         str = fmt_str;
+       }
+
+      /* If the string was "", printf does nothing.  */
+      if (str[0] == '\0')
+       {
+         replace_call_with_value (gsi, NULL_TREE);
+         return true;
+       }
+
+      /* If the string has length of 1, call putchar.  */
+      if (str[1] == '\0')
+       {
+         /* Given printf("c"), (where c is any one character,)
+            convert "c"[0] to an int and pass that to the replacement
+            function.  */
+         newarg = build_int_cst (integer_type_node, str[0]);
+         if (fn_putchar)
+           {
+             gcall *repl = gimple_build_call (fn_putchar, 1, newarg);
+             replace_call_with_call_and_fold (gsi, repl);
+             return true;
+           }
+       }
+      else
+       {
+         /* If the string was "string\n", call puts("string").  */
+         size_t len = strlen (str);
+         if ((unsigned char)str[len - 1] == target_newline
+             && (size_t) (int) len == len
+             && (int) len > 0)
+           {
+             char *newstr;
+             tree offset_node, string_cst;
+
+             /* Create a NUL-terminated string that's one char shorter
+                than the original, stripping off the trailing '\n'.  */
+             newarg = build_string_literal (len, str);
+             string_cst = string_constant (newarg, &offset_node);
+             gcc_checking_assert (string_cst
+                                  && (TREE_STRING_LENGTH (string_cst)
+                                      == (int) len)
+                                  && integer_zerop (offset_node)
+                                  && (unsigned char)
+                                     TREE_STRING_POINTER (string_cst)[len - 1]
+                                     == target_newline);
+             /* build_string_literal creates a new STRING_CST,
+                modify it in place to avoid double copying.  */
+             newstr = CONST_CAST (char *, TREE_STRING_POINTER (string_cst));
+             newstr[len - 1] = '\0';
+             if (fn_puts)
+               {
+                 gcall *repl = gimple_build_call (fn_puts, 1, newarg);
+                 replace_call_with_call_and_fold (gsi, repl);
+                 return true;
+               }
+           }
+         else
+           /* We'd like to arrange to call fputs(string,stdout) here,
+              but we need stdout and don't have a way to get it yet.  */
+           return false;
+       }
+    }
+
+  /* The other optimizations can be done only on the non-va_list variants.  */
+  else if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK)
+    return false;
+
+  /* If the format specifier was "%s\n", call __builtin_puts(arg).  */
+  else if (strcmp (fmt_str, target_percent_s_newline) == 0)
+    {
+      if (!arg || ! POINTER_TYPE_P (TREE_TYPE (arg)))
+       return false;
+      if (fn_puts)
+       {
+         gcall *repl = gimple_build_call (fn_puts, 1, arg);
+         replace_call_with_call_and_fold (gsi, repl);
+         return true;
+       }
+    }
+
+  /* If the format specifier was "%c", call __builtin_putchar(arg).  */
+  else if (strcmp (fmt_str, target_percent_c) == 0)
+    {
+      if (!arg || ! useless_type_conversion_p (integer_type_node,
+                                              TREE_TYPE (arg)))
+       return false;
+      if (fn_putchar)
+       {
+         gcall *repl = gimple_build_call (fn_putchar, 1, arg);
+         replace_call_with_call_and_fold (gsi, repl);
+         return true;
+       }
+    }
+
+  return false;
+}
+
+
 
 /* Fold a call to __builtin_strlen with known length LEN.  */
 
@@ -2423,7 +2845,7 @@ gimple_fold_builtin_strlen (gimple_stmt_iterator *gsi)
 static bool
 gimple_fold_builtin (gimple_stmt_iterator *gsi)
 {
-  gimple stmt = gsi_stmt (*gsi);
+  gcall *stmt = as_a <gcall *>(gsi_stmt (*gsi));
   tree callee = gimple_call_fndecl (stmt);
 
   /* Give up for always_inline inline builtins until they are
@@ -2431,7 +2853,9 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
   if (avoid_folding_inline_builtin (callee))
     return false;
 
-  switch (DECL_FUNCTION_CODE (callee))
+  unsigned n = gimple_call_num_args (stmt);
+  enum built_in_function fcode = DECL_FUNCTION_CODE (callee);
+  switch (fcode)
     {
     case BUILT_IN_BZERO:
       return gimple_fold_builtin_memset (gsi, integer_zero_node,
@@ -2454,9 +2878,11 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
                                            gimple_call_arg (stmt, 1), 3);
     case BUILT_IN_SPRINTF_CHK:
     case BUILT_IN_VSPRINTF_CHK:
-      return gimple_fold_builtin_sprintf_chk (gsi, DECL_FUNCTION_CODE (callee));
+      return gimple_fold_builtin_sprintf_chk (gsi, fcode);
     case BUILT_IN_STRCAT_CHK:
       return gimple_fold_builtin_strcat_chk (gsi);
+    case BUILT_IN_STRNCAT_CHK:
+      return gimple_fold_builtin_strncat_chk (gsi);
     case BUILT_IN_STRLEN:
       return gimple_fold_builtin_strlen (gsi);
     case BUILT_IN_STRCPY:
@@ -2471,6 +2897,8 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
     case BUILT_IN_STRCAT:
       return gimple_fold_builtin_strcat (gsi, gimple_call_arg (stmt, 0),
                                         gimple_call_arg (stmt, 1));
+    case BUILT_IN_STRNCAT:
+      return gimple_fold_builtin_strncat (gsi);
     case BUILT_IN_FPUTS:
       return gimple_fold_builtin_fputs (gsi, gimple_call_arg (stmt, 0),
                                        gimple_call_arg (stmt, 1), false);
@@ -2486,14 +2914,16 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
                                             gimple_call_arg (stmt, 1),
                                             gimple_call_arg (stmt, 2),
                                             gimple_call_arg (stmt, 3),
-                                            DECL_FUNCTION_CODE (callee));
+                                            fcode);
+    case BUILT_IN_STPCPY:
+      return gimple_fold_builtin_stpcpy (gsi);
     case BUILT_IN_STRCPY_CHK:
     case BUILT_IN_STPCPY_CHK:
       return gimple_fold_builtin_stxcpy_chk (gsi,
                                             gimple_call_arg (stmt, 0),
                                             gimple_call_arg (stmt, 1),
                                             gimple_call_arg (stmt, 2),
-                                            DECL_FUNCTION_CODE (callee));
+                                            fcode);
     case BUILT_IN_STRNCPY_CHK:
     case BUILT_IN_STPNCPY_CHK:
       return gimple_fold_builtin_stxncpy_chk (gsi,
@@ -2501,15 +2931,53 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
                                              gimple_call_arg (stmt, 1),
                                              gimple_call_arg (stmt, 2),
                                              gimple_call_arg (stmt, 3),
-                                             DECL_FUNCTION_CODE (callee));
+                                             fcode);
     case BUILT_IN_SNPRINTF_CHK:
     case BUILT_IN_VSNPRINTF_CHK:
-      return gimple_fold_builtin_snprintf_chk (gsi,
-                                              DECL_FUNCTION_CODE (callee));
+      return gimple_fold_builtin_snprintf_chk (gsi, fcode);
     case BUILT_IN_SNPRINTF:
       return gimple_fold_builtin_snprintf (gsi);
     case BUILT_IN_SPRINTF:
       return gimple_fold_builtin_sprintf (gsi);
+    case BUILT_IN_FPRINTF:
+    case BUILT_IN_FPRINTF_UNLOCKED:
+    case BUILT_IN_VFPRINTF:
+      if (n == 2 || n == 3)
+       return gimple_fold_builtin_fprintf (gsi,
+                                           gimple_call_arg (stmt, 0),
+                                           gimple_call_arg (stmt, 1),
+                                           n == 3
+                                           ? gimple_call_arg (stmt, 2)
+                                           : NULL_TREE,
+                                           fcode);
+      break;
+    case BUILT_IN_FPRINTF_CHK:
+    case BUILT_IN_VFPRINTF_CHK:
+      if (n == 3 || n == 4)
+       return gimple_fold_builtin_fprintf (gsi,
+                                           gimple_call_arg (stmt, 0),
+                                           gimple_call_arg (stmt, 2),
+                                           n == 4
+                                           ? gimple_call_arg (stmt, 3)
+                                           : NULL_TREE,
+                                           fcode);
+      break;
+    case BUILT_IN_PRINTF:
+    case BUILT_IN_PRINTF_UNLOCKED:
+    case BUILT_IN_VPRINTF:
+      if (n == 1 || n == 2)
+       return gimple_fold_builtin_printf (gsi, gimple_call_arg (stmt, 0),
+                                          n == 2
+                                          ? gimple_call_arg (stmt, 1)
+                                          : NULL_TREE, fcode);
+      break;
+    case BUILT_IN_PRINTF_CHK:
+    case BUILT_IN_VPRINTF_CHK:
+      if (n == 2 || n == 3)
+       return gimple_fold_builtin_printf (gsi, gimple_call_arg (stmt, 1),
+                                          n == 3
+                                          ? gimple_call_arg (stmt, 2)
+                                          : NULL_TREE, fcode);
     default:;
     }
 
@@ -2530,6 +2998,33 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
   return false;
 }
 
+/* Return true if ARG0 CODE ARG1 in infinite signed precision operation
+   doesn't fit into TYPE.  The test for overflow should be regardless of
+   -fwrapv, and even for unsigned types.  */
+
+bool
+arith_overflowed_p (enum tree_code code, const_tree type,
+                   const_tree arg0, const_tree arg1)
+{
+  typedef FIXED_WIDE_INT (WIDE_INT_MAX_PRECISION * 2) widest2_int;
+  typedef generic_wide_int <wi::extended_tree <WIDE_INT_MAX_PRECISION * 2> >
+    widest2_int_cst;
+  widest2_int warg0 = widest2_int_cst (arg0);
+  widest2_int warg1 = widest2_int_cst (arg1);
+  widest2_int wres;
+  switch (code)
+    {
+    case PLUS_EXPR: wres = wi::add (warg0, warg1); break;
+    case MINUS_EXPR: wres = wi::sub (warg0, warg1); break;
+    case MULT_EXPR: wres = wi::mul (warg0, warg1); break;
+    default: gcc_unreachable ();
+    }
+  signop sign = TYPE_SIGN (type);
+  if (sign == UNSIGNED && wi::neg_p (wres))
+    return true;
+  return wi::min_precision (wres, sign) > TYPE_PRECISION (type);
+}
+
 /* Attempt to fold a call statement referenced by the statement iterator GSI.
    The statement may be replaced by another statement, e.g., if the call
    simplifies to a constant value. Return true if any changes were made.
@@ -2538,7 +3033,7 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
 static bool
 gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
 {
-  gimple stmt = gsi_stmt (*gsi);
+  gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
   tree callee;
   bool changed = false;
   unsigned i;
@@ -2603,13 +3098,14 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
                    {
                      if (TREE_CODE (lhs) == SSA_NAME)
                        {
-                         tree var = create_tmp_var (TREE_TYPE (lhs), NULL);
+                         tree var = create_tmp_var (TREE_TYPE (lhs));
                          tree def = get_or_create_ssa_default_def (cfun, var);
                          gimple new_stmt = gimple_build_assign (lhs, def);
                          gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
                        }
                      gimple_call_set_lhs (stmt, NULL_TREE);
                    }
+                 maybe_remove_unused_call_args (cfun, stmt);
                }
              else
                {
@@ -2618,7 +3114,7 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
                  gimple_set_location (new_stmt, gimple_location (stmt));
                  if (lhs && TREE_CODE (lhs) == SSA_NAME)
                    {
-                     tree var = create_tmp_var (TREE_TYPE (lhs), NULL);
+                     tree var = create_tmp_var (TREE_TYPE (lhs));
                      tree def = get_or_create_ssa_default_def (cfun, var);
 
                      /* To satisfy condition for
@@ -2629,13 +3125,38 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
                      gsi_insert_before (gsi, new_stmt, GSI_NEW_STMT);
                    }
                  else
-                   gsi_replace (gsi, new_stmt, true);
+                   {
+                     gimple_set_vuse (new_stmt, gimple_vuse (stmt));
+                     gimple_set_vdef (new_stmt, gimple_vdef (stmt));
+                     gsi_replace (gsi, new_stmt, false);
+                   }
                  return true;
                }
            }
        }
     }
 
+  /* Check for indirect calls that became direct calls, and then
+     no longer require a static chain.  */
+  if (gimple_call_chain (stmt))
+    {
+      tree fn = gimple_call_fndecl (stmt);
+      if (fn && !DECL_STATIC_CHAIN (fn))
+       {
+         gimple_call_set_chain (stmt, NULL);
+         changed = true;
+       }
+      else
+       {
+         tree tmp = maybe_fold_reference (gimple_call_chain (stmt), false);
+         if (tmp)
+           {
+             gimple_call_set_chain (stmt, tmp);
+             changed = true;
+           }
+       }
+    }
+
   if (inplace)
     return changed;
 
@@ -2654,6 +3175,8 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
     {
       enum tree_code subcode = ERROR_MARK;
       tree result = NULL_TREE;
+      bool cplx_result = false;
+      tree overflow = NULL_TREE;
       switch (gimple_call_internal_fn (stmt))
        {
        case IFN_BUILTIN_EXPECT:
@@ -2662,6 +3185,19 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
                                        gimple_call_arg (stmt, 1),
                                        gimple_call_arg (stmt, 2));
          break;
+       case IFN_UBSAN_OBJECT_SIZE:
+         if (integer_all_onesp (gimple_call_arg (stmt, 2))
+             || (TREE_CODE (gimple_call_arg (stmt, 1)) == INTEGER_CST
+                 && TREE_CODE (gimple_call_arg (stmt, 2)) == INTEGER_CST
+                 && tree_int_cst_le (gimple_call_arg (stmt, 1),
+                                     gimple_call_arg (stmt, 2))))
+           {
+             gsi_replace (gsi, gimple_build_nop (), true);
+             unlink_stmt_vdef (stmt);
+             release_defs (stmt);
+             return true;
+           }
+         break;
        case IFN_UBSAN_CHECK_ADD:
          subcode = PLUS_EXPR;
          break;
@@ -2671,6 +3207,18 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
        case IFN_UBSAN_CHECK_MUL:
          subcode = MULT_EXPR;
          break;
+       case IFN_ADD_OVERFLOW:
+         subcode = PLUS_EXPR;
+         cplx_result = true;
+         break;
+       case IFN_SUB_OVERFLOW:
+         subcode = MINUS_EXPR;
+         cplx_result = true;
+         break;
+       case IFN_MUL_OVERFLOW:
+         subcode = MULT_EXPR;
+         cplx_result = true;
+         break;
        default:
          break;
        }
@@ -2678,30 +3226,88 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
        {
          tree arg0 = gimple_call_arg (stmt, 0);
          tree arg1 = gimple_call_arg (stmt, 1);
+         tree type = TREE_TYPE (arg0);
+         if (cplx_result)
+           {
+             tree lhs = gimple_call_lhs (stmt);
+             if (lhs == NULL_TREE)
+               type = NULL_TREE;
+             else
+               type = TREE_TYPE (TREE_TYPE (lhs));
+           }
+         if (type == NULL_TREE)
+           ;
          /* x = y + 0; x = y - 0; x = y * 0; */
-         if (integer_zerop (arg1))
-           result = subcode == MULT_EXPR
-                    ? build_zero_cst (TREE_TYPE (arg0))
-                    : arg0;
+         else if (integer_zerop (arg1))
+           result = subcode == MULT_EXPR ? integer_zero_node : arg0;
          /* x = 0 + y; x = 0 * y; */
          else if (subcode != MINUS_EXPR && integer_zerop (arg0))
-           result = subcode == MULT_EXPR
-                    ? build_zero_cst (TREE_TYPE (arg0))
-                    : arg1;
+           result = subcode == MULT_EXPR ? integer_zero_node : arg1;
          /* x = y - y; */
          else if (subcode == MINUS_EXPR && operand_equal_p (arg0, arg1, 0))
-           result = build_zero_cst (TREE_TYPE (arg0));
+           result = integer_zero_node;
          /* x = y * 1; x = 1 * y; */
-         else if (subcode == MULT_EXPR)
+         else if (subcode == MULT_EXPR && integer_onep (arg1))
+           result = arg0;
+         else if (subcode == MULT_EXPR && integer_onep (arg0))
+           result = arg1;
+         else if (TREE_CODE (arg0) == INTEGER_CST
+                  && TREE_CODE (arg1) == INTEGER_CST)
            {
-             if (integer_onep (arg1))
-               result = arg0;
-             else if (integer_onep (arg0))
-               result = arg1;
+             if (cplx_result)
+               result = int_const_binop (subcode, fold_convert (type, arg0),
+                                         fold_convert (type, arg1));
+             else
+               result = int_const_binop (subcode, arg0, arg1);
+             if (result && arith_overflowed_p (subcode, type, arg0, arg1))
+               {
+                 if (cplx_result)
+                   overflow = build_one_cst (type);
+                 else
+                   result = NULL_TREE;
+               }
+           }
+         if (result)
+           {
+             if (result == integer_zero_node)
+               result = build_zero_cst (type);
+             else if (cplx_result && TREE_TYPE (result) != type)
+               {
+                 if (TREE_CODE (result) == INTEGER_CST)
+                   {
+                     if (arith_overflowed_p (PLUS_EXPR, type, result,
+                                             integer_zero_node))
+                       overflow = build_one_cst (type);
+                   }
+                 else if ((!TYPE_UNSIGNED (TREE_TYPE (result))
+                           && TYPE_UNSIGNED (type))
+                          || (TYPE_PRECISION (type)
+                              < (TYPE_PRECISION (TREE_TYPE (result))
+                                 + (TYPE_UNSIGNED (TREE_TYPE (result))
+                                    && !TYPE_UNSIGNED (type)))))
+                   result = NULL_TREE;
+                 if (result)
+                   result = fold_convert (type, result);
+               }
            }
        }
+
       if (result)
        {
+         if (TREE_CODE (result) == INTEGER_CST && TREE_OVERFLOW (result))
+           result = drop_tree_overflow (result);
+         if (cplx_result)
+           {
+             if (overflow == NULL_TREE)
+               overflow = build_zero_cst (TREE_TYPE (result));
+             tree ctype = build_complex_type (TREE_TYPE (result));
+             if (TREE_CODE (result) == INTEGER_CST
+                 && TREE_CODE (overflow) == INTEGER_CST)
+               result = build_complex (ctype, result, overflow);
+             else
+               result = build2_loc (gimple_location (stmt), COMPLEX_EXPR,
+                                    ctype, result, overflow);
+           }
          if (!update_call_from_tree (gsi, result))
            gimplify_and_update_call_from_tree (gsi, result);
          changed = true;
@@ -2711,6 +3317,121 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
   return changed;
 }
 
+
+/* Worker for fold_stmt_1 dispatch to pattern based folding with
+   gimple_simplify.
+
+   Replaces *GSI with the simplification result in RCODE and OPS
+   and the associated statements in *SEQ.  Does the replacement
+   according to INPLACE and returns true if the operation succeeded.  */
+
+static bool
+replace_stmt_with_simplification (gimple_stmt_iterator *gsi,
+                                 code_helper rcode, tree *ops,
+                                 gimple_seq *seq, bool inplace)
+{
+  gimple stmt = gsi_stmt (*gsi);
+
+  /* Play safe and do not allow abnormals to be mentioned in
+     newly created statements.  See also maybe_push_res_to_seq.  */
+  if ((TREE_CODE (ops[0]) == SSA_NAME
+       && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0]))
+      || (ops[1]
+         && TREE_CODE (ops[1]) == SSA_NAME
+         && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1]))
+      || (ops[2]
+         && TREE_CODE (ops[2]) == SSA_NAME
+         && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2])))
+    return false;
+
+  if (gcond *cond_stmt = dyn_cast <gcond *> (stmt))
+    {
+      gcc_assert (rcode.is_tree_code ());
+      if (TREE_CODE_CLASS ((enum tree_code)rcode) == tcc_comparison
+         /* GIMPLE_CONDs condition may not throw.  */
+         && (!flag_exceptions
+             || !cfun->can_throw_non_call_exceptions
+             || !operation_could_trap_p (rcode,
+                                         FLOAT_TYPE_P (TREE_TYPE (ops[0])),
+                                         false, NULL_TREE)))
+       gimple_cond_set_condition (cond_stmt, rcode, ops[0], ops[1]);
+      else if (rcode == SSA_NAME)
+       gimple_cond_set_condition (cond_stmt, NE_EXPR, ops[0],
+                                  build_zero_cst (TREE_TYPE (ops[0])));
+      else if (rcode == INTEGER_CST)
+       {
+         if (integer_zerop (ops[0]))
+           gimple_cond_make_false (cond_stmt);
+         else
+           gimple_cond_make_true (cond_stmt);
+       }
+      else if (!inplace)
+       {
+         tree res = maybe_push_res_to_seq (rcode, boolean_type_node,
+                                           ops, seq);
+         if (!res)
+           return false;
+         gimple_cond_set_condition (cond_stmt, NE_EXPR, res,
+                                    build_zero_cst (TREE_TYPE (res)));
+       }
+      else
+       return false;
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "gimple_simplified to ");
+         if (!gimple_seq_empty_p (*seq))
+           print_gimple_seq (dump_file, *seq, 0, TDF_SLIM);
+         print_gimple_stmt (dump_file, gsi_stmt (*gsi),
+                            0, TDF_SLIM);
+       }
+      gsi_insert_seq_before (gsi, *seq, GSI_SAME_STMT);
+      return true;
+    }
+  else if (is_gimple_assign (stmt)
+          && rcode.is_tree_code ())
+    {
+      if (!inplace
+         || gimple_num_ops (stmt) > get_gimple_rhs_num_ops (rcode))
+       {
+         maybe_build_generic_op (rcode,
+                                 TREE_TYPE (gimple_assign_lhs (stmt)),
+                                 &ops[0], ops[1], ops[2]);
+         gimple_assign_set_rhs_with_ops (gsi, rcode, ops[0], ops[1], ops[2]);
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           {
+             fprintf (dump_file, "gimple_simplified to ");
+             if (!gimple_seq_empty_p (*seq))
+               print_gimple_seq (dump_file, *seq, 0, TDF_SLIM);
+             print_gimple_stmt (dump_file, gsi_stmt (*gsi),
+                                0, TDF_SLIM);
+           }
+         gsi_insert_seq_before (gsi, *seq, GSI_SAME_STMT);
+         return true;
+       }
+    }
+  else if (!inplace)
+    {
+      if (gimple_has_lhs (stmt))
+       {
+         tree lhs = gimple_get_lhs (stmt);
+         if (!maybe_push_res_to_seq (rcode, TREE_TYPE (lhs),
+                                     ops, seq, lhs))
+           return false;
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           {
+             fprintf (dump_file, "gimple_simplified to ");
+             print_gimple_seq (dump_file, *seq, 0, TDF_SLIM);
+           }
+         gsi_replace_with_seq_vops (gsi, *seq);
+         return true;
+       }
+      else
+       gcc_unreachable ();
+    }
+
+  return false;
+}
+
 /* Canonicalize MEM_REFs invariant address operand after propagation.  */
 
 static bool
@@ -2755,7 +3476,8 @@ maybe_canonicalize_mem_ref_addr (tree *t)
      accessed is a decl that has the same access semantics as the MEM_REF.  */
   if (TREE_CODE (*t) == MEM_REF
       && TREE_CODE (TREE_OPERAND (*t, 0)) == ADDR_EXPR
-      && integer_zerop (TREE_OPERAND (*t, 1)))
+      && integer_zerop (TREE_OPERAND (*t, 1))
+      && MR_DEPENDENCE_CLIQUE (*t) == 0)
     {
       tree decl = TREE_OPERAND (TREE_OPERAND (*t, 0), 0);
       tree alias_type = TREE_TYPE (TREE_OPERAND (*t, 1));
@@ -2797,7 +3519,7 @@ maybe_canonicalize_mem_ref_addr (tree *t)
    distinguishes both cases.  */
 
 static bool
-fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace)
+fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace, tree (*valueize) (tree))
 {
   bool changed = false;
   gimple stmt = gsi_stmt (*gsi);
@@ -2842,17 +3564,18 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace)
       }
     case GIMPLE_ASM:
       {
-       for (i = 0; i < gimple_asm_noutputs (stmt); ++i)
+       gasm *asm_stmt = as_a <gasm *> (stmt);
+       for (i = 0; i < gimple_asm_noutputs (asm_stmt); ++i)
          {
-           tree link = gimple_asm_output_op (stmt, i);
+           tree link = gimple_asm_output_op (asm_stmt, i);
            tree op = TREE_VALUE (link);
            if (REFERENCE_CLASS_P (op)
                && maybe_canonicalize_mem_ref_addr (&TREE_VALUE (link)))
              changed = true;
          }
-       for (i = 0; i < gimple_asm_ninputs (stmt); ++i)
+       for (i = 0; i < gimple_asm_ninputs (asm_stmt); ++i)
          {
-           tree link = gimple_asm_input_op (stmt, i);
+           tree link = gimple_asm_input_op (asm_stmt, i);
            tree op = TREE_VALUE (link);
            if ((REFERENCE_CLASS_P (op)
                 || TREE_CODE (op) == ADDR_EXPR)
@@ -2875,6 +3598,26 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace)
     default:;
     }
 
+  /* Dispatch to pattern-based folding.  */
+  if (!inplace
+      || is_gimple_assign (stmt)
+      || gimple_code (stmt) == GIMPLE_COND)
+    {
+      gimple_seq seq = NULL;
+      code_helper rcode;
+      tree ops[3] = {};
+      if (gimple_simplify (stmt, &rcode, ops, inplace ? NULL : &seq,
+                          valueize, valueize))
+       {
+         if (replace_stmt_with_simplification (gsi, rcode, ops, &seq, inplace))
+           changed = true;
+         else
+           gimple_seq_discard (seq);
+       }
+    }
+
+  stmt = gsi_stmt (*gsi);
+
   /* Fold the main computation performed by the statement.  */
   switch (gimple_code (stmt))
     {
@@ -2912,7 +3655,7 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace)
       }
 
     case GIMPLE_COND:
-      changed |= fold_gimple_cond (stmt);
+      changed |= fold_gimple_cond (as_a <gcond *> (stmt));
       break;
 
     case GIMPLE_CALL:
@@ -2922,17 +3665,18 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace)
     case GIMPLE_ASM:
       /* Fold *& in asm operands.  */
       {
+       gasm *asm_stmt = as_a <gasm *> (stmt);
        size_t noutputs;
        const char **oconstraints;
        const char *constraint;
        bool allows_mem, allows_reg;
 
-       noutputs = gimple_asm_noutputs (stmt);
+       noutputs = gimple_asm_noutputs (asm_stmt);
        oconstraints = XALLOCAVEC (const char *, noutputs);
 
-       for (i = 0; i < gimple_asm_noutputs (stmt); ++i)
+       for (i = 0; i < gimple_asm_noutputs (asm_stmt); ++i)
          {
-           tree link = gimple_asm_output_op (stmt, i);
+           tree link = gimple_asm_output_op (asm_stmt, i);
            tree op = TREE_VALUE (link);
            oconstraints[i]
              = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
@@ -2943,9 +3687,9 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace)
                changed = true;
              }
          }
-       for (i = 0; i < gimple_asm_ninputs (stmt); ++i)
+       for (i = 0; i < gimple_asm_ninputs (asm_stmt); ++i)
          {
-           tree link = gimple_asm_input_op (stmt, i);
+           tree link = gimple_asm_input_op (asm_stmt, i);
            tree op = TREE_VALUE (link);
            constraint
              = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
@@ -3014,6 +3758,25 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace)
   return changed;
 }
 
+/* Valueziation callback that ends up not following SSA edges.  */
+
+tree
+no_follow_ssa_edges (tree)
+{
+  return NULL_TREE;
+}
+
+/* Valueization callback that ends up following single-use SSA edges only.  */
+
+tree
+follow_single_use_edges (tree val)
+{
+  if (TREE_CODE (val) == SSA_NAME
+      && !has_single_use (val))
+    return NULL_TREE;
+  return val;
+}
+
 /* Fold the statement pointed to by GSI.  In some cases, this function may
    replace the whole statement with a new one.  Returns true iff folding
    makes any changes.
@@ -3024,7 +3787,13 @@ fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace)
 bool
 fold_stmt (gimple_stmt_iterator *gsi)
 {
-  return fold_stmt_1 (gsi, false);
+  return fold_stmt_1 (gsi, false, no_follow_ssa_edges);
+}
+
+bool
+fold_stmt (gimple_stmt_iterator *gsi, tree (*valueize) (tree))
+{
+  return fold_stmt_1 (gsi, false, valueize);
 }
 
 /* Perform the minimal folding on statement *GSI.  Only operations like
@@ -3039,7 +3808,7 @@ bool
 fold_stmt_inplace (gimple_stmt_iterator *gsi)
 {
   gimple stmt = gsi_stmt (*gsi);
-  bool changed = fold_stmt_1 (gsi, true);
+  bool changed = fold_stmt_1 (gsi, true, no_follow_ssa_edges);
   gcc_assert (gsi_stmt (*gsi) == stmt);
   return changed;
 }
@@ -3062,7 +3831,7 @@ canonicalize_bool (tree expr, bool invert)
       else if (TREE_CODE (expr) == SSA_NAME)
        return fold_build2 (EQ_EXPR, boolean_type_node, expr,
                            build_int_cst (TREE_TYPE (expr), 0));
-      else if (TREE_CODE_CLASS (TREE_CODE (expr)) == tcc_comparison)
+      else if (COMPARISON_CLASS_P (expr))
        return fold_build2 (invert_tree_comparison (TREE_CODE (expr), false),
                            boolean_type_node,
                            TREE_OPERAND (expr, 0),
@@ -3081,7 +3850,7 @@ canonicalize_bool (tree expr, bool invert)
       else if (TREE_CODE (expr) == SSA_NAME)
        return fold_build2 (NE_EXPR, boolean_type_node, expr,
                            build_int_cst (TREE_TYPE (expr), 0));
-      else if (TREE_CODE_CLASS (TREE_CODE (expr)) == tcc_comparison)
+      else if (COMPARISON_CLASS_P (expr))
        return fold_build2 (TREE_CODE (expr),
                            boolean_type_node,
                            TREE_OPERAND (expr, 0),
@@ -3162,12 +3931,12 @@ same_bool_result_p (const_tree op1, const_tree op2)
   /* Check the cases where at least one of the operands is a comparison.
      These are a bit smarter than operand_equal_p in that they apply some
      identifies on SSA_NAMEs.  */
-  if (TREE_CODE_CLASS (TREE_CODE (op2)) == tcc_comparison
+  if (COMPARISON_CLASS_P (op2)
       && same_bool_comparison_p (op1, TREE_CODE (op2),
                                 TREE_OPERAND (op2, 0),
                                 TREE_OPERAND (op2, 1)))
     return true;
-  if (TREE_CODE_CLASS (TREE_CODE (op1)) == tcc_comparison
+  if (COMPARISON_CLASS_P (op1)
       && same_bool_comparison_p (op2, TREE_CODE (op1),
                                 TREE_OPERAND (op1, 0),
                                 TREE_OPERAND (op1, 1)))
@@ -4136,8 +4905,33 @@ maybe_fold_or_comparisons (enum tree_code code1, tree op1a, tree op1b,
    to avoid the indirect function call overhead.  */
 
 tree
-gimple_fold_stmt_to_constant_1 (gimple stmt, tree (*valueize) (tree))
+gimple_fold_stmt_to_constant_1 (gimple stmt, tree (*valueize) (tree),
+                               tree (*gvalueize) (tree))
 {
+  code_helper rcode;
+  tree ops[3] = {};
+  /* ???  The SSA propagators do not correctly deal with following SSA use-def
+     edges if there are intermediate VARYING defs.  For this reason
+     do not follow SSA edges here even though SCCVN can technically
+     just deal fine with that.  */
+  if (gimple_simplify (stmt, &rcode, ops, NULL, gvalueize, valueize)
+      && rcode.is_tree_code ()
+      && (TREE_CODE_LENGTH ((tree_code) rcode) == 0
+         || ((tree_code) rcode) == ADDR_EXPR)
+      && is_gimple_val (ops[0]))
+    {
+      tree res = ops[0];
+      if (dump_file && dump_flags & TDF_DETAILS)
+       {
+         fprintf (dump_file, "Match-and-simplified ");
+         print_gimple_expr (dump_file, stmt, 0, TDF_SLIM);
+         fprintf (dump_file, " to ");
+         print_generic_expr (dump_file, res, 0);
+         fprintf (dump_file, "\n");
+       }
+      return res;
+    }
+
   location_t loc = gimple_location (stmt);
   switch (gimple_code (stmt))
     {
@@ -4249,16 +5043,7 @@ gimple_fold_stmt_to_constant_1 (gimple stmt, tree (*valueize) (tree))
             }
 
           case GIMPLE_UNARY_RHS:
-            {
-              /* Handle unary operators that can appear in GIMPLE form.
-                 Note that we know the single operand must be a constant,
-                 so this should almost always return a simplified RHS.  */
-              tree op0 = (*valueize) (gimple_assign_rhs1 (stmt));
-
-              return
-               fold_unary_ignore_overflow_loc (loc, subcode,
-                                               gimple_expr_type (stmt), op0);
-            }
+           return NULL_TREE;
 
           case GIMPLE_BINARY_RHS:
             {
@@ -4316,6 +5101,7 @@ gimple_fold_stmt_to_constant_1 (gimple stmt, tree (*valueize) (tree))
     case GIMPLE_CALL:
       {
        tree fn;
+       gcall *call_stmt = as_a <gcall *> (stmt);
 
        if (gimple_call_internal_p (stmt))
          {
@@ -4375,19 +5161,19 @@ gimple_fold_stmt_to_constant_1 (gimple stmt, tree (*valueize) (tree))
                                                       TREE_OPERAND (fn, 0)))
          {
            tree *args = XALLOCAVEC (tree, gimple_call_num_args (stmt));
-           tree call, retval;
+           tree retval;
            unsigned i;
            for (i = 0; i < gimple_call_num_args (stmt); ++i)
              args[i] = (*valueize) (gimple_call_arg (stmt, i));
-           call = build_call_array_loc (loc,
-                                        gimple_call_return_type (stmt),
+           retval = fold_builtin_call_array (loc,
+                                        gimple_call_return_type (call_stmt),
                                         fn, gimple_call_num_args (stmt), args);
-           retval = fold_call_expr (EXPR_LOCATION (call), call, false);
            if (retval)
              {
                /* fold_call_expr wraps the result inside a NOP_EXPR.  */
                STRIP_NOPS (retval);
-               retval = fold_convert (gimple_call_return_type (stmt), retval);
+               retval = fold_convert (gimple_call_return_type (call_stmt),
+                                      retval);
              }
            return retval;
          }
@@ -4416,10 +5202,6 @@ gimple_fold_stmt_to_constant (gimple stmt, tree (*valueize) (tree))
 /* The following set of functions are supposed to fold references using
    their constant initializers.  */
 
-static tree fold_ctor_reference (tree type, tree ctor,
-                                unsigned HOST_WIDE_INT offset,
-                                unsigned HOST_WIDE_INT size, tree);
-
 /* See if we can find constructor defining value of BASE.
    When we know the consructor with constant offset (such as
    base is array[40] and we do know constructor of array), then
@@ -4655,7 +5437,7 @@ fold_nonarray_ctor_reference (tree type, tree ctor,
 /* CTOR is value initializing memory, fold reference of type TYPE and size SIZE
    to the memory at bit OFFSET.  */
 
-static tree
+tree
 fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset,
                     unsigned HOST_WIDE_INT size, tree from_decl)
 {
@@ -4676,7 +5458,7 @@ fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset,
       ret = canonicalize_constructor_val (unshare_expr (ctor), from_decl);
       ret = fold_unary (VIEW_CONVERT_EXPR, type, ret);
       if (ret)
-       STRIP_NOPS (ret);
+       STRIP_USELESS_TYPE_CONVERSION (ret);
       return ret;
     }
   /* For constants and byte-aligned/sized reads try to go through
@@ -4721,7 +5503,7 @@ fold_const_aggregate_ref_1 (tree t, tree (*valueize) (tree))
   if (TREE_THIS_VOLATILE (t))
     return NULL_TREE;
 
-  if (TREE_CODE_CLASS (TREE_CODE (t)) == tcc_declaration)
+  if (DECL_P (t))
     return get_symbol_constant_value (t);
 
   tem = fold_read_from_constant_string (t);
@@ -4854,7 +5636,6 @@ gimple_get_virt_method_for_vtable (HOST_WIDE_INT token,
   if (TREE_CODE (v) != VAR_DECL
       || !DECL_VIRTUAL_P (v))
     {
-      gcc_assert (in_lto_p);
       /* Pass down that we lost track of the target.  */
       if (can_refer)
        *can_refer = false;
@@ -5054,7 +5835,7 @@ gimple_val_nonnegative_real_p (tree val)
            CASE_FLT_FN (BUILT_IN_SQRT):
              /* sqrt(-0.0) is -0.0, and sqrt is not defined over other
                 nonnegative inputs.  */
-             if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (val))))
+             if (!HONOR_SIGNED_ZEROS (val))
                return true;
 
              break;
@@ -5276,9 +6057,205 @@ rewrite_to_defined_overflow (gimple stmt)
   if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
     gimple_assign_set_rhs_code (stmt, PLUS_EXPR);
   gimple_seq_add_stmt (&stmts, stmt);
-  gimple cvt = gimple_build_assign_with_ops
-      (NOP_EXPR, lhs, gimple_assign_lhs (stmt), NULL_TREE);
+  gimple cvt = gimple_build_assign (lhs, NOP_EXPR, gimple_assign_lhs (stmt));
   gimple_seq_add_stmt (&stmts, cvt);
 
   return stmts;
 }
+
+
+/* The valueization hook we use for the gimple_build API simplification.
+   This makes us match fold_buildN behavior by only combining with
+   statements in the sequence(s) we are currently building.  */
+
+static tree
+gimple_build_valueize (tree op)
+{
+  if (gimple_bb (SSA_NAME_DEF_STMT (op)) == NULL)
+    return op;
+  return NULL_TREE;
+}
+
+/* Build the expression CODE OP0 of type TYPE with location LOC,
+   simplifying it first if possible.  Returns the built
+   expression value and appends statements possibly defining it
+   to SEQ.  */
+
+tree
+gimple_build (gimple_seq *seq, location_t loc,
+             enum tree_code code, tree type, tree op0)
+{
+  tree res = gimple_simplify (code, type, op0, seq, gimple_build_valueize);
+  if (!res)
+    {
+      if (gimple_in_ssa_p (cfun))
+       res = make_ssa_name (type);
+      else
+       res = create_tmp_reg (type);
+      gimple stmt;
+      if (code == REALPART_EXPR
+         || code == IMAGPART_EXPR
+         || code == VIEW_CONVERT_EXPR)
+       stmt = gimple_build_assign (res, code, build1 (code, type, op0));
+      else
+       stmt = gimple_build_assign (res, code, op0);
+      gimple_set_location (stmt, loc);
+      gimple_seq_add_stmt_without_update (seq, stmt);
+    }
+  return res;
+}
+
+/* Build the expression OP0 CODE OP1 of type TYPE with location LOC,
+   simplifying it first if possible.  Returns the built
+   expression value and appends statements possibly defining it
+   to SEQ.  */
+
+tree
+gimple_build (gimple_seq *seq, location_t loc,
+             enum tree_code code, tree type, tree op0, tree op1)
+{
+  tree res = gimple_simplify (code, type, op0, op1, seq, gimple_build_valueize);
+  if (!res)
+    {
+      if (gimple_in_ssa_p (cfun))
+       res = make_ssa_name (type);
+      else
+       res = create_tmp_reg (type);
+      gimple stmt = gimple_build_assign (res, code, op0, op1);
+      gimple_set_location (stmt, loc);
+      gimple_seq_add_stmt_without_update (seq, stmt);
+    }
+  return res;
+}
+
+/* Build the expression (CODE OP0 OP1 OP2) of type TYPE with location LOC,
+   simplifying it first if possible.  Returns the built
+   expression value and appends statements possibly defining it
+   to SEQ.  */
+
+tree
+gimple_build (gimple_seq *seq, location_t loc,
+             enum tree_code code, tree type, tree op0, tree op1, tree op2)
+{
+  tree res = gimple_simplify (code, type, op0, op1, op2,
+                             seq, gimple_build_valueize);
+  if (!res)
+    {
+      if (gimple_in_ssa_p (cfun))
+       res = make_ssa_name (type);
+      else
+       res = create_tmp_reg (type);
+      gimple stmt;
+      if (code == BIT_FIELD_REF)
+       stmt = gimple_build_assign (res, code,
+                                   build3 (code, type, op0, op1, op2));
+      else
+       stmt = gimple_build_assign (res, code, op0, op1, op2);
+      gimple_set_location (stmt, loc);
+      gimple_seq_add_stmt_without_update (seq, stmt);
+    }
+  return res;
+}
+
+/* Build the call FN (ARG0) with a result of type TYPE
+   (or no result if TYPE is void) with location LOC,
+   simplifying it first if possible.  Returns the built
+   expression value (or NULL_TREE if TYPE is void) and appends
+   statements possibly defining it to SEQ.  */
+
+tree
+gimple_build (gimple_seq *seq, location_t loc,
+             enum built_in_function fn, tree type, tree arg0)
+{
+  tree res = gimple_simplify (fn, type, arg0, seq, gimple_build_valueize);
+  if (!res)
+    {
+      tree decl = builtin_decl_implicit (fn);
+      gimple stmt = gimple_build_call (decl, 1, arg0);
+      if (!VOID_TYPE_P (type))
+       {
+         if (gimple_in_ssa_p (cfun))
+           res = make_ssa_name (type);
+         else
+           res = create_tmp_reg (type);
+         gimple_call_set_lhs (stmt, res);
+       }
+      gimple_set_location (stmt, loc);
+      gimple_seq_add_stmt_without_update (seq, stmt);
+    }
+  return res;
+}
+
+/* Build the call FN (ARG0, ARG1) with a result of type TYPE
+   (or no result if TYPE is void) with location LOC,
+   simplifying it first if possible.  Returns the built
+   expression value (or NULL_TREE if TYPE is void) and appends
+   statements possibly defining it to SEQ.  */
+
+tree
+gimple_build (gimple_seq *seq, location_t loc,
+             enum built_in_function fn, tree type, tree arg0, tree arg1)
+{
+  tree res = gimple_simplify (fn, type, arg0, arg1, seq, gimple_build_valueize);
+  if (!res)
+    {
+      tree decl = builtin_decl_implicit (fn);
+      gimple stmt = gimple_build_call (decl, 2, arg0, arg1);
+      if (!VOID_TYPE_P (type))
+       {
+         if (gimple_in_ssa_p (cfun))
+           res = make_ssa_name (type);
+         else
+           res = create_tmp_reg (type);
+         gimple_call_set_lhs (stmt, res);
+       }
+      gimple_set_location (stmt, loc);
+      gimple_seq_add_stmt_without_update (seq, stmt);
+    }
+  return res;
+}
+
+/* Build the call FN (ARG0, ARG1, ARG2) with a result of type TYPE
+   (or no result if TYPE is void) with location LOC,
+   simplifying it first if possible.  Returns the built
+   expression value (or NULL_TREE if TYPE is void) and appends
+   statements possibly defining it to SEQ.  */
+
+tree
+gimple_build (gimple_seq *seq, location_t loc,
+             enum built_in_function fn, tree type,
+             tree arg0, tree arg1, tree arg2)
+{
+  tree res = gimple_simplify (fn, type, arg0, arg1, arg2,
+                             seq, gimple_build_valueize);
+  if (!res)
+    {
+      tree decl = builtin_decl_implicit (fn);
+      gimple stmt = gimple_build_call (decl, 3, arg0, arg1, arg2);
+      if (!VOID_TYPE_P (type))
+       {
+         if (gimple_in_ssa_p (cfun))
+           res = make_ssa_name (type);
+         else
+           res = create_tmp_reg (type);
+         gimple_call_set_lhs (stmt, res);
+       }
+      gimple_set_location (stmt, loc);
+      gimple_seq_add_stmt_without_update (seq, stmt);
+    }
+  return res;
+}
+
+/* Build the conversion (TYPE) OP with a result of type TYPE
+   with location LOC if such conversion is neccesary in GIMPLE,
+   simplifying it first.
+   Returns the built expression value and appends
+   statements possibly defining it to SEQ.  */
+
+tree
+gimple_convert (gimple_seq *seq, location_t loc, tree type, tree op)
+{
+  if (useless_type_conversion_p (type, TREE_TYPE (op)))
+    return op;
+  return gimple_build (seq, loc, NOP_EXPR, type, op);
+}