Charles.Forsyth20060303644188019 years agoHistory
842 lines · 12.5 KB · C
RawDownload
#include "gc.h" voidcodgen(Node *n, Node *nn){	Prog *sp;	Node *n1, nod, nod1; 	cursafe = 0;	curarg = 0;	maxargsafe = 0; 	/*	 * isolate name	 */	for(n1 = nn;; n1 = n1->left) {		if(n1 == Z) {			diag(nn, "cant find function name");			return;		}		if(n1->op == ONAME)			break;	}	nearln = nn->lineno;	gpseudo(ATEXT, n1->sym, nodconst(stkoff)); 	/*	 * isolate first argument	 */	if(REGARG) {		if(typesuv[thisfn->link->etype]) {			nod1 = *nodret->left;			nodreg(&nod, &nod1, REGARG);			gmove(&nod, &nod1);		} else		if(firstarg && typechlp[firstargtype->etype]) {			nod1 = *nodret->left;			nod1.sym = firstarg;			nod1.type = firstargtype;			nod1.xoffset = align(0, firstargtype, Aarg1);			nod1.etype = firstargtype->etype;			nodreg(&nod, &nod1, REGARG);			gmove(&nod, &nod1);		}	} 	sp = p;	retok = 0;	gen(n);	if(!retok)		if(thisfn->link->etype != TVOID)			warn(Z, "no return at end of function: %s", n1->sym->name);	noretval(3);	if(thisfn && thisfn->link && typefd[thisfn->link->etype])		gins(AFLDZ, Z, Z);	gbranch(ORETURN); 	if(!debug['N'] || debug['R'] || debug['P'])		regopt(sp);	sp->to.offset += maxargsafe;} voidsupgen(Node *n){	long spc;	Prog *sp; 	if(n == Z)		return;	suppress++;	spc = pc;	sp = lastp;	gen(n);	lastp = sp;	pc = spc;	sp->link = nil;	suppress--;} voidgen(Node *n){	Node *l, nod;	Prog *sp, *spc, *spb;	Case *cn;	long sbc, scc;	int f, o; loop:	if(n == Z)		return;	nearln = n->lineno;	o = n->op;	if(debug['G'])		if(o != OLIST)			print("%L %O\n", nearln, o); 	retok = 0;	switch(o) { 	default:		complex(n);		cgen(n, Z);		break; 	case OLIST:		gen(n->left); 	rloop:		n = n->right;		goto loop; 	case ORETURN:		retok = 1;		complex(n);		if(n->type == T)			break;		l = n->left;		if(l == Z) {			noretval(3);			if(typefd[n->type->etype])				gins(AFLDZ, Z, Z);			gbranch(ORETURN);			break;		}		if(typesuv[n->type->etype]) {			sugen(l, nodret, n->type->width);			noretval(3);			gbranch(ORETURN);			break;		}		regret(&nod, n);		cgen(l, &nod);		regfree(&nod);		if(typefd[n->type->etype])			noretval(1);		else			noretval(2);		gbranch(ORETURN);		break; 	case OLABEL:		l = n->left;		if(l) {			l->xoffset = pc;			if(l->label)				patch(l->label, pc);		}		gbranch(OGOTO);	/* prevent self reference in reg */		patch(p, pc);		goto rloop; 	case OGOTO:		retok = 1;		n = n->left;		if(n == Z)			return;		if(n->complex == 0) {			diag(Z, "label undefined: %s", n->sym->name);			return;		}		if(suppress)			return;		gbranch(OGOTO);		if(n->xoffset) {			patch(p, n->xoffset);			return;		}		if(n->label)			patch(n->label, pc-1);		n->label = p;		return; 	case OCASE:		l = n->left;		if(cases == C)			diag(n, "case/default outside a switch");		if(l == Z) {			cas();			cases->val = 0;			cases->def = 1;			cases->label = pc;			goto rloop;		}		complex(l);		if(l->type == T)			goto rloop;		if(l->op == OCONST)		if(typechl[l->type->etype]) {			cas();			cases->val = l->vconst;			cases->def = 0;			cases->label = pc;			goto rloop;		}		diag(n, "case expression must be integer constant");		goto rloop; 	case OSWITCH:		l = n->left;		complex(l);		if(l->type == T)			break;		if(!typechl[l->type->etype]) {			diag(n, "switch expression must be integer");			break;		} 		gbranch(OGOTO);		/* entry */		sp = p; 		cn = cases;		cases = C;		cas(); 		sbc = breakpc;		breakpc = pc;		gbranch(OGOTO);		spb = p; 		gen(n->right);		gbranch(OGOTO);		patch(p, breakpc); 		patch(sp, pc);		regalloc(&nod, l, Z);		nod.type = types[TLONG];		cgen(l, &nod);		doswit(&nod);		regfree(&nod);		patch(spb, pc); 		cases = cn;		breakpc = sbc;		break; 	case OWHILE:	case ODWHILE:		l = n->left;		gbranch(OGOTO);		/* entry */		sp = p; 		scc = continpc;		continpc = pc;		gbranch(OGOTO);		spc = p; 		sbc = breakpc;		breakpc = pc;		gbranch(OGOTO);		spb = p; 		patch(spc, pc);		if(n->op == OWHILE)			patch(sp, pc);		bcomplex(l, Z);		/* test */		patch(p, breakpc); 		if(n->op == ODWHILE)			patch(sp, pc);		gen(n->right);		/* body */		gbranch(OGOTO);		patch(p, continpc); 		patch(spb, pc);		continpc = scc;		breakpc = sbc;		break; 	case OFOR:		l = n->left;		gen(l->right->left);	/* init */		gbranch(OGOTO);		/* entry */		sp = p; 		scc = continpc;		continpc = pc;		gbranch(OGOTO);		spc = p; 		sbc = breakpc;		breakpc = pc;		gbranch(OGOTO);		spb = p; 		patch(spc, pc);		gen(l->right->right);	/* inc */		patch(sp, pc);			if(l->left != Z) {	/* test */			bcomplex(l->left, Z);			patch(p, breakpc);		}		gen(n->right);		/* body */		gbranch(OGOTO);		patch(p, continpc); 		patch(spb, pc);		continpc = scc;		breakpc = sbc;		break; 	case OCONTINUE:		if(continpc < 0) {			diag(n, "continue not in a loop");			break;		}		gbranch(OGOTO);		patch(p, continpc);		break; 	case OBREAK:		if(breakpc < 0) {			diag(n, "break not in a loop");			break;		}		gbranch(OGOTO);		patch(p, breakpc);		break; 	case OIF:		l = n->left;		if(bcomplex(l, n->right)) {			if(typefd[l->type->etype])				f = !l->fconst;			else				f = !l->vconst;			if(debug['c'])				print("%L const if %s\n", nearln, f ? "false" : "true");			if(f) {				supgen(n->right->left);				gen(n->right->right);			}			else {				gen(n->right->left);				supgen(n->right->right);			}		}		else {			sp = p;			if(n->right->left != Z)				gen(n->right->left);			if(n->right->right != Z) {				gbranch(OGOTO);				patch(sp, pc);				sp = p;				gen(n->right->right);			}			patch(sp, pc);		}		break; 	case OSET:	case OUSED:		usedset(n->left, o);		break;	}} voidusedset(Node *n, int o){	if(n->op == OLIST) {		usedset(n->left, o);		usedset(n->right, o);		return;	}	complex(n);	switch(n->op) {	case OADDR:	/* volatile */		gins(ANOP, n, Z);		break;	case ONAME:		if(o == OSET)			gins(ANOP, Z, n);		else			gins(ANOP, n, Z);		break;	}} voidnoretval(int n){ 	if(n & 1) {		gins(ANOP, Z, Z);		p->to.type = REGRET;	}	if(n & 2) {		gins(ANOP, Z, Z);		p->to.type = FREGRET;	}} /* welcome to commute */static voidcommute(Node *n){	Node *l, *r; 	l = n->left;	r = n->right;	if(r->complex > l->complex) {		n->left = r;		n->right = l;	}} voidindexshift(Node *n){	int g; 	if(!typechlp[n->type->etype])		return;	simplifyshift(n);	if(n->op == OASHL && n->right->op == OCONST){		g = vconst(n->right);		if(g >= 0 && g < 4)			n->addable = 7;	}} /* *	calculate addressability as follows *		NAME ==> 10/11		name+value(SB/SP) *		REGISTER ==> 12		register *		CONST ==> 20		$value *		*(20) ==> 21		value *		&(10) ==> 13		$name+value(SB) *		&(11) ==> 1		$name+value(SP) *		(13) + (20) ==> 13	fold constants *		(1) + (20) ==> 1	fold constants *		*(13) ==> 10		back to name *		*(1) ==> 11		back to name * *		(20) * (X) ==> 7	multiplier in indexing *		(X,7) + (13,1) ==> 8	adder in indexing (addresses) *		(8) ==> &9(OINDEX)	index, almost addressable * *	calculate complexity (number of registers) */voidxcom(Node *n){	Node *l, *r;	int g; 	if(n == Z)		return;	l = n->left;	r = n->right;	n->complex = 0;	n->addable = 0;	switch(n->op) {	case OCONST:		n->addable = 20;		break; 	case ONAME:		n->addable = 10;		if(n->class == CPARAM || n->class == CAUTO)			n->addable = 11;		break; 	case OREGISTER:		n->addable = 12;		break; 	case OINDREG:		n->addable = 12;		break; 	case OADDR:		xcom(l);		if(l->addable == 10)			n->addable = 13;		else		if(l->addable == 11)			n->addable = 1;		break; 	case OADD:		xcom(l);		xcom(r);		if(n->type->etype != TIND)			break; 		switch(r->addable) {		case 20:			switch(l->addable) {			case 1:			case 13:			commadd:				l->type = n->type;				*n = *l;				l = new(0, Z, Z);				*l = *(n->left);				l->xoffset += r->vconst;

Lines 1–500 of 842.