diff options
author | Richard Biener <rguenther@suse.de> | 2014-10-24 11:00:08 +0000 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2014-10-24 11:00:08 +0000 |
commit | e0ee10ed5af17d90ea7621d4270a50284ad76c45 (patch) | |
tree | 826b57b3cced839600a97bf9bbdd9105348dfd6e /gcc/genmatch.c | |
parent | 77efea31205aab4e4fa0d2760d2fa6108d4a56f3 (diff) | |
download | gcc-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.c | 295 |
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++) |