]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/tree-ssa-math-opts.c
Correct a function pre/postcondition [PR102403].
[thirdparty/gcc.git] / gcc / tree-ssa-math-opts.c
index b7bbde4e40288c1a3f93e06273652454f7ed0899..c4a6492b50df25b4cf296a75bd51e5af34eeacc7 100644 (file)
@@ -1,5 +1,5 @@
 /* Global, SSA-based optimizations using mathematical identities.
-   Copyright (C) 2005-2019 Free Software Foundation, Inc.
+   Copyright (C) 2005-2021 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -109,50 +109,70 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dfa.h"
 #include "tree-ssa.h"
 #include "builtins.h"
-#include "params.h"
 #include "internal-fn.h"
 #include "case-cfn-macros.h"
 #include "optabs-libfuncs.h"
 #include "tree-eh.h"
 #include "targhooks.h"
 #include "domwalk.h"
+#include "tree-ssa-math-opts.h"
 
 /* This structure represents one basic block that either computes a
    division, or is a common dominator for basic block that compute a
    division.  */
 struct occurrence {
   /* The basic block represented by this structure.  */
-  basic_block bb;
+  basic_block bb = basic_block();
 
   /* If non-NULL, the SSA_NAME holding the definition for a reciprocal
      inserted in BB.  */
-  tree recip_def;
+  tree recip_def = tree();
 
   /* If non-NULL, the SSA_NAME holding the definition for a squared
      reciprocal inserted in BB.  */
-  tree square_recip_def;
+  tree square_recip_def = tree();
 
   /* If non-NULL, the GIMPLE_ASSIGN for a reciprocal computation that
      was inserted in BB.  */
-  gimple *recip_def_stmt;
+  gimple *recip_def_stmt = nullptr;
 
   /* Pointer to a list of "struct occurrence"s for blocks dominated
      by BB.  */
-  struct occurrence *children;
+  struct occurrence *children = nullptr;
 
   /* Pointer to the next "struct occurrence"s in the list of blocks
      sharing a common dominator.  */
-  struct occurrence *next;
+  struct occurrence *next = nullptr;
 
   /* The number of divisions that are in BB before compute_merit.  The
      number of divisions that are in BB or post-dominate it after
      compute_merit.  */
-  int num_divisions;
+  int num_divisions = 0;
 
   /* True if the basic block has a division, false if it is a common
      dominator for basic blocks that do.  If it is false and trapping
      math is active, BB is not a candidate for inserting a reciprocal.  */
-  bool bb_has_division;
+  bool bb_has_division = false;
+
+  /* Construct a struct occurrence for basic block BB, and whose
+     children list is headed by CHILDREN.  */
+  occurrence (basic_block bb, struct occurrence *children)
+  : bb (bb), children (children)
+  {
+    bb->aux = this;
+  }
+
+  /* Destroy a struct occurrence and remove it from its basic block.  */
+  ~occurrence ()
+  {
+    bb->aux = nullptr;
+  }
+
+  /* Allocate memory for a struct occurrence from OCC_POOL.  */
+  static void* operator new (size_t);
+
+  /* Return memory for a struct occurrence to OCC_POOL.  */
+  static void operator delete (void*, size_t);
 };
 
 static struct
@@ -168,6 +188,10 @@ static struct
 {
   /* Number of cexpi calls inserted.  */
   int inserted;
+
+  /* Number of conversions removed.  */
+  int conv_removed;
+
 } sincos_stats;
 
 static struct
@@ -192,23 +216,17 @@ static struct occurrence *occ_head;
 /* Allocation pool for getting instances of "struct occurrence".  */
 static object_allocator<occurrence> *occ_pool;
 
-
-
-/* Allocate and return a new struct occurrence for basic block BB, and
-   whose children list is headed by CHILDREN.  */
-static struct occurrence *
-occ_new (basic_block bb, struct occurrence *children)
+void* occurrence::operator new (size_t n)
 {
-  struct occurrence *occ;
-
-  bb->aux = occ = occ_pool->allocate ();
-  memset (occ, 0, sizeof (struct occurrence));
-
-  occ->bb = bb;
-  occ->children = children;
-  return occ;
+  gcc_assert (n == sizeof(occurrence));
+  return occ_pool->allocate_raw ();
 }
 
+void occurrence::operator delete (void *occ, size_t n)
+{
+  gcc_assert (n == sizeof(occurrence));
+  occ_pool->remove_raw (occ);
+}
 
 /* Insert NEW_OCC into our subset of the dominator tree.  P_HEAD points to a
    list of "struct occurrence"s, one per basic block, having IDOM as
@@ -260,7 +278,7 @@ insert_bb (struct occurrence *new_occ, basic_block idom,
          /* None of the previous blocks has DOM as a dominator: if we tail
             recursed, we would reexamine them uselessly. Just switch BB with
             DOM, and go on looking for blocks dominated by DOM.  */
-          new_occ = occ_new (dom, new_occ);
+         new_occ = new occurrence (dom, new_occ);
        }
 
       else
@@ -289,7 +307,7 @@ register_division_in (basic_block bb, int importance)
   occ = (struct occurrence *) bb->aux;
   if (!occ)
     {
-      occ = occ_new (bb, NULL);
+      occ = new occurrence (bb, NULL);
       insert_bb (occ, ENTRY_BLOCK_PTR_FOR_FN (cfun), &occ_head);
     }
 
@@ -433,7 +451,7 @@ insert_reciprocals (gimple_stmt_iterator *def_gsi, struct occurrence *occ,
          if (should_insert_square_recip)
            gsi_insert_before (&gsi, new_square_stmt, GSI_SAME_STMT);
        }
-      else if (def_gsi && occ->bb == def_gsi->bb)
+      else if (def_gsi && occ->bb == gsi_bb (*def_gsi))
        {
          /* Case 2: insert right after the definition.  Note that this will
             never happen if the definition statement can throw, because in
@@ -519,8 +537,7 @@ free_bb (struct occurrence *occ)
   /* First get the two pointers hanging off OCC.  */
   next = occ->next;
   child = occ->children;
-  occ->bb->aux = NULL;
-  occ_pool->remove (occ);
+  delete occ;
 
   /* Now ensure that we don't recurse unless it is necessary.  */
   if (!child)
@@ -1040,14 +1057,9 @@ pass_cse_reciprocals::execute (function *fun)
                      else
                        stmt2 = gimple_build_call_internal_vec (ifn, args);
                      gimple_call_set_lhs (stmt2, arg1);
-                     if (gimple_vdef (call))
-                       {
-                         gimple_set_vdef (stmt2, gimple_vdef (call));
-                         SSA_NAME_DEF_STMT (gimple_vdef (stmt2)) = stmt2;
-                       }
+                     gimple_move_vops (stmt2, call);
                      gimple_call_set_nothrow (stmt2,
                                               gimple_call_nothrow_p (call));
-                     gimple_set_vuse (stmt2, gimple_vuse (call));
                      gimple_stmt_iterator gsi2 = gsi_for_stmt (call);
                      gsi_replace (&gsi2, stmt2, true);
                    }
@@ -1092,6 +1104,103 @@ make_pass_cse_reciprocals (gcc::context *ctxt)
   return new pass_cse_reciprocals (ctxt);
 }
 
+/* If NAME is the result of a type conversion, look for other
+   equivalent dominating or dominated conversions, and replace all
+   uses with the earliest dominating name, removing the redundant
+   conversions.  Return the prevailing name.  */
+
+static tree
+execute_cse_conv_1 (tree name)
+{
+  if (SSA_NAME_IS_DEFAULT_DEF (name)
+      || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name))
+    return name;
+
+  gimple *def_stmt = SSA_NAME_DEF_STMT (name);
+
+  if (!gimple_assign_cast_p (def_stmt))
+    return name;
+
+  tree src = gimple_assign_rhs1 (def_stmt);
+
+  if (TREE_CODE (src) != SSA_NAME)
+    return name;
+
+  imm_use_iterator use_iter;
+  gimple *use_stmt;
+
+  /* Find the earliest dominating def.    */
+  FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, src)
+    {
+      if (use_stmt == def_stmt
+         || !gimple_assign_cast_p (use_stmt))
+       continue;
+
+      tree lhs = gimple_assign_lhs (use_stmt);
+
+      if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)
+         || (gimple_assign_rhs1 (use_stmt)
+             != gimple_assign_rhs1 (def_stmt))
+         || !types_compatible_p (TREE_TYPE (name), TREE_TYPE (lhs)))
+       continue;
+
+      bool use_dominates;
+      if (gimple_bb (def_stmt) == gimple_bb (use_stmt))
+       {
+         gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
+         while (!gsi_end_p (gsi) && gsi_stmt (gsi) != def_stmt)
+           gsi_next (&gsi);
+         use_dominates = !gsi_end_p (gsi);
+       }
+      else if (dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt),
+                              gimple_bb (def_stmt)))
+       use_dominates = false;
+      else if (dominated_by_p (CDI_DOMINATORS, gimple_bb (def_stmt),
+                              gimple_bb (use_stmt)))
+       use_dominates = true;
+      else
+       continue;
+
+      if (use_dominates)
+       {
+         std::swap (name, lhs);
+         std::swap (def_stmt, use_stmt);
+       }
+    }
+
+  /* Now go through all uses of SRC again, replacing the equivalent
+     dominated conversions.  We may replace defs that were not
+     dominated by the then-prevailing defs when we first visited
+     them.  */
+  FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, src)
+    {
+      if (use_stmt == def_stmt
+         || !gimple_assign_cast_p (use_stmt))
+       continue;
+
+      tree lhs = gimple_assign_lhs (use_stmt);
+
+      if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs)
+         || (gimple_assign_rhs1 (use_stmt)
+             != gimple_assign_rhs1 (def_stmt))
+         || !types_compatible_p (TREE_TYPE (name), TREE_TYPE (lhs)))
+       continue;
+
+      if (gimple_bb (def_stmt) == gimple_bb (use_stmt)
+         || dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt),
+                            gimple_bb (def_stmt)))
+       {
+         sincos_stats.conv_removed++;
+
+         gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
+         replace_uses_by (lhs, name);
+         gsi_remove (&gsi, true);
+       }
+    }
+
+  return name;
+}
+
 /* Records an occurrence at statement USE_STMT in the vector of trees
    STMTS if it is dominated by *TOP_BB or dominates it or this basic block
    is not yet initialized.  Returns true if the occurrence was pushed on
@@ -1132,7 +1241,7 @@ execute_cse_sincos_1 (tree name)
 {
   gimple_stmt_iterator gsi;
   imm_use_iterator use_iter;
-  tree fndecl, res, type;
+  tree fndecl, res, type = NULL_TREE;
   gimple *def_stmt, *use_stmt, *stmt;
   int seen_cos = 0, seen_sin = 0, seen_cexpi = 0;
   auto_vec<gimple *> stmts;
@@ -1140,7 +1249,8 @@ execute_cse_sincos_1 (tree name)
   int i;
   bool cfg_changed = false;
 
-  type = TREE_TYPE (name);
+  name = execute_cse_conv_1 (name);
+
   FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, name)
     {
       if (gimple_code (use_stmt) != GIMPLE_CALL
@@ -1162,9 +1272,21 @@ execute_cse_sincos_1 (tree name)
          break;
 
        default:;
+         continue;
        }
-    }
 
+      tree t = mathfn_built_in_type (gimple_call_combined_fn (use_stmt));
+      if (!type)
+       {
+         type = t;
+         t = TREE_TYPE (name);
+       }
+      /* This checks that NAME has the right type in the first round,
+        and, in subsequent rounds, that the built_in type is the same
+        type, or a compatible type.  */
+      if (type != t && !types_compatible_p (type, t))
+       return false;
+    }
   if (seen_cos + seen_sin + seen_cexpi <= 1)
     return false;
 
@@ -1406,7 +1528,7 @@ powi_as_mults_1 (gimple_stmt_iterator *gsi, location_t loc, tree type,
 /* Convert ARG0**N to a tree of multiplications of ARG0 with itself.
    This function needs to be kept in sync with powi_cost above.  */
 
-static tree
+tree
 powi_as_mults (gimple_stmt_iterator *gsi, location_t loc,
               tree arg0, HOST_WIDE_INT n)
 {
@@ -1415,9 +1537,9 @@ powi_as_mults (gimple_stmt_iterator *gsi, location_t loc,
   tree target;
 
   if (n == 0)
-    return build_real (type, dconst1);
+    return build_one_cst (type);
 
-  memset (cache, 0,  sizeof (cache));
+  memset (cache, 0, sizeof (cache));
   cache[1] = arg0;
 
   result = powi_as_mults_1 (gsi, loc, type, (n < 0) ? -n : n, cache);
@@ -1980,7 +2102,7 @@ gimple_expand_builtin_pow (gimple_stmt_iterator *gsi, location_t loc,
       && !HONOR_SIGNED_ZEROS (mode))
     {
       unsigned int max_depth = speed_p
-                               ? PARAM_VALUE (PARAM_MAX_POW_SQRT_DEPTH)
+                               ? param_max_pow_sqrt_depth
                                : 2;
 
       tree expand_with_sqrts
@@ -2169,12 +2291,14 @@ pass_cse_sincos::execute (function *fun)
                CASE_CFN_COS:
                CASE_CFN_SIN:
                CASE_CFN_CEXPI:
+                 arg = gimple_call_arg (stmt, 0);
                  /* Make sure we have either sincos or cexp.  */
-                 if (!targetm.libc_has_function (function_c99_math_complex)
-                     && !targetm.libc_has_function (function_sincos))
+                 if (!targetm.libc_has_function (function_c99_math_complex,
+                                                 TREE_TYPE (arg))
+                     && !targetm.libc_has_function (function_sincos,
+                                                    TREE_TYPE (arg)))
                    break;
 
-                 arg = gimple_call_arg (stmt, 0);
                  if (TREE_CODE (arg) == SSA_NAME)
                    cfg_changed |= execute_cse_sincos_1 (arg);
                  break;
@@ -2276,6 +2400,8 @@ pass_cse_sincos::execute (function *fun)
 
   statistics_counter_event (fun, "sincos statements inserted",
                            sincos_stats.inserted);
+  statistics_counter_event (fun, "conv statements removed",
+                           sincos_stats.conv_removed);
 
   return cfg_changed ? TODO_cleanup_cfg : 0;
 }
@@ -2483,7 +2609,7 @@ is_copysign_call_with_1 (gimple *call)
 }
 
 /* Try to expand the pattern x * copysign (1, y) into xorsign (x, y).
-   This only happens when the the xorsign optab is defined, if the
+   This only happens when the xorsign optab is defined, if the
    pattern is not a xorsign pattern or if expansion fails FALSE is
    returned, otherwise TRUE is returned.  */
 static bool
@@ -2721,11 +2847,14 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple *stmt,
      multiply-and-accumulate instructions.
 
      If the widened-multiplication result has more than one uses, it is
-     probably wiser not to do the conversion.  */
+     probably wiser not to do the conversion.  Also restrict this operation
+     to single basic block to avoid moving the multiply to a different block
+     with a higher execution frequency.  */
   if (code == PLUS_EXPR
       && (rhs1_code == MULT_EXPR || rhs1_code == WIDEN_MULT_EXPR))
     {
       if (!has_single_use (rhs1)
+         || gimple_bb (rhs1_stmt) != gimple_bb (stmt)
          || !is_widening_mult_p (rhs1_stmt, &type1, &mult_rhs1,
                                  &type2, &mult_rhs2))
        return false;
@@ -2735,6 +2864,7 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple *stmt,
   else if (rhs2_code == MULT_EXPR || rhs2_code == WIDEN_MULT_EXPR)
     {
       if (!has_single_use (rhs2)
+         || gimple_bb (rhs2_stmt) != gimple_bb (stmt)
          || !is_widening_mult_p (rhs2_stmt, &type1, &mult_rhs1,
                                  &type2, &mult_rhs2))
        return false;
@@ -2932,6 +3062,35 @@ convert_mult_to_fma_1 (tree mul_result, tree op1, tree op2)
          fprintf (dump_file, "\n");
        }
 
+      /* If the FMA result is negated in a single use, fold the negation
+        too.  */
+      orig_stmt = gsi_stmt (gsi);
+      use_operand_p use_p;
+      gimple *neg_stmt;
+      if (is_gimple_call (orig_stmt)
+         && gimple_call_internal_p (orig_stmt)
+         && gimple_call_lhs (orig_stmt)
+         && TREE_CODE (gimple_call_lhs (orig_stmt)) == SSA_NAME
+         && single_imm_use (gimple_call_lhs (orig_stmt), &use_p, &neg_stmt)
+         && is_gimple_assign (neg_stmt)
+         && gimple_assign_rhs_code (neg_stmt) == NEGATE_EXPR
+         && !stmt_could_throw_p (cfun, neg_stmt))
+       {
+         gsi = gsi_for_stmt (neg_stmt);
+         if (fold_stmt (&gsi, follow_all_ssa_edges))
+           {
+             if (maybe_clean_or_replace_eh_stmt (neg_stmt, gsi_stmt (gsi)))
+               gcc_unreachable ();
+             update_stmt (gsi_stmt (gsi));
+             if (dump_file && (dump_flags & TDF_DETAILS))
+               {
+                 fprintf (dump_file, "Folded FMA negation ");
+                 print_gimple_stmt (dump_file, gsi_stmt (gsi), 0, TDF_NONE);
+                 fprintf (dump_file, "\n");
+               }
+           }
+       }
+
       widen_mul_stats.fmas_inserted++;
     }
 }
@@ -3044,6 +3203,8 @@ last_fma_candidate_feeds_initial_phi (fma_deferring_state *state,
 /* Combine the multiplication at MUL_STMT with operands MULOP1 and MULOP2
    with uses in additions and subtractions to form fused multiply-add
    operations.  Returns true if successful and MUL_STMT should be removed.
+   If MUL_COND is nonnull, the multiplication in MUL_STMT is conditional
+   on MUL_COND, otherwise it is unconditional.
 
    If STATE indicates that we are deferring FMA transformation, that means
    that we do not produce FMAs for basic blocks which look like:
@@ -3060,7 +3221,7 @@ last_fma_candidate_feeds_initial_phi (fma_deferring_state *state,
 
 static bool
 convert_mult_to_fma (gimple *mul_stmt, tree op1, tree op2,
-                    fma_deferring_state *state)
+                    fma_deferring_state *state, tree mul_cond = NULL_TREE)
 {
   tree mul_result = gimple_get_lhs (mul_stmt);
   tree type = TREE_TYPE (mul_result);
@@ -3091,8 +3252,8 @@ convert_mult_to_fma (gimple *mul_stmt, tree op1, tree op2,
 
   bool check_defer
     = (state->m_deferring_p
-       && (tree_to_shwi (TYPE_SIZE (type))
-          <= PARAM_VALUE (PARAM_AVOID_FMA_MAX_BITS)));
+       && maybe_le (tree_to_poly_int64 (TYPE_SIZE (type)),
+                   param_avoid_fma_max_bits));
   bool defer = check_defer;
   bool seen_negate_p = false;
   /* Make sure that the multiplication statement becomes dead after
@@ -3174,6 +3335,9 @@ convert_mult_to_fma (gimple *mul_stmt, tree op1, tree op2,
          return false;
        }
 
+      if (mul_cond && cond != mul_cond)
+       return false;
+
       if (cond)
        {
          if (cond == result || else_value == result)
@@ -3288,33 +3452,272 @@ convert_mult_to_fma (gimple *mul_stmt, tree op1, tree op2,
 }
 
 
-/* Helper function of match_uaddsub_overflow.  Return 1
+/* Helper function of match_arith_overflow.  For MUL_OVERFLOW, if we have
+   a check for non-zero like:
+   _1 = x_4(D) * y_5(D);
+   *res_7(D) = _1;
+   if (x_4(D) != 0)
+     goto <bb 3>; [50.00%]
+   else
+     goto <bb 4>; [50.00%]
+
+   <bb 3> [local count: 536870913]:
+   _2 = _1 / x_4(D);
+   _9 = _2 != y_5(D);
+   _10 = (int) _9;
+
+   <bb 4> [local count: 1073741824]:
+   # iftmp.0_3 = PHI <_10(3), 0(2)>
+   then in addition to using .MUL_OVERFLOW (x_4(D), y_5(D)) we can also
+   optimize the x_4(D) != 0 condition to 1.  */
+
+static void
+maybe_optimize_guarding_check (vec<gimple *> &mul_stmts, gimple *cond_stmt,
+                              gimple *div_stmt, bool *cfg_changed)
+{
+  basic_block bb = gimple_bb (cond_stmt);
+  if (gimple_bb (div_stmt) != bb || !single_pred_p (bb))
+    return;
+  edge pred_edge = single_pred_edge (bb);
+  basic_block pred_bb = pred_edge->src;
+  if (EDGE_COUNT (pred_bb->succs) != 2)
+    return;
+  edge other_edge = EDGE_SUCC (pred_bb, EDGE_SUCC (pred_bb, 0) == pred_edge);
+  edge other_succ_edge = NULL;
+  if (gimple_code (cond_stmt) == GIMPLE_COND)
+    {
+      if (EDGE_COUNT (bb->succs) != 2)
+       return;
+      other_succ_edge = EDGE_SUCC (bb, 0);
+      if (gimple_cond_code (cond_stmt) == NE_EXPR)
+       {
+         if (other_succ_edge->flags & EDGE_TRUE_VALUE)
+           other_succ_edge = EDGE_SUCC (bb, 1);
+       }
+      else if (other_succ_edge->flags & EDGE_FALSE_VALUE)
+       other_succ_edge = EDGE_SUCC (bb, 0);
+      if (other_edge->dest != other_succ_edge->dest)
+       return;
+    }
+  else if (!single_succ_p (bb) || other_edge->dest != single_succ (bb))
+    return;
+  gimple *zero_cond = last_stmt (pred_bb);
+  if (zero_cond == NULL
+      || gimple_code (zero_cond) != GIMPLE_COND
+      || (gimple_cond_code (zero_cond)
+         != ((pred_edge->flags & EDGE_TRUE_VALUE) ? NE_EXPR : EQ_EXPR))
+      || !integer_zerop (gimple_cond_rhs (zero_cond)))
+    return;
+  tree zero_cond_lhs = gimple_cond_lhs (zero_cond);
+  if (TREE_CODE (zero_cond_lhs) != SSA_NAME)
+    return;
+  if (gimple_assign_rhs2 (div_stmt) != zero_cond_lhs)
+    {
+      /* Allow the divisor to be result of a same precision cast
+        from zero_cond_lhs.  */
+      tree rhs2 = gimple_assign_rhs2 (div_stmt);
+      if (TREE_CODE (rhs2) != SSA_NAME)
+       return;
+      gimple *g = SSA_NAME_DEF_STMT (rhs2);
+      if (!gimple_assign_cast_p (g)
+         || gimple_assign_rhs1 (g) != gimple_cond_lhs (zero_cond)
+         || !INTEGRAL_TYPE_P (TREE_TYPE (zero_cond_lhs))
+         || (TYPE_PRECISION (TREE_TYPE (zero_cond_lhs))
+             != TYPE_PRECISION (TREE_TYPE (rhs2))))
+       return;
+    }
+  gimple_stmt_iterator gsi = gsi_after_labels (bb);
+  mul_stmts.quick_push (div_stmt);
+  if (is_gimple_debug (gsi_stmt (gsi)))
+    gsi_next_nondebug (&gsi);
+  unsigned cast_count = 0;
+  while (gsi_stmt (gsi) != cond_stmt)
+    {
+      /* If original mul_stmt has a single use, allow it in the same bb,
+        we are looking then just at __builtin_mul_overflow_p.
+        Though, in that case the original mul_stmt will be replaced
+        by .MUL_OVERFLOW, REALPART_EXPR and IMAGPART_EXPR stmts.  */
+      gimple *mul_stmt;
+      unsigned int i;
+      bool ok = false;
+      FOR_EACH_VEC_ELT (mul_stmts, i, mul_stmt)
+       {
+         if (gsi_stmt (gsi) == mul_stmt)
+           {
+             ok = true;
+             break;
+           }
+       }
+      if (!ok && gimple_assign_cast_p (gsi_stmt (gsi)) && ++cast_count < 4)
+       ok = true;
+      if (!ok)
+       return;
+      gsi_next_nondebug (&gsi);
+    }
+  if (gimple_code (cond_stmt) == GIMPLE_COND)
+    {
+      basic_block succ_bb = other_edge->dest;
+      for (gphi_iterator gpi = gsi_start_phis (succ_bb); !gsi_end_p (gpi);
+          gsi_next (&gpi))
+       {
+         gphi *phi = gpi.phi ();
+         tree v1 = gimple_phi_arg_def (phi, other_edge->dest_idx);
+         tree v2 = gimple_phi_arg_def (phi, other_succ_edge->dest_idx);
+         if (!operand_equal_p (v1, v2, 0))
+           return;
+       }
+    }
+  else
+    {
+      tree lhs = gimple_assign_lhs (cond_stmt);
+      if (!lhs || !INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
+       return;
+      gsi_next_nondebug (&gsi);
+      if (!gsi_end_p (gsi))
+       {
+         if (gimple_assign_rhs_code (cond_stmt) == COND_EXPR)
+           return;
+         gimple *cast_stmt = gsi_stmt (gsi);
+         if (!gimple_assign_cast_p (cast_stmt))
+           return;
+         tree new_lhs = gimple_assign_lhs (cast_stmt);
+         gsi_next_nondebug (&gsi);
+         if (!gsi_end_p (gsi)
+             || !new_lhs
+             || !INTEGRAL_TYPE_P (TREE_TYPE (new_lhs))
+             || TYPE_PRECISION (TREE_TYPE (new_lhs)) <= 1)
+           return;
+         lhs = new_lhs;
+       }
+      edge succ_edge = single_succ_edge (bb);
+      basic_block succ_bb = succ_edge->dest;
+      gsi = gsi_start_phis (succ_bb);
+      if (gsi_end_p (gsi))
+       return;
+      gphi *phi = as_a <gphi *> (gsi_stmt (gsi));
+      gsi_next (&gsi);
+      if (!gsi_end_p (gsi))
+       return;
+      if (gimple_phi_arg_def (phi, succ_edge->dest_idx) != lhs)
+       return;
+      tree other_val = gimple_phi_arg_def (phi, other_edge->dest_idx);
+      if (gimple_assign_rhs_code (cond_stmt) == COND_EXPR)
+       {
+         tree cond = gimple_assign_rhs1 (cond_stmt);
+         if (TREE_CODE (cond) == NE_EXPR)
+           {
+             if (!operand_equal_p (other_val,
+                                   gimple_assign_rhs3 (cond_stmt), 0))
+               return;
+           }
+         else if (!operand_equal_p (other_val,
+                                    gimple_assign_rhs2 (cond_stmt), 0))
+           return;
+       }
+      else if (gimple_assign_rhs_code (cond_stmt) == NE_EXPR)
+       {
+         if (!integer_zerop (other_val))
+           return;
+       }
+      else if (!integer_onep (other_val))
+       return;
+    }
+  gcond *zero_gcond = as_a <gcond *> (zero_cond);
+  if (pred_edge->flags & EDGE_TRUE_VALUE)
+    gimple_cond_make_true (zero_gcond);
+  else
+    gimple_cond_make_false (zero_gcond);
+  update_stmt (zero_cond);
+  *cfg_changed = true;
+}
+
+/* Helper function for arith_overflow_check_p.  Return true
+   if VAL1 is equal to VAL2 cast to corresponding integral type
+   with other signedness or vice versa.  */
+
+static bool
+arith_cast_equal_p (tree val1, tree val2)
+{
+  if (TREE_CODE (val1) == INTEGER_CST && TREE_CODE (val2) == INTEGER_CST)
+    return wi::eq_p (wi::to_wide (val1), wi::to_wide (val2));
+  else if (TREE_CODE (val1) != SSA_NAME || TREE_CODE (val2) != SSA_NAME)
+    return false;
+  if (gimple_assign_cast_p (SSA_NAME_DEF_STMT (val1))
+      && gimple_assign_rhs1 (SSA_NAME_DEF_STMT (val1)) == val2)
+    return true;
+  if (gimple_assign_cast_p (SSA_NAME_DEF_STMT (val2))
+      && gimple_assign_rhs1 (SSA_NAME_DEF_STMT (val2)) == val1)
+    return true;
+  return false;
+}
+
+/* Helper function of match_arith_overflow.  Return 1
    if USE_STMT is unsigned overflow check ovf != 0 for
    STMT, -1 if USE_STMT is unsigned overflow check ovf == 0
    and 0 otherwise.  */
 
 static int
-uaddsub_overflow_check_p (gimple *stmt, gimple *use_stmt)
+arith_overflow_check_p (gimple *stmt, gimple *cast_stmt, gimple *&use_stmt,
+                       tree maxval, tree *other)
 {
   enum tree_code ccode = ERROR_MARK;
   tree crhs1 = NULL_TREE, crhs2 = NULL_TREE;
-  if (gimple_code (use_stmt) == GIMPLE_COND)
+  enum tree_code code = gimple_assign_rhs_code (stmt);
+  tree lhs = gimple_assign_lhs (cast_stmt ? cast_stmt : stmt);
+  tree rhs1 = gimple_assign_rhs1 (stmt);
+  tree rhs2 = gimple_assign_rhs2 (stmt);
+  tree multop = NULL_TREE, divlhs = NULL_TREE;
+  gimple *cur_use_stmt = use_stmt;
+
+  if (code == MULT_EXPR)
+    {
+      if (!is_gimple_assign (use_stmt))
+       return 0;
+      if (gimple_assign_rhs_code (use_stmt) != TRUNC_DIV_EXPR)
+       return 0;
+      if (gimple_assign_rhs1 (use_stmt) != lhs)
+       return 0;
+      if (cast_stmt)
+       {
+         if (arith_cast_equal_p (gimple_assign_rhs2 (use_stmt), rhs1))
+           multop = rhs2;
+         else if (arith_cast_equal_p (gimple_assign_rhs2 (use_stmt), rhs2))
+           multop = rhs1;
+         else
+           return 0;
+       }
+      else if (gimple_assign_rhs2 (use_stmt) == rhs1)
+       multop = rhs2;
+      else if (operand_equal_p (gimple_assign_rhs2 (use_stmt), rhs2, 0))
+       multop = rhs1;
+      else
+       return 0;
+      if (stmt_ends_bb_p (use_stmt))
+       return 0;
+      divlhs = gimple_assign_lhs (use_stmt);
+      if (!divlhs)
+       return 0;
+      use_operand_p use;
+      if (!single_imm_use (divlhs, &use, &cur_use_stmt))
+       return 0;
+    }
+  if (gimple_code (cur_use_stmt) == GIMPLE_COND)
     {
-      ccode = gimple_cond_code (use_stmt);
-      crhs1 = gimple_cond_lhs (use_stmt);
-      crhs2 = gimple_cond_rhs (use_stmt);
+      ccode = gimple_cond_code (cur_use_stmt);
+      crhs1 = gimple_cond_lhs (cur_use_stmt);
+      crhs2 = gimple_cond_rhs (cur_use_stmt);
     }
-  else if (is_gimple_assign (use_stmt))
+  else if (is_gimple_assign (cur_use_stmt))
     {
-      if (gimple_assign_rhs_class (use_stmt) == GIMPLE_BINARY_RHS)
+      if (gimple_assign_rhs_class (cur_use_stmt) == GIMPLE_BINARY_RHS)
        {
-         ccode = gimple_assign_rhs_code (use_stmt);
-         crhs1 = gimple_assign_rhs1 (use_stmt);
-         crhs2 = gimple_assign_rhs2 (use_stmt);
+         ccode = gimple_assign_rhs_code (cur_use_stmt);
+         crhs1 = gimple_assign_rhs1 (cur_use_stmt);
+         crhs2 = gimple_assign_rhs2 (cur_use_stmt);
        }
-      else if (gimple_assign_rhs_code (use_stmt) == COND_EXPR)
+      else if (gimple_assign_rhs_code (cur_use_stmt) == COND_EXPR)
        {
-         tree cond = gimple_assign_rhs1 (use_stmt);
+         tree cond = gimple_assign_rhs1 (cur_use_stmt);
          if (COMPARISON_CLASS_P (cond))
            {
              ccode = TREE_CODE (cond);
@@ -3333,30 +3736,75 @@ uaddsub_overflow_check_p (gimple *stmt, gimple *use_stmt)
   if (TREE_CODE_CLASS (ccode) != tcc_comparison)
     return 0;
 
-  enum tree_code code = gimple_assign_rhs_code (stmt);
-  tree lhs = gimple_assign_lhs (stmt);
-  tree rhs1 = gimple_assign_rhs1 (stmt);
-  tree rhs2 = gimple_assign_rhs2 (stmt);
-
   switch (ccode)
     {
     case GT_EXPR:
     case LE_EXPR:
+      if (maxval)
+       {
+         /* r = a + b; r > maxval or r <= maxval  */
+         if (crhs1 == lhs
+             && TREE_CODE (crhs2) == INTEGER_CST
+             && tree_int_cst_equal (crhs2, maxval))
+           return ccode == GT_EXPR ? 1 : -1;
+         break;
+       }
       /* r = a - b; r > a or r <= a
         r = a + b; a > r or a <= r or b > r or b <= r.  */
       if ((code == MINUS_EXPR && crhs1 == lhs && crhs2 == rhs1)
          || (code == PLUS_EXPR && (crhs1 == rhs1 || crhs1 == rhs2)
              && crhs2 == lhs))
        return ccode == GT_EXPR ? 1 : -1;
+      /* r = ~a; b > r or b <= r.  */
+      if (code == BIT_NOT_EXPR && crhs2 == lhs)
+       {
+         if (other)
+           *other = crhs1;
+         return ccode == GT_EXPR ? 1 : -1;
+       }
       break;
     case LT_EXPR:
     case GE_EXPR:
+      if (maxval)
+       break;
       /* r = a - b; a < r or a >= r
         r = a + b; r < a or r >= a or r < b or r >= b.  */
       if ((code == MINUS_EXPR && crhs1 == rhs1 && crhs2 == lhs)
          || (code == PLUS_EXPR && crhs1 == lhs
              && (crhs2 == rhs1 || crhs2 == rhs2)))
        return ccode == LT_EXPR ? 1 : -1;
+      /* r = ~a; r < b or r >= b.  */
+      if (code == BIT_NOT_EXPR && crhs1 == lhs)
+       {
+         if (other)
+           *other = crhs2;
+         return ccode == LT_EXPR ? 1 : -1;
+       }
+      break;
+    case EQ_EXPR:
+    case NE_EXPR:
+      /* r = a * b; _1 = r / a; _1 == b
+        r = a * b; _1 = r / b; _1 == a
+        r = a * b; _1 = r / a; _1 != b
+        r = a * b; _1 = r / b; _1 != a.  */
+      if (code == MULT_EXPR)
+       {
+         if (cast_stmt)
+           {
+             if ((crhs1 == divlhs && arith_cast_equal_p (crhs2, multop))
+                 || (crhs2 == divlhs && arith_cast_equal_p (crhs1, multop)))
+               {
+                 use_stmt = cur_use_stmt;
+                 return ccode == NE_EXPR ? 1 : -1;
+               }
+           }
+         else if ((crhs1 == divlhs && operand_equal_p (crhs2, multop, 0))
+                  || (crhs2 == divlhs && crhs1 == multop))
+           {
+             use_stmt = cur_use_stmt;
+             return ccode == NE_EXPR ? 1 : -1;
+           }
+       }
       break;
     default:
       break;
@@ -3368,15 +3816,58 @@ uaddsub_overflow_check_p (gimple *stmt, gimple *use_stmt)
    x = y - z;
    if (x > y)
    where there are other uses of x and replace it with
-   _7 = SUB_OVERFLOW (y, z);
+   _7 = .SUB_OVERFLOW (y, z);
    x = REALPART_EXPR <_7>;
    _8 = IMAGPART_EXPR <_7>;
    if (_8)
-   and similarly for addition.  */
+   and similarly for addition.
+
+   Also recognize:
+   yc = (type) y;
+   zc = (type) z;
+   x = yc + zc;
+   if (x > max)
+   where y and z have unsigned types with maximum max
+   and there are other uses of x and all of those cast x
+   back to that unsigned type and again replace it with
+   _7 = .ADD_OVERFLOW (y, z);
+   _9 = REALPART_EXPR <_7>;
+   _8 = IMAGPART_EXPR <_7>;
+   if (_8)
+   and replace (utype) x with _9.
+
+   Also recognize:
+   x = ~z;
+   if (y > x)
+   and replace it with
+   _7 = .ADD_OVERFLOW (y, z);
+   _8 = IMAGPART_EXPR <_7>;
+   if (_8)
+
+   And also recognize:
+   z = x * y;
+   if (x != 0)
+     goto <bb 3>; [50.00%]
+   else
+     goto <bb 4>; [50.00%]
+
+   <bb 3> [local count: 536870913]:
+   _2 = z / x;
+   _9 = _2 != y;
+   _10 = (int) _9;
+
+   <bb 4> [local count: 1073741824]:
+   # iftmp.0_3 = PHI <_10(3), 0(2)>
+   and replace it with
+   _7 = .MUL_OVERFLOW (x, y);
+   z = IMAGPART_EXPR <_7>;
+   _8 = IMAGPART_EXPR <_7>;
+   _9 = _8 != 0;
+   iftmp.0_3 = (int) _9;  */
 
 static bool
-match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
-                       enum tree_code code)
+match_arith_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
+                     enum tree_code code, bool *cfg_changed)
 {
   tree lhs = gimple_assign_lhs (stmt);
   tree type = TREE_TYPE (lhs);
@@ -3385,58 +3876,382 @@ match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
   bool use_seen = false;
   bool ovf_use_seen = false;
   gimple *use_stmt;
-
-  gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR);
+  gimple *add_stmt = NULL;
+  bool add_first = false;
+  gimple *cond_stmt = NULL;
+  gimple *cast_stmt = NULL;
+  tree cast_lhs = NULL_TREE;
+
+  gcc_checking_assert (code == PLUS_EXPR
+                      || code == MINUS_EXPR
+                      || code == MULT_EXPR
+                      || code == BIT_NOT_EXPR);
   if (!INTEGRAL_TYPE_P (type)
       || !TYPE_UNSIGNED (type)
       || has_zero_uses (lhs)
-      || has_single_use (lhs)
-      || optab_handler (code == PLUS_EXPR ? uaddv4_optab : usubv4_optab,
-                       TYPE_MODE (type)) == CODE_FOR_nothing)
+      || (code != PLUS_EXPR
+         && code != MULT_EXPR
+         && optab_handler (code == MINUS_EXPR ? usubv4_optab : uaddv4_optab,
+                           TYPE_MODE (type)) == CODE_FOR_nothing))
     return false;
 
+  tree rhs1 = gimple_assign_rhs1 (stmt);
+  tree rhs2 = gimple_assign_rhs2 (stmt);
   FOR_EACH_IMM_USE_FAST (use_p, iter, lhs)
     {
       use_stmt = USE_STMT (use_p);
       if (is_gimple_debug (use_stmt))
        continue;
 
-      if (uaddsub_overflow_check_p (stmt, use_stmt))
-       ovf_use_seen = true;
-      else
-       use_seen = true;
+      tree other = NULL_TREE;
+      if (arith_overflow_check_p (stmt, NULL, use_stmt, NULL_TREE, &other))
+       {
+         if (code == BIT_NOT_EXPR)
+           {
+             gcc_assert (other);
+             if (TREE_CODE (other) != SSA_NAME)
+               return false;
+             if (rhs2 == NULL)
+               rhs2 = other;
+             else
+               return false;
+             cond_stmt = use_stmt;
+           }
+         ovf_use_seen = true;
+       }
+      else 
+       {
+         use_seen = true;
+         if (code == MULT_EXPR
+             && cast_stmt == NULL
+             && gimple_assign_cast_p (use_stmt))
+           {
+             cast_lhs = gimple_assign_lhs (use_stmt);
+             if (INTEGRAL_TYPE_P (TREE_TYPE (cast_lhs))
+                 && !TYPE_UNSIGNED (TREE_TYPE (cast_lhs))
+                 && (TYPE_PRECISION (TREE_TYPE (cast_lhs))
+                     == TYPE_PRECISION (TREE_TYPE (lhs))))
+               cast_stmt = use_stmt;
+             else
+               cast_lhs = NULL_TREE;
+           }
+       }
       if (ovf_use_seen && use_seen)
        break;
     }
 
-  if (!ovf_use_seen || !use_seen)
-    return false;
+  if (!ovf_use_seen
+      && code == MULT_EXPR
+      && cast_stmt)
+    {
+      if (TREE_CODE (rhs1) != SSA_NAME
+         || (TREE_CODE (rhs2) != SSA_NAME && TREE_CODE (rhs2) != INTEGER_CST))
+       return false;
+      FOR_EACH_IMM_USE_FAST (use_p, iter, cast_lhs)
+       {
+         use_stmt = USE_STMT (use_p);
+         if (is_gimple_debug (use_stmt))
+           continue;
+
+         if (arith_overflow_check_p (stmt, cast_stmt, use_stmt,
+                                     NULL_TREE, NULL))
+           ovf_use_seen = true;
+       }
+    }
+  else
+    {
+      cast_stmt = NULL;
+      cast_lhs = NULL_TREE;
+    }
+
+  tree maxval = NULL_TREE;
+  if (!ovf_use_seen
+      || (code != MULT_EXPR && (code == BIT_NOT_EXPR ? use_seen : !use_seen))
+      || (code == PLUS_EXPR
+         && optab_handler (uaddv4_optab,
+                           TYPE_MODE (type)) == CODE_FOR_nothing)
+      || (code == MULT_EXPR
+         && optab_handler (cast_stmt ? mulv4_optab : umulv4_optab,
+                           TYPE_MODE (type)) == CODE_FOR_nothing))
+    {
+      if (code != PLUS_EXPR)
+       return false;
+      if (TREE_CODE (rhs1) != SSA_NAME
+         || !gimple_assign_cast_p (SSA_NAME_DEF_STMT (rhs1)))
+       return false;
+      rhs1 = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (rhs1));
+      tree type1 = TREE_TYPE (rhs1);
+      if (!INTEGRAL_TYPE_P (type1)
+         || !TYPE_UNSIGNED (type1)
+         || TYPE_PRECISION (type1) >= TYPE_PRECISION (type)
+         || (TYPE_PRECISION (type1)
+             != GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (type1))))
+       return false;
+      if (TREE_CODE (rhs2) == INTEGER_CST)
+       {
+         if (wi::ne_p (wi::rshift (wi::to_wide (rhs2),
+                                   TYPE_PRECISION (type1),
+                                   UNSIGNED), 0))
+           return false;
+         rhs2 = fold_convert (type1, rhs2);
+       }
+      else
+       {
+         if (TREE_CODE (rhs2) != SSA_NAME
+             || !gimple_assign_cast_p (SSA_NAME_DEF_STMT (rhs2)))
+           return false;
+         rhs2 = gimple_assign_rhs1 (SSA_NAME_DEF_STMT (rhs2));
+         tree type2 = TREE_TYPE (rhs2);
+         if (!INTEGRAL_TYPE_P (type2)
+             || !TYPE_UNSIGNED (type2)
+             || TYPE_PRECISION (type2) >= TYPE_PRECISION (type)
+             || (TYPE_PRECISION (type2)
+                 != GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (type2))))
+           return false;
+       }
+      if (TYPE_PRECISION (type1) >= TYPE_PRECISION (TREE_TYPE (rhs2)))
+       type = type1;
+      else
+       type = TREE_TYPE (rhs2);
+
+      if (TREE_CODE (type) != INTEGER_TYPE
+         || optab_handler (uaddv4_optab,
+                           TYPE_MODE (type)) == CODE_FOR_nothing)
+       return false;
+
+      maxval = wide_int_to_tree (type, wi::max_value (TYPE_PRECISION (type),
+                                                     UNSIGNED));
+      ovf_use_seen = false;
+      use_seen = false;
+      basic_block use_bb = NULL;
+      FOR_EACH_IMM_USE_FAST (use_p, iter, lhs)
+       {
+         use_stmt = USE_STMT (use_p);
+         if (is_gimple_debug (use_stmt))
+           continue;
+
+         if (arith_overflow_check_p (stmt, NULL, use_stmt, maxval, NULL))
+           {
+             ovf_use_seen = true;
+             use_bb = gimple_bb (use_stmt);
+           }
+         else
+           {
+             if (!gimple_assign_cast_p (use_stmt)
+                 || gimple_assign_rhs_code (use_stmt) == VIEW_CONVERT_EXPR)
+               return false;
+             tree use_lhs = gimple_assign_lhs (use_stmt);
+             if (!INTEGRAL_TYPE_P (TREE_TYPE (use_lhs))
+                 || (TYPE_PRECISION (TREE_TYPE (use_lhs))
+                     > TYPE_PRECISION (type)))
+               return false;
+             use_seen = true;
+           }
+       }
+      if (!ovf_use_seen)
+       return false;
+      if (!useless_type_conversion_p (type, TREE_TYPE (rhs1)))
+       {
+         if (!use_seen)
+           return false;
+         tree new_rhs1 = make_ssa_name (type);
+         gimple *g = gimple_build_assign (new_rhs1, NOP_EXPR, rhs1);
+         gsi_insert_before (gsi, g, GSI_SAME_STMT);
+         rhs1 = new_rhs1;
+       }
+      else if (!useless_type_conversion_p (type, TREE_TYPE (rhs2)))
+       {
+         if (!use_seen)
+           return false;
+         tree new_rhs2 = make_ssa_name (type);
+         gimple *g = gimple_build_assign (new_rhs2, NOP_EXPR, rhs2);
+         gsi_insert_before (gsi, g, GSI_SAME_STMT);
+         rhs2 = new_rhs2;
+       }
+      else if (!use_seen)
+       {
+         /* If there are no uses of the wider addition, check if
+            forwprop has not created a narrower addition.
+            Require it to be in the same bb as the overflow check.  */
+         FOR_EACH_IMM_USE_FAST (use_p, iter, rhs1)
+           {
+             use_stmt = USE_STMT (use_p);
+             if (is_gimple_debug (use_stmt))
+               continue;
+
+             if (use_stmt == stmt)
+               continue;
+
+             if (!is_gimple_assign (use_stmt)
+                 || gimple_bb (use_stmt) != use_bb
+                 || gimple_assign_rhs_code (use_stmt) != PLUS_EXPR)
+               continue;
+
+             if (gimple_assign_rhs1 (use_stmt) == rhs1)
+               {
+                 if (!operand_equal_p (gimple_assign_rhs2 (use_stmt),
+                                       rhs2, 0))
+                   continue;
+               }
+             else if (gimple_assign_rhs2 (use_stmt) == rhs1)
+               {
+                 if (gimple_assign_rhs1 (use_stmt) != rhs2)
+                   continue;
+               }
+             else
+               continue;
 
+             add_stmt = use_stmt;
+             break;
+           }
+         if (add_stmt == NULL)
+           return false;
+
+         /* If stmt and add_stmt are in the same bb, we need to find out
+            which one is earlier.  If they are in different bbs, we've
+            checked add_stmt is in the same bb as one of the uses of the
+            stmt lhs, so stmt needs to dominate add_stmt too.  */
+         if (gimple_bb (stmt) == gimple_bb (add_stmt))
+           {
+             gimple_stmt_iterator gsif = *gsi;
+             gimple_stmt_iterator gsib = *gsi;
+             int i;
+             /* Search both forward and backward from stmt and have a small
+                upper bound.  */
+             for (i = 0; i < 128; i++)
+               {
+                 if (!gsi_end_p (gsib))
+                   {
+                     gsi_prev_nondebug (&gsib);
+                     if (gsi_stmt (gsib) == add_stmt)
+                       {
+                         add_first = true;
+                         break;
+                       }
+                   }
+                 else if (gsi_end_p (gsif))
+                   break;
+                 if (!gsi_end_p (gsif))
+                   {
+                     gsi_next_nondebug (&gsif);
+                     if (gsi_stmt (gsif) == add_stmt)
+                       break;
+                   }
+               }
+             if (i == 128)
+               return false;
+             if (add_first)
+               *gsi = gsi_for_stmt (add_stmt);
+           }
+       }
+    }
+
+  if (code == BIT_NOT_EXPR)
+    *gsi = gsi_for_stmt (cond_stmt);
+
+  auto_vec<gimple *, 8> mul_stmts;
+  if (code == MULT_EXPR && cast_stmt)
+    {
+      type = TREE_TYPE (cast_lhs);
+      gimple *g = SSA_NAME_DEF_STMT (rhs1);
+      if (gimple_assign_cast_p (g)
+         && useless_type_conversion_p (type,
+                                       TREE_TYPE (gimple_assign_rhs1 (g)))
+         && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs1 (g)))
+       rhs1 = gimple_assign_rhs1 (g);
+      else
+       {
+         g = gimple_build_assign (make_ssa_name (type), NOP_EXPR, rhs1);
+         gsi_insert_before (gsi, g, GSI_SAME_STMT);
+         rhs1 = gimple_assign_lhs (g);
+         mul_stmts.quick_push (g);
+       }
+      if (TREE_CODE (rhs2) == INTEGER_CST)
+       rhs2 = fold_convert (type, rhs2);
+      else
+       {
+         g = SSA_NAME_DEF_STMT (rhs2);
+         if (gimple_assign_cast_p (g)
+             && useless_type_conversion_p (type,
+                                           TREE_TYPE (gimple_assign_rhs1 (g)))
+             && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs1 (g)))
+           rhs2 = gimple_assign_rhs1 (g);
+         else
+           {
+             g = gimple_build_assign (make_ssa_name (type), NOP_EXPR, rhs2);
+             gsi_insert_before (gsi, g, GSI_SAME_STMT);
+             rhs2 = gimple_assign_lhs (g);
+             mul_stmts.quick_push (g);
+           }
+       }
+    }
   tree ctype = build_complex_type (type);
-  tree rhs1 = gimple_assign_rhs1 (stmt);
-  tree rhs2 = gimple_assign_rhs2 (stmt);
-  gcall *g = gimple_build_call_internal (code == PLUS_EXPR
+  gcall *g = gimple_build_call_internal (code == MULT_EXPR
+                                        ? IFN_MUL_OVERFLOW
+                                        : code != MINUS_EXPR
                                         ? IFN_ADD_OVERFLOW : IFN_SUB_OVERFLOW,
                                         2, rhs1, rhs2);
   tree ctmp = make_ssa_name (ctype);
   gimple_call_set_lhs (g, ctmp);
   gsi_insert_before (gsi, g, GSI_SAME_STMT);
-  gassign *g2 = gimple_build_assign (lhs, REALPART_EXPR,
-                                    build1 (REALPART_EXPR, type, ctmp));
-  gsi_replace (gsi, g2, true);
+  tree new_lhs = (maxval || cast_stmt) ? make_ssa_name (type) : lhs;
+  gassign *g2;
+  if (code != BIT_NOT_EXPR)
+    {
+      g2 = gimple_build_assign (new_lhs, REALPART_EXPR,
+                               build1 (REALPART_EXPR, type, ctmp));
+      if (maxval || cast_stmt)
+       {
+         gsi_insert_before (gsi, g2, GSI_SAME_STMT);
+         if (add_first)
+           *gsi = gsi_for_stmt (stmt);
+       }
+      else
+       gsi_replace (gsi, g2, true);
+      if (code == MULT_EXPR)
+       {
+         mul_stmts.quick_push (g);
+         mul_stmts.quick_push (g2);
+         if (cast_stmt)
+           {
+             g2 = gimple_build_assign (lhs, NOP_EXPR, new_lhs);
+             gsi_replace (gsi, g2, true);
+             mul_stmts.quick_push (g2);
+           }
+       }
+    }
   tree ovf = make_ssa_name (type);
   g2 = gimple_build_assign (ovf, IMAGPART_EXPR,
                            build1 (IMAGPART_EXPR, type, ctmp));
-  gsi_insert_after (gsi, g2, GSI_NEW_STMT);
+  if (code != BIT_NOT_EXPR)
+    gsi_insert_after (gsi, g2, GSI_NEW_STMT);
+  else
+    gsi_insert_before (gsi, g2, GSI_SAME_STMT);
+  if (code == MULT_EXPR)
+    mul_stmts.quick_push (g2);
 
-  FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
+  FOR_EACH_IMM_USE_STMT (use_stmt, iter, cast_lhs ? cast_lhs : lhs)
     {
       if (is_gimple_debug (use_stmt))
        continue;
 
-      int ovf_use = uaddsub_overflow_check_p (stmt, use_stmt);
+      gimple *orig_use_stmt = use_stmt;
+      int ovf_use = arith_overflow_check_p (stmt, cast_stmt, use_stmt,
+                                           maxval, NULL);
       if (ovf_use == 0)
-       continue;
+       {
+         gcc_assert (code != BIT_NOT_EXPR);
+         if (maxval)
+           {
+             tree use_lhs = gimple_assign_lhs (use_stmt);
+             gimple_assign_set_rhs1 (use_stmt, new_lhs);
+             if (useless_type_conversion_p (TREE_TYPE (use_lhs),
+                                            TREE_TYPE (new_lhs)))
+               gimple_assign_set_rhs_code (use_stmt, SSA_NAME);
+             update_stmt (use_stmt);
+           }
+         continue;
+       }
       if (gimple_code (use_stmt) == GIMPLE_COND)
        {
          gcond *cond_stmt = as_a <gcond *> (use_stmt);
@@ -3465,8 +4280,35 @@ match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
            }
        }
       update_stmt (use_stmt);
+      if (code == MULT_EXPR && use_stmt != orig_use_stmt)
+       {
+         gimple_stmt_iterator gsi2 = gsi_for_stmt (orig_use_stmt);
+         maybe_optimize_guarding_check (mul_stmts, use_stmt, orig_use_stmt,
+                                        cfg_changed);
+         gsi_remove (&gsi2, true);
+         release_ssa_name (gimple_assign_lhs (orig_use_stmt));
+       }
     }
-  return true;
+  if (maxval)
+    {
+      gimple_stmt_iterator gsi2 = gsi_for_stmt (stmt);
+      gsi_remove (&gsi2, true);
+      if (add_stmt)
+       {
+         gimple *g = gimple_build_assign (gimple_assign_lhs (add_stmt),
+                                          new_lhs);
+         gsi2 = gsi_for_stmt (add_stmt);
+         gsi_replace (&gsi2, g, true);
+       }
+    }
+  else if (code == BIT_NOT_EXPR)
+    {
+      *gsi = gsi_for_stmt (stmt);
+      gsi_remove (gsi, true);
+      release_ssa_name (lhs);
+      return true;
+    }
+  return false;
 }
 
 /* Return true if target has support for divmod.  */
@@ -3520,9 +4362,24 @@ divmod_candidate_p (gassign *stmt)
 
   /* Disable the transform if either is a constant, since division-by-constant
      may have specialized expansion.  */
-  if (CONSTANT_CLASS_P (op1) || CONSTANT_CLASS_P (op2))
+  if (CONSTANT_CLASS_P (op1))
     return false;
 
+  if (CONSTANT_CLASS_P (op2))
+    {
+      if (integer_pow2p (op2))
+       return false;
+
+      if (TYPE_PRECISION (type) <= HOST_BITS_PER_WIDE_INT
+         && TYPE_PRECISION (type) <= BITS_PER_WORD)
+       return false;
+
+      /* If the divisor is not power of 2 and the precision wider than
+        HWI, expand_divmod punts on that, so in that case it is better
+        to use divmod optab or libfunc.  Similarly if choose_multiplier
+        might need pre/post shifts of BITS_PER_WORD or more.  */
+    }
+
   /* Exclude the case where TYPE_OVERFLOW_TRAPS (type) as that should
      expand using the [su]divv optabs.  */
   if (TYPE_OVERFLOW_TRAPS (type))
@@ -3744,7 +4601,7 @@ math_opts_dom_walker::after_dom_children (basic_block bb)
 {
   gimple_stmt_iterator gsi;
 
-  fma_deferring_state fma_state (PARAM_VALUE (PARAM_AVOID_FMA_MAX_BITS) > 0);
+  fma_deferring_state fma_state (param_avoid_fma_max_bits > 0);
 
   for (gsi = gsi_after_labels (bb); !gsi_end_p (gsi);)
     {
@@ -3768,12 +4625,18 @@ math_opts_dom_walker::after_dom_children (basic_block bb)
                  release_defs (stmt);
                  continue;
                }
+             match_arith_overflow (&gsi, stmt, code, m_cfg_changed_p);
              break;
 
            case PLUS_EXPR:
            case MINUS_EXPR:
              if (!convert_plusminus_to_widen (&gsi, stmt, code))
-               match_uaddsub_overflow (&gsi, stmt, code);
+               match_arith_overflow (&gsi, stmt, code, m_cfg_changed_p);
+             break;
+
+           case BIT_NOT_EXPR:
+             if (match_arith_overflow (&gsi, stmt, code, m_cfg_changed_p))
+               continue;
              break;
 
            case TRUNC_MOD_EXPR:
@@ -3785,38 +4648,48 @@ math_opts_dom_walker::after_dom_children (basic_block bb)
        }
       else if (is_gimple_call (stmt))
        {
-         tree fndecl = gimple_call_fndecl (stmt);
-         if (fndecl && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
+         switch (gimple_call_combined_fn (stmt))
            {
-             switch (DECL_FUNCTION_CODE (fndecl))
+           CASE_CFN_POW:
+             if (gimple_call_lhs (stmt)
+                 && TREE_CODE (gimple_call_arg (stmt, 1)) == REAL_CST
+                 && real_equal (&TREE_REAL_CST (gimple_call_arg (stmt, 1)),
+                                &dconst2)
+                 && convert_mult_to_fma (stmt,
+                                         gimple_call_arg (stmt, 0),
+                                         gimple_call_arg (stmt, 0),
+                                         &fma_state))
                {
-               case BUILT_IN_POWF:
-               case BUILT_IN_POW:
-               case BUILT_IN_POWL:
-                 if (gimple_call_lhs (stmt)
-                     && TREE_CODE (gimple_call_arg (stmt, 1)) == REAL_CST
-                     && real_equal
-                     (&TREE_REAL_CST (gimple_call_arg (stmt, 1)),
-                      &dconst2)
-                     && convert_mult_to_fma (stmt,
-                                             gimple_call_arg (stmt, 0),
-                                             gimple_call_arg (stmt, 0),
-                                             &fma_state))
-                   {
-                     unlink_stmt_vdef (stmt);
-                     if (gsi_remove (&gsi, true)
-                         && gimple_purge_dead_eh_edges (bb))
-                       *m_cfg_changed_p = true;
-                     release_defs (stmt);
-                     continue;
-                   }
-                 break;
+                 unlink_stmt_vdef (stmt);
+                 if (gsi_remove (&gsi, true)
+                     && gimple_purge_dead_eh_edges (bb))
+                   *m_cfg_changed_p = true;
+                 release_defs (stmt);
+                 continue;
+               }
+             break;
 
-               default:;
+           case CFN_COND_MUL:
+             if (convert_mult_to_fma (stmt,
+                                      gimple_call_arg (stmt, 1),
+                                      gimple_call_arg (stmt, 2),
+                                      &fma_state,
+                                      gimple_call_arg (stmt, 0)))
+
+               {
+                 gsi_remove (&gsi, true);
+                 release_defs (stmt);
+                 continue;
                }
+             break;
+
+           case CFN_LAST:
+             cancel_fma_deferring (&fma_state);
+             break;
+
+           default:
+             break;
            }
-         else
-           cancel_fma_deferring (&fma_state);
        }
       gsi_next (&gsi);
     }
@@ -3840,7 +4713,7 @@ pass_optimize_widening_mul::execute (function *fun)
 
   memset (&widen_mul_stats, 0, sizeof (widen_mul_stats));
   calculate_dominance_info (CDI_DOMINATORS);
-  renumber_gimple_stmt_uids ();
+  renumber_gimple_stmt_uids (cfun);
 
   math_opts_dom_walker (&cfg_changed).walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));