On Tue, Aug 5, 2014 at 3:15 PM, Richard Biener <richard.guent...@gmail.com> wrote: > On Mon, Aug 4, 2014 at 4:44 PM, Prathamesh Kulkarni > <bilbotheelffri...@gmail.com> wrote: >> On Mon, Aug 4, 2014 at 2:59 PM, Richard Biener >> <richard.guent...@gmail.com> wrote: >>> On Mon, Aug 4, 2014 at 12:16 AM, Prathamesh Kulkarni >>> <bilbotheelffri...@gmail.com> wrote: >>>> On Thu, Jul 31, 2014 at 2:49 PM, Prathamesh Kulkarni >>>> <bilbotheelffri...@gmail.com> wrote: >>>>> On Thu, Jul 31, 2014 at 2:44 PM, Richard Biener >>>>> <richard.guent...@gmail.com> wrote: >>>>>> On Thu, Jul 31, 2014 at 11:09 AM, Prathamesh Kulkarni >>>>>> <bilbotheelffri...@gmail.com> wrote: >>>>>>> On Thu, Jul 31, 2014 at 2:15 PM, Richard Biener >>>>>>> <richard.guent...@gmail.com> wrote: >>>>>>>> On Thu, Jul 31, 2014 at 7:41 AM, Prathamesh Kulkarni >>>>>>>> <bilbotheelffri...@gmail.com> wrote: >>>>>>>>> On Wed, Jul 30, 2014 at 11:49 PM, Prathamesh Kulkarni >>>>>>>>> <bilbotheelffri...@gmail.com> wrote: >>>>>>>>>> On Wed, Jul 30, 2014 at 4:49 PM, Richard Biener >>>>>>>>>> <richard.guent...@gmail.com> wrote: >>>>>>>>>>> On Wed, Jul 30, 2014 at 1:11 PM, Richard Biener >>>>>>>>>>> <richard.guent...@gmail.com> wrote: >>>>>>>>>>>> On Wed, Jul 30, 2014 at 12:49 PM, Prathamesh Kulkarni >>>>>>>>>>>> <bilbotheelffri...@gmail.com> wrote: >>>>>>>>>>>>> Hi, >>>>>>>>>>>>> Sorry to ask a stupid question, but I am having issues writing >>>>>>>>>>>>> patterns >>>>>>>>>>>>> involving casts. I am trying to write patterns from >>>>>>>>>>>>> simplify_rotate. >>>>>>>>>>>>> >>>>>>>>>>>>> Could you show me how to write a patterns that involve >>>>>>>>>>>>> casts ? >>>>>>>>>>>>> for eg: >>>>>>>>>>>>> ((T) ((T2) X << CNT1)) + ((T) ((T2) X >> CNT2)) iff CNT1 + >>>>>>>>>>>>> CNT2 == B >>>>>>>>>>>>> T -> some unsigned type with bitsize B, and some type T2 wider >>>>>>>>>>>>> than T. >>>>>>>>>>>>> How to express this in the pattern ? >>>>>>>>>>>> >>>>>>>>>>>> [copying gcc@ because of the syntax stuff] >>>>>>>>>>>> >>>>>>>>>>>> for example with (leaving captures as the appear in the pattern >>>>>>>>>>>> above) >>>>>>>>>>>> >>>>>>>>>>>> (match_and_simplify >>>>>>>>>>>> (plus (convert@2 (lshift (convert@0 X) CNT1)) >>>>>>>>>>>> (convert (rshift (convert@1 X) CNT2))) >>>>>>>>>>>> /* Types T2 have to match */ >>>>>>>>>>>> (if (types_compatible_p (TREE_TYPE (@0), TREE_TYPE (@1)) >>>>>>>>>>>> /* Type T should be unsigned. */ >>>>>>>>>>>> && TYPE_UNSIGNED (TREE_TYPE (@2)) >>>>>>>>>>>> /* T2 should be wider than T. */ >>>>>>>>>>>> && TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION >>>>>>>>>>>> (TREE_TYPE (@2)) >>>>>>>>>>>> /* CNT1 + CNT2 == B */ >>>>>>>>>>>> && wi::eq_p (TYPE_PRECISION (TREE_TYPE (@2)), >>>>>>>>>>>> wi::add (CNT1, CNT2)))) >>>>>>>>>>>> (lrotate CNT1)) >>>>>>>>>>> >>>>>>>>>>> Note that this will _explicitely_ require a conversion. That is, >>>>>>>>>>> if T == T2 >>>>>>>>>>> it won't match because the conversion to T will not be there, nor >>>>>>>>>>> if X >>>>>>>>>>> is already of type T2. >>>>>>>>>>> >>>>>>>>>>> Which means that we want to match multiple variants of this >>>>>>>>>>> (with conversions in place or not). Hmm. Maybe with extending >>>>>>>>>>> 'for' like >>>>>>>>>>> >>>>>>>>>>> (for cvt1 in convert * >>>>>>>>>>> (fot cvt2 in convert * >>>>>>>>>>> (plus@2 (cvt1 (lshift@0 (cvt2 X) CNT1)) >>>>>>>>>>> (cvt1 (rshift@1 (cvt2 X) CNT2))) >>>>>>>>>>> ... >>>>>>>>>>> >>>>>>>>>>> adding an "empty" operator to the list of operators to substitute >>>>>>>>>>> for cvt1 >>>>>>>>>>> and allowing nested for. The "empty" operator would necessarily be >>>>>>>>>>> unary and be just un-wrapped. >>>>>>>>>> Would it be better to have syntax (say using ?) for denoting that an >>>>>>>>>> operator is optional ? >>>>>>>>>> operator should be unary, and it's operand must be an expression. >>>>>>>>>> >>>>>>>>>> so the pattern becomes sth like: >>>>>>>>>> (plus@2 (convert? (lshift@0 (convert? X) CNT1)) >>>>>>>>>> (convert? (rshift@1 (convert? X) CNT2))) >>>>>>>>>> >>>>>>>>> Let me rephrase it. >>>>>>>>> An operator can be marked optional, if >>>>>>>>> a) it's unary >>>>>>>>> b) if in outermost-expr, the operand must be an expression >>>>>>>>> >>>>>>>>> I want to reject case like: >>>>>>>>> (negate? @0) >>>>>>>>> >>>>>>>>> (op? operand) >>>>>>>>> generates code : >>>>>>>>> match (op) >>>>>>>>> match (operand) >>>>>>>>> >>>>>>>>> and once without op >>>>>>>>> match (operand) >>>>>>>>> >>>>>>>>> Implementation-wise I think, we could duplicate the AST, like we do >>>>>>>>> for "for pattern". >>>>>>>>> Would that be okay ? >>>>>>>> >>>>>>>> I thought of something similar but how exactly would you do the >>>>>>>> duplication in the above example? The point is that we know >>>>>>>> that the conversions will exist in pairs, that is, either >>>>>>>> the two outer and no inner or no outer and both inner or >>>>>>>> both outer and both inner. You can express that with the >>>>>>>> nested for - with just a '?' you can't do that. Of course you could >>>>>>>> do sth like >>>>>>>> >>>>>>>> (plus@2 (convert?1 (lshift@0 (convert?2 X) CNT1)) >>>>>>>> (convert?1 (rshift@1 (convert?2 X) CNT2))) >>>>>>>> >>>>>>>> that is, add an index to ?s and tie them together. We want to >>>>>>>> avoid generating useless patterns - in this case 4 are sufficient >>>>>>>> but if we generate all possible combinations we'd have an additional >>>>>>>> 12 useless patterns. >>>>>>> Ah yes, didn't realize that, thanks. >>>>>>>> >>>>>>>> But using '?' indeed looks better than (ab)using 'for'. Note that >>>>>>>> it is _only_ 'convert' that I can see this useful for (or can you >>>>>>>> think of other cases?). So maybe we instead want to make >>>>>>>> it a special operator like >>>>>>>> >>>>>>>> (plus@2 (opt_convert 1 (lshift@0 (opt_convert 2 X) CNT1)) >>>>>>>> (opt_convert 1 (rshift@1 (opt_convert 2 X) CONT2))) >>>>>>>> >>>>>>>> with an additional operand specifying the group (or simply >>>>>>>> have opt_convert1 and opt_convert2 operands - hoping for >>>>>>>> more "groups" to never happen ;)). >>>>>>>> >>>>>>>> Actually I like opt_convert[123] most. >>>>>>> I like opt_convert[123] too. >>>>>>> Implementation-wise I don't think it would be more difficult to >>>>>>> generalize it for other operators ... >>>>>> >>>>>> Of course, but I don't see the need for that. Conversions are really >>>>>> special in this regard. >>>>>> >>>>>>> I was thinking about this ... Instead of grouping by indexes, >>>>>>> how about defining operator aliases ? >>>>>>> sth like: >>>>>>> (define_op cvt1 convert) >>>>>>> (define_op cvt2 convert) >>>>>>> >>>>>>> and then the pattern becomes: >>>>>>> >>>>>>> (plus@2 (cvt1? (lshift@0 (cvt2? X) CNT1)) >>>>>>> (cvt1? (rshift@1 (cvt2? X) CNT2))) >>>>>>> >>>>>>> that would avoid generating useless patterns (since cvt1, cvt2 are >>>>>>> "different"), however during code-gen >>>>>>> both shall map to CONVERT_EXPR (and once without it since its optional). >>>>>> >>>>>> Yeah, that would work if we'd implement it that way. Still I don't like >>>>>> a general '?' facility unless we come up with really good uses apart from >>>>>> conversions. >>>>> Agreed. I will start with implementing opt_convert. >>>> I have attached patch, that implements opt_convert. >>>> The implementation is not very efficient (i hope we can combine >>>> replace_opt_convert and lower_opt_convert). >>>> >>>> Some issues with implementation: >>>> a) since OPT_CONVERT is not defined in tree.def, i added it after >>>> #include tree.def in enum tree_code. >>>> So our enum tree_code becomes different from the usual enum tree_code. >>>> >>>> b) checks if there's any opt_convert remaining before lowering it to >>>> CONVERT >>>> and once removing it (this leads to walking AST thrice per each group). >>>> We can probably combine lower_opt_convert, remove_opt_convert and >>>> has_opt_convert into one function. >>>> >>>> c) opt_convert cannot be captured, for instance doesn't make sense >>>> when it's operand is not an expression >>>> eg - (opt_convert 1 @0) >>>> Or maybe allow capturing if the operand is expression ? >>> >>> Hmm. Capturing the convert may be necessary though as we usually >>> have to constrain allowed conversions. Like >>> >>> (convert?@0 @1) >>> if (TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (TREE_TYPE (@1)) >>> >>> to allow an optional widening convertsion. But yes, we can't >>> possibly evaluate that if-expression if the convert is not there. >>> >>> Bummer. >>> >>> That rules out this way of doing a conditional conversion. >>> >>> OTOH we can simply make the capturing of the conversion >>> capture its operand if it is not there? >> I am not sure if I understood this. >> eg: (foo (convert?@0 @1)) where foo's any operator. >> gets lowered to: >> a) (foo (convert@0 @1)) >> b) (foo @1) > > b) (foo @0@1) > > that is, both captures capture the same > >> in case a), @0 captures (convert @1). >> in case b), when there's no convert, what should @0 capture ? >> It cannot capture foo, (foo@0 @1) since foo's in outermost-expr, >> so should @0 be same as @1 for this case ? > > Yes. > >>> >>>> d) Use of opt_convert inside for operator-list is rejected. >>>> eg - (for op in convert opt_convert bit_not) >>>> >>>> * Changing syntax: >>>> I was wondering if instead of having new operator like opt_convert, we >>>> could reuse convert ? >>>> convert becomes optional if it's followed with '?' >>>> eg: >>>> (convert? 1 @0) is "optional convert". >>>> or maybe use colon ? >>>> (convert:1 @0) ? >>>> (IMHO '?' is slightly better since it's typically used to denote >>>> "optional" in regexp, but >>>> '? number' looks somewhat out of place in the pattern, ': number' looks >>>> better). >>> >>> Hmm, then if we resort to predicate/flag syntax why not do >>> convert:?1 or convert:? convert:?? convert:??? with the number >>> of ?s also providing the match-number. Of course that makes >>> it look like a generic flag when we should only accept it on converts. >>> >>> Or do convert1? I don't like the binary form or the number following >>> the ? (looks too much like a capture). Note that convert1? lexes >>> as one identifier followed by a ? though. >>> >>>> the above pattern becomes: >>>> (plus@2 (convert? 1 (lshift@0 (convert? 2 X) CNT1)) >>>> (convert? 1 (rshift@1 (convert? 2 X) CNT2))) >>>> >>>> "optional" converts won't be allowed to get captured (non-optional convert >>>> yes). >>> >>> See above - we should capture its operand if it is not there. >>> >>> So I think let's go with convert1? and allow capturing. Doing that >>> with appending CONVERT1, CONVERT2, ... to tree.def works for me. >> Thanks, I would do that. >> I was wondering whether it would be okay to change tree.def for this >> purpose though ? >> since convert1, convert2 would be having no other use. > > No, not changing tree.def but its use as you did in your first proposed > patch. I have got it done except for capturing optional converts. for instance (negate (convert1@0 @1)) does not work. This is because of insertion in decision tree (insert::operand). Since captures were always predicate or expressions, ie, the corresponding dt-node->type was dt_node::DT_OPERAND, i could hard-code for a search on dt_node::DT_OPERAND. This changes when capture itself can be captured (dt_node::DT_TRUE/DT_MATCH), and there's no easy way right now to obtain corresponding dt-node from a given operand node.
Should we keep a mapping (hash_map/std::map) from operand * to dt_node * ? That will also get rid of dt_node::parent (but we need to then introduce parent in AST). Other cases where convert1, convert2 are not captured work fine. (bit_not (convert1 @0) (convert2 @1)) I have attached patch for reference (don't intend to get it committed). Thanks, Prathamesh > > Richard. > >> Thanks, >> Prathamesh >>> >>> Richard. >>> >>>> >>>> * genmatch.c (enum tree_code): New value OPT_CONVERT. >>>> (e_operation): New member unsigned group_index. >>>> (e_operation::e_operation): Add new default argument. >>>> Adjust to changes in >>>> e_operation. >>>> (remove_opt_convert): New function. >>>> (has_opt_convert): Likewise. >>>> (lower_opt_convert): Likewise. >>>> (lower_opt_convert): New overloaded function. >>>> (lower_opt_convert): Likewise. >>>> (parse_expr): Adjust to parse opt_convert. >>>> (parse_for): Reject opt_convert in opers. >>>> (main): Call lower_opt_convert. >>>> >>>> Thanks, >>>> Prathamesh >>>>> >>>>> Thanks, >>>>> Prathamesh. >>>>>> >>>>>> Richard. >>>>>> >>>>>>> Thanks, >>>>>>> Prathamesh >>>>>>> >>>>>>>> >>>>>>>> Richard. >>>>>>>> >>>>>>>>> Thanks, >>>>>>>>> Prathamesh >>>>>>>>> >>>>>>>>> >>>>>>>>>> Thanks, >>>>>>>>>> Prathamesh >>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> Extending for in this way avoids treating conversions specially >>>>>>>>>>> (I don't see an easy way to do very good at that automagically). We >>>>>>>>>>> need multiple patterns in the decision tree here anyway. >>>>>>>>>>> >>>>>>>>>>> Now guess sth fancy in place of '*' ... >>>>>>>>>>> >>>>>>>>>>> Lisp style would be less free-form like >>>>>>>>>>> >>>>>>>>>>> (for cvt (convert ()) >>>>>>>>>>> >>>>>>>>>>> where we could use an empty list for the "empty" operator. >>>>>>>>>>> >>>>>>>>>>> Is nested for support already implemented? >>>>>>>>>>> >>>>>>>>>>> Thanks, >>>>>>>>>>> Richard. >>>>>>>>>>> >>>>>>>>>>>> which suggests that we may want to add some type capturing / >>>>>>>>>>>> matching >>>>>>>>>>>> so we can maybe write >>>>>>>>>>>> >>>>>>>>>>>> (plus (convert@T (lshift (convert@T2 X) CNT1)) >>>>>>>>>>>> (convert (rshift (convert@T2 X) CNT2))) >>>>>>>>>>>> (if (/* T2s will be matched automagically */ >>>>>>>>>>>> && TYPE_UNSIGNED (@T) >>>>>>>>>>>> && TYPE_PRECISION (@T2) > TYPE_PRECISION (@T) >>>>>>>>>>>> && wi::eq_p (TYPE_PRECISION (@T), wi::add (CNT1, CNT2)))) >>>>>>>>>>>> >>>>>>>>>>>> which is less to type and supports requiring matching types. Maybe >>>>>>>>>>>> require @T[0-9]+ here thus use @T0 and disallow plain @T. We could >>>>>>>>>>>> then also use @T for the implicitely "captured" outermost type we >>>>>>>>>>>> refer to as plain 'type' right now. >>>>>>>>>>>> >>>>>>>>>>>> I suggest to go ahead without a new syntax for now and see if it >>>>>>>>>>>> gets unwieldingly ugly without first. >>>>>>>>>>>> >>>>>>>>>>>>> For this week, I have planned: >>>>>>>>>>>>> a) writing patterns from simplify_rotate >>>>>>>>>>>>> b) replacing op in c_expr >>>>>>>>>>>>> c) writing more test-cases. >>>>>>>>>>>>> >>>>>>>>>>>>> If there's anything else you would like me to do, I would be happy >>>>>>>>>>>>> to know. >>>>>>>>>>>> >>>>>>>>>>>> Just keep an eye open for things like above - easy ways to reduce >>>>>>>>>>>> typing for patterns. >>>>>>>>>>>> >>>>>>>>>>>> Btw, I suggest to split up match.pd by code you converted from. >>>>>>>>>>>> Thus >>>>>>>>>>>> for simplify_rotate add >>>>>>>>>>>> >>>>>>>>>>>> match-simplify-rotate.pd >>>>>>>>>>>> >>>>>>>>>>>> with the patterns and do a #include "match-simplify-rotate.pd" >>>>>>>>>>>> in match.pd. That will make it easier to match the two later. >>>>>>>>>>>> >>>>>>>>>>>> Thanks, >>>>>>>>>>>> Richard. >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>>> Thanks, >>>>>>>>>>>>> Prathamesh
Index: genmatch.c =================================================================== --- genmatch.c (revision 213756) +++ genmatch.c (working copy) @@ -101,6 +101,8 @@ output_line_directive (FILE *f, source_l #define DEFTREECODE(SYM, STRING, TYPE, NARGS) SYM, enum tree_code { #include "tree.def" +CONVERT1, +CONVERT2, MAX_TREE_CODES }; #undef DEFTREECODE @@ -600,6 +602,134 @@ lower_commutative (simplify *s, vec<simp } } +operand * +lower_opt_convert (operand *o, const char *oper) +{ + if (capture *c = dyn_cast<capture *> (o)) + { + if (c->what) + return new capture (c->where, lower_opt_convert (c->what, oper)); + else + return c; + } + + if (!is_a<expr *> (o)) + return o; + + expr *e = as_a<expr *> (o); + if (strcmp (e->operation->op->id, oper) == 0) + { + expr *ne = new expr (new e_operation ("CONVERT_EXPR")); + ne->append_op (lower_opt_convert (e->ops[0], oper)); + return ne; + } + + expr *ne = new expr (e->operation); + for (unsigned i = 0; i < e->ops.length (); ++i) + ne->append_op (lower_opt_convert (e->ops[i], oper)); + + return ne; +} + +operand * +remove_opt_convert (operand *o, const char *oper) +{ + if (capture *c = dyn_cast<capture *> (o)) + { + if (c->what) + return new capture (c->where, remove_opt_convert (c->what, oper)); + else + return c; + } + + if (!is_a<expr *> (o)) + return o; + + expr *e = as_a<expr *> (o); + if (strcmp (e->operation->op->id, oper) == 0) + return remove_opt_convert (e->ops[0], oper); + + expr *ne = new expr (e->operation); + for (unsigned i = 0; i < e->ops.length (); ++i) + ne->append_op (remove_opt_convert (e->ops[i], oper)); + + return ne; +} + +bool +has_opt_convert (operand *o, const char *oper) +{ + if (capture *c = dyn_cast<capture *> (o)) + { + if (c->what) + return has_opt_convert (c->what, oper); + else + return false; + } + + if (!is_a<expr *> (o)) + return false; + + expr *e = as_a<expr *> (o); + + if (strcmp (e->operation->op->id, oper) == 0) + return true; + + for (unsigned i = 0; i < e->ops.length (); ++i) + if (has_opt_convert (e->ops[i], oper)) + return true; + + return false; +} + +void +lower_opt_convert (vec<operand *>& v, operand *o, const char *oper) +{ + if (has_opt_convert (o, oper)) + { + v.safe_push (lower_opt_convert (o, oper)); + v.safe_push (remove_opt_convert (o, oper)); + } +} + +vec<operand *> +lower_opt_convert (operand *o) +{ + vec<operand *> v1 = vNULL, v2; + + v1.safe_push (o); + + const char *opers[] = { "CONVERT1", "CONVERT2", 0 }; + + for (unsigned i = 0; opers[i]; ++i) + { + v2 = vNULL; + for (unsigned j = 0; j < v1.length (); ++j) + lower_opt_convert (v2, v1[j], opers[i]); + + if (v2 != vNULL) + { + v1 = vNULL; + for (unsigned j = 0; j < v2.length (); ++j) + v1.safe_push (v2[j]); + } + } + + return v1; +} + +void +lower_opt_convert (simplify *s, vec<simplify *>& simplifiers) +{ + vec<operand *> matchers = lower_opt_convert (s->match); + for (unsigned i = 0; i < matchers.length (); ++i) + { + simplify *ns = new simplify (s->name, matchers[i], s->match_location, + s->result, s->result_location, s->ifexpr_vec); + simplifiers.safe_push (ns); + } +} + void check_operator (id_base *op, unsigned n_ops, const cpp_token *token = 0) { @@ -816,6 +946,7 @@ decision_tree::cmp_node (dt_node *n1, dt if (!n1 || !n2 || n1->type != n2->type) return false; + if (n1 == n2 || n1->type == dt_node::DT_TRUE) return true; @@ -924,8 +1055,36 @@ decision_tree::insert_operand (dt_node * if (c->what) { q = insert_operand (p, c->what, indexes, pos, parent); + operand *op = 0; + dt_operand *match_op = 0; + enum dt_node::dt_type type; +#if 0 + if (capture *cc = dyn_cast<capture *> (c->what)) + { + unsigned cc_index = atoi (cc->where); + if (indexes[cc_index] == 0) + type = dt_node::DT_TRUE; + else + { + type = dt_node::DT_MATCH; + match_op = indexes[cc_index]; + fprintf (stderr, "got indexes [%u]= %p\n", cc_index, match_op); + } + } + else + { + type = dt_node::DT_OPERAND; + op = c->what; + } + + fprintf (stderr, "type = %u\n", type); +#endif + + // FIXME: This segfaults when c->what is a capture, since + // find_node returns NULL for that, and we segfault at gcc_assert (elm->typ == ...) dt_operand temp (dt_node::DT_OPERAND, c->what, 0); elm = decision_tree::find_node (p->kids, &temp); + } else q = elm = p->append_true_op (parent, pos); @@ -2125,7 +2284,11 @@ parse_for (cpp_reader *r, source_locatio token = peek (r); if (token->type != CPP_NAME) break; - opers.safe_push (get_ident (r)); + const char *id = get_ident (r); + id_base *idb = get_operator (id); + if (strcmp (idb->id, "CONVERT1") == 0 || strcmp (idb->id, "CONVERT2") == 0) + fatal_at (token, "CONVERT1, CONVERT2 cannot be used inside for"); + opers.safe_push (id); } if (token->type == CPP_CLOSE_PAREN) @@ -2254,6 +2417,8 @@ main(int argc, char **argv) add_operator (SYM, # SYM, # TYPE, NARGS); #define END_OF_BASE_TREE_CODES #include "tree.def" +add_operator (CONVERT1, "CONVERT1", "tcc_unary", 1); +add_operator (CONVERT2, "CONVERT2", "tcc_unary", 1); #undef END_OF_BASE_TREE_CODES #undef DEFTREECODE @@ -2273,9 +2438,13 @@ main(int argc, char **argv) for (unsigned i = 0; i < simplifiers.length (); ++i) check_no_user_id (simplifiers[i]); - vec<simplify *> out_simplifiers = vNULL; + vec<simplify *> out_simplifiers0 = vNULL; for (unsigned i = 0; i < simplifiers.length (); ++i) - lower_commutative (simplifiers[i], out_simplifiers); + lower_opt_convert (simplifiers[i], out_simplifiers0); + + vec<simplify *> out_simplifiers = vNULL; + for (unsigned i = 0; i < out_simplifiers0.length (); ++i) + lower_commutative (out_simplifiers0[i], out_simplifiers); if (verbose) for (unsigned i = 0; i < out_simplifiers.length (); ++i)