Example #1
0
static void checkundef(Node *n, Reaching *r, Bitset *reach, Bitset *kill)
{
    size_t i, j, did;
    Node *def;
    Type *t;

    if (n->type != Nexpr)
        return;
    if (exprop(n) == Ovar) {
        did = n->expr.did;
        for (j = 0; j < r->ndefs[did]; j++) {
            t = tybase(exprtype(n));
            if (t->type == Tystruct || t->type == Tyunion || t->type == Tyarray || t->type == Tytuple)
                continue;
            if (bshas(kill, r->defs[did][j]))
                continue;
            if (!bshas(reach, r->defs[did][j]))
                continue;
            def = nodes[r->defs[did][j]];
            if (exprop(def) == Oundef)
                fatal(n, "%s used before definition", namestr(n->expr.args[0]));
        }
    } else {
        switch (exprop(n)) {
            case Oset:
            case Oasn:
            case Oblit:
                checkundef(n->expr.args[1], r, reach, kill);
                break;
            case Oaddr:
            case Oslice:
                /* these don't actually look at the of args[0], so they're ok. */
                for (i = 1; i < n->expr.nargs; i++)
                    checkundef(n->expr.args[i], r, reach, kill);
                break;
            case Ocall:
                for (i = 1; i < n->expr.nargs; i++)
                    if (exprop(n->expr.args[i]) != Oaddr)
                        checkundef(n->expr.args[i], r, reach, kill);
                break;
            default:
                for (i = 0; i < n->expr.nargs; i++)
                    checkundef(n->expr.args[i], r, reach, kill);
                break;
        }
    }
}
Example #2
0
File: live.c Project: 8l/qbe
static void
bset(Ref r, Blk *b, int *nlv, Tmp *tmp)
{

	if (rtype(r) != RTmp)
		return;
	bsset(b->gen, r.val);
	if (!bshas(b->in, r.val)) {
		nlv[KBASE(tmp[r.val].cls)]++;
		bsset(b->in, r.val);
	}
}
Example #3
0
File: pmov.c Project: 8l/qbe
int
main()
{
	Ins *i1;
	unsigned long long tm, rm, cnt;
	RMap mend;
	int reg[NIReg], val[NIReg+1];
	int t, i, r, nr;

	tmp = (Tmp[Tmp0+NIReg]){{{0}}};
	for (t=0; t<Tmp0+NIReg; t++)
		if (t >= Tmp0) {
			tmp[t].cls = Kw;
			tmp[t].hint.r = -1;
			tmp[t].hint.m = 0;
			tmp[t].slot = -1;
			sprintf(tmp[t].name, "tmp%d", t-Tmp0+1);
		}

	bsinit_(mbeg.b, Tmp0+NIReg);
	bsinit_(mend.b, Tmp0+NIReg);
	cnt = 0;
	for (tm = 0; tm < 1ull << (2*NIReg); tm++) {
		mbeg.n = 0;
		bszero(mbeg.b);
		ip = ins;

		/* find what temporaries are in copy and
		 * wether or not they are in register
		 */
		for (t=0; t<NIReg; t++)
			switch ((tm >> (2*t)) & 3) {
			case 0:
				/* not in copy, not in reg */
				break;
			case 1:
				/* not in copy, in reg */
				radd(&mbeg, Tmp0+t, t+1);
				break;
			case 2:
				/* in copy, not in reg */
				*ip++ = (Ins){OCopy, TMP(Tmp0+t), {R, R}, Kw};
				break;
			case 3:
				/* in copy, in reg */
				*ip++ = (Ins){OCopy, TMP(Tmp0+t), {R, R}, Kw};
				radd(&mbeg, Tmp0+t, t+1);
				break;
			}

		if (ip == ins)
			/* cancel if the parallel move
			 * is empty
			 */
			goto Nxt;

		/* find registers for temporaries
		 * in mbeg
		 */
		nr = ip - ins;
		rm = (1ull << (nr+1)) - 1;
		for (i=0; i<nr; i++)
			reg[i] = i+1;

		for (;;) {
			/* set registers on copies
			 */
			for (i=0, i1=ins; i1<ip; i1++, i++)
				i1->arg[0] = TMP(reg[i]);

			/* compile the parallel move
			 */
			rcopy(&mend, &mbeg);
			dopm(&dummyb, ip-1, &mend);
			cnt++;

			/* check that mend contain mappings for
			 * source registers and does not map any
			 * assigned temporary, then check that
			 * all temporaries in mend are mapped in
			 * mbeg and not used in the copy
			 */
			for (i1=ins; i1<ip; i1++) {
				r = i1->arg[0].val;
				assert(rfree(&mend, r) == r);
				t = i1->to.val;
				assert(!bshas(mend.b, t));
			}
			for (i=0; i<mend.n; i++) {
				t = mend.t[i];
				assert(bshas(mbeg.b, t));
				t -= Tmp0;
				assert(((tm >> (2*t)) & 3) == 1);
			}

			/* execute the code generated and check
			 * that all assigned temporaries got their
			 * value, and that all live variables's
			 * content got preserved
			 */
			 for (i=1; i<=NIReg; i++)
			 	val[i] = i;
			 iexec(val);
			 for (i1=ins; i1<ip; i1++) {
			 	t = i1->to.val;
			 	r = rfind(&mbeg, t);
			 	if (r != -1)
			 		assert(val[r] == i1->arg[0].val);
			 }
			 for (i=0; i<mend.n; i++) {
			 	t = mend.t[i];
			 	r = mend.r[i];
			 	assert(val[t-Tmp0+1] == r);
			 }

			/* find the next register assignment */
			i = nr - 1;
			for (;;) {
				r = reg[i];
				rm &= ~(1ull<<r);
				do
					r++;
				while (r <= NIReg && (rm & (1ull<<r)));
				if (r == NIReg+1) {
					if (i == 0)
						goto Nxt;
					i--;
				} else {
					rm |= (1ull<<r);
					reg[i++] = r;
					break;
				}
			}
			for (; i<nr; i++)
				for (r=1; r<=NIReg; r++)
					if (!(rm & (1ull<<r))) {
						rm |= (1ull<<r);
						reg[i] = r;
						break;
					}
		}
	Nxt:	freeall();
	}
	printf("%llu tests successful!\n", cnt);
	exit(0);
}
Example #4
0
File: live.c Project: 8l/qbe
/* liveness analysis
 * requires rpo computation
 */
void
filllive(Fn *f)
{
	Blk *b;
	Ins *i;
	int k, t, m[2], n, chg, nlv[2];
	BSet u[1], v[1];
	Mem *ma;

	bsinit(u, f->ntmp);
	bsinit(v, f->ntmp);
	for (b=f->start; b; b=b->link) {
		bsinit(b->in, f->ntmp);
		bsinit(b->out, f->ntmp);
		bsinit(b->gen, f->ntmp);
	}
	chg = 1;
Again:
	for (n=f->nblk-1; n>=0; n--) {
		b = f->rpo[n];

		bscopy(u, b->out);
		if (b->s1) {
			liveon(v, b, b->s1);
			bsunion(b->out, v);
		}
		if (b->s2) {
			liveon(v, b, b->s2);
			bsunion(b->out, v);
		}
		chg |= !bsequal(b->out, u);

		memset(nlv, 0, sizeof nlv);
		b->out->t[0] |= T.rglob;
		bscopy(b->in, b->out);
		for (t=0; bsiter(b->in, &t); t++)
			nlv[KBASE(f->tmp[t].cls)]++;
		if (rtype(b->jmp.arg) == RCall) {
			assert((int)bscount(b->in) == T.nrglob &&
				nlv[0] == T.nrglob &&
				nlv[1] == 0);
			b->in->t[0] |= T.retregs(b->jmp.arg, nlv);
		} else
			bset(b->jmp.arg, b, nlv, f->tmp);
		for (k=0; k<2; k++)
			b->nlive[k] = nlv[k];
		for (i=&b->ins[b->nins]; i!=b->ins;) {
			if ((--i)->op == Ocall && rtype(i->arg[1]) == RCall) {
				b->in->t[0] &= ~T.retregs(i->arg[1], m);
				for (k=0; k<2; k++) {
					nlv[k] -= m[k];
					/* caller-save registers are used
					 * by the callee, in that sense,
					 * right in the middle of the call,
					 * they are live: */
					nlv[k] += T.nrsave[k];
					if (nlv[k] > b->nlive[k])
						b->nlive[k] = nlv[k];
				}
				b->in->t[0] |= T.argregs(i->arg[1], m);
				for (k=0; k<2; k++) {
					nlv[k] -= T.nrsave[k];
					nlv[k] += m[k];
				}
			}
			if (!req(i->to, R)) {
				assert(rtype(i->to) == RTmp);
				t = i->to.val;
				if (bshas(b->in, i->to.val))
					nlv[KBASE(f->tmp[t].cls)]--;
				bsset(b->gen, t);
				bsclr(b->in, t);
			}
			for (k=0; k<2; k++)
				switch (rtype(i->arg[k])) {
				case RMem:
					ma = &f->mem[i->arg[k].val];
					bset(ma->base, b, nlv, f->tmp);
					bset(ma->index, b, nlv, f->tmp);
					break;
				default:
					bset(i->arg[k], b, nlv, f->tmp);
					break;
				}
			for (k=0; k<2; k++)
				if (nlv[k] > b->nlive[k])
					b->nlive[k] = nlv[k];
		}
	}
	if (chg) {
		chg = 0;
		goto Again;
	}

	if (debug['L']) {
		fprintf(stderr, "\n> Liveness analysis:\n");
		for (b=f->start; b; b=b->link) {
			fprintf(stderr, "\t%-10sin:   ", b->name);
			dumpts(b->in, f->tmp, stderr);
			fprintf(stderr, "\t          out:  ");
			dumpts(b->out, f->tmp, stderr);
			fprintf(stderr, "\t          gen:  ");
			dumpts(b->gen, f->tmp, stderr);
			fprintf(stderr, "\t          live: ");
			fprintf(stderr, "%d %d\n", b->nlive[0], b->nlive[1]);
		}
	}
}