https://gcc.gnu.org/g:99aa410f5e0a722822698e765ca165e73ca4f637
commit r16-189-g99aa410f5e0a722822698e765ca165e73ca4f637 Author: Richard Biener <rguent...@suse.de> Date: Tue Jan 21 13:50:26 2025 +0100 middle-end/80342 - genmatch optimize outer conversions 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. * 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. Diff: --- 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 85bd77aa4cfc..c6097cd722bf 100644 --- a/gcc/genmatch.cc +++ b/gcc/genmatch.cc @@ -1485,7 +1485,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 (); } }; @@ -1538,8 +1538,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 @@ -1572,8 +1572,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. */ @@ -1593,8 +1593,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. */ @@ -3196,6 +3196,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. */ @@ -3249,7 +3257,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 @@ -3307,10 +3315,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) @@ -3322,7 +3343,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; @@ -3333,45 +3355,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); @@ -3397,7 +3469,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; @@ -3417,8 +3489,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); @@ -3501,8 +3575,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) @@ -4353,7 +4430,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; } @@ -4408,16 +4486,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 0fe90a6edc46..a150de5184f6 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -5701,11 +5701,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