From: Richard Biener Date: Mon, 3 Aug 2015 07:39:12 +0000 (+0000) Subject: genmatch.c (struct sinfo, [...]): New hash-map to record equivalent transforms. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=03038b8b7ad8e68a203cecdc43a44ee5ddbb7f6f;p=gcc.git genmatch.c (struct sinfo, [...]): New hash-map to record equivalent transforms. 2015-08-03 Richard Biener * genmatch.c (struct sinfo, struct sinfo_hashmap_traits, sinfo_map_t): New hash-map to record equivalent transforms. (dt_node::analyze): Populate the equivalent transforms hash-map. (dt_simplify::info): Add reference to hash-map entry. (dt_simplify::gen): If we have split out a function for the transform, generate a call to it. (sinfo_hashmap_traits::hash): New function. (compare_op): New helper function for ... (sinfo_hashmap_traits::equal_keys): ... this new function. (decision_tree::gen): Split out common equivalent transforms into functions. From-SVN: r226490 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7e6464890fe..3a3012a89e5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2015-08-03 Richard Biener + + * genmatch.c (struct sinfo, struct sinfo_hashmap_traits, sinfo_map_t): + New hash-map to record equivalent transforms. + (dt_node::analyze): Populate the equivalent transforms hash-map. + (dt_simplify::info): Add reference to hash-map entry. + (dt_simplify::gen): If we have split out a function for the + transform, generate a call to it. + (sinfo_hashmap_traits::hash): New function. + (compare_op): New helper function for ... + (sinfo_hashmap_traits::equal_keys): ... this new function. + (decision_tree::gen): Split out common equivalent transforms + into functions. + 2015-08-03 Richard Biener * gimple-fold.c (fold_gimple_assign): Remove folding of diff --git a/gcc/genmatch.c b/gcc/genmatch.c index 0579449a8ea..a1bc410c39b 100644 --- a/gcc/genmatch.c +++ b/gcc/genmatch.c @@ -1220,6 +1220,29 @@ lower (vec& simplifiers, bool gimple) matching code. It represents the 'match' expression of all simplifies and has those as its leafs. */ +struct dt_simplify; + +/* A hash-map collecting semantically equivalent leafs in the decision + tree for splitting out to separate functions. */ +struct sinfo +{ + dt_simplify *s; + + const char *fname; + unsigned cnt; +}; + +struct sinfo_hashmap_traits : simple_hashmap_traits > +{ + static inline hashval_t hash (const key_type &); + static inline bool equal_keys (const key_type &, const key_type &); + template static inline void remove (T &) {} +}; + +typedef hash_map + sinfo_map_t; + + /* Decision tree base class, used for DT_TRUE and DT_NODE. */ struct dt_node @@ -1250,7 +1273,7 @@ struct dt_node vec, vec, vec, vec, vec, vec); - void analyze (); + void analyze (sinfo_map_t &); }; /* Generic decision tree node used for DT_OPERAND and DT_MATCH. */ @@ -1285,10 +1308,11 @@ struct dt_simplify : public dt_node simplify *s; unsigned pattern_no; dt_operand **indexes; + sinfo *info; dt_simplify (simplify *s_, unsigned pattern_no_, dt_operand **indexes_) : dt_node (DT_SIMPLIFY), s (s_), pattern_no (pattern_no_), - indexes (indexes_) {} + indexes (indexes_), info (NULL) {} void gen_1 (FILE *, int, bool, operand *); void gen (FILE *f, int, bool); @@ -1303,6 +1327,16 @@ is_a_helper ::test (dt_node *n) || n->type == dt_node::DT_MATCH); } +template<> +template<> +inline bool +is_a_helper ::test (dt_node *n) +{ + return n->type == dt_node::DT_SIMPLIFY; +} + + + /* A container for the actual decision tree. */ struct decision_tree @@ -1455,7 +1489,7 @@ dt_node::append_simplify (simplify *s, unsigned pattern_no, /* Analyze the node and its children. */ void -dt_node::analyze () +dt_node::analyze (sinfo_map_t &map) { num_leafs = 0; total_size = 1; @@ -1463,13 +1497,27 @@ dt_node::analyze () if (type == DT_SIMPLIFY) { + /* Populate the map of equivalent simplifies. */ + dt_simplify *s = as_a (this); + bool existed; + sinfo *&si = map.get_or_insert (s, &existed); + if (!existed) + { + si = new sinfo; + si->s = s; + si->cnt = 1; + si->fname = NULL; + } + else + si->cnt++; + s->info = si; num_leafs = 1; return; } for (unsigned i = 0; i < kids.length (); ++i) { - kids[i]->analyze (); + kids[i]->analyze (map); num_leafs += kids[i]->num_leafs; total_size += kids[i]->total_size; max_level = MAX (max_level, kids[i]->max_level); @@ -2986,25 +3034,179 @@ dt_simplify::gen (FILE *f, int indent, bool gimple) i, indexes[i]->get_name (opname)); } - gen_1 (f, indent, gimple, s->result); + /* If we have a split-out function for the actual transform, call it. */ + if (info && info->fname) + { + if (gimple) + { + fprintf_indent (f, indent, "if (%s (res_code, res_ops, seq, " + "valueize, type, captures))\n", info->fname); + fprintf_indent (f, indent, " return true;\n"); + } + else + { + fprintf_indent (f, indent, "tree res = %s (loc, type", + info->fname); + for (unsigned i = 0; i < as_a (s->match)->ops.length (); ++i) + fprintf (f, ", op%d", i); + fprintf (f, ", captures);\n"); + fprintf_indent (f, indent, "if (res) return res;\n"); + } + } + else + gen_1 (f, indent, gimple, s->result); indent -= 2; fprintf_indent (f, indent, "}\n"); } + +/* Hash function for finding equivalent transforms. */ + +hashval_t +sinfo_hashmap_traits::hash (const key_type &v) +{ + /* Only bother to compare those originating from the same source pattern. */ + return v->s->result->location; +} + +/* Compare function for finding equivalent transforms. */ + +static bool +compare_op (operand *o1, simplify *s1, operand *o2, simplify *s2) +{ + if (o1->type != o2->type) + return false; + + switch (o1->type) + { + case operand::OP_IF: + { + if_expr *if1 = as_a (o1); + if_expr *if2 = as_a (o2); + /* ??? Properly compare c-exprs. */ + if (if1->cond != if2->cond) + return false; + if (!compare_op (if1->trueexpr, s1, if2->trueexpr, s2)) + return false; + if (if1->falseexpr != if2->falseexpr + || (if1->falseexpr + && !compare_op (if1->falseexpr, s1, if2->falseexpr, s2))) + return false; + return true; + } + case operand::OP_WITH: + { + with_expr *with1 = as_a (o1); + with_expr *with2 = as_a (o2); + if (with1->with != with2->with) + return false; + return compare_op (with1->subexpr, s1, with2->subexpr, s2); + } + default:; + } + + /* We've hit a result. Time to compare capture-infos - this is required + in addition to the conservative pointer-equivalency of the result IL. */ + capture_info cinfo1 (s1, o1, true); + capture_info cinfo2 (s2, o2, true); + + if (cinfo1.force_no_side_effects != cinfo2.force_no_side_effects + || cinfo1.info.length () != cinfo2.info.length ()) + return false; + + for (unsigned i = 0; i < cinfo1.info.length (); ++i) + { + if (cinfo1.info[i].expr_p != cinfo2.info[i].expr_p + || cinfo1.info[i].cse_p != cinfo2.info[i].cse_p + || (cinfo1.info[i].force_no_side_effects_p + != cinfo2.info[i].force_no_side_effects_p) + || cinfo1.info[i].force_single_use != cinfo2.info[i].force_single_use + || cinfo1.info[i].cond_expr_cond_p != cinfo2.info[i].cond_expr_cond_p + /* toplevel_msk is an optimization */ + || cinfo1.info[i].result_use_count != cinfo2.info[i].result_use_count + || cinfo1.info[i].same_as != cinfo2.info[i].same_as + /* the pointer back to the capture is for diagnostics only */) + return false; + } + + /* ??? Deep-compare the actual result. */ + return o1 == o2; +} + +bool +sinfo_hashmap_traits::equal_keys (const key_type &v, + const key_type &candidate) +{ + return compare_op (v->s->result, v->s, candidate->s->result, candidate->s); +} + + /* Main entry to generate code for matching GIMPLE IL off the decision tree. */ void decision_tree::gen (FILE *f, bool gimple) { - root->analyze (); + sinfo_map_t si; + + root->analyze (si); fprintf (stderr, "%s decision tree has %u leafs, maximum depth %u and " "a total number of %u nodes\n", gimple ? "GIMPLE" : "GENERIC", root->num_leafs, root->max_level, root->total_size); + /* First split out the transform part of equal leafs. */ + unsigned rcnt = 0; + unsigned fcnt = 1; + for (sinfo_map_t::iterator iter = si.begin (); + iter != si.end (); ++iter) + { + sinfo *s = (*iter).second; + /* Do not split out single uses. */ + if (s->cnt <= 1) + continue; + + rcnt += s->cnt - 1; + if (verbose >= 1) + { + fprintf (stderr, "found %u uses of", s->cnt); + output_line_directive (stderr, s->s->s->result->location); + } + + /* Generate a split out function with the leaf transform code. */ + s->fname = xasprintf ("%s_simplify_%u", gimple ? "gimple" : "generic", + fcnt++); + if (gimple) + fprintf (f, "\nstatic bool\n" + "%s (code_helper *res_code, tree *res_ops,\n" + " gimple_seq *seq, tree (*valueize)(tree) " + "ATTRIBUTE_UNUSED,\n" + " tree ARG_UNUSED (type), tree *ARG_UNUSED " + "(captures))\n", + s->fname); + else + { + fprintf (f, "\nstatic tree\n" + "%s (location_t ARG_UNUSED (loc), tree ARG_UNUSED (type),\n", + (*iter).second->fname); + for (unsigned i = 0; + i < as_a (s->s->s->match)->ops.length (); ++i) + fprintf (f, " tree ARG_UNUSED (op%d),", i); + fprintf (f, " tree *captures)\n"); + } + + fprintf (f, "{\n"); + s->s->gen_1 (f, 2, gimple, s->s->s->result); + if (gimple) + fprintf (f, " return false;\n"); + else + fprintf (f, " return NULL_TREE;\n"); + fprintf (f, "}\n"); + } + fprintf (stderr, "removed %u duplicate tails\n", rcnt); + for (unsigned n = 1; n <= 3; ++n) { /* First generate split-out functions. */