File:  [Plan 9 NeXT] / lucent / sys / src / alef / k / sugen.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:01:04 2018 UTC (8 years, 1 month ago) by root
Branches: lucent, MAIN
CVS tags: plan9, HEAD
Plan 9 NeXT

#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#define Extern extern
#include "parl.h"
#include "globl.h"

static Glab *gotos;
static Glab *labels;
static Jmps *contstack;
static Jmps *brkstack;
static Jmps *retstack;
static Jmps *rescues;
static Node *lstmnt;

/* Compile a function */
void
fungen(Node *code, Node *args)
{
	int l;
	Type *t;
	Node n1;
	ulong rpc;
	Inst *fcode;

	l = line;
	fcode = ipc;

	iter(code, 1);
	typechk(code, 0);
	rewrite(code);

	args->left->right = code;

	if(code)
		sucalc(code);

	if(opt('t')) {
		print("\nTree:\n");
		ptree(code, 0);
	}

	/* Clear the label stack */
	labels = 0;
	gotos = 0;
	rescues = 0;

	if(opt('q') == 0 && nerr == 0) {
		t = curfunc->t->next;
		switch(t->type) {
		case TPOLY:
			curfunc = dupn(curfunc);
			curfunc->t = at(TFUNC, polyshape);
			/* No Break */
		case TADT:
		case TUNION:
		case TAGGREGATE:
			t = at(TIND, t);
			regret(&n1, t);
			rnode = stknode(n1.t);
			assign(&n1, rnode);
			regfree(&n1);
			becomentry = ipc;
		}

		lstmnt = nil;
		if(code)
			stmnt(code);

		if(t->type != TVOID)
		if(lstmnt == 0 ||
		  (lstmnt->type != ORET && lstmnt->type != OBECOME))
			diag(lstmnt, "typed function has no return");

		rpc = ipc->pc+1;
		/* Improve optimiser by using non return register */
		switch(t->type) {
		case TVOID:
			instruction(ANOP, ZeroN, ZeroN, regn(Freg));
			instruction(ANOP, ZeroN, ZeroN, regn(Retireg));
			break;
		case TFLOAT:
			instruction(ANOP, ZeroN, ZeroN, regn(Retireg));
			break;
		default:
			instruction(ANOP, ZeroN, ZeroN, regn(Freg));
			break;
		}

		instruction(ARETURN, ZeroN, ZeroN, ZeroN);

		/* Patch in all the returns */
		while(retstack) {
			label(retstack->i, rpc);
			popjmp(&retstack);
		}

		/* Back patch the entry */
		resolvegoto();

		/* Patch in the frame size */
		funentry->dst.ival = maxframe + frame;
	}

	leaveblock();

	regcheck();

	if(opt('N') || opt('R') || opt('P'))
		regopt(fcode);

	line = l;
}

void
bstmnt(Node *n)
{
	Node *tmp;

	tmp = lstmnt;
	stmnt(n);
	lstmnt = tmp;
}

/* Compile code for a statement */
void
stmnt(Node *n)
{
	Jmps *p;
	Node *l, *r, n1, com;
	Inst *false, *truedone, *loop, *enter;

	if(n == ZeroN)
		return;

	l = n->left;
	r = n->right;
	iline = n->srcline;
	lstmnt = n;

	switch(n->type) {
	default:
		genexp(n, ZeroN);
		break;

	case OLIST:
		stmnt(l);
		stmnt(r);
		break;

	case OBLOCK:
		stmnt(l);
		break;

	case OLBLOCK:
		if(l == ZeroN) {
			warn(n, "empty guarded block");
			break;
		}
		lblock(l);
		break;

	case OPAR:
		parcode(l->left);
		break;

	case OSWITCH:
		switchcode(n);
		break;

	case OSELECT:
		selcode(n);
		break;

	case OGOTO:
		instruction(AJMP, ZeroN, ZeroN, ZeroN);
		setgoto(n, ipc);
		break;

	case OLABEL:
		setlabel(n, ipc->pc+1);
		break;

	case OCASE:
	case ODEFAULT:
		n->pc = ipc->pc+1;

		if(l && l->type != OCONST)
			stmnt(l);

		if(r)
			stmnt(r);
		break;

	case OIF:
		gencond(l, ZeroN, True);
		false = ipc;
		if(r && r->type == OELSE) {
			stmnt(r->left);
			truedone = instruction(AJMP, ZeroN, ZeroN, ZeroN);
			label(false, ipc->pc+1);
			stmnt(r->right);
			label(truedone, ipc->pc+1);
			break;
		}

		if(r)
			stmnt(r);

		label(false, ipc->pc+1);
		break;

	case ORET:
		if(l) {
			switch(l->t->type) {
			default:
				regret(&n1, l->t);
				genexp(l, &n1);
				regfree(&n1);
				break;

			case TADT:
			case TUNION:
			case TAGGREGATE:
				com.type = OASGN;
				com.t = l->t;
				com.left = an(OIND, rnode, ZeroN);
				com.left->t = rnode->t->next;
				com.right = l;
				sucalc(&com);
				genexp(&com, ZeroN);
				break;
			}
		}

		instruction(AJMP, ZeroN, ZeroN, ZeroN);
		pushjmp(&retstack);
		break;

	case ODWHILE:
		instruction(AJMP, ZeroN, ZeroN, ZeroN);
		enter = ipc;
		instruction(AJMP, ZeroN, ZeroN, ZeroN);	/* Continue */
		pushjmp(&contstack);
		instruction(AJMP, ZeroN, ZeroN, ZeroN); /* Break */
		pushjmp(&brkstack);

		label(enter, ipc->pc+1);
		loop = ipc;
		if(r)
			stmnt(r);

		label(contstack->i, ipc->pc+1);
		if(l) {
			gencond(l, ZeroN, True);
			label(ipc, brkstack->i->pc);
		}
		instruction(AJMP, ZeroN, ZeroN, ZeroN); /* Loop */
		label(ipc, loop->pc+1);

		label(brkstack->i, ipc->pc+1);
		popjmp(&contstack);
		popjmp(&brkstack);
		break;

	case OWHILE:
		instruction(AJMP, ZeroN, ZeroN, ZeroN);	/* Continue */
		pushjmp(&contstack);
		instruction(AJMP, ZeroN, ZeroN, ZeroN); /* Break */
		pushjmp(&brkstack);

		label(contstack->i, ipc->pc+1);
		loop = ipc;
		if(l) {					/* Cond */
			gencond(l, ZeroN, True);
			label(ipc, brkstack->i->pc);
		}
		
		if(r)
			stmnt(r);

		instruction(AJMP, ZeroN, ZeroN, ZeroN);	/* Loop */
		label(ipc, loop->pc+1);

		label(brkstack->i, ipc->pc+1);
		popjmp(&contstack);
		popjmp(&brkstack);
		break;

	case OFOR:
		if(l->left)				/* Assign */
			genexp(l->left, ZeroN);

		l = l->right;

		instruction(AJMP, ZeroN, ZeroN, ZeroN);
		enter = ipc;
		instruction(AJMP, ZeroN, ZeroN, ZeroN);	/* Continue */
		pushjmp(&contstack);
		instruction(AJMP, ZeroN, ZeroN, ZeroN); /* Break */
		pushjmp(&brkstack);
		label(enter, ipc->pc+1);

		if(l->left) {				/* Cond */
			gencond(l->left, ZeroN, True);
			label(ipc, brkstack->i->pc);
		}
		if(r)
			stmnt(r);
		label(contstack->i, ipc->pc+1);
		if(l->right)				/* Action */
			genexp(l->right, ZeroN);

		instruction(AJMP, ZeroN, ZeroN, ZeroN);
		label(ipc, enter->pc);

		label(brkstack->i, ipc->pc+1);
		popjmp(&contstack);
		popjmp(&brkstack);
		break;

	case ORAISE:
		if(l) {
			instruction(AJMP, ZeroN, ZeroN, ZeroN);
			setgoto(l, ipc);
			break;
		}
		if(rescues == 0) {
			diag(n, "raise without rescue");
			break;
		}
		instruction(AJMP, ZeroN, ZeroN, ZeroN);
		label(ipc, rescues->i->pc+1);
		if(rescues->par != inpar)
			diag(n, "raise breaks join in par");
		if(rescues->crit != incrit)
			diag(n, "raise breaks critical section");
		break;

	case ORESCUE:
		instruction(AJMP, ZeroN, ZeroN, ZeroN);
		enter = ipc;
		if(l->type == OLABEL) {
			setlabel(l, ipc->pc+1);
			l = l->left;
		}
		stmnt(l);
		label(enter, ipc->pc+1);
		pushlab(&rescues, enter);
		break;

	case OBREAK:
		p = brkstack;
		while(p) {
			n->ival--;
			if(n->ival == 0)
				break;
			p = p->next;
		}
		if(p) {
			if(p->par != inpar)
				diag(n, "break breaks join in par");
			if(p->crit != incrit)
				diag(n, "break breaks critical section");
			instruction(AJMP, ZeroN, ZeroN, ZeroN);
			label(ipc, p->i->pc);
			break;
		}
		diag(n, "break not in loop/switch/select");
		break;

	case OCONT:
		p = contstack;
		while(p) {
			n->ival--;
			if(n->ival == 0)
				break;
			p = p->next;
		}
		if(p) {
			if(p->par != inpar)
				diag(n, "continue breaks join in par");
			if(p->crit != incrit)
				diag(n, "continue breaks critical section");
			instruction(AJMP, ZeroN, ZeroN, ZeroN);
			label(ipc, p->i->pc);
			break;
		}
		diag(n, "continue not in loop");
		break;
	}
}

int
cascmp(Node **a, Node **b)
{
	int av, bv;

	av = (*a)->left->ival;
	bv = (*b)->left->ival;
	if(av < bv)
		return -1;
	return  av > bv;
}

void
casecount(Node *n, Node **vec)
{
	if(n == ZeroN)
		return;

	switch(n->type) {
	case ODEFAULT:
	case OCASE:
		if(vec)
			vec[veccnt] = n;
		veccnt++;	
		break;

	default:
		casecount(n->left, vec);
		casecount(n->right, vec);
		break;
	}
}

void
switchcode(Node *n)
{
	Node val;
	long defpc;
	Inst *enter;
	int i, r, safe;
	Node **cases, *defl, *c, *il, com;

	c = n->right;
	if(c == ZeroN) {
		warn(n, "empty switch statement");
		return;
	}

	instruction(AJMP, ZeroN, ZeroN, ZeroN);		/* Entry */
	enter = ipc;
	instruction(AJMP, ZeroN, ZeroN, ZeroN); 	/* Break */
	pushjmp(&brkstack);

	safe = 0;
	if(c->type == OLBLOCK) {
		incrit++;
		safe = 1;
		c = c->left;
	}
	/* Generate the code */
	stmnt(c);

	instruction(AJMP, ZeroN, ZeroN, ZeroN); 	/* Done break */
	label(ipc, brkstack->i->pc);

	/* Count */
	veccnt = 0;
	casecount(c, 0);

	/* Save */
	cases = malloc(sizeof(Node*)*veccnt);
	veccnt = 0;
	casecount(c, cases);

	defl = 0;
	for(i = 0; i < veccnt; i++) {
		c = cases[i];
		switch(c->type) {
		case OCASE:
			if(c->left->type != OCONST) {
				diag(c, "case must be constant");
				cases[i] = ZeroN;
			}
			break;

		case ODEFAULT:
			if(defl)
				diag(c, "switch already has default");
			defl = c;
			cases[i] = ZeroN;
			break;
		}
	}

	/* Close up the table */
	for(i = 0; i < veccnt; i++) {
		if(cases[i] == ZeroN) {
			veccnt--;
			memmove(cases+i, cases+i+1,  (veccnt-i)*sizeof(Node*));
		}
	}

	qsort(cases, veccnt, sizeof(Node*), cascmp);

	for(i = 0; i < veccnt-1; i++) {
		r = cases[i]->left->ival;
		if(r == cases[i+1]->left->ival)
			diag(cases[i+1], "duplicate case %d in switch", r);
	}

	label(enter, ipc->pc+1);
	SET(il);
	if(safe) {
		il = internnode(builtype[TIND]);
		il = an(OADDR, il, ZeroN);
		il->t = builtype[TIND];

		com.type = OCALL;
		com.t = builtype[TVOID];
		com.left = ginode;
		com.right = il;

		sucalc(&com);
		stmnt(&com);
	}

	reg(&val, builtype[TINT], ZeroN);
	genexp(n->left, &val);

	defpc = brkstack->i->pc;
	if(defl)
		defpc = defl->pc;
 
	gencmps(cases, veccnt, defpc, &val);

	regfree(&val);
	label(brkstack->i, ipc->pc+1);

	if(safe) {
		com.type = OCALL;
		com.t = builtype[TVOID];
		com.left = gonode;
		com.right = il;

		sucalc(&com);
		stmnt(&com);
		incrit--;
	}
	popjmp(&brkstack);
}

Node*
gcom(Node *n)
{
	Node *l;

	if(n == 0)
		return ZeroN;

	switch(n->type) {
	case ORECV:
		return n;
	case OCALL:
		if(issend(n->left))
			return n;
		/* Fall through */
	default:
		l = gcom(n->left);
		if(l == 0)
			l = gcom(n->right);
		return l;
	}
}

int
regcode(Node **cases, int cnt)
{
	int i, var;
	Node *l, *c;

	var = 0;
	for(i = 0; i < cnt; i++) {
		c = cases[i];
		switch(c->type) {
		case OCASE:
			l = gcom(c->left);
			if(l == 0) {
				diag(c, "case expr needs send/receive");
				cases[i] = ZeroN;
				break;
			}
			if(l->t->variant)
				var++;
			switch(l->type) {
			default:		/* Catch the send rewrites */
				l->left = selsend;
				c->t = l->t;
				l->t = builtype[TVOID];
				break;
			case ORECV:
			case OCRCV:
				c->left = l;
				l->type = OCALL;
				c->t = l->t;
				l->t = builtype[TVOID];
				l->left = selrecv;
				break;
			}
			/* Only the channel argument */
			while(l->right->type == OLIST)
				l->right = l->right->left;
			break;
		case ODEFAULT:
			diag(c, "alt already has default");
			cases[i] = ZeroN;
			break;
		}
	}
	return var;
}

void
selcode(Node *n)
{
	Inst *enter;
	Node val, com;
	int i, x, safe, var;
	Node **cases, *c, *il;

	safe = 0;

	val.srcline = n->srcline;
	com.srcline = n->srcline;

	instruction(AJMP, ZeroN, ZeroN, ZeroN);		/* Entry */
	enter = ipc;
	instruction(AJMP, ZeroN, ZeroN, ZeroN); 	/* Break */
	pushjmp(&brkstack);

	c = n->left;
	if(c == nil)
		return;
	if(c->type == OLBLOCK) {
		incrit++;
		safe = 1;
		c = c->left;
	}
	stmnt(c);

	instruction(AJMP, ZeroN, ZeroN, ZeroN); 	/* Done break */
	label(ipc, brkstack->i->pc);

	veccnt = 0;
	casecount(n->left, 0);
	cases = malloc(sizeof(Node*)*veccnt);
	veccnt = 0;
	casecount(n->left, cases);

	/* Convert expression to register channels for select */
	var = regcode(cases, veccnt);

	for(i = 0; i < veccnt; i++) {
		if(cases[i] == ZeroN) {
			veccnt--;
			memmove(cases+i, cases+i+1,  (veccnt-i)*sizeof(Node*));
		}
	}
	if(veccnt == 0)
		return;

	label(enter, ipc->pc+1);
	SET(il);
	if(safe) {
		il = internnode(builtype[TIND]);
		il = an(OADDR, il, ZeroN);
		il->t = builtype[TIND];

		com.type = OCALL;
		com.t = builtype[TVOID];
		com.left = ginode;
		com.right = il;

		sucalc(&com);
		stmnt(&com);
	}

	/* Assign values */
	for(i = 0; i < veccnt; i++) {
		c = cases[i];
		x = i;
		if(var)
			x = typesig(c->t);
		c->left->ival = x;
	}

	/* Sort if type match */
	if(var)
		qsort(cases, veccnt, sizeof(Node*), cascmp);

	/* Detect type clashes */
	for(i = 0; i < veccnt-1; i++) {
		c = cases[i];
		if(c->left->ival == cases[i+1]->left->ival)
			diag(c, "duplicate variant type %V", c->t);
	}

	/* Code the selsend/selrecv expressions */
	for(i = 0; i < veccnt; i++)
		genexp(cases[i]->left, ZeroN);

	com.type = OCALL;
	com.t = builtype[TVOID];
	com.left = doselect;
	if(var)
		com.left = varselect;
	com.right = ZeroN;
	sucalc(&com);
	stmnt(&com);

	regret(&val, builtype[TINT]);
	gencmps(cases, veccnt, -1, &val);
	regfree(&val);

	label(brkstack->i, ipc->pc+1);
	if(safe) {
		com.type = OCALL;
		com.t = builtype[TVOID];
		com.left = gonode;
		com.right = il;
		sucalc(&com);
		stmnt(&com);
		incrit--;
	}
	popjmp(&brkstack);
}

void
gencmps(Node **c, int cnt, long defpc, Node *val)
{
	Node n, con, **r;
	int i;
	Inst *patch;

	con.type = OCONST;
	con.t = builtype[TINT];

	if(cnt < 4) {
		for(i = 0; i < cnt; i++) {
			con.ival = (*c)->left->ival;
			reg(&n, builtype[TINT], ZeroN);
			assign(&con, &n);
			codcond(OEQ, &n, val);
			label(ipc, (*c)->pc);
			regfree(&n);
			c++;
		}
		if(defpc != -1) {
			instruction(AJMP, ZeroN, ZeroN, ZeroN);
			label(ipc, defpc);
		}
		return;
	}
	i = cnt/2;
	r = c+i;

	con.ival = (*r)->left->ival;
	reg(&n, builtype[TINT], ZeroN);
	assign(&con, &n);
	codcond(OLT, &n, val);
	patch = ipc;
	codcond(OEQ, &n, val);
	label(ipc, (*r)->pc);
	regfree(&n);
	gencmps(c, i, defpc, val);

	label(patch, ipc->pc+1);
	gencmps(r+1, cnt-i-1, defpc, val);
}

ulong
framefind(Node *n)
{
	ulong l, r;

	if(n == ZeroN)
		return 0;

	switch(n->type) {
	default:
		l = framefind(n->left);
		r = framefind(n->right);
		if(r > l)
			l = r;
		break;
	case OCALL:
		frsize = 0;
		framesize(n->right);
		l = frsize;
	}
	return l;
}

void
parcode(Node *n)
{
	Type *t;
	ulong frs;
	int i, cnt;
	Inst *loop;
	Node *barrier, **slist, com, retr;
	Node *stv, *stvp, *oatv, *p;

	veccnt = 0;
	listcount(n, 0);
	slist = malloc(sizeof(Node*)*veccnt);
	veccnt = 0;
	listcount(n, slist);

	if(opt('O')) {
		for(i = 0; i < veccnt; i++) {
			ptree(slist[i], 0);
			print("*\n");
		}
	}

	if(veccnt < 2) {
		warn(n, "only one statement in par");
		stmnt(slist[0]);
		return;
	}

	inpar++;
	oatv = atv;
	cnt = veccnt;

	/*
	 * This slime is Parrend in the runtime
	 */
	t = at(TAGGREGATE, 0);
	t->size = SZPAREND*builtype[TINT]->size;
	barrier = an(OADDR, stknode(t), ZeroN);
	barrier->t = at(TIND, t);

	/*
	 * Build activation vector
	 */
	t = at(TIND, builtype[TIND]);
	t->size = t->next->size * cnt;	
	stv = stknode(t);
	stv->ti->t = at(TARRAY, 0);

	/*
	 * craft: pid = pfork(cnt, stv)
	 */
	com.type = OCALL;
	com.t = builtype[TINT];
	com.left = pforknode;
	stvp = an(OADDR, stv, ZeroN);
	stvp->t = builtype[TIND];
	com.right = an(OLIST, con(veccnt-1), an(OLIST, stvp, barrier));

	sucalc(&com);
	genexp(&com, ZeroN);

	for(i = 0; i < cnt-1; i++) {
		regret(&retr, builtype[TINT]);
		instruction(ACMP, con(i), ZeroN, &retr);
		instruction(ABNE, ZeroN, ZeroN, ZeroN);
		loop = ipc;
		regfree(&retr);

		/*
		 * find the largest frame in this activation
		 */
		frs = framefind(slist[i]);
		/* ensure enough space for ALEF_pexit args */
		if(frs < 2*builtype[TIND]->size) {
			frs = 2*builtype[TIND]->size;
			frs = align(frs, builtype[TIND]);
		}
		if(opt('O'))
			print("%d: frame %d\n", i, frs);

		/*
		 * Compute my activation from stack vector: atv = stv[pid]
		 */
		t = builtype[TIND];
		atv = stknode(t);
		p = an(OADD, stvp, con(i*builtype[TIND]->size));
		p->t = t;
		p = an(OIND, p, ZeroN);
		p->t = t;
		/*
		 * 2*sizeof(*) is enough for save SP at activation top plus hole
		 * for the saved activation pc
		 */
		p = an(OSUB, p, con(frs+2*builtype[TIND]->size));
		p->t = t;
		/*
		 * word used for activation link
		 */
		atv->atvsafe = frs+builtype[TIND]->size;
		p = an(OASGN, atv, p);
		p->t = t;

		sucalc(p);
		genexp(p, ZeroN);

		stmnt(slist[i]);

		com.type = OCALL;
		com.t = builtype[TVOID];
		com.left = pexitnode;
		com.right = barrier;

		sucalc(&com);
		stmnt(&com);

		label(loop, ipc->pc+1);
	}
	atv = oatv;

	stmnt(slist[i]);

	/*
	 * craft terminator: ALEF_pdone(&barrier, stv);
	 */
	com.type = OCALL;
	com.t = builtype[TINT];
	com.left = pdonenode;
	stvp = an(OADDR, stv, ZeroN);
	stvp->t = builtype[TIND];
	com.right = an(OLIST, barrier, stvp);

	sucalc(&com);
	stmnt(&com);

	inpar--;
}

void
lblock(Node *n)
{
	Node com, *i;

	i = internnode(builtype[TIND]);
	i = an(OADDR, i, ZeroN);
	i->t = builtype[TIND];

	com.type = OCALL;
	com.t = builtype[TVOID];
	com.left = ginode;
	com.right = i;
	sucalc(&com);
	stmnt(&com);

	incrit++;
	stmnt(n);
	incrit--;

	com.type = OCALL;
	com.t = builtype[TVOID];
	com.left = gonode;
	com.right = i;
	sucalc(&com);
	stmnt(&com);
}

/* determine addressablility and number of registers */
void
sucalc(Node *n)
{
	Node *l, *r;

	if(n == 0)
		return;

	l = n->left;
	r = n->right;
	n->sun = 0;
	n->islval = 0;

	/* Addressability */
	switch(n->type) {
	case OBECOME:
		sucalc(l);
		if(l->type == OCALL)
			n->right = paramdep(l->right);
		return;

	case OCONST:
		n->islval = 20;
		return;

	case OREGISTER:
		n->islval = 11;
		return;

	case OINDREG:
		n->islval = 12;
		return;

	case ONAME:
		n->islval = 10;
		return;

	case OADDR:
		sucalc(l);
		if(l->islval == 10)
			n->islval = 2;
		if(l->islval == 12)
			n->islval = 3;
		break;

	case OIND:
		sucalc(l);
		if(l->islval == 11)
			n->islval = 12;
		if(l->islval == 3)
			n->islval = 12;
		if(l->islval == 2)
			n->islval = 10;
		break;

	case OADD:
		sucalc(l);
		sucalc(r);
		if(l->islval == 20) {
			if(r->islval == 2)
				n->islval = 2;
			if(r->islval == 3)
				n->islval = 3;
		}
		if(r->islval == 20) {
			if(l->islval == 2)
				n->islval = 2;
			if(l->islval == 3)
				n->islval = 3;
		}
		break;

	default:
		sucalc(l);
		sucalc(r);
		break;
	}

	/* Number of registers */
	switch(n->type) {
	default:
		if(l != ZeroN)
			n->sun = l->sun;
		if(r != ZeroN) {
			if(n->sun == r->sun)
				n->sun = n->sun + 1;
			else if(r->sun > n->sun)
				n->sun = r->sun;
		}
		if(n->sun == 0)
			n->sun = 1;
		break;

	case OCALL:
	case OSEND:
	case ORECV:
		n->sun = Sucall;
		break;
	}
}

void
setlabel(Node *n, ulong pc)
{
	Glab *i;

	for(i = labels; i; i = i->next) {
		if(i->n->sym == n->sym) {
			diag(n, "label %s used twice", n->sym->name);
			return;
		}
	}
	i = malloc(sizeof(Glab));
	i->n = n;
	i->par = inpar;
	i->crit = incrit;
	i->pc = pc;
	i->next = labels;
	labels = i;	
}

void
setgoto(Node *n, Inst *i)
{
	Glab *g;

	g = malloc(sizeof(Glab));
	g->n = n;
	g->i = i;
	g->par = inpar;
	g->crit = incrit;
	g->next = gotos;
	gotos = g;
}

Glab*
findlab(Node *n)
{
	Glab *i;

	for(i = labels; i; i = i->next)
		if(i->n->sym == n->sym)
			return i;

	return 0;
}

void
resolvegoto(void)
{
	Glab *g, *l;

	for(g = gotos; g; g = g->next) {
		l = findlab(g->n);
		if(l == 0) {
			diag(g->n, "no label called %s", g->n->sym->name);
			continue;
		}

		if(g->par != l->par)
			diag(g->n, "raise/goto breaks join from par");
		if(g->crit != l->crit)
			diag(g->n, "raise/goto breaks critical section");

		label(g->i, l->pc);
	}
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.