On Wed, 22 Oct 2014, Richard Biener wrote: > > The following auto-handles preserving of side-effects properly > for GENERIC simplification instead of simply rejecting operands > with side-effects. Cases we cannot handle correctly are still > handled that way. > > For example for > > /* (x | CST1) & CST2 -> (x & CST2) | (CST1 & CST2) */ > (simplify > (bit_and (bit_ior @0 CONSTANT_CLASS_P@1) CONSTANT_CLASS_P@2) > (bit_ior (bit_and @0 @2) (bit_and @1 @2))) > > we generate > > captures[0] = o20; > captures[1] = o21; > captures[2] = op1; > if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Applying > pattern match-bitwise.pd:59, %s:%d\n", __FILE__, __LINE__); > if (TREE_SIDE_EFFECTS (captures[2])) > captures[2] = save_expr (captures[2]); > ... > res = fold_build2_loc (loc, BIT_IOR_EXPR, type, res_op0, res_op1); > return res; > > of course somewhat pointless for CONSTANT_CLASS_P @2 (but well...). > > For example for > > (simplify > (minus @0 @0) > (if (!FLOAT_TYPE_P (type) || !HONOR_NANS (TYPE_MODE (type))) > { build_zero_cst (type); })) > > we generate > > captures[0] = op0; > /* #line 48 "/space/rguenther/src/svn/match-and-simplify/gcc/match.pd" */ > if (!FLOAT_TYPE_P (type) || !HONOR_NANS (TYPE_MODE (type))) > { > if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, > "Applying pattern match.pd:49, %s:%d\n", __FILE__, __LINE__); > tree res; > res = build_zero_cst (type); > if (TREE_SIDE_EFFECTS (captures[0])) > res = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (captures[0]), > fold_ignored_result (captures[0]), res);
Just noticed wrong type used here, fixed to do res = build2_loc (loc, COMPOUND_EXPR, type, fold_ignored_result (captures[0]), res); Richard. > return res; > } > > I chose to open-code omit_N_operands. > > For example for > > (simplify > (cond (bit_not @0) @1 @2) > (cond @0 @2 @1)) > > we generate > > captures[0] = o20; > captures[1] = op1; > captures[2] = op2; > if (TREE_SIDE_EFFECTS (op0) || TREE_SIDE_EFFECTS (op1) || > TREE_SIDE_EFFECTS (op2)) return NULL_TREE; > if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Applying > pattern match.pd:207, %s:%d\n", __FILE__, __LINE__); > tree res_op0; > res_op0 = captures[0]; > tree res_op1; > res_op1 = captures[2]; > tree res_op2; > res_op2 = captures[1]; > tree res; > res = fold_build3_loc (loc, COND_EXPR, type, res_op0, res_op1, res_op2); > return res; > > thus give up if any operand of the outer expression has side effects. > > We currently give up for conditionally executed side-effects and > for C expressions in transforms that mention any captures (we > don't understand if they constitute a substitution into the > result). I also give up if captured expressions are substituted > (they would make captures inside that expression used) and if > the replacement contains CSEs. We could fix the latter two cases > if required. > > Bootstrap and regtest running on x86_64-unknown-linux-gnu. > > Richard. > > 2014-10-22 Richard Biener <rguent...@suse.de> > > * genmatch.c (count_captures): New function. > (dt_simplify::gen): Handle preserving side-effects for > GENERIC code generation. > (decision_tree::gen_generic): Do not reject operands > with TREE_SIDE_EFFECTS. > > Index: gcc/genmatch.c > =================================================================== > --- gcc/genmatch.c (revision 216549) > +++ gcc/genmatch.c (working copy) > @@ -1861,6 +1861,46 @@ dt_operand::gen (FILE *f, bool gimple) > fprintf (f, "}\n"); > } > > +/* Count how many times captures are substituted in O and put the > + result in the array of counters CPT. Return false if the > + counting isn't precise. */ > + > +static bool > +count_captures (operand *o, int *cpt) > +{ > + if (capture *c = dyn_cast <capture *> (o)) > + { > + /* Give up for non-leafs (CSEs). */ > + if (c->what) > + return false; > + cpt[c->where]++; > + } > + else if (expr *e = dyn_cast <expr *> (o)) > + { > + /* Give up for conditionally executed operands. */ > + if (*e->operation == COND_EXPR > + || *e->operation == TRUTH_ANDIF_EXPR > + || *e->operation == TRUTH_ORIF_EXPR) > + return false; > + for (unsigned i = 0; i < e->ops.length (); ++i) > + if (!count_captures (e->ops[i], cpt)) > + return false; > + } > + else if (c_expr *e = dyn_cast <c_expr *> (o)) > + { > + /* Give up for C exprs mentioning captures. */ > + for (unsigned i = 0; i < e->code.length (); ++i) > + if (e->code[i].type == CPP_ATSIGN > + && (e->code[i+1].type == CPP_NUMBER > + || e->code[i+1].type == CPP_NAME) > + && !(e->code[i+1].flags & PREV_WHITE)) > + return false; > + } > + else > + gcc_unreachable (); > + return true; > +} > + > /* Generate code for the '(if ...)', '(with ..)' and actual transform > step of a '(simplify ...)' or '(match ...)'. This handles everything > that is not part of the decision tree (simplify->match). */ > @@ -1929,6 +1969,25 @@ dt_simplify::gen (FILE *f, bool gimple) > n_braces++; > } > > + /* 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. Try to compute the number > + of times an expression is substituted. */ > + int *cpt = XALLOCAVEC (int, s->capture_max + 1); > + memset (cpt, 0, sizeof (int) * (s->capture_max + 1)); > + if (!gimple > + && s->result > + && !count_captures (s->result, cpt)) > + { > + /* Oops. We could not get an exact count - give up and simply > + reject the pattern if any input operand had side-effects. */ > + fprintf (f, "if (TREE_SIDE_EFFECTS (op0)"); > + for (unsigned i = 1; i < as_a <expr *> (s->match)->ops.length (); ++i) > + fprintf (f, " || TREE_SIDE_EFFECTS (op%u)", i); > + fprintf (f, ") return NULL_TREE;\n"); > + cpt[0] = -1; > + } > + > fprintf (f, "if (dump_file && (dump_flags & TDF_DETAILS)) " > "fprintf (dump_file, \"Applying pattern "); > output_line_directive (f, s->result_location, true); > @@ -1983,10 +2042,21 @@ dt_simplify::gen (FILE *f, bool gimple) > } > else /* GENERIC */ > { > + bool is_predicate = false; > if (result->type == operand::OP_EXPR) > { > expr *e = as_a <expr *> (result); > - bool is_predicate = is_a <predicate_id *> (e->operation); > + is_predicate = is_a <predicate_id *> (e->operation); > + /* Search for captures used multiple times in the result expression > + and dependent on TREE_SIDE_EFFECTS emit a SAVE_EXPR. */ > + if (!is_predicate && cpt[0] != -1) > + for (int i = 0; i < s->capture_max + 1; ++i) > + { > + if (cpt[i] > 1) > + fprintf (f, " if (TREE_SIDE_EFFECTS (captures[%d]))\n" > + " captures[%d] = save_expr (captures[%d]);\n", > + i, i, i); > + } > for (unsigned j = 0; j < e->ops.length (); ++j) > { > char dest[32]; > @@ -2004,22 +2074,23 @@ dt_simplify::gen (FILE *f, bool gimple) > ? NULL : "TREE_TYPE (res_op0)"); > e->ops[j]->gen_transform (f, dest, false, 1, optype, indexes); > } > - if (is_a <predicate_id *> (e->operation)) > + if (is_predicate) > fprintf (f, "return true;\n"); > else > { > + fprintf (f, " tree res;\n"); > /* Re-fold the toplevel result. Use non_lvalue to > build NON_LVALUE_EXPRs so they get properly > ignored when in GIMPLE form. */ > if (*e->operation == NON_LVALUE_EXPR) > - fprintf (f, " return non_lvalue_loc (loc, res_op0);\n"); > + fprintf (f, " res = non_lvalue_loc (loc, res_op0);\n"); > else > { > if (e->operation->kind == id_base::CODE) > - fprintf (f, " return fold_build%d_loc (loc, %s, type", > + fprintf (f, " res = fold_build%d_loc (loc, %s, type", > e->ops.length (), e->operation->id); > else > - fprintf (f, " return build_call_expr_loc " > + fprintf (f, " res = build_call_expr_loc " > "(loc, builtin_decl_implicit (%s), %d", > e->operation->id, e->ops.length()); > for (unsigned j = 0; j < e->ops.length (); ++j) > @@ -2030,13 +2101,29 @@ dt_simplify::gen (FILE *f, bool gimple) > } > else if (result->type == operand::OP_CAPTURE > || result->type == operand::OP_C_EXPR) > + > { > fprintf (f, " tree res;\n"); > s->result->gen_transform (f, " res", false, 1, "type", indexes); > - fprintf (f, " return res;\n"); > } > else > gcc_unreachable (); > + if (!is_predicate) > + { > + /* Search for captures not used in the result expression and dependent > + on TREE_SIDE_EFFECTS emit omit_one_operand. */ > + if (cpt[0] != -1) > + for (int i = 0; i < s->capture_max + 1; ++i) > + { > + if (cpt[i] == 0) > + fprintf (f, " if (TREE_SIDE_EFFECTS (captures[%d]))\n" > + " res = build2_loc (loc, COMPOUND_EXPR, " > + "TREE_TYPE (captures[%d]), " > + "fold_ignored_result (captures[%d]), res);\n", > + i, i, i); > + } > + fprintf (f, " return res;\n"); > + } > } > > for (unsigned i = 0; i < n_braces; ++i) > @@ -2107,18 +2194,6 @@ decision_tree::gen_generic (FILE *f) > fprintf (f, ")\n"); > fprintf (f, "{\n"); > > - /* ??? For now reject all simplifications on operands with > - side-effects as we are not prepared to properly wrap > - omitted parts with omit_one_operand and friends. In > - principle we can do that automagically for a subset of > - transforms (and only reject the remaining cases). > - This fixes for example gcc.c-torture/execute/20050131-1.c. */ > - fprintf (f, "if ((op0 && TREE_SIDE_EFFECTS (op0))"); > - for (unsigned i = 1; i < n; ++i) > - fprintf (f, "|| (op%d && TREE_SIDE_EFFECTS (op%d))", i, i); > - fprintf (f, ")\n" > - " return NULL_TREE;\n"); > - > fprintf (f, "switch (code)\n" > "{\n"); > for (unsigned i = 0; i < root->kids.length (); i++) > -- Richard Biener <rguent...@suse.de> SUSE / SUSE Labs SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746 GF: Jeff Hawn, Jennifer Guild, Felix Imend"orffer