643 lines · 10.9 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include	"l.h" /* * flag: insert nops to prevent three consecutive stores. * workaround for 24k erratum #48, costs about 10% in text space, * so only enable this if you need it.  test cases are "hoc -e '7^6'" * and "{ echo moon; echo plot } | scat". */enum {	Mips24k	= 0,}; static intisdblwrdmov(Prog *p){	if(p == nil)		return 0;	switch(p->as){	case AMOVD:	case AMOVDF:	case AMOVDW:	case AMOVFD:	case AMOVWD:	case AMOVV:	case AMOVVL:	case AMOVVR:	case AMOVFV:	case AMOVDV:	case AMOVVF:	case AMOVVD:		return 1;	}	return 0;} static intismove(Prog *p){	if(p == nil)		return 0;	switch(p->as){	case AMOVB:	case AMOVBU:	case AMOVF:	case AMOVFW:	case AMOVH:	case AMOVHU:	case AMOVW:	case AMOVWF:	case AMOVWL:	case AMOVWR:	case AMOVWU:		return 1;	}	if(isdblwrdmov(p))		return 1;	return 0;} static intisstore(Prog *p){	if(p == nil)		return 0;	if(ismove(p))		switch(p->to.type) {		case D_OREG:		case D_EXTERN:		case D_STATIC:		case D_AUTO:		case D_PARAM:			return 1;		}	return 0;} static intiscondbranch(Prog *p){	if(p == nil)		return 0;	switch(p->as){	case ABEQ:	case ABFPF:	case ABFPT:	case ABGEZ:	case ABGEZAL:	case ABGTZ:	case ABLEZ:	case ABLTZ:	case ABLTZAL:	case ABNE:		return 1;	}	return 0;} static intisbranch(Prog *p){	if(p == nil)		return 0;	switch(p->as){	case AJAL:	case AJMP:	case ARET:	case ARFE:		return 1;	}	if(iscondbranch(p))		return 1;	return 0;} static voidnopafter(Prog *p){	p->mark |= LABEL|SYNC;	addnop(p);} /* * workaround for 24k erratum #48, costs about 0.5% in space. * inserts a NOP before the last of 3 consecutive stores. * double-word stores complicate things. */static intno3stores(Prog *p){	Prog *p1; 	if(!isstore(p))		return 0;	p1 = p->link;	if(!isstore(p1))		return 0;	if(isdblwrdmov(p) || isdblwrdmov(p1)) {		nopafter(p);		nop.store.count++;		nop.store.outof++;		return 1;	}	if(isstore(p1->link)) {		nopafter(p1);		nop.store.count++;		nop.store.outof++;		return 1;	}	return 0;} /* * keep stores out of branch delay slots. * this is costly in space (the other 9.5%), but makes no3stores effective. * there is undoubtedly a better way to do this. */voidstoresnosched(void){	Prog *p; 	for(p = firstp; p != P; p = p->link)		if(isstore(p))			p->mark |= NOSCHED;} inttriplestorenops(void){	int r;	Prog *p, *p1; 	r = 0;	for(p = firstp; p != P; p = p1) {		p1 = p->link;//		if (p->mark & NOSCHED)//			continue;		if(ismove(p) && isstore(p)) {			if (no3stores(p))				r++;			/*			 * given storenosched, the next two			 * checks shouldn't be necessary.			 */			/*			 * add nop after first MOV in `MOV; Bcond; MOV'.			 */			else if(isbranch(p1) && isstore(p1->link)) {				nopafter(p);				nop.branch.count++;				nop.branch.outof++;				r++;			}			/*			 * this may be a branch target, so insert a nop after,			 * in case a branch leading here has a store in its			 * delay slot and we have consecutive stores here.			 */			if(p->mark & (LABEL|SYNC) && !isnop(p1)) {				nopafter(p);				nop.branch.count++;				nop.branch.outof++;				r++;			}		} else if (isbranch(p))			/*			 * can't ignore delay slot of a conditional branch;			 * the branch could fail and fall through.			 */			if (!iscondbranch(p) && p1)				p1 = p1->link;	/* skip its delay slot */	}	return r;} voidnoops(void){	Prog *p, *p1, *q, *q1;	int o, curframe, curbecome, maxbecome; 	/*	 * find leaf subroutines	 * become sizes	 * frame sizes	 * strip NOPs	 * expand RET	 * expand BECOME pseudo	 */ 	if(debug['v'])		Bprint(&bso, "%5.2f noops\n", cputime());	Bflush(&bso); 	curframe = 0;	curbecome = 0;	maxbecome = 0;	curtext = 0; 	q = P;	for(p = firstp; p != P; p = p->link) { 		/* find out how much arg space is used in this TEXT */		if(p->to.type == D_OREG && p->to.reg == REGSP)			if(p->to.offset > curframe)				curframe = p->to.offset; 		switch(p->as) {		case ATEXT:			if(curtext && curtext->from.sym) {				curtext->from.sym->frame = curframe;				curtext->from.sym->become = curbecome;				if(curbecome > maxbecome)					maxbecome = curbecome;			}			curframe = 0;			curbecome = 0; 			p->mark |= LABEL|LEAF|SYNC;			if(p->link)				p->link->mark |= LABEL;			curtext = p;			break; 		/* too hard, just leave alone */		case AMOVW:			if(p->to.type == D_FCREG ||			   p->to.type == D_MREG) {				p->mark |= LABEL|SYNC;				break;			}			if(p->from.type == D_FCREG ||			   p->from.type == D_MREG) {				p->mark |= LABEL|SYNC;				addnop(p);				addnop(p);				nop.mfrom.count += 2;				nop.mfrom.outof += 2;				break;			}			break; 		/* too hard, just leave alone */		case ACASE:		case ASYSCALL:		case AWORD:		case ATLBWR:		case ATLBWI:		case ATLBP:		case ATLBR:			p->mark |= LABEL|SYNC;			break; 		case ANOR:			if(p->to.type == D_REG && p->to.reg == REGZERO)				p->mark |= LABEL|SYNC;			break; 		case ARET:			/* special form of RET is BECOME */			if(p->from.type == D_CONST)				if(p->from.offset > curbecome)					curbecome = p->from.offset; 			if(p->link != P)				p->link->mark |= LABEL;			break; 		case ANOP:			q1 = p->link;			q->link = q1;		/* q is non-nop */			q1->mark |= p->mark;			continue; 		case ABCASE:			p->mark |= LABEL|SYNC;			goto dstlab; 		case ABGEZAL:		case ABLTZAL:		case AJAL:			if(curtext != P)				curtext->mark &= ~LEAF; 		case AJMP:		case ABEQ:		case ABGEZ:		case ABGTZ:		case ABLEZ:		case ABLTZ:		case ABNE:		case ABFPT:		case ABFPF:			p->mark |= BRANCH; 		dstlab:			q1 = p->cond;			if(q1 != P) {				while(q1->as == ANOP) {					q1 = q1->link;					p->cond = q1;				}				if(!(q1->mark & LEAF))					q1->mark |= LABEL;			} else				p->mark |= LABEL;			q1 = p->link;			if(q1 != P)				q1->mark |= LABEL;			break;		}		q = p;	} 	if(curtext && curtext->from.sym) {		curtext->from.sym->frame = curframe;		curtext->from.sym->become = curbecome;		if(curbecome > maxbecome)			maxbecome = curbecome;	} 	if(debug['b'])		print("max become = %d\n", maxbecome);	xdefine("ALEFbecome", STEXT, maxbecome); 	curtext = 0;	for(p = firstp; p != P; p = p->link) {		switch(p->as) {		case ATEXT:			curtext = p;			break;		case AJAL:			if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {				o = maxbecome - curtext->from.sym->frame;				if(o <= 0)					break;				/* calling a become or calling a variable */				if(p->to.sym == S || p->to.sym->become) {					curtext->to.offset += o;					if(debug['b']) {						curp = p;						print("%D calling %D increase %d\n",							&curtext->from, &p->to, o);					}				}			}			break;		}	} 	for(p = firstp; p != P; p = p->link) {		o = p->as;		switch(o) {		case ATEXT:			curtext = p;			autosize = p->to.offset + 4;			if(autosize <= 4)			if(curtext->mark & LEAF) {				p->to.offset = -4;				autosize = 0;			} 			q = p;			if(autosize) {				q = prg();				q->as = AADD;				q->line = p->line;				q->from.type = D_CONST;				q->from.offset = -autosize;				q->to.type = D_REG;				q->to.reg = REGSP; 				q->link = p->link;				p->link = q;			} else			if(!(curtext->mark & LEAF)) {				if(debug['v'])					Bprint(&bso, "save suppressed in: %s\n",						curtext->from.sym->name);				Bflush(&bso);				curtext->mark |= LEAF;			} 			if(curtext->mark & LEAF) {				if(curtext->from.sym)					curtext->from.sym->type = SLEAF;				break;			} 			q1 = prg();			q1->as = AMOVW;			q1->line = p->line;			q1->from.type = D_REG;			q1->from.reg = REGLINK;			q1->to.type = D_OREG;			q1->from.offset = 0;			q1->to.reg = REGSP; 			q1->link = q->link;			q->link = q1;			break; 		case ARET:			nocache(p);			if(p->from.type == D_CONST)				goto become;			if(curtext->mark & LEAF) {				if(!autosize) {					p->as = AJMP;					p->from = zprg.from;					p->to.type = D_OREG;					p->to.offset = 0;					p->to.reg = REGLINK;					p->mark |= BRANCH;					break;				} 				p->as = AADD;				p->from.type = D_CONST;				p->from.offset = autosize;				p->to.type = D_REG;				p->to.reg = REGSP; 				q = prg();				q->as = AJMP;				q->line = p->line;				q->to.type = D_OREG;				q->to.offset = 0;				q->to.reg = REGLINK;				q->mark |= BRANCH; 				q->link = p->link;				p->link = q;				break;			}			p->as = AMOVW;			p->from.type = D_OREG;			p->from.offset = 0;			p->from.reg = REGSP;			p->to.type = D_REG;			p->to.reg = 2; 			q = p;			if(autosize) {				q = prg();				q->as = AADD;				q->line = p->line;				q->from.type = D_CONST;				q->from.offset = autosize;				q->to.type = D_REG;				q->to.reg = REGSP;

Lines 1–500 of 643.