aboutsummaryrefslogtreecommitdiff
path: root/gcc/genmatch.c
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2014-10-24 11:00:08 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2014-10-24 11:00:08 +0000
commite0ee10ed5af17d90ea7621d4270a50284ad76c45 (patch)
tree826b57b3cced839600a97bf9bbdd9105348dfd6e /gcc/genmatch.c
parent77efea31205aab4e4fa0d2760d2fa6108d4a56f3 (diff)
downloadgcc-e0ee10ed5af17d90ea7621d4270a50284ad76c45.zip
gcc-e0ee10ed5af17d90ea7621d4270a50284ad76c45.tar.gz
gcc-e0ee10ed5af17d90ea7621d4270a50284ad76c45.tar.bz2
genmatch.c (expr::gen_transform): Use fold_buildN_loc and build_call_expr_loc.
2014-10-24 Richard Biener <rguenther@suse.de> * genmatch.c (expr::gen_transform): Use fold_buildN_loc and build_call_expr_loc. (dt_simplify::gen): Drop non_lvalue for GIMPLE, use non_lvalue_loc to build it for GENERIC. (decision_tree::gen_generic): Add location argument to generic_simplify prototype. (capture_info): New class. (capture_info::capture_info): New constructor. (capture_info::walk_match): New method. (capture_info::walk_result): New method. (capture_info::walk_c_expr): New method. (dt_simplify::gen): Handle preserving side-effects for GENERIC code generation. (decision_tree::gen_generic): Do not reject operands with TREE_SIDE_EFFECTS. * generic-match.h: New file. * generic-match-head.c: Include generic-match.h, not gimple-match.h. * match.pd: Add some constant folding patterns from fold-const.c. * fold-const.c: Include generic-match.h. (fold_unary_loc): Dispatch to generic_simplify. (fold_ternary_loc): Likewise. (fold_binary_loc): Likewise. Remove patterns now implemented by generic_simplify. * gimple-fold.c (replace_stmt_with_simplification): New function. (fold_stmt_1): Add valueize parameter, dispatch to gimple_simplify. (no_follow_ssa_edges): New function. (fold_stmt): New overload with valueization hook. Use no_follow_ssa_edges for the overload without hook. (fold_stmt_inplace): Likewise. * gimple-fold.h (no_follow_ssa_edges): Declare. From-SVN: r216631
Diffstat (limited to 'gcc/genmatch.c')
-rw-r--r--gcc/genmatch.c295
1 files changed, 257 insertions, 38 deletions
diff --git a/gcc/genmatch.c b/gcc/genmatch.c
index 2def7fa..ebdb7d3 100644
--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -1374,10 +1374,11 @@ expr::gen_transform (FILE *f, const char *dest, bool gimple, int depth,
else
{
if (operation->kind == id_base::CODE)
- fprintf (f, " res = fold_build%d (%s, %s",
+ fprintf (f, " res = fold_build%d_loc (loc, %s, %s",
ops.length(), operation->id, type);
else
- fprintf (f, " res = build_call_expr (builtin_decl_implicit (%s), %d",
+ fprintf (f, " res = build_call_expr_loc (loc, "
+ "builtin_decl_implicit (%s), %d",
operation->id, ops.length());
for (unsigned i = 0; i < ops.length (); ++i)
fprintf (f, ", ops%d[%u]", depth, i);
@@ -1860,6 +1861,167 @@ dt_operand::gen (FILE *f, bool gimple)
fprintf (f, "}\n");
}
+
+/* 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. */
+ 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))
+ {
+ const cpp_token *n = &e->code[i+1];
+ 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)[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
that is not part of the decision tree (simplify->match). */
@@ -1928,21 +2090,54 @@ dt_simplify::gen (FILE *f, bool gimple)
n_braces++;
}
+ /* Analyze captures and perform early-outs on the incoming arguments
+ that cover cases we cannot handle. */
+ capture_info cinfo (s);
+ expr *e;
+ if (!gimple
+ && s->result
+ && !((e = dyn_cast <expr *> (s->result))
+ && is_a <predicate_id *> (e->operation)))
+ {
+ for (unsigned i = 0; i < as_a <expr *> (s->match)->ops.length (); ++i)
+ if (cinfo.force_no_side_effects & (1 << i))
+ fprintf (f, "if (TREE_SIDE_EFFECTS (op%d)) return NULL_TREE;\n", i);
+ for (int i = 0; i <= s->capture_max; ++i)
+ if (cinfo.info[i].cse_p)
+ ;
+ else if (cinfo.info[i].force_no_side_effects_p
+ && (cinfo.info[i].toplevel_msk
+ & cinfo.force_no_side_effects) == 0)
+ fprintf (f, "if (TREE_SIDE_EFFECTS (captures[%d])) "
+ "return NULL_TREE;\n", i);
+ else if ((cinfo.info[i].toplevel_msk
+ & cinfo.force_no_side_effects) != 0)
+ /* Mark capture as having no side-effects if we had to verify
+ that via forced toplevel operand checks. */
+ cinfo.info[i].force_no_side_effects_p = true;
+ }
+
fprintf (f, "if (dump_file && (dump_flags & TDF_DETAILS)) "
"fprintf (dump_file, \"Applying pattern ");
output_line_directive (f, s->result_location, true);
fprintf (f, ", %%s:%%d\\n\", __FILE__, __LINE__);\n");
- if (!s->result)
+ operand *result = s->result;
+ if (!result)
{
/* If there is no result then this is a predicate implementation. */
fprintf (f, "return true;\n");
}
else if (gimple)
{
- if (s->result->type == operand::OP_EXPR)
+ /* For GIMPLE simply drop NON_LVALUE_EXPR (which only appears
+ in outermost position). */
+ if (result->type == operand::OP_EXPR
+ && *as_a <expr *> (result)->operation == NON_LVALUE_EXPR)
+ result = as_a <expr *> (result)->ops[0];
+ if (result->type == operand::OP_EXPR)
{
- expr *e = as_a <expr *> (s->result);
+ expr *e = as_a <expr *> (result);
bool is_predicate = is_a <predicate_id *> (e->operation);
if (!is_predicate)
fprintf (f, "*res_code = %s;\n", e->operation->id);
@@ -1964,10 +2159,10 @@ dt_simplify::gen (FILE *f, bool gimple)
fprintf (f, "gimple_resimplify%d (seq, res_code, type, "
"res_ops, valueize);\n", e->ops.length ());
}
- else if (s->result->type == operand::OP_CAPTURE
- || s->result->type == operand::OP_C_EXPR)
+ else if (result->type == operand::OP_CAPTURE
+ || result->type == operand::OP_C_EXPR)
{
- s->result->gen_transform (f, "res_ops[0]", true, 1, "type", indexes);
+ result->gen_transform (f, "res_ops[0]", true, 1, "type", indexes);
fprintf (f, "*res_code = TREE_CODE (res_ops[0]);\n");
}
else
@@ -1976,10 +2171,22 @@ dt_simplify::gen (FILE *f, bool gimple)
}
else /* GENERIC */
{
- if (s->result->type == operand::OP_EXPR)
+ bool is_predicate = false;
+ if (result->type == operand::OP_EXPR)
{
- expr *e = as_a <expr *> (s->result);
- bool is_predicate = is_a <predicate_id *> (e->operation);
+ expr *e = as_a <expr *> (result);
+ 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)
+ for (int i = 0; i < s->capture_max + 1; ++i)
+ {
+ if (!cinfo.info[i].force_no_side_effects_p
+ && cinfo.info[i].result_use_count > 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];
@@ -1997,32 +2204,56 @@ 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
{
- /* Re-fold the toplevel result. */
- if (e->operation->kind == id_base::CODE)
- fprintf (f, " return fold_build%d (%s, type",
- e->ops.length (), e->operation->id);
+ 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, " res = non_lvalue_loc (loc, res_op0);\n");
else
- fprintf (f, " return build_call_expr "
- "(builtin_decl_implicit (%s), %d",
- e->operation->id, e->ops.length());
- for (unsigned j = 0; j < e->ops.length (); ++j)
- fprintf (f, ", res_op%d", j);
- fprintf (f, ");\n");
+ {
+ if (e->operation->kind == id_base::CODE)
+ fprintf (f, " res = fold_build%d_loc (loc, %s, type",
+ e->ops.length (), e->operation->id);
+ else
+ 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)
+ fprintf (f, ", res_op%d", j);
+ fprintf (f, ");\n");
+ }
}
}
- else if (s->result->type == operand::OP_CAPTURE
- || s->result->type == operand::OP_C_EXPR)
+ 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. */
+ for (int i = 0; i < s->capture_max + 1; ++i)
+ {
+ if (!cinfo.info[i].force_no_side_effects_p
+ && !cinfo.info[i].expr_p
+ && cinfo.info[i].result_use_count == 0)
+ fprintf (f, " if (TREE_SIDE_EFFECTS (captures[%d]))\n"
+ " res = build2_loc (loc, COMPOUND_EXPR, type,"
+ " fold_ignored_result (captures[%d]), res);\n",
+ i, i);
+ }
+ fprintf (f, " return res;\n");
+ }
}
for (unsigned i = 0; i < n_braces; ++i)
@@ -2086,25 +2317,13 @@ decision_tree::gen_generic (FILE *f)
for (unsigned n = 1; n <= 3; ++n)
{
fprintf (f, "\ntree\n"
- "generic_simplify (enum tree_code code, "
+ "generic_simplify (location_t loc, enum tree_code code, "
"tree type ATTRIBUTE_UNUSED");
for (unsigned i = 0; i < n; ++i)
fprintf (f, ", tree op%d", i);
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++)