~cfg_t();
static tagver_t compact(const cfg_t &cfg, tagver_t *ver2new);
static void liveness_analysis(const cfg_t &cfg, bool *live);
+ static void live_through_bblock(const tcmd_t *cmd, bool *live);
static void dead_code_elimination(cfg_t &cfg, const bool *live);
static void interference(const cfg_t &cfg, const bool *live, bool *interf);
static tagver_t variable_allocation(const cfg_t &cfg, const bool *interf, tagver_t *ver2new);
// final and fallback tags can't be dead by construction
cfg_bb_t *b = cfg.bblocks, *e = b + cfg.nbbarc;
+ // ignore possible local liveness inside of bblock:
+ // by construction we have no versions local to bblock
for (; b < e; ++b, live += nver) {
for (tcmd_t *p, **pp = &b->cmd; (p = *pp);) {
if (!live[p->lhs]) {
{
// 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 subsequent commands.
+ // the same RHS by other commands in this block.
memcpy(buf1, live, nver * sizeof(bool));
for (const tcmd_t *p = cmd; p; p = p->next) {
const tagver_t r = p->rhs;
- // alive after this command: RHSs of subsequent commands
- // and all tags alive after this basic block
+ // alive after this command
memcpy(buf2, buf1, nver * sizeof(bool));
- for (const tcmd_t *q = p->next; q; q = q->next) {
- const tagver_t v = q->rhs;
- if (v != r && tcmd_t::iscopy(v)) {
- buf2[v] = true;
- }
- }
+ cfg_t::live_through_bblock(p->next, buf2);
- // exclude: tags equal to RHS of this command
+ // exclude RHS
if (tcmd_t::iscopy(r)) {
buf2[r] = false;
}
+
+ // exclude tags assigned to the same RHS
for (const tcmd_t *q = cmd; q; q = q->next) {
if (q->rhs == r) {
buf2[q->lhs] = false;
return ++ord;
}
+void cfg_t::live_through_bblock(const tcmd_t *cmd, bool *live)
+{
+ if (!cmd) return;
+
+ live_through_bblock(cmd->next, live);
+
+ const tagver_t l = cmd->lhs, r = cmd->rhs;
+ if (live[l] && tcmd_t::iscopy(r)) {
+ live[r] = true;
+ }
+ live[l] = false;
+}
+
void cfg_t::liveness_analysis(const cfg_t &cfg, bool *live)
{
const std::vector<Tag> &tags = cfg.dfa.tags;
const tcmd_t *cmd = cfg.bblocks[*j].cmd;
memcpy(buf2, l, nver * sizeof(bool));
- // need two passes: same version may occur as both LHS and RHS
- for (const tcmd_t *p = cmd; p; p = p->next) {
- buf2[p->lhs] = false;
- }
- for (const tcmd_t *p = cmd; p; p = p->next) {
- if (l[p->lhs] && tcmd_t::iscopy(p->rhs)) {
- buf2[p->rhs] = true;
- }
- }
+ cfg_t::live_through_bblock(cmd, buf2);
for (size_t v = 0; v < nver; ++v) {
buf1[v] |= buf2[v];
}
// need two passes: same version may occur as both LHS and RHS
+ // not the same as backward propagation of liveness through bblock
for (const tcmd_t *p = b->cmd; p; p = p->next) {
buf1[p->lhs] = false;
}
for (const tcmd_t *p = b->cmd; p; p = p->next) {
- if (tcmd_t::iscopy(p->rhs)) {
- buf1[p->rhs] = true;
+ const tagver_t v = p->rhs;
+ if (tcmd_t::iscopy(v)) {
+ buf1[v] = true;
}
}