*pacts = copy;
// see note [topological ordering of copy commands]
- const bool acyclic = tcmd_t::topsort(pacts, indeg);
+ const bool nontrivial_cycles = tcmd_t::topsort(pacts, indeg);
// in case of cycles restore 'save' commands and fail
- if (!acyclic) {
+ if (nontrivial_cycles) {
pa = pacts;
for (size_t i = 0; i < nact; ++i) {
*pa = a = actnext[i];
*pa = NULL;
}
- return acyclic;
+ return !nontrivial_cycles;
}
kernels_t::kernels_t(Tagpool &tagp, tcpool_t &tcp, const std::vector<Tag> &ts)
* overwrites 'y' before its precious value is copied to 'x').
*
* To avoid overwrites, commands should be topologically sorted.
- * Cycles of length 2 are not allowed by construction; cycles of
- * length 3 or more are left as is.
+ * The algorithm detects cycles and terminates; non-trivial cycles
+ * (induced by 2 or more nodes) are reported. We don't care about
+ * trivial cycles (loopbacks), because they can be implemented without
+ * temporary variable. Non-trivial cycles need a new temporary variable
+ * local to the given basic block, which makes liveness analysis more
+ * complex (so we simply forbid such mappings).
*
* For the purpose of topsort, we treat commands as arcs of directed
* acyclic graph: command 'x = y' yields arc X -> Y. Topsort works
tcmd_t
*x0 = *phead, **px, *x,
*y0 = NULL, **py, **py1;
- bool acyclic = true;
+ bool nontrivial_cycles = false;
// initialize in-degree
for (x = x0; x; x = x->next) {
// only cycles left
if (py == py1) {
- acyclic = false;
+ // look for cycles of length 2 or more
+ for (x = x0; x && x->lhs == x->rhs; x = x->next);
+ nontrivial_cycles = x != NULL;
break;
}
}
*py = x0;
*phead = y0;
- return acyclic;
+ return nontrivial_cycles;
}
tcpool_t::tcpool_t()