re PR libfortran/89020 (close(status='DELETE') does not remove file)
[gcc.git] / gcc / tree-if-conv.c
index cb535bc571bf8e2fae4a61c42c533c40eaf033fc..bdd4c2aa6c42721247664dc93c2beba3fd7d1a3e 100644 (file)
@@ -1,5 +1,5 @@
 /* If-conversion for vectorizer.
-   Copyright (C) 2004-2015 Free Software Foundation, Inc.
+   Copyright (C) 2004-2019 Free Software Foundation, Inc.
    Contributed by Devang Patel <dpatel@apple.com>
 
 This file is part of GCC.
@@ -83,75 +83,127 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "vec.h"
-#include "double-int.h"
-#include "input.h"
-#include "alias.h"
-#include "symtab.h"
-#include "wide-int.h"
-#include "inchash.h"
+#include "backend.h"
+#include "rtl.h"
 #include "tree.h"
+#include "gimple.h"
+#include "cfghooks.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "expmed.h"
+#include "optabs-query.h"
+#include "gimple-pretty-print.h"
+#include "alias.h"
 #include "fold-const.h"
 #include "stor-layout.h"
-#include "flags.h"
-#include "predict.h"
-#include "hard-reg-set.h"
-#include "function.h"
-#include "dominance.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple-pretty-print.h"
-#include "tree-ssa-alias.h"
-#include "internal-fn.h"
 #include "gimple-fold.h"
-#include "gimple-expr.h"
-#include "is-a.h"
-#include "gimple.h"
 #include "gimplify.h"
 #include "gimple-iterator.h"
 #include "gimplify-me.h"
-#include "gimple-ssa.h"
 #include "tree-cfg.h"
-#include "tree-phinodes.h"
-#include "ssa-iterators.h"
-#include "stringpool.h"
-#include "tree-ssanames.h"
 #include "tree-into-ssa.h"
 #include "tree-ssa.h"
 #include "cfgloop.h"
-#include "tree-chrec.h"
 #include "tree-data-ref.h"
 #include "tree-scalar-evolution.h"
+#include "tree-ssa-loop.h"
+#include "tree-ssa-loop-niter.h"
 #include "tree-ssa-loop-ivopts.h"
 #include "tree-ssa-address.h"
-#include "tree-pass.h"
 #include "dbgcnt.h"
-#include "hashtab.h"
-#include "rtl.h"
-#include "statistics.h"
-#include "real.h"
-#include "fixed-value.h"
-#include "insn-config.h"
-#include "expmed.h"
-#include "dojump.h"
-#include "explow.h"
-#include "calls.h"
-#include "emit-rtl.h"
+#include "tree-hash-traits.h"
 #include "varasm.h"
-#include "stmt.h"
-#include "expr.h"
-#include "insn-codes.h"
-#include "optabs.h"
+#include "builtins.h"
+#include "params.h"
+#include "cfganal.h"
+#include "internal-fn.h"
+#include "fold-const.h"
+#include "tree-ssa-sccvn.h"
+
+/* Only handle PHIs with no more arguments unless we are asked to by
+   simd pragma.  */
+#define MAX_PHI_ARG_NUM \
+  ((unsigned) PARAM_VALUE (PARAM_MAX_TREE_IF_CONVERSION_PHI_ARGS))
+
+/* True if we've converted a statement that was only executed when some
+   condition C was true, and if for correctness we need to predicate the
+   statement to ensure that it is a no-op when C is false.  See
+   predicate_statements for the kinds of predication we support.  */
+static bool need_to_predicate;
+
+/* Indicate if there are any complicated PHIs that need to be handled in
+   if-conversion.  Complicated PHI has more than two arguments and can't
+   be degenerated to two arguments PHI.  See more information in comment
+   before phi_convertible_by_degenerating_args.  */
+static bool any_complicated_phi;
+
+/* Hash for struct innermost_loop_behavior.  It depends on the user to
+   free the memory.  */
+
+struct innermost_loop_behavior_hash : nofree_ptr_hash <innermost_loop_behavior>
+{
+  static inline hashval_t hash (const value_type &);
+  static inline bool equal (const value_type &,
+                           const compare_type &);
+};
+
+inline hashval_t
+innermost_loop_behavior_hash::hash (const value_type &e)
+{
+  hashval_t hash;
+
+  hash = iterative_hash_expr (e->base_address, 0);
+  hash = iterative_hash_expr (e->offset, hash);
+  hash = iterative_hash_expr (e->init, hash);
+  return iterative_hash_expr (e->step, hash);
+}
+
+inline bool
+innermost_loop_behavior_hash::equal (const value_type &e1,
+                                    const compare_type &e2)
+{
+  if ((e1->base_address && !e2->base_address)
+      || (!e1->base_address && e2->base_address)
+      || (!e1->offset && e2->offset)
+      || (e1->offset && !e2->offset)
+      || (!e1->init && e2->init)
+      || (e1->init && !e2->init)
+      || (!e1->step && e2->step)
+      || (e1->step && !e2->step))
+    return false;
+
+  if (e1->base_address && e2->base_address
+      && !operand_equal_p (e1->base_address, e2->base_address, 0))
+    return false;
+  if (e1->offset && e2->offset
+      && !operand_equal_p (e1->offset, e2->offset, 0))
+    return false;
+  if (e1->init && e2->init
+      && !operand_equal_p (e1->init, e2->init, 0))
+    return false;
+  if (e1->step && e2->step
+      && !operand_equal_p (e1->step, e2->step, 0))
+    return false;
+
+  return true;
+}
 
 /* List of basic blocks in if-conversion-suitable order.  */
 static basic_block *ifc_bbs;
 
+/* Hash table to store <DR's innermost loop behavior, DR> pairs.  */
+static hash_map<innermost_loop_behavior_hash,
+               data_reference_p> *innermost_DR_map;
+
+/* Hash table to store <base reference, DR> pairs.  */
+static hash_map<tree_operand_hash, data_reference_p> *baseref_DR_map;
+
+/* List of redundant SSA names: the first should be replaced by the second.  */
+static vec< std::pair<tree, tree> > redundant_ssa_names;
+
 /* Structure used to predicate basic blocks.  This is attached to the
    ->aux field of the BBs in the loop to be if-converted.  */
-typedef struct bb_predicate_s {
+struct bb_predicate {
 
   /* The condition under which this basic block is executed.  */
   tree predicate;
@@ -160,7 +212,7 @@ typedef struct bb_predicate_s {
      recorded here, in order to avoid the duplication of computations
      that occur in previous conditions.  See PR44483.  */
   gimple_seq predicate_gimplified_stmts;
-} *bb_predicate_p;
+};
 
 /* Returns true when the basic block BB has a predicate.  */
 
@@ -175,7 +227,7 @@ bb_has_predicate (basic_block bb)
 static inline tree
 bb_predicate (basic_block bb)
 {
-  return ((bb_predicate_p) bb->aux)->predicate;
+  return ((struct bb_predicate *) bb->aux)->predicate;
 }
 
 /* Sets the gimplified predicate COND for basic block BB.  */
@@ -186,7 +238,7 @@ set_bb_predicate (basic_block bb, tree cond)
   gcc_assert ((TREE_CODE (cond) == TRUTH_NOT_EXPR
               && is_gimple_condexpr (TREE_OPERAND (cond, 0)))
              || is_gimple_condexpr (cond));
-  ((bb_predicate_p) bb->aux)->predicate = cond;
+  ((struct bb_predicate *) bb->aux)->predicate = cond;
 }
 
 /* Returns the sequence of statements of the gimplification of the
@@ -195,7 +247,7 @@ set_bb_predicate (basic_block bb, tree cond)
 static inline gimple_seq
 bb_predicate_gimplified_stmts (basic_block bb)
 {
-  return ((bb_predicate_p) bb->aux)->predicate_gimplified_stmts;
+  return ((struct bb_predicate *) bb->aux)->predicate_gimplified_stmts;
 }
 
 /* Sets the sequence of statements STMTS of the gimplification of the
@@ -204,7 +256,7 @@ bb_predicate_gimplified_stmts (basic_block bb)
 static inline void
 set_bb_predicate_gimplified_stmts (basic_block bb, gimple_seq stmts)
 {
-  ((bb_predicate_p) bb->aux)->predicate_gimplified_stmts = stmts;
+  ((struct bb_predicate *) bb->aux)->predicate_gimplified_stmts = stmts;
 }
 
 /* Adds the sequence of statements STMTS to the sequence of statements
@@ -213,8 +265,21 @@ set_bb_predicate_gimplified_stmts (basic_block bb, gimple_seq stmts)
 static inline void
 add_bb_predicate_gimplified_stmts (basic_block bb, gimple_seq stmts)
 {
-  gimple_seq_add_seq
-    (&(((bb_predicate_p) bb->aux)->predicate_gimplified_stmts), stmts);
+  /* We might have updated some stmts in STMTS via force_gimple_operand
+     calling fold_stmt and that producing multiple stmts.  Delink immediate
+     uses so update_ssa after loop versioning doesn't get confused for
+     the not yet inserted predicates.
+     ???  This should go away once we reliably avoid updating stmts
+     not in any BB.  */
+  for (gimple_stmt_iterator gsi = gsi_start (stmts);
+       !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      gimple *stmt = gsi_stmt (gsi);
+      delink_stmt_imm_use (stmt);
+      gimple_set_modified (stmt, true);
+    }
+  gimple_seq_add_seq_without_update
+    (&(((struct bb_predicate *) bb->aux)->predicate_gimplified_stmts), stmts);
 }
 
 /* Initializes to TRUE the predicate of basic block BB.  */
@@ -222,13 +287,12 @@ add_bb_predicate_gimplified_stmts (basic_block bb, gimple_seq stmts)
 static inline void
 init_bb_predicate (basic_block bb)
 {
-  bb->aux = XNEW (struct bb_predicate_s);
+  bb->aux = XNEW (struct bb_predicate);
   set_bb_predicate_gimplified_stmts (bb, NULL);
   set_bb_predicate (bb, boolean_true_node);
 }
 
-/* Release the SSA_NAMEs associated with the predicate of basic block BB,
-   but don't actually free it.  */
+/* Release the SSA_NAMEs associated with the predicate of basic block BB.  */
 
 static inline void
 release_bb_predicate (basic_block bb)
@@ -236,10 +300,14 @@ release_bb_predicate (basic_block bb)
   gimple_seq stmts = bb_predicate_gimplified_stmts (bb);
   if (stmts)
     {
-      gimple_stmt_iterator i;
-
-      for (i = gsi_start (stmts); !gsi_end_p (i); gsi_next (&i))
-       free_stmt_operands (cfun, gsi_stmt (i));
+      /* Ensure that these stmts haven't yet been added to a bb.  */
+      if (flag_checking)
+       for (gimple_stmt_iterator i = gsi_start (stmts);
+            !gsi_end_p (i); gsi_next (&i))
+         gcc_assert (! gimple_bb (gsi_stmt (i)));
+
+      /* Discard them.  */
+      gimple_seq_discard (stmts);
       set_bb_predicate_gimplified_stmts (bb, NULL);
     }
 }
@@ -280,11 +348,22 @@ static tree
 ifc_temp_var (tree type, tree expr, gimple_stmt_iterator *gsi)
 {
   tree new_name = make_temp_ssa_name (type, NULL, "_ifc_");
-  gimple stmt = gimple_build_assign (new_name, expr);
+  gimple *stmt = gimple_build_assign (new_name, expr);
+  gimple_set_vuse (stmt, gimple_vuse (gsi_stmt (*gsi)));
   gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
   return new_name;
 }
 
+/* Return true when COND is a false predicate.  */
+
+static inline bool
+is_false_predicate (tree cond)
+{
+  return (cond != NULL_TREE
+         && (cond == boolean_false_node
+             || integer_zerop (cond)));
+}
+
 /* Return true when COND is a true predicate.  */
 
 static inline bool
@@ -310,7 +389,7 @@ is_predicated (basic_block bb)
 static enum tree_code
 parse_predicate (tree cond, tree *op0, tree *op1)
 {
-  gimple s;
+  gimple *s;
 
   if (TREE_CODE (cond) == SSA_NAME
       && is_gimple_assign (s = SSA_NAME_DEF_STMT (cond)))
@@ -335,7 +414,7 @@ parse_predicate (tree cond, tree *op0, tree *op1)
       return ERROR_MARK;
     }
 
-  if (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison)
+  if (COMPARISON_CLASS_P (cond))
     {
       *op0 = TREE_OPERAND (cond, 0);
       *op1 = TREE_OPERAND (cond, 1);
@@ -365,24 +444,6 @@ fold_or_predicates (location_t loc, tree c1, tree c2)
   return fold_build2_loc (loc, TRUTH_OR_EXPR, boolean_type_node, c1, c2);
 }
 
-/* Returns true if N is either a constant or a SSA_NAME.  */
-
-static bool
-constant_or_ssa_name (tree n)
-{
-  switch (TREE_CODE (n))
-    {
-      case SSA_NAME:
-      case INTEGER_CST:
-      case REAL_CST:
-      case COMPLEX_CST:
-      case VECTOR_CST:
-       return true;
-      default:
-       return false;
-    }
-}
-
 /* Returns either a COND_EXPR or the folded expression if the folded
    expression is a MIN_EXPR, a MAX_EXPR, an ABS_EXPR,
    a constant or a SSA_NAME. */
@@ -391,22 +452,33 @@ static tree
 fold_build_cond_expr (tree type, tree cond, tree rhs, tree lhs)
 {
   tree rhs1, lhs1, cond_expr;
-  cond_expr = fold_ternary (COND_EXPR, type, cond,
-                           rhs, lhs);
+
+  /* If COND is comparison r != 0 and r has boolean type, convert COND
+     to SSA_NAME to accept by vect bool pattern.  */
+  if (TREE_CODE (cond) == NE_EXPR)
+    {
+      tree op0 = TREE_OPERAND (cond, 0);
+      tree op1 = TREE_OPERAND (cond, 1);
+      if (TREE_CODE (op0) == SSA_NAME
+         && TREE_CODE (TREE_TYPE (op0)) == BOOLEAN_TYPE
+         && (integer_zerop (op1)))
+       cond = op0;
+    }
+  cond_expr = fold_ternary (COND_EXPR, type, cond, rhs, lhs);
 
   if (cond_expr == NULL_TREE)
     return build3 (COND_EXPR, type, cond, rhs, lhs);
 
   STRIP_USELESS_TYPE_CONVERSION (cond_expr);
 
-  if (constant_or_ssa_name (cond_expr))
+  if (is_gimple_val (cond_expr))
     return cond_expr;
 
   if (TREE_CODE (cond_expr) == ABS_EXPR)
     {
       rhs1 = TREE_OPERAND (cond_expr, 1);
       STRIP_USELESS_TYPE_CONVERSION (rhs1);
-      if (constant_or_ssa_name (rhs1))
+      if (is_gimple_val (rhs1))
        return build1 (ABS_EXPR, type, rhs1);
     }
 
@@ -417,8 +489,7 @@ fold_build_cond_expr (tree type, tree cond, tree rhs, tree lhs)
       STRIP_USELESS_TYPE_CONVERSION (lhs1);
       rhs1 = TREE_OPERAND (cond_expr, 1);
       STRIP_USELESS_TYPE_CONVERSION (rhs1);
-      if (constant_or_ssa_name (rhs1)
-         && constant_or_ssa_name (lhs1))
+      if (is_gimple_val (rhs1) && is_gimple_val (lhs1))
        return build2 (TREE_CODE (cond_expr), type, lhs1, rhs1);
     }
   return build3 (COND_EXPR, type, cond, rhs, lhs);
@@ -505,7 +576,8 @@ add_to_dst_predicate_list (struct loop *loop, edge e,
     cond = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
                        prev_cond, cond);
 
-  add_to_predicate_list (loop, e->dest, cond);
+  if (!dominated_by_p (CDI_DOMINATORS, loop->latch, e->dest))
+    add_to_predicate_list (loop, e->dest, cond);
 }
 
 /* Return true if one of the successor edges of BB exits LOOP.  */
@@ -523,63 +595,84 @@ bb_with_exit_edge_p (struct loop *loop, basic_block bb)
   return false;
 }
 
-/* Return true when PHI is if-convertible.  PHI is part of loop LOOP
-   and it belongs to basic block BB.
+/* Given PHI which has more than two arguments, this function checks if
+   it's if-convertible by degenerating its arguments.  Specifically, if
+   below two conditions are satisfied:
+
+     1) Number of PHI arguments with different values equals to 2 and one
+       argument has the only occurrence.
+     2) The edge corresponding to the unique argument isn't critical edge.
+
+   Such PHI can be handled as PHIs have only two arguments.  For example,
+   below PHI:
 
-   PHI is not if-convertible if:
-   - it has more than 2 arguments.
+     res = PHI <A_1(e1), A_1(e2), A_2(e3)>;
 
-   When the flag_tree_loop_if_convert_stores is not set, PHI is not
-   if-convertible if:
-   - a virtual PHI is immediately used in another PHI node,
-   - there is a virtual PHI in a BB other than the loop->header.  */
+   can be transformed into:
+
+     res = (predicate of e3) ? A_2 : A_1;
+
+   Return TRUE if it is the case, FALSE otherwise.  */
 
 static bool
-if_convertible_phi_p (struct loop *loop, basic_block bb, gphi *phi,
-                     bool any_mask_load_store)
+phi_convertible_by_degenerating_args (gphi *phi)
 {
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "-------------------------\n");
-      print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
-    }
-
-  if (bb != loop->header && gimple_phi_num_args (phi) != 2)
-    {
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       fprintf (dump_file, "More than two phi node args.\n");
-      return false;
-    }
+  edge e;
+  tree arg, t1 = NULL, t2 = NULL;
+  unsigned int i, i1 = 0, i2 = 0, n1 = 0, n2 = 0;
+  unsigned int num_args = gimple_phi_num_args (phi);
 
-  if (flag_tree_loop_if_convert_stores || any_mask_load_store)
-    return true;
+  gcc_assert (num_args > 2);
 
-  /* When the flag_tree_loop_if_convert_stores is not set, check
-     that there are no memory writes in the branches of the loop to be
-     if-converted.  */
-  if (virtual_operand_p (gimple_phi_result (phi)))
+  for (i = 0; i < num_args; i++)
     {
-      imm_use_iterator imm_iter;
-      use_operand_p use_p;
-
-      if (bb != loop->header)
+      arg = gimple_phi_arg_def (phi, i);
+      if (t1 == NULL || operand_equal_p (t1, arg, 0))
        {
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           fprintf (dump_file, "Virtual phi not on loop->header.\n");
-         return false;
+         n1++;
+         i1 = i;
+         t1 = arg;
        }
-
-      FOR_EACH_IMM_USE_FAST (use_p, imm_iter, gimple_phi_result (phi))
+      else if (t2 == NULL || operand_equal_p (t2, arg, 0))
        {
-         if (gimple_code (USE_STMT (use_p)) == GIMPLE_PHI)
-           {
-             if (dump_file && (dump_flags & TDF_DETAILS))
-               fprintf (dump_file, "Difficult to handle this virtual phi.\n");
-             return false;
-           }
+         n2++;
+         i2 = i;
+         t2 = arg;
        }
+      else
+       return false;
+    }
+
+  if (n1 != 1 && n2 != 1)
+    return false;
+
+  /* Check if the edge corresponding to the unique arg is critical.  */
+  e = gimple_phi_arg_edge (phi, (n1 == 1) ? i1 : i2);
+  if (EDGE_COUNT (e->src->succs) > 1)
+    return false;
+
+  return true;
+}
+
+/* Return true when PHI is if-convertible.  PHI is part of loop LOOP
+   and it belongs to basic block BB.  Note at this point, it is sure
+   that PHI is if-convertible.  This function updates global variable
+   ANY_COMPLICATED_PHI if PHI is complicated.  */
+
+static bool
+if_convertible_phi_p (struct loop *loop, basic_block bb, gphi *phi)
+{
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "-------------------------\n");
+      print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
     }
 
+  if (bb != loop->header
+      && gimple_phi_num_args (phi) > 2
+      && !phi_convertible_by_degenerating_args (phi))
+    any_complicated_phi = true;
+
   return true;
 }
 
@@ -587,144 +680,168 @@ if_convertible_phi_p (struct loop *loop, basic_block bb, gphi *phi,
    each DR->aux field.  */
 
 struct ifc_dr {
-  /* -1 when not initialized, 0 when false, 1 when true.  */
-  int written_at_least_once;
+  bool rw_unconditionally;
+  bool w_unconditionally;
+  bool written_at_least_once;
 
-  /* -1 when not initialized, 0 when false, 1 when true.  */
-  int rw_unconditionally;
+  tree rw_predicate;
+  tree w_predicate;
+  tree base_w_predicate;
 };
 
 #define IFC_DR(DR) ((struct ifc_dr *) (DR)->aux)
-#define DR_WRITTEN_AT_LEAST_ONCE(DR) (IFC_DR (DR)->written_at_least_once)
+#define DR_BASE_W_UNCONDITIONALLY(DR) (IFC_DR (DR)->written_at_least_once)
 #define DR_RW_UNCONDITIONALLY(DR) (IFC_DR (DR)->rw_unconditionally)
+#define DR_W_UNCONDITIONALLY(DR) (IFC_DR (DR)->w_unconditionally)
+
+/* Iterates over DR's and stores refs, DR and base refs, DR pairs in
+   HASH tables.  While storing them in HASH table, it checks if the
+   reference is unconditionally read or written and stores that as a flag
+   information.  For base reference it checks if it is written atlest once
+   unconditionally and stores it as flag information along with DR.
+   In other words for every data reference A in STMT there exist other
+   accesses to a data reference with the same base with predicates that
+   add up (OR-up) to the true predicate: this ensures that the data
+   reference A is touched (read or written) on every iteration of the
+   if-converted loop.  */
+static void
+hash_memrefs_baserefs_and_store_DRs_read_written_info (data_reference_p a)
+{
+
+  data_reference_p *master_dr, *base_master_dr;
+  tree base_ref = DR_BASE_OBJECT (a);
+  innermost_loop_behavior *innermost = &DR_INNERMOST (a);
+  tree ca = bb_predicate (gimple_bb (DR_STMT (a)));
+  bool exist1, exist2;
+
+  master_dr = &innermost_DR_map->get_or_insert (innermost, &exist1);
+  if (!exist1)
+    *master_dr = a;
+
+  if (DR_IS_WRITE (a))
+    {
+      IFC_DR (*master_dr)->w_predicate
+       = fold_or_predicates (UNKNOWN_LOCATION, ca,
+                             IFC_DR (*master_dr)->w_predicate);
+      if (is_true_predicate (IFC_DR (*master_dr)->w_predicate))
+       DR_W_UNCONDITIONALLY (*master_dr) = true;
+    }
+  IFC_DR (*master_dr)->rw_predicate
+    = fold_or_predicates (UNKNOWN_LOCATION, ca,
+                         IFC_DR (*master_dr)->rw_predicate);
+  if (is_true_predicate (IFC_DR (*master_dr)->rw_predicate))
+    DR_RW_UNCONDITIONALLY (*master_dr) = true;
 
-/* Returns true when the memory references of STMT are read or written
-   unconditionally.  In other words, this function returns true when
-   for every data reference A in STMT there exist other accesses to
-   a data reference with the same base with predicates that add up (OR-up) to
-   the true predicate: this ensures that the data reference A is touched
-   (read or written) on every iteration of the if-converted loop.  */
+  if (DR_IS_WRITE (a))
+    {
+      base_master_dr = &baseref_DR_map->get_or_insert (base_ref, &exist2);
+      if (!exist2)
+       *base_master_dr = a;
+      IFC_DR (*base_master_dr)->base_w_predicate
+       = fold_or_predicates (UNKNOWN_LOCATION, ca,
+                             IFC_DR (*base_master_dr)->base_w_predicate);
+      if (is_true_predicate (IFC_DR (*base_master_dr)->base_w_predicate))
+       DR_BASE_W_UNCONDITIONALLY (*base_master_dr) = true;
+    }
+}
+
+/* Return TRUE if can prove the index IDX of an array reference REF is
+   within array bound.  Return false otherwise.  */
 
 static bool
-memrefs_read_or_written_unconditionally (gimple stmt,
-                                        vec<data_reference_p> drs)
+idx_within_array_bound (tree ref, tree *idx, void *dta)
 {
-  int i, j;
-  data_reference_p a, b;
-  tree ca = bb_predicate (gimple_bb (stmt));
+  wi::overflow_type overflow;
+  widest_int niter, valid_niter, delta, wi_step;
+  tree ev, init, step;
+  tree low, high;
+  struct loop *loop = (struct loop*) dta;
+
+  /* Only support within-bound access for array references.  */
+  if (TREE_CODE (ref) != ARRAY_REF)
+    return false;
 
-  for (i = 0; drs.iterate (i, &a); i++)
-    if (DR_STMT (a) == stmt)
-      {
-       bool found = false;
-       int x = DR_RW_UNCONDITIONALLY (a);
+  /* For arrays at the end of the structure, we are not guaranteed that they
+     do not really extend over their declared size.  However, for arrays of
+     size greater than one, this is unlikely to be intended.  */
+  if (array_at_struct_end_p (ref))
+    return false;
 
-       if (x == 0)
-         return false;
+  ev = analyze_scalar_evolution (loop, *idx);
+  ev = instantiate_parameters (loop, ev);
+  init = initial_condition (ev);
+  step = evolution_part_in_loop_num (ev, loop->num);
 
-       if (x == 1)
-         continue;
+  if (!init || TREE_CODE (init) != INTEGER_CST
+      || (step && TREE_CODE (step) != INTEGER_CST))
+    return false;
 
-       for (j = 0; drs.iterate (j, &b); j++)
-          {
-            tree ref_base_a = DR_REF (a);
-            tree ref_base_b = DR_REF (b);
+  low = array_ref_low_bound (ref);
+  high = array_ref_up_bound (ref);
 
-            if (DR_STMT (b) == stmt)
-              continue;
+  /* The case of nonconstant bounds could be handled, but it would be
+     complicated.  */
+  if (TREE_CODE (low) != INTEGER_CST
+      || !high || TREE_CODE (high) != INTEGER_CST)
+    return false;
 
-            while (TREE_CODE (ref_base_a) == COMPONENT_REF
-                   || TREE_CODE (ref_base_a) == IMAGPART_EXPR
-                   || TREE_CODE (ref_base_a) == REALPART_EXPR)
-              ref_base_a = TREE_OPERAND (ref_base_a, 0);
+  /* Check if the intial idx is within bound.  */
+  if (wi::to_widest (init) < wi::to_widest (low)
+      || wi::to_widest (init) > wi::to_widest (high))
+    return false;
 
-            while (TREE_CODE (ref_base_b) == COMPONENT_REF
-                   || TREE_CODE (ref_base_b) == IMAGPART_EXPR
-                   || TREE_CODE (ref_base_b) == REALPART_EXPR)
-              ref_base_b = TREE_OPERAND (ref_base_b, 0);
+  /* The idx is always within bound.  */
+  if (!step || integer_zerop (step))
+    return true;
 
-           if (!operand_equal_p (ref_base_a, ref_base_b, 0))
-             {
-               tree cb = bb_predicate (gimple_bb (DR_STMT (b)));
-
-               if (DR_RW_UNCONDITIONALLY (b) == 1
-                   || is_true_predicate (cb)
-                   || is_true_predicate (ca
-                        = fold_or_predicates (EXPR_LOCATION (cb), ca, cb)))
-                 {
-                   DR_RW_UNCONDITIONALLY (a) = 1;
-                   DR_RW_UNCONDITIONALLY (b) = 1;
-                   found = true;
-                   break;
-                 }
-               }
-           }
+  if (!max_loop_iterations (loop, &niter))
+    return false;
 
-       if (!found)
-         {
-           DR_RW_UNCONDITIONALLY (a) = 0;
-           return false;
-         }
-      }
+  if (wi::to_widest (step) < 0)
+    {
+      delta = wi::to_widest (init) - wi::to_widest (low);
+      wi_step = -wi::to_widest (step);
+    }
+  else
+    {
+      delta = wi::to_widest (high) - wi::to_widest (init);
+      wi_step = wi::to_widest (step);
+    }
 
-  return true;
+  valid_niter = wi::div_floor (delta, wi_step, SIGNED, &overflow);
+  /* The iteration space of idx is within array bound.  */
+  if (!overflow && niter <= valid_niter)
+    return true;
+
+  return false;
 }
 
-/* Returns true when the memory references of STMT are unconditionally
-   written.  In other words, this function returns true when for every
-   data reference A written in STMT, there exist other writes to the
-   same data reference with predicates that add up (OR-up) to the true
-   predicate: this ensures that the data reference A is written on
-   every iteration of the if-converted loop.  */
+/* Return TRUE if ref is a within bound array reference.  */
 
 static bool
-write_memrefs_written_at_least_once (gimple stmt,
-                                    vec<data_reference_p> drs)
+ref_within_array_bound (gimple *stmt, tree ref)
 {
-  int i, j;
-  data_reference_p a, b;
-  tree ca = bb_predicate (gimple_bb (stmt));
-
-  for (i = 0; drs.iterate (i, &a); i++)
-    if (DR_STMT (a) == stmt
-       && DR_IS_WRITE (a))
-      {
-       bool found = false;
-       int x = DR_WRITTEN_AT_LEAST_ONCE (a);
-
-       if (x == 0)
-         return false;
+  struct loop *loop = loop_containing_stmt (stmt);
 
-       if (x == 1)
-         continue;
+  gcc_assert (loop != NULL);
+  return for_each_index (&ref, idx_within_array_bound, loop);
+}
 
-       for (j = 0; drs.iterate (j, &b); j++)
-         if (DR_STMT (b) != stmt
-             && DR_IS_WRITE (b)
-             && same_data_refs_base_objects (a, b))
-           {
-             tree cb = bb_predicate (gimple_bb (DR_STMT (b)));
 
-             if (DR_WRITTEN_AT_LEAST_ONCE (b) == 1
-                 || is_true_predicate (cb)
-                 || is_true_predicate (ca = fold_or_predicates (EXPR_LOCATION (cb),
-                                                                ca, cb)))
-               {
-                 DR_WRITTEN_AT_LEAST_ONCE (a) = 1;
-                 DR_WRITTEN_AT_LEAST_ONCE (b) = 1;
-                 found = true;
-                 break;
-               }
-           }
+/* Given a memory reference expression T, return TRUE if base object
+   it refers to is writable.  The base object of a memory reference
+   is the main object being referenced, which is returned by function
+   get_base_address.  */
 
-       if (!found)
-         {
-           DR_WRITTEN_AT_LEAST_ONCE (a) = 0;
-           return false;
-         }
-      }
+static bool
+base_object_writable (tree ref)
+{
+  tree base_tree = get_base_address (ref);
 
-  return true;
+  return (base_tree
+         && DECL_P (base_tree)
+         && decl_binds_to_current_def_p (base_tree)
+         && !TREE_READONLY (base_tree));
 }
 
 /* Return true when the memory references of STMT won't trap in the
@@ -743,49 +860,77 @@ write_memrefs_written_at_least_once (gimple stmt,
    iteration.  To check that the memory accesses are correctly formed
    and that we are allowed to read and write in these locations, we
    check that the memory accesses to be if-converted occur at every
-   iteration unconditionally.  */
-
+   iteration unconditionally.
+
+   Returns true for the memory reference in STMT, same memory reference
+   is read or written unconditionally atleast once and the base memory
+   reference is written unconditionally once.  This is to check reference
+   will not write fault.  Also retuns true if the memory reference is
+   unconditionally read once then we are conditionally writing to memory
+   which is defined as read and write and is bound to the definition
+   we are seeing.  */
 static bool
-ifcvt_memrefs_wont_trap (gimple stmt, vec<data_reference_p> refs)
+ifcvt_memrefs_wont_trap (gimple *stmt, vec<data_reference_p> drs)
 {
-  return write_memrefs_written_at_least_once (stmt, refs)
-    && memrefs_read_or_written_unconditionally (stmt, refs);
-}
+  /* If DR didn't see a reference here we can't use it to tell
+     whether the ref traps or not.  */
+  if (gimple_uid (stmt) == 0)
+    return false;
 
-/* Wrapper around gimple_could_trap_p refined for the needs of the
-   if-conversion.  Try to prove that the memory accesses of STMT could
-   not trap in the innermost loop containing STMT.  */
+  data_reference_p *master_dr, *base_master_dr;
+  data_reference_p a = drs[gimple_uid (stmt) - 1];
 
-static bool
-ifcvt_could_trap_p (gimple stmt, vec<data_reference_p> refs)
-{
-  if (gimple_vuse (stmt)
-      && !gimple_could_trap_p_1 (stmt, false, false)
-      && ifcvt_memrefs_wont_trap (stmt, refs))
-    return false;
+  tree base = DR_BASE_OBJECT (a);
+  innermost_loop_behavior *innermost = &DR_INNERMOST (a);
+
+  gcc_assert (DR_STMT (a) == stmt);
+  gcc_assert (DR_BASE_ADDRESS (a) || DR_OFFSET (a)
+              || DR_INIT (a) || DR_STEP (a));
+
+  master_dr = innermost_DR_map->get (innermost);
+  gcc_assert (master_dr != NULL);
+
+  base_master_dr = baseref_DR_map->get (base);
+
+  /* If a is unconditionally written to it doesn't trap.  */
+  if (DR_W_UNCONDITIONALLY (*master_dr))
+    return true;
+
+  /* If a is unconditionally accessed then ...
+
+     Even a is conditional access, we can treat it as an unconditional
+     one if it's an array reference and all its index are within array
+     bound.  */
+  if (DR_RW_UNCONDITIONALLY (*master_dr)
+      || ref_within_array_bound (stmt, DR_REF (a)))
+    {
+      /* an unconditional read won't trap.  */
+      if (DR_IS_READ (a))
+       return true;
+
+      /* an unconditionaly write won't trap if the base is written
+         to unconditionally.  */
+      if (base_master_dr
+         && DR_BASE_W_UNCONDITIONALLY (*base_master_dr))
+       return PARAM_VALUE (PARAM_ALLOW_STORE_DATA_RACES);
+      /* or the base is known to be not readonly.  */
+      else if (base_object_writable (DR_REF (a)))
+       return PARAM_VALUE (PARAM_ALLOW_STORE_DATA_RACES);
+    }
 
-  return gimple_could_trap_p (stmt);
+  return false;
 }
 
 /* Return true if STMT could be converted into a masked load or store
    (conditional load or store based on a mask computed from bb predicate).  */
 
 static bool
-ifcvt_can_use_mask_load_store (gimple stmt)
+ifcvt_can_use_mask_load_store (gimple *stmt)
 {
-  tree lhs, ref;
-  machine_mode mode;
-  basic_block bb = gimple_bb (stmt);
-  bool is_load;
-
-  if (!(flag_tree_loop_vectorize || bb->loop_father->force_vectorize)
-      || bb->loop_father->dont_vectorize
-      || !gimple_assign_single_p (stmt)
-      || gimple_has_volatile_ops (stmt))
-    return false;
-
   /* Check whether this is a load or store.  */
-  lhs = gimple_assign_lhs (stmt);
+  tree lhs = gimple_assign_lhs (stmt);
+  bool is_load;
+  tree ref;
   if (gimple_store_p (stmt))
     {
       if (!is_gimple_val (gimple_assign_rhs1 (stmt)))
@@ -806,17 +951,42 @@ ifcvt_can_use_mask_load_store (gimple stmt)
 
   /* Mask should be integer mode of the same size as the load/store
      mode.  */
-  mode = TYPE_MODE (TREE_TYPE (lhs));
-  if (int_mode_for_mode (mode) == BLKmode
-      || VECTOR_MODE_P (mode))
+  machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
+  if (!int_mode_for_mode (mode).exists () || VECTOR_MODE_P (mode))
     return false;
 
-  if (can_vec_mask_load_store_p (mode, is_load))
+  if (can_vec_mask_load_store_p (mode, VOIDmode, is_load))
     return true;
 
   return false;
 }
 
+/* Return true if STMT could be converted from an operation that is
+   unconditional to one that is conditional on a bb predicate mask.  */
+
+static bool
+ifcvt_can_predicate (gimple *stmt)
+{
+  basic_block bb = gimple_bb (stmt);
+
+  if (!(flag_tree_loop_vectorize || bb->loop_father->force_vectorize)
+      || bb->loop_father->dont_vectorize
+      || gimple_has_volatile_ops (stmt))
+    return false;
+
+  if (gimple_assign_single_p (stmt))
+    return ifcvt_can_use_mask_load_store (stmt);
+
+  tree_code code = gimple_assign_rhs_code (stmt);
+  tree lhs_type = TREE_TYPE (gimple_assign_lhs (stmt));
+  tree rhs_type = TREE_TYPE (gimple_assign_rhs1 (stmt));
+  if (!types_compatible_p (lhs_type, rhs_type))
+    return false;
+  internal_fn cond_fn = get_conditional_internal_fn (code);
+  return (cond_fn != IFN_LAST
+         && vectorized_internal_fn_supported_p (cond_fn, lhs_type));
+}
+
 /* Return true when STMT is if-convertible.
 
    GIMPLE_ASSIGN statement is not if-convertible if,
@@ -825,12 +995,10 @@ ifcvt_can_use_mask_load_store (gimple stmt)
    - LHS is not var decl.  */
 
 static bool
-if_convertible_gimple_assign_stmt_p (gimple stmt,
-                                    vec<data_reference_p> refs,
-                                    bool *any_mask_load_store)
+if_convertible_gimple_assign_stmt_p (gimple *stmt,
+                                    vec<data_reference_p> refs)
 {
   tree lhs = gimple_assign_lhs (stmt);
-  basic_block bb;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -858,29 +1026,15 @@ if_convertible_gimple_assign_stmt_p (gimple stmt,
      we can perform loop versioning.  */
   gimple_set_plf (stmt, GF_PLF_2, false);
 
-  if (flag_tree_loop_if_convert_stores)
-    {
-      if (ifcvt_could_trap_p (stmt, refs))
-       {
-         if (ifcvt_can_use_mask_load_store (stmt))
-           {
-             gimple_set_plf (stmt, GF_PLF_2, true);
-             *any_mask_load_store = true;
-             return true;
-           }
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           fprintf (dump_file, "tree could trap...\n");
-         return false;
-       }
-      return true;
-    }
-
-  if (gimple_assign_rhs_could_trap_p (stmt))
+  if ((! gimple_vuse (stmt)
+       || gimple_could_trap_p_1 (stmt, false, false)
+       || ! ifcvt_memrefs_wont_trap (stmt, refs))
+      && gimple_could_trap_p (stmt))
     {
-      if (ifcvt_can_use_mask_load_store (stmt))
+      if (ifcvt_can_predicate (stmt))
        {
          gimple_set_plf (stmt, GF_PLF_2, true);
-         *any_mask_load_store = true;
+         need_to_predicate = true;
          return true;
        }
       if (dump_file && (dump_flags & TDF_DETAILS))
@@ -888,25 +1042,10 @@ if_convertible_gimple_assign_stmt_p (gimple stmt,
       return false;
     }
 
-  bb = gimple_bb (stmt);
-
-  if (TREE_CODE (lhs) != SSA_NAME
-      && bb != bb->loop_father->header
-      && !bb_with_exit_edge_p (bb->loop_father, bb))
-    {
-      if (ifcvt_can_use_mask_load_store (stmt))
-       {
-         gimple_set_plf (stmt, GF_PLF_2, true);
-         *any_mask_load_store = true;
-         return true;
-       }
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       {
-         fprintf (dump_file, "LHS is not var\n");
-         print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
-       }
-      return false;
-    }
+  /* When if-converting stores force versioning, likewise if we
+     ended up generating store data races.  */
+  if (gimple_vdef (stmt))
+    need_to_predicate = true;
 
   return true;
 }
@@ -915,11 +1054,11 @@ if_convertible_gimple_assign_stmt_p (gimple stmt,
 
    A statement is if-convertible if:
    - it is an if-convertible GIMPLE_ASSIGN,
-   - it is a GIMPLE_LABEL or a GIMPLE_COND.  */
+   - it is a GIMPLE_LABEL or a GIMPLE_COND,
+   - it is builtins call.  */
 
 static bool
-if_convertible_stmt_p (gimple stmt, vec<data_reference_p> refs,
-                      bool *any_mask_load_store)
+if_convertible_stmt_p (gimple *stmt, vec<data_reference_p> refs)
 {
   switch (gimple_code (stmt))
     {
@@ -929,8 +1068,7 @@ if_convertible_stmt_p (gimple stmt, vec<data_reference_p> refs,
       return true;
 
     case GIMPLE_ASSIGN:
-      return if_convertible_gimple_assign_stmt_p (stmt, refs,
-                                                 any_mask_load_store);
+      return if_convertible_gimple_assign_stmt_p (stmt, refs);
 
     case GIMPLE_CALL:
       {
@@ -942,7 +1080,7 @@ if_convertible_stmt_p (gimple stmt, vec<data_reference_p> refs,
                && !(flags & ECF_LOOPING_CONST_OR_PURE)
                /* We can only vectorize some builtins at the moment,
                   so restrict if-conversion to those.  */
-               && DECL_BUILT_IN (fndecl))
+               && fndecl_built_in_p (fndecl))
              return true;
          }
        return false;
@@ -956,12 +1094,27 @@ if_convertible_stmt_p (gimple stmt, vec<data_reference_p> refs,
          print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
        }
       return false;
-      break;
     }
 
   return true;
 }
 
+/* Assumes that BB has more than 1 predecessors.
+   Returns false if at least one successor is not on critical edge
+   and true otherwise.  */
+
+static inline bool
+all_preds_critical_p (basic_block bb)
+{
+  edge e;
+  edge_iterator ei;
+
+  FOR_EACH_EDGE (e, ei, bb->preds)
+    if (EDGE_COUNT (e->src->succs) == 1)
+      return false;
+  return true;
+}
+
 /* Return true when BB is if-convertible.  This routine does not check
    basic block's statements and phis.
 
@@ -982,8 +1135,7 @@ if_convertible_bb_p (struct loop *loop, basic_block bb, basic_block exit_bb)
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "----------[%d]-------------\n", bb->index);
 
-  if (EDGE_COUNT (bb->preds) > 2
-      || EDGE_COUNT (bb->succs) > 2)
+  if (EDGE_COUNT (bb->succs) > 2)
     return false;
 
   if (exit_bb)
@@ -1019,24 +1171,6 @@ if_convertible_bb_p (struct loop *loop, basic_block bb, basic_block exit_bb)
        return false;
       }
 
-  /* At least one incoming edge has to be non-critical as otherwise edge
-     predicates are not equal to basic-block predicates of the edge
-     source.  */
-  if (EDGE_COUNT (bb->preds) > 1
-      && bb != loop->header)
-    {
-      bool found = false;
-      FOR_EACH_EDGE (e, ei, bb->preds)
-       if (EDGE_COUNT (e->src->succs) == 1)
-         found = true;
-      if (!found)
-       {
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           fprintf (dump_file, "only critical predecessors\n");
-         return false;
-       }
-    }
-
   return true;
 }
 
@@ -1144,13 +1278,14 @@ predicate_bbs (loop_p loop)
     {
       basic_block bb = ifc_bbs[i];
       tree cond;
-      gimple stmt;
+      gimple *stmt;
 
-      /* The loop latch is always executed and has no extra conditions
-        to be processed: skip it.  */
-      if (bb == loop->latch)
+      /* The loop latch and loop exit block are always executed and
+        have no extra conditions to be processed: skip them.  */
+      if (bb == loop->latch
+         || bb_with_exit_edge_p (loop, bb))
        {
-         reset_bb_predicate (loop->latch);
+         reset_bb_predicate (bb);
          continue;
        }
 
@@ -1161,7 +1296,7 @@ predicate_bbs (loop_p loop)
          tree c2;
          edge true_edge, false_edge;
          location_t loc = gimple_location (stmt);
-         tree c = fold_build2_loc (loc, gimple_cond_code (stmt),
+         tree c = build2_loc (loc, gimple_cond_code (stmt),
                                    boolean_type_node,
                                    gimple_cond_lhs (stmt),
                                    gimple_cond_rhs (stmt));
@@ -1205,28 +1340,53 @@ predicate_bbs (loop_p loop)
              && bb_predicate_gimplified_stmts (loop->latch) == NULL);
 }
 
+/* Build region by adding loop pre-header and post-header blocks.  */
+
+static vec<basic_block>
+build_region (struct loop *loop)
+{
+  vec<basic_block> region = vNULL;
+  basic_block exit_bb = NULL;
+
+  gcc_assert (ifc_bbs);
+  /* The first element is loop pre-header.  */
+  region.safe_push (loop_preheader_edge (loop)->src);
+
+  for (unsigned int i = 0; i < loop->num_nodes; i++)
+    {
+      basic_block bb = ifc_bbs[i];
+      region.safe_push (bb);
+      /* Find loop postheader.  */
+      edge e;
+      edge_iterator ei;
+      FOR_EACH_EDGE (e, ei, bb->succs)
+       if (loop_exit_edge_p (loop, e))
+         {
+             exit_bb = e->dest;
+             break;
+         }
+    }
+  /* The last element is loop post-header.  */
+  gcc_assert (exit_bb);
+  region.safe_push (exit_bb);
+  return region;
+}
+
 /* Return true when LOOP is if-convertible.  This is a helper function
    for if_convertible_loop_p.  REFS and DDRS are initialized and freed
    in if_convertible_loop_p.  */
 
 static bool
-if_convertible_loop_p_1 (struct loop *loop,
-                        vec<loop_p> *loop_nest,
-                        vec<data_reference_p> *refs,
-                        vec<ddr_p> *ddrs, bool *any_mask_load_store)
+if_convertible_loop_p_1 (struct loop *loop, vec<data_reference_p> *refs)
 {
-  bool res;
   unsigned int i;
   basic_block exit_bb = NULL;
+  vec<basic_block> region;
 
-  /* Don't if-convert the loop when the data dependences cannot be
-     computed: the loop won't be vectorized in that case.  */
-  res = compute_data_dependences_for_loop (loop, true, loop_nest, refs, ddrs);
-  if (!res)
+  if (find_data_references_in_loop (loop, refs) == chrec_dont_know)
     return false;
 
   calculate_dominance_info (CDI_DOMINATORS);
-  calculate_dominance_info (CDI_POST_DOMINATORS);
 
   /* Allow statements that can be handled during if-conversion.  */
   ifc_bbs = get_loop_body_in_if_conv_order (loop);
@@ -1261,23 +1421,61 @@ if_convertible_loop_p_1 (struct loop *loop,
          case GIMPLE_CALL:
          case GIMPLE_DEBUG:
          case GIMPLE_COND:
+           gimple_set_uid (gsi_stmt (gsi), 0);
            break;
          default:
            return false;
          }
     }
 
-  if (flag_tree_loop_if_convert_stores)
-    {
-      data_reference_p dr;
+  data_reference_p dr;
 
-      for (i = 0; refs->iterate (i, &dr); i++)
-       {
-         dr->aux = XNEW (struct ifc_dr);
-         DR_WRITTEN_AT_LEAST_ONCE (dr) = -1;
-         DR_RW_UNCONDITIONALLY (dr) = -1;
-       }
-      predicate_bbs (loop);
+  innermost_DR_map
+         = new hash_map<innermost_loop_behavior_hash, data_reference_p>;
+  baseref_DR_map = new hash_map<tree_operand_hash, data_reference_p>;
+
+  /* Compute post-dominator tree locally.  */
+  region = build_region (loop);
+  calculate_dominance_info_for_region (CDI_POST_DOMINATORS, region);
+
+  predicate_bbs (loop);
+
+  /* Free post-dominator tree since it is not used after predication.  */
+  free_dominance_info_for_region (cfun, CDI_POST_DOMINATORS, region);
+  region.release ();
+
+  for (i = 0; refs->iterate (i, &dr); i++)
+    {
+      tree ref = DR_REF (dr);
+
+      dr->aux = XNEW (struct ifc_dr);
+      DR_BASE_W_UNCONDITIONALLY (dr) = false;
+      DR_RW_UNCONDITIONALLY (dr) = false;
+      DR_W_UNCONDITIONALLY (dr) = false;
+      IFC_DR (dr)->rw_predicate = boolean_false_node;
+      IFC_DR (dr)->w_predicate = boolean_false_node;
+      IFC_DR (dr)->base_w_predicate = boolean_false_node;
+      if (gimple_uid (DR_STMT (dr)) == 0)
+       gimple_set_uid (DR_STMT (dr), i + 1);
+
+      /* If DR doesn't have innermost loop behavior or it's a compound
+         memory reference, we synthesize its innermost loop behavior
+         for hashing.  */
+      if (TREE_CODE (ref) == COMPONENT_REF
+          || TREE_CODE (ref) == IMAGPART_EXPR
+          || TREE_CODE (ref) == REALPART_EXPR
+          || !(DR_BASE_ADDRESS (dr) || DR_OFFSET (dr)
+              || DR_INIT (dr) || DR_STEP (dr)))
+        {
+          while (TREE_CODE (ref) == COMPONENT_REF
+                || TREE_CODE (ref) == IMAGPART_EXPR
+                || TREE_CODE (ref) == REALPART_EXPR)
+           ref = TREE_OPERAND (ref, 0);
+
+         memset (&DR_INNERMOST (dr), 0, sizeof (DR_INNERMOST (dr)));
+         DR_BASE_ADDRESS (dr) = ref;
+        }
+      hash_memrefs_baserefs_and_store_DRs_read_written_info (dr);
     }
 
   for (i = 0; i < loop->num_nodes; i++)
@@ -1288,15 +1486,10 @@ if_convertible_loop_p_1 (struct loop *loop,
       /* Check the if-convertibility of statements in predicated BBs.  */
       if (!dominated_by_p (CDI_DOMINATORS, loop->latch, bb))
        for (itr = gsi_start_bb (bb); !gsi_end_p (itr); gsi_next (&itr))
-         if (!if_convertible_stmt_p (gsi_stmt (itr), *refs,
-                                     any_mask_load_store))
+         if (!if_convertible_stmt_p (gsi_stmt (itr), *refs))
            return false;
     }
 
-  if (flag_tree_loop_if_convert_stores)
-    for (i = 0; i < loop->num_nodes; i++)
-      free_bb_predicate (ifc_bbs[i]);
-
   /* Checking PHIs needs to be done after stmts, as the fact whether there
      are any masked loads or stores affects the tests.  */
   for (i = 0; i < loop->num_nodes; i++)
@@ -1305,8 +1498,7 @@ if_convertible_loop_p_1 (struct loop *loop,
       gphi_iterator itr;
 
       for (itr = gsi_start_phis (bb); !gsi_end_p (itr); gsi_next (&itr))
-       if (!if_convertible_phi_p (loop, bb, itr.phi (),
-                                  *any_mask_load_store))
+       if (!if_convertible_phi_p (loop, bb, itr.phi ()))
          return false;
     }
 
@@ -1325,13 +1517,12 @@ if_convertible_loop_p_1 (struct loop *loop,
    - if its basic blocks and phi nodes are if convertible.  */
 
 static bool
-if_convertible_loop_p (struct loop *loop, bool *any_mask_load_store)
+if_convertible_loop_p (struct loop *loop)
 {
   edge e;
   edge_iterator ei;
   bool res = false;
   vec<data_reference_p> refs;
-  vec<ddr_p> ddrs;
 
   /* Handle only innermost loop.  */
   if (!loop || loop->inner)
@@ -1364,77 +1555,22 @@ if_convertible_loop_p (struct loop *loop, bool *any_mask_load_store)
       return false;
 
   refs.create (5);
-  ddrs.create (25);
-  auto_vec<loop_p, 3> loop_nest;
-  res = if_convertible_loop_p_1 (loop, &loop_nest, &refs, &ddrs,
-                                any_mask_load_store);
-
-  if (flag_tree_loop_if_convert_stores)
-    {
-      data_reference_p dr;
-      unsigned int i;
+  res = if_convertible_loop_p_1 (loop, &refs);
 
-      for (i = 0; refs.iterate (i, &dr); i++)
-       free (dr->aux);
-    }
+  data_reference_p dr;
+  unsigned int i;
+  for (i = 0; refs.iterate (i, &dr); i++)
+    free (dr->aux);
 
   free_data_refs (refs);
-  free_dependence_relations (ddrs);
-  return res;
-}
 
-/* Basic block BB has two predecessors.  Using predecessor's bb
-   predicate, set an appropriate condition COND for the PHI node
-   replacement.  Return the true block whose phi arguments are
-   selected when cond is true.  LOOP is the loop containing the
-   if-converted region, GSI is the place to insert the code for the
-   if-conversion.  */
+  delete innermost_DR_map;
+  innermost_DR_map = NULL;
 
-static basic_block
-find_phi_replacement_condition (basic_block bb, tree *cond,
-                               gimple_stmt_iterator *gsi)
-{
-  edge first_edge, second_edge;
-  tree tmp_cond;
-
-  gcc_assert (EDGE_COUNT (bb->preds) == 2);
-  first_edge = EDGE_PRED (bb, 0);
-  second_edge = EDGE_PRED (bb, 1);
-
-  /* Prefer an edge with a not negated predicate.
-     ???  That's a very weak cost model.  */
-  tmp_cond = bb_predicate (first_edge->src);
-  gcc_assert (tmp_cond);
-  if (TREE_CODE (tmp_cond) == TRUTH_NOT_EXPR)
-    {
-      edge tmp_edge;
-
-      tmp_edge = first_edge;
-      first_edge = second_edge;
-      second_edge = tmp_edge;
-    }
+  delete baseref_DR_map;
+  baseref_DR_map = NULL;
 
-  /* Check if the edge we take the condition from is not critical.
-     We know that at least one non-critical edge exists.  */
-  if (EDGE_COUNT (first_edge->src->succs) > 1)
-    {
-      *cond = bb_predicate (second_edge->src);
-
-      if (TREE_CODE (*cond) == TRUTH_NOT_EXPR)
-       *cond = TREE_OPERAND (*cond, 0);
-      else
-       /* Select non loop header bb.  */
-       first_edge = second_edge;
-    }
-  else
-    *cond = bb_predicate (first_edge->src);
-
-  /* Gimplify the condition to a valid cond-expr conditonal operand.  */
-  *cond = force_gimple_operand_gsi_1 (gsi, unshare_expr (*cond),
-                                     is_gimple_condexpr, NULL_TREE,
-                                     true, GSI_SAME_STMT);
-
-  return first_edge->src;
+  return res;
 }
 
 /* Returns true if def-stmt for phi argument ARG is simple increment/decrement
@@ -1447,29 +1583,30 @@ find_phi_replacement_condition (basic_block bb, tree *cond,
          reduc_3 = ...
        reduc_2 = PHI <reduc_1, reduc_3>
 
-   REDUC, OP0 and OP1 contain reduction stmt and its operands.  */
+   ARG_0 and ARG_1 are correspondent PHI arguments.
+   REDUC, OP0 and OP1 contain reduction stmt and its operands.
+   EXTENDED is true if PHI has > 2 arguments.  */
 
 static bool
-is_cond_scalar_reduction (gimple phi, gimple *reduc,
-                         tree *op0, tree *op1)
+is_cond_scalar_reduction (gimple *phi, gimple **reduc, tree arg_0, tree arg_1,
+                         tree *op0, tree *op1, bool extended)
 {
   tree lhs, r_op1, r_op2;
-  tree arg_0, arg_1;
-  gimple stmt;
-  gimple header_phi = NULL;
+  gimple *stmt;
+  gimple *header_phi = NULL;
   enum tree_code reduction_op;
   basic_block bb = gimple_bb (phi);
   struct loop *loop = bb->loop_father;
   edge latch_e = loop_latch_edge (loop);
   imm_use_iterator imm_iter;
   use_operand_p use_p;
-
-  arg_0 = PHI_ARG_DEF (phi, 0);
-  arg_1 = PHI_ARG_DEF (phi, 1);
+  edge e;
+  edge_iterator ei;
+  bool result = false;
   if (TREE_CODE (arg_0) != SSA_NAME || TREE_CODE (arg_1) != SSA_NAME)
     return false;
 
-  if (gimple_code (SSA_NAME_DEF_STMT (arg_0)) == GIMPLE_PHI)
+  if (!extended && gimple_code (SSA_NAME_DEF_STMT (arg_0)) == GIMPLE_PHI)
     {
       lhs = arg_1;
       header_phi = SSA_NAME_DEF_STMT (arg_0);
@@ -1500,8 +1637,13 @@ is_cond_scalar_reduction (gimple phi, gimple *reduc,
     return false;
 
   /* Check that stmt-block is predecessor of phi-block.  */
-  if (EDGE_PRED (bb, 0)->src != gimple_bb (stmt)
-      && EDGE_PRED (bb, 1)->src != gimple_bb (stmt))
+  FOR_EACH_EDGE (e, ei, gimple_bb (stmt)->succs)
+    if (e->dest == bb)
+      {
+       result = true;
+       break;
+      }
+  if (!result)
     return false;
 
   if (!has_single_use (lhs))
@@ -1516,18 +1658,14 @@ is_cond_scalar_reduction (gimple phi, gimple *reduc,
   /* Make R_OP1 to hold reduction variable.  */
   if (r_op2 == PHI_RESULT (header_phi)
       && reduction_op == PLUS_EXPR)
-    {
-      tree tmp = r_op1;
-      r_op1 = r_op2;
-      r_op2 = tmp;
-    }
+    std::swap (r_op1, r_op2);
   else if (r_op1 != PHI_RESULT (header_phi))
     return false;
 
   /* Check that R_OP1 is used in reduction stmt or in PHI only.  */
   FOR_EACH_IMM_USE_FAST (use_p, imm_iter, r_op1)
     {
-      gimple use_stmt = USE_STMT (use_p);
+      gimple *use_stmt = USE_STMT (use_p);
       if (is_gimple_debug (use_stmt))
        continue;
       if (use_stmt == stmt)
@@ -1560,11 +1698,11 @@ is_cond_scalar_reduction (gimple phi, gimple *reduc,
   Returns rhs of resulting PHI assignment.  */
 
 static tree
-convert_scalar_cond_reduction (gimple reduc, gimple_stmt_iterator *gsi,
+convert_scalar_cond_reduction (gimple *reduc, gimple_stmt_iterator *gsi,
                               tree cond, tree op0, tree op1, bool swap)
 {
   gimple_stmt_iterator stmt_it;
-  gimple new_assign;
+  gimple *new_assign;
   tree rhs;
   tree rhs1 = gimple_assign_rhs1 (reduc);
   tree tmp = make_temp_ssa_name (TREE_TYPE (rhs1), NULL, "_ifc_");
@@ -1598,9 +1736,57 @@ convert_scalar_cond_reduction (gimple reduc, gimple_stmt_iterator *gsi,
   return rhs;
 }
 
+/* Produce condition for all occurrences of ARG in PHI node.  */
+
+static tree
+gen_phi_arg_condition (gphi *phi, vec<int> *occur,
+                      gimple_stmt_iterator *gsi)
+{
+  int len;
+  int i;
+  tree cond = NULL_TREE;
+  tree c;
+  edge e;
+
+  len = occur->length ();
+  gcc_assert (len > 0);
+  for (i = 0; i < len; i++)
+    {
+      e = gimple_phi_arg_edge (phi, (*occur)[i]);
+      c = bb_predicate (e->src);
+      if (is_true_predicate (c))
+       {
+         cond = c;
+         break;
+       }
+      c = force_gimple_operand_gsi_1 (gsi, unshare_expr (c),
+                                     is_gimple_condexpr, NULL_TREE,
+                                     true, GSI_SAME_STMT);
+      if (cond != NULL_TREE)
+       {
+         /* Must build OR expression.  */
+         cond = fold_or_predicates (EXPR_LOCATION (c), c, cond);
+         cond = force_gimple_operand_gsi_1 (gsi, unshare_expr (cond),
+                                            is_gimple_condexpr, NULL_TREE,
+                                            true, GSI_SAME_STMT);
+       }
+      else
+       cond = c;
+    }
+  gcc_assert (cond != NULL_TREE);
+  return cond;
+}
+
+/* Local valueization callback that follows all-use SSA edges.  */
+
+static tree
+ifcvt_follow_ssa_use_edges (tree val)
+{
+  return val;
+}
+
 /* Replace a scalar PHI node with a COND_EXPR using COND as condition.
-   This routine does not handle PHI nodes with more than two
-   arguments.
+   This routine can handle PHI nodes with more than two arguments.
 
    For example,
      S1: A = PHI <x1(1), x2(5)>
@@ -1608,69 +1794,207 @@ convert_scalar_cond_reduction (gimple reduc, gimple_stmt_iterator *gsi,
      S2: A = cond ? x1 : x2;
 
    The generated code is inserted at GSI that points to the top of
-   basic block's statement list.  When COND is true, phi arg from
-   TRUE_BB is selected.  */
+   basic block's statement list.
+   If PHI node has more than two arguments a chain of conditional
+   expression is produced.  */
+
 
 static void
-predicate_scalar_phi (gphi *phi, tree cond,
-                     basic_block true_bb,
-                     gimple_stmt_iterator *gsi)
+predicate_scalar_phi (gphi *phi, gimple_stmt_iterator *gsi)
 {
-  gimple new_stmt;
+  gimple *new_stmt = NULL, *reduc;
+  tree rhs, res, arg0, arg1, op0, op1, scev;
+  tree cond;
+  unsigned int index0;
+  unsigned int max, args_len;
+  edge e;
   basic_block bb;
-  tree rhs, res, arg, scev;
-
-  gcc_assert (gimple_code (phi) == GIMPLE_PHI
-             && gimple_phi_num_args (phi) == 2);
+  unsigned int i;
 
   res = gimple_phi_result (phi);
-  /* Do not handle virtual phi nodes.  */
   if (virtual_operand_p (res))
     return;
 
-  bb = gimple_bb (phi);
-
-  if ((arg = degenerate_phi_result (phi))
+  if ((rhs = degenerate_phi_result (phi))
       || ((scev = analyze_scalar_evolution (gimple_bb (phi)->loop_father,
                                            res))
          && !chrec_contains_undetermined (scev)
          && scev != res
-         && (arg = gimple_phi_arg_def (phi, 0))))
-    rhs = arg;
-  else
+         && (rhs = gimple_phi_arg_def (phi, 0))))
     {
-      tree arg_0, arg_1;
-      tree op0, op1;
-      gimple reduc;
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "Degenerate phi!\n");
+         print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
+       }
+      new_stmt = gimple_build_assign (res, rhs);
+      gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
+      update_stmt (new_stmt);
+      return;
+    }
 
-      /* Use condition that is not TRUTH_NOT_EXPR in conditional modify expr.  */
+  bb = gimple_bb (phi);
+  if (EDGE_COUNT (bb->preds) == 2)
+    {
+      /* Predicate ordinary PHI node with 2 arguments.  */
+      edge first_edge, second_edge;
+      basic_block true_bb;
+      first_edge = EDGE_PRED (bb, 0);
+      second_edge = EDGE_PRED (bb, 1);
+      cond = bb_predicate (first_edge->src);
+      if (TREE_CODE (cond) == TRUTH_NOT_EXPR)
+       std::swap (first_edge, second_edge);
+      if (EDGE_COUNT (first_edge->src->succs) > 1)
+       {
+         cond = bb_predicate (second_edge->src);
+         if (TREE_CODE (cond) == TRUTH_NOT_EXPR)
+           cond = TREE_OPERAND (cond, 0);
+         else
+           first_edge = second_edge;
+       }
+      else
+       cond = bb_predicate (first_edge->src);
+      /* Gimplify the condition to a valid cond-expr conditonal operand.  */
+      cond = force_gimple_operand_gsi_1 (gsi, unshare_expr (cond),
+                                        is_gimple_condexpr, NULL_TREE,
+                                        true, GSI_SAME_STMT);
+      true_bb = first_edge->src;
       if (EDGE_PRED (bb, 1)->src == true_bb)
        {
-         arg_0 = gimple_phi_arg_def (phi, 1);
-         arg_1 = gimple_phi_arg_def (phi, 0);
+         arg0 = gimple_phi_arg_def (phi, 1);
+         arg1 = gimple_phi_arg_def (phi, 0);
        }
       else
        {
-         arg_0 = gimple_phi_arg_def (phi, 0);
-         arg_1 = gimple_phi_arg_def (phi, 1);
+         arg0 = gimple_phi_arg_def (phi, 0);
+         arg1 = gimple_phi_arg_def (phi, 1);
        }
-      if (is_cond_scalar_reduction (phi, &reduc, &op0, &op1))
+      if (is_cond_scalar_reduction (phi, &reduc, arg0, arg1,
+                                   &op0, &op1, false))
        /* Convert reduction stmt into vectorizable form.  */
        rhs = convert_scalar_cond_reduction (reduc, gsi, cond, op0, op1,
                                             true_bb != gimple_bb (reduc));
       else
        /* Build new RHS using selected condition and arguments.  */
        rhs = fold_build_cond_expr (TREE_TYPE (res), unshare_expr (cond),
-                                   arg_0, arg_1);
+                                   arg0, arg1);
+      new_stmt = gimple_build_assign (res, rhs);
+      gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
+      gimple_stmt_iterator new_gsi = gsi_for_stmt (new_stmt);
+      if (fold_stmt (&new_gsi, ifcvt_follow_ssa_use_edges))
+       {
+         new_stmt = gsi_stmt (new_gsi);
+         update_stmt (new_stmt);
+       }
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "new phi replacement stmt\n");
+         print_gimple_stmt (dump_file, new_stmt, 0, TDF_SLIM);
+       }
+      return;
     }
 
-  new_stmt = gimple_build_assign (res, rhs);
-  gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
-  update_stmt (new_stmt);
+  /* Create hashmap for PHI node which contain vector of argument indexes
+     having the same value.  */
+  bool swap = false;
+  hash_map<tree_operand_hash, auto_vec<int> > phi_arg_map;
+  unsigned int num_args = gimple_phi_num_args (phi);
+  int max_ind = -1;
+  /* Vector of different PHI argument values.  */
+  auto_vec<tree> args (num_args);
+
+  /* Compute phi_arg_map.  */
+  for (i = 0; i < num_args; i++)
+    {
+      tree arg;
+
+      arg = gimple_phi_arg_def (phi, i);
+      if (!phi_arg_map.get (arg))
+       args.quick_push (arg);
+      phi_arg_map.get_or_insert (arg).safe_push (i);
+    }
+
+  /* Determine element with max number of occurrences.  */
+  max_ind = -1;
+  max = 1;
+  args_len = args.length ();
+  for (i = 0; i < args_len; i++)
+    {
+      unsigned int len;
+      if ((len = phi_arg_map.get (args[i])->length ()) > max)
+       {
+         max_ind = (int) i;
+         max = len;
+       }
+    }
+
+  /* Put element with max number of occurences to the end of ARGS.  */
+  if (max_ind != -1 && max_ind +1 != (int) args_len)
+    std::swap (args[args_len - 1], args[max_ind]);
+
+  /* Handle one special case when number of arguments with different values
+     is equal 2 and one argument has the only occurrence.  Such PHI can be
+     handled as if would have only 2 arguments.  */
+  if (args_len == 2 && phi_arg_map.get (args[0])->length () == 1)
+    {
+      vec<int> *indexes;
+      indexes = phi_arg_map.get (args[0]);
+      index0 = (*indexes)[0];
+      arg0 = args[0];
+      arg1 = args[1];
+      e = gimple_phi_arg_edge (phi, index0);
+      cond = bb_predicate (e->src);
+      if (TREE_CODE (cond) == TRUTH_NOT_EXPR)
+       {
+         swap = true;
+         cond = TREE_OPERAND (cond, 0);
+       }
+      /* Gimplify the condition to a valid cond-expr conditonal operand.  */
+      cond = force_gimple_operand_gsi_1 (gsi, unshare_expr (cond),
+                                        is_gimple_condexpr, NULL_TREE,
+                                        true, GSI_SAME_STMT);
+      if (!(is_cond_scalar_reduction (phi, &reduc, arg0 , arg1,
+                                     &op0, &op1, true)))
+       rhs = fold_build_cond_expr (TREE_TYPE (res), unshare_expr (cond),
+                                   swap? arg1 : arg0,
+                                   swap? arg0 : arg1);
+      else
+       /* Convert reduction stmt into vectorizable form.  */
+       rhs = convert_scalar_cond_reduction (reduc, gsi, cond, op0, op1,
+                                            swap);
+      new_stmt = gimple_build_assign (res, rhs);
+      gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
+      update_stmt (new_stmt);
+    }
+  else
+    {
+      /* Common case.  */
+      vec<int> *indexes;
+      tree type = TREE_TYPE (gimple_phi_result (phi));
+      tree lhs;
+      arg1 = args[1];
+      for (i = 0; i < args_len; i++)
+       {
+         arg0 = args[i];
+         indexes = phi_arg_map.get (args[i]);
+         if (i != args_len - 1)
+           lhs = make_temp_ssa_name (type, NULL, "_ifc_");
+         else
+           lhs = res;
+         cond = gen_phi_arg_condition (phi, indexes, gsi);
+         rhs = fold_build_cond_expr (type, unshare_expr (cond),
+                                     arg0, arg1);
+         new_stmt = gimple_build_assign (lhs, rhs);
+         gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
+         update_stmt (new_stmt);
+         arg1 = lhs;
+       }
+    }
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
-      fprintf (dump_file, "new phi replacement stmt\n");
+      fprintf (dump_file, "new extended phi replacement stmt\n");
       print_gimple_stmt (dump_file, new_stmt, 0, TDF_SLIM);
     }
 }
@@ -1688,10 +2012,8 @@ predicate_all_scalar_phis (struct loop *loop)
   for (i = 1; i < orig_loop_num_nodes; i++)
     {
       gphi *phi;
-      tree cond = NULL_TREE;
       gimple_stmt_iterator gsi;
       gphi_iterator phi_gsi;
-      basic_block true_bb = NULL;
       bb = ifc_bbs[i];
 
       if (bb == loop->header)
@@ -1701,20 +2023,18 @@ predicate_all_scalar_phis (struct loop *loop)
       if (gsi_end_p (phi_gsi))
        continue;
 
-      /* BB has two predecessors.  Using predecessor's aux field, set
-        appropriate condition for the PHI node replacement.  */
       gsi = gsi_after_labels (bb);
-      true_bb = find_phi_replacement_condition (bb, &cond, &gsi);
-
       while (!gsi_end_p (phi_gsi))
        {
          phi = phi_gsi.phi ();
-         predicate_scalar_phi (phi, cond, true_bb, &gsi);
-         release_phi_node (phi);
-         gsi_next (&phi_gsi);
+         if (virtual_operand_p (gimple_phi_result (phi)))
+           gsi_next (&phi_gsi);
+         else
+           {
+             predicate_scalar_phi (phi, &gsi);
+             remove_phi_node (&phi_gsi, false);
+           }
        }
-
-      set_phi_nodes (bb, NULL);
     }
 }
 
@@ -1722,7 +2042,7 @@ predicate_all_scalar_phis (struct loop *loop)
    gimplification of the predicates.  */
 
 static void
-insert_gimplified_predicates (loop_p loop, bool any_mask_load_store)
+insert_gimplified_predicates (loop_p loop)
 {
   unsigned int i;
 
@@ -1730,7 +2050,8 @@ insert_gimplified_predicates (loop_p loop, bool any_mask_load_store)
     {
       basic_block bb = ifc_bbs[i];
       gimple_seq stmts;
-
+      if (!is_predicated (bb))
+       gcc_assert (bb_predicate_gimplified_stmts (bb) == NULL);
       if (!is_predicated (bb))
        {
          /* Do not insert statements for a basic block that is not
@@ -1743,8 +2064,7 @@ insert_gimplified_predicates (loop_p loop, bool any_mask_load_store)
       stmts = bb_predicate_gimplified_stmts (bb);
       if (stmts)
        {
-         if (flag_tree_loop_if_convert_stores
-             || any_mask_load_store)
+         if (need_to_predicate)
            {
              /* Insert the predicate of the BB just after the label,
                 as the if-conversion of memory writes will use this
@@ -1772,6 +2092,174 @@ insert_gimplified_predicates (loop_p loop, bool any_mask_load_store)
     }
 }
 
+/* Helper function for predicate_statements. Returns index of existent
+   mask if it was created for given SIZE and -1 otherwise.  */
+
+static int
+mask_exists (int size, vec<int> vec)
+{
+  unsigned int ix;
+  int v;
+  FOR_EACH_VEC_ELT (vec, ix, v)
+    if (v == size)
+      return (int) ix;
+  return -1;
+}
+
+/* Helper function for predicate_statements.  STMT is a memory read or
+   write and it needs to be predicated by MASK.  Return a statement
+   that does so.  */
+
+static gimple *
+predicate_load_or_store (gimple_stmt_iterator *gsi, gassign *stmt, tree mask)
+{
+  gcall *new_stmt;
+
+  tree lhs = gimple_assign_lhs (stmt);
+  tree rhs = gimple_assign_rhs1 (stmt);
+  tree ref = TREE_CODE (lhs) == SSA_NAME ? rhs : lhs;
+  mark_addressable (ref);
+  tree addr = force_gimple_operand_gsi (gsi, build_fold_addr_expr (ref),
+                                       true, NULL_TREE, true, GSI_SAME_STMT);
+  tree ptr = build_int_cst (reference_alias_ptr_type (ref),
+                           get_object_alignment (ref));
+  /* Copy points-to info if possible.  */
+  if (TREE_CODE (addr) == SSA_NAME && !SSA_NAME_PTR_INFO (addr))
+    copy_ref_info (build2 (MEM_REF, TREE_TYPE (ref), addr, ptr),
+                  ref);
+  if (TREE_CODE (lhs) == SSA_NAME)
+    {
+      new_stmt
+       = gimple_build_call_internal (IFN_MASK_LOAD, 3, addr,
+                                     ptr, mask);
+      gimple_call_set_lhs (new_stmt, lhs);
+      gimple_set_vuse (new_stmt, gimple_vuse (stmt));
+    }
+  else
+    {
+      new_stmt
+       = gimple_build_call_internal (IFN_MASK_STORE, 4, addr, ptr,
+                                     mask, rhs);
+      gimple_set_vuse (new_stmt, gimple_vuse (stmt));
+      gimple_set_vdef (new_stmt, gimple_vdef (stmt));
+      SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
+    }
+  gimple_call_set_nothrow (new_stmt, true);
+  return new_stmt;
+}
+
+/* STMT uses OP_LHS.  Check whether it is equivalent to:
+
+     ... = OP_MASK ? OP_LHS : X;
+
+   Return X if so, otherwise return null.  OP_MASK is an SSA_NAME that is
+   known to have value OP_COND.  */
+
+static tree
+check_redundant_cond_expr (gimple *stmt, tree op_mask, tree op_cond,
+                          tree op_lhs)
+{
+  gassign *assign = dyn_cast <gassign *> (stmt);
+  if (!assign || gimple_assign_rhs_code (assign) != COND_EXPR)
+    return NULL_TREE;
+
+  tree use_cond = gimple_assign_rhs1 (assign);
+  tree if_true = gimple_assign_rhs2 (assign);
+  tree if_false = gimple_assign_rhs3 (assign);
+
+  if ((use_cond == op_mask || operand_equal_p (use_cond, op_cond, 0))
+      && if_true == op_lhs)
+    return if_false;
+
+  if (inverse_conditions_p (use_cond, op_cond) && if_false == op_lhs)
+    return if_true;
+
+  return NULL_TREE;
+}
+
+/* Return true if VALUE is available for use at STMT.  SSA_NAMES is
+   the set of SSA names defined earlier in STMT's block.  */
+
+static bool
+value_available_p (gimple *stmt, hash_set<tree_ssa_name_hash> *ssa_names,
+                  tree value)
+{
+  if (is_gimple_min_invariant (value))
+    return true;
+
+  if (TREE_CODE (value) == SSA_NAME)
+    {
+      if (SSA_NAME_IS_DEFAULT_DEF (value))
+       return true;
+
+      basic_block def_bb = gimple_bb (SSA_NAME_DEF_STMT (value));
+      basic_block use_bb = gimple_bb (stmt);
+      return (def_bb == use_bb
+             ? ssa_names->contains (value)
+             : dominated_by_p (CDI_DOMINATORS, use_bb, def_bb));
+    }
+
+  return false;
+}
+
+/* Helper function for predicate_statements.  STMT is a potentially-trapping
+   arithmetic operation that needs to be predicated by MASK, an SSA_NAME that
+   has value COND.  Return a statement that does so.  SSA_NAMES is the set of
+   SSA names defined earlier in STMT's block.  */
+
+static gimple *
+predicate_rhs_code (gassign *stmt, tree mask, tree cond,
+                   hash_set<tree_ssa_name_hash> *ssa_names)
+{
+  tree lhs = gimple_assign_lhs (stmt);
+  tree_code code = gimple_assign_rhs_code (stmt);
+  unsigned int nops = gimple_num_ops (stmt);
+  internal_fn cond_fn = get_conditional_internal_fn (code);
+
+  /* Construct the arguments to the conditional internal function.   */
+  auto_vec<tree, 8> args;
+  args.safe_grow (nops + 1);
+  args[0] = mask;
+  for (unsigned int i = 1; i < nops; ++i)
+    args[i] = gimple_op (stmt, i);
+  args[nops] = NULL_TREE;
+
+  /* Look for uses of the result to see whether they are COND_EXPRs that can
+     be folded into the conditional call.  */
+  imm_use_iterator imm_iter;
+  gimple *use_stmt;
+  FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, lhs)
+    {
+      tree new_else = check_redundant_cond_expr (use_stmt, mask, cond, lhs);
+      if (new_else && value_available_p (stmt, ssa_names, new_else))
+       {
+         if (!args[nops])
+           args[nops] = new_else;
+         if (operand_equal_p (new_else, args[nops], 0))
+           {
+             /* We have:
+
+                  LHS = IFN_COND (MASK, ..., ELSE);
+                  X = MASK ? LHS : ELSE;
+
+                which makes X equivalent to LHS.  */
+             tree use_lhs = gimple_assign_lhs (use_stmt);
+             redundant_ssa_names.safe_push (std::make_pair (use_lhs, lhs));
+           }
+       }
+    }
+  if (!args[nops])
+    args[nops] = targetm.preferred_else_value (cond_fn, TREE_TYPE (lhs),
+                                              nops - 1, &args[1]);
+
+  /* Create and insert the call.  */
+  gcall *new_stmt = gimple_build_call_internal_vec (cond_fn, args);
+  gimple_call_set_lhs (new_stmt, lhs);
+  gimple_call_set_nothrow (new_stmt, true);
+
+  return new_stmt;
+}
+
 /* Predicate each write to memory in LOOP.
 
    This function transforms control flow constructs containing memory
@@ -1836,7 +2324,7 @@ insert_gimplified_predicates (loop_p loop, bool any_mask_load_store)
    |   goto bb_1
    | end_bb_4
 
-   predicate_mem_writes is then predicating the memory write as follows:
+   predicate_statements is then predicating the memory write as follows:
 
    | bb_0
    |   i = 0
@@ -1880,9 +2368,12 @@ insert_gimplified_predicates (loop_p loop, bool any_mask_load_store)
 */
 
 static void
-predicate_mem_writes (loop_p loop)
+predicate_statements (loop_p loop)
 {
   unsigned int i, orig_loop_num_nodes = loop->num_nodes;
+  auto_vec<int, 1> vect_sizes;
+  auto_vec<tree, 1> vect_masks;
+  hash_set<tree_ssa_name_hash> ssa_names;
 
   for (i = 1; i < orig_loop_num_nodes; i++)
     {
@@ -1890,7 +2381,7 @@ predicate_mem_writes (loop_p loop)
       basic_block bb = ifc_bbs[i];
       tree cond = bb_predicate (bb);
       bool swap;
-      gimple stmt;
+      int index;
 
       if (is_true_predicate (cond))
        continue;
@@ -1902,70 +2393,89 @@ predicate_mem_writes (loop_p loop)
          cond = TREE_OPERAND (cond, 0);
        }
 
-      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-       if (!gimple_assign_single_p (stmt = gsi_stmt (gsi)))
-         continue;
-       else if (gimple_plf (stmt, GF_PLF_2))
-         {
-           tree lhs = gimple_assign_lhs (stmt);
-           tree rhs = gimple_assign_rhs1 (stmt);
-           tree ref, addr, ptr, masktype, mask_op0, mask_op1, mask;
-           gimple new_stmt;
-           int bitsize = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (lhs)));
-
-           masktype = build_nonstandard_integer_type (bitsize, 1);
-           mask_op0 = build_int_cst (masktype, swap ? 0 : -1);
-           mask_op1 = build_int_cst (masktype, swap ? -1 : 0);
-           ref = TREE_CODE (lhs) == SSA_NAME ? rhs : lhs;
-           mark_addressable (ref);
-           addr = force_gimple_operand_gsi (&gsi, build_fold_addr_expr (ref),
-                                            true, NULL_TREE, true,
-                                            GSI_SAME_STMT);
-           cond = force_gimple_operand_gsi_1 (&gsi, unshare_expr (cond),
-                                              is_gimple_condexpr, NULL_TREE,
-                                              true, GSI_SAME_STMT);
-           mask = fold_build_cond_expr (masktype, unshare_expr (cond),
-                                        mask_op0, mask_op1);
-           mask = ifc_temp_var (masktype, mask, &gsi);
-           ptr = build_int_cst (reference_alias_ptr_type (ref), 0);
-           /* Copy points-to info if possible.  */
-           if (TREE_CODE (addr) == SSA_NAME && !SSA_NAME_PTR_INFO (addr))
-             copy_ref_info (build2 (MEM_REF, TREE_TYPE (ref), addr, ptr),
-                            ref);
-           if (TREE_CODE (lhs) == SSA_NAME)
-             {
-               new_stmt
-                 = gimple_build_call_internal (IFN_MASK_LOAD, 3, addr,
-                                               ptr, mask);
-               gimple_call_set_lhs (new_stmt, lhs);
-             }
-           else
-             new_stmt
-               = gimple_build_call_internal (IFN_MASK_STORE, 4, addr, ptr,
-                                             mask, rhs);
-           gsi_replace (&gsi, new_stmt, true);
-         }
-       else if (gimple_vdef (stmt))
-         {
-           tree lhs = gimple_assign_lhs (stmt);
-           tree rhs = gimple_assign_rhs1 (stmt);
-           tree type = TREE_TYPE (lhs);
+      vect_sizes.truncate (0);
+      vect_masks.truncate (0);
 
-           lhs = ifc_temp_var (type, unshare_expr (lhs), &gsi);
-           rhs = ifc_temp_var (type, unshare_expr (rhs), &gsi);
-           if (swap)
-             {
-               tree tem = lhs;
-               lhs = rhs;
-               rhs = tem;
-             }
-           cond = force_gimple_operand_gsi_1 (&gsi, unshare_expr (cond),
-                                              is_gimple_condexpr, NULL_TREE,
-                                              true, GSI_SAME_STMT);
-           rhs = fold_build_cond_expr (type, unshare_expr (cond), rhs, lhs);
-           gimple_assign_set_rhs1 (stmt, ifc_temp_var (type, rhs, &gsi));
-           update_stmt (stmt);
-         }
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
+       {
+         gassign *stmt = dyn_cast <gassign *> (gsi_stmt (gsi));
+         if (!stmt)
+           ;
+         else if (is_false_predicate (cond)
+                  && gimple_vdef (stmt))
+           {
+             unlink_stmt_vdef (stmt);
+             gsi_remove (&gsi, true);
+             release_defs (stmt);
+             continue;
+           }
+         else if (gimple_plf (stmt, GF_PLF_2))
+           {
+             tree lhs = gimple_assign_lhs (stmt);
+             tree mask;
+             gimple *new_stmt;
+             gimple_seq stmts = NULL;
+             machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
+             /* We checked before setting GF_PLF_2 that an equivalent
+                integer mode exists.  */
+             int bitsize = GET_MODE_BITSIZE (mode).to_constant ();
+             if (!vect_sizes.is_empty ()
+                 && (index = mask_exists (bitsize, vect_sizes)) != -1)
+               /* Use created mask.  */
+               mask = vect_masks[index];
+             else
+               {
+                 if (COMPARISON_CLASS_P (cond))
+                   mask = gimple_build (&stmts, TREE_CODE (cond),
+                                        boolean_type_node,
+                                        TREE_OPERAND (cond, 0),
+                                        TREE_OPERAND (cond, 1));
+                 else
+                   mask = cond;
+
+                 if (swap)
+                   {
+                     tree true_val
+                       = constant_boolean_node (true, TREE_TYPE (mask));
+                     mask = gimple_build (&stmts, BIT_XOR_EXPR,
+                                          TREE_TYPE (mask), mask, true_val);
+                   }
+                 gsi_insert_seq_before (&gsi, stmts, GSI_SAME_STMT);
+
+                 /* Save mask and its size for further use.  */
+                 vect_sizes.safe_push (bitsize);
+                 vect_masks.safe_push (mask);
+               }
+             if (gimple_assign_single_p (stmt))
+               new_stmt = predicate_load_or_store (&gsi, stmt, mask);
+             else
+               new_stmt = predicate_rhs_code (stmt, mask, cond, &ssa_names);
+
+             gsi_replace (&gsi, new_stmt, true);
+           }
+         else if (gimple_vdef (stmt))
+           {
+             tree lhs = gimple_assign_lhs (stmt);
+             tree rhs = gimple_assign_rhs1 (stmt);
+             tree type = TREE_TYPE (lhs);
+
+             lhs = ifc_temp_var (type, unshare_expr (lhs), &gsi);
+             rhs = ifc_temp_var (type, unshare_expr (rhs), &gsi);
+             if (swap)
+               std::swap (lhs, rhs);
+             cond = force_gimple_operand_gsi_1 (&gsi, unshare_expr (cond),
+                                                is_gimple_condexpr, NULL_TREE,
+                                                true, GSI_SAME_STMT);
+             rhs = fold_build_cond_expr (type, unshare_expr (cond), rhs, lhs);
+             gimple_assign_set_rhs1 (stmt, ifc_temp_var (type, rhs, &gsi));
+             update_stmt (stmt);
+           }
+         tree lhs = gimple_get_lhs (gsi_stmt (gsi));
+         if (lhs && TREE_CODE (lhs) == SSA_NAME)
+           ssa_names.add (lhs);
+         gsi_next (&gsi);
+       }
+      ssa_names.empty ();
     }
 }
 
@@ -2015,7 +2525,7 @@ remove_conditions_and_labels (loop_p loop)
    blocks.  Replace PHI nodes with conditional modify expressions.  */
 
 static void
-combine_blocks (struct loop *loop, bool any_mask_load_store)
+combine_blocks (struct loop *loop)
 {
   basic_block bb, exit_bb, merge_target_bb;
   unsigned int orig_loop_num_nodes = loop->num_nodes;
@@ -2023,20 +2533,21 @@ combine_blocks (struct loop *loop, bool any_mask_load_store)
   edge e;
   edge_iterator ei;
 
-  predicate_bbs (loop);
   remove_conditions_and_labels (loop);
-  insert_gimplified_predicates (loop, any_mask_load_store);
+  insert_gimplified_predicates (loop);
   predicate_all_scalar_phis (loop);
 
-  if (flag_tree_loop_if_convert_stores || any_mask_load_store)
-    predicate_mem_writes (loop);
+  if (need_to_predicate)
+    predicate_statements (loop);
 
   /* Merge basic blocks: first remove all the edges in the loop,
      except for those from the exit block.  */
   exit_bb = NULL;
+  bool *predicated = XNEWVEC (bool, orig_loop_num_nodes);
   for (i = 0; i < orig_loop_num_nodes; i++)
     {
       bb = ifc_bbs[i];
+      predicated[i] = !is_true_predicate (bb_predicate (bb));
       free_bb_predicate (bb);
       if (bb_with_exit_edge_p (loop, bb))
        {
@@ -2064,7 +2575,7 @@ combine_blocks (struct loop *loop, bool any_mask_load_store)
       if (exit_bb != loop->header)
        {
          /* Connect this node to loop header.  */
-         make_edge (loop->header, exit_bb, EDGE_FALLTHRU);
+         make_single_succ_edge (loop->header, exit_bb, EDGE_FALLTHRU);
          set_immediate_dominator (CDI_DOMINATORS, exit_bb, loop->header);
        }
 
@@ -2084,6 +2595,20 @@ combine_blocks (struct loop *loop, bool any_mask_load_store)
     }
 
   merge_target_bb = loop->header;
+
+  /* Get at the virtual def valid for uses starting at the first block
+     we merge into the header.  Without a virtual PHI the loop has the
+     same virtual use on all stmts.  */
+  gphi *vphi = get_virtual_phi (loop->header);
+  tree last_vdef = NULL_TREE;
+  if (vphi)
+    {
+      last_vdef = gimple_phi_result (vphi);
+      for (gimple_stmt_iterator gsi = gsi_start_bb (loop->header);
+          ! gsi_end_p (gsi); gsi_next (&gsi))
+       if (gimple_vdef (gsi_stmt (gsi)))
+         last_vdef = gimple_vdef (gsi_stmt (gsi));
+    }
   for (i = 1; i < orig_loop_num_nodes; i++)
     {
       gimple_stmt_iterator gsi;
@@ -2094,13 +2619,55 @@ combine_blocks (struct loop *loop, bool any_mask_load_store)
       if (bb == exit_bb || bb == loop->latch)
        continue;
 
-      /* Make stmts member of loop->header.  */
+      /* We release virtual PHIs late because we have to propagate them
+         out using the current VUSE.  The def might be the one used
+        after the loop.  */
+      vphi = get_virtual_phi (bb);
+      if (vphi)
+       {
+         imm_use_iterator iter;
+         use_operand_p use_p;
+         gimple *use_stmt;
+         FOR_EACH_IMM_USE_STMT (use_stmt, iter, gimple_phi_result (vphi))
+           {
+             FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
+               SET_USE (use_p, last_vdef);
+           }
+         if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (vphi)))
+           SSA_NAME_OCCURS_IN_ABNORMAL_PHI (last_vdef) = 1;
+         gsi = gsi_for_stmt (vphi); 
+         remove_phi_node (&gsi, true);
+       }
+
+      /* Make stmts member of loop->header and clear range info from all stmts
+        in BB which is now no longer executed conditional on a predicate we
+        could have derived it from.  */
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-       gimple_set_bb (gsi_stmt (gsi), merge_target_bb);
+       {
+         gimple *stmt = gsi_stmt (gsi);
+         gimple_set_bb (stmt, merge_target_bb);
+         /* Update virtual operands.  */
+         if (last_vdef)
+           {
+             use_operand_p use_p = ssa_vuse_operand (stmt);
+             if (use_p
+                 && USE_FROM_PTR (use_p) != last_vdef)
+               SET_USE (use_p, last_vdef);
+             if (gimple_vdef (stmt))
+               last_vdef = gimple_vdef (stmt);
+           }
+         if (predicated[i])
+           {
+             ssa_op_iter i;
+             tree op;
+             FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_DEF)
+               reset_flow_sensitive_info (op);
+           }
+       }
 
       /* Update stmt list.  */
       last = gsi_last_bb (merge_target_bb);
-      gsi_insert_seq_after (&last, bb_seq (bb), GSI_NEW_STMT);
+      gsi_insert_seq_after_without_update (&last, bb_seq (bb), GSI_NEW_STMT);
       set_bb_seq (bb, NULL);
 
       delete_basic_block (bb);
@@ -2110,84 +2677,400 @@ combine_blocks (struct loop *loop, bool any_mask_load_store)
      This reduces the number of basic blocks to two, to please the
      vectorizer that handles only loops with two nodes.  */
   if (exit_bb
-      && exit_bb != loop->header
-      && can_merge_blocks_p (loop->header, exit_bb))
-    merge_blocks (loop->header, exit_bb);
+      && exit_bb != loop->header)
+    {
+      /* We release virtual PHIs late because we have to propagate them
+         out using the current VUSE.  The def might be the one used
+        after the loop.  */
+      vphi = get_virtual_phi (exit_bb);
+      if (vphi)
+       {
+         imm_use_iterator iter;
+         use_operand_p use_p;
+         gimple *use_stmt;
+         FOR_EACH_IMM_USE_STMT (use_stmt, iter, gimple_phi_result (vphi))
+           {
+             FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
+               SET_USE (use_p, last_vdef);
+           }
+         if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (vphi)))
+           SSA_NAME_OCCURS_IN_ABNORMAL_PHI (last_vdef) = 1;
+         gimple_stmt_iterator gsi = gsi_for_stmt (vphi); 
+         remove_phi_node (&gsi, true);
+       }
+
+      if (can_merge_blocks_p (loop->header, exit_bb))
+       merge_blocks (loop->header, exit_bb);
+    }
 
   free (ifc_bbs);
   ifc_bbs = NULL;
+  free (predicated);
 }
 
-/* Version LOOP before if-converting it, the original loop
-   will be then if-converted, the new copy of the loop will not,
+/* Version LOOP before if-converting it; the original loop
+   will be if-converted, the new copy of the loop will not,
    and the LOOP_VECTORIZED internal call will be guarding which
    loop to execute.  The vectorizer pass will fold this
-   internal call into either true or false.  */
+   internal call into either true or false. 
 
-static bool
+   Note that this function intentionally invalidates profile.  Both edges
+   out of LOOP_VECTORIZED must have 100% probability so the profile remains
+   consistent after the condition is folded in the vectorizer.  */
+
+static struct loop *
 version_loop_for_if_conversion (struct loop *loop)
 {
   basic_block cond_bb;
   tree cond = make_ssa_name (boolean_type_node);
   struct loop *new_loop;
-  gimple g;
+  gimple *g;
   gimple_stmt_iterator gsi;
+  unsigned int save_length;
 
   g = gimple_build_call_internal (IFN_LOOP_VECTORIZED, 2,
                                  build_int_cst (integer_type_node, loop->num),
                                  integer_zero_node);
   gimple_call_set_lhs (g, cond);
 
+  /* Save BB->aux around loop_version as that uses the same field.  */
+  save_length = loop->inner ? loop->inner->num_nodes : loop->num_nodes;
+  void **saved_preds = XALLOCAVEC (void *, save_length);
+  for (unsigned i = 0; i < save_length; i++)
+    saved_preds[i] = ifc_bbs[i]->aux;
+
   initialize_original_copy_tables ();
+  /* At this point we invalidate porfile confistency until IFN_LOOP_VECTORIZED
+     is re-merged in the vectorizer.  */
   new_loop = loop_version (loop, cond, &cond_bb,
-                          REG_BR_PROB_BASE, REG_BR_PROB_BASE,
-                          REG_BR_PROB_BASE, true);
+                          profile_probability::always (),
+                          profile_probability::always (),
+                          profile_probability::always (),
+                          profile_probability::always (), true);
   free_original_copy_tables ();
+
+  for (unsigned i = 0; i < save_length; i++)
+    ifc_bbs[i]->aux = saved_preds[i];
+
   if (new_loop == NULL)
-    return false;
+    return NULL;
+
   new_loop->dont_vectorize = true;
   new_loop->force_vectorize = false;
   gsi = gsi_last_bb (cond_bb);
   gimple_call_set_arg (g, 1, build_int_cst (integer_type_node, new_loop->num));
   gsi_insert_before (&gsi, g, GSI_SAME_STMT);
   update_ssa (TODO_update_ssa);
+  return new_loop;
+}
+
+/* Return true when LOOP satisfies the follow conditions that will
+   allow it to be recognized by the vectorizer for outer-loop
+   vectorization:
+    - The loop is not the root node of the loop tree.
+    - The loop has exactly one inner loop.
+    - The loop has a single exit.
+    - The loop header has a single successor, which is the inner
+      loop header.
+    - Each of the inner and outer loop latches have a single
+      predecessor.
+    - The loop exit block has a single predecessor, which is the
+      inner loop's exit block.  */
+
+static bool
+versionable_outer_loop_p (struct loop *loop)
+{
+  if (!loop_outer (loop)
+      || loop->dont_vectorize
+      || !loop->inner
+      || loop->inner->next
+      || !single_exit (loop)
+      || !single_succ_p (loop->header)
+      || single_succ (loop->header) != loop->inner->header
+      || !single_pred_p (loop->latch)
+      || !single_pred_p (loop->inner->latch))
+    return false;
+
+  basic_block outer_exit = single_pred (loop->latch);
+  basic_block inner_exit = single_pred (loop->inner->latch);
+
+  if (!single_pred_p (outer_exit) || single_pred (outer_exit) != inner_exit)
+    return false;
+
+  if (dump_file)
+    fprintf (dump_file, "Found vectorizable outer loop for versioning\n");
+
   return true;
 }
 
+/* Performs splitting of critical edges.  Skip splitting and return false
+   if LOOP will not be converted because:
+
+     - LOOP is not well formed.
+     - LOOP has PHI with more than MAX_PHI_ARG_NUM arguments.
+
+   Last restriction is valid only if AGGRESSIVE_IF_CONV is false.  */
+
+static bool
+ifcvt_split_critical_edges (struct loop *loop, bool aggressive_if_conv)
+{
+  basic_block *body;
+  basic_block bb;
+  unsigned int num = loop->num_nodes;
+  unsigned int i;
+  gimple *stmt;
+  edge e;
+  edge_iterator ei;
+  auto_vec<edge> critical_edges;
+
+  /* Loop is not well formed.  */
+  if (num <= 2 || loop->inner || !single_exit (loop))
+    return false;
+
+  body = get_loop_body (loop);
+  for (i = 0; i < num; i++)
+    {
+      bb = body[i];
+      if (!aggressive_if_conv
+         && phi_nodes (bb)
+         && EDGE_COUNT (bb->preds) > MAX_PHI_ARG_NUM)
+       {
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           fprintf (dump_file,
+                    "BB %d has complicated PHI with more than %u args.\n",
+                    bb->index, MAX_PHI_ARG_NUM);
+
+         free (body);
+         return false;
+       }
+      if (bb == loop->latch || bb_with_exit_edge_p (loop, bb))
+       continue;
+
+      stmt = last_stmt (bb);
+      /* Skip basic blocks not ending with conditional branch.  */
+      if (!stmt || gimple_code (stmt) != GIMPLE_COND)
+       continue;
+
+      FOR_EACH_EDGE (e, ei, bb->succs)
+       if (EDGE_CRITICAL_P (e) && e->dest->loop_father == loop)
+         critical_edges.safe_push (e);
+    }
+  free (body);
+
+  while (critical_edges.length () > 0)
+    {
+      e = critical_edges.pop ();
+      /* Don't split if bb can be predicated along non-critical edge.  */
+      if (EDGE_COUNT (e->dest->preds) > 2 || all_preds_critical_p (e->dest))
+       split_edge (e);
+    }
+
+  return true;
+}
+
+/* Delete redundant statements produced by predication which prevents
+   loop vectorization.  */
+
+static void
+ifcvt_local_dce (basic_block bb)
+{
+  gimple *stmt;
+  gimple *stmt1;
+  gimple *phi;
+  gimple_stmt_iterator gsi;
+  auto_vec<gimple *> worklist;
+  enum gimple_code code;
+  use_operand_p use_p;
+  imm_use_iterator imm_iter;
+  std::pair <tree, tree> *name_pair;
+  unsigned int i;
+
+  FOR_EACH_VEC_ELT (redundant_ssa_names, i, name_pair)
+    replace_uses_by (name_pair->first, name_pair->second);
+  redundant_ssa_names.release ();
+
+  worklist.create (64);
+  /* Consider all phi as live statements.  */
+  for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      phi = gsi_stmt (gsi);
+      gimple_set_plf (phi, GF_PLF_2, true);
+      worklist.safe_push (phi);
+    }
+  /* Consider load/store statements, CALL and COND as live.  */
+  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      stmt = gsi_stmt (gsi);
+      if (gimple_store_p (stmt)
+         || gimple_assign_load_p (stmt)
+         || is_gimple_debug (stmt))
+       {
+         gimple_set_plf (stmt, GF_PLF_2, true);
+         worklist.safe_push (stmt);
+         continue;
+       }
+      code = gimple_code (stmt);
+      if (code == GIMPLE_COND || code == GIMPLE_CALL)
+       {
+         gimple_set_plf (stmt, GF_PLF_2, true);
+         worklist.safe_push (stmt);
+         continue;
+       }
+      gimple_set_plf (stmt, GF_PLF_2, false);
+
+      if (code == GIMPLE_ASSIGN)
+       {
+         tree lhs = gimple_assign_lhs (stmt);
+         FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
+           {
+             stmt1 = USE_STMT (use_p);
+             if (gimple_bb (stmt1) != bb)
+               {
+                 gimple_set_plf (stmt, GF_PLF_2, true);
+                 worklist.safe_push (stmt);
+                 break;
+               }
+           }
+       }
+    }
+  /* Propagate liveness through arguments of live stmt.  */
+  while (worklist.length () > 0)
+    {
+      ssa_op_iter iter;
+      use_operand_p use_p;
+      tree use;
+
+      stmt = worklist.pop ();
+      FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
+       {
+         use = USE_FROM_PTR (use_p);
+         if (TREE_CODE (use) != SSA_NAME)
+           continue;
+         stmt1 = SSA_NAME_DEF_STMT (use);
+         if (gimple_bb (stmt1) != bb
+             || gimple_plf (stmt1, GF_PLF_2))
+           continue;
+         gimple_set_plf (stmt1, GF_PLF_2, true);
+         worklist.safe_push (stmt1);
+       }
+    }
+  /* Delete dead statements.  */
+  gsi = gsi_start_bb (bb);
+  while (!gsi_end_p (gsi))
+    {
+      stmt = gsi_stmt (gsi);
+      if (gimple_plf (stmt, GF_PLF_2))
+       {
+         gsi_next (&gsi);
+         continue;
+       }
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "Delete dead stmt in bb#%d\n", bb->index);
+         print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+       }
+      gsi_remove (&gsi, true);
+      release_defs (stmt);
+    }
+}
+
 /* If-convert LOOP when it is legal.  For the moment this pass has no
    profitability analysis.  Returns non-zero todo flags when something
    changed.  */
 
-static unsigned int
+unsigned int
 tree_if_conversion (struct loop *loop)
 {
   unsigned int todo = 0;
+  bool aggressive_if_conv;
+  struct loop *rloop;
+  bitmap exit_bbs;
+
+ again:
+  rloop = NULL;
   ifc_bbs = NULL;
-  bool any_mask_load_store = false;
+  need_to_predicate = false;
+  any_complicated_phi = false;
+
+  /* Apply more aggressive if-conversion when loop or its outer loop were
+     marked with simd pragma.  When that's the case, we try to if-convert
+     loop containing PHIs with more than MAX_PHI_ARG_NUM arguments.  */
+  aggressive_if_conv = loop->force_vectorize;
+  if (!aggressive_if_conv)
+    {
+      struct loop *outer_loop = loop_outer (loop);
+      if (outer_loop && outer_loop->force_vectorize)
+       aggressive_if_conv = true;
+    }
 
-  if (!if_convertible_loop_p (loop, &any_mask_load_store)
+  if (!ifcvt_split_critical_edges (loop, aggressive_if_conv))
+    goto cleanup;
+
+  if (!if_convertible_loop_p (loop)
       || !dbg_cnt (if_conversion_tree))
     goto cleanup;
 
-  if (any_mask_load_store
+  if ((need_to_predicate || any_complicated_phi)
       && ((!flag_tree_loop_vectorize && !loop->force_vectorize)
          || loop->dont_vectorize))
     goto cleanup;
 
-  if (any_mask_load_store && !version_loop_for_if_conversion (loop))
-    goto cleanup;
+  /* Since we have no cost model, always version loops unless the user
+     specified -ftree-loop-if-convert or unless versioning is required.
+     Either version this loop, or if the pattern is right for outer-loop
+     vectorization, version the outer loop.  In the latter case we will
+     still if-convert the original inner loop.  */
+  if (need_to_predicate
+      || any_complicated_phi
+      || flag_tree_loop_if_convert != 1)
+    {
+      struct loop *vloop
+       = (versionable_outer_loop_p (loop_outer (loop))
+          ? loop_outer (loop) : loop);
+      struct loop *nloop = version_loop_for_if_conversion (vloop);
+      if (nloop == NULL)
+       goto cleanup;
+      if (vloop != loop)
+       {
+         /* If versionable_outer_loop_p decided to version the
+            outer loop, version also the inner loop of the non-vectorized
+            loop copy.  So we transform:
+             loop1
+               loop2
+            into:
+             if (LOOP_VECTORIZED (1, 3))
+               {
+                 loop1
+                   loop2
+               }
+             else
+               loop3 (copy of loop1)
+                 if (LOOP_VECTORIZED (4, 5))
+                   loop4 (copy of loop2)
+                 else
+                   loop5 (copy of loop4)  */
+         gcc_assert (nloop->inner && nloop->inner->next == NULL);
+         rloop = nloop->inner;
+       }
+    }
 
   /* Now all statements are if-convertible.  Combine all the basic
      blocks into one huge basic block doing the if-conversion
      on-the-fly.  */
-  combine_blocks (loop, any_mask_load_store);
+  combine_blocks (loop);
+
+  /* Delete dead predicate computations.  */
+  ifcvt_local_dce (loop->header);
+
+  /* Perform local CSE, this esp. helps the vectorizer analysis if loads
+     and stores are involved.
+     ???  We'll still keep dead stores though.  */
+  exit_bbs = BITMAP_ALLOC (NULL);
+  bitmap_set_bit (exit_bbs, single_exit (loop)->dest->index);
+  todo |= do_rpo_vn (cfun, loop_preheader_edge (loop), exit_bbs);
+  BITMAP_FREE (exit_bbs);
 
   todo |= TODO_cleanup_cfg;
-  if (flag_tree_loop_if_convert_stores || any_mask_load_store)
-    {
-      mark_virtual_operands_for_renaming (cfun);
-      todo |= TODO_update_ssa_only_virtuals;
-    }
 
  cleanup:
   if (ifc_bbs)
@@ -2200,7 +3083,11 @@ tree_if_conversion (struct loop *loop)
       free (ifc_bbs);
       ifc_bbs = NULL;
     }
-  free_dominance_info (CDI_POST_DOMINATORS);
+  if (rloop != NULL)
+    {
+      loop = rloop;
+      goto again;
+    }
 
   return todo;
 }
@@ -2214,7 +3101,7 @@ const pass_data pass_data_if_conversion =
   GIMPLE_PASS, /* type */
   "ifcvt", /* name */
   OPTGROUP_NONE, /* optinfo_flags */
-  TV_NONE, /* tv_id */
+  TV_TREE_LOOP_IFCVT, /* tv_id */
   ( PROP_cfg | PROP_ssa ), /* properties_required */
   0, /* properties_provided */
   0, /* properties_destroyed */
@@ -2240,8 +3127,7 @@ pass_if_conversion::gate (function *fun)
 {
   return (((flag_tree_loop_vectorize || fun->has_force_vectorize_loops)
           && flag_tree_loop_if_convert != 0)
-         || flag_tree_loop_if_convert == 1
-         || flag_tree_loop_if_convert_stores == 1);
+         || flag_tree_loop_if_convert == 1);
 }
 
 unsigned int
@@ -2255,18 +3141,22 @@ pass_if_conversion::execute (function *fun)
 
   FOR_EACH_LOOP (loop, 0)
     if (flag_tree_loop_if_convert == 1
-       || flag_tree_loop_if_convert_stores == 1
        || ((flag_tree_loop_vectorize || loop->force_vectorize)
            && !loop->dont_vectorize))
       todo |= tree_if_conversion (loop);
 
-#ifdef ENABLE_CHECKING
-  {
-    basic_block bb;
-    FOR_EACH_BB_FN (bb, fun)
-      gcc_assert (!bb->aux);
-  }
-#endif
+  if (todo)
+    {
+      free_numbers_of_iterations_estimates (fun);
+      scev_reset ();
+    }
+
+  if (flag_checking)
+    {
+      basic_block bb;
+      FOR_EACH_BB_FN (bb, fun)
+       gcc_assert (!bb->aux);
+    }
 
   return todo;
 }