From: Ulya Trofimovich <skvadrik@gmail.com>
Date: Sun, 2 Jul 2017 08:05:29 +0000 (+0100)
Subject: Allow trivial cycles (of length 1) in tag commands.
X-Git-Tag: 1.0~39^2~36
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7897755dc2943110698806239bf3ff9da232d94f;p=re2c

Allow trivial cycles (of length 1) in tag commands.

We forbid cycles of length 2 or more because they would need temporary
variable local to the basic block, which would complicate liveness
analysis. However, trivial cycles don't need a temporary.
---

diff --git a/re2c/src/dfa/find_state.cc b/re2c/src/dfa/find_state.cc
index aed43b9d..7f667fe7 100644
--- a/re2c/src/dfa/find_state.cc
+++ b/re2c/src/dfa/find_state.cc
@@ -183,10 +183,10 @@ bool kernels_t::operator()(const kernel_t *k1, const kernel_t *k2)
 	*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];
@@ -196,7 +196,7 @@ bool kernels_t::operator()(const kernel_t *k1, const kernel_t *k2)
 		*pa = NULL;
 	}
 
-	return acyclic;
+	return !nontrivial_cycles;
 }
 
 kernels_t::kernels_t(Tagpool &tagp, tcpool_t &tcp, const std::vector<Tag> &ts)
diff --git a/re2c/src/dfa/tcmd.cc b/re2c/src/dfa/tcmd.cc
index 36079270..d7e142eb 100644
--- a/re2c/src/dfa/tcmd.cc
+++ b/re2c/src/dfa/tcmd.cc
@@ -32,8 +32,12 @@ bool tcmd_t::equal_history(const tagver_t *h, const tagver_t *g)
  * 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
@@ -72,7 +76,7 @@ bool tcmd_t::topsort(tcmd_t **phead, uint32_t *indeg)
 	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) {
@@ -102,14 +106,16 @@ bool tcmd_t::topsort(tcmd_t **phead, uint32_t *indeg)
 
 		// 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()