Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / gcc / tree-ssa-forwprop.c
index fe2e89f..edcf929 100644 (file)
@@ -1,6 +1,5 @@
 /* Forward propagation of expressions for single use variables.
-   Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010, 2011
-   Free Software Foundation, Inc.
+   Copyright (C) 2004-2013 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -25,15 +24,16 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "tm_p.h"
 #include "basic-block.h"
-#include "timevar.h"
 #include "gimple-pretty-print.h"
 #include "tree-flow.h"
 #include "tree-pass.h"
-#include "tree-dump.h"
 #include "langhooks.h"
 #include "flags.h"
 #include "gimple.h"
 #include "expr.h"
+#include "cfgloop.h"
+#include "optabs.h"
+#include "tree-ssa-propagate.h"
 
 /* This pass propagates the RHS of assignment statements into use
    sites of the LHS of the assignment.  It's basically a specialized
@@ -163,7 +163,7 @@ along with GCC; see the file COPYING3.  If not see
 
 static bool forward_propagate_addr_expr (tree name, tree rhs);
 
-/* Set to true if we delete EH edges during the optimization.  */
+/* Set to true if we delete dead edges during the optimization.  */
 static bool cfg_changed;
 
 static tree rhs_to_tree (tree type, gimple stmt);
@@ -227,29 +227,15 @@ get_prop_source_stmt (tree name, bool single_use_only, bool *single_use_p)
     if (!is_gimple_assign (def_stmt))
       return NULL;
 
-    /* If def_stmt is not a simple copy, we possibly found it.  */
-    if (!gimple_assign_ssa_name_copy_p (def_stmt))
+    /* If def_stmt is a simple copy, continue looking.  */
+    if (gimple_assign_rhs_code (def_stmt) == SSA_NAME)
+      name = gimple_assign_rhs1 (def_stmt);
+    else
       {
-       tree rhs;
-
        if (!single_use_only && single_use_p)
          *single_use_p = single_use;
 
-       /* We can look through pointer conversions in the search
-          for a useful stmt for the comparison folding.  */
-       rhs = gimple_assign_rhs1 (def_stmt);
-       if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt))
-           && TREE_CODE (rhs) == SSA_NAME
-           && POINTER_TYPE_P (TREE_TYPE (gimple_assign_lhs (def_stmt)))
-           && POINTER_TYPE_P (TREE_TYPE (rhs)))
-         name = rhs;
-       else
-         return def_stmt;
-      }
-    else
-      {
-       /* Continue searching the def of the copy source name.  */
-       name = gimple_assign_rhs1 (def_stmt);
+       return def_stmt;
       }
   } while (1);
 }
@@ -325,9 +311,9 @@ remove_prop_source_from_use (tree name)
     bb = gimple_bb (stmt);
     gsi = gsi_for_stmt (stmt);
     unlink_stmt_vdef (stmt);
-    gsi_remove (&gsi, true);
+    if (gsi_remove (&gsi, true))
+      cfg_changed |= gimple_purge_dead_eh_edges (bb);
     release_defs (stmt);
-    cfg_changed |= gimple_purge_dead_eh_edges (bb);
 
     name = is_gimple_assign (stmt) ? gimple_assign_rhs1 (stmt) : NULL_TREE;
   } while (name && TREE_CODE (name) == SSA_NAME);
@@ -564,33 +550,35 @@ forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
   gimple stmt = gsi_stmt (*gsi_p);
   tree tmp = NULL_TREE;
   tree cond = gimple_assign_rhs1 (stmt);
+  enum tree_code code = gimple_assign_rhs_code (stmt);
   bool swap = false;
 
   /* We can do tree combining on SSA_NAME and comparison expressions.  */
   if (COMPARISON_CLASS_P (cond))
     tmp = forward_propagate_into_comparison_1 (stmt, TREE_CODE (cond),
-                                              boolean_type_node,
+                                              TREE_TYPE (cond),
                                               TREE_OPERAND (cond, 0),
                                               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);
       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,
-                              boolean_type_node,
+                              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))))
+      else if (code == COND_EXPR
+              && ((def_code == BIT_NOT_EXPR
+                   && TYPE_PRECISION (TREE_TYPE (cond)) == 1)
+                  || (def_code == BIT_XOR_EXPR
+                      && integer_onep (gimple_assign_rhs2 (def_stmt)))))
        {
          tmp = gimple_assign_rhs1 (def_stmt);
          swap = true;
@@ -609,7 +597,8 @@ 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));
@@ -632,6 +621,58 @@ 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.  */
 
@@ -647,128 +688,6 @@ tidy_after_forward_propagate_addr (gimple stmt)
      recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt));
 }
 
-/* DEF_RHS contains the address of the 0th element in an array.
-   USE_STMT uses type of DEF_RHS to compute the address of an
-   arbitrary element within the array.  The (variable) byte offset
-   of the element is contained in OFFSET.
-
-   We walk back through the use-def chains of OFFSET to verify that
-   it is indeed computing the offset of an element within the array
-   and extract the index corresponding to the given byte offset.
-
-   We then try to fold the entire address expression into a form
-   &array[index].
-
-   If we are successful, we replace the right hand side of USE_STMT
-   with the new address computation.  */
-
-static bool
-forward_propagate_addr_into_variable_array_index (tree offset,
-                                                 tree def_rhs,
-                                                 gimple_stmt_iterator *use_stmt_gsi)
-{
-  tree index, tunit;
-  gimple offset_def, use_stmt = gsi_stmt (*use_stmt_gsi);
-  tree new_rhs, tmp;
-
-  if (TREE_CODE (TREE_OPERAND (def_rhs, 0)) == ARRAY_REF)
-    tunit = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (def_rhs)));
-  else if (TREE_CODE (TREE_TYPE (TREE_OPERAND (def_rhs, 0))) == ARRAY_TYPE)
-    tunit = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (TREE_TYPE (def_rhs))));
-  else
-    return false;
-  if (!host_integerp (tunit, 1))
-    return false;
-
-  /* Get the offset's defining statement.  */
-  offset_def = SSA_NAME_DEF_STMT (offset);
-
-  /* Try to find an expression for a proper index.  This is either a
-     multiplication expression by the element size or just the ssa name we came
-     along in case the element size is one. In that case, however, we do not
-     allow multiplications because they can be computing index to a higher
-     level dimension (PR 37861). */
-  if (integer_onep (tunit))
-    {
-      if (is_gimple_assign (offset_def)
-         && gimple_assign_rhs_code (offset_def) == MULT_EXPR)
-       return false;
-
-      index = offset;
-    }
-  else
-    {
-      /* The statement which defines OFFSET before type conversion
-         must be a simple GIMPLE_ASSIGN.  */
-      if (!is_gimple_assign (offset_def))
-       return false;
-
-      /* The RHS of the statement which defines OFFSET must be a
-        multiplication of an object by the size of the array elements.
-        This implicitly verifies that the size of the array elements
-        is constant.  */
-     if (gimple_assign_rhs_code (offset_def) == MULT_EXPR
-        && TREE_CODE (gimple_assign_rhs2 (offset_def)) == INTEGER_CST
-        && tree_int_cst_equal (gimple_assign_rhs2 (offset_def), tunit))
-       {
-        /* The first operand to the MULT_EXPR is the desired index.  */
-        index = gimple_assign_rhs1 (offset_def);
-       }
-     /* If we have idx * tunit + CST * tunit re-associate that.  */
-     else if ((gimple_assign_rhs_code (offset_def) == PLUS_EXPR
-              || gimple_assign_rhs_code (offset_def) == MINUS_EXPR)
-             && TREE_CODE (gimple_assign_rhs1 (offset_def)) == SSA_NAME
-             && TREE_CODE (gimple_assign_rhs2 (offset_def)) == INTEGER_CST
-             && (tmp = div_if_zero_remainder (EXACT_DIV_EXPR,
-                                              gimple_assign_rhs2 (offset_def),
-                                              tunit)) != NULL_TREE)
-       {
-        gimple offset_def2 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (offset_def));
-        if (is_gimple_assign (offset_def2)
-            && gimple_assign_rhs_code (offset_def2) == MULT_EXPR
-            && TREE_CODE (gimple_assign_rhs2 (offset_def2)) == INTEGER_CST
-            && tree_int_cst_equal (gimple_assign_rhs2 (offset_def2), tunit))
-          {
-            index = fold_build2 (gimple_assign_rhs_code (offset_def),
-                                 TREE_TYPE (offset),
-                                 gimple_assign_rhs1 (offset_def2), tmp);
-          }
-        else
-          return false;
-       }
-     else
-       return false;
-    }
-
-  /* Replace the pointer addition with array indexing.  */
-  index = force_gimple_operand_gsi (use_stmt_gsi, index, true, NULL_TREE,
-                                   true, GSI_SAME_STMT);
-  if (TREE_CODE (TREE_OPERAND (def_rhs, 0)) == ARRAY_REF)
-    {
-      new_rhs = unshare_expr (def_rhs);
-      TREE_OPERAND (TREE_OPERAND (new_rhs, 0), 1) = index;
-    }
-  else
-    {
-      new_rhs = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (TREE_TYPE (def_rhs))),
-                       unshare_expr (TREE_OPERAND (def_rhs, 0)),
-                       index, integer_zero_node, NULL_TREE);
-      new_rhs = build_fold_addr_expr (new_rhs);
-      if (!useless_type_conversion_p (TREE_TYPE (gimple_assign_lhs (use_stmt)),
-                                     TREE_TYPE (new_rhs)))
-       {
-         new_rhs = force_gimple_operand_gsi (use_stmt_gsi, new_rhs, true,
-                                             NULL_TREE, true, GSI_SAME_STMT);
-         new_rhs = fold_convert (TREE_TYPE (gimple_assign_lhs (use_stmt)),
-                                 new_rhs);
-       }
-    }
-  gimple_assign_set_rhs_from_tree (use_stmt_gsi, new_rhs);
-  fold_stmt (use_stmt_gsi);
-  tidy_after_forward_propagate_addr (gsi_stmt (*use_stmt_gsi));
-  return true;
-}
-
 /* NAME is a SSA_NAME representing DEF_RHS which is of the form
    ADDR_EXPR <whatever>.
 
@@ -884,11 +803,10 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
        {
          double_int off = mem_ref_offset (lhs);
          tree new_ptr;
-         off = double_int_add (off,
-                               shwi_to_double_int (def_rhs_offset));
+         off += double_int::from_shwi (def_rhs_offset);
          if (TREE_CODE (def_rhs_base) == MEM_REF)
            {
-             off = double_int_add (off, mem_ref_offset (def_rhs_base));
+             off += mem_ref_offset (def_rhs_base);
              new_ptr = TREE_OPERAND (def_rhs_base, 0);
            }
          else
@@ -969,11 +887,10 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
        {
          double_int off = mem_ref_offset (rhs);
          tree new_ptr;
-         off = double_int_add (off,
-                               shwi_to_double_int (def_rhs_offset));
+         off += double_int::from_shwi (def_rhs_offset);
          if (TREE_CODE (def_rhs_base) == MEM_REF)
            {
-             off = double_int_add (off, mem_ref_offset (def_rhs_base));
+             off += mem_ref_offset (def_rhs_base);
              new_ptr = TREE_OPERAND (def_rhs_base, 0);
            }
          else
@@ -1061,19 +978,6 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
       return true;
     }
 
-  /* Try to optimize &x[0] p+ OFFSET where OFFSET is defined by
-     converting a multiplication of an index by the size of the
-     array elements, then the result is converted into the proper
-     type for the arithmetic.  */
-  if (TREE_CODE (rhs2) == SSA_NAME
-      && (TREE_CODE (array_ref) != ARRAY_REF
-         || integer_zerop (TREE_OPERAND (array_ref, 1)))
-      && useless_type_conversion_p (TREE_TYPE (name), TREE_TYPE (def_rhs))
-      /* Avoid problems with IVopts creating PLUS_EXPRs with a
-        different type than their operands.  */
-      && useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (def_rhs)))
-    return forward_propagate_addr_into_variable_array_index (rhs2, def_rhs,
-                                                            use_stmt_gsi);
   return false;
 }
 
@@ -1087,7 +991,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
 static bool
 forward_propagate_addr_expr (tree name, tree rhs)
 {
-  int stmt_loop_depth = gimple_bb (SSA_NAME_DEF_STMT (name))->loop_depth;
+  int stmt_loop_depth = bb_loop_depth (gimple_bb (SSA_NAME_DEF_STMT (name)));
   imm_use_iterator iter;
   gimple use_stmt;
   bool all = true;
@@ -1110,7 +1014,7 @@ forward_propagate_addr_expr (tree name, tree rhs)
       /* 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 (gimple_bb (use_stmt)->loop_depth > stmt_loop_depth
+      if (bb_loop_depth (gimple_bb (use_stmt)) > stmt_loop_depth
          && !is_gimple_min_invariant (rhs))
        {
          all = false;
@@ -1150,16 +1054,18 @@ forward_propagate_addr_expr (tree name, tree rhs)
 }
 
 
-/* Forward propagate the comparison defined in STMT like
+/* 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.  */
+   Returns true if stmt is now unused.  Advance DEFGSI to the next
+   statement.  */
 
 static bool
-forward_propagate_comparison (gimple stmt)
+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;
@@ -1172,18 +1078,18 @@ forward_propagate_comparison (gimple stmt)
        && 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))))
-    return false;
+    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))
-    return false;
+    goto bailout;
 
   code = gimple_assign_rhs_code (use_stmt);
   lhs = gimple_assign_lhs (use_stmt);
   if (!INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
-    return false;
+    goto bailout;
 
   /* We can propagate the condition into a statement that
      computes the logical negation of the comparison result.  */
@@ -1197,13 +1103,13 @@ forward_propagate_comparison (gimple stmt)
       enum tree_code inv_code;
       inv_code = invert_tree_comparison (gimple_assign_rhs_code (stmt), nans);
       if (inv_code == ERROR_MARK)
-       return false;
+       goto bailout;
 
       tmp = build2 (inv_code, TREE_TYPE (lhs), gimple_assign_rhs1 (stmt),
                    gimple_assign_rhs2 (stmt));
     }
   else
-    return false;
+    goto bailout;
 
   gsi = gsi_for_stmt (use_stmt);
   gimple_assign_set_rhs_from_tree (&gsi, unshare_expr (tmp));
@@ -1219,8 +1125,16 @@ forward_propagate_comparison (gimple stmt)
       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;
 }
 
 
@@ -1267,6 +1181,79 @@ simplify_not_neg_expr (gimple_stmt_iterator *gsi_p)
   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)
+{
+  unsigned int branch_num = gimple_switch_num_labels (stmt);
+  vec<tree> labels;
+  labels.create (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++)
+    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
+     in the GIMPLE_SWITCH statement with the correct ones.
+     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 = labels.length ();
+  if (len < branch_num - 1)
+    {
+      bitmap target_blocks;
+      edge_iterator ei;
+      edge e;
+
+      /* Corner case: *all* case labels have been removed as being
+        out-of-range for INDEX_TYPE.  Push one label and let the
+        CFG cleanups deal with this further.  */
+      if (len == 0)
+       {
+         tree label, elt;
+
+         label = CASE_LABEL (gimple_switch_default_label (stmt));
+         elt = build_case_label (build_int_cst (index_type, 0), NULL, label);
+         labels.quick_push (elt);
+         len = 1;
+       }
+
+      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);
+
+      /* Cleanup any edges that are now dead.  */
+      target_blocks = BITMAP_ALLOC (NULL);
+      for (i = 0; i < gimple_switch_num_labels (stmt); i++)
+       {
+         tree elt = gimple_switch_label (stmt, i);
+         basic_block target = label_to_block (CASE_LABEL (elt));
+         bitmap_set_bit (target_blocks, target->index);
+       }
+      for (ei = ei_start (gimple_bb (stmt)->succs); (e = ei_safe_edge (ei)); )
+       {
+         if (! bitmap_bit_p (target_blocks, e->dest->index))
+           {
+             remove_edge (e);
+             cfg_changed = true;
+             free_dominance_info (CDI_DOMINATORS);
+           }
+         else
+           ei_next (&ei);
+       } 
+      BITMAP_FREE (target_blocks);
+    }
+
+  labels.release ();
+}
+
 /* STMT is a SWITCH_EXPR for which we attempt to find equivalent forms of
    the condition which we may be able to optimize better.  */
 
@@ -1292,9 +1279,6 @@ simplify_gimple_switch (gimple stmt)
 
              def = gimple_assign_rhs1 (def_stmt);
 
-             /* ??? Why was Jeff testing this?  We are gimple...  */
-             gcc_checking_assert (is_gimple_val (def));
-
              to = TREE_TYPE (cond);
              ti = TREE_TYPE (def);
 
@@ -1315,6 +1299,7 @@ simplify_gimple_switch (gimple stmt)
              if (!fail)
                {
                  gimple_switch_set_index (stmt, def);
+                 simplify_gimple_switch_label_vec (stmt, ti);
                  update_stmt (stmt);
                  return true;
                }
@@ -1558,7 +1543,7 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
          else
            src_buf[0] = tree_low_cst (src1, 0);
          memset (src_buf + tree_low_cst (diff, 1),
-                 tree_low_cst (val2, 1), tree_low_cst (len2, 1));
+                 tree_low_cst (val2, 0), tree_low_cst (len2, 1));
          src_buf[src_len] = '\0';
          /* Neither builtin_strncpy_read_str nor builtin_memcpy_read_str
             handle embedded '\0's.  */
@@ -1742,6 +1727,74 @@ simplify_bitwise_binary_1 (enum tree_code code, tree type,
   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. */
+
+static inline void
+defcodefor_name (tree name, enum tree_code *code, tree *arg1, tree *arg2)
+{
+  gimple def;
+  enum tree_code code1;
+  tree arg11;
+  tree arg21;
+  tree arg31;
+  enum gimple_rhs_class grhs_class;
+
+  code1 = TREE_CODE (name);
+  arg11 = name;
+  arg21 = NULL_TREE;
+  grhs_class = get_gimple_rhs_class (code1);
+
+  if (code1 == SSA_NAME)
+    {
+      def = SSA_NAME_DEF_STMT (name);
+      
+      if (def && is_gimple_assign (def)
+         && can_propagate_from (def))
+       {
+         code1 = gimple_assign_rhs_code (def);
+         arg11 = gimple_assign_rhs1 (def);
+          arg21 = gimple_assign_rhs2 (def);
+          arg31 = gimple_assign_rhs2 (def);
+       }
+    }
+  else if (grhs_class == GIMPLE_TERNARY_RHS
+          || GIMPLE_BINARY_RHS
+          || GIMPLE_UNARY_RHS
+          || GIMPLE_SINGLE_RHS)
+    extract_ops_from_tree_1 (name, &code1, &arg11, &arg21, &arg31);
+
+  *code = code1;
+  *arg1 = arg11;
+  if (arg2)
+    *arg2 = arg21;
+  /* Ignore arg3 currently. */
+}
+
+/* Return true if a conversion of an operand from type FROM to type TO
+   should be applied after performing the operation instead.  */
+
+static bool
+hoist_conversion_for_bitop_p (tree to, tree from)
+{
+  /* That's a good idea if the conversion widens the operand, thus
+     after hoisting the conversion the operation will be narrower.  */
+  if (TYPE_PRECISION (from) < TYPE_PRECISION (to))
+    return true;
+
+  /* It's also a good idea if the conversion is to a non-integer mode.  */
+  if (GET_MODE_CLASS (TYPE_MODE (to)) != MODE_INT)
+    return true;
+
+  /* Or if the precision of TO is not the same as the precision
+     of its mode.  */
+  if (TYPE_PRECISION (to) != GET_MODE_PRECISION (TYPE_MODE (to)))
+    return true;
+
+  return false;
+}
+
 /* Simplify bitwise binary operations.
    Return true if a transformation applied, otherwise return false.  */
 
@@ -1753,49 +1806,27 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
   tree arg2 = gimple_assign_rhs2 (stmt);
   enum tree_code code = gimple_assign_rhs_code (stmt);
   tree res;
-  gimple def1 = NULL, def2 = NULL;
-  tree def1_arg1, def2_arg1;
+  tree def1_arg1, def1_arg2, def2_arg1, def2_arg2;
   enum tree_code def1_code, def2_code;
 
-  def1_code = TREE_CODE (arg1);
-  def1_arg1 = arg1;
-  if (TREE_CODE (arg1) == SSA_NAME)
-    {
-      def1 = SSA_NAME_DEF_STMT (arg1);
-      if (is_gimple_assign (def1))
-       {
-         def1_code = gimple_assign_rhs_code (def1);
-         def1_arg1 = gimple_assign_rhs1 (def1);
-       }
-    }
+  defcodefor_name (arg1, &def1_code, &def1_arg1, &def1_arg2);
+  defcodefor_name (arg2, &def2_code, &def2_arg1, &def2_arg2);
 
-  def2_code = TREE_CODE (arg2);
-  def2_arg1 = arg2;
-  if (TREE_CODE (arg2) == SSA_NAME)
-    {
-      def2 = SSA_NAME_DEF_STMT (arg2);
-      if (is_gimple_assign (def2))
-       {
-         def2_code = gimple_assign_rhs_code (def2);
-         def2_arg1 = gimple_assign_rhs1 (def2);
-       }
-    }
-
-  /* Try to fold (type) X op CST -> (type) (X op ((type-x) CST)).  */
+  /* Try to fold (type) X op CST -> (type) (X op ((type-x) CST))
+     when profitable.  */
   if (TREE_CODE (arg2) == INTEGER_CST
       && CONVERT_EXPR_CODE_P (def1_code)
+      && hoist_conversion_for_bitop_p (TREE_TYPE (arg1), TREE_TYPE (def1_arg1))
       && INTEGRAL_TYPE_P (TREE_TYPE (def1_arg1))
       && int_fits_type_p (arg2, TREE_TYPE (def1_arg1)))
     {
       gimple newop;
-      tree tem = create_tmp_reg (TREE_TYPE (def1_arg1), NULL);
+      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));
-      tem = make_ssa_name (tem, newop);
-      gimple_assign_set_lhs (newop, tem);
       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,
@@ -1810,22 +1841,11 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
   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))))))
+      && hoist_conversion_for_bitop_p (TREE_TYPE (arg1), TREE_TYPE (def1_arg1)))
     {
       gimple newop;
-      tree tem = create_tmp_reg (TREE_TYPE (def1_arg1),
-                                NULL);
+      tree tem = make_ssa_name (TREE_TYPE (def1_arg1), NULL);
       newop = gimple_build_assign_with_ops (code, tem, def1_arg1, def2_arg1);
-      tem = make_ssa_name (tem, newop);
-      gimple_assign_set_lhs (newop, tem);
       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,
@@ -1834,14 +1854,60 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
       return true;
     }
 
+
+   /* 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 (gimple_assign_rhs2 (def1)) == INTEGER_CST)
+      && TREE_CODE (def1_arg2) == INTEGER_CST)
     {
       tree cst = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg2),
-                             arg2, gimple_assign_rhs2 (def1));
+                             arg2, def1_arg2);
       tree tem;
       gimple newop;
       if (integer_zerop (cst))
@@ -1850,11 +1916,9 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
          update_stmt (stmt);
          return true;
        }
-      tem = create_tmp_reg (TREE_TYPE (arg2), NULL);
+      tem = make_ssa_name (TREE_TYPE (arg2), NULL);
       newop = gimple_build_assign_with_ops (BIT_AND_EXPR,
                                            tem, def1_arg1, arg2);
-      tem = make_ssa_name (tem, newop);
-      gimple_assign_set_lhs (newop, tem);
       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);
@@ -1871,10 +1935,10 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
        || code == BIT_XOR_EXPR)
       && def1_code == code 
       && TREE_CODE (arg2) == INTEGER_CST
-      && TREE_CODE (gimple_assign_rhs2 (def1)) == INTEGER_CST)
+      && TREE_CODE (def1_arg2) == INTEGER_CST)
     {
       tree cst = fold_build2 (code, TREE_TYPE (arg2),
-                             arg2, gimple_assign_rhs2 (def1));
+                             arg2, def1_arg2);
       gimple_assign_set_rhs1 (stmt, def1_arg1);
       gimple_assign_set_rhs2 (stmt, cst);
       update_stmt (stmt);
@@ -1901,6 +1965,86 @@ simplify_bitwise_binary (gimple_stmt_iterator *gsi)
       return true;
     }
 
+  if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR)
+    {
+      enum tree_code ocode = code == BIT_AND_EXPR ? BIT_IOR_EXPR : BIT_AND_EXPR;
+      if (def1_code == ocode)
+       {
+         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;
+           }
+       }
+    }
+
   return false;
 }
 
@@ -2191,6 +2335,58 @@ out:
   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.  */
@@ -2202,6 +2398,7 @@ combine_conversions (gimple_stmt_iterator *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
@@ -2222,7 +2419,9 @@ combine_conversions (gimple_stmt_iterator *gsi)
   if (!is_gimple_assign (def_stmt))
     return 0;
 
-  if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)))
+  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);
@@ -2279,7 +2478,7 @@ combine_conversions (gimple_stmt_iterator *gsi)
          && inter_prec >= inside_prec
          && (inter_float || inter_vec
              || inter_unsignedp == inside_unsignedp)
-         && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
+         && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
                && TYPE_MODE (type) == TYPE_MODE (inter_type))
          && ! final_ptr
          && (! final_vec || inter_prec == inside_prec))
@@ -2290,10 +2489,13 @@ combine_conversions (gimple_stmt_iterator *gsi)
        }
 
       /* If we have a sign-extension of a zero-extended value, we can
-        replace that by a single zero-extension.  */
+        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)
+         && ((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);
@@ -2321,7 +2523,7 @@ combine_conversions (gimple_stmt_iterator *gsi)
              == (final_unsignedp && final_prec > inter_prec))
          && ! (inside_ptr && inter_prec != final_prec)
          && ! (final_ptr && inside_prec != inter_prec)
-         && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
+         && ! (final_prec != GET_MODE_PRECISION (TYPE_MODE (type))
                && TYPE_MODE (type) == TYPE_MODE (inter_type)))
        {
          gimple_assign_set_rhs1 (stmt, defop0);
@@ -2340,7 +2542,7 @@ combine_conversions (gimple_stmt_iterator *gsi)
          tem = fold_build2 (BIT_AND_EXPR, inside_type,
                             defop0,
                             double_int_to_tree
-                              (inside_type, double_int_mask (inter_prec)));
+                              (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,
@@ -2352,11 +2554,349 @@ combine_conversions (gimple_stmt_iterator *gsi)
          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;
+           }
+       }
     }
 
   return 0;
 }
 
+/* Combine an element access with a shuffle.  Returns true if there were
+   any changes made, else it returns false.  */
+static bool
+simplify_bitfield_ref (gimple_stmt_iterator *gsi)
+{
+  gimple stmt = gsi_stmt (*gsi);
+  gimple def_stmt;
+  tree op, op0, op1, op2;
+  tree elem_type;
+  unsigned idx, n, size;
+  enum tree_code code;
+
+  op = gimple_assign_rhs1 (stmt);
+  gcc_checking_assert (TREE_CODE (op) == BIT_FIELD_REF);
+
+  op0 = TREE_OPERAND (op, 0);
+  if (TREE_CODE (op0) != SSA_NAME
+      || TREE_CODE (TREE_TYPE (op0)) != VECTOR_TYPE)
+    return false;
+
+  def_stmt = get_prop_source_stmt (op0, false, NULL);
+  if (!def_stmt || !can_propagate_from (def_stmt))
+    return false;
+
+  op1 = TREE_OPERAND (op, 1);
+  op2 = TREE_OPERAND (op, 2);
+  code = gimple_assign_rhs_code (def_stmt);
+
+  if (code == CONSTRUCTOR)
+    {
+      tree tem = fold_ternary (BIT_FIELD_REF, TREE_TYPE (op),
+                              gimple_assign_rhs1 (def_stmt), op1, op2);
+      if (!tem || !valid_gimple_rhs_p (tem))
+       return false;
+      gimple_assign_set_rhs_from_tree (gsi, tem);
+      update_stmt (gsi_stmt (*gsi));
+      return true;
+    }
+
+  elem_type = TREE_TYPE (TREE_TYPE (op0));
+  if (TREE_TYPE (op) != elem_type)
+    return false;
+
+  size = TREE_INT_CST_LOW (TYPE_SIZE (elem_type));
+  n = TREE_INT_CST_LOW (op1) / size;
+  if (n != 1)
+    return false;
+  idx = TREE_INT_CST_LOW (op2) / size;
+
+  if (code == VEC_PERM_EXPR)
+    {
+      tree p, m, index, tem;
+      unsigned nelts;
+      m = gimple_assign_rhs3 (def_stmt);
+      if (TREE_CODE (m) != VECTOR_CST)
+       return false;
+      nelts = VECTOR_CST_NELTS (m);
+      idx = TREE_INT_CST_LOW (VECTOR_CST_ELT (m, idx));
+      idx %= 2 * nelts;
+      if (idx < nelts)
+       {
+         p = gimple_assign_rhs1 (def_stmt);
+       }
+      else
+       {
+         p = gimple_assign_rhs2 (def_stmt);
+         idx -= nelts;
+       }
+      index = build_int_cst (TREE_TYPE (TREE_TYPE (m)), idx * size);
+      tem = build3 (BIT_FIELD_REF, TREE_TYPE (op),
+                   unshare_expr (p), op1, index);
+      gimple_assign_set_rhs1 (stmt, tem);
+      fold_stmt (gsi);
+      update_stmt (gsi_stmt (*gsi));
+      return true;
+    }
+
+  return false;
+}
+
+/* Determine whether applying the 2 permutations (mask1 then mask2)
+   gives back one of the input.  */
+
+static int
+is_combined_permutation_identity (tree mask1, tree mask2)
+{
+  tree mask;
+  unsigned int nelts, i, j;
+  bool maybe_identity1 = true;
+  bool maybe_identity2 = true;
+
+  gcc_checking_assert (TREE_CODE (mask1) == VECTOR_CST
+                      && TREE_CODE (mask2) == VECTOR_CST);
+  mask = fold_ternary (VEC_PERM_EXPR, TREE_TYPE (mask1), mask1, mask1, mask2);
+  gcc_assert (TREE_CODE (mask) == VECTOR_CST);
+
+  nelts = VECTOR_CST_NELTS (mask);
+  for (i = 0; i < nelts; i++)
+    {
+      tree val = VECTOR_CST_ELT (mask, i);
+      gcc_assert (TREE_CODE (val) == INTEGER_CST);
+      j = TREE_INT_CST_LOW (val) & (2 * nelts - 1);
+      if (j == i)
+       maybe_identity2 = false;
+      else if (j == i + nelts)
+       maybe_identity1 = false;
+      else
+       return 0;
+    }
+  return maybe_identity1 ? 1 : maybe_identity2 ? 2 : 0;
+}
+
+/* Combine a shuffle with its arguments.  Returns 1 if there were any
+   changes made, 2 if cfg-cleanup needs to run.  Else it returns 0.  */
+static int
+simplify_permutation (gimple_stmt_iterator *gsi)
+{
+  gimple stmt = gsi_stmt (*gsi);
+  gimple def_stmt;
+  tree op0, op1, op2, op3, arg0, arg1;
+  enum tree_code code;
+  bool single_use_op0 = false;
+
+  gcc_checking_assert (gimple_assign_rhs_code (stmt) == VEC_PERM_EXPR);
+
+  op0 = gimple_assign_rhs1 (stmt);
+  op1 = gimple_assign_rhs2 (stmt);
+  op2 = gimple_assign_rhs3 (stmt);
+
+  if (TREE_CODE (op2) != VECTOR_CST)
+    return 0;
+
+  if (TREE_CODE (op0) == VECTOR_CST)
+    {
+      code = VECTOR_CST;
+      arg0 = op0;
+    }
+  else if (TREE_CODE (op0) == SSA_NAME)
+    {
+      def_stmt = get_prop_source_stmt (op0, false, &single_use_op0);
+      if (!def_stmt || !can_propagate_from (def_stmt))
+       return 0;
+
+      code = gimple_assign_rhs_code (def_stmt);
+      arg0 = gimple_assign_rhs1 (def_stmt);
+    }
+  else
+    return 0;
+
+  /* Two consecutive shuffles.  */
+  if (code == VEC_PERM_EXPR)
+    {
+      tree orig;
+      int ident;
+
+      if (op0 != op1)
+       return 0;
+      op3 = gimple_assign_rhs3 (def_stmt);
+      if (TREE_CODE (op3) != VECTOR_CST)
+       return 0;
+      ident = is_combined_permutation_identity (op3, op2);
+      if (!ident)
+       return 0;
+      orig = (ident == 1) ? gimple_assign_rhs1 (def_stmt)
+                         : gimple_assign_rhs2 (def_stmt);
+      gimple_assign_set_rhs1 (stmt, unshare_expr (orig));
+      gimple_assign_set_rhs_code (stmt, TREE_CODE (orig));
+      gimple_set_num_ops (stmt, 2);
+      update_stmt (stmt);
+      return remove_prop_source_from_use (op0) ? 2 : 1;
+    }
+
+  /* Shuffle of a constructor.  */
+  else if (code == CONSTRUCTOR || code == VECTOR_CST)
+    {
+      tree opt;
+      bool ret = false;
+      if (op0 != op1)
+       {
+         if (TREE_CODE (op0) == SSA_NAME && !single_use_op0)
+           return 0;
+
+         if (TREE_CODE (op1) == VECTOR_CST)
+           arg1 = op1;
+         else if (TREE_CODE (op1) == SSA_NAME)
+           {
+             enum tree_code code2;
+
+             gimple def_stmt2 = get_prop_source_stmt (op1, true, NULL);
+             if (!def_stmt2 || !can_propagate_from (def_stmt2))
+               return 0;
+
+             code2 = gimple_assign_rhs_code (def_stmt2);
+             if (code2 != CONSTRUCTOR && code2 != VECTOR_CST)
+               return 0;
+             arg1 = gimple_assign_rhs1 (def_stmt2);
+           }
+         else
+           return 0;
+       }
+      else
+       {
+         /* Already used twice in this statement.  */
+         if (TREE_CODE (op0) == SSA_NAME && num_imm_uses (op0) > 2)
+           return 0;
+         arg1 = arg0;
+       }
+      opt = fold_ternary (VEC_PERM_EXPR, TREE_TYPE(op0), arg0, arg1, op2);
+      if (!opt
+         || (TREE_CODE (opt) != CONSTRUCTOR && TREE_CODE(opt) != VECTOR_CST))
+       return 0;
+      gimple_assign_set_rhs_from_tree (gsi, opt);
+      update_stmt (gsi_stmt (*gsi));
+      if (TREE_CODE (op0) == SSA_NAME)
+       ret = remove_prop_source_from_use (op0);
+      if (op0 != op1 && TREE_CODE (op1) == SSA_NAME)
+       ret |= remove_prop_source_from_use (op1);
+      return ret ? 2 : 1;
+    }
+
+  return 0;
+}
+
+/* Recognize a VEC_PERM_EXPR.  Returns true if there were any changes.  */
+
+static bool
+simplify_vector_constructor (gimple_stmt_iterator *gsi)
+{
+  gimple stmt = gsi_stmt (*gsi);
+  gimple def_stmt;
+  tree op, op2, orig, type, elem_type;
+  unsigned elem_size, nelts, i;
+  enum tree_code code;
+  constructor_elt *elt;
+  unsigned char *sel;
+  bool maybe_ident;
+
+  gcc_checking_assert (gimple_assign_rhs_code (stmt) == CONSTRUCTOR);
+
+  op = gimple_assign_rhs1 (stmt);
+  type = TREE_TYPE (op);
+  gcc_checking_assert (TREE_CODE (type) == VECTOR_TYPE);
+
+  nelts = TYPE_VECTOR_SUBPARTS (type);
+  elem_type = TREE_TYPE (type);
+  elem_size = TREE_INT_CST_LOW (TYPE_SIZE (elem_type));
+
+  sel = XALLOCAVEC (unsigned char, nelts);
+  orig = NULL;
+  maybe_ident = true;
+  FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (op), i, elt)
+    {
+      tree ref, op1;
+
+      if (i >= nelts)
+       return false;
+
+      if (TREE_CODE (elt->value) != SSA_NAME)
+       return false;
+      def_stmt = get_prop_source_stmt (elt->value, false, NULL);
+      if (!def_stmt)
+       return false;
+      code = gimple_assign_rhs_code (def_stmt);
+      if (code != BIT_FIELD_REF)
+       return false;
+      op1 = gimple_assign_rhs1 (def_stmt);
+      ref = TREE_OPERAND (op1, 0);
+      if (orig)
+       {
+         if (ref != orig)
+           return false;
+       }
+      else
+       {
+         if (TREE_CODE (ref) != SSA_NAME)
+           return false;
+         if (!useless_type_conversion_p (type, TREE_TYPE (ref)))
+           return false;
+         orig = ref;
+       }
+      if (TREE_INT_CST_LOW (TREE_OPERAND (op1, 1)) != elem_size)
+       return false;
+      sel[i] = TREE_INT_CST_LOW (TREE_OPERAND (op1, 2)) / elem_size;
+      if (sel[i] != i) maybe_ident = false;
+    }
+  if (i < nelts)
+    return false;
+
+  if (maybe_ident)
+    gimple_assign_set_rhs_from_tree (gsi, orig);
+  else
+    {
+      tree mask_type, *mask_elts;
+
+      if (!can_vec_perm_p (TYPE_MODE (type), false, sel))
+       return false;
+      mask_type
+       = build_vector_type (build_nonstandard_integer_type (elem_size, 1),
+                            nelts);
+      if (GET_MODE_CLASS (TYPE_MODE (mask_type)) != MODE_VECTOR_INT
+         || GET_MODE_SIZE (TYPE_MODE (mask_type))
+            != GET_MODE_SIZE (TYPE_MODE (type)))
+       return false;
+      mask_elts = XALLOCAVEC (tree, nelts);
+      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);
+    }
+  update_stmt (gsi_stmt (*gsi));
+  return true;
+}
+
 /* Main entry point for the forward propagation and statement combine
    optimizer.  */
 
@@ -2370,8 +2910,7 @@ ssa_forward_propagate_and_combine (void)
 
   FOR_EACH_BB (bb)
     {
-      gimple_stmt_iterator gsi, prev;
-      bool prev_initialized;
+      gimple_stmt_iterator gsi;
 
       /* Apply forward propagation to all stmts in the basic-block.
         Note we update GSI within the loop as necessary.  */
@@ -2414,7 +2953,6 @@ ssa_forward_propagate_and_combine (void)
                  && forward_propagate_addr_expr (lhs, rhs))
                {
                  release_defs (stmt);
-                 todoflags |= TODO_remove_unused_locals;
                  gsi_remove (&gsi, true);
                }
              else
@@ -2439,7 +2977,6 @@ ssa_forward_propagate_and_combine (void)
                                                               off)))))
                {
                  release_defs (stmt);
-                 todoflags |= TODO_remove_unused_locals;
                  gsi_remove (&gsi, true);
                }
              else if (is_gimple_min_invariant (rhs))
@@ -2455,9 +2992,8 @@ ssa_forward_propagate_and_combine (void)
            }
          else if (TREE_CODE_CLASS (code) == tcc_comparison)
            {
-             if (forward_propagate_comparison (stmt))
+             if (forward_propagate_comparison (&gsi))
                cfg_changed = true;
-             gsi_next (&gsi);
            }
          else
            gsi_next (&gsi);
@@ -2465,12 +3001,14 @@ ssa_forward_propagate_and_combine (void)
 
       /* Combine stmts with the stmts defining their operands.
         Note we update GSI within the loop as necessary.  */
-      prev_initialized = false;
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
        {
          gimple stmt = gsi_stmt (gsi);
          bool changed = false;
 
+         /* Mark stmt as potentially needing revisiting.  */
+         gimple_set_plf (stmt, GF_PLF_1, false);
+
          switch (gimple_code (stmt))
            {
            case GIMPLE_ASSIGN:
@@ -2482,11 +3020,16 @@ ssa_forward_propagate_and_combine (void)
                     || code == NEGATE_EXPR)
                    && TREE_CODE (rhs1) == SSA_NAME)
                  changed = simplify_not_neg_expr (&gsi);
-               else if (code == COND_EXPR)
+               else if (code == COND_EXPR
+                        || code == VEC_COND_EXPR)
                  {
                    /* In this case the entire COND_EXPR is in rhs1. */
-                   changed |= forward_propagate_into_cond (&gsi);
-                   stmt = gsi_stmt (gsi);
+                   if (forward_propagate_into_cond (&gsi)
+                       || combine_cond_exprs (&gsi))
+                     {
+                       changed = true;
+                       stmt = gsi_stmt (gsi);
+                     }
                  }
                else if (TREE_CODE_CLASS (code) == tcc_comparison)
                  {
@@ -2503,6 +3046,8 @@ ssa_forward_propagate_and_combine (void)
                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)
@@ -2512,6 +3057,18 @@ ssa_forward_propagate_and_combine (void)
                      cfg_changed = true;
                    changed = did_something != 0;
                  }
+               else if (code == VEC_PERM_EXPR)
+                 {
+                   int did_something = simplify_permutation (&gsi);
+                   if (did_something == 2)
+                     cfg_changed = true;
+                   changed = did_something != 0;
+                 }
+               else if (code == BIT_FIELD_REF)
+                 changed = simplify_bitfield_ref (&gsi);
+                else if (code == CONSTRUCTOR
+                         && TREE_CODE (TREE_TYPE (rhs1)) == VECTOR_TYPE)
+                  changed = simplify_vector_constructor (&gsi);
                break;
              }
 
@@ -2545,18 +3102,18 @@ ssa_forward_propagate_and_combine (void)
            {
              /* If the stmt changed then re-visit it and the statements
                 inserted before it.  */
-             if (!prev_initialized)
+             for (; !gsi_end_p (gsi); gsi_prev (&gsi))
+               if (gimple_plf (gsi_stmt (gsi), GF_PLF_1))
+                 break;
+             if (gsi_end_p (gsi))
                gsi = gsi_start_bb (bb);
              else
-               {
-                 gsi = prev;
-                 gsi_next (&gsi);
-               }
+               gsi_next (&gsi);
            }
          else
            {
-             prev = gsi;
-             prev_initialized = true;
+             /* Stmt no longer needs to be revisited.  */
+             gimple_set_plf (stmt, GF_PLF_1, true);
              gsi_next (&gsi);
            }
        }
@@ -2580,6 +3137,7 @@ struct gimple_opt_pass pass_forwprop =
  {
   GIMPLE_PASS,
   "forwprop",                  /* name */
+  OPTGROUP_NONE,                /* optinfo_flags */
   gate_forwprop,               /* gate */
   ssa_forward_propagate_and_combine,   /* execute */
   NULL,                                /* sub */