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 <pointer_hash <dt_simplify> >
+{
+ static inline hashval_t hash (const key_type &);
+ static inline bool equal_keys (const key_type &, const key_type &);
+ template <typename T> static inline void remove (T &) {}
+};
+
+typedef hash_map<void * /* unused */, sinfo *, sinfo_hashmap_traits>
+ sinfo_map_t;
+
+
/* Decision tree base class, used for DT_TRUE and DT_NODE. */
struct dt_node
vec<dt_operand *>, vec<dt_operand *>, vec<dt_operand *>,
vec<dt_operand *>, vec<dt_operand *>, vec<dt_node *>);
- void analyze ();
+ void analyze (sinfo_map_t &);
};
/* Generic decision tree node used for DT_OPERAND and DT_MATCH. */
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);
|| n->type == dt_node::DT_MATCH);
}
+template<>
+template<>
+inline bool
+is_a_helper <dt_simplify *>::test (dt_node *n)
+{
+ return n->type == dt_node::DT_SIMPLIFY;
+}
+
+
+
/* A container for the actual decision tree. */
struct decision_tree
/* Analyze the node and its children. */
void
-dt_node::analyze ()
+dt_node::analyze (sinfo_map_t &map)
{
num_leafs = 0;
total_size = 1;
if (type == DT_SIMPLIFY)
{
+ /* Populate the map of equivalent simplifies. */
+ dt_simplify *s = as_a <dt_simplify *> (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);
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 <expr *> (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 <if_expr *> (o1);
+ if_expr *if2 = as_a <if_expr *> (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 <with_expr *> (o1);
+ with_expr *with2 = as_a <with_expr *> (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 <expr *>(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. */