namespace re2c
{
-static size_t mask_dead_tags(Tagpool &tagpool,
- size_t oldidx, const bool *live)
-{
- const bool *oldtags = tagpool[oldidx];
- bool *newtags = new bool[tagpool.ntags];
- for (size_t i = 0; i < tagpool.ntags; ++i) {
- newtags[i] = oldtags[i] & live[i];
- }
- const size_t newidx = tagpool.insert(newtags);
- delete[] newtags;
- return newidx;
-}
-
static bool dangling_arcs(const size_t *arcs, size_t narcs)
{
for (size_t i = 0; i < narcs; ++i) {
/* note [liveness analyses on tags]
*
- * Tag T is alive in state S if either:
+ * Tag T is alive in state S if there is a transition
+ * from S to some state S' that does not update T
+ * and either:
*
- * - There is a transition from S to default state that does not set T,
- * S is final and T belongs to tag set associated with rule in S.
+ * - S' is the default state
+ * and S is final
+ * and T belongs to S's final tag set
*
- * - There is a transition from S to default state that does not set T
- * and T belongs to any tag set associated with fallback rules.
+ * - S' is the default state
+ * and S is not final
+ * and T belongs to fallback tag set
*
- * - There is a transition from S to some state S' (maybe equal to S)
- * that does not set T and T is alive in S'.
+ * - S' is not the default state
+ * and T is alive in S'
*/
-static void calc_live(const dfa_t &dfa, const bool *fallback, bool *live)
+static void calc_live(const dfa_t &dfa, size_t fallback, size_t *live)
{
const size_t nstates = dfa.states.size();
- const size_t ntags = dfa.tags.size();
for (size_t i = 0; i < nstates; ++i) {
dfa_state_t *s = dfa.states[i];
if (dangling_arcs(s->arcs, dfa.nchars)) {
if (s->rule != Rule::NONE) {
// final state, only rule tags are alive
- add_tags_with_mask(&live[i * ntags],
- dfa.rules[s->rule].tags,
- dfa.tagpool[s->rule_tags],
- ntags);
+ dfa.tagpool.orl_with_mask(&live[i],
+ dfa.rules[s->rule].tags, s->rule_tags);
} else {
// transition to default state and dispatch on
// 'yyaccept': all fallback rules are potentially
// reachable, their tags are alive
// no mask: no rule implies no rule tags
- add_tags(&live[i * ntags], fallback, ntags);
+ dfa.tagpool.orl(&live[i], fallback);
}
}
}
for (size_t c = 0; c < dfa.nchars; ++c) {
const size_t j = s->arcs[c];
if (j != dfa_t::NIL) {
- loop |= addcmp_tags_with_mask(&live[i * ntags],
- &live[j * ntags],
- dfa.tagpool[s->tags[c]],
- ntags);
+ const size_t old = live[i];
+ dfa.tagpool.orl_with_mask(&live[i], live[j], s->tags[c]);
+ loop |= old != live[i];
}
}
}
}
}
-static void mask_dead(dfa_t &dfa,
- const bool *livetags)
+static void mask_dead(dfa_t &dfa, const size_t *live)
{
const size_t nstates = dfa.states.size();
- const size_t ntags = dfa.tags.size();
for (size_t i = 0; i < nstates; ++i) {
dfa_state_t *s = dfa.states[i];
for (size_t c = 0; c < dfa.nchars; ++c) {
const size_t j = s->arcs[c];
if (j != dfa_t::NIL) {
- s->tags[c] = mask_dead_tags(dfa.tagpool,
- s->tags[c], &livetags[j * ntags]);
+ dfa.tagpool.andl(&s->tags[c], live[j]);
}
}
if (s->rule != Rule::NONE) {
- s->rule_tags = mask_dead_tags(dfa.tagpool,
- s->rule_tags, dfa.rules[s->rule].tags);
+ dfa.tagpool.andl(&s->rule_tags, dfa.rules[s->rule].tags);
}
}
}
// tags that are updated here are pairwise incompatible
// with all tags that are alive, but not updated here
static void incompatible(bool *tbl,
- const bool *live,
- const bool *tags,
- size_t ntags)
+ Tagpool &tagpool, size_t l, size_t t)
{
+ const size_t ntags = tagpool.ntags;
+ const bool *live = tagpool[l];
+ const bool *tags = tagpool[t];
for (size_t i = 0; i < ntags; ++i) {
if (live[i] && !tags[i]) {
for (size_t j = 0; j < ntags; ++j) {
}
static void incompatibility_table(const dfa_t &dfa,
- const bool *livetags,
- const bool *deftags,
+ const size_t *livetags, size_t deftags,
bool *incompattbl)
{
const size_t nstates = dfa.states.size();
for (size_t c = 0; c < dfa.nchars; ++c) {
const size_t j = s->arcs[c];
if (j != dfa_t::NIL) {
- incompatible(incompattbl,
- &livetags[j * ntags],
- dfa.tagpool[s->tags[c]],
- ntags);
+ incompatible(incompattbl, dfa.tagpool,
+ livetags[j], s->tags[c]);
}
}
if (dangling_arcs(s->arcs, dfa.nchars)) {
if (s->rule != Rule::NONE) {
- incompatible(incompattbl,
- dfa.rules[s->rule].tags,
- dfa.tagpool[s->rule_tags],
- ntags);
+ incompatible(incompattbl, dfa.tagpool,
+ dfa.rules[s->rule].tags, s->rule_tags);
} else {
- incompatible(incompattbl,
- deftags,
- dfa.tagpool[s->rule_tags],
- ntags);
+ incompatible(incompattbl, dfa.tagpool,
+ deftags, s->rule_tags);
}
}
}
* Finding minimal clique cover in arbitrary graph is NP-complete.
* We build just some cover (not necessarily minimal).
* The algorithm takes quadratic (in the number of tags) time.
- * static void equivalence_classes(const std::vector<bool> &incompattbl,
*/
static void equivalence_classes(const bool *incompattbl,
size_t ntags, std::vector<size_t> &represent)
}
}
-static size_t patch_tagset(Tagpool &tagpool, size_t oldidx,
- const std::vector<size_t> &represent)
-{
- const bool *oldtags = tagpool[oldidx];
- bool *newtags = new bool[tagpool.ntags]();
- for (size_t i = 0; i < tagpool.ntags; ++i) {
- if (oldtags[i]) {
- newtags[represent[i]] = true;
- }
- }
- const size_t newidx = tagpool.insert(newtags);
- delete[] newtags;
- return newidx;
-}
-
static void patch_tags(dfa_t &dfa, const std::vector<size_t> &represent)
{
const size_t nstates = dfa.states.size();
for (size_t i = 0; i < nstates; ++i) {
dfa_state_t *s = dfa.states[i];
for (size_t c = 0; c < dfa.nchars; ++c) {
- s->tags[c] = patch_tagset(dfa.tagpool, s->tags[c], represent);
+ dfa.tagpool.subst(&s->tags[c], represent);
}
- s->rule_tags = patch_tagset(dfa.tagpool, s->rule_tags, represent);
+ dfa.tagpool.subst(&s->rule_tags, represent);
}
const size_t ntags = dfa.tags.size();
return 0;
}
- bool *fbtags = new bool[ntags]();
+ size_t fbtags = 0;
for (size_t i = 0; i < fallback.size(); ++i) {
const size_t r = dfa.states[fallback[i]]->rule;
- add_tags(fbtags, dfa.rules[r].tags, ntags);
+ dfa.tagpool.orl(&fbtags, dfa.rules[r].tags);
}
const size_t nstates = dfa.states.size();
- bool *live = new bool[nstates * ntags]();
+ size_t *live = new size_t[nstates]();
calc_live(dfa, fbtags, live);
mask_dead(dfa, live);
patch_tags(dfa, represent);
}
- delete[] fbtags;
delete[] live;
delete[] incompattbl;
--- /dev/null
+#include "src/ir/tagpool.h"
+#include "src/util/forbid_copy.h"
+
+namespace re2c
+{
+
+Tagpool::Tagpool(size_t n)
+ : ntags(n)
+ , pool()
+ , buff(new bool[ntags]())
+{
+ // all-no tag set must have number 0
+ insert(buff);
+}
+
+Tagpool::~Tagpool()
+{
+ delete[] buff;
+}
+
+size_t Tagpool::insert(const bool *tags)
+{
+ return pool.insert(tags, ntags * sizeof(bool));
+}
+
+void Tagpool::orl(size_t *pt, size_t o)
+{
+ const size_t t = *pt;
+ if (t == o || o == 0) {
+ return;
+ } else if (t == 0) {
+ *pt = o;
+ return;
+ }
+
+ const bool *tags = operator[](t);
+ const bool *ortags = operator[](o);
+ for (size_t i = 0; i < ntags; ++i) {
+ buff[i] = tags[i] | ortags[i];
+ }
+ *pt = insert(buff);
+}
+
+void Tagpool::orl_with_mask(size_t *pt, size_t o, size_t m)
+{
+ const size_t t = *pt;
+ if (t == o || o == 0) {
+ return;
+ }
+
+ const bool *tags = operator[](t);
+ const bool *ortags = operator[](o);
+ const bool *masktags = operator[](m);
+ for (size_t i = 0; i < ntags; ++i) {
+ buff[i] = tags[i] | (ortags[i] & ~masktags[i]);
+ }
+ *pt = insert(buff);
+}
+
+void Tagpool::andl(size_t *pt, size_t a)
+{
+ const size_t t = *pt;
+ if (t == a) {
+ return;
+ } else if (t == 0 || a == 0) {
+ *pt = 0;
+ return;
+ }
+
+ const bool *tags = operator[](t);
+ const bool *andtags = operator[](a);
+ for (size_t i = 0; i < ntags; ++i) {
+ buff[i] = tags[i] & andtags[i];
+ }
+ *pt = insert(buff);
+}
+
+void Tagpool::subst(size_t *pt, const std::vector<size_t> &represent)
+{
+ const bool *tags = operator[](*pt);
+ memset(buff, 0, ntags * sizeof(bool));
+ for (size_t i = 0; i < ntags; ++i) {
+ if (tags[i]) {
+ buff[represent[i]] = true;
+ }
+ }
+ *pt = insert(buff);
+}
+
+const bool *Tagpool::operator[](size_t idx)
+{
+ const bool *tags;
+ pool.deref<const bool>(idx, tags);
+ return tags;
+}
+
+} // namespace re2c
#define _RE2C_IR_TAGPOOL_
#include "src/util/ord_hash_set.h"
+#include "src/util/forbid_copy.h"
namespace re2c
{
private:
ord_hash_set_t pool;
+ bool *buff;
public:
- explicit inline Tagpool(size_t n);
- inline size_t insert(const bool *tags);
- inline const bool *operator[](size_t idx);
+ explicit Tagpool(size_t n);
+ ~Tagpool();
+ size_t insert(const bool *tags);
+ void orl(size_t *pt, size_t o);
+ void orl_with_mask(size_t *pt, size_t o, size_t m);
+ void andl(size_t *pt, size_t a);
+ void subst(size_t *pt, const std::vector<size_t> &represent);
+ const bool *operator[](size_t idx);
+ FORBID_COPY(Tagpool);
};
-Tagpool::Tagpool(size_t n)
- : ntags(n)
- , pool()
-{
- const bool *zerotags = new bool[ntags]();
- insert(zerotags);
- delete[] zerotags;
-}
-
-size_t Tagpool::insert(const bool *tags)
-{
- return pool.insert(tags, ntags * sizeof(bool));
-}
-
-const bool *Tagpool::operator[](size_t idx)
-{
- const bool *tags;
- pool.deref<const bool>(idx, tags);
- return tags;
-}
-
-inline void add_tags(bool *oldtags, const bool *newtags, size_t ntags)
-{
- for (size_t i = 0; i < ntags; ++i) {
- oldtags[i] |= newtags[i];
- }
-}
-
-inline void add_tags_with_mask(bool *oldtags, const bool *newtags,
- const bool *mask, size_t ntags)
-{
- for (size_t i = 0; i < ntags; ++i) {
- oldtags[i] |= newtags[i] & ~mask[i];
- }
-}
-
-inline bool addcmp_tags_with_mask(bool *oldtags, const bool *newtags,
- const bool *mask, size_t ntags)
-{
- bool diff = false;
- for (size_t i = 0; i < ntags; ++i) {
- const bool old = oldtags[i];
- oldtags[i] |= newtags[i] & ~mask[i];
- diff |= old != oldtags[i];
- }
- return diff;
-}
-
} // namespace re2c
#endif // _RE2C_IR_TAGPOOL_