This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH][match-and-simplify] Hande side-effects in GENERIC
- From: Richard Biener <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Jakub Jelinek <jakub at redhat dot com>
- Date: Wed, 22 Oct 2014 16:35:03 +0200 (CEST)
- Subject: Re: [PATCH][match-and-simplify] Hande side-effects in GENERIC
- Authentication-results: sourceware.org; auth=none
- References: <alpine dot LSU dot 2 dot 11 dot 1410221609380 dot 9891 at zhemvz dot fhfr dot qr>
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 <rguenther@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 <rguenther@suse.de>
SUSE / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746
GF: Jeff Hawn, Jennifer Guild, Felix Imend"orffer