On Tue, 11 Nov 2014, Richard Biener wrote: > On Tue, 11 Nov 2014, Richard Biener wrote: > > > On Mon, 10 Nov 2014, Andrew Pinski wrote: > > > > > On Fri, Nov 7, 2014 at 2:23 AM, Richard Biener <rguent...@suse.de> wrote: > > > > On Thu, 6 Nov 2014, Andrew Pinski wrote: > > > > > > > >> On Thu, Nov 6, 2014 at 2:40 AM, Richard Biener <rguent...@suse.de> > > > >> wrote: > > > >> > On Thu, 6 Nov 2014, Richard Biener wrote: > > > >> > > > > >> >> On Wed, 5 Nov 2014, Andrew Pinski wrote: > > > >> >> > > > >> >> > Hi, > > > >> >> > I was trying to hook up tree-ssa-phiopt to match-and-simplify > > > >> >> > using > > > >> >> > either gimple_build (or rather using gimple_simplify depending on > > > >> >> > if > > > >> >> > we want to produce cond_expr for conditional move). I ran into a > > > >> >> > problem. > > > >> >> > With the pattern below: > > > >> >> > /* a ? 0 : 1 -> a if 0 and 1 are integral types. */ > > > >> >> > (simplify > > > >> >> > (cond_expr @0 integer_zerop integer_onep) > > > >> >> > (if (INTEGRAL_TYPE_P (type)) > > > >> >> > (convert @0))) > > > >> >> > > > >> >> Ok, so you are capturing a GENERIC expr here but nothing knows that. > > > >> >> It would work if you'd do (ugh) > > > >> >> > > > >> >> (for op (lt le eq ne ge gt) > > > >> >> (simplify > > > >> >> (cond_expr (op @0 @1) integer_zerop integer_onep) > > > >> >> (if (INTEGRAL_TYPE_P (type)) > > > >> >> (convert (op @0 @1))))) > > > >> >> (simplify > > > >> >> (cond_expr SSA_NAME@0 integer_zerop integer_onep) > > > >> >> (if (INTEGRAL_TYPE_P (type)) > > > >> >> (convert @0)))) > > > >> >> > > > >> >> as a workaround. To make your version work will require (quite) > > > >> >> some special-casing in the code generator or maybe the resimplify > > > >> >> helper. Let me see if I can cook up a "simple" fix. > > > >> > > > > >> > Sth like below (for the real fix this has to be replicated in > > > >> > all gimple_resimplifyN functions). I'm missing a testcase > > > >> > where the pattern would apply (and not be already folded by fold), > > > >> > so I didn't check if it actually works. > > > >> > > > >> You do need to check if seq is NULL though as gimple_build depends on > > > >> seq not being NULL. But otherwise yes this works for me. > > > > > > > > Ok, here is a better and more complete fix. The optimization > > > > whether a captured expression may be a GENERIC condition isn't > > > > implemented so a lot of checks are emitted right now. Also > > > > if gimple_build would fail this terminates the whole matching > > > > process, not just matching of the current pattern (failing "late" > > > > isn't supported with the style of code we emit - well, without > > > > adding ugly gotos and labels). > > > > > > > > At least it avoids splitting up conditions if substituted into > > > > a COND_EXPR, so simplifications of COND_EXPRs in-place (w/o seq) > > > > should still work. > > > > > > > > Can you check whether this works for you? > > > > > > This works for most cases but does not work for things like: > > > /* a != b ? a : b -> a */ > > > (simplify > > > (cond_expr (ne @0 @1) @0 @1) > > > @0) > > > > > > In gimple_simplify after it matches COND_EXPR. It does not look into > > > the operand 0 to see if it matches NE_EXPR, it just sees if it was a > > > SSA_NAME. In this case I was trying to do a simple replacement of > > > value_replacement in tree-ssa-phiopt.c. > > > > Yeah - I hoped you wouldn't notice. It's not too difficult to fix. > > Still this ugly ambiguity in the GIMPLE IL is bad and I wonder if > > it is better to finally fix it with > > > > Index: gcc/gimple-expr.c > > =================================================================== > > --- gcc/gimple-expr.c (revision 216973) > > +++ gcc/gimple-expr.c (working copy) > > @@ -641,10 +641,7 @@ is_gimple_lvalue (tree t) > > bool > > is_gimple_condexpr (tree t) > > { > > - return (is_gimple_val (t) || (COMPARISON_CLASS_P (t) > > - && !tree_could_throw_p (t) > > - && is_gimple_val (TREE_OPERAND (t, 0)) > > - && is_gimple_val (TREE_OPERAND (t, 1)))); > > + return is_gimple_val (t); > > } > > > > /* Return true if T is a gimple address. */ > > > > I expect mostly fallout from passes building [VEC_]COND_EXPRs and > > not gimplifying it and of course missed optimizations from the > > vectorizer which will likely now try to vectorize the separate > > comparisons in some maybe odd way (not sure). > > > > I did this experiment once but didn't finish it. Too bad :/ > > > > > But for my purpose right now this is sufficient and will be posting a > > > patch which does not remove things from tree-ssa-phiopt.c just yet. > > > > Fair enough. I suppose for GCC 5 I will need to deal with the odd > > GIMPLE IL. At least I can consider it a "bug" and thus fix this > > during stage3 ;) > > Well. Like the following which creates the expected code for > > (simplify > (cond_expr (eq @0 @1) @0 @1) > @1) > > I'll install this on the branch and work on the other patch to > clean it up a bit.
Here is a combined patch to test. Richard. Index: gcc/genmatch.c =================================================================== --- gcc/genmatch.c (revision 217279) +++ gcc/genmatch.c (working copy) @@ -411,6 +411,7 @@ typedef hash_map<const char *, unsigned, /* The AST produced by parsing of the pattern definitions. */ struct dt_operand; +struct capture_info; /* The base class for operands. */ @@ -419,7 +420,9 @@ struct operand { operand (enum op_type type_) : type (type_) {} enum op_type type; virtual void gen_transform (FILE *, const char *, bool, int, - const char *, dt_operand ** = 0) + const char *, capture_info *, + dt_operand ** = 0, + bool = true) { gcc_unreachable (); } }; @@ -438,7 +441,8 @@ struct expr : public operand { expr (id_base *operation_, bool is_commutative_ = false) : operand (OP_EXPR), operation (operation_), - ops (vNULL), expr_type (NULL), is_commutative (is_commutative_) {} + ops (vNULL), expr_type (NULL), is_commutative (is_commutative_), + is_generic (false) {} void append_op (operand *op) { ops.safe_push (op); } /* The operator and its operands. */ id_base *operation; @@ -448,8 +452,11 @@ struct expr : public operand /* Whether the operation is to be applied commutatively. This is later lowered to two separate patterns. */ bool is_commutative; + /* Whether the expression is expected to be in GENERIC form. */ + bool is_generic; virtual void gen_transform (FILE *f, const char *, bool, int, - const char *, dt_operand ** = 0); + const char *, capture_info *, + dt_operand ** = 0, bool = true); }; /* An operator that is represented by native C code. This is always @@ -479,7 +486,8 @@ struct c_expr : public operand /* The identifier replacement vector. */ vec<id_tab> ids; virtual void gen_transform (FILE *f, const char *, bool, int, - const char *, dt_operand **); + const char *, capture_info *, + dt_operand ** = 0, bool = true); }; /* A wrapper around another operand that captures its value. */ @@ -493,7 +501,8 @@ struct capture : public operand /* The captured value. */ operand *what; virtual void gen_transform (FILE *f, const char *, bool, int, - const char *, dt_operand ** = 0); + const char *, capture_info *, + dt_operand ** = 0, bool = true); }; template<> @@ -842,6 +851,106 @@ lower_opt_convert (simplify *s, vec<simp } } +/* Lower the compare operand of COND_EXPRs and VEC_COND_EXPRs to a + GENERIC and a GIMPLE variant. */ + +static vec<operand *> +lower_cond (operand *o) +{ + vec<operand *> ro = vNULL; + + if (capture *c = dyn_cast<capture *> (o)) + { + if (c->what) + { + vec<operand *> lop = vNULL; + lop = lower_cond (c->what); + + for (unsigned i = 0; i < lop.length (); ++i) + ro.safe_push (new capture (c->where, lop[i])); + return ro; + } + } + + expr *e = dyn_cast<expr *> (o); + if (!e || e->ops.length () == 0) + { + ro.safe_push (o); + return ro; + } + + vec< vec<operand *> > ops_vector = vNULL; + for (unsigned i = 0; i < e->ops.length (); ++i) + ops_vector.safe_push (lower_cond (e->ops[i])); + + auto_vec< vec<operand *> > result; + auto_vec<operand *> v (e->ops.length ()); + v.quick_grow_cleared (e->ops.length ()); + cartesian_product (ops_vector, result, v, 0); + + for (unsigned i = 0; i < result.length (); ++i) + { + expr *ne = new expr (e->operation); + for (unsigned j = 0; j < result[i].length (); ++j) + ne->append_op (result[i][j]); + ro.safe_push (ne); + /* If this is a COND with a captured expression or an + expression with two operands then also match a GENERIC + form on the compare. */ + if ((*e->operation == COND_EXPR + || *e->operation == VEC_COND_EXPR) + && ((is_a <capture *> (e->ops[0]) + && as_a <capture *> (e->ops[0])->what + && is_a <expr *> (as_a <capture *> (e->ops[0])->what) + && as_a <expr *> + (as_a <capture *> (e->ops[0])->what)->ops.length () == 2) + || (is_a <expr *> (e->ops[0]) + && as_a <expr *> (e->ops[0])->ops.length () == 2))) + { + expr *ne = new expr (e->operation); + for (unsigned j = 0; j < result[i].length (); ++j) + ne->append_op (result[i][j]); + if (capture *c = dyn_cast <capture *> (ne->ops[0])) + { + expr *ocmp = as_a <expr *> (c->what); + expr *cmp = new expr (ocmp->operation); + for (unsigned j = 0; j < ocmp->ops.length (); ++j) + cmp->append_op (ocmp->ops[j]); + cmp->is_generic = true; + ne->ops[0] = new capture (c->where, cmp); + } + else + { + expr *ocmp = as_a <expr *> (ne->ops[0]); + expr *cmp = new expr (ocmp->operation); + for (unsigned j = 0; j < ocmp->ops.length (); ++j) + cmp->append_op (ocmp->ops[j]); + cmp->is_generic = true; + ne->ops[0] = cmp; + } + ro.safe_push (ne); + } + } + + return ro; +} + +/* Lower the compare operand of COND_EXPRs and VEC_COND_EXPRs to a + GENERIC and a GIMPLE variant. */ + +static void +lower_cond (simplify *s, vec<simplify *>& simplifiers) +{ + vec<operand *> matchers = lower_cond (s->match); + for (unsigned i = 0; i < matchers.length (); ++i) + { + simplify *ns = new simplify (matchers[i], s->match_location, + s->result, s->result_location, s->ifexpr_vec, + s->for_vec, s->capture_ids); + simplifiers.safe_push (ns); + } +} + /* In AST operand O replace operator ID with operator WITH. */ operand * @@ -937,19 +1046,27 @@ lower_for (simplify *sin, vec<simplify * /* Lower the AST for everything in SIMPLIFIERS. */ static void -lower (vec<simplify *>& simplifiers) +lower (vec<simplify *>& simplifiers, bool gimple) { - auto_vec<simplify *> out_simplifiers0; + auto_vec<simplify *> out_simplifiers; for (unsigned i = 0; i < simplifiers.length (); ++i) - lower_opt_convert (simplifiers[i], out_simplifiers0); + lower_opt_convert (simplifiers[i], out_simplifiers); + + simplifiers.truncate (0); + for (unsigned i = 0; i < out_simplifiers.length (); ++i) + lower_commutative (out_simplifiers[i], simplifiers); + + out_simplifiers.truncate (0); + if (gimple) + for (unsigned i = 0; i < simplifiers.length (); ++i) + lower_cond (simplifiers[i], out_simplifiers); + else + out_simplifiers.safe_splice (simplifiers); - auto_vec<simplify *> out_simplifiers1; - for (unsigned i = 0; i < out_simplifiers0.length (); ++i) - lower_commutative (out_simplifiers0[i], out_simplifiers1); simplifiers.truncate (0); - for (unsigned i = 0; i < out_simplifiers1.length (); ++i) - lower_for (out_simplifiers1[i], simplifiers); + for (unsigned i = 0; i < out_simplifiers.length (); ++i) + lower_for (out_simplifiers[i], simplifiers); } @@ -1069,7 +1186,8 @@ cmp_operand (operand *o1, operand *o2) { expr *e1 = static_cast<expr *>(o1); expr *e2 = static_cast<expr *>(o2); - return e1->operation == e2->operation; + return (e1->operation == e2->operation + && e1->is_generic == e2->is_generic); } else return false; @@ -1306,6 +1424,196 @@ decision_tree::print (FILE *f) } +/* For GENERIC we have to take care of wrapping multiple-used + expressions with side-effects in save_expr and preserve side-effects + of expressions with omit_one_operand. Analyze captures in + match, result and with expressions and perform early-outs + on the outermost match expression operands for cases we cannot + handle. */ + +struct capture_info +{ + capture_info (simplify *s); + void walk_match (operand *o, unsigned toplevel_arg, bool, bool); + void walk_result (operand *o, bool); + void walk_c_expr (c_expr *); + + struct cinfo + { + bool expr_p; + bool cse_p; + bool force_no_side_effects_p; + bool cond_expr_cond_p; + unsigned long toplevel_msk; + int result_use_count; + }; + + auto_vec<cinfo> info; + unsigned long force_no_side_effects; +}; + +/* Analyze captures in S. */ + +capture_info::capture_info (simplify *s) +{ + expr *e; + if (!s->result + || ((e = dyn_cast <expr *> (s->result)) + && is_a <predicate_id *> (e->operation))) + { + force_no_side_effects = -1; + return; + } + + force_no_side_effects = 0; + info.safe_grow_cleared (s->capture_max + 1); + e = as_a <expr *> (s->match); + for (unsigned i = 0; i < e->ops.length (); ++i) + walk_match (e->ops[i], i, + (i != 0 + && (*e->operation == COND_EXPR + || *e->operation == VEC_COND_EXPR)) + || *e->operation == TRUTH_ANDIF_EXPR + || *e->operation == TRUTH_ORIF_EXPR, + i == 0 + && (*e->operation == COND_EXPR + || *e->operation == VEC_COND_EXPR)); + + walk_result (s->result, false); + + for (unsigned i = 0; i < s->ifexpr_vec.length (); ++i) + if (s->ifexpr_vec[i].is_with) + walk_c_expr (as_a <c_expr *>(s->ifexpr_vec[i].cexpr)); +} + +/* Analyze captures in the match expression piece O. */ + +void +capture_info::walk_match (operand *o, unsigned toplevel_arg, + bool conditional_p, bool cond_expr_cond_p) +{ + if (capture *c = dyn_cast <capture *> (o)) + { + info[c->where].toplevel_msk |= 1 << toplevel_arg; + info[c->where].force_no_side_effects_p |= conditional_p; + info[c->where].cond_expr_cond_p |= cond_expr_cond_p; + /* Mark expr (non-leaf) captures and recurse. */ + if (c->what + && is_a <expr *> (c->what)) + { + info[c->where].expr_p = true; + walk_match (c->what, toplevel_arg, conditional_p, false); + } + } + else if (expr *e = dyn_cast <expr *> (o)) + { + for (unsigned i = 0; i < e->ops.length (); ++i) + { + bool cond_p = conditional_p; + bool cond_expr_cond_p = false; + if (*e->operation == COND_EXPR + || *e->operation == VEC_COND_EXPR) + { + if (i != 0) + cond_p = true; + else + cond_expr_cond_p = true; + } + else if (*e->operation == TRUTH_ANDIF_EXPR + || *e->operation == TRUTH_ORIF_EXPR) + cond_p = true; + walk_match (e->ops[i], toplevel_arg, cond_p, cond_expr_cond_p); + } + } + else if (is_a <predicate *> (o)) + { + /* Mark non-captured leafs toplevel arg for checking. */ + force_no_side_effects |= 1 << toplevel_arg; + } + else + gcc_unreachable (); +} + +/* Analyze captures in the result expression piece O. */ + +void +capture_info::walk_result (operand *o, bool conditional_p) +{ + if (capture *c = dyn_cast <capture *> (o)) + { + info[c->where].result_use_count++; + /* If we substitute an expression capture we don't know + which captures this will end up using (well, we don't + compute that). Force the uses to be side-effect free + which means forcing the toplevels that reach the + expression side-effect free. */ + if (info[c->where].expr_p) + force_no_side_effects |= info[c->where].toplevel_msk; + /* Mark CSE capture capture uses as forced to have + no side-effects. */ + if (c->what + && is_a <expr *> (c->what)) + { + info[c->where].cse_p = true; + walk_result (c->what, true); + } + } + else if (expr *e = dyn_cast <expr *> (o)) + { + for (unsigned i = 0; i < e->ops.length (); ++i) + { + bool cond_p = conditional_p; + if (i == 0 + && (*e->operation == COND_EXPR + || *e->operation == VEC_COND_EXPR)) + cond_p = true; + else if (*e->operation == TRUTH_ANDIF_EXPR + || *e->operation == TRUTH_ORIF_EXPR) + cond_p = true; + walk_result (e->ops[i], cond_p); + } + } + else if (c_expr *e = dyn_cast <c_expr *> (o)) + walk_c_expr (e); + else + gcc_unreachable (); +} + +/* Look for captures in the C expr E. */ + +void +capture_info::walk_c_expr (c_expr *e) +{ + /* Give up for C exprs mentioning captures not inside TREE_TYPE (). */ + unsigned p_depth = 0; + for (unsigned i = 0; i < e->code.length (); ++i) + { + const cpp_token *t = &e->code[i]; + const cpp_token *n = i < e->code.length () - 1 ? &e->code[i+1] : NULL; + if (t->type == CPP_NAME + && strcmp ((const char *)CPP_HASHNODE + (t->val.node.node)->ident.str, "TREE_TYPE") == 0 + && n->type == CPP_OPEN_PAREN) + p_depth++; + else if (t->type == CPP_CLOSE_PAREN + && p_depth > 0) + p_depth--; + else if (p_depth == 0 + && t->type == CPP_ATSIGN + && (n->type == CPP_NUMBER + || n->type == CPP_NAME) + && !(n->flags & PREV_WHITE)) + { + const char *id; + if (n->type == CPP_NUMBER) + id = (const char *)n->val.str.text; + else + id = (const char *)CPP_HASHNODE (n->val.node.node)->ident.str; + info[*e->capture_ids->get(id)].force_no_side_effects_p = true; + } + } +} + /* Code generation off the decision tree and the refered AST nodes. */ @@ -1355,7 +1663,8 @@ get_operand_type (id_base *op, const cha void expr::gen_transform (FILE *f, const char *dest, bool gimple, int depth, - const char *in_type, dt_operand **indexes) + const char *in_type, capture_info *cinfo, + dt_operand **indexes, bool) { bool conversion_p = is_conversion (operation); const char *type = expr_type; @@ -1402,7 +1711,10 @@ expr::gen_transform (FILE *f, const char const char *optype = get_operand_type (operation, in_type, expr_type, i == 0 ? NULL : op0type); - ops[i]->gen_transform (f, dest, gimple, depth + 1, optype, indexes); + ops[i]->gen_transform (f, dest, gimple, depth + 1, optype, cinfo, indexes, + ((!(*operation == COND_EXPR) + && !(*operation == VEC_COND_EXPR)) + || i != 0)); } const char *opr; @@ -1452,7 +1764,8 @@ expr::gen_transform (FILE *f, const char void c_expr::gen_transform (FILE *f, const char *dest, - bool, int, const char *, dt_operand **) + bool, int, const char *, capture_info *, + dt_operand **, bool) { if (dest && nr_stmts == 1) fprintf (f, "%s = ", dest); @@ -1521,7 +1834,8 @@ c_expr::gen_transform (FILE *f, const ch void capture::gen_transform (FILE *f, const char *dest, bool gimple, int depth, - const char *in_type, dt_operand **indexes) + const char *in_type, capture_info *cinfo, + dt_operand **indexes, bool expand_compares) { if (what && is_a<expr *> (what)) { @@ -1529,11 +1843,25 @@ capture::gen_transform (FILE *f, const c { char buf[20]; sprintf (buf, "captures[%u]", where); - what->gen_transform (f, buf, gimple, depth, in_type, NULL); + what->gen_transform (f, buf, gimple, depth, in_type, cinfo, NULL); } } fprintf (f, "%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 (f, "if (COMPARISON_CLASS_P (%s))\n" + " {\n" + " if (!seq) return false;\n" + " %s = gimple_build (seq, TREE_CODE (%s)," + " TREE_TYPE (%s), TREE_OPERAND (%s, 0)," + " TREE_OPERAND (%s, 1));\n" + " }\n", dest, dest, dest, dest, dest, dest); } /* Return the name of the operand representing the decision tree node. @@ -1617,7 +1945,8 @@ dt_operand::gen_gimple_expr (FILE *f) if (id->kind == id_base::CODE) { - if (*id == REALPART_EXPR || *id == IMAGPART_EXPR + if (e->is_generic + || *id == REALPART_EXPR || *id == IMAGPART_EXPR || *id == BIT_FIELD_REF || *id == VIEW_CONVERT_EXPR) { /* ??? If this is a memory operation we can't (and should not) @@ -1921,178 +2250,6 @@ dt_operand::gen (FILE *f, bool gimple) } -/* For GENERIC we have to take care of wrapping multiple-used - expressions with side-effects in save_expr and preserve side-effects - of expressions with omit_one_operand. Analyze captures in - match, result and with expressions and perform early-outs - on the outermost match expression operands for cases we cannot - handle. */ - -struct capture_info -{ - capture_info (simplify *s); - void walk_match (operand *o, unsigned toplevel_arg, bool); - void walk_result (operand *o, bool); - void walk_c_expr (c_expr *); - - struct cinfo - { - bool expr_p; - bool cse_p; - bool force_no_side_effects_p; - unsigned long toplevel_msk; - int result_use_count; - }; - - auto_vec<cinfo> info; - unsigned long force_no_side_effects; -}; - -/* Analyze captures in S. */ - -capture_info::capture_info (simplify *s) -{ - expr *e; - if (!s->result - || ((e = dyn_cast <expr *> (s->result)) - && is_a <predicate_id *> (e->operation))) - { - force_no_side_effects = -1; - return; - } - - force_no_side_effects = 0; - info.safe_grow_cleared (s->capture_max + 1); - e = as_a <expr *> (s->match); - for (unsigned i = 0; i < e->ops.length (); ++i) - walk_match (e->ops[i], i, false); - - walk_result (s->result, false); - - for (unsigned i = 0; i < s->ifexpr_vec.length (); ++i) - if (s->ifexpr_vec[i].is_with) - walk_c_expr (as_a <c_expr *>(s->ifexpr_vec[i].cexpr)); -} - -/* Analyze captures in the match expression piece O. */ - -void -capture_info::walk_match (operand *o, unsigned toplevel_arg, bool conditional_p) -{ - if (capture *c = dyn_cast <capture *> (o)) - { - info[c->where].toplevel_msk |= 1 << toplevel_arg; - info[c->where].force_no_side_effects_p |= conditional_p; - /* Mark expr (non-leaf) captures and recurse. */ - if (c->what - && is_a <expr *> (c->what)) - { - info[c->where].expr_p = true; - walk_match (c->what, toplevel_arg, conditional_p); - } - } - else if (expr *e = dyn_cast <expr *> (o)) - { - for (unsigned i = 0; i < e->ops.length (); ++i) - { - bool cond_p = conditional_p; - if (i == 0 - && *e->operation == COND_EXPR) - cond_p = true; - else if (*e->operation == TRUTH_ANDIF_EXPR - || *e->operation == TRUTH_ORIF_EXPR) - cond_p = true; - walk_match (e->ops[i], toplevel_arg, cond_p); - } - } - else if (is_a <predicate *> (o)) - { - /* Mark non-captured leafs toplevel arg for checking. */ - force_no_side_effects |= 1 << toplevel_arg; - } - else - gcc_unreachable (); -} - -/* Analyze captures in the result expression piece O. */ - -void -capture_info::walk_result (operand *o, bool conditional_p) -{ - if (capture *c = dyn_cast <capture *> (o)) - { - info[c->where].result_use_count++; - /* If we substitute an expression capture we don't know - which captures this will end up using (well, we don't - compute that). Force the uses to be side-effect free - which means forcing the toplevels that reach the - expression side-effect free. */ - if (info[c->where].expr_p) - force_no_side_effects |= info[c->where].toplevel_msk; - /* Mark CSE capture capture uses as forced to have - no side-effects. */ - if (c->what - && is_a <expr *> (c->what)) - { - info[c->where].cse_p = true; - walk_result (c->what, true); - } - } - else if (expr *e = dyn_cast <expr *> (o)) - { - for (unsigned i = 0; i < e->ops.length (); ++i) - { - bool cond_p = conditional_p; - if (i == 0 - && *e->operation == COND_EXPR) - cond_p = true; - else if (*e->operation == TRUTH_ANDIF_EXPR - || *e->operation == TRUTH_ORIF_EXPR) - cond_p = true; - walk_result (e->ops[i], cond_p); - } - } - else if (c_expr *e = dyn_cast <c_expr *> (o)) - walk_c_expr (e); - else - gcc_unreachable (); -} - -/* Look for captures in the C expr E. */ - -void -capture_info::walk_c_expr (c_expr *e) -{ - /* Give up for C exprs mentioning captures not inside TREE_TYPE (). */ - unsigned p_depth = 0; - for (unsigned i = 0; i < e->code.length (); ++i) - { - const cpp_token *t = &e->code[i]; - const cpp_token *n = i < e->code.length () - 1 ? &e->code[i+1] : NULL; - if (t->type == CPP_NAME - && strcmp ((const char *)CPP_HASHNODE - (t->val.node.node)->ident.str, "TREE_TYPE") == 0 - && n->type == CPP_OPEN_PAREN) - p_depth++; - else if (t->type == CPP_CLOSE_PAREN - && p_depth > 0) - p_depth--; - else if (p_depth == 0 - && t->type == CPP_ATSIGN - && (n->type == CPP_NUMBER - || n->type == CPP_NAME) - && !(n->flags & PREV_WHITE)) - { - const char *id; - if (n->type == CPP_NUMBER) - id = (const char *)n->val.str.text; - else - id = (const char *)CPP_HASHNODE (n->val.node.node)->ident.str; - info[*e->capture_ids->get(id)].force_no_side_effects_p = true; - } - } -} - /* Generate code for the '(if ...)', '(with ..)' and actual transform step of a '(simplify ...)' or '(match ...)'. This handles everything @@ -2124,7 +2281,7 @@ dt_simplify::gen (FILE *f, bool gimple) { fprintf (f, "{\n"); output_line_directive (f, w.location); - w.cexpr->gen_transform (f, NULL, true, 1, "type"); + w.cexpr->gen_transform (f, NULL, true, 1, "type", NULL); n_braces++; } else @@ -2133,7 +2290,7 @@ dt_simplify::gen (FILE *f, bool gimple) fprintf (f, "if ("); if (i == s->ifexpr_vec.length () - 1 || s->ifexpr_vec[i+1].is_with) - w.cexpr->gen_transform (f, NULL, true, 1, "type"); + w.cexpr->gen_transform (f, NULL, true, 1, "type", NULL); else { unsigned j = i; @@ -2147,7 +2304,8 @@ dt_simplify::gen (FILE *f, bool gimple) } fprintf (f, "("); s->ifexpr_vec[j].cexpr->gen_transform (f, NULL, - true, 1, "type"); + true, 1, "type", + NULL); fprintf (f, ")"); ++j; } @@ -2224,7 +2382,18 @@ dt_simplify::gen (FILE *f, bool gimple) "type", e->expr_type, j == 0 ? NULL : "TREE_TYPE (res_ops[0])"); - e->ops[j]->gen_transform (f, dest, true, 1, optype, indexes); + /* 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. */ + && ((!(*e->operation == COND_EXPR) + && !(*e->operation == VEC_COND_EXPR)) + || j != 0)); + e->ops[j]->gen_transform (f, dest, true, 1, optype, &cinfo, + indexes, expand_generic_cond_exprs_p); } /* Re-fold the toplevel result. It's basically an embedded @@ -2236,8 +2405,23 @@ dt_simplify::gen (FILE *f, bool gimple) else if (result->type == operand::OP_CAPTURE || result->type == operand::OP_C_EXPR) { - result->gen_transform (f, "res_ops[0]", true, 1, "type", indexes); - fprintf (f, "*res_code = TREE_CODE (res_ops[0]);\n"); + result->gen_transform (f, "res_ops[0]", true, 1, "type", + &cinfo, indexes, false); + if (is_a <capture *> (result) + && cinfo.info[as_a <capture *> (result)->where].cond_expr_cond_p) + { + /* ??? Stupid tcc_comparison GENERIC trees in COND_EXPRs. Deal + with substituting a capture of that. */ + fprintf (f, "if (COMPARISON_CLASS_P (res_ops[0]))\n" + " {\n" + " tree tem = res_ops[0];\n" + " res_ops[0] = TREE_OPERAND (tem, 0);\n" + " res_ops[1] = TREE_OPERAND (tem, 1);\n" + " *res_code = TREE_CODE (tem);\n" + " }\n" + "else\n" + " *res_code = TREE_CODE (res_ops[0]);\n"); + } } else gcc_unreachable (); @@ -2276,7 +2460,8 @@ dt_simplify::gen (FILE *f, bool gimple) "type", e->expr_type, j == 0 ? NULL : "TREE_TYPE (res_op0)"); - e->ops[j]->gen_transform (f, dest, false, 1, optype, indexes); + e->ops[j]->gen_transform (f, dest, false, 1, optype, + &cinfo, indexes); } if (is_predicate) fprintf (f, "return true;\n"); @@ -2310,7 +2495,8 @@ dt_simplify::gen (FILE *f, bool gimple) { fprintf (f, " tree res;\n"); - s->result->gen_transform (f, " res", false, 1, "type", indexes); + s->result->gen_transform (f, " res", false, 1, "type", + &cinfo, indexes); } else gcc_unreachable (); @@ -3387,7 +3573,7 @@ add_operator (CONVERT2, "CONVERT2", "tcc for (unsigned i = 0; i < p.user_predicates.length (); ++i) { predicate_id *pred = p.user_predicates[i]; - lower (pred->matchers); + lower (pred->matchers, gimple); if (verbose) for (unsigned i = 0; i < pred->matchers.length (); ++i) @@ -3404,7 +3590,7 @@ add_operator (CONVERT2, "CONVERT2", "tcc } /* Lower the main simplifiers and generate code for them. */ - lower (p.simplifiers); + lower (p.simplifiers, gimple); if (verbose) for (unsigned i = 0; i < p.simplifiers.length (); ++i)