alias.c: Reorder #include statements and remove duplicates.
[platform/upstream/gcc.git] / gcc / tree-ssa-forwprop.c
index b6c5654..491178d 100644 (file)
@@ -1,6 +1,5 @@
 /* Forward propagation of expressions for single use variables.
-   Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012
-   Free Software Foundation, Inc.
+   Copyright (C) 2004-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -21,20 +20,46 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
+#include "rtl.h"
 #include "tree.h"
+#include "gimple.h"
+#include "cfghooks.h"
+#include "tree-pass.h"
 #include "tm_p.h"
-#include "basic-block.h"
+#include "ssa.h"
+#include "expmed.h"
+#include "optabs-query.h"
+#include "insn-config.h"
+#include "emit-rtl.h"
 #include "gimple-pretty-print.h"
-#include "tree-flow.h"
-#include "tree-pass.h"
-#include "langhooks.h"
+#include "diagnostic.h"
+#include "alias.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "tree-eh.h"
+#include "gimplify.h"
+#include "gimple-iterator.h"
+#include "gimplify-me.h"
+#include "tree-cfg.h"
 #include "flags.h"
-#include "gimple.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "varasm.h"
+#include "stmt.h"
 #include "expr.h"
+#include "tree-dfa.h"
+#include "langhooks.h"
 #include "cfgloop.h"
-#include "optabs.h"
 #include "tree-ssa-propagate.h"
+#include "tree-ssa-dom.h"
+#include "builtins.h"
+#include "tree-cfgcleanup.h"
+#include "tree-into-ssa.h"
+#include "cfganal.h"
 
 /* This pass propagates the RHS of assignment statements into use
    sites of the LHS of the assignment.  It's basically a specialized
@@ -162,45 +187,44 @@ along with GCC; see the file COPYING3.  If not see
 
    This will (of course) be extended as other needs arise.  */
 
-static bool forward_propagate_addr_expr (tree name, tree rhs);
+static bool forward_propagate_addr_expr (tree, tree, bool);
 
 /* Set to true if we delete dead edges during the optimization.  */
 static bool cfg_changed;
 
-static tree rhs_to_tree (tree type, gimple stmt);
+static tree rhs_to_tree (tree type, gimple *stmt);
 
-/* Get the next statement we can propagate NAME's value into skipping
-   trivial copies.  Returns the statement that is suitable as a
-   propagation destination or NULL_TREE if there is no such one.
-   This only returns destinations in a single-use chain.  FINAL_NAME_P
-   if non-NULL is written to the ssa name that represents the use.  */
+static bitmap to_purge;
 
-static gimple
-get_prop_dest_stmt (tree name, tree *final_name_p)
-{
-  use_operand_p use;
-  gimple use_stmt;
+/* Const-and-copy lattice.  */
+static vec<tree> lattice;
 
-  do {
-    /* If name has multiple uses, bail out.  */
-    if (!single_imm_use (name, &use, &use_stmt))
-      return NULL;
-
-    /* If this is not a trivial copy, we found it.  */
-    if (!gimple_assign_ssa_name_copy_p (use_stmt)
-       || gimple_assign_rhs1 (use_stmt) != name)
-      break;
-
-    /* Continue searching uses of the copy destination.  */
-    name = gimple_assign_lhs (use_stmt);
-  } while (1);
-
-  if (final_name_p)
-    *final_name_p = name;
+/* Set the lattice entry for NAME to VAL.  */
+static void
+fwprop_set_lattice_val (tree name, tree val)
+{
+  if (TREE_CODE (name) == SSA_NAME)
+    {
+      if (SSA_NAME_VERSION (name) >= lattice.length ())
+       {
+         lattice.reserve (num_ssa_names - lattice.length ());
+         lattice.quick_grow_cleared (num_ssa_names);
+       }
+      lattice[SSA_NAME_VERSION (name)] = val;
+    }
+}
 
-  return use_stmt;
+/* Invalidate the lattice entry for NAME, done when releasing SSA names.  */
+static void
+fwprop_invalidate_lattice (tree name)
+{
+  if (name
+      && TREE_CODE (name) == SSA_NAME
+      && SSA_NAME_VERSION (name) < lattice.length ())
+    lattice[SSA_NAME_VERSION (name)] = NULL_TREE;
 }
 
+
 /* Get the statement we can propagate from into NAME skipping
    trivial copies.  Returns the statement which defines the
    propagation source or NULL_TREE if there is no such one.
@@ -209,13 +233,13 @@ get_prop_dest_stmt (tree name, tree *final_name_p)
    it is set to whether the chain to NAME is a single use chain
    or not.  SINGLE_USE_P is not written to if SINGLE_USE_ONLY is set.  */
 
-static gimple
+static gimple *
 get_prop_source_stmt (tree name, bool single_use_only, bool *single_use_p)
 {
   bool single_use = true;
 
   do {
-    gimple def_stmt = SSA_NAME_DEF_STMT (name);
+    gimple *def_stmt = SSA_NAME_DEF_STMT (name);
 
     if (!has_single_use (name))
       {
@@ -245,7 +269,7 @@ get_prop_source_stmt (tree name, bool single_use_only, bool *single_use_p)
    propagation source.  Returns true if so, otherwise false.  */
 
 static bool
-can_propagate_from (gimple def_stmt)
+can_propagate_from (gimple *def_stmt)
 {
   gcc_assert (is_gimple_assign (def_stmt));
 
@@ -293,7 +317,7 @@ static bool
 remove_prop_source_from_use (tree name)
 {
   gimple_stmt_iterator gsi;
-  gimple stmt;
+  gimple *stmt;
   bool cfg_changed = false;
 
   do {
@@ -313,7 +337,8 @@ remove_prop_source_from_use (tree name)
     gsi = gsi_for_stmt (stmt);
     unlink_stmt_vdef (stmt);
     if (gsi_remove (&gsi, true))
-      cfg_changed |= gimple_purge_dead_eh_edges (bb);
+      bitmap_set_bit (to_purge, bb->index);
+    fwprop_invalidate_lattice (gimple_get_lhs (stmt));
     release_defs (stmt);
 
     name = is_gimple_assign (stmt) ? gimple_assign_rhs1 (stmt) : NULL_TREE;
@@ -322,7 +347,7 @@ remove_prop_source_from_use (tree name)
   return cfg_changed;
 }
 
-/* Return the rhs of a gimple_assign STMT in a form of a single tree,
+/* Return the rhs of a gassign *STMT in a form of a single tree,
    converted to type TYPE.
 
    This should disappear, but is needed so we can combine expressions and use
@@ -330,7 +355,7 @@ remove_prop_source_from_use (tree name)
    routines that deal with gimple exclusively . */
 
 static tree
-rhs_to_tree (tree type, gimple stmt)
+rhs_to_tree (tree type, gimple *stmt)
 {
   location_t loc = gimple_location (stmt);
   enum tree_code code = gimple_assign_rhs_code (stmt);
@@ -356,7 +381,7 @@ rhs_to_tree (tree type, gimple stmt)
    considered simplified.  */
 
 static tree
-combine_cond_expr_cond (gimple stmt, enum tree_code code, tree type,
+combine_cond_expr_cond (gimple *stmt, enum tree_code code, tree type,
                        tree op0, tree op1, bool invariant_only)
 {
   tree t;
@@ -394,7 +419,7 @@ combine_cond_expr_cond (gimple stmt, enum tree_code code, tree type,
    were no simplifying combines.  */
 
 static tree
-forward_propagate_into_comparison_1 (gimple stmt,
+forward_propagate_into_comparison_1 (gimple *stmt,
                                     enum tree_code code, tree type,
                                     tree op0, tree op1)
 {
@@ -406,12 +431,24 @@ forward_propagate_into_comparison_1 (gimple stmt,
      simplify comparisons against constants.  */
   if (TREE_CODE (op0) == SSA_NAME)
     {
-      gimple def_stmt = get_prop_source_stmt (op0, false, &single_use0_p);
+      gimple *def_stmt = get_prop_source_stmt (op0, false, &single_use0_p);
       if (def_stmt && can_propagate_from (def_stmt))
        {
+         enum tree_code def_code = gimple_assign_rhs_code (def_stmt);
+         bool invariant_only_p = !single_use0_p;
+
          rhs0 = rhs_to_tree (TREE_TYPE (op1), def_stmt);
+
+         /* Always combine comparisons or conversions from booleans.  */
+         if (TREE_CODE (op1) == INTEGER_CST
+             && ((CONVERT_EXPR_CODE_P (def_code)
+                  && TREE_CODE (TREE_TYPE (TREE_OPERAND (rhs0, 0)))
+                     == BOOLEAN_TYPE)
+                 || TREE_CODE_CLASS (def_code) == tcc_comparison))
+           invariant_only_p = false;
+
          tmp = combine_cond_expr_cond (stmt, code, type,
-                                       rhs0, op1, !single_use0_p);
+                                       rhs0, op1, invariant_only_p);
          if (tmp)
            return tmp;
        }
@@ -420,7 +457,7 @@ forward_propagate_into_comparison_1 (gimple stmt,
   /* If that wasn't successful, try the second operand.  */
   if (TREE_CODE (op1) == SSA_NAME)
     {
-      gimple def_stmt = get_prop_source_stmt (op1, false, &single_use1_p);
+      gimple *def_stmt = get_prop_source_stmt (op1, false, &single_use1_p);
       if (def_stmt && can_propagate_from (def_stmt))
        {
          rhs1 = rhs_to_tree (TREE_TYPE (op0), def_stmt);
@@ -449,7 +486,7 @@ forward_propagate_into_comparison_1 (gimple stmt,
 static int 
 forward_propagate_into_comparison (gimple_stmt_iterator *gsi)
 {
-  gimple stmt = gsi_stmt (*gsi);
+  gimple *stmt = gsi_stmt (*gsi);
   tree tmp;
   bool cfg_changed = false;
   tree type = TREE_TYPE (gimple_assign_lhs (stmt));
@@ -484,7 +521,7 @@ forward_propagate_into_comparison (gimple_stmt_iterator *gsi)
    This must be kept in sync with forward_propagate_into_cond.  */
 
 static int
-forward_propagate_into_gimple_cond (gimple stmt)
+forward_propagate_into_gimple_cond (gcond *stmt)
 {
   tree tmp;
   enum tree_code code = gimple_cond_code (stmt);
@@ -548,10 +585,10 @@ forward_propagate_into_gimple_cond (gimple stmt)
 static bool
 forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
 {
-  gimple stmt = gsi_stmt (*gsi_p);
+  gimple *stmt = gsi_stmt (*gsi_p);
   tree tmp = NULL_TREE;
   tree cond = gimple_assign_rhs1 (stmt);
-  bool swap = false;
+  enum tree_code code = gimple_assign_rhs_code (stmt);
 
   /* We can do tree combining on SSA_NAME and comparison expressions.  */
   if (COMPARISON_CLASS_P (cond))
@@ -561,27 +598,19 @@ forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
                                               TREE_OPERAND (cond, 1));
   else if (TREE_CODE (cond) == SSA_NAME)
     {
-      enum tree_code code;
+      enum tree_code def_code;
       tree name = cond;
-      gimple def_stmt = get_prop_source_stmt (name, true, NULL);
+      gimple *def_stmt = get_prop_source_stmt (name, true, NULL);
       if (!def_stmt || !can_propagate_from (def_stmt))
        return 0;
 
-      code = gimple_assign_rhs_code (def_stmt);
-      if (TREE_CODE_CLASS (code) == tcc_comparison)
+      def_code = gimple_assign_rhs_code (def_stmt);
+      if (TREE_CODE_CLASS (def_code) == tcc_comparison)
        tmp = fold_build2_loc (gimple_location (def_stmt),
-                              code,
+                              def_code,
                               TREE_TYPE (cond),
                               gimple_assign_rhs1 (def_stmt),
                               gimple_assign_rhs2 (def_stmt));
-      else if ((code == BIT_NOT_EXPR
-               && TYPE_PRECISION (TREE_TYPE (cond)) == 1)
-              || (code == BIT_XOR_EXPR
-                  && integer_onep (gimple_assign_rhs2 (def_stmt))))
-       {
-         tmp = gimple_assign_rhs1 (def_stmt);
-         swap = true;
-       }
     }
 
   if (tmp
@@ -596,20 +625,13 @@ forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
          fprintf (dump_file, "'\n");
        }
 
-      if (integer_onep (tmp))
+      if ((code == VEC_COND_EXPR) ? integer_all_onesp (tmp)
+                                 : integer_onep (tmp))
        gimple_assign_set_rhs_from_tree (gsi_p, gimple_assign_rhs2 (stmt));
       else if (integer_zerop (tmp))
        gimple_assign_set_rhs_from_tree (gsi_p, gimple_assign_rhs3 (stmt));
       else
-       {
-         gimple_assign_set_rhs1 (stmt, unshare_expr (tmp));
-         if (swap)
-           {
-             tree t = gimple_assign_rhs2 (stmt);
-             gimple_assign_set_rhs2 (stmt, gimple_assign_rhs3 (stmt));
-             gimple_assign_set_rhs3 (stmt, t);
-           }
-       }
+       gimple_assign_set_rhs1 (stmt, unshare_expr (tmp));
       stmt = gsi_stmt (*gsi_p);
       update_stmt (stmt);
 
@@ -619,68 +641,15 @@ forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
   return 0;
 }
 
-/* Propagate from the ssa name definition statements of COND_EXPR
-   values in the rhs of statement STMT into the conditional arms
-   if that simplifies it.
-   Returns true if the stmt was changed.  */
-
-static bool
-combine_cond_exprs (gimple_stmt_iterator *gsi_p)
-{
-  gimple stmt = gsi_stmt (*gsi_p);
-  tree cond, val1, val2;
-  bool changed = false;
-
-  cond = gimple_assign_rhs1 (stmt);
-  val1 = gimple_assign_rhs2 (stmt);
-  if (TREE_CODE (val1) == SSA_NAME)
-    {
-      gimple def_stmt = SSA_NAME_DEF_STMT (val1);
-      if (is_gimple_assign (def_stmt)
-         && gimple_assign_rhs_code (def_stmt) == gimple_assign_rhs_code (stmt)
-         && operand_equal_p (gimple_assign_rhs1 (def_stmt), cond, 0))
-       {
-         val1 = unshare_expr (gimple_assign_rhs2 (def_stmt));
-         gimple_assign_set_rhs2 (stmt, val1);
-         changed = true;
-       }
-    }
-  val2 = gimple_assign_rhs3 (stmt);
-  if (TREE_CODE (val2) == SSA_NAME)
-    {
-      gimple def_stmt = SSA_NAME_DEF_STMT (val2);
-      if (is_gimple_assign (def_stmt)
-         && gimple_assign_rhs_code (def_stmt) == gimple_assign_rhs_code (stmt)
-         && operand_equal_p (gimple_assign_rhs1 (def_stmt), cond, 0))
-       {
-         val2 = unshare_expr (gimple_assign_rhs3 (def_stmt));
-         gimple_assign_set_rhs3 (stmt, val2);
-         changed = true;
-       }
-    }
-  if (operand_equal_p (val1, val2, 0))
-    {
-      gimple_assign_set_rhs_from_tree (gsi_p, val1);
-      stmt = gsi_stmt (*gsi_p);
-      changed = true;
-    }
-
-  if (changed)
-    update_stmt (stmt);
-
-  return changed;
-}
-
 /* We've just substituted an ADDR_EXPR into stmt.  Update all the
    relevant data structures to match.  */
 
 static void
-tidy_after_forward_propagate_addr (gimple stmt)
+tidy_after_forward_propagate_addr (gimple *stmt)
 {
   /* We may have turned a trapping insn into a non-trapping insn.  */
-  if (maybe_clean_or_replace_eh_stmt (stmt, stmt)
-      && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
-    cfg_changed = true;
+  if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
+    bitmap_set_bit (to_purge, gimple_bb (stmt)->index);
 
   if (TREE_CODE (gimple_assign_rhs1 (stmt)) == ADDR_EXPR)
      recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt));
@@ -702,7 +671,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
                               bool single_use_p)
 {
   tree lhs, rhs, rhs2, array_ref;
-  gimple use_stmt = gsi_stmt (*use_stmt_gsi);
+  gimple *use_stmt = gsi_stmt (*use_stmt_gsi);
   enum tree_code rhs_code;
   bool res = true;
 
@@ -712,36 +681,45 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
   rhs_code = gimple_assign_rhs_code (use_stmt);
   rhs = gimple_assign_rhs1 (use_stmt);
 
-  /* Trivial cases.  The use statement could be a trivial copy or a
-     useless conversion.  Recurse to the uses of the lhs as copyprop does
-     not copy through different variant pointers and FRE does not catch
-     all useless conversions.  Treat the case of a single-use name and
+  /* Do not perform copy-propagation but recurse through copy chains.  */
+  if (TREE_CODE (lhs) == SSA_NAME
+      && rhs_code == SSA_NAME)
+    return forward_propagate_addr_expr (lhs, def_rhs, single_use_p);
+
+  /* The use statement could be a conversion.  Recurse to the uses of the
+     lhs as copyprop does not copy through pointer to integer to pointer
+     conversions and FRE does not catch all cases either.
+     Treat the case of a single-use name and
      a conversion to def_rhs type separate, though.  */
   if (TREE_CODE (lhs) == SSA_NAME
-      && ((rhs_code == SSA_NAME && rhs == name)
-         || CONVERT_EXPR_CODE_P (rhs_code)))
+      && CONVERT_EXPR_CODE_P (rhs_code))
     {
-      /* Only recurse if we don't deal with a single use or we cannot
-        do the propagation to the current statement.  In particular
-        we can end up with a conversion needed for a non-invariant
-        address which we cannot do in a single statement.  */
-      if (!single_use_p
-         || (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (def_rhs))
-             && (!is_gimple_min_invariant (def_rhs)
-                 || (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
-                     && POINTER_TYPE_P (TREE_TYPE (def_rhs))
-                     && (TYPE_PRECISION (TREE_TYPE (lhs))
-                         > TYPE_PRECISION (TREE_TYPE (def_rhs)))))))
-       return forward_propagate_addr_expr (lhs, def_rhs);
-
-      gimple_assign_set_rhs1 (use_stmt, unshare_expr (def_rhs));
-      if (useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (def_rhs)))
-       gimple_assign_set_rhs_code (use_stmt, TREE_CODE (def_rhs));
-      else
-       gimple_assign_set_rhs_code (use_stmt, NOP_EXPR);
-      return true;
+      /* If there is a point in a conversion chain where the types match
+         so we can remove a conversion re-materialize the address here
+        and stop.  */
+      if (single_use_p
+         && useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (def_rhs)))
+       {
+         gimple_assign_set_rhs1 (use_stmt, unshare_expr (def_rhs));
+         gimple_assign_set_rhs_code (use_stmt, TREE_CODE (def_rhs));
+         return true;
+       }
+
+      /* Else recurse if the conversion preserves the address value.  */
+      if ((INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+          || POINTER_TYPE_P (TREE_TYPE (lhs)))
+         && (TYPE_PRECISION (TREE_TYPE (lhs))
+             >= TYPE_PRECISION (TREE_TYPE (def_rhs))))
+       return forward_propagate_addr_expr (lhs, def_rhs, single_use_p);
+
+      return false;
     }
 
+  /* If this isn't a conversion chain from this on we only can propagate
+     into compatible pointer contexts.  */
+  if (!types_compatible_p (TREE_TYPE (name), TREE_TYPE (def_rhs)))
+    return false;
+
   /* Propagate through constant pointer adjustments.  */
   if (TREE_CODE (lhs) == SSA_NAME
       && rhs_code == POINTER_PLUS_EXPR
@@ -766,15 +744,14 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
       /* Recurse.  If we could propagate into all uses of lhs do not
         bother to replace into the current use but just pretend we did.  */
       if (TREE_CODE (new_def_rhs) == ADDR_EXPR
-         && forward_propagate_addr_expr (lhs, new_def_rhs))
+         && forward_propagate_addr_expr (lhs, new_def_rhs, single_use_p))
        return true;
 
       if (useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (new_def_rhs)))
        gimple_assign_set_rhs_with_ops (use_stmt_gsi, TREE_CODE (new_def_rhs),
-                                       new_def_rhs, NULL_TREE);
+                                       new_def_rhs);
       else if (is_gimple_min_invariant (new_def_rhs))
-       gimple_assign_set_rhs_with_ops (use_stmt_gsi, NOP_EXPR,
-                                       new_def_rhs, NULL_TREE);
+       gimple_assign_set_rhs_with_ops (use_stmt_gsi, NOP_EXPR, new_def_rhs);
       else
        return false;
       gcc_assert (gsi_stmt (*use_stmt_gsi) == use_stmt);
@@ -784,9 +761,10 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
 
   /* Now strip away any outer COMPONENT_REF/ARRAY_REF nodes from the LHS.
      ADDR_EXPR will not appear on the LHS.  */
-  lhs = gimple_assign_lhs (use_stmt);
-  while (handled_component_p (lhs))
-    lhs = TREE_OPERAND (lhs, 0);
+  tree *lhsp = gimple_assign_lhs_ptr (use_stmt);
+  while (handled_component_p (*lhsp))
+    lhsp = &TREE_OPERAND (*lhsp, 0);
+  lhs = *lhsp;
 
   /* Now see if the LHS node is a MEM_REF using NAME.  If so,
      propagate the ADDR_EXPR into the use of NAME and fold the result.  */
@@ -799,9 +777,9 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
       if ((def_rhs_base = get_addr_base_and_unit_offset (TREE_OPERAND (def_rhs, 0),
                                                         &def_rhs_offset)))
        {
-         double_int off = mem_ref_offset (lhs);
+         offset_int off = mem_ref_offset (lhs);
          tree new_ptr;
-         off += double_int::from_shwi (def_rhs_offset);
+         off += def_rhs_offset;
          if (TREE_CODE (def_rhs_base) == MEM_REF)
            {
              off += mem_ref_offset (def_rhs_base);
@@ -811,7 +789,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
            new_ptr = build_fold_addr_expr (def_rhs_base);
          TREE_OPERAND (lhs, 0) = new_ptr;
          TREE_OPERAND (lhs, 1)
-           = double_int_to_tree (TREE_TYPE (TREE_OPERAND (lhs, 1)), off);
+           = wide_int_to_tree (TREE_TYPE (TREE_OPERAND (lhs, 1)), off);
          tidy_after_forward_propagate_addr (use_stmt);
          /* Continue propagating into the RHS if this was not the only use.  */
          if (single_use_p)
@@ -820,11 +798,17 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
       /* If the LHS is a plain dereference and the value type is the same as
          that of the pointed-to type of the address we can put the
         dereferenced address on the LHS preserving the original alias-type.  */
-      else if (gimple_assign_lhs (use_stmt) == lhs
-              && integer_zerop (TREE_OPERAND (lhs, 1))
-              && useless_type_conversion_p
-                   (TREE_TYPE (TREE_OPERAND (def_rhs, 0)),
-                    TREE_TYPE (gimple_assign_rhs1 (use_stmt))))
+      else if (integer_zerop (TREE_OPERAND (lhs, 1))
+              && ((gimple_assign_lhs (use_stmt) == lhs
+                   && useless_type_conversion_p
+                        (TREE_TYPE (TREE_OPERAND (def_rhs, 0)),
+                         TREE_TYPE (gimple_assign_rhs1 (use_stmt))))
+                  || types_compatible_p (TREE_TYPE (lhs),
+                                         TREE_TYPE (TREE_OPERAND (def_rhs, 0))))
+              /* Don't forward anything into clobber stmts if it would result
+                 in the lhs no longer being a MEM_REF.  */
+              && (!gimple_clobber_p (use_stmt)
+                  || TREE_CODE (TREE_OPERAND (def_rhs, 0)) == MEM_REF))
        {
          tree *def_rhs_basep = &TREE_OPERAND (def_rhs, 0);
          tree new_offset, new_base, saved, new_lhs;
@@ -848,7 +832,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
          TREE_SIDE_EFFECTS (*def_rhs_basep) = TREE_SIDE_EFFECTS (lhs);
          TREE_THIS_NOTRAP (*def_rhs_basep) = TREE_THIS_NOTRAP (lhs);
          new_lhs = unshare_expr (TREE_OPERAND (def_rhs, 0));
-         gimple_assign_set_lhs (use_stmt, new_lhs);
+         *lhsp = new_lhs;
          TREE_THIS_VOLATILE (new_lhs) = TREE_THIS_VOLATILE (lhs);
          TREE_SIDE_EFFECTS (new_lhs) = TREE_SIDE_EFFECTS (lhs);
          *def_rhs_basep = saved;
@@ -867,11 +851,12 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
 
   /* Strip away any outer COMPONENT_REF, ARRAY_REF or ADDR_EXPR
      nodes from the RHS.  */
-  rhs = gimple_assign_rhs1 (use_stmt);
-  if (TREE_CODE (rhs) == ADDR_EXPR)
-    rhs = TREE_OPERAND (rhs, 0);
-  while (handled_component_p (rhs))
-    rhs = TREE_OPERAND (rhs, 0);
+  tree *rhsp = gimple_assign_rhs1_ptr (use_stmt);
+  if (TREE_CODE (*rhsp) == ADDR_EXPR)
+    rhsp = &TREE_OPERAND (*rhsp, 0);
+  while (handled_component_p (*rhsp))
+    rhsp = &TREE_OPERAND (*rhsp, 0);
+  rhs = *rhsp;
 
   /* Now see if the RHS node is a MEM_REF using NAME.  If so,
      propagate the ADDR_EXPR into the use of NAME and fold the result.  */
@@ -883,9 +868,9 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
       if ((def_rhs_base = get_addr_base_and_unit_offset (TREE_OPERAND (def_rhs, 0),
                                                         &def_rhs_offset)))
        {
-         double_int off = mem_ref_offset (rhs);
+         offset_int off = mem_ref_offset (rhs);
          tree new_ptr;
-         off += double_int::from_shwi (def_rhs_offset);
+         off += def_rhs_offset;
          if (TREE_CODE (def_rhs_base) == MEM_REF)
            {
              off += mem_ref_offset (def_rhs_base);
@@ -895,7 +880,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
            new_ptr = build_fold_addr_expr (def_rhs_base);
          TREE_OPERAND (rhs, 0) = new_ptr;
          TREE_OPERAND (rhs, 1)
-           = double_int_to_tree (TREE_TYPE (TREE_OPERAND (rhs, 1)), off);
+           = wide_int_to_tree (TREE_TYPE (TREE_OPERAND (rhs, 1)), off);
          fold_stmt_inplace (use_stmt_gsi);
          tidy_after_forward_propagate_addr (use_stmt);
          return res;
@@ -903,11 +888,13 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
       /* If the RHS is a plain dereference and the value type is the same as
          that of the pointed-to type of the address we can put the
         dereferenced address on the RHS preserving the original alias-type.  */
-      else if (gimple_assign_rhs1 (use_stmt) == rhs
-              && integer_zerop (TREE_OPERAND (rhs, 1))
-              && useless_type_conversion_p
-                   (TREE_TYPE (gimple_assign_lhs (use_stmt)),
-                    TREE_TYPE (TREE_OPERAND (def_rhs, 0))))
+      else if (integer_zerop (TREE_OPERAND (rhs, 1))
+              && ((gimple_assign_rhs1 (use_stmt) == rhs
+                   && useless_type_conversion_p
+                        (TREE_TYPE (gimple_assign_lhs (use_stmt)),
+                         TREE_TYPE (TREE_OPERAND (def_rhs, 0))))
+                  || types_compatible_p (TREE_TYPE (rhs),
+                                         TREE_TYPE (TREE_OPERAND (def_rhs, 0)))))
        {
          tree *def_rhs_basep = &TREE_OPERAND (def_rhs, 0);
          tree new_offset, new_base, saved, new_rhs;
@@ -931,7 +918,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
          TREE_SIDE_EFFECTS (*def_rhs_basep) = TREE_SIDE_EFFECTS (rhs);
          TREE_THIS_NOTRAP (*def_rhs_basep) = TREE_THIS_NOTRAP (rhs);
          new_rhs = unshare_expr (TREE_OPERAND (def_rhs, 0));
-         gimple_assign_set_rhs1 (use_stmt, new_rhs);
+         *rhsp = new_rhs;
          TREE_THIS_VOLATILE (new_rhs) = TREE_THIS_VOLATILE (rhs);
          TREE_SIDE_EFFECTS (new_rhs) = TREE_SIDE_EFFECTS (rhs);
          *def_rhs_basep = saved;
@@ -984,16 +971,20 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
    Try to forward propagate the ADDR_EXPR into all uses of the SSA_NAME.
    Often this will allow for removal of an ADDR_EXPR and INDIRECT_REF
    node or for recovery of array indexing from pointer arithmetic.
+
+   PARENT_SINGLE_USE_P tells if, when in a recursive invocation, NAME was
+   the single use in the previous invocation.  Pass true when calling
+   this as toplevel.
+
    Returns true, if all uses have been propagated into.  */
 
 static bool
-forward_propagate_addr_expr (tree name, tree rhs)
+forward_propagate_addr_expr (tree name, tree rhs, bool parent_single_use_p)
 {
-  int stmt_loop_depth = bb_loop_depth (gimple_bb (SSA_NAME_DEF_STMT (name)));
   imm_use_iterator iter;
-  gimple use_stmt;
+  gimple *use_stmt;
   bool all = true;
-  bool single_use_p = has_single_use (name);
+  bool single_use_p = parent_single_use_p && has_single_use (name);
 
   FOR_EACH_IMM_USE_STMT (use_stmt, iter, name)
     {
@@ -1002,37 +993,24 @@ forward_propagate_addr_expr (tree name, tree rhs)
 
       /* If the use is not in a simple assignment statement, then
         there is nothing we can do.  */
-      if (gimple_code (use_stmt) != GIMPLE_ASSIGN)
+      if (!is_gimple_assign (use_stmt))
        {
          if (!is_gimple_debug (use_stmt))
            all = false;
          continue;
        }
 
-      /* If the use is in a deeper loop nest, then we do not want
-        to propagate non-invariant ADDR_EXPRs into the loop as that
-        is likely adding expression evaluations into the loop.  */
-      if (bb_loop_depth (gimple_bb (use_stmt)) > stmt_loop_depth
-         && !is_gimple_min_invariant (rhs))
+      gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
+      result = forward_propagate_addr_expr_1 (name, rhs, &gsi,
+                                             single_use_p);
+      /* If the use has moved to a different statement adjust
+        the update machinery for the old statement too.  */
+      if (use_stmt != gsi_stmt (gsi))
        {
-         all = false;
-         continue;
+         update_stmt (use_stmt);
+         use_stmt = gsi_stmt (gsi);
        }
-
-      {
-       gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
-       result = forward_propagate_addr_expr_1 (name, rhs, &gsi,
-                                               single_use_p);
-       /* If the use has moved to a different statement adjust
-          the update machinery for the old statement too.  */
-       if (use_stmt != gsi_stmt (gsi))
-         {
-           update_stmt (use_stmt);
-           use_stmt = gsi_stmt (gsi);
-         }
-
-       update_stmt (use_stmt);
-      }
+      update_stmt (use_stmt);
       all &= result;
 
       /* Remove intermediate now unused copy and conversion chains.  */
@@ -1043,6 +1021,7 @@ forward_propagate_addr_expr (tree name, tree rhs)
          && has_zero_uses (gimple_assign_lhs (use_stmt)))
        {
          gimple_stmt_iterator gsi = gsi_for_stmt (use_stmt);
+         fwprop_invalidate_lattice (gimple_get_lhs (use_stmt));
          release_defs (use_stmt);
          gsi_remove (&gsi, true);
        }
@@ -1052,147 +1031,20 @@ forward_propagate_addr_expr (tree name, tree rhs)
 }
 
 
-/* Forward propagate the comparison defined in *DEFGSI like
-   cond_1 = x CMP y to uses of the form
-     a_1 = (T')cond_1
-     a_1 = !cond_1
-     a_1 = cond_1 != 0
-   Returns true if stmt is now unused.  Advance DEFGSI to the next
-   statement.  */
-
-static bool
-forward_propagate_comparison (gimple_stmt_iterator *defgsi)
-{
-  gimple stmt = gsi_stmt (*defgsi);
-  tree name = gimple_assign_lhs (stmt);
-  gimple use_stmt;
-  tree tmp = NULL_TREE;
-  gimple_stmt_iterator gsi;
-  enum tree_code code;
-  tree lhs;
-
-  /* Don't propagate ssa names that occur in abnormal phis.  */
-  if ((TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
-       && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs1 (stmt)))
-      || (TREE_CODE (gimple_assign_rhs2 (stmt)) == SSA_NAME
-        && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs2 (stmt))))
-    goto bailout;
-
-  /* Do not un-cse comparisons.  But propagate through copies.  */
-  use_stmt = get_prop_dest_stmt (name, &name);
-  if (!use_stmt
-      || !is_gimple_assign (use_stmt))
-    goto bailout;
-
-  code = gimple_assign_rhs_code (use_stmt);
-  lhs = gimple_assign_lhs (use_stmt);
-  if (!INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
-    goto bailout;
-
-  /* We can propagate the condition into a statement that
-     computes the logical negation of the comparison result.  */
-  if ((code == BIT_NOT_EXPR
-       && TYPE_PRECISION (TREE_TYPE (lhs)) == 1)
-      || (code == BIT_XOR_EXPR
-         && integer_onep (gimple_assign_rhs2 (use_stmt))))
-    {
-      tree type = TREE_TYPE (gimple_assign_rhs1 (stmt));
-      bool nans = HONOR_NANS (TYPE_MODE (type));
-      enum tree_code inv_code;
-      inv_code = invert_tree_comparison (gimple_assign_rhs_code (stmt), nans);
-      if (inv_code == ERROR_MARK)
-       goto bailout;
-
-      tmp = build2 (inv_code, TREE_TYPE (lhs), gimple_assign_rhs1 (stmt),
-                   gimple_assign_rhs2 (stmt));
-    }
-  else
-    goto bailout;
-
-  gsi = gsi_for_stmt (use_stmt);
-  gimple_assign_set_rhs_from_tree (&gsi, unshare_expr (tmp));
-  use_stmt = gsi_stmt (gsi);
-  update_stmt (use_stmt);
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "  Replaced '");
-      print_gimple_expr (dump_file, stmt, 0, dump_flags);
-      fprintf (dump_file, "' with '");
-      print_gimple_expr (dump_file, use_stmt, 0, dump_flags);
-      fprintf (dump_file, "'\n");
-    }
-
-  /* When we remove stmt now the iterator defgsi goes off it's current
-     sequence, hence advance it now.  */
-  gsi_next (defgsi);
-
-  /* Remove defining statements.  */
-  return remove_prop_source_from_use (name);
-
-bailout:
-  gsi_next (defgsi);
-  return false;
-}
-
-
-/* If we have lhs = ~x (STMT), look and see if earlier we had x = ~y.
-   If so, we can change STMT into lhs = y which can later be copy
-   propagated.  Similarly for negation.
-
-   This could trivially be formulated as a forward propagation
-   to immediate uses.  However, we already had an implementation
-   from DOM which used backward propagation via the use-def links.
-
-   It turns out that backward propagation is actually faster as
-   there's less work to do for each NOT/NEG expression we find.
-   Backwards propagation needs to look at the statement in a single
-   backlink.  Forward propagation needs to look at potentially more
-   than one forward link.
-
-   Returns true when the statement was changed.  */
-
-static bool 
-simplify_not_neg_expr (gimple_stmt_iterator *gsi_p)
-{
-  gimple stmt = gsi_stmt (*gsi_p);
-  tree rhs = gimple_assign_rhs1 (stmt);
-  gimple rhs_def_stmt = SSA_NAME_DEF_STMT (rhs);
-
-  /* See if the RHS_DEF_STMT has the same form as our statement.  */
-  if (is_gimple_assign (rhs_def_stmt)
-      && gimple_assign_rhs_code (rhs_def_stmt) == gimple_assign_rhs_code (stmt))
-    {
-      tree rhs_def_operand = gimple_assign_rhs1 (rhs_def_stmt);
-
-      /* Verify that RHS_DEF_OPERAND is a suitable SSA_NAME.  */
-      if (TREE_CODE (rhs_def_operand) == SSA_NAME
-         && ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs_def_operand))
-       {
-         gimple_assign_set_rhs_from_tree (gsi_p, rhs_def_operand);
-         stmt = gsi_stmt (*gsi_p);
-         update_stmt (stmt);
-         return true;
-       }
-    }
-
-  return false;
-}
-
 /* Helper function for simplify_gimple_switch.  Remove case labels that
    have values outside the range of the new type.  */
 
 static void
-simplify_gimple_switch_label_vec (gimple stmt, tree index_type)
+simplify_gimple_switch_label_vec (gswitch *stmt, tree index_type)
 {
   unsigned int branch_num = gimple_switch_num_labels (stmt);
-  VEC(tree, heap) *labels = VEC_alloc (tree, heap, branch_num);
+  auto_vec<tree> labels (branch_num);
   unsigned int i, len;
 
   /* Collect the existing case labels in a VEC, and preprocess it as if
      we are gimplifying a GENERIC SWITCH_EXPR.  */
   for (i = 1; i < branch_num; i++)
-    VEC_quick_push (tree, labels, gimple_switch_label (stmt, i));
+    labels.quick_push (gimple_switch_label (stmt, i));
   preprocess_case_label_vec_for_gimple (labels, index_type, NULL);
 
   /* If any labels were removed, replace the existing case labels
@@ -1200,7 +1052,7 @@ simplify_gimple_switch_label_vec (gimple stmt, tree index_type)
      Note that the type updates were done in-place on the case labels,
      so we only have to replace the case labels in the GIMPLE_SWITCH
      if the number of labels changed.  */
-  len = VEC_length (tree, labels);
+  len = labels.length ();
   if (len < branch_num - 1)
     {
       bitmap target_blocks;
@@ -1216,12 +1068,12 @@ simplify_gimple_switch_label_vec (gimple stmt, tree index_type)
 
          label = CASE_LABEL (gimple_switch_default_label (stmt));
          elt = build_case_label (build_int_cst (index_type, 0), NULL, label);
-         VEC_quick_push (tree, labels, elt);
+         labels.quick_push (elt);
          len = 1;
        }
 
-      for (i = 0; i < VEC_length (tree, labels); i++)
-       gimple_switch_set_label (stmt, i + 1, VEC_index (tree, labels, i));
+      for (i = 0; i < labels.length (); i++)
+       gimple_switch_set_label (stmt, i + 1, labels[i]);
       for (i++ ; i < branch_num; i++)
        gimple_switch_set_label (stmt, i, NULL_TREE);
       gimple_switch_set_num_labels (stmt, len + 1);
@@ -1247,53 +1099,46 @@ simplify_gimple_switch_label_vec (gimple stmt, tree index_type)
        } 
       BITMAP_FREE (target_blocks);
     }
-
-  VEC_free (tree, heap, labels);
 }
 
 /* STMT is a SWITCH_EXPR for which we attempt to find equivalent forms of
    the condition which we may be able to optimize better.  */
 
 static bool
-simplify_gimple_switch (gimple stmt)
+simplify_gimple_switch (gswitch *stmt)
 {
-  tree cond = gimple_switch_index (stmt);
-  tree def, to, ti;
-  gimple def_stmt;
-
   /* The optimization that we really care about is removing unnecessary
      casts.  That will let us do much better in propagating the inferred
      constant at the switch target.  */
+  tree cond = gimple_switch_index (stmt);
   if (TREE_CODE (cond) == SSA_NAME)
     {
-      def_stmt = SSA_NAME_DEF_STMT (cond);
-      if (is_gimple_assign (def_stmt))
+      gimple *def_stmt = SSA_NAME_DEF_STMT (cond);
+      if (gimple_assign_cast_p (def_stmt))
        {
-         if (gimple_assign_rhs_code (def_stmt) == NOP_EXPR)
-           {
-             int need_precision;
-             bool fail;
-
-             def = gimple_assign_rhs1 (def_stmt);
-
-             to = TREE_TYPE (cond);
-             ti = TREE_TYPE (def);
-
-             /* If we have an extension that preserves value, then we
-                can copy the source value into the switch.  */
-
-             need_precision = TYPE_PRECISION (ti);
-             fail = false;
-             if (! INTEGRAL_TYPE_P (ti))
-               fail = true;
-             else if (TYPE_UNSIGNED (to) && !TYPE_UNSIGNED (ti))
-               fail = true;
-             else if (!TYPE_UNSIGNED (to) && TYPE_UNSIGNED (ti))
-               need_precision += 1;
-             if (TYPE_PRECISION (to) < need_precision)
-               fail = true;
+         tree def = gimple_assign_rhs1 (def_stmt);
+         if (TREE_CODE (def) != SSA_NAME)
+           return false;
 
-             if (!fail)
+         /* If we have an extension or sign-change that preserves the
+            values we check against then we can copy the source value into
+            the switch.  */
+         tree ti = TREE_TYPE (def);
+         if (INTEGRAL_TYPE_P (ti)
+             && TYPE_PRECISION (ti) <= TYPE_PRECISION (TREE_TYPE (cond)))
+           {
+             size_t n = gimple_switch_num_labels (stmt);
+             tree min = NULL_TREE, max = NULL_TREE;
+             if (n > 1)
+               {
+                 min = CASE_LOW (gimple_switch_label (stmt, 1));
+                 if (CASE_HIGH (gimple_switch_label (stmt, n - 1)))
+                   max = CASE_HIGH (gimple_switch_label (stmt, n - 1));
+                 else
+                   max = CASE_LOW (gimple_switch_label (stmt, n - 1));
+               }
+             if ((!min || int_fits_type_p (min, ti))
+                 && (!max || int_fits_type_p (max, ti)))
                {
                  gimple_switch_set_index (stmt, def);
                  simplify_gimple_switch_label_vec (stmt, ti);
@@ -1323,7 +1168,7 @@ constant_pointer_difference (tree p1, tree p2)
     {
       tree p = i ? p1 : p2;
       tree off = size_zero_node;
-      gimple stmt;
+      gimple *stmt;
       enum tree_code code;
 
       /* For each of p1 and p2 we need to iterate at least
@@ -1351,8 +1196,8 @@ constant_pointer_difference (tree p1, tree p2)
                {
                  p = TREE_OPERAND (q, 0);
                  off = size_binop (PLUS_EXPR, off,
-                                   double_int_to_tree (sizetype,
-                                                       mem_ref_offset (q)));
+                                   wide_int_to_tree (sizetype,
+                                                     mem_ref_offset (q)));
                }
              else
                {
@@ -1378,7 +1223,7 @@ constant_pointer_difference (tree p1, tree p2)
              off = size_binop (PLUS_EXPR, off, gimple_assign_rhs2 (stmt));
              p = gimple_assign_rhs1 (stmt);
            }
-         else if (code == ADDR_EXPR || code == NOP_EXPR)
+         else if (code == ADDR_EXPR || CONVERT_EXPR_CODE_P (code))
            p = gimple_assign_rhs1 (stmt);
          else
            break;
@@ -1406,7 +1251,7 @@ constant_pointer_difference (tree p1, tree p2)
 static bool
 simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
 {
-  gimple stmt1, stmt2 = gsi_stmt (*gsi_p);
+  gimple *stmt1, *stmt2 = gsi_stmt (*gsi_p);
   tree vuse = gimple_vuse (stmt2);
   if (vuse == NULL)
     return false;
@@ -1428,14 +1273,15 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
          tree val2 = gimple_call_arg (stmt2, 1);
          tree len2 = gimple_call_arg (stmt2, 2);
          tree diff, vdef, new_str_cst;
-         gimple use_stmt;
+         gimple *use_stmt;
          unsigned int ptr1_align;
          unsigned HOST_WIDE_INT src_len;
          char *src_buf;
          use_operand_p use_p;
 
-         if (!host_integerp (val2, 0)
-             || !host_integerp (len2, 1))
+         if (!tree_fits_shwi_p (val2)
+             || !tree_fits_uhwi_p (len2)
+             || compare_tree_int (len2, 1024) == 1)
            break;
          if (is_gimple_call (stmt1))
            {
@@ -1454,15 +1300,15 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
              src1 = gimple_call_arg (stmt1, 1);
              len1 = gimple_call_arg (stmt1, 2);
              lhs1 = gimple_call_lhs (stmt1);
-             if (!host_integerp (len1, 1))
+             if (!tree_fits_uhwi_p (len1))
                break;
              str1 = string_constant (src1, &off1);
              if (str1 == NULL_TREE)
                break;
-             if (!host_integerp (off1, 1)
+             if (!tree_fits_uhwi_p (off1)
                  || compare_tree_int (off1, TREE_STRING_LENGTH (str1) - 1) > 0
                  || compare_tree_int (len1, TREE_STRING_LENGTH (str1)
-                                            - tree_low_cst (off1, 1)) > 0
+                                            - tree_to_uhwi (off1)) > 0
                  || TREE_CODE (TREE_TYPE (str1)) != ARRAY_TYPE
                  || TYPE_MODE (TREE_TYPE (TREE_TYPE (str1)))
                     != TYPE_MODE (char_type_node))
@@ -1476,7 +1322,7 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
              src1 = gimple_assign_rhs1 (stmt1);
              if (TREE_CODE (ptr1) != MEM_REF
                  || TYPE_MODE (TREE_TYPE (ptr1)) != TYPE_MODE (char_type_node)
-                 || !host_integerp (src1, 0))
+                 || !tree_fits_shwi_p (src1))
                break;
              ptr1 = build_fold_addr_expr (ptr1);
              callee1 = NULL_TREE;
@@ -1500,16 +1346,17 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
          /* If the difference between the second and first destination pointer
             is not constant, or is bigger than memcpy length, bail out.  */
          if (diff == NULL
-             || !host_integerp (diff, 1)
-             || tree_int_cst_lt (len1, diff))
+             || !tree_fits_uhwi_p (diff)
+             || tree_int_cst_lt (len1, diff)
+             || compare_tree_int (diff, 1024) == 1)
            break;
 
          /* Use maximum of difference plus memset length and memcpy length
             as the new memcpy length, if it is too big, bail out.  */
-         src_len = tree_low_cst (diff, 1);
-         src_len += tree_low_cst (len2, 1);
-         if (src_len < (unsigned HOST_WIDE_INT) tree_low_cst (len1, 1))
-           src_len = tree_low_cst (len1, 1);
+         src_len = tree_to_uhwi (diff);
+         src_len += tree_to_uhwi (len2);
+         if (src_len < tree_to_uhwi (len1))
+           src_len = tree_to_uhwi (len1);
          if (src_len > 1024)
            break;
 
@@ -1535,12 +1382,12 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
          src_buf = XALLOCAVEC (char, src_len + 1);
          if (callee1)
            memcpy (src_buf,
-                   TREE_STRING_POINTER (str1) + tree_low_cst (off1, 1),
-                   tree_low_cst (len1, 1));
+                   TREE_STRING_POINTER (str1) + tree_to_uhwi (off1),
+                   tree_to_uhwi (len1));
          else
-           src_buf[0] = tree_low_cst (src1, 0);
-         memset (src_buf + tree_low_cst (diff, 1),
-                 tree_low_cst (val2, 0), tree_low_cst (len2, 1));
+           src_buf[0] = tree_to_shwi (src1);
+         memset (src_buf + tree_to_uhwi (diff),
+                 tree_to_shwi (val2), tree_to_uhwi (len2));
          src_buf[src_len] = '\0';
          /* Neither builtin_strncpy_read_str nor builtin_memcpy_read_str
             handle embedded '\0's.  */
@@ -1569,9 +1416,13 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
              update_stmt (stmt1);
              unlink_stmt_vdef (stmt2);
              gsi_remove (gsi_p, true);
+             fwprop_invalidate_lattice (gimple_get_lhs (stmt2));
              release_defs (stmt2);
              if (lhs1 && DECL_FUNCTION_CODE (callee1) == BUILT_IN_MEMPCPY)
-               release_ssa_name (lhs1);
+               {
+                 fwprop_invalidate_lattice (lhs1);
+                 release_ssa_name (lhs1);
+               }
              return true;
            }
          else
@@ -1592,6 +1443,7 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
                                   build_int_cst (TREE_TYPE (len2), src_len));
              unlink_stmt_vdef (stmt1);
              gsi_remove (&gsi, true);
+             fwprop_invalidate_lattice (gimple_get_lhs (stmt1));
              release_defs (stmt1);
              update_stmt (stmt2);
              return false;
@@ -1604,126 +1456,6 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
   return false;
 }
 
-/* Checks if expression has type of one-bit precision, or is a known
-   truth-valued expression.  */
-static bool
-truth_valued_ssa_name (tree name)
-{
-  gimple def;
-  tree type = TREE_TYPE (name);
-
-  if (!INTEGRAL_TYPE_P (type))
-    return false;
-  /* Don't check here for BOOLEAN_TYPE as the precision isn't
-     necessarily one and so ~X is not equal to !X.  */
-  if (TYPE_PRECISION (type) == 1)
-    return true;
-  def = SSA_NAME_DEF_STMT (name);
-  if (is_gimple_assign (def))
-    return truth_value_p (gimple_assign_rhs_code (def));
-  return false;
-}
-
-/* Helper routine for simplify_bitwise_binary_1 function.
-   Return for the SSA name NAME the expression X if it mets condition
-   NAME = !X. Otherwise return NULL_TREE.
-   Detected patterns for NAME = !X are:
-     !X and X == 0 for X with integral type.
-     X ^ 1, X != 1,or ~X for X with integral type with precision of one.  */
-static tree
-lookup_logical_inverted_value (tree name)
-{
-  tree op1, op2;
-  enum tree_code code;
-  gimple def;
-
-  /* If name has none-intergal type, or isn't a SSA_NAME, then
-     return.  */
-  if (TREE_CODE (name) != SSA_NAME
-      || !INTEGRAL_TYPE_P (TREE_TYPE (name)))
-    return NULL_TREE;
-  def = SSA_NAME_DEF_STMT (name);
-  if (!is_gimple_assign (def))
-    return NULL_TREE;
-
-  code = gimple_assign_rhs_code (def);
-  op1 = gimple_assign_rhs1 (def);
-  op2 = NULL_TREE;
-
-  /* Get for EQ_EXPR or BIT_XOR_EXPR operation the second operand.
-     If CODE isn't an EQ_EXPR, BIT_XOR_EXPR, or BIT_NOT_EXPR, then return.  */
-  if (code == EQ_EXPR || code == NE_EXPR
-      || code == BIT_XOR_EXPR)
-    op2 = gimple_assign_rhs2 (def);
-
-  switch (code)
-    {
-    case BIT_NOT_EXPR:
-      if (truth_valued_ssa_name (name))
-       return op1;
-      break;
-    case EQ_EXPR:
-      /* Check if we have X == 0 and X has an integral type.  */
-      if (!INTEGRAL_TYPE_P (TREE_TYPE (op1)))
-       break;
-      if (integer_zerop (op2))
-       return op1;
-      break;
-    case NE_EXPR:
-      /* Check if we have X != 1 and X is a truth-valued.  */
-      if (!INTEGRAL_TYPE_P (TREE_TYPE (op1)))
-       break;
-      if (integer_onep (op2) && truth_valued_ssa_name (op1))
-       return op1;
-      break;
-    case BIT_XOR_EXPR:
-      /* Check if we have X ^ 1 and X is truth valued.  */
-      if (integer_onep (op2) && truth_valued_ssa_name (op1))
-       return op1;
-      break;
-    default:
-      break;
-    }
-
-  return NULL_TREE;
-}
-
-/* Optimize ARG1 CODE ARG2 to a constant for bitwise binary
-   operations CODE, if one operand has the logically inverted
-   value of the other.  */
-static tree
-simplify_bitwise_binary_1 (enum tree_code code, tree type,
-                          tree arg1, tree arg2)
-{
-  tree anot;
-
-  /* If CODE isn't a bitwise binary operation, return NULL_TREE.  */
-  if (code != BIT_AND_EXPR && code != BIT_IOR_EXPR
-      && code != BIT_XOR_EXPR)
-    return NULL_TREE;
-
-  /* First check if operands ARG1 and ARG2 are equal.  If so
-     return NULL_TREE as this optimization is handled fold_stmt.  */
-  if (arg1 == arg2)
-    return NULL_TREE;
-  /* See if we have in arguments logical-not patterns.  */
-  if (((anot = lookup_logical_inverted_value (arg1)) == NULL_TREE
-       || anot != arg2)
-      && ((anot = lookup_logical_inverted_value (arg2)) == NULL_TREE
-         || anot != arg1))
-    return NULL_TREE;
-
-  /* X & !X -> 0.  */
-  if (code == BIT_AND_EXPR)
-    return fold_convert (type, integer_zero_node);
-  /* X | !X -> 1 and X ^ !X -> 1, if X is truth-valued.  */
-  if (truth_valued_ssa_name (anot))
-    return fold_convert (type, integer_one_node);
-
-  /* ??? Otherwise result is (X != 0 ? X : 1).  not handled.  */
-  return NULL_TREE;
-}
-
 /* Given a ssa_name in NAME see if it was defined by an assignment and
    set CODE to be the code and ARG1 to the first operand on the rhs and ARG2
    to the second operand on the rhs. */
@@ -1731,7 +1463,7 @@ simplify_bitwise_binary_1 (enum tree_code code, tree type,
 static inline void
 defcodefor_name (tree name, enum tree_code *code, tree *arg1, tree *arg2)
 {
-  gimple def;
+  gimple *def;
   enum tree_code code1;
   tree arg11;
   tree arg21;
@@ -1769,797 +1501,239 @@ defcodefor_name (tree name, enum tree_code *code, tree *arg1, tree *arg2)
   /* Ignore arg3 currently. */
 }
 
-/* Simplify bitwise binary operations.
-   Return true if a transformation applied, otherwise return false.  */
-
-static bool
-simplify_bitwise_binary (gimple_stmt_iterator *gsi)
-{
-  gimple stmt = gsi_stmt (*gsi);
-  tree arg1 = gimple_assign_rhs1 (stmt);
-  tree arg2 = gimple_assign_rhs2 (stmt);
-  enum tree_code code = gimple_assign_rhs_code (stmt);
-  tree res;
-  tree def1_arg1, def1_arg2, def2_arg1, def2_arg2;
-  enum tree_code def1_code, def2_code;
-
-  defcodefor_name (arg1, &def1_code, &def1_arg1, &def1_arg2);
-  defcodefor_name (arg2, &def2_code, &def2_arg1, &def2_arg2);
-
-  /* Try to fold (type) X op CST -> (type) (X op ((type-x) CST)).  */
-  if (TREE_CODE (arg2) == INTEGER_CST
-      && CONVERT_EXPR_CODE_P (def1_code)
-      && INTEGRAL_TYPE_P (TREE_TYPE (def1_arg1))
-      && int_fits_type_p (arg2, TREE_TYPE (def1_arg1)))
-    {
-      gimple newop;
-      tree tem = make_ssa_name (TREE_TYPE (def1_arg1), NULL);
-      newop =
-        gimple_build_assign_with_ops (code, tem, def1_arg1,
-                                     fold_convert_loc (gimple_location (stmt),
-                                                       TREE_TYPE (def1_arg1),
-                                                       arg2));
-      gimple_set_location (newop, gimple_location (stmt));
-      gsi_insert_before (gsi, newop, GSI_SAME_STMT);
-      gimple_assign_set_rhs_with_ops_1 (gsi, NOP_EXPR,
-                                       tem, NULL_TREE, NULL_TREE);
-      update_stmt (gsi_stmt (*gsi));
-      return true;
-    }
-
-  /* For bitwise binary operations apply operand conversions to the
-     binary operation result instead of to the operands.  This allows
-     to combine successive conversions and bitwise binary operations.  */
-  if (CONVERT_EXPR_CODE_P (def1_code)
-      && CONVERT_EXPR_CODE_P (def2_code)
-      && types_compatible_p (TREE_TYPE (def1_arg1), TREE_TYPE (def2_arg1))
-      /* Make sure that the conversion widens the operands, or has same
-        precision,  or that it changes the operation to a bitfield
-        precision.  */
-      && ((TYPE_PRECISION (TREE_TYPE (def1_arg1))
-          <= TYPE_PRECISION (TREE_TYPE (arg1)))
-         || (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (arg1)))
-             != MODE_INT)
-         || (TYPE_PRECISION (TREE_TYPE (arg1))
-             != GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (arg1))))))
-    {
-      gimple newop;
-      tree tem = make_ssa_name (TREE_TYPE (def1_arg1), NULL);
-      newop = gimple_build_assign_with_ops (code, tem, def1_arg1, def2_arg1);
-      gimple_set_location (newop, gimple_location (stmt));
-      gsi_insert_before (gsi, newop, GSI_SAME_STMT);
-      gimple_assign_set_rhs_with_ops_1 (gsi, NOP_EXPR,
-                                       tem, NULL_TREE, NULL_TREE);
-      update_stmt (gsi_stmt (*gsi));
-      return true;
-    }
 
+/* Recognize rotation patterns.  Return true if a transformation
+   applied, otherwise return false.
 
-   /* Simplify (A & B) OP0 (C & B) to (A OP0 C) & B. */
-   if (def1_code == def2_code
-       && def1_code == BIT_AND_EXPR
-       && operand_equal_for_phi_arg_p (def1_arg2,
-                                      def2_arg2))
-    {
-      tree b = def1_arg2;
-      tree a = def1_arg1;
-      tree c = def2_arg1;
-      tree inner = fold_build2 (code, TREE_TYPE (arg2), a, c);
-      /* If A OP0 C (this usually means C is the same as A) is 0
-        then fold it down correctly. */
-      if (integer_zerop (inner))
-       {
-         gimple_assign_set_rhs_from_tree (gsi, inner);
-         update_stmt (stmt);
-         return true;
-       }
-      /* If A OP0 C (this usually means C is the same as A) is a ssa_name
-        then fold it down correctly. */
-      else if (TREE_CODE (inner) == SSA_NAME)
-       {
-         tree outer = fold_build2 (def1_code, TREE_TYPE (inner),
-                                   inner, b);
-         gimple_assign_set_rhs_from_tree (gsi, outer);
-         update_stmt (stmt);
-         return true;
-       }
-      else
-       {
-         gimple newop;
-         tree tem;
-         tem = make_ssa_name (TREE_TYPE (arg2), NULL);
-         newop = gimple_build_assign_with_ops (code, tem, a, c);
-         gimple_set_location (newop, gimple_location (stmt));
-         /* Make sure to re-process the new stmt as it's walking upwards.  */
-         gsi_insert_before (gsi, newop, GSI_NEW_STMT);
-         gimple_assign_set_rhs1 (stmt, tem);
-         gimple_assign_set_rhs2 (stmt, b);
-         gimple_assign_set_rhs_code (stmt, def1_code);
-         update_stmt (stmt);
-         return true;
-       }
-    }
-
-  /* (a | CST1) & CST2  ->  (a & CST2) | (CST1 & CST2).  */
-  if (code == BIT_AND_EXPR
-      && def1_code == BIT_IOR_EXPR
-      && TREE_CODE (arg2) == INTEGER_CST
-      && TREE_CODE (def1_arg2) == INTEGER_CST)
-    {
-      tree cst = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg2),
-                             arg2, def1_arg2);
-      tree tem;
-      gimple newop;
-      if (integer_zerop (cst))
-       {
-         gimple_assign_set_rhs1 (stmt, def1_arg1);
-         update_stmt (stmt);
-         return true;
-       }
-      tem = make_ssa_name (TREE_TYPE (arg2), NULL);
-      newop = gimple_build_assign_with_ops (BIT_AND_EXPR,
-                                           tem, def1_arg1, arg2);
-      gimple_set_location (newop, gimple_location (stmt));
-      /* Make sure to re-process the new stmt as it's walking upwards.  */
-      gsi_insert_before (gsi, newop, GSI_NEW_STMT);
-      gimple_assign_set_rhs1 (stmt, tem);
-      gimple_assign_set_rhs2 (stmt, cst);
-      gimple_assign_set_rhs_code (stmt, BIT_IOR_EXPR);
-      update_stmt (stmt);
-      return true;
-    }
+   We are looking for X with unsigned type T with bitsize B, OP being
+   +, | or ^, some type T2 wider than T and
+   (X << CNT1) OP (X >> CNT2)                          iff CNT1 + CNT2 == B
+   ((T) ((T2) X << CNT1)) OP ((T) ((T2) X >> CNT2))    iff CNT1 + CNT2 == B
+   (X << Y) OP (X >> (B - Y))
+   (X << (int) Y) OP (X >> (int) (B - Y))
+   ((T) ((T2) X << Y)) OP ((T) ((T2) X >> (B - Y)))
+   ((T) ((T2) X << (int) Y)) OP ((T) ((T2) X >> (int) (B - Y)))
+   (X << Y) | (X >> ((-Y) & (B - 1)))
+   (X << (int) Y) | (X >> (int) ((-Y) & (B - 1)))
+   ((T) ((T2) X << Y)) | ((T) ((T2) X >> ((-Y) & (B - 1))))
+   ((T) ((T2) X << (int) Y)) | ((T) ((T2) X >> (int) ((-Y) & (B - 1))))
 
-  /* Combine successive equal operations with constants.  */
-  if ((code == BIT_AND_EXPR
-       || code == BIT_IOR_EXPR
-       || code == BIT_XOR_EXPR)
-      && def1_code == code 
-      && TREE_CODE (arg2) == INTEGER_CST
-      && TREE_CODE (def1_arg2) == INTEGER_CST)
-    {
-      tree cst = fold_build2 (code, TREE_TYPE (arg2),
-                             arg2, def1_arg2);
-      gimple_assign_set_rhs1 (stmt, def1_arg1);
-      gimple_assign_set_rhs2 (stmt, cst);
-      update_stmt (stmt);
-      return true;
-    }
+   and transform these into:
+   X r<< CNT1
+   X r<< Y
 
-  /* Canonicalize X ^ ~0 to ~X.  */
-  if (code == BIT_XOR_EXPR
-      && TREE_CODE (arg2) == INTEGER_CST
-      && integer_all_onesp (arg2))
-    {
-      gimple_assign_set_rhs_with_ops (gsi, BIT_NOT_EXPR, arg1, NULL_TREE);
-      gcc_assert (gsi_stmt (*gsi) == stmt);
-      update_stmt (stmt);
-      return true;
-    }
+   Note, in the patterns with T2 type, the type of OP operands
+   might be even a signed type, but should have precision B.  */
 
-  /* Try simple folding for X op !X, and X op X.  */
-  res = simplify_bitwise_binary_1 (code, TREE_TYPE (arg1), arg1, arg2);
-  if (res != NULL_TREE)
-    {
-      gimple_assign_set_rhs_from_tree (gsi, res);
-      update_stmt (gsi_stmt (*gsi));
-      return true;
-    }
+static bool
+simplify_rotate (gimple_stmt_iterator *gsi)
+{
+  gimple *stmt = gsi_stmt (*gsi);
+  tree arg[2], rtype, rotcnt = NULL_TREE;
+  tree def_arg1[2], def_arg2[2];
+  enum tree_code def_code[2];
+  tree lhs;
+  int i;
+  bool swapped_p = false;
+  gimple *g;
+
+  arg[0] = gimple_assign_rhs1 (stmt);
+  arg[1] = gimple_assign_rhs2 (stmt);
+  rtype = TREE_TYPE (arg[0]);
+
+  /* Only create rotates in complete modes.  Other cases are not
+     expanded properly.  */
+  if (!INTEGRAL_TYPE_P (rtype)
+      || TYPE_PRECISION (rtype) != GET_MODE_PRECISION (TYPE_MODE (rtype)))
+    return false;
 
-  if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR)
+  for (i = 0; i < 2; i++)
+    defcodefor_name (arg[i], &def_code[i], &def_arg1[i], &def_arg2[i]);
+
+  /* Look through narrowing conversions.  */
+  if (CONVERT_EXPR_CODE_P (def_code[0])
+      && CONVERT_EXPR_CODE_P (def_code[1])
+      && INTEGRAL_TYPE_P (TREE_TYPE (def_arg1[0]))
+      && INTEGRAL_TYPE_P (TREE_TYPE (def_arg1[1]))
+      && TYPE_PRECISION (TREE_TYPE (def_arg1[0]))
+        == TYPE_PRECISION (TREE_TYPE (def_arg1[1]))
+      && TYPE_PRECISION (TREE_TYPE (def_arg1[0])) > TYPE_PRECISION (rtype)
+      && has_single_use (arg[0])
+      && has_single_use (arg[1]))
     {
-      enum tree_code ocode = code == BIT_AND_EXPR ? BIT_IOR_EXPR : BIT_AND_EXPR;
-      if (def1_code == ocode)
+      for (i = 0; i < 2; i++)
        {
-         tree x = arg2;
-         enum tree_code coden;
-         tree a1, a2;
-         /* ( X | Y) & X -> X */
-         /* ( X & Y) | X -> X */
-         if (x == def1_arg1
-             || x == def1_arg2)
-           {
-             gimple_assign_set_rhs_from_tree (gsi, x);
-             update_stmt (gsi_stmt (*gsi));
-             return true;
-           }
-
-         defcodefor_name (def1_arg1, &coden, &a1, &a2);
-         /* (~X | Y) & X -> X & Y */
-         /* (~X & Y) | X -> X | Y */
-         if (coden == BIT_NOT_EXPR && a1 == x)
-           {
-             gimple_assign_set_rhs_with_ops (gsi, code,
-                                             x, def1_arg2);
-             gcc_assert (gsi_stmt (*gsi) == stmt);
-             update_stmt (stmt);
-             return true;
-           }
-         defcodefor_name (def1_arg2, &coden, &a1, &a2);
-         /* (Y | ~X) & X -> X & Y */
-         /* (Y & ~X) | X -> X | Y */
-         if (coden == BIT_NOT_EXPR && a1 == x)
-           {
-             gimple_assign_set_rhs_with_ops (gsi, code,
-                                             x, def1_arg1);
-             gcc_assert (gsi_stmt (*gsi) == stmt);
-             update_stmt (stmt);
-             return true;
-           }
-       }
-      if (def2_code == ocode)
-       {
-         enum tree_code coden;
-         tree a1;
-         tree x = arg1;
-         /* X & ( X | Y) -> X */
-         /* X | ( X & Y) -> X */
-         if (x == def2_arg1
-             || x == def2_arg2)
-           {
-             gimple_assign_set_rhs_from_tree (gsi, x);
-             update_stmt (gsi_stmt (*gsi));
-             return true;
-           }
-         defcodefor_name (def2_arg1, &coden, &a1, NULL);
-         /* (~X | Y) & X -> X & Y */
-         /* (~X & Y) | X -> X | Y */
-         if (coden == BIT_NOT_EXPR && a1 == x)
-           {
-             gimple_assign_set_rhs_with_ops (gsi, code,
-                                             x, def2_arg2);
-             gcc_assert (gsi_stmt (*gsi) == stmt);
-             update_stmt (stmt);
-             return true;
-           }
-         defcodefor_name (def2_arg2, &coden, &a1, NULL);
-         /* (Y | ~X) & X -> X & Y */
-         /* (Y & ~X) | X -> X | Y */
-         if (coden == BIT_NOT_EXPR && a1 == x)
-           {
-             gimple_assign_set_rhs_with_ops (gsi, code,
-                                             x, def2_arg1);
-             gcc_assert (gsi_stmt (*gsi) == stmt);
-             update_stmt (stmt);
-             return true;
-           }
+         arg[i] = def_arg1[i];
+         defcodefor_name (arg[i], &def_code[i], &def_arg1[i], &def_arg2[i]);
        }
     }
 
-  return false;
-}
-
-
-/* Perform re-associations of the plus or minus statement STMT that are
-   always permitted.  Returns true if the CFG was changed.  */
-
-static bool
-associate_plusminus (gimple_stmt_iterator *gsi)
-{
-  gimple stmt = gsi_stmt (*gsi);
-  tree rhs1 = gimple_assign_rhs1 (stmt);
-  tree rhs2 = gimple_assign_rhs2 (stmt);
-  enum tree_code code = gimple_assign_rhs_code (stmt);
-  bool changed;
-
-  /* We can't reassociate at all for saturating types.  */
-  if (TYPE_SATURATING (TREE_TYPE (rhs1)))
+  /* One operand has to be LSHIFT_EXPR and one RSHIFT_EXPR.  */
+  for (i = 0; i < 2; i++)
+    if (def_code[i] != LSHIFT_EXPR && def_code[i] != RSHIFT_EXPR)
+      return false;
+    else if (!has_single_use (arg[i]))
+      return false;
+  if (def_code[0] == def_code[1])
     return false;
 
-  /* First contract negates.  */
-  do
-    {
-      changed = false;
-
-      /* A +- (-B) -> A -+ B.  */
-      if (TREE_CODE (rhs2) == SSA_NAME)
-       {
-         gimple def_stmt = SSA_NAME_DEF_STMT (rhs2);
-         if (is_gimple_assign (def_stmt)
-             && gimple_assign_rhs_code (def_stmt) == NEGATE_EXPR
-             && can_propagate_from (def_stmt))
-           {
-             code = (code == MINUS_EXPR) ? PLUS_EXPR : MINUS_EXPR;
-             gimple_assign_set_rhs_code (stmt, code);
-             rhs2 = gimple_assign_rhs1 (def_stmt);
-             gimple_assign_set_rhs2 (stmt, rhs2);
-             gimple_set_modified (stmt, true);
-             changed = true;
-           }
-       }
+  /* If we've looked through narrowing conversions before, look through
+     widening conversions from unsigned type with the same precision
+     as rtype here.  */
+  if (TYPE_PRECISION (TREE_TYPE (def_arg1[0])) != TYPE_PRECISION (rtype))
+    for (i = 0; i < 2; i++)
+      {
+       tree tem;
+       enum tree_code code;
+       defcodefor_name (def_arg1[i], &code, &tem, NULL);
+       if (!CONVERT_EXPR_CODE_P (code)
+           || !INTEGRAL_TYPE_P (TREE_TYPE (tem))
+           || TYPE_PRECISION (TREE_TYPE (tem)) != TYPE_PRECISION (rtype))
+         return false;
+       def_arg1[i] = tem;
+      }
+  /* Both shifts have to use the same first operand.  */
+  if (TREE_CODE (def_arg1[0]) != SSA_NAME || def_arg1[0] != def_arg1[1])
+    return false;
+  if (!TYPE_UNSIGNED (TREE_TYPE (def_arg1[0])))
+    return false;
 
-      /* (-A) + B -> B - A.  */
-      if (TREE_CODE (rhs1) == SSA_NAME
-         && code == PLUS_EXPR)
-       {
-         gimple def_stmt = SSA_NAME_DEF_STMT (rhs1);
-         if (is_gimple_assign (def_stmt)
-             && gimple_assign_rhs_code (def_stmt) == NEGATE_EXPR
-             && can_propagate_from (def_stmt))
-           {
-             code = MINUS_EXPR;
-             gimple_assign_set_rhs_code (stmt, code);
-             rhs1 = rhs2;
-             gimple_assign_set_rhs1 (stmt, rhs1);
-             rhs2 = gimple_assign_rhs1 (def_stmt);
-             gimple_assign_set_rhs2 (stmt, rhs2);
-             gimple_set_modified (stmt, true);
-             changed = true;
-           }
-       }
-    }
-  while (changed);
-
-  /* We can't reassociate floating-point or fixed-point plus or minus
-     because of saturation to +-Inf.  */
-  if (FLOAT_TYPE_P (TREE_TYPE (rhs1))
-      || FIXED_POINT_TYPE_P (TREE_TYPE (rhs1)))
-    goto out;
-
-  /* Second match patterns that allow contracting a plus-minus pair
-     irrespective of overflow issues.
-
-       (A +- B) - A       ->  +- B
-       (A +- B) -+ B      ->  A
-       (CST +- A) +- CST  ->  CST +- A
-       (A + CST) +- CST   ->  A + CST
-       ~A + A             ->  -1
-       ~A + 1             ->  -A 
-       A - (A +- B)       ->  -+ B
-       A +- (B +- A)      ->  +- B
-       CST +- (CST +- A)  ->  CST +- A
-       CST +- (A +- CST)  ->  CST +- A
-       A + ~A             ->  -1
-
-     via commutating the addition and contracting operations to zero
-     by reassociation.  */
-
-  if (TREE_CODE (rhs1) == SSA_NAME)
+  /* CNT1 + CNT2 == B case above.  */
+  if (tree_fits_uhwi_p (def_arg2[0])
+      && tree_fits_uhwi_p (def_arg2[1])
+      && tree_to_uhwi (def_arg2[0])
+        + tree_to_uhwi (def_arg2[1]) == TYPE_PRECISION (rtype))
+    rotcnt = def_arg2[0];
+  else if (TREE_CODE (def_arg2[0]) != SSA_NAME
+          || TREE_CODE (def_arg2[1]) != SSA_NAME)
+    return false;
+  else
     {
-      gimple def_stmt = SSA_NAME_DEF_STMT (rhs1);
-      if (is_gimple_assign (def_stmt) && can_propagate_from (def_stmt))
+      tree cdef_arg1[2], cdef_arg2[2], def_arg2_alt[2];
+      enum tree_code cdef_code[2];
+      /* Look through conversion of the shift count argument.
+        The C/C++ FE cast any shift count argument to integer_type_node.
+        The only problem might be if the shift count type maximum value
+        is equal or smaller than number of bits in rtype.  */
+      for (i = 0; i < 2; i++)
        {
-         enum tree_code def_code = gimple_assign_rhs_code (def_stmt);
-         if (def_code == PLUS_EXPR
-             || def_code == MINUS_EXPR)
+         def_arg2_alt[i] = def_arg2[i];
+         defcodefor_name (def_arg2[i], &cdef_code[i],
+                          &cdef_arg1[i], &cdef_arg2[i]);
+         if (CONVERT_EXPR_CODE_P (cdef_code[i])
+             && INTEGRAL_TYPE_P (TREE_TYPE (cdef_arg1[i]))
+             && TYPE_PRECISION (TREE_TYPE (cdef_arg1[i]))
+                > floor_log2 (TYPE_PRECISION (rtype))
+             && TYPE_PRECISION (TREE_TYPE (cdef_arg1[i]))
+                == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (cdef_arg1[i]))))
            {
-             tree def_rhs1 = gimple_assign_rhs1 (def_stmt);
-             tree def_rhs2 = gimple_assign_rhs2 (def_stmt);
-             if (operand_equal_p (def_rhs1, rhs2, 0)
-                 && code == MINUS_EXPR)
-               {
-                 /* (A +- B) - A -> +- B.  */
-                 code = ((def_code == PLUS_EXPR)
-                         ? TREE_CODE (def_rhs2) : NEGATE_EXPR);
-                 rhs1 = def_rhs2;
-                 rhs2 = NULL_TREE;
-                 gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
-                 gcc_assert (gsi_stmt (*gsi) == stmt);
-                 gimple_set_modified (stmt, true);
-               }
-             else if (operand_equal_p (def_rhs2, rhs2, 0)
-                      && code != def_code)
-               {
-                 /* (A +- B) -+ B -> A.  */
-                 code = TREE_CODE (def_rhs1);
-                 rhs1 = def_rhs1;
-                 rhs2 = NULL_TREE;
-                 gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
-                 gcc_assert (gsi_stmt (*gsi) == stmt);
-                 gimple_set_modified (stmt, true);
-               }
-             else if (TREE_CODE (rhs2) == INTEGER_CST
-                      && TREE_CODE (def_rhs1) == INTEGER_CST)
-               {
-                 /* (CST +- A) +- CST -> CST +- A.  */
-                 tree cst = fold_binary (code, TREE_TYPE (rhs1),
-                                         def_rhs1, rhs2);
-                 if (cst && !TREE_OVERFLOW (cst))
-                   {
-                     code = def_code;
-                     gimple_assign_set_rhs_code (stmt, code);
-                     rhs1 = cst;
-                     gimple_assign_set_rhs1 (stmt, rhs1);
-                     rhs2 = def_rhs2;
-                     gimple_assign_set_rhs2 (stmt, rhs2);
-                     gimple_set_modified (stmt, true);
-                   }
-               }
-             else if (TREE_CODE (rhs2) == INTEGER_CST
-                      && TREE_CODE (def_rhs2) == INTEGER_CST
-                      && def_code == PLUS_EXPR)
-               {
-                 /* (A + CST) +- CST -> A + CST.  */
-                 tree cst = fold_binary (code, TREE_TYPE (rhs1),
-                                         def_rhs2, rhs2);
-                 if (cst && !TREE_OVERFLOW (cst))
-                   {
-                     code = PLUS_EXPR;
-                     gimple_assign_set_rhs_code (stmt, code);
-                     rhs1 = def_rhs1;
-                     gimple_assign_set_rhs1 (stmt, rhs1);
-                     rhs2 = cst;
-                     gimple_assign_set_rhs2 (stmt, rhs2);
-                     gimple_set_modified (stmt, true);
-                   }
-               }
-           }
-         else if (def_code == BIT_NOT_EXPR
-                  && INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
-           {
-             tree def_rhs1 = gimple_assign_rhs1 (def_stmt);
-             if (code == PLUS_EXPR
-                 && operand_equal_p (def_rhs1, rhs2, 0))
-               {
-                 /* ~A + A -> -1.  */
-                 code = INTEGER_CST;
-                 rhs1 = build_int_cst_type (TREE_TYPE (rhs2), -1);
-                 rhs2 = NULL_TREE;
-                 gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
-                 gcc_assert (gsi_stmt (*gsi) == stmt);
-                 gimple_set_modified (stmt, true);
-               }
-             else if (code == PLUS_EXPR
-                      && integer_onep (rhs1))
-               {
-                 /* ~A + 1 -> -A.  */
-                 code = NEGATE_EXPR;
-                 rhs1 = def_rhs1;
-                 rhs2 = NULL_TREE;
-                 gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
-                 gcc_assert (gsi_stmt (*gsi) == stmt);
-                 gimple_set_modified (stmt, true);
-               }
+             def_arg2_alt[i] = cdef_arg1[i];
+             defcodefor_name (def_arg2_alt[i], &cdef_code[i],
+                              &cdef_arg1[i], &cdef_arg2[i]);
            }
        }
-    }
+      for (i = 0; i < 2; i++)
+       /* Check for one shift count being Y and the other B - Y,
+          with optional casts.  */
+       if (cdef_code[i] == MINUS_EXPR
+           && tree_fits_shwi_p (cdef_arg1[i])
+           && tree_to_shwi (cdef_arg1[i]) == TYPE_PRECISION (rtype)
+           && TREE_CODE (cdef_arg2[i]) == SSA_NAME)
+         {
+           tree tem;
+           enum tree_code code;
 
-  if (rhs2 && TREE_CODE (rhs2) == SSA_NAME)
-    {
-      gimple def_stmt = SSA_NAME_DEF_STMT (rhs2);
-      if (is_gimple_assign (def_stmt) && can_propagate_from (def_stmt))
-       {
-         enum tree_code def_code = gimple_assign_rhs_code (def_stmt);
-         if (def_code == PLUS_EXPR
-             || def_code == MINUS_EXPR)
-           {
-             tree def_rhs1 = gimple_assign_rhs1 (def_stmt);
-             tree def_rhs2 = gimple_assign_rhs2 (def_stmt);
-             if (operand_equal_p (def_rhs1, rhs1, 0)
-                 && code == MINUS_EXPR)
-               {
-                 /* A - (A +- B) -> -+ B.  */
-                 code = ((def_code == PLUS_EXPR)
-                         ? NEGATE_EXPR : TREE_CODE (def_rhs2));
-                 rhs1 = def_rhs2;
-                 rhs2 = NULL_TREE;
-                 gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
-                 gcc_assert (gsi_stmt (*gsi) == stmt);
-                 gimple_set_modified (stmt, true);
-               }
-             else if (operand_equal_p (def_rhs2, rhs1, 0)
-                      && code != def_code)
-               {
-                 /* A +- (B +- A) -> +- B.  */
-                 code = ((code == PLUS_EXPR)
-                         ? TREE_CODE (def_rhs1) : NEGATE_EXPR);
-                 rhs1 = def_rhs1;
-                 rhs2 = NULL_TREE;
-                 gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
-                 gcc_assert (gsi_stmt (*gsi) == stmt);
-                 gimple_set_modified (stmt, true);
-               }
-             else if (TREE_CODE (rhs1) == INTEGER_CST
-                      && TREE_CODE (def_rhs1) == INTEGER_CST)
-               {
-                 /* CST +- (CST +- A) -> CST +- A.  */
-                 tree cst = fold_binary (code, TREE_TYPE (rhs2),
-                                         rhs1, def_rhs1);
-                 if (cst && !TREE_OVERFLOW (cst))
-                   {
-                     code = (code == def_code ? PLUS_EXPR : MINUS_EXPR);
-                     gimple_assign_set_rhs_code (stmt, code);
-                     rhs1 = cst;
-                     gimple_assign_set_rhs1 (stmt, rhs1);
-                     rhs2 = def_rhs2;
-                     gimple_assign_set_rhs2 (stmt, rhs2);
-                     gimple_set_modified (stmt, true);
-                   }
-               }
-             else if (TREE_CODE (rhs1) == INTEGER_CST
-                      && TREE_CODE (def_rhs2) == INTEGER_CST)
-               {
-                 /* CST +- (A +- CST) -> CST +- A.  */
-                 tree cst = fold_binary (def_code == code
-                                         ? PLUS_EXPR : MINUS_EXPR,
-                                         TREE_TYPE (rhs2),
-                                         rhs1, def_rhs2);
-                 if (cst && !TREE_OVERFLOW (cst))
-                   {
-                     rhs1 = cst;
-                     gimple_assign_set_rhs1 (stmt, rhs1);
-                     rhs2 = def_rhs1;
-                     gimple_assign_set_rhs2 (stmt, rhs2);
-                     gimple_set_modified (stmt, true);
-                   }
-               }
-           }
-         else if (def_code == BIT_NOT_EXPR
-                  && INTEGRAL_TYPE_P (TREE_TYPE (rhs2)))
-           {
-             tree def_rhs1 = gimple_assign_rhs1 (def_stmt);
-             if (code == PLUS_EXPR
-                 && operand_equal_p (def_rhs1, rhs1, 0))
-               {
-                 /* A + ~A -> -1.  */
-                 code = INTEGER_CST;
-                 rhs1 = build_int_cst_type (TREE_TYPE (rhs1), -1);
-                 rhs2 = NULL_TREE;
-                 gimple_assign_set_rhs_with_ops (gsi, code, rhs1, NULL_TREE);
-                 gcc_assert (gsi_stmt (*gsi) == stmt);
-                 gimple_set_modified (stmt, true);
-               }
-           }
-       }
+           if (cdef_arg2[i] == def_arg2[1 - i]
+               || cdef_arg2[i] == def_arg2_alt[1 - i])
+             {
+               rotcnt = cdef_arg2[i];
+               break;
+             }
+           defcodefor_name (cdef_arg2[i], &code, &tem, NULL);
+           if (CONVERT_EXPR_CODE_P (code)
+               && INTEGRAL_TYPE_P (TREE_TYPE (tem))
+               && TYPE_PRECISION (TREE_TYPE (tem))
+                > floor_log2 (TYPE_PRECISION (rtype))
+               && TYPE_PRECISION (TREE_TYPE (tem))
+                == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (tem)))
+               && (tem == def_arg2[1 - i]
+                   || tem == def_arg2_alt[1 - i]))
+             {
+               rotcnt = tem;
+               break;
+             }
+         }
+       /* The above sequence isn't safe for Y being 0,
+          because then one of the shifts triggers undefined behavior.
+          This alternative is safe even for rotation count of 0.
+          One shift count is Y and the other (-Y) & (B - 1).  */
+       else if (cdef_code[i] == BIT_AND_EXPR
+                && tree_fits_shwi_p (cdef_arg2[i])
+                && tree_to_shwi (cdef_arg2[i])
+                   == TYPE_PRECISION (rtype) - 1
+                && TREE_CODE (cdef_arg1[i]) == SSA_NAME
+                && gimple_assign_rhs_code (stmt) == BIT_IOR_EXPR)
+         {
+           tree tem;
+           enum tree_code code;
+
+           defcodefor_name (cdef_arg1[i], &code, &tem, NULL);
+           if (CONVERT_EXPR_CODE_P (code)
+               && INTEGRAL_TYPE_P (TREE_TYPE (tem))
+               && TYPE_PRECISION (TREE_TYPE (tem))
+                > floor_log2 (TYPE_PRECISION (rtype))
+               && TYPE_PRECISION (TREE_TYPE (tem))
+                == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (tem))))
+             defcodefor_name (tem, &code, &tem, NULL);
+
+           if (code == NEGATE_EXPR)
+             {
+               if (tem == def_arg2[1 - i] || tem == def_arg2_alt[1 - i])
+                 {
+                   rotcnt = tem;
+                   break;
+                 }
+               defcodefor_name (tem, &code, &tem, NULL);
+               if (CONVERT_EXPR_CODE_P (code)
+                   && INTEGRAL_TYPE_P (TREE_TYPE (tem))
+                   && TYPE_PRECISION (TREE_TYPE (tem))
+                      > floor_log2 (TYPE_PRECISION (rtype))
+                   && TYPE_PRECISION (TREE_TYPE (tem))
+                      == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (tem)))
+                   && (tem == def_arg2[1 - i]
+                       || tem == def_arg2_alt[1 - i]))
+                 {
+                   rotcnt = tem;
+                   break;
+                 }
+             }
+         }
+      if (rotcnt == NULL_TREE)
+       return false;
+      swapped_p = i != 1;
     }
 
-out:
-  if (gimple_modified_p (stmt))
+  if (!useless_type_conversion_p (TREE_TYPE (def_arg2[0]),
+                                 TREE_TYPE (rotcnt)))
     {
-      fold_stmt_inplace (gsi);
-      update_stmt (stmt);
-      if (maybe_clean_or_replace_eh_stmt (stmt, stmt)
-         && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
-       return true;
+      g = gimple_build_assign (make_ssa_name (TREE_TYPE (def_arg2[0])),
+                              NOP_EXPR, rotcnt);
+      gsi_insert_before (gsi, g, GSI_SAME_STMT);
+      rotcnt = gimple_assign_lhs (g);
     }
-
-  return false;
-}
-
-/* Associate operands of a POINTER_PLUS_EXPR assignmen at *GSI.  Returns
-   true if anything changed, false otherwise.  */
-
-static bool
-associate_pointerplus (gimple_stmt_iterator *gsi)
-{
-  gimple stmt = gsi_stmt (*gsi);
-  gimple def_stmt;
-  tree ptr, rhs, algn;
-
-  /* Pattern match
-       tem = (sizetype) ptr;
-       tem = tem & algn;
-       tem = -tem;
-       ... = ptr p+ tem;
-     and produce the simpler and easier to analyze with respect to alignment
-       ... = ptr & ~algn;  */
-  ptr = gimple_assign_rhs1 (stmt);
-  rhs = gimple_assign_rhs2 (stmt);
-  if (TREE_CODE (rhs) != SSA_NAME)
-    return false;
-  def_stmt = SSA_NAME_DEF_STMT (rhs);
-  if (!is_gimple_assign (def_stmt)
-      || gimple_assign_rhs_code (def_stmt) != NEGATE_EXPR)
-    return false;
-  rhs = gimple_assign_rhs1 (def_stmt);
-  if (TREE_CODE (rhs) != SSA_NAME)
-    return false;
-  def_stmt = SSA_NAME_DEF_STMT (rhs);
-  if (!is_gimple_assign (def_stmt)
-      || gimple_assign_rhs_code (def_stmt) != BIT_AND_EXPR)
-    return false;
-  rhs = gimple_assign_rhs1 (def_stmt);
-  algn = gimple_assign_rhs2 (def_stmt);
-  if (TREE_CODE (rhs) != SSA_NAME
-      || TREE_CODE (algn) != INTEGER_CST)
-    return false;
-  def_stmt = SSA_NAME_DEF_STMT (rhs);
-  if (!is_gimple_assign (def_stmt)
-      || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)))
-    return false;
-  if (gimple_assign_rhs1 (def_stmt) != ptr)
-    return false;
-
-  algn = double_int_to_tree (TREE_TYPE (ptr), ~tree_to_double_int (algn));
-  gimple_assign_set_rhs_with_ops (gsi, BIT_AND_EXPR, ptr, algn);
-  fold_stmt_inplace (gsi);
-  update_stmt (stmt);
-
-  return true;
-}
-
-/* Combine two conversions in a row for the second conversion at *GSI.
-   Returns 1 if there were any changes made, 2 if cfg-cleanup needs to
-   run.  Else it returns 0.  */
-static int
-combine_conversions (gimple_stmt_iterator *gsi)
-{
-  gimple stmt = gsi_stmt (*gsi);
-  gimple def_stmt;
-  tree op0, lhs;
-  enum tree_code code = gimple_assign_rhs_code (stmt);
-  enum tree_code code2;
-
-  gcc_checking_assert (CONVERT_EXPR_CODE_P (code)
-                      || code == FLOAT_EXPR
-                      || code == FIX_TRUNC_EXPR);
-
   lhs = gimple_assign_lhs (stmt);
-  op0 = gimple_assign_rhs1 (stmt);
-  if (useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (op0)))
+  if (!useless_type_conversion_p (rtype, TREE_TYPE (def_arg1[0])))
+    lhs = make_ssa_name (TREE_TYPE (def_arg1[0]));
+  g = gimple_build_assign (lhs,
+                          ((def_code[0] == LSHIFT_EXPR) ^ swapped_p)
+                          ? LROTATE_EXPR : RROTATE_EXPR, def_arg1[0], rotcnt);
+  if (!useless_type_conversion_p (rtype, TREE_TYPE (def_arg1[0])))
     {
-      gimple_assign_set_rhs_code (stmt, TREE_CODE (op0));
-      return 1;
-    }
-
-  if (TREE_CODE (op0) != SSA_NAME)
-    return 0;
-
-  def_stmt = SSA_NAME_DEF_STMT (op0);
-  if (!is_gimple_assign (def_stmt))
-    return 0;
-
-  code2 = gimple_assign_rhs_code (def_stmt);
-
-  if (CONVERT_EXPR_CODE_P (code2) || code2 == FLOAT_EXPR)
-    {
-      tree defop0 = gimple_assign_rhs1 (def_stmt);
-      tree type = TREE_TYPE (lhs);
-      tree inside_type = TREE_TYPE (defop0);
-      tree inter_type = TREE_TYPE (op0);
-      int inside_int = INTEGRAL_TYPE_P (inside_type);
-      int inside_ptr = POINTER_TYPE_P (inside_type);
-      int inside_float = FLOAT_TYPE_P (inside_type);
-      int inside_vec = TREE_CODE (inside_type) == VECTOR_TYPE;
-      unsigned int inside_prec = TYPE_PRECISION (inside_type);
-      int inside_unsignedp = TYPE_UNSIGNED (inside_type);
-      int inter_int = INTEGRAL_TYPE_P (inter_type);
-      int inter_ptr = POINTER_TYPE_P (inter_type);
-      int inter_float = FLOAT_TYPE_P (inter_type);
-      int inter_vec = TREE_CODE (inter_type) == VECTOR_TYPE;
-      unsigned int inter_prec = TYPE_PRECISION (inter_type);
-      int inter_unsignedp = TYPE_UNSIGNED (inter_type);
-      int final_int = INTEGRAL_TYPE_P (type);
-      int final_ptr = POINTER_TYPE_P (type);
-      int final_float = FLOAT_TYPE_P (type);
-      int final_vec = TREE_CODE (type) == VECTOR_TYPE;
-      unsigned int final_prec = TYPE_PRECISION (type);
-      int final_unsignedp = TYPE_UNSIGNED (type);
-
-      /* Don't propagate ssa names that occur in abnormal phis.  */
-      if (TREE_CODE (defop0) == SSA_NAME
-         && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (defop0))
-       return 0;
-
-      /* In addition to the cases of two conversions in a row
-        handled below, if we are converting something to its own
-        type via an object of identical or wider precision, neither
-        conversion is needed.  */
-      if (useless_type_conversion_p (type, inside_type)
-         && (((inter_int || inter_ptr) && final_int)
-             || (inter_float && final_float))
-         && inter_prec >= final_prec)
-       {
-         gimple_assign_set_rhs1 (stmt, unshare_expr (defop0));
-         gimple_assign_set_rhs_code (stmt, TREE_CODE (defop0));
-         update_stmt (stmt);
-         return remove_prop_source_from_use (op0) ? 2 : 1;
-       }
-
-      /* Likewise, if the intermediate and initial types are either both
-        float or both integer, we don't need the middle conversion if the
-        former is wider than the latter and doesn't change the signedness
-        (for integers).  Avoid this if the final type is a pointer since
-        then we sometimes need the middle conversion.  Likewise if the
-        final type has a precision not equal to the size of its mode.  */
-      if (((inter_int && inside_int)
-          || (inter_float && inside_float)
-          || (inter_vec && inside_vec))
-         && inter_prec >= inside_prec
-         && (inter_float || inter_vec
-             || inter_unsignedp == inside_unsignedp)
-         && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
-               && TYPE_MODE (type) == TYPE_MODE (inter_type))
-         && ! final_ptr
-         && (! final_vec || inter_prec == inside_prec))
-       {
-         gimple_assign_set_rhs1 (stmt, defop0);
-         update_stmt (stmt);
-         return remove_prop_source_from_use (op0) ? 2 : 1;
-       }
-
-      /* If we have a sign-extension of a zero-extended value, we can
-        replace that by a single zero-extension.  Likewise if the
-        final conversion does not change precision we can drop the
-        intermediate conversion.  */
-      if (inside_int && inter_int && final_int
-         && ((inside_prec < inter_prec && inter_prec < final_prec
-              && inside_unsignedp && !inter_unsignedp)
-             || final_prec == inter_prec))
-       {
-         gimple_assign_set_rhs1 (stmt, defop0);
-         update_stmt (stmt);
-         return remove_prop_source_from_use (op0) ? 2 : 1;
-       }
-
-      /* Two conversions in a row are not needed unless:
-        - some conversion is floating-point (overstrict for now), or
-        - some conversion is a vector (overstrict for now), or
-        - the intermediate type is narrower than both initial and
-        final, or
-        - the intermediate type and innermost type differ in signedness,
-        and the outermost type is wider than the intermediate, or
-        - the initial type is a pointer type and the precisions of the
-        intermediate and final types differ, or
-        - the final type is a pointer type and the precisions of the
-        initial and intermediate types differ.  */
-      if (! inside_float && ! inter_float && ! final_float
-         && ! inside_vec && ! inter_vec && ! final_vec
-         && (inter_prec >= inside_prec || inter_prec >= final_prec)
-         && ! (inside_int && inter_int
-               && inter_unsignedp != inside_unsignedp
-               && inter_prec < final_prec)
-         && ((inter_unsignedp && inter_prec > inside_prec)
-             == (final_unsignedp && final_prec > inter_prec))
-         && ! (inside_ptr && inter_prec != final_prec)
-         && ! (final_ptr && inside_prec != inter_prec)
-         && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
-               && TYPE_MODE (type) == TYPE_MODE (inter_type)))
-       {
-         gimple_assign_set_rhs1 (stmt, defop0);
-         update_stmt (stmt);
-         return remove_prop_source_from_use (op0) ? 2 : 1;
-       }
-
-      /* A truncation to an unsigned type should be canonicalized as
-        bitwise and of a mask.  */
-      if (final_int && inter_int && inside_int
-         && final_prec == inside_prec
-         && final_prec > inter_prec
-         && inter_unsignedp)
-       {
-         tree tem;
-         tem = fold_build2 (BIT_AND_EXPR, inside_type,
-                            defop0,
-                            double_int_to_tree
-                              (inside_type, double_int::mask (inter_prec)));
-         if (!useless_type_conversion_p (type, inside_type))
-           {
-             tem = force_gimple_operand_gsi (gsi, tem, true, NULL_TREE, true,
-                                             GSI_SAME_STMT);
-             gimple_assign_set_rhs1 (stmt, tem);
-           }
-         else
-           gimple_assign_set_rhs_from_tree (gsi, tem);
-         update_stmt (gsi_stmt (*gsi));
-         return 1;
-       }
-
-      /* If we are converting an integer to a floating-point that can
-        represent it exactly and back to an integer, we can skip the
-        floating-point conversion.  */
-      if (inside_int && inter_float && final_int &&
-          (unsigned) significand_size (TYPE_MODE (inter_type))
-          >= inside_prec - !inside_unsignedp)
-        {
-         if (useless_type_conversion_p (type, inside_type))
-           {
-             gimple_assign_set_rhs1 (stmt, unshare_expr (defop0));
-             gimple_assign_set_rhs_code (stmt, TREE_CODE (defop0));
-             update_stmt (stmt);
-             return remove_prop_source_from_use (op0) ? 2 : 1;
-           }
-         else
-           {
-             gimple_assign_set_rhs1 (stmt, defop0);
-             gimple_assign_set_rhs_code (stmt, CONVERT_EXPR);
-             update_stmt (stmt);
-             return remove_prop_source_from_use (op0) ? 2 : 1;
-           }
-       }
+      gsi_insert_before (gsi, g, GSI_SAME_STMT);
+      g = gimple_build_assign (gimple_assign_lhs (stmt), NOP_EXPR, lhs);
     }
-
-  return 0;
+  gsi_replace (gsi, g, false);
+  return true;
 }
 
 /* Combine an element access with a shuffle.  Returns true if there were
@@ -2568,8 +1742,8 @@ combine_conversions (gimple_stmt_iterator *gsi)
 static bool
 simplify_bitfield_ref (gimple_stmt_iterator *gsi)
 {
-  gimple stmt = gsi_stmt (*gsi);
-  gimple def_stmt;
+  gimple *stmt = gsi_stmt (*gsi);
+  gimple *def_stmt;
   tree op, op0, op1, op2;
   tree elem_type;
   unsigned idx, n, size;
@@ -2681,8 +1855,8 @@ is_combined_permutation_identity (tree mask1, tree mask2)
 static int
 simplify_permutation (gimple_stmt_iterator *gsi)
 {
-  gimple stmt = gsi_stmt (*gsi);
-  gimple def_stmt;
+  gimple *stmt = gsi_stmt (*gsi);
+  gimple *def_stmt;
   tree op0, op1, op2, op3, arg0, arg1;
   enum tree_code code;
   bool single_use_op0 = false;
@@ -2752,7 +1926,7 @@ simplify_permutation (gimple_stmt_iterator *gsi)
            {
              enum tree_code code2;
 
-             gimple def_stmt2 = get_prop_source_stmt (op1, true, NULL);
+             gimple *def_stmt2 = get_prop_source_stmt (op1, true, NULL);
              if (!def_stmt2 || !can_propagate_from (def_stmt2))
                return 0;
 
@@ -2771,9 +1945,9 @@ simplify_permutation (gimple_stmt_iterator *gsi)
            return 0;
          arg1 = arg0;
        }
-      opt = fold_ternary (VEC_PERM_EXPR, TREE_TYPE(op0), arg0, arg1, op2);
+      opt = fold_ternary (VEC_PERM_EXPR, TREE_TYPE (op0), arg0, arg1, op2);
       if (!opt
-         || (TREE_CODE (opt) != CONSTRUCTOR && TREE_CODE(opt) != VECTOR_CST))
+         || (TREE_CODE (opt) != CONSTRUCTOR && TREE_CODE (opt) != VECTOR_CST))
        return 0;
       gimple_assign_set_rhs_from_tree (gsi, opt);
       update_stmt (gsi_stmt (*gsi));
@@ -2792,8 +1966,8 @@ simplify_permutation (gimple_stmt_iterator *gsi)
 static bool
 simplify_vector_constructor (gimple_stmt_iterator *gsi)
 {
-  gimple stmt = gsi_stmt (*gsi);
-  gimple def_stmt;
+  gimple *stmt = gsi_stmt (*gsi);
+  gimple *def_stmt;
   tree op, op2, orig, type, elem_type;
   unsigned elem_size, nelts, i;
   enum tree_code code;
@@ -2814,7 +1988,7 @@ simplify_vector_constructor (gimple_stmt_iterator *gsi)
   sel = XALLOCAVEC (unsigned char, nelts);
   orig = NULL;
   maybe_ident = true;
-  FOR_EACH_VEC_ELT (constructor_elt, CONSTRUCTOR_ELTS (op), i, elt)
+  FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (op), i, elt)
     {
       tree ref, op1;
 
@@ -2871,32 +2045,89 @@ simplify_vector_constructor (gimple_stmt_iterator *gsi)
       for (i = 0; i < nelts; i++)
        mask_elts[i] = build_int_cst (TREE_TYPE (mask_type), sel[i]);
       op2 = build_vector (mask_type, mask_elts);
-      gimple_assign_set_rhs_with_ops_1 (gsi, VEC_PERM_EXPR, orig, orig, op2);
+      gimple_assign_set_rhs_with_ops (gsi, VEC_PERM_EXPR, orig, orig, op2);
     }
   update_stmt (gsi_stmt (*gsi));
   return true;
 }
 
+
+/* Primitive "lattice" function for gimple_simplify.  */
+
+static tree
+fwprop_ssa_val (tree name)
+{
+  /* First valueize NAME.  */
+  if (TREE_CODE (name) == SSA_NAME
+      && SSA_NAME_VERSION (name) < lattice.length ())
+    {
+      tree val = lattice[SSA_NAME_VERSION (name)];
+      if (val)
+       name = val;
+    }
+  /* We continue matching along SSA use-def edges for SSA names
+     that are not single-use.  Currently there are no patterns
+     that would cause any issues with that.  */
+  return name;
+}
+
 /* Main entry point for the forward propagation and statement combine
    optimizer.  */
 
-static unsigned int
-ssa_forward_propagate_and_combine (void)
+namespace {
+
+const pass_data pass_data_forwprop =
+{
+  GIMPLE_PASS, /* type */
+  "forwprop", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_TREE_FORWPROP, /* tv_id */
+  ( PROP_cfg | PROP_ssa ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_update_ssa, /* todo_flags_finish */
+};
+
+class pass_forwprop : public gimple_opt_pass
+{
+public:
+  pass_forwprop (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_forwprop, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_forwprop (m_ctxt); }
+  virtual bool gate (function *) { return flag_tree_forwprop; }
+  virtual unsigned int execute (function *);
+
+}; // class pass_forwprop
+
+unsigned int
+pass_forwprop::execute (function *fun)
 {
-  basic_block bb;
   unsigned int todoflags = 0;
 
   cfg_changed = false;
 
-  FOR_EACH_BB (bb)
+  /* Combine stmts with the stmts defining their operands.  Do that
+     in an order that guarantees visiting SSA defs before SSA uses.  */
+  lattice.create (num_ssa_names);
+  lattice.quick_grow_cleared (num_ssa_names);
+  int *postorder = XNEWVEC (int, n_basic_blocks_for_fn (fun));
+  int postorder_num = inverted_post_order_compute (postorder);
+  auto_vec<gimple *, 4> to_fixup;
+  to_purge = BITMAP_ALLOC (NULL);
+  for (int i = 0; i < postorder_num; ++i)
     {
       gimple_stmt_iterator gsi;
+      basic_block bb = BASIC_BLOCK_FOR_FN (fun, postorder[i]);
 
       /* Apply forward propagation to all stmts in the basic-block.
         Note we update GSI within the loop as necessary.  */
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
        {
-         gimple stmt = gsi_stmt (gsi);
+         gimple *stmt = gsi_stmt (gsi);
          tree lhs, rhs;
          enum tree_code code;
 
@@ -2930,10 +2161,10 @@ ssa_forward_propagate_and_combine (void)
                   || !DECL_P (base)
                   || decl_address_invariant_p (base))
                  && !stmt_references_abnormal_ssa_name (stmt)
-                 && forward_propagate_addr_expr (lhs, rhs))
+                 && forward_propagate_addr_expr (lhs, rhs, true))
                {
+                 fwprop_invalidate_lattice (gimple_get_lhs (stmt));
                  release_defs (stmt);
-                 todoflags |= TODO_remove_unused_locals;
                  gsi_remove (&gsi, true);
                }
              else
@@ -2955,10 +2186,10 @@ ssa_forward_propagate_and_combine (void)
                                                 TREE_TYPE (TREE_TYPE (rhs)),
                                                 rhs,
                                                 fold_convert (ptr_type_node,
-                                                              off)))))
+                                                              off))), true))
                {
+                 fwprop_invalidate_lattice (gimple_get_lhs (stmt));
                  release_defs (stmt);
-                 todoflags |= TODO_remove_unused_locals;
                  gsi_remove (&gsi, true);
                }
              else if (is_gimple_min_invariant (rhs))
@@ -2972,10 +2203,107 @@ ssa_forward_propagate_and_combine (void)
              else
                gsi_next (&gsi);
            }
-         else if (TREE_CODE_CLASS (code) == tcc_comparison)
+         else if (TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE
+                  && gimple_assign_load_p (stmt)
+                  && !gimple_has_volatile_ops (stmt)
+                  && (TREE_CODE (gimple_assign_rhs1 (stmt))
+                      != TARGET_MEM_REF)
+                  && !stmt_can_throw_internal (stmt))
            {
-             if (forward_propagate_comparison (&gsi))
-               cfg_changed = true;
+             /* Rewrite loads used only in real/imagpart extractions to
+                component-wise loads.  */
+             use_operand_p use_p;
+             imm_use_iterator iter;
+             bool rewrite = true;
+             FOR_EACH_IMM_USE_FAST (use_p, iter, lhs)
+               {
+                 gimple *use_stmt = USE_STMT (use_p);
+                 if (is_gimple_debug (use_stmt))
+                   continue;
+                 if (!is_gimple_assign (use_stmt)
+                     || (gimple_assign_rhs_code (use_stmt) != REALPART_EXPR
+                         && gimple_assign_rhs_code (use_stmt) != IMAGPART_EXPR))
+                   {
+                     rewrite = false;
+                     break;
+                   }
+               }
+             if (rewrite)
+               {
+                 gimple *use_stmt;
+                 FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
+                   {
+                     if (is_gimple_debug (use_stmt))
+                       {
+                         if (gimple_debug_bind_p (use_stmt))
+                           {
+                             gimple_debug_bind_reset_value (use_stmt);
+                             update_stmt (use_stmt);
+                           }
+                         continue;
+                       }
+
+                     tree new_rhs = build1 (gimple_assign_rhs_code (use_stmt),
+                                            TREE_TYPE (TREE_TYPE (rhs)),
+                                            unshare_expr (rhs));
+                     gimple *new_stmt
+                       = gimple_build_assign (gimple_assign_lhs (use_stmt),
+                                              new_rhs);
+
+                     location_t loc = gimple_location (use_stmt);
+                     gimple_set_location (new_stmt, loc);
+                     gimple_stmt_iterator gsi2 = gsi_for_stmt (use_stmt);
+                     unlink_stmt_vdef (use_stmt);
+                     gsi_remove (&gsi2, true);
+
+                     gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT);
+                   }
+
+                 release_defs (stmt);
+                 gsi_remove (&gsi, true);
+               }
+             else
+               gsi_next (&gsi);
+           }
+         else if (code == COMPLEX_EXPR)
+           {
+             /* Rewrite stores of a single-use complex build expression
+                to component-wise stores.  */
+             use_operand_p use_p;
+             gimple *use_stmt;
+             if (single_imm_use (lhs, &use_p, &use_stmt)
+                 && gimple_store_p (use_stmt)
+                 && !gimple_has_volatile_ops (use_stmt)
+                 && is_gimple_assign (use_stmt)
+                 && (TREE_CODE (gimple_assign_lhs (use_stmt))
+                     != TARGET_MEM_REF))
+               {
+                 tree use_lhs = gimple_assign_lhs (use_stmt);
+                 tree new_lhs = build1 (REALPART_EXPR,
+                                        TREE_TYPE (TREE_TYPE (use_lhs)),
+                                        unshare_expr (use_lhs));
+                 gimple *new_stmt = gimple_build_assign (new_lhs, rhs);
+                 location_t loc = gimple_location (use_stmt);
+                 gimple_set_location (new_stmt, loc);
+                 gimple_set_vuse (new_stmt, gimple_vuse (use_stmt));
+                 gimple_set_vdef (new_stmt, make_ssa_name (gimple_vop (cfun)));
+                 SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
+                 gimple_set_vuse (use_stmt, gimple_vdef (new_stmt));
+                 gimple_stmt_iterator gsi2 = gsi_for_stmt (use_stmt);
+                 gsi_insert_before (&gsi2, new_stmt, GSI_SAME_STMT);
+
+                 new_lhs = build1 (IMAGPART_EXPR,
+                                   TREE_TYPE (TREE_TYPE (use_lhs)),
+                                   unshare_expr (use_lhs));
+                 gimple_assign_set_lhs (use_stmt, new_lhs);
+                 gimple_assign_set_rhs1 (use_stmt, gimple_assign_rhs2 (stmt));
+                 update_stmt (use_stmt);
+
+                 release_defs (stmt);
+                 gsi_remove (&gsi, true);
+               }
+             else
+               gsi_next (&gsi);
            }
          else
            gsi_next (&gsi);
@@ -2985,12 +2313,33 @@ ssa_forward_propagate_and_combine (void)
         Note we update GSI within the loop as necessary.  */
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
        {
-         gimple stmt = gsi_stmt (gsi);
+         gimple *stmt = gsi_stmt (gsi);
+         gimple *orig_stmt = stmt;
          bool changed = false;
+         bool was_noreturn = (is_gimple_call (stmt)
+                              && gimple_call_noreturn_p (stmt));
 
          /* Mark stmt as potentially needing revisiting.  */
          gimple_set_plf (stmt, GF_PLF_1, false);
 
+         if (fold_stmt (&gsi, fwprop_ssa_val))
+           {
+             changed = true;
+             stmt = gsi_stmt (gsi);
+             if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
+               bitmap_set_bit (to_purge, bb->index);
+             if (!was_noreturn
+                 && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt))
+               to_fixup.safe_push (stmt);
+             /* Cleanup the CFG if we simplified a condition to
+                true or false.  */
+             if (gcond *cond = dyn_cast <gcond *> (stmt))
+               if (gimple_cond_true_p (cond)
+                   || gimple_cond_false_p (cond))
+                 cfg_changed = true;
+             update_stmt (stmt);
+           }
+
          switch (gimple_code (stmt))
            {
            case GIMPLE_ASSIGN:
@@ -2998,16 +2347,11 @@ ssa_forward_propagate_and_combine (void)
                tree rhs1 = gimple_assign_rhs1 (stmt);
                enum tree_code code = gimple_assign_rhs_code (stmt);
 
-               if ((code == BIT_NOT_EXPR
-                    || code == NEGATE_EXPR)
-                   && TREE_CODE (rhs1) == SSA_NAME)
-                 changed = simplify_not_neg_expr (&gsi);
-               else if (code == COND_EXPR
-                        || code == VEC_COND_EXPR)
+               if (code == COND_EXPR
+                   || code == VEC_COND_EXPR)
                  {
                    /* In this case the entire COND_EXPR is in rhs1. */
-                   if (forward_propagate_into_cond (&gsi)
-                       || combine_cond_exprs (&gsi))
+                   if (forward_propagate_into_cond (&gsi))
                      {
                        changed = true;
                        stmt = gsi_stmt (gsi);
@@ -3021,24 +2365,11 @@ ssa_forward_propagate_and_combine (void)
                      cfg_changed = true;
                    changed = did_something != 0;
                  }
-               else if (code == BIT_AND_EXPR
-                        || code == BIT_IOR_EXPR
-                        || code == BIT_XOR_EXPR)
-                 changed = simplify_bitwise_binary (&gsi);
-               else if (code == PLUS_EXPR
-                        || code == MINUS_EXPR)
-                 changed = associate_plusminus (&gsi);
-               else if (code == POINTER_PLUS_EXPR)
-                 changed = associate_pointerplus (&gsi);
-               else if (CONVERT_EXPR_CODE_P (code)
-                        || code == FLOAT_EXPR
-                        || code == FIX_TRUNC_EXPR)
-                 {
-                   int did_something = combine_conversions (&gsi);
-                   if (did_something == 2)
-                     cfg_changed = true;
-                   changed = did_something != 0;
-                 }
+               else if ((code == PLUS_EXPR
+                         || code == BIT_IOR_EXPR
+                         || code == BIT_XOR_EXPR)
+                        && simplify_rotate (&gsi))
+                 changed = true;
                else if (code == VEC_PERM_EXPR)
                  {
                    int did_something = simplify_permutation (&gsi);
@@ -3055,13 +2386,13 @@ ssa_forward_propagate_and_combine (void)
              }
 
            case GIMPLE_SWITCH:
-             changed = simplify_gimple_switch (stmt);
+             changed = simplify_gimple_switch (as_a <gswitch *> (stmt));
              break;
 
            case GIMPLE_COND:
              {
-               int did_something;
-               did_something = forward_propagate_into_gimple_cond (stmt);
+               int did_something
+                 = forward_propagate_into_gimple_cond (as_a <gcond *> (stmt));
                if (did_something == 2)
                  cfg_changed = true;
                changed = did_something != 0;
@@ -3096,10 +2427,48 @@ ssa_forward_propagate_and_combine (void)
            {
              /* Stmt no longer needs to be revisited.  */
              gimple_set_plf (stmt, GF_PLF_1, true);
+
+             /* Fill up the lattice.  */
+             if (gimple_assign_single_p (stmt))
+               {
+                 tree lhs = gimple_assign_lhs (stmt);
+                 tree rhs = gimple_assign_rhs1 (stmt);
+                 if (TREE_CODE (lhs) == SSA_NAME)
+                   {
+                     tree val = lhs;
+                     if (TREE_CODE (rhs) == SSA_NAME)
+                       val = fwprop_ssa_val (rhs);
+                     else if (is_gimple_min_invariant (rhs))
+                       val = rhs;
+                     fwprop_set_lattice_val (lhs, val);
+                   }
+               }
+
              gsi_next (&gsi);
            }
        }
     }
+  free (postorder);
+  lattice.release ();
+
+  /* Fixup stmts that became noreturn calls.  This may require splitting
+     blocks and thus isn't possible during the walk.  Do this
+     in reverse order so we don't inadvertedly remove a stmt we want to
+     fixup by visiting a dominating now noreturn call first.  */
+  while (!to_fixup.is_empty ())
+    {
+      gimple *stmt = to_fixup.pop ();
+      if (dump_file && dump_flags & TDF_DETAILS)
+       {
+         fprintf (dump_file, "Fixing up noreturn call ");
+         print_gimple_stmt (dump_file, stmt, 0, 0);
+         fprintf (dump_file, "\n");
+       }
+      cfg_changed |= fixup_noreturn_call (stmt);
+    }
+
+  cfg_changed |= gimple_purge_all_dead_eh_edges (to_purge);
+  BITMAP_FREE (to_purge);
 
   if (cfg_changed)
     todoflags |= TODO_cleanup_cfg;
@@ -3107,30 +2476,10 @@ ssa_forward_propagate_and_combine (void)
   return todoflags;
 }
 
+} // anon namespace
 
-static bool
-gate_forwprop (void)
+gimple_opt_pass *
+make_pass_forwprop (gcc::context *ctxt)
 {
-  return flag_tree_forwprop;
+  return new pass_forwprop (ctxt);
 }
-
-struct gimple_opt_pass pass_forwprop =
-{
- {
-  GIMPLE_PASS,
-  "forwprop",                  /* name */
-  gate_forwprop,               /* gate */
-  ssa_forward_propagate_and_combine,   /* execute */
-  NULL,                                /* sub */
-  NULL,                                /* next */
-  0,                           /* static_pass_number */
-  TV_TREE_FORWPROP,            /* tv_id */
-  PROP_cfg | PROP_ssa,         /* properties_required */
-  0,                           /* properties_provided */
-  0,                           /* properties_destroyed */
-  0,                           /* todo_flags_start */
-  TODO_ggc_collect
-  | TODO_update_ssa
-  | TODO_verify_ssa            /* todo_flags_finish */
- }
-};