]> granicus.if.org Git - re2c/commitdiff
Tag interference analysis: compare actual values, not formal RHS.
authorUlya Trofimovich <skvadrik@gmail.com>
Fri, 14 Apr 2017 10:45:23 +0000 (11:45 +0100)
committerUlya Trofimovich <skvadrik@gmail.com>
Fri, 14 Apr 2017 11:03:07 +0000 (12:03 +0100)
Commands in the same basic block may have equal right hand sides,
e.g. 'x = y; z = y;'. Clearly in this case 'x' and 'z' do not interfere:
both versions are equal to 'y'. This optimization allows to deduplicate
cases like '("a" @x @y @z "b")*', where multiple tags have the same
values.

However, it is insufficient to find all commands in the current block
with RHS equal to current RHS. An example when this algorithm fails:
'x = y; w = z; z = y;', here 'x' and 'z' are assigned to the same RHS
'y', but if we merge them into one variable, 'w' will get the wrong
value.

The fix is as follows: first, ignore subsequent commands and consider
only commands that precede current command: if subsequent command that
sets LHS to the same value precedes any use of it, liveness propagation
through basic block would mark this LHS as dead and not interfering
anyway; otherwise (if use precedes setting to the same value), then it
indeed interferes with current LHS. This fixes the above example
'x = y; w = z; z = y;': when analysing 'x = y;' command we find that
'z' is alive (as before), but ignore subsequent 'z = y;' command (due
to the fix).

Second, when analysing preceding commands, calculate actual value for
each LHS (based on pessimistic assumption that on entry of basic block
all used versions are different). Formal RHS of some preceding command
may coincide with current formal RHS, but their values might differ:
'x = y; y = w; z = y;', here 'x = y;' and 'z = y;' have identical formal
RHS, but the value may be different. On the other hand, formal RHS
might be different, while their actual values are equal, as in
'x = y; w = y; z = w;'.

re2c/src/dfa/cfg/interfere.cc
re2c/test/posix_captures/basic/01.i--flex-syntax.c
re2c/test/posix_captures/basic/02.i--flex-syntax.c
re2c/test/posix_captures/glennfowler/43.i--flex-syntax.c

index dfb8465daa312d7af1955699b0542de2c1e65858..8562e76e49f7132fb27632097be8573001e8d706 100644 (file)
@@ -5,49 +5,79 @@
 namespace re2c
 {
 
-static void interfere(const tcmd_t *cmd, const bool *live, bool *interf, bool *buf, size_t nver);
+typedef std::vector<tagver_t> vals_t;
+static void interfere(const tcmd_t *cmd, const bool *live, bool *interf, bool *buf, vals_t *vals, size_t nver);
 
 void cfg_t::interference(const cfg_t &cfg, const bool *live, bool *interf)
 {
        const size_t nver = static_cast<size_t>(cfg.dfa.maxtagver) + 1;
        bool *buf = new bool[nver];
+       vals_t *vals = new vals_t[nver]();
        const cfg_bb_t *b = cfg.bblocks, *e = b + cfg.nbbfin;
 
        memset(interf, 0, nver * nver * sizeof(bool));
        for (; b < e; ++b, live += nver) {
-               interfere(b->cmd, live, interf, buf, nver);
+               interfere(b->cmd, live, interf, buf, vals, nver);
        }
 
        delete[] buf;
+       delete[] vals;
 }
 
 void interfere(const tcmd_t *cmd, const bool *live, bool *interf,
-       bool *buf, size_t nver)
+       bool *buf, vals_t *vals, size_t nver)
 {
-       // LHS of each command iterferes with all tags that are alive after
-       // this command except its RHS and tags that are are assigned to
-       // the same RHS by other commands in this block.
+       // initialize value of RHS for all commands in this basic block
        for (const tcmd_t *p = cmd; p; p = p->next) {
-               const tagver_t r = p->rhs, *h = p->history;
+               const tagver_t r = p->rhs;
+               if (r != TAGVER_ZERO) {
+                       vals[r].clear();
+                       vals[r].push_back(r);
+               }
+       }
+
+       // find interference list for LHS of each command
+       for (const tcmd_t *p = cmd; p; p = p->next) {
+               const tagver_t l = p->lhs, r = p->rhs, *h = p->history;
+               vals_t &vl = vals[l], &vr = vals[r];
 
                // alive after this command
                memcpy(buf, live, nver * sizeof(bool));
                cfg_t::live_through_bblock(p->next, buf);
 
-               // exclude RHS
+               // if copy command, exclude RHS
                if (tcmd_t::iscopy(p)) buf[r] = false;
 
-               // exclude tags assigned to the same RHS
-               for (const tcmd_t *q = cmd; q; q = q->next) {
-                       if (q->rhs == r && tcmd_t::equal_history(h, q->history)) {
+               // update value of current command's LHS
+               if (tcmd_t::iscopy(p)) {
+                       vl = vr;
+               } else if (tcmd_t::isset(p)) {
+                       vl.clear();
+                       vl.push_back(*h);
+               } else {
+                       if (l != r) vl = vr;
+                       for (; *++h != TAGVER_ZERO;); // history is reversed
+                       for (; h-- != p->history;) {
+                               vl.push_back(*h);
+                       }
+               }
+               // Exclude from interference list all LHS from preceding commands
+               // which value is equal to current LHS value. Subsequent commands
+               // are ignored: if subsequent command that sets LHS to the same value
+               // precedes any use of it, liveness propagation through basic block
+               // would mark this LHS as dead and not interfering anyway; otherwise
+               // (if use precedes setting to the same value), then it indeed
+               // interferes with current LHS.
+               for (const tcmd_t *q = cmd; q != p; q = q->next) {
+                       if (vals[q->lhs] == vl) {
                                buf[q->lhs] = false;
                        }
                }
 
-               const size_t l = static_cast<size_t>(p->lhs);
+               const size_t u = static_cast<size_t>(l);
                for (size_t v = 0; v < nver; ++v) {
                        if (!buf[v]) continue;
-                       interf[l * nver + v] = interf[v * nver + l] = true;
+                       interf[u * nver + v] = interf[v * nver + u] = true;
                }
        }
 }
index 95f82f15e97bbc05650381caae4d4016fb1e2795..dc68a0acb7c3be7d074d942c40967382d8781a61 100644 (file)
@@ -64,7 +64,7 @@ yy9:
        if (YYLIMIT <= YYCURSOR) YYFILL(1);
        yych = *YYCURSOR;
        if (yych <= 0x00) {
-               yyt3 = yyt2;
+               yyt3 = yyt5;
                yyt4 = yyt5 = NULL;
                yyt2 = YYCURSOR;
                goto yy2;
@@ -78,9 +78,9 @@ yy9:
                yyt4 = YYCURSOR;
                goto yy2;
        }
-       yyt4 = yyt2;
-       yyt5 = yyt3;
        yyt2 = yyt3;
+       yyt4 = yyt5;
+       yyt5 = yyt3;
        goto yy9;
 }
 
index 95f82f15e97bbc05650381caae4d4016fb1e2795..dc68a0acb7c3be7d074d942c40967382d8781a61 100644 (file)
@@ -64,7 +64,7 @@ yy9:
        if (YYLIMIT <= YYCURSOR) YYFILL(1);
        yych = *YYCURSOR;
        if (yych <= 0x00) {
-               yyt3 = yyt2;
+               yyt3 = yyt5;
                yyt4 = yyt5 = NULL;
                yyt2 = YYCURSOR;
                goto yy2;
@@ -78,9 +78,9 @@ yy9:
                yyt4 = YYCURSOR;
                goto yy2;
        }
-       yyt4 = yyt2;
-       yyt5 = yyt3;
        yyt2 = yyt3;
+       yyt4 = yyt5;
+       yyt5 = yyt3;
        goto yy9;
 }
 
index 462354c93b1703b35d666edece6437f93052904f..c6e785739def3da4067276ff2809fc15fcc551cf 100644 (file)
@@ -66,7 +66,7 @@ yy9:
        if (YYLIMIT <= YYCURSOR) YYFILL(1);
        yych = *YYCURSOR;
        if (yych <= 0x00) {
-               yyt3 = yyt2;
+               yyt3 = yyt5;
                yyt4 = yyt5 = NULL;
                yyt2 = YYCURSOR;
                goto yy2;
@@ -80,9 +80,9 @@ yy9:
                yyt4 = YYCURSOR;
                goto yy2;
        }
-       yyt4 = yyt2;
-       yyt5 = yyt3;
        yyt2 = yyt3;
+       yyt4 = yyt5;
+       yyt5 = yyt3;
        goto yy9;
 }