summary refs log tree commit diff
path: root/lisc/live.c
blob: c3aae8621f9c39fe38e89c89ef39f86e5f0d509d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include "lisc.h"

static void
bset(Ref r, Blk *b, int *nlv)
{
	if (rtype(r) != RTmp)
		return;
	BSET(b->gen, r.val);
	if (!BGET(b->in, r.val)) {
		++*nlv;
		BSET(b->in, r.val);
	}
}

/* liveness analysis
 * requires rpo computation
 */
void
filllive(Fn *f)
{
	Blk *b;
	Ins *i;
	Phi *p;
	int z, m, n, chg, nlv;
	uint a;
	Bits tb;

	assert(f->ntmp <= NBit*BITS);
	for (b=f->start; b; b=b->link) {
		b->in = (Bits){{0}};
		b->out = (Bits){{0}};
		b->gen = (Bits){{0}};
	}
	chg = 1;
Again:
	for (n=f->nblk-1; n>=0; n--) {
		b = f->rpo[n];

		tb = b->out;
		if (b->s1)
			for (z=0; z<BITS; z++)
				b->out.t[z] |= b->s1->in.t[z];
		if (b->s2)
			for (z=0; z<BITS; z++)
				b->out.t[z] |= b->s2->in.t[z];
		chg |= memcmp(&b->out, &tb, sizeof(Bits));

		b->in = b->out;
		nlv = bcnt(&b->in);
		bset(b->jmp.arg, b, &nlv);
		b->nlive = nlv;
		for (i=&b->ins[b->nins]; i!=b->ins;) {
			if ((--i)->op == OCall) {
				b->in.t[0] &= ~calldef(*i, &m);
				nlv -= m;
				if (nlv + NRSave > b->nlive)
					b->nlive = nlv + NRSave;
				b->in.t[0] |= calluse(*i, &m);
				nlv += m;
				bset(i->arg[0], b, &nlv);
			}
			if (!req(i->to, R)) {
				assert(rtype(i->to) == RTmp);
				nlv -= BGET(b->in, i->to.val);
				BCLR(b->in, i->to.val);
			}
			bset(i->arg[0], b, &nlv);
			bset(i->arg[1], b, &nlv);
			if (nlv > b->nlive)
				b->nlive = nlv;
		}

		for (p=b->phi; p; p=p->link) {
			BCLR(b->in, p->to.val);
			for (a=0; a<p->narg; a++)
				if (rtype(p->arg[a]) == RTmp)
					BSET(p->blk[a]->out, p->arg[a].val);
		}
	}
	if (chg) {
		chg = 0;
		goto Again;
	}
}