Hi All, For boolean mask handling we have to lower BIT_NOT_EXPR for correctness into BIT_XOR_EXPR. Normally this is done through vect_recog_bool_pattern by following the defs of the gimple_assign.
In the PR we ICE because early exits have the comparison inside the gcond itself and so vect_recog_bool_pattern does not get a chance to lower it. This patch changes it so vect_recog_gcond_pattern also does the lowering. The reason we ICE with SLP but not non-SLP is because for non-SLP the vectorization is driven from the gcond, where vectorizable_comparison_1 rejects the operation. For SLP the body is vectorized before the root. My initial attempt was to try to re-use vect_recog_bool_pattern but this didn't work for the same reasons we didn't change vect_recog_bool_pattern to handle gconds. I also tried introducing an explicit assign for the conditional and having vect_recog_bool_pattern see the conditional. However this fails because vect_recog_bool_pattern and helpers only handle COND_EXPR, converts and operands that are being loaded from memory. Since I believe BIT_NOT_EXPR is the only one needing to be lowered for correctness, I just manually do so like we do in other places. Bootstrapped Regtested on aarch64-none-linux-gnu and no issues. Ok for master? Thanks, Tamar gcc/ChangeLog: PR tree-optimization/117176 * tree-vect-patterns.cc (vect_recog_gcond_pattern): Lower BIT_NOT_EXPR. gcc/testsuite/ChangeLog: PR tree-optimization/117176 * gcc.dg/vect/vect-early-break_130-pr117176.c: New test. --- diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_130-pr117176.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_130-pr117176.c new file mode 100644 index 0000000000000000000000000000000000000000..841dcce284dd7cff0c4f0648e6dc57082c8756c1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_130-pr117176.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +struct ColorSpace { + int componentCt; +}; + +struct Psnr { + double psnr[3]; +}; + +int f(struct Psnr psnr, struct ColorSpace colorSpace) { + int i, hitsTarget = 1; + + for (i = 1; i < colorSpace.componentCt && hitsTarget; ++i) + hitsTarget = !(psnr.psnr[i] < 1); + + return hitsTarget; +} diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc index 746f100a0842090953571b535ff05375f46033c0..b7cb6cf1308590e2723ca2872cf917edb4036c57 100644 --- a/gcc/tree-vect-patterns.cc +++ b/gcc/tree-vect-patterns.cc @@ -5946,8 +5946,45 @@ vect_recog_gcond_pattern (vec_info *vinfo, if (code == NE_EXPR && zerop (rhs) + && TREE_CODE (lhs) == SSA_NAME && VECT_SCALAR_BOOLEAN_TYPE_P (scalar_type)) - return NULL; + { + stmt_vec_info def_stmt_info = vect_get_internal_def (vinfo, lhs); + if (!def_stmt_info) + return NULL; + + gimple *lhs_stmt = STMT_VINFO_STMT (def_stmt_info); + if (!is_gimple_assign (lhs_stmt)) + return NULL; + + /* This is normally handled by adjust_bool_pattern, however this is + driven from a gimple assign normally and cannot handle gcond. + BIT_NOT_EXPR are the only ones needing to be lowered for correctness, + the rest are more optimizations. */ + switch (gimple_assign_rhs_code (lhs_stmt)) + { + case BIT_NOT_EXPR: + { + tree rhs1 = gimple_assign_rhs1 (lhs_stmt); + tree itype = TREE_TYPE (rhs1); + tree ilhs = vect_recog_temp_ssa_var (boolean_type_node, NULL); + gimple *pattern_stmt + = gimple_build_assign (ilhs, BIT_XOR_EXPR, rhs1, + build_int_cst (itype, 1)); + + tree lhs_vtype = get_mask_type_for_scalar_type (vinfo, itype); + if (lhs_vtype == NULL_TREE) + return NULL; + + append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt, lhs_vtype, + itype); + lhs = ilhs; + break; + } + default: + return NULL; + } + } tree vecitype = get_vectype_for_scalar_type (vinfo, scalar_type); if (vecitype == NULL_TREE) @@ -6208,7 +6245,6 @@ vect_recog_bool_pattern (vec_info *vinfo, return NULL; } - /* A helper for vect_recog_mask_conversion_pattern. Build conversion of MASK to a type suitable for masking VECTYPE. Built statement gets required vectype and is appended to --
diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_130-pr117176.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_130-pr117176.c new file mode 100644 index 0000000000000000000000000000000000000000..841dcce284dd7cff0c4f0648e6dc57082c8756c1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_130-pr117176.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-add-options vect_early_break } */ +/* { dg-require-effective-target vect_early_break } */ +/* { dg-require-effective-target vect_int } */ + +struct ColorSpace { + int componentCt; +}; + +struct Psnr { + double psnr[3]; +}; + +int f(struct Psnr psnr, struct ColorSpace colorSpace) { + int i, hitsTarget = 1; + + for (i = 1; i < colorSpace.componentCt && hitsTarget; ++i) + hitsTarget = !(psnr.psnr[i] < 1); + + return hitsTarget; +} diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc index 746f100a0842090953571b535ff05375f46033c0..b7cb6cf1308590e2723ca2872cf917edb4036c57 100644 --- a/gcc/tree-vect-patterns.cc +++ b/gcc/tree-vect-patterns.cc @@ -5946,8 +5946,45 @@ vect_recog_gcond_pattern (vec_info *vinfo, if (code == NE_EXPR && zerop (rhs) + && TREE_CODE (lhs) == SSA_NAME && VECT_SCALAR_BOOLEAN_TYPE_P (scalar_type)) - return NULL; + { + stmt_vec_info def_stmt_info = vect_get_internal_def (vinfo, lhs); + if (!def_stmt_info) + return NULL; + + gimple *lhs_stmt = STMT_VINFO_STMT (def_stmt_info); + if (!is_gimple_assign (lhs_stmt)) + return NULL; + + /* This is normally handled by adjust_bool_pattern, however this is + driven from a gimple assign normally and cannot handle gcond. + BIT_NOT_EXPR are the only ones needing to be lowered for correctness, + the rest are more optimizations. */ + switch (gimple_assign_rhs_code (lhs_stmt)) + { + case BIT_NOT_EXPR: + { + tree rhs1 = gimple_assign_rhs1 (lhs_stmt); + tree itype = TREE_TYPE (rhs1); + tree ilhs = vect_recog_temp_ssa_var (boolean_type_node, NULL); + gimple *pattern_stmt + = gimple_build_assign (ilhs, BIT_XOR_EXPR, rhs1, + build_int_cst (itype, 1)); + + tree lhs_vtype = get_mask_type_for_scalar_type (vinfo, itype); + if (lhs_vtype == NULL_TREE) + return NULL; + + append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt, lhs_vtype, + itype); + lhs = ilhs; + break; + } + default: + return NULL; + } + } tree vecitype = get_vectype_for_scalar_type (vinfo, scalar_type); if (vecitype == NULL_TREE) @@ -6208,7 +6245,6 @@ vect_recog_bool_pattern (vec_info *vinfo, return NULL; } - /* A helper for vect_recog_mask_conversion_pattern. Build conversion of MASK to a type suitable for masking VECTYPE. Built statement gets required vectype and is appended to