This adjusts the PR70251 fix as discussed in the PR audit trail and fixes a bug in genmatch required (bah, stupid GENERIC comparisons in GIMPLE operands...).
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied. Richard. 2016-03-22 Richard Biener <rguent...@suse.de> PR middle-end/70251 * genmatch.c (gen_transform): Adjust last parameter to a three-state int... (capture::gen_transform): ... to change behavior when substituting a condition into cond or not-cond expr context. (dt_simplify::gen_1): Adjust. * gimple-match-head.c: Include gimplify.h for unshare_expr. * match.pd (A + (B vcmp C ? 1 : 0) -> A - (B vcmp C)): Revert last change and instead change to A + (B vcmp C ? 1 : 0) -> A - (B vcmp C ? -1 : 0). (A - (B vcmp C ? 1 : 0) -> A + (B vcmp C)): Likewise. * g++.dg/torture/pr70251.C: New testcase. Index: gcc/genmatch.c =================================================================== *** gcc/genmatch.c (revision 234394) --- gcc/genmatch.c (working copy) *************** struct operand { *** 548,554 **** virtual void gen_transform (FILE *, int, const char *, bool, int, const char *, capture_info *, dt_operand ** = 0, ! bool = true) { gcc_unreachable (); } }; --- 548,554 ---- virtual void gen_transform (FILE *, int, const char *, bool, int, const char *, capture_info *, dt_operand ** = 0, ! int = 0) { gcc_unreachable (); } }; *************** struct expr : public operand *** 590,596 **** bool force_single_use; virtual void gen_transform (FILE *f, int, const char *, bool, int, const char *, capture_info *, ! dt_operand ** = 0, bool = true); }; /* An operator that is represented by native C code. This is always --- 590,596 ---- bool force_single_use; virtual void gen_transform (FILE *f, int, const char *, bool, int, const char *, capture_info *, ! dt_operand ** = 0, int = 0); }; /* An operator that is represented by native C code. This is always *************** struct c_expr : public operand *** 622,628 **** vec<id_tab> ids; virtual void gen_transform (FILE *f, int, const char *, bool, int, const char *, capture_info *, ! dt_operand ** = 0, bool = true); }; /* A wrapper around another operand that captures its value. */ --- 622,628 ---- vec<id_tab> ids; virtual void gen_transform (FILE *f, int, const char *, bool, int, const char *, capture_info *, ! dt_operand ** = 0, int = 0); }; /* A wrapper around another operand that captures its value. */ *************** struct capture : public operand *** 637,643 **** operand *what; virtual void gen_transform (FILE *f, int, const char *, bool, int, const char *, capture_info *, ! dt_operand ** = 0, bool = true); }; /* if expression. */ --- 637,643 ---- operand *what; virtual void gen_transform (FILE *f, int, const char *, bool, int, const char *, capture_info *, ! dt_operand ** = 0, int = 0); }; /* if expression. */ *************** get_operand_type (id_base *op, const cha *** 2149,2155 **** void expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, int depth, const char *in_type, capture_info *cinfo, ! dt_operand **indexes, bool) { id_base *opr = operation; /* When we delay operator substituting during lowering of fors we --- 2149,2155 ---- void expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, int depth, const char *in_type, capture_info *cinfo, ! dt_operand **indexes, int) { id_base *opr = operation; /* When we delay operator substituting during lowering of fors we *************** expr::gen_transform (FILE *f, int indent *** 2213,2221 **** i == 0 ? NULL : op0type); ops[i]->gen_transform (f, indent, dest, gimple, depth + 1, optype, cinfo, indexes, ! ((!(*opr == COND_EXPR) ! && !(*opr == VEC_COND_EXPR)) ! || i != 0)); } const char *opr_name; --- 2213,2220 ---- i == 0 ? NULL : op0type); ops[i]->gen_transform (f, indent, dest, gimple, depth + 1, optype, cinfo, indexes, ! (*opr == COND_EXPR ! || *opr == VEC_COND_EXPR) && i == 0 ? 1 : 2); } const char *opr_name; *************** expr::gen_transform (FILE *f, int indent *** 2306,2312 **** void c_expr::gen_transform (FILE *f, int indent, const char *dest, bool, int, const char *, capture_info *, ! dt_operand **, bool) { if (dest && nr_stmts == 1) fprintf_indent (f, indent, "%s = ", dest); --- 2305,2311 ---- void c_expr::gen_transform (FILE *f, int indent, const char *dest, bool, int, const char *, capture_info *, ! dt_operand **, int) { if (dest && nr_stmts == 1) fprintf_indent (f, indent, "%s = ", dest); *************** c_expr::gen_transform (FILE *f, int inde *** 2378,2384 **** void capture::gen_transform (FILE *f, int indent, const char *dest, bool gimple, int depth, const char *in_type, capture_info *cinfo, ! dt_operand **indexes, bool expand_compares) { if (what && is_a<expr *> (what)) { --- 2377,2383 ---- void capture::gen_transform (FILE *f, int indent, const char *dest, bool gimple, int depth, const char *in_type, capture_info *cinfo, ! dt_operand **indexes, int cond_handling) { if (what && is_a<expr *> (what)) { *************** capture::gen_transform (FILE *f, int ind *** 2394,2413 **** fprintf_indent (f, indent, "%s = captures[%u];\n", dest, where); /* ??? Stupid tcc_comparison GENERIC trees in COND_EXPRs. Deal ! with substituting a capture of that. ! ??? Returning false here will also not allow any other patterns ! to match. */ ! if (gimple && expand_compares && cinfo->info[where].cond_expr_cond_p) { ! fprintf_indent (f, indent, "if (COMPARISON_CLASS_P (%s))\n", dest); ! fprintf_indent (f, indent, " {\n"); ! fprintf_indent (f, indent, " if (!seq) return false;\n"); ! fprintf_indent (f, indent, " %s = gimple_build (seq, TREE_CODE (%s)," ! " TREE_TYPE (%s), TREE_OPERAND (%s, 0)," ! " TREE_OPERAND (%s, 1));\n", ! dest, dest, dest, dest, dest); ! fprintf_indent (f, indent, " }\n"); } } --- 2393,2421 ---- fprintf_indent (f, indent, "%s = captures[%u];\n", dest, where); /* ??? Stupid tcc_comparison GENERIC trees in COND_EXPRs. Deal ! with substituting a capture of that. */ ! if (gimple ! && cond_handling != 0 && cinfo->info[where].cond_expr_cond_p) { ! /* If substituting into a cond_expr condition, unshare. */ ! if (cond_handling == 1) ! fprintf_indent (f, indent, "%s = unshare_expr (%s);\n", dest, dest); ! /* If substituting elsewhere we might need to decompose it. */ ! else if (cond_handling == 2) ! { ! /* ??? Returning false here will also not allow any other patterns ! to match unless this generator was split out. */ ! fprintf_indent (f, indent, "if (COMPARISON_CLASS_P (%s))\n", dest); ! fprintf_indent (f, indent, " {\n"); ! fprintf_indent (f, indent, " if (!seq) return false;\n"); ! fprintf_indent (f, indent, " %s = gimple_build (seq," ! " TREE_CODE (%s)," ! " TREE_TYPE (%s), TREE_OPERAND (%s, 0)," ! " TREE_OPERAND (%s, 1));\n", ! dest, dest, dest, dest, dest); ! fprintf_indent (f, indent, " }\n"); ! } } } *************** dt_simplify::gen_1 (FILE *f, int indent, *** 3043,3060 **** "type", e->expr_type, j == 0 ? NULL : "TREE_TYPE (res_ops[0])"); /* We need to expand GENERIC conditions we captured from ! COND_EXPRs. */ ! bool expand_generic_cond_exprs_p ! = (!is_predicate ! /* But avoid doing that if the GENERIC condition is ! valid - which it is in the first operand of COND_EXPRs ! and VEC_COND_EXRPs. */ ! && ((!(*opr == COND_EXPR) ! && !(*opr == VEC_COND_EXPR)) ! || j != 0)); e->ops[j]->gen_transform (f, indent, dest, true, 1, optype, ! &cinfo, ! indexes, expand_generic_cond_exprs_p); } /* Re-fold the toplevel result. It's basically an embedded --- 3051,3064 ---- "type", e->expr_type, j == 0 ? NULL : "TREE_TYPE (res_ops[0])"); /* We need to expand GENERIC conditions we captured from ! COND_EXPRs and we need to unshare them when substituting ! into COND_EXPRs. */ ! int cond_handling = 0; ! if (!is_predicate) ! cond_handling = ((*opr == COND_EXPR ! || *opr == VEC_COND_EXPR) && j == 0) ? 1 : 2; e->ops[j]->gen_transform (f, indent, dest, true, 1, optype, ! &cinfo, indexes, cond_handling); } /* Re-fold the toplevel result. It's basically an embedded *************** dt_simplify::gen_1 (FILE *f, int indent, *** 3068,3074 **** || result->type == operand::OP_C_EXPR) { result->gen_transform (f, indent, "res_ops[0]", true, 1, "type", ! &cinfo, indexes, false); fprintf_indent (f, indent, "*res_code = TREE_CODE (res_ops[0]);\n"); if (is_a <capture *> (result) && cinfo.info[as_a <capture *> (result)->where].cond_expr_cond_p) --- 3072,3078 ---- || result->type == operand::OP_C_EXPR) { result->gen_transform (f, indent, "res_ops[0]", true, 1, "type", ! &cinfo, indexes); fprintf_indent (f, indent, "*res_code = TREE_CODE (res_ops[0]);\n"); if (is_a <capture *> (result) && cinfo.info[as_a <capture *> (result)->where].cond_expr_cond_p) Index: gcc/gimple-match-head.c =================================================================== *** gcc/gimple-match-head.c (revision 234394) --- gcc/gimple-match-head.c (working copy) *************** along with GCC; see the file COPYING3. *** 38,43 **** --- 38,44 ---- #include "tree-pass.h" #include "internal-fn.h" #include "case-cfn-macros.h" + #include "gimplify.h" /* Forward declarations of the private auto-generated matchers. Index: gcc/match.pd =================================================================== *** gcc/match.pd (revision 234394) --- gcc/match.pd (working copy) *************** DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) *** 1752,1779 **** (cnd (logical_inverted_value truth_valued_p@0) @1 @2) (cnd @0 @2 @1))) ! /* A + (B vcmp C ? 1 : 0) -> A - (B vcmp C), since vector comparisons ! return all-1 or all-0 results. */ /* ??? We could instead convert all instances of the vec_cond to negate, but that isn't necessarily a win on its own. */ (simplify ! (plus:c @3 (view_convert? (vec_cond @0 integer_each_onep@1 integer_zerop@2))) (if (VECTOR_TYPE_P (type) - && VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (@0))) && TYPE_VECTOR_SUBPARTS (type) == TYPE_VECTOR_SUBPARTS (TREE_TYPE (@0)) && (TYPE_MODE (TREE_TYPE (type)) == TYPE_MODE (TREE_TYPE (TREE_TYPE (@0))))) ! (minus @3 (view_convert @0)))) ! /* ... likewise A - (B vcmp C ? 1 : 0) -> A + (B vcmp C). */ (simplify ! (minus @3 (view_convert? (vec_cond @0 integer_each_onep@1 integer_zerop@2))) (if (VECTOR_TYPE_P (type) - && VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (@0))) && TYPE_VECTOR_SUBPARTS (type) == TYPE_VECTOR_SUBPARTS (TREE_TYPE (@0)) && (TYPE_MODE (TREE_TYPE (type)) == TYPE_MODE (TREE_TYPE (TREE_TYPE (@0))))) ! (plus @3 (view_convert @0)))) /* Simplifications of comparisons. */ --- 1752,1777 ---- (cnd (logical_inverted_value truth_valued_p@0) @1 @2) (cnd @0 @2 @1))) ! /* A + (B vcmp C ? 1 : 0) -> A - (B vcmp C ? -1 : 0), since vector comparisons ! return all -1 or all 0 results. */ /* ??? We could instead convert all instances of the vec_cond to negate, but that isn't necessarily a win on its own. */ (simplify ! (plus:c @3 (view_convert? (vec_cond:s @0 integer_each_onep@1 integer_zerop@2))) (if (VECTOR_TYPE_P (type) && TYPE_VECTOR_SUBPARTS (type) == TYPE_VECTOR_SUBPARTS (TREE_TYPE (@0)) && (TYPE_MODE (TREE_TYPE (type)) == TYPE_MODE (TREE_TYPE (TREE_TYPE (@0))))) ! (minus @3 (view_convert (vec_cond @0 (negate @1) @2))))) ! /* ... likewise A - (B vcmp C ? 1 : 0) -> A + (B vcmp C ? -1 : 0). */ (simplify ! (minus @3 (view_convert? (vec_cond:s @0 integer_each_onep@1 integer_zerop@2))) (if (VECTOR_TYPE_P (type) && TYPE_VECTOR_SUBPARTS (type) == TYPE_VECTOR_SUBPARTS (TREE_TYPE (@0)) && (TYPE_MODE (TREE_TYPE (type)) == TYPE_MODE (TREE_TYPE (TREE_TYPE (@0))))) ! (plus @3 (view_convert (vec_cond @0 (negate @1) @2))))) /* Simplifications of comparisons. */ Index: gcc/testsuite/g++.dg/torture/pr70251.C =================================================================== *** gcc/testsuite/g++.dg/torture/pr70251.C (revision 0) --- gcc/testsuite/g++.dg/torture/pr70251.C (working copy) *************** *** 0 **** --- 1,11 ---- + // { dg-do compile } + // { dg-additional-options "-w -Wno-psabi" } + + typedef int vec __attribute__((vector_size(64))); + vec f(vec x,vec y,vec z) + { + vec zero={}; + vec one=zero+1; + vec c=x<y; + return z+(c?one:zero); + }