The following improves genmatch generated code so we avoid more spurious SSA assignments to be pushed to the GIMPLE sequence or simplifications rejected when we're not supposed to produce any for outer and intermediate conversions.
Bootstrapped and tested on x86_64-unknown-linux-gnu, queued for stage1. Richard. * genmatch.cc (::gen_transform): Add in_place parameter. Assert it isn't set in unexpected places. (possible_noop_convert): New. (expr::gen_transform): Support in_place and emit code to compute a child in-place when the operation is a conversion. (dt_simplify::gen_1): Arrange for an outermost conversion to be elided by generating the transform of the operand in-place. * match.pd (__real cepxi (x) -> cos (x)): Use single_use. --- gcc/genmatch.cc | 201 +++++++++++++++++++++++++++++++++++++----------- gcc/match.pd | 10 ++- 2 files changed, 160 insertions(+), 51 deletions(-) diff --git a/gcc/genmatch.cc b/gcc/genmatch.cc index b9a792e2455..a81629c57b2 100644 --- a/gcc/genmatch.cc +++ b/gcc/genmatch.cc @@ -1475,7 +1475,7 @@ public: virtual void gen_transform (FILE *, int, const char *, bool, int, const char *, capture_info *, dt_operand ** = 0, - int = 0) + int = 0, const char * = nullptr) { gcc_unreachable (); } }; @@ -1528,8 +1528,8 @@ public: /* If non-zero, the group for optional handling. */ unsigned char opt_grp; void gen_transform (FILE *f, int, const char *, bool, int, - const char *, capture_info *, - dt_operand ** = 0, int = 0) override; + const char *, capture_info *, dt_operand ** = 0, + int = 0, const char * = nullptr) override; }; /* An operator that is represented by native C code. This is always @@ -1562,8 +1562,8 @@ public: /* The identifier replacement vector. */ vec<id_tab> ids; void gen_transform (FILE *f, int, const char *, bool, int, - const char *, capture_info *, - dt_operand ** = 0, int = 0) final override; + const char *, capture_info *, dt_operand ** = 0, + int = 0, const char * = nullptr) final override; }; /* A wrapper around another operand that captures its value. */ @@ -1583,8 +1583,8 @@ public: /* The captured value. */ operand *what; void gen_transform (FILE *f, int, const char *, bool, int, - const char *, capture_info *, - dt_operand ** = 0, int = 0) final override; + const char *, capture_info *, dt_operand ** = 0, + int = 0, const char * = nullptr) final override; }; /* if expression. */ @@ -3186,6 +3186,14 @@ is_conversion (id_base *op) || *op == VIEW_CONVERT_EXPR); } +bool +possible_noop_convert (id_base *op) +{ + return (*op == CONVERT_EXPR + || *op == NOP_EXPR + || *op == VIEW_CONVERT_EXPR); +} + /* Get the type to be used for generating operand POS of OP from the various sources. */ @@ -3239,7 +3247,7 @@ get_operand_type (id_base *op, unsigned pos, void expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, int depth, const char *in_type, capture_info *cinfo, - dt_operand **indexes, int) + dt_operand **indexes, int, const char *in_place) { id_base *opr = operation; /* When we delay operator substituting during lowering of fors we @@ -3297,10 +3305,23 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, if (!type) fatal_at (location, "cannot determine type of operand"); + bool child_in_place = (!in_place + && gimple + && possible_noop_convert (opr) + && is_a <expr *> (ops[0])); + fprintf_indent (f, indent, "{\n"); indent += 2; - fprintf_indent (f, indent, - "tree _o%d[%u], _r%d;\n", depth, ops.length (), depth); + if (child_in_place) + { + fprintf_indent (f, indent, "tree _r%d;\n", depth); + fprintf_indent (f, indent, + "gimple_match_op tem_op (res_op->cond.any_else (), " + "ERROR_MARK, error_mark_node, 1);\n"); + } + else + fprintf_indent (f, indent, + "tree _o%d[%u], _r%d;\n", depth, ops.length (), depth); char op0type[64]; snprintf (op0type, sizeof (op0type), "TREE_TYPE (_o%d[0])", depth); for (unsigned i = 0; i < ops.length (); ++i) @@ -3312,7 +3333,8 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, i == 0 ? NULL : op0type); ops[i]->gen_transform (f, indent, dest1, gimple, depth + 1, optype1, cinfo, indexes, - *opr == COND_EXPR && i == 0 ? 1 : 2); + *opr == COND_EXPR && i == 0 ? 1 : 2, + child_in_place ? "tem_op" : NULL); } const char *opr_name; @@ -3323,45 +3345,95 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, if (gimple) { - if (*opr == CONVERT_EXPR) + if (child_in_place) { + gcc_assert (!in_place); fprintf_indent (f, indent, - "if (%s != TREE_TYPE (_o%d[0])\n", - type, depth); + "if (%s != tem_op.type\n", type); fprintf_indent (f, indent, - " && !useless_type_conversion_p (%s, TREE_TYPE " - "(_o%d[0])))\n", - type, depth); + " && !useless_type_conversion_p (%s, tem_op.type))\n", + type); fprintf_indent (f, indent + 2, "{\n"); indent += 4; + fprintf_indent (f, indent, + "_r%d = maybe_push_res_to_seq (&tem_op, %s);\n", + depth, (!as_a <expr *> (ops[0])->force_leaf + ? "lseq" : "NULL")); + fprintf_indent (f, indent, + "if (!_r%d) goto %s;\n", depth, fail_label); + fprintf_indent (f, indent, + "tem_op.set_op (%s, %s, 1);\n", opr_name, type); + fprintf_indent (f, indent, + "tem_op.ops[0] = _r%d;\n", depth); + fprintf_indent (f, indent, + "tem_op.resimplify (%s, valueize);\n", + !force_leaf ? "lseq" : "NULL"); + indent -= 4; + fprintf_indent (f, indent + 2, "}\n"); + fprintf_indent (f, indent, + "_r%d = maybe_push_res_to_seq (&tem_op, %s);\n", + depth, !force_leaf ? "lseq" : "NULL"); + fprintf_indent (f, indent, + "if (!_r%d) goto %s;\n", depth, fail_label); } - /* ??? Building a stmt can fail for various reasons here, seq being - NULL or the stmt referencing SSA names occuring in abnormal PHIs. - So if we fail here we should continue matching other patterns. */ - fprintf_indent (f, indent, "gimple_match_op tem_op " - "(res_op->cond.any_else (), %s, %s", opr_name, type); - for (unsigned i = 0; i < ops.length (); ++i) - fprintf (f, ", _o%d[%u]", depth, i); - fprintf (f, ");\n"); - fprintf_indent (f, indent, "tem_op.resimplify (%s, valueize);\n", - !force_leaf ? "lseq" : "NULL"); - fprintf_indent (f, indent, - "_r%d = maybe_push_res_to_seq (&tem_op, %s);\n", depth, - !force_leaf ? "lseq" : "NULL"); - fprintf_indent (f, indent, - "if (!_r%d) goto %s;\n", - depth, fail_label); - if (*opr == CONVERT_EXPR) + else if (in_place) { - indent -= 4; - fprintf_indent (f, indent, " }\n"); - fprintf_indent (f, indent, "else\n"); - fprintf_indent (f, indent, " _r%d = _o%d[0];\n", depth, depth); + gcc_assert (!child_in_place); + fprintf_indent (f, indent, + "%s.set_op (%s, %s, %d);\n", in_place, + opr_name, type, ops.length ()); + for (unsigned i = 0; i < ops.length (); ++i) + fprintf_indent (f, indent, + "%s.ops[%u] = _o%d[%u];\n", in_place, i, depth, i); + fprintf_indent (f, indent, + "%s.resimplify (%s, valueize);\n", + in_place, !force_leaf ? "lseq" : "NULL"); + indent -= 2; + fprintf_indent (f, indent, "}\n"); + return; + } + else + { + if (possible_noop_convert (opr)) + { + fprintf_indent (f, indent, + "if (%s != TREE_TYPE (_o%d[0]) /* XXX */\n", + type, depth); + fprintf_indent (f, indent, + " && !useless_type_conversion_p (%s, TREE_TYPE " + "(_o%d[0])))\n", + type, depth); + fprintf_indent (f, indent + 2, "{\n"); + indent += 4; + } + /* ??? Building a stmt can fail for various reasons here, seq being + NULL or the stmt referencing SSA names occuring in abnormal PHIs. + So if we fail here we should continue matching other patterns. */ + fprintf_indent (f, indent, "gimple_match_op tem_op " + "(res_op->cond.any_else (), %s, %s", opr_name, type); + for (unsigned i = 0; i < ops.length (); ++i) + fprintf (f, ", _o%d[%u]", depth, i); + fprintf (f, ");\n"); + fprintf_indent (f, indent, "tem_op.resimplify (%s, valueize);\n", + !force_leaf ? "lseq" : "NULL"); + fprintf_indent (f, indent, + "_r%d = maybe_push_res_to_seq (&tem_op, %s);\n", + depth, !force_leaf ? "lseq" : "NULL"); + fprintf_indent (f, indent, + "if (!_r%d) goto %s;\n", + depth, fail_label); + if (possible_noop_convert (opr)) + { + indent -= 4; + fprintf_indent (f, indent, " }\n"); + fprintf_indent (f, indent, "else\n"); + fprintf_indent (f, indent, " _r%d = _o%d[0];\n", depth, depth); + } } } else { - if (*opr == CONVERT_EXPR) + if (possible_noop_convert (opr)) { fprintf_indent (f, indent, "if (TREE_TYPE (_o%d[0]) != %s)\n", depth, type); @@ -3387,7 +3459,7 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, fprintf_indent (f, indent, "if (EXPR_P (_r%d))\n", depth); fprintf_indent (f, indent, " goto %s;\n", fail_label); } - if (*opr == CONVERT_EXPR) + if (possible_noop_convert (opr)) { fprintf_indent (f, indent - 2, "}\n"); indent -= 4; @@ -3407,8 +3479,10 @@ expr::gen_transform (FILE *f, int indent, const char *dest, bool gimple, void c_expr::gen_transform (FILE *f, int indent, const char *dest, bool, int, const char *, capture_info *, - dt_operand **, int) + dt_operand **, int, const char *in_place) { + gcc_assert (!in_place); + if (dest && nr_stmts == 1) fprintf_indent (f, indent, "%s = ", dest); @@ -3491,8 +3565,11 @@ c_expr::gen_transform (FILE *f, int indent, const char *dest, void capture::gen_transform (FILE *f, int indent, const char *dest, bool gimple, int depth, const char *in_type, capture_info *cinfo, - dt_operand **indexes, int cond_handling) + dt_operand **indexes, int cond_handling, + const char *in_place) { + gcc_assert (!in_place); + if (what && is_a<expr *> (what)) { if (indexes[where] == 0) @@ -4343,7 +4420,8 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) if (s->kind == simplify::SIMPLIFY) { - fprintf_indent (f, indent, "if (UNLIKELY (!dbg_cnt (match))) goto %s;\n", fail_label); + fprintf_indent (f, indent, "if (UNLIKELY (!dbg_cnt (match))) goto %s;\n", + fail_label); needs_label = true; } @@ -4398,16 +4476,45 @@ dt_simplify::gen_1 (FILE *f, int indent, bool gimple, operand *result) if (!is_predicate) cond_handling = (*opr == COND_EXPR && j == 0) ? 1 : 2; e->ops[j]->gen_transform (f, indent, dest, true, 1, optype, - &cinfo, indexes, cond_handling); + &cinfo, indexes, cond_handling, + (possible_noop_convert (opr) + && is_a <expr *> (e->ops[j])) + ? "(*res_op)" : NULL); } /* Re-fold the toplevel result. It's basically an embedded gimple_build w/o actually building the stmt. */ if (!is_predicate) { - fprintf_indent (f, indent, - "res_op->resimplify (%s, valueize);\n", - !e->force_leaf ? "lseq" : "NULL"); + if (possible_noop_convert (opr) + && is_a <expr *> (e->ops[0])) + { + fprintf_indent (f, indent, + "if (type != res_op->type\n"); + fprintf_indent (f, indent, + " && !useless_type_conversion_p (type, res_op->type))\n"); + fprintf_indent (f, indent, + " {\n"); + indent += 4; + fprintf_indent (f, indent, + "if (!(res_op->ops[0] = maybe_push_res_to_seq (res_op, %s))) goto %s;\n", + !as_a <expr *> (e->ops[0])->force_leaf + ? "lseq" : "NULL", fail_label); + needs_label = true; + fprintf_indent (f, indent, + "res_op->set_op (%s, type, 1);\n", + *opr == CONVERT_EXPR ? "NOP_EXPR" : opr->id); + fprintf_indent (f, indent, + "res_op->resimplify (%s, valueize);\n", + !e->force_leaf ? "lseq" : "NULL"); + indent -= 4; + fprintf_indent (f, indent, + " }\n"); + } + else + fprintf_indent (f, indent, + "res_op->resimplify (%s, valueize);\n", + !e->force_leaf ? "lseq" : "NULL"); if (e->force_leaf) { fprintf_indent (f, indent, diff --git a/gcc/match.pd b/gcc/match.pd index 6991868fbe2..d452c62b322 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -5629,11 +5629,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (part (convert?:s@2 (op:s @0 @1))) (convert (op (part @0) (part @1)))))) (simplify - (realpart (convert?:s (CEXPI:s @0))) - (convert (COS @0))) + (realpart (convert?@2 (CEXPI@1 @0))) + (if (single_use (@1) && single_use (@2)) + (convert (COS @0)))) (simplify - (imagpart (convert?:s (CEXPI:s @0))) - (convert (SIN @0))) + (imagpart (convert?@2 (CEXPI@1 @0))) + (if (single_use (@1) && single_use (@2)) + (convert (SIN @0)))) /* conj(conj(x)) -> x */ (simplify -- 2.43.0