Hi, Currently compiler may ICE when loaded boolean is compared with vector invariant or another boolean value. This is because we don't detect mix of bool and non-bool vectypes and incorrectly determine vectype for boolean loop invariant for comparison. This was fixed for COND_EXP before but also needs to be fixed for comparison. This patch was bootstrapped and tested on x86_64-unknown-linux-gnu. OK for trunk?
Thanks, Ilya -- gcc/ 2015-11-12 Ilya Enkovich <enkovich....@gmail.com> * tree-vect-loop.c (vect_determine_vectorization_factor): Check mix of boolean and integer vectors in a single statement. * tree-vect-slp.c (vect_mask_constant_operand_p): New. (vect_get_constant_vectors): Use vect_mask_constant_operand_p to determine constant type. * tree-vect-stmts.c (vectorizable_comparison): Provide vectype for loop invariants. gcc/testsuite/ 2015-11-12 Ilya Enkovich <enkovich....@gmail.com> * g++.dg/vect/simd-bool-comparison-1.cc: New test. * g++.dg/vect/simd-bool-comparison-2.cc: New test. diff --git a/gcc/testsuite/g++.dg/vect/simd-bool-comparison-1.cc b/gcc/testsuite/g++.dg/vect/simd-bool-comparison-1.cc new file mode 100644 index 0000000..a08362f --- /dev/null +++ b/gcc/testsuite/g++.dg/vect/simd-bool-comparison-1.cc @@ -0,0 +1,21 @@ +// { dg-do compile } +// { dg-additional-options "-mavx512bw -mavx512dq" { target { i?86-*-* x86_64-*-* } } } + +#define N 1024 + +double a[N]; +bool b[N]; +bool c; + +void test () +{ + int i; + + for (i = 0; i < N; i++) + if (b[i] != c) + a[i] = 0.0; + else + a[i] = 1.0; +} + +// { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { i?86-*-* x86_64-*-* } } } } diff --git a/gcc/testsuite/g++.dg/vect/simd-bool-comparison-2.cc b/gcc/testsuite/g++.dg/vect/simd-bool-comparison-2.cc new file mode 100644 index 0000000..4accf56 --- /dev/null +++ b/gcc/testsuite/g++.dg/vect/simd-bool-comparison-2.cc @@ -0,0 +1,20 @@ +// { dg-do compile } +// { dg-additional-options "-mavx512bw -mavx512dq" { target { i?86-*-* x86_64-*-* } } } + +#define N 1024 + +double a[N]; +bool b[N]; +char c[N]; + +void test () +{ + int i; + + #pragma omp simd + for (i = 0; i < N; i++) + if ((c[i] > 0) && b[i]) + a[i] = 0.0; + else + a[i] = 1.0; +} diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 55e5309..6b78b55 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -649,7 +649,32 @@ vect_determine_vectorization_factor (loop_vec_info loop_vinfo) } return false; } + else if (VECTOR_BOOLEAN_TYPE_P (mask_type) + != VECTOR_BOOLEAN_TYPE_P (vectype)) + { + if (dump_enabled_p ()) + { + dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, + "not vectorized: mixed mask and " + "nonmask vector types in statement, "); + dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, + mask_type); + dump_printf (MSG_MISSED_OPTIMIZATION, " and "); + dump_generic_expr (MSG_MISSED_OPTIMIZATION, TDF_SLIM, + vectype); + dump_printf (MSG_MISSED_OPTIMIZATION, "\n"); + } + return false; + } } + + /* We may compare boolean value loaded as vector of integers. + Fix mask_type in such case. */ + if (mask_type + && !VECTOR_BOOLEAN_TYPE_P (mask_type) + && gimple_code (stmt) == GIMPLE_ASSIGN + && TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) == tcc_comparison) + mask_type = build_same_sized_truth_vector_type (mask_type); } /* No mask_type should mean loop invariant predicate. diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c index 9d97140..f3acb04 100644 --- a/gcc/tree-vect-slp.c +++ b/gcc/tree-vect-slp.c @@ -2589,6 +2589,57 @@ vect_slp_bb (basic_block bb) } +/* Return 1 if vector type of boolean constant which is OPNUM + operand in statement STMT is a boolean vector. */ + +static bool +vect_mask_constant_operand_p (gimple *stmt, int opnum) +{ + stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt); + enum tree_code code = gimple_expr_code (stmt); + tree op, vectype; + gimple *def_stmt; + enum vect_def_type dt; + + /* For comparison and COND_EXPR type is chosen depending + on the other comparison operand. */ + if (TREE_CODE_CLASS (code) == tcc_comparison) + { + if (opnum) + op = gimple_assign_rhs1 (stmt); + else + op = gimple_assign_rhs2 (stmt); + + if (!vect_is_simple_use (op, stmt_vinfo->vinfo, &def_stmt, + &dt, &vectype)) + gcc_unreachable (); + + return !vectype || VECTOR_BOOLEAN_TYPE_P (vectype); + } + + if (code == COND_EXPR) + { + tree cond = gimple_assign_rhs1 (stmt); + + if (TREE_CODE (cond) == SSA_NAME) + return false; + + if (opnum) + op = TREE_OPERAND (cond, 1); + else + op = TREE_OPERAND (cond, 0); + + if (!vect_is_simple_use (op, stmt_vinfo->vinfo, &def_stmt, + &dt, &vectype)) + gcc_unreachable (); + + return !vectype || VECTOR_BOOLEAN_TYPE_P (vectype); + } + + return VECTOR_BOOLEAN_TYPE_P (STMT_VINFO_VECTYPE (stmt_vinfo)); +} + + /* For constant and loop invariant defs of SLP_NODE this function returns (vector) defs (VEC_OPRNDS) that will be used in the vectorized stmts. OP_NUM determines if we gather defs for operand 0 or operand 1 of the RHS of @@ -2625,8 +2676,7 @@ vect_get_constant_vectors (tree op, slp_tree slp_node, /* Check if vector type is a boolean vector. */ if (TREE_CODE (TREE_TYPE (op)) == BOOLEAN_TYPE - && (VECTOR_BOOLEAN_TYPE_P (STMT_VINFO_VECTYPE (stmt_vinfo)) - || (code == COND_EXPR && op_num < 2))) + && vect_mask_constant_operand_p (stmt, op_num)) vector_type = build_same_sized_truth_vector_type (STMT_VINFO_VECTYPE (stmt_vinfo)); else diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index cfe30e0..c990dfa 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -7642,8 +7642,8 @@ vectorizable_comparison (gimple *stmt, gimple_stmt_iterator *gsi, } else { - vec_rhs1 = vect_get_vec_def_for_operand (rhs1, stmt, NULL); - vec_rhs2 = vect_get_vec_def_for_operand (rhs2, stmt, NULL); + vec_rhs1 = vect_get_vec_def_for_operand (rhs1, stmt, vectype); + vec_rhs2 = vect_get_vec_def_for_operand (rhs2, stmt, vectype); } } else