The following patch removes the restriction on seeing a tree of stmts
in vectorizer bool pattern detection (aka single-use).  With this
it is no longer necessary to unshare DEFs in ifcvt_repair_bool_pattern
and that compile-time hog can go (it's now enabled unconditionally for GCC 7).

Instead the pattern detection code will now "unshare" the condition tree
for each bool pattern root my means of adding all pattern stmts of the
condition tree to its pattern def sequence (so we still get some
unnecessary copying, worst-case quadratic rather than exponential).

Ilja - I had to disable the

          tree mask_type = get_mask_type_for_scalar_type (TREE_TYPE 
(rhs1));
          if (mask_type
              && expand_vec_cmp_expr_p (comp_vectype, mask_type))
            return false;

check you added to check_bool_pattern to get any coverage for bool
patterns on x86_64.  Doing that regresses

FAIL: gcc.target/i386/mask-pack.c scan-tree-dump-times vect "vectorized 1 
loops" 10
FAIL: gcc.target/i386/mask-unpack.c scan-tree-dump-times vect "vectorized 
1 loops" 10
FAIL: gcc.target/i386/pr70021.c scan-tree-dump-times vect "vectorized 1 
loops" 2

so somehow bool patterns mess up things here (I didn't investigate).
The final patch will enable the above path again, avoiding the regression.

Yuri - I suppose you have a larger set of testcases using OMP simd
or other forced vectorization you added ifcvt_repair_bool_pattern for.
I'd appreciate testing (and testcases if anything fails unexpectedly).

Testing on other targets is of course appreciated as well.

Bootstrapped and tested on x86_64-unknown-linux-gnu (with the #if 0).

Comments?

I agree with Ilya elsewhere to remove bool patterns completely
(as a first step making them apply to individual stmts).  We do
currently not support mixed cond/non-cond uses anyway, like

_Bool a[64];
unsigned char b[64];

void foo (void)
{
  for (int i = 0; i < 64; ++i)
    {
      _Bool x = a[i] && b[i] < 10;
      a[i] = x;
    }
}

and stmt-local "patterns" can be added when vectorizing the stmt
(like in the above case a tem = a[i] != 0 ? -1 : 0).  Doing
bool "promotion" optimally requires a better vectorizer IL
(similar to placing of shuffles).

Thanks,
Richard.

2016-05-30  Richard Biener  <rguent...@suse.de>

        PR tree-optimization/71261
        * tree-vect-patterns.c (check_bool_pattern): Gather a hash-set
        of stmts successfully put in the bool pattern.  Remove
        single-use restriction.
        (adjust_bool_pattern_cast): Add cast at the use site via the
        pattern def sequence.
        (adjust_bool_pattern): Remove recursion, maintain a hash-map
        of patterned defs.  Use the pattern def seqence instead of
        multiple independent patterns.
        (sort_after_uid): New qsort compare function.
        (adjust_bool_stmts): New function to process stmts in the bool
        pattern in IL order.
        (vect_recog_bool_pattern): Adjust.
        * tree-if-conv.c (ifcvt_split_def_stmt): Remove.
        (ifcvt_walk_pattern_tree): Likewise.
        (stmt_is_root_of_bool_pattern): Likewise.
        (ifcvt_repair_bool_pattern): Likewise.
        (tree_if_conversion): Do not call ifcvt_repair_bool_pattern.

        * gcc.dg/torture/vect-bool-1.c: New testcase.

Index: gcc/tree-vect-patterns.c
===================================================================
*** gcc/tree-vect-patterns.c.orig       2016-05-27 14:32:49.778686018 +0200
--- gcc/tree-vect-patterns.c    2016-05-30 11:06:23.563532173 +0200
*************** vect_recog_mixed_size_cond_pattern (vec<
*** 2888,2897 ****
  /* Helper function of vect_recog_bool_pattern.  Called recursively, return
     true if bool VAR can and should be optimized that way.  Assume it shouldn't
     in case it's a result of a comparison which can be directly vectorized into
!    a vector comparison.  */
  
  static bool
! check_bool_pattern (tree var, vec_info *vinfo)
  {
    gimple *def_stmt;
    enum vect_def_type dt;
--- 2888,2898 ----
  /* Helper function of vect_recog_bool_pattern.  Called recursively, return
     true if bool VAR can and should be optimized that way.  Assume it shouldn't
     in case it's a result of a comparison which can be directly vectorized into
!    a vector comparison.  Fills in STMTS with all stmts visited during the
!    walk.  */
  
  static bool
! check_bool_pattern (tree var, vec_info *vinfo, hash_set<gimple *> &stmts)
  {
    gimple *def_stmt;
    enum vect_def_type dt;
*************** check_bool_pattern (tree var, vec_info *
*** 2907,2943 ****
    if (!is_gimple_assign (def_stmt))
      return false;
  
!   if (!has_single_use (var))
!     return false;
  
    rhs1 = gimple_assign_rhs1 (def_stmt);
    rhs_code = gimple_assign_rhs_code (def_stmt);
    switch (rhs_code)
      {
      case SSA_NAME:
!       return check_bool_pattern (rhs1, vinfo);
  
      CASE_CONVERT:
        if ((TYPE_PRECISION (TREE_TYPE (rhs1)) != 1
           || !TYPE_UNSIGNED (TREE_TYPE (rhs1)))
          && TREE_CODE (TREE_TYPE (rhs1)) != BOOLEAN_TYPE)
        return false;
!       return check_bool_pattern (rhs1, vinfo);
  
      case BIT_NOT_EXPR:
!       return check_bool_pattern (rhs1, vinfo);
  
      case BIT_AND_EXPR:
      case BIT_IOR_EXPR:
      case BIT_XOR_EXPR:
!       if (!check_bool_pattern (rhs1, vinfo))
        return false;
!       return check_bool_pattern (gimple_assign_rhs2 (def_stmt), vinfo);
  
      default:
        if (TREE_CODE_CLASS (rhs_code) == tcc_comparison)
        {
!         tree vecitype, comp_vectype, mask_type;
  
          /* If the comparison can throw, then is_gimple_condexpr will be
             false and we can't make a COND_EXPR/VEC_COND_EXPR out of it.  */
--- 2908,2951 ----
    if (!is_gimple_assign (def_stmt))
      return false;
  
!   if (stmts.contains (def_stmt))
!     return true;
  
    rhs1 = gimple_assign_rhs1 (def_stmt);
    rhs_code = gimple_assign_rhs_code (def_stmt);
    switch (rhs_code)
      {
      case SSA_NAME:
!       if (! check_bool_pattern (rhs1, vinfo, stmts))
!       return false;
!       break;
  
      CASE_CONVERT:
        if ((TYPE_PRECISION (TREE_TYPE (rhs1)) != 1
           || !TYPE_UNSIGNED (TREE_TYPE (rhs1)))
          && TREE_CODE (TREE_TYPE (rhs1)) != BOOLEAN_TYPE)
        return false;
!       if (! check_bool_pattern (rhs1, vinfo, stmts))
!       return false;
!       break;
  
      case BIT_NOT_EXPR:
!       if (! check_bool_pattern (rhs1, vinfo, stmts))
!       return false;
!       break;
  
      case BIT_AND_EXPR:
      case BIT_IOR_EXPR:
      case BIT_XOR_EXPR:
!       if (! check_bool_pattern (rhs1, vinfo, stmts)
!         || ! check_bool_pattern (gimple_assign_rhs2 (def_stmt), vinfo, stmts))
        return false;
!       break;
  
      default:
        if (TREE_CODE_CLASS (rhs_code) == tcc_comparison)
        {
!         tree vecitype, comp_vectype;
  
          /* If the comparison can throw, then is_gimple_condexpr will be
             false and we can't make a COND_EXPR/VEC_COND_EXPR out of it.  */
*************** check_bool_pattern (tree var, vec_info *
*** 2948,2957 ****
          if (comp_vectype == NULL_TREE)
            return false;
  
!         mask_type = get_mask_type_for_scalar_type (TREE_TYPE (rhs1));
          if (mask_type
              && expand_vec_cmp_expr_p (comp_vectype, mask_type))
            return false;
  
          if (TREE_CODE (TREE_TYPE (rhs1)) != INTEGER_TYPE)
            {
--- 2956,2967 ----
          if (comp_vectype == NULL_TREE)
            return false;
  
! #if 0
!         tree mask_type = get_mask_type_for_scalar_type (TREE_TYPE (rhs1));
          if (mask_type
              && expand_vec_cmp_expr_p (comp_vectype, mask_type))
            return false;
+ #endif
  
          if (TREE_CODE (TREE_TYPE (rhs1)) != INTEGER_TYPE)
            {
*************** check_bool_pattern (tree var, vec_info *
*** 2964,3013 ****
            }
          else
            vecitype = comp_vectype;
!         return expand_vec_cond_expr_p (vecitype, comp_vectype);
        }
!       return false;
      }
  }
  
  
  /* Helper function of adjust_bool_pattern.  Add a cast to TYPE to a previous
!    stmt (SSA_NAME_DEF_STMT of VAR) by moving the COND_EXPR from RELATED_STMT
!    to PATTERN_DEF_SEQ and adding a cast as RELATED_STMT.  */
  
  static tree
! adjust_bool_pattern_cast (tree type, tree var)
  {
!   stmt_vec_info stmt_vinfo = vinfo_for_stmt (SSA_NAME_DEF_STMT (var));
!   gimple *cast_stmt, *pattern_stmt;
! 
!   gcc_assert (!STMT_VINFO_PATTERN_DEF_SEQ (stmt_vinfo));
!   pattern_stmt = STMT_VINFO_RELATED_STMT (stmt_vinfo);
!   new_pattern_def_seq (stmt_vinfo, pattern_stmt);
!   cast_stmt = gimple_build_assign (vect_recog_temp_ssa_var (type, NULL),
!                                  NOP_EXPR, gimple_assign_lhs (pattern_stmt));
!   STMT_VINFO_RELATED_STMT (stmt_vinfo) = cast_stmt;
    return gimple_assign_lhs (cast_stmt);
  }
  
! 
! /* Helper function of vect_recog_bool_pattern.  Do the actual transformations,
!    recursively.  VAR is an SSA_NAME that should be transformed from bool
!    to a wider integer type, OUT_TYPE is the desired final integer type of
!    the whole pattern, TRUEVAL should be NULL unless optimizing
!    BIT_AND_EXPR into a COND_EXPR with one integer from one of the operands
!    in the then_clause, STMTS is where statements with added pattern stmts
!    should be pushed to.  */
! 
! static tree
! adjust_bool_pattern (tree var, tree out_type, tree trueval,
!                    vec<gimple *> *stmts)
  {
    gimple *stmt = SSA_NAME_DEF_STMT (var);
    enum tree_code rhs_code, def_rhs_code;
    tree itype, cond_expr, rhs1, rhs2, irhs1, irhs2;
    location_t loc;
    gimple *pattern_stmt, *def_stmt;
  
    rhs1 = gimple_assign_rhs1 (stmt);
    rhs2 = gimple_assign_rhs2 (stmt);
--- 2974,3027 ----
            }
          else
            vecitype = comp_vectype;
!         if (! expand_vec_cond_expr_p (vecitype, comp_vectype))
!           return false;
        }
!       else
!       return false;
!       break;
      }
+ 
+   bool res = stmts.add (def_stmt);
+   /* We can't end up recursing when just visiting SSA defs but not PHIs.  */
+   gcc_assert (!res);
+ 
+   return true;
  }
  
  
  /* Helper function of adjust_bool_pattern.  Add a cast to TYPE to a previous
!    stmt (SSA_NAME_DEF_STMT of VAR) adding a cast to STMT_INFOs
!    pattern sequence.  */
  
  static tree
! adjust_bool_pattern_cast (tree type, tree var, stmt_vec_info stmt_info)
  {
!   gimple *cast_stmt = gimple_build_assign (vect_recog_temp_ssa_var (type, 
NULL),
!                                          NOP_EXPR, var);
!   stmt_vec_info patt_vinfo = new_stmt_vec_info (cast_stmt, stmt_info->vinfo);
!   set_vinfo_for_stmt (cast_stmt, patt_vinfo);
!   STMT_VINFO_VECTYPE (patt_vinfo) = get_vectype_for_scalar_type (type);
!   append_pattern_def_seq (stmt_info, cast_stmt);
    return gimple_assign_lhs (cast_stmt);
  }
  
! /* Helper function of vect_recog_bool_pattern.  Do the actual transformations.
!    VAR is an SSA_NAME that should be transformed from bool to a wider integer
!    type, OUT_TYPE is the desired final integer type of the whole pattern.
!    STMT_INFO is the info of the pattern root and is where pattern stmts should
!    be associated with.  DEFS is a map of pattern defs.  */
! 
! static void
! adjust_bool_pattern (tree var, tree out_type,
!                    stmt_vec_info stmt_info, hash_map <tree, tree> &defs)
  {
    gimple *stmt = SSA_NAME_DEF_STMT (var);
    enum tree_code rhs_code, def_rhs_code;
    tree itype, cond_expr, rhs1, rhs2, irhs1, irhs2;
    location_t loc;
    gimple *pattern_stmt, *def_stmt;
+   tree trueval = NULL_TREE;
  
    rhs1 = gimple_assign_rhs1 (stmt);
    rhs2 = gimple_assign_rhs2 (stmt);
*************** adjust_bool_pattern (tree var, tree out_
*** 3017,3023 ****
      {
      case SSA_NAME:
      CASE_CONVERT:
!       irhs1 = adjust_bool_pattern (rhs1, out_type, NULL_TREE, stmts);
        itype = TREE_TYPE (irhs1);
        pattern_stmt
        = gimple_build_assign (vect_recog_temp_ssa_var (itype, NULL),
--- 3031,3037 ----
      {
      case SSA_NAME:
      CASE_CONVERT:
!       irhs1 = *defs.get (rhs1);
        itype = TREE_TYPE (irhs1);
        pattern_stmt
        = gimple_build_assign (vect_recog_temp_ssa_var (itype, NULL),
*************** adjust_bool_pattern (tree var, tree out_
*** 3025,3031 ****
        break;
  
      case BIT_NOT_EXPR:
!       irhs1 = adjust_bool_pattern (rhs1, out_type, NULL_TREE, stmts);
        itype = TREE_TYPE (irhs1);
        pattern_stmt
        = gimple_build_assign (vect_recog_temp_ssa_var (itype, NULL),
--- 3039,3045 ----
        break;
  
      case BIT_NOT_EXPR:
!       irhs1 = *defs.get (rhs1);
        itype = TREE_TYPE (irhs1);
        pattern_stmt
        = gimple_build_assign (vect_recog_temp_ssa_var (itype, NULL),
*************** adjust_bool_pattern (tree var, tree out_
*** 3070,3126 ****
        def_rhs_code = gimple_assign_rhs_code (def_stmt);
        if (TREE_CODE_CLASS (def_rhs_code) == tcc_comparison)
        {
          tree def_rhs1 = gimple_assign_rhs1 (def_stmt);
-         irhs1 = adjust_bool_pattern (rhs1, out_type, NULL_TREE, stmts);
          if (TYPE_PRECISION (TREE_TYPE (irhs1))
              == GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (def_rhs1))))
            {
!             gimple *tstmt;
!             stmt_vec_info stmt_def_vinfo = vinfo_for_stmt (def_stmt);
!             irhs2 = adjust_bool_pattern (rhs2, out_type, irhs1, stmts);
!             tstmt = stmts->pop ();
!             gcc_assert (tstmt == def_stmt);
!             stmts->quick_push (stmt);
!             STMT_VINFO_RELATED_STMT (vinfo_for_stmt (stmt))
!               = STMT_VINFO_RELATED_STMT (stmt_def_vinfo);
!             gcc_assert (!STMT_VINFO_PATTERN_DEF_SEQ (stmt_def_vinfo));
!             STMT_VINFO_RELATED_STMT (stmt_def_vinfo) = NULL;
!             return irhs2;
            }
          else
!           irhs2 = adjust_bool_pattern (rhs2, out_type, NULL_TREE, stmts);
          goto and_ior_xor;
        }
        def_stmt = SSA_NAME_DEF_STMT (rhs1);
        def_rhs_code = gimple_assign_rhs_code (def_stmt);
        if (TREE_CODE_CLASS (def_rhs_code) == tcc_comparison)
        {
          tree def_rhs1 = gimple_assign_rhs1 (def_stmt);
-         irhs2 = adjust_bool_pattern (rhs2, out_type, NULL_TREE, stmts);
          if (TYPE_PRECISION (TREE_TYPE (irhs2))
              == GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (def_rhs1))))
            {
!             gimple *tstmt;
!             stmt_vec_info stmt_def_vinfo = vinfo_for_stmt (def_stmt);
!             irhs1 = adjust_bool_pattern (rhs1, out_type, irhs2, stmts);
!             tstmt = stmts->pop ();
!             gcc_assert (tstmt == def_stmt);
!             stmts->quick_push (stmt);
!             STMT_VINFO_RELATED_STMT (vinfo_for_stmt (stmt))
!               = STMT_VINFO_RELATED_STMT (stmt_def_vinfo);
!             gcc_assert (!STMT_VINFO_PATTERN_DEF_SEQ (stmt_def_vinfo));
!             STMT_VINFO_RELATED_STMT (stmt_def_vinfo) = NULL;
!             return irhs1;
            }
          else
!           irhs1 = adjust_bool_pattern (rhs1, out_type, NULL_TREE, stmts);
          goto and_ior_xor;
        }
        /* FALLTHRU */
      case BIT_IOR_EXPR:
      case BIT_XOR_EXPR:
!       irhs1 = adjust_bool_pattern (rhs1, out_type, NULL_TREE, stmts);
!       irhs2 = adjust_bool_pattern (rhs2, out_type, NULL_TREE, stmts);
      and_ior_xor:
        if (TYPE_PRECISION (TREE_TYPE (irhs1))
          != TYPE_PRECISION (TREE_TYPE (irhs2)))
--- 3084,3128 ----
        def_rhs_code = gimple_assign_rhs_code (def_stmt);
        if (TREE_CODE_CLASS (def_rhs_code) == tcc_comparison)
        {
+         irhs1 = *defs.get (rhs1);
          tree def_rhs1 = gimple_assign_rhs1 (def_stmt);
          if (TYPE_PRECISION (TREE_TYPE (irhs1))
              == GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (def_rhs1))))
            {
!             rhs_code = def_rhs_code;
!             rhs1 = def_rhs1;
!             rhs2 = gimple_assign_rhs2 (def_stmt);
!             trueval = irhs1;
!             goto do_compare;
            }
          else
!           irhs2 = *defs.get (rhs2);
          goto and_ior_xor;
        }
        def_stmt = SSA_NAME_DEF_STMT (rhs1);
        def_rhs_code = gimple_assign_rhs_code (def_stmt);
        if (TREE_CODE_CLASS (def_rhs_code) == tcc_comparison)
        {
+         irhs2 = *defs.get (rhs2);
          tree def_rhs1 = gimple_assign_rhs1 (def_stmt);
          if (TYPE_PRECISION (TREE_TYPE (irhs2))
              == GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (def_rhs1))))
            {
!             rhs_code = def_rhs_code;
!             rhs1 = def_rhs1;
!             rhs2 = gimple_assign_rhs2 (def_stmt);
!             trueval = irhs2;
!             goto do_compare;
            }
          else
!           irhs1 = *defs.get (rhs1);
          goto and_ior_xor;
        }
        /* FALLTHRU */
      case BIT_IOR_EXPR:
      case BIT_XOR_EXPR:
!       irhs1 = *defs.get (rhs1);
!       irhs2 = *defs.get (rhs2);
      and_ior_xor:
        if (TYPE_PRECISION (TREE_TYPE (irhs1))
          != TYPE_PRECISION (TREE_TYPE (irhs2)))
*************** adjust_bool_pattern (tree var, tree out_
*** 3129,3141 ****
          int prec2 = TYPE_PRECISION (TREE_TYPE (irhs2));
          int out_prec = TYPE_PRECISION (out_type);
          if (absu_hwi (out_prec - prec1) < absu_hwi (out_prec - prec2))
!           irhs2 = adjust_bool_pattern_cast (TREE_TYPE (irhs1), rhs2);
          else if (absu_hwi (out_prec - prec1) > absu_hwi (out_prec - prec2))
!           irhs1 = adjust_bool_pattern_cast (TREE_TYPE (irhs2), rhs1);
          else
            {
!             irhs1 = adjust_bool_pattern_cast (out_type, rhs1);
!             irhs2 = adjust_bool_pattern_cast (out_type, rhs2);
            }
        }
        itype = TREE_TYPE (irhs1);
--- 3131,3145 ----
          int prec2 = TYPE_PRECISION (TREE_TYPE (irhs2));
          int out_prec = TYPE_PRECISION (out_type);
          if (absu_hwi (out_prec - prec1) < absu_hwi (out_prec - prec2))
!           irhs2 = adjust_bool_pattern_cast (TREE_TYPE (irhs1), irhs2,
!                                             stmt_info);
          else if (absu_hwi (out_prec - prec1) > absu_hwi (out_prec - prec2))
!           irhs1 = adjust_bool_pattern_cast (TREE_TYPE (irhs2), irhs1,
!                                             stmt_info);
          else
            {
!             irhs1 = adjust_bool_pattern_cast (out_type, irhs1, stmt_info);
!             irhs2 = adjust_bool_pattern_cast (out_type, irhs2, stmt_info);
            }
        }
        itype = TREE_TYPE (irhs1);
*************** adjust_bool_pattern (tree var, tree out_
*** 3145,3150 ****
--- 3149,3155 ----
        break;
  
      default:
+     do_compare:
        gcc_assert (TREE_CODE_CLASS (rhs_code) == tcc_comparison);
        if (TREE_CODE (TREE_TYPE (rhs1)) != INTEGER_TYPE
          || !TYPE_UNSIGNED (TREE_TYPE (rhs1))
*************** adjust_bool_pattern (tree var, tree out_
*** 3170,3181 ****
        break;
      }
  
-   stmts->safe_push (stmt);
    gimple_set_location (pattern_stmt, loc);
!   STMT_VINFO_RELATED_STMT (vinfo_for_stmt (stmt)) = pattern_stmt;
!   return gimple_assign_lhs (pattern_stmt);
  }
  
  
  /* Return the proper type for converting bool VAR into
     an integer value or NULL_TREE if no such type exists.
--- 3175,3228 ----
        break;
      }
  
    gimple_set_location (pattern_stmt, loc);
!   /* ???  Why does vect_mark_pattern_stmts set the vector type on all
!      pattern def seq stmts instead of just letting auto-detection do
!      its work?  */
!   stmt_vec_info patt_vinfo = new_stmt_vec_info (pattern_stmt, 
stmt_info->vinfo);
!   set_vinfo_for_stmt (pattern_stmt, patt_vinfo);
!   STMT_VINFO_VECTYPE (patt_vinfo) = get_vectype_for_scalar_type (itype);
!   append_pattern_def_seq (stmt_info, pattern_stmt);
!   defs.put (var, gimple_assign_lhs (pattern_stmt));
  }
  
+ /* Comparison function to qsort a vector of gimple stmts after UID.  */
+ 
+ static int
+ sort_after_uid (const void *p1, const void *p2)
+ {
+   const gimple *stmt1 = *(const gimple * const *)p1;
+   const gimple *stmt2 = *(const gimple * const *)p2;
+   return gimple_uid (stmt1) - gimple_uid (stmt2);
+ }
+ 
+ /* Create pattern stmts for all stmts participating in the bool pattern
+    specified by BOOL_STMT_SET and its root STMT with the desired type
+    OUT_TYPE.  Return the def of the pattern root.  */
+ 
+ static tree
+ adjust_bool_stmts (hash_set <gimple *> &bool_stmt_set,
+                  tree out_type, gimple *stmt)
+ {
+   /* Gather original stmts in the bool pattern in their order of appearance
+      in the IL.  */
+   auto_vec<gimple *> bool_stmts (bool_stmt_set.elements ());
+   for (hash_set <gimple *>::iterator i = bool_stmt_set.begin ();
+        i != bool_stmt_set.end (); ++i)
+     bool_stmts.quick_push (*i);
+   bool_stmts.qsort (sort_after_uid);
+ 
+   /* Now process them in that order, producing pattern stmts.  */
+   hash_map <tree, tree> defs;
+   for (unsigned i = 0; i < bool_stmts.length (); ++i)
+     adjust_bool_pattern (gimple_assign_lhs (bool_stmts[i]),
+                        out_type, vinfo_for_stmt (stmt), defs);
+ 
+   /* Pop the last pattern seq stmt and install it as pattern root for STMT.  
*/
+   gimple *pattern_stmt
+     = gimple_seq_last_stmt (STMT_VINFO_PATTERN_DEF_SEQ (vinfo_for_stmt 
(stmt)));
+   return gimple_assign_lhs (pattern_stmt);
+ }
  
  /* Return the proper type for converting bool VAR into
     an integer value or NULL_TREE if no such type exists.
*************** vect_recog_bool_pattern (vec<gimple *> *
*** 3338,3343 ****
--- 3385,3392 ----
        && TREE_CODE (TREE_TYPE (var)) != BOOLEAN_TYPE)
      return NULL;
  
+   hash_set<gimple *> bool_stmts;
+ 
    rhs_code = gimple_assign_rhs_code (last_stmt);
    if (CONVERT_EXPR_CODE_P (rhs_code))
      {
*************** vect_recog_bool_pattern (vec<gimple *> *
*** 3348,3356 ****
        if (vectype == NULL_TREE)
        return NULL;
  
!       if (check_bool_pattern (var, vinfo))
        {
!         rhs = adjust_bool_pattern (var, TREE_TYPE (lhs), NULL_TREE, stmts);
          lhs = vect_recog_temp_ssa_var (TREE_TYPE (lhs), NULL);
          if (useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
            pattern_stmt = gimple_build_assign (lhs, SSA_NAME, rhs);
--- 3397,3405 ----
        if (vectype == NULL_TREE)
        return NULL;
  
!       if (check_bool_pattern (var, vinfo, bool_stmts))
        {
!         rhs = adjust_bool_stmts (bool_stmts, TREE_TYPE (lhs), last_stmt);
          lhs = vect_recog_temp_ssa_var (TREE_TYPE (lhs), NULL);
          if (useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs)))
            pattern_stmt = gimple_build_assign (lhs, SSA_NAME, rhs);
*************** vect_recog_bool_pattern (vec<gimple *> *
*** 3420,3429 ****
        if (get_vectype_for_scalar_type (type) == NULL_TREE)
        return NULL;
  
!       if (!check_bool_pattern (var, vinfo))
        return NULL;
  
!       rhs = adjust_bool_pattern (var, type, NULL_TREE, stmts);
  
        lhs = vect_recog_temp_ssa_var (TREE_TYPE (lhs), NULL);
        pattern_stmt 
--- 3469,3478 ----
        if (get_vectype_for_scalar_type (type) == NULL_TREE)
        return NULL;
  
!       if (!check_bool_pattern (var, vinfo, bool_stmts))
        return NULL;
  
!       rhs = adjust_bool_stmts (bool_stmts, type, last_stmt);
  
        lhs = vect_recog_temp_ssa_var (TREE_TYPE (lhs), NULL);
        pattern_stmt 
*************** vect_recog_bool_pattern (vec<gimple *> *
*** 3450,3458 ****
        if (!VECTOR_MODE_P (TYPE_MODE (vectype)))
        return NULL;
  
!       if (check_bool_pattern (var, vinfo))
!       rhs = adjust_bool_pattern (var, TREE_TYPE (vectype),
!                                  NULL_TREE, stmts);
        else
        {
          tree type = search_type_for_mask (var, vinfo);
--- 3499,3506 ----
        if (!VECTOR_MODE_P (TYPE_MODE (vectype)))
        return NULL;
  
!       if (check_bool_pattern (var, vinfo, bool_stmts))
!       rhs = adjust_bool_stmts (bool_stmts, TREE_TYPE (vectype), last_stmt);
        else
        {
          tree type = search_type_for_mask (var, vinfo);
Index: gcc/tree-if-conv.c
===================================================================
*** gcc/tree-if-conv.c.orig     2016-05-27 14:32:49.778686018 +0200
--- gcc/tree-if-conv.c  2016-05-30 09:52:10.086304123 +0200
*************** ifcvt_split_critical_edges (struct loop
*** 2516,2709 ****
    return true;
  }
  
- /* Assumes that lhs of DEF_STMT have multiple uses.
-    Delete one use by (1) creation of copy DEF_STMT with
-    unique lhs; (2) change original use of lhs in one
-    use statement with newly created lhs.  */
- 
- static void
- ifcvt_split_def_stmt (gimple *def_stmt, gimple *use_stmt)
- {
-   tree var;
-   tree lhs;
-   gimple *copy_stmt;
-   gimple_stmt_iterator gsi;
-   use_operand_p use_p;
-   ssa_op_iter iter;
- 
-   var = gimple_assign_lhs (def_stmt);
-   copy_stmt = gimple_copy (def_stmt);
-   lhs = make_temp_ssa_name (TREE_TYPE (var), NULL, "_ifc_");
-   gimple_assign_set_lhs (copy_stmt, lhs);
-   SSA_NAME_DEF_STMT (lhs) = copy_stmt;
-   /* Insert copy of DEF_STMT.  */
-   gsi = gsi_for_stmt (def_stmt);
-   gsi_insert_after (&gsi, copy_stmt, GSI_SAME_STMT);
-   /* Change use of var to lhs in use_stmt.  */
-   if (dump_file && (dump_flags & TDF_DETAILS))
-     {
-       fprintf (dump_file, "Change use of var  ");
-       print_generic_expr (dump_file, var, TDF_SLIM);
-       fprintf (dump_file, " to ");
-       print_generic_expr (dump_file, lhs, TDF_SLIM);
-       fprintf (dump_file, "\n");
-     }
-   FOR_EACH_SSA_USE_OPERAND (use_p, use_stmt, iter, SSA_OP_USE)
-     {
-       if (USE_FROM_PTR (use_p) != var)
-       continue;
-       SET_USE (use_p, lhs);
-       break;
-     }
- }
- 
- /* Traverse bool pattern recursively starting from VAR.
-    Save its def and use statements to defuse_list if VAR does
-    not have single use.  */
- 
- static void
- ifcvt_walk_pattern_tree (tree var, vec<gimple *> *defuse_list,
-                        gimple *use_stmt)
- {
-   tree rhs1, rhs2;
-   enum tree_code code;
-   gimple *def_stmt;
- 
-   if (TREE_CODE (var) != SSA_NAME)
-     return;
- 
-   def_stmt = SSA_NAME_DEF_STMT (var);
-   if (gimple_code (def_stmt) != GIMPLE_ASSIGN)
-     return;
-   if (!has_single_use (var))
-     {
-       /* Put def and use stmts into defuse_list.  */
-       defuse_list->safe_push (def_stmt);
-       defuse_list->safe_push (use_stmt);
-       if (dump_file && (dump_flags & TDF_DETAILS))
-       {
-         fprintf (dump_file, "Multiple lhs uses in stmt\n");
-         print_gimple_stmt (dump_file, def_stmt, 0, TDF_SLIM);
-       }
-     }
-   rhs1 = gimple_assign_rhs1 (def_stmt);
-   code = gimple_assign_rhs_code (def_stmt);
-   switch (code)
-     {
-     case SSA_NAME:
-       ifcvt_walk_pattern_tree (rhs1, defuse_list, def_stmt);
-       break;
-     CASE_CONVERT:
-       if ((TYPE_PRECISION (TREE_TYPE (rhs1)) != 1
-          || !TYPE_UNSIGNED (TREE_TYPE (rhs1)))
-         && TREE_CODE (TREE_TYPE (rhs1)) != BOOLEAN_TYPE)
-       break;
-       ifcvt_walk_pattern_tree (rhs1, defuse_list, def_stmt);
-       break;
-     case BIT_NOT_EXPR:
-       ifcvt_walk_pattern_tree (rhs1, defuse_list, def_stmt);
-       break;
-     case BIT_AND_EXPR:
-     case BIT_IOR_EXPR:
-     case BIT_XOR_EXPR:
-       ifcvt_walk_pattern_tree (rhs1, defuse_list, def_stmt);
-       rhs2 = gimple_assign_rhs2 (def_stmt);
-       ifcvt_walk_pattern_tree (rhs2, defuse_list, def_stmt);
-       break;
-     default:
-       break;
-     }
-   return;
- }
- 
- /* Returns true if STMT can be a root of bool pattern applied
-    by vectorizer.  */
- 
- static bool
- stmt_is_root_of_bool_pattern (gimple *stmt)
- {
-   enum tree_code code;
-   tree lhs, rhs;
- 
-   code = gimple_assign_rhs_code (stmt);
-   if (CONVERT_EXPR_CODE_P (code))
-     {
-       lhs = gimple_assign_lhs (stmt);
-       rhs = gimple_assign_rhs1 (stmt);
-       if (TREE_CODE (TREE_TYPE (rhs)) != BOOLEAN_TYPE)
-       return false;
-       if (TREE_CODE (TREE_TYPE (lhs)) == BOOLEAN_TYPE)
-       return false;
-       return true;
-     }
-   else if (code == COND_EXPR)
-     {
-       rhs = gimple_assign_rhs1 (stmt);
-       if (TREE_CODE (rhs) != SSA_NAME)
-       return false;
-       return true;
-     }
-   return false;
- }
- 
- /*  Traverse all statements in BB which correspond to loop header to
-     find out all statements which can start bool pattern applied by
-     vectorizer and convert multiple uses in it to conform pattern
-     restrictions.  Such case can occur if the same predicate is used both
-     for phi node conversion and load/store mask.  */
- 
- static void
- ifcvt_repair_bool_pattern (basic_block bb)
- {
-   tree rhs;
-   gimple *stmt;
-   gimple_stmt_iterator gsi;
-   auto_vec<gimple *> defuse_list;
-   auto_vec<gimple *> pattern_roots;
-   bool repeat = true;
-   int niter = 0;
-   unsigned int ix;
- 
-   /* Collect all root pattern statements.  */
-   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-     {
-       stmt = gsi_stmt (gsi);
-       if (gimple_code (stmt) != GIMPLE_ASSIGN)
-       continue;
-       if (!stmt_is_root_of_bool_pattern (stmt))
-       continue;
-       pattern_roots.safe_push (stmt);
-     }
- 
-   if (pattern_roots.is_empty ())
-     return;
- 
-   /* Split all statements with multiple uses iteratively since splitting
-      may create new multiple uses.  */
-   while (repeat)
-     {
-       repeat = false;
-       niter++;
-       FOR_EACH_VEC_ELT (pattern_roots, ix, stmt)
-       {
-         rhs = gimple_assign_rhs1 (stmt);
-         ifcvt_walk_pattern_tree (rhs, &defuse_list, stmt);
-         while (defuse_list.length () > 0)
-           {
-             repeat = true;
-             gimple *def_stmt, *use_stmt;
-             use_stmt = defuse_list.pop ();
-             def_stmt = defuse_list.pop ();
-             ifcvt_split_def_stmt (def_stmt, use_stmt);
-           }
- 
-       }
-     }
-   if (dump_file && (dump_flags & TDF_DETAILS))
-     fprintf (dump_file, "Repair bool pattern takes %d iterations. \n",
-            niter);
- }
- 
  /* Delete redundant statements produced by predication which prevents
     loop vectorization.  */
  
--- 2516,2521 ----
*************** tree_if_conversion (struct loop *loop)
*** 2850,2859 ****
       on-the-fly.  */
    combine_blocks (loop);
  
!   /* Delete dead predicate computations and repair tree correspondent
!      to bool pattern to delete multiple uses of predicates.  */
    ifcvt_local_dce (loop->header);
-   ifcvt_repair_bool_pattern (loop->header);
  
    todo |= TODO_cleanup_cfg;
    mark_virtual_operands_for_renaming (cfun);
--- 2662,2669 ----
       on-the-fly.  */
    combine_blocks (loop);
  
!   /* Delete dead predicate computations.  */
    ifcvt_local_dce (loop->header);
  
    todo |= TODO_cleanup_cfg;
    mark_virtual_operands_for_renaming (cfun);
Index: gcc/testsuite/gcc.dg/torture/vect-bool-1.c
===================================================================
*** /dev/null   1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/torture/vect-bool-1.c  2016-05-30 09:52:10.102304313 
+0200
***************
*** 0 ****
--- 1,14 ----
+ /* { dg-do compile } */
+ 
+ int a[64];
+ long b[64];
+ 
+ void foo (void)
+ {
+   for (int i = 0; i < 64; ++i)
+     {
+       _Bool x = a[i] < 10;
+       a[i] = x;
+       b[i] = x;
+     }
+ }

Reply via email to