forsyth20121205-174063a80cc13 years agoHistory
1262 lines · 21.3 KB · C
RawDownload
#include	"l.h" static struct {	ulong	start;	ulong	size;	ulong	extra;} pool; int	checkpool(Prog*, int);int 	flushpool(Prog*, int, int); intisbranch(Prog *p){	int as = p->as;	return (as >= ABEQ && as <= ABLE) || as == AB || as == ABL || as == ABX;} static intispad(Prog *p){	if(p->as != AMOVW)		return 0;	if(p->from.type != D_REG || p->from.reg != REGSB)		return 0;	if(p->to.type != D_REG || p->to.reg != REGSB)		return 0;	return 1;} intfninc(Sym *s){	if(thumb){		if(s->thumb){			if(s->foreign)				return 8;			else				return 0;		}		else{			if(s->foreign)				return 0;			else				diag("T A !foreign in fninc");		}	}	else{		if(s->thumb){			if(s->foreign)				return 0;			else				diag("A T !foreign in fninc");		}		else{			if(s->foreign)				return 4;			else				return 0;		}				}	return 0;} int fnpinc(Sym *s){	if(!s->fnptr){	// a simplified case BX O(R) -> BL O(R)		if(!debug['f'])			diag("fnptr == 0 in fnpinc");		if(s->foreign)			diag("bad usage in fnpinc %s %d %d %d", s->name, s->used, s->foreign, s->thumb);		return 0;	}	/* 0, 1, 2, 3 squared */	if(s->thumb)		return s->foreign ? 9 : 1;	else		return s->foreign ? 4 : 0;} static Prog *pad(Prog *p, int pc){	Prog *q; 	q = prg();	q->as = AMOVW;	q->line = p->line;	q->from.type = D_REG;	q->from.reg = REGSB;	q->to.type = D_REG;	q->to.reg = REGSB;	q->pc = pc;	q->link = p->link;	return q;} static intscan(Prog *op, Prog *p, int c){	Prog *q; 	for(q = op->link; q != p; q = q->link){		q->pc = c;		c += oplook(q)->size;		nocache(q);	}	return c;} /* size of a case statement including jump table */static longcasesz(Prog *p){	int jt = 0;	long n = 0;	Optab *o; 	for( ; p != P; p = p->link){		if(p->as == ABCASE)			jt = 1;		else if(jt)			break;		o = oplook(p);		n += o->size;	}	return n;} voidspan(void){	Prog *p, *op;	Sym *setext, *s;	Optab *o;	int m, bflag, i;	long c, otxt, v;	int lastthumb = -1; 	if(debug['v'])		Bprint(&bso, "%5.2f span\n", cputime());	Bflush(&bso); 	bflag = 0;	c = INITTEXT;	op = nil;	otxt = c;	for(p = firstp; p != P; op = p, p = p->link) {		setarch(p);		p->pc = c;		o = oplook(p);		m = o->size;		// must check literal pool here in case p generates many instructions		if(blitrl){			if(thumb && isbranch(p))				pool.extra += brextra(p);			if(checkpool(op, p->as == ACASE ? casesz(p) : m))				c = p->pc = scan(op, p, c);		}		if(m == 0) {			if(p->as == ATEXT) {				if(blitrl && lastthumb != -1 && lastthumb != thumb){	// flush literal pool					if(flushpool(op, 0, 1))						c = p->pc = scan(op, p, c);				}				lastthumb = thumb;				curtext = p;				autosize = p->to.offset + 4;				if(p->from.sym != S)					p->from.sym->value = c;				/* need passes to resolve branches */				if(c-otxt >= 1L<<17)					bflag = 1;				otxt = c;				if(thumb && blitrl)					pool.extra += brextra(p);				continue;			}			diag("zero-width instruction\n%P", p);			continue;		}		switch(o->flag & (LFROM|LTO|LPOOL)) {		case LFROM:			addpool(p, &p->from);			break;		case LTO:			addpool(p, &p->to);			break;		case LPOOL:			if ((p->scond&C_SCOND) == 14)				flushpool(p, 0, 0);			break;		}		if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)			flushpool(p, 0, 0);		c += m;		if(blitrl && p->link == P){			if(thumb && isbranch(p))				pool.extra += brextra(p);			checkpool(p, 0);		}	} 	/*	 * if any procedure is large enough to	 * generate a large SBRA branch, then	 * generate extra passes putting branches	 * around jmps to fix. this is rare.	 */	while(bflag) {		if(debug['v'])			Bprint(&bso, "%5.2f span1\n", cputime());		bflag = 0;		c = INITTEXT;		for(p = firstp; p != P; p = p->link) {			setarch(p);			p->pc = c;			if(thumb && isbranch(p))				nocache(p);			o = oplook(p);/* very larg branches			if(o->type == 6 && p->cond) {				otxt = p->cond->pc - c;				if(otxt < 0)					otxt = -otxt;				if(otxt >= (1L<<17) - 10) {					q = prg();					q->link = p->link;					p->link = q;					q->as = AB;					q->to.type = D_BRANCH;					q->cond = p->cond;					p->cond = q;					q = prg();					q->link = p->link;					p->link = q;					q->as = AB;					q->to.type = D_BRANCH;					q->cond = q->link->link;					bflag = 1;				}			} */			m = o->size;			if(m == 0) {				if(p->as == ATEXT) {					curtext = p;					autosize = p->to.offset + 4;					if(p->from.sym != S)						p->from.sym->value = c;					continue;				}				diag("zero-width instruction\n%P", p);				continue;			}			c += m;		}	} 	if(seenthumb){		// branch resolution		int passes = 0;		int lastc = 0;		int again;		Prog *oop; 	loop:		passes++;		if(passes > 150){			diag("span looping !");			errorexit();		}		c = INITTEXT;		oop = op = nil;		again = 0;		for(p = firstp; p != P; oop = op, op = p, p = p->link){			setarch(p);			if(p->pc != c)				again = 1;			p->pc = c;			if(thumb && isbranch(p))				nocache(p);			o = oplook(p);			m = o->size;			if(passes == 1 && thumb && isbranch(p)){	// start conservative so unneeded alignment is not added				if(p->as == ABL)					m = 4;				else					m = 2;				p->align = 0;			}				if(p->align){				if((p->align == 4 && (c&3)) || (p->align == 2 && !(c&3))){					if(ispad(op)){						oop->link = p;						op = oop;						c -= 2;						p->pc = c;					}					else{						op->link = pad(op, c);						op = op->link;						c += 2;						p->pc = c;					}					again = 1;				}			}			if(m == 0) {				if(p->as == ATEXT) {					curtext = p;					autosize = p->to.offset + 4;					if(p->from.sym != S)						p->from.sym->value = c;					continue;				}			}			c += m;		}		if(c != lastc || again){			lastc = c;			goto loop;		}	} 	if(0 && seenthumb){		// rm redundant padding - obsolete		int d; 		op = nil;		d = 0;		for(p = firstp; p != P; op = p, p = p->link){			p->pc -= d;			if(p->as == ATEXT){				if(p->from.sym != S)					p->from.sym->value -= d;// if(p->from.sym != S) print("%s %ux %d %d %d\n", p->from.sym->name ? p->from.sym->name : "?", p->from.sym->value, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr);			}			if(ispad(p) && p->link != P && ispad(p->link)){				op->link = p->link->link;				d += 4;				p = op;			}		}		// print("%d bytes removed (padding)\n", d);		c -= d;	}		if(debug['t']) {		/* 		 * add strings to text segment		 */		c = rnd(c, 8);		for(i=0; i<NHASH; i++)		for(s = hash[i]; s != S; s = s->link) {			if(s->type != SSTRING)				continue;			v = s->value;			while(v & 3)				v++;			s->value = c;			c += v;		}	}				c = rnd(c, 8); 	setext = lookup("etext", 0);	if(setext != S) {		setext->value = c;		textsize = c - INITTEXT;	}	if(INITRND)		INITDAT = rnd(c, INITRND);	if(debug['v'])		Bprint(&bso, "tsize = %lux\n", textsize);	Bflush(&bso);} /* * when the first reference to the literal pool threatens * to go out of range of a 12-bit PC-relative offset, * drop the pool now, and branch round it. * this happens only in extended basic blocks that exceed 4k. */intcheckpool(Prog *p, int sz){	if(thumb){		if(pool.size >= 0x3fc || (p->pc+sz+pool.extra+2+2)+(pool.size-4)-pool.start-4 >= 0x3fc)			return flushpool(p, 1, 0);		else if(p->link == P)			return flushpool(p, 2, 0);		return 0;	}	if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0)		return flushpool(p, 1, 0);	else if(p->link == P)		return flushpool(p, 2, 0);	return 0;} intflushpool(Prog *p, int skip, int force){	Prog *q; 	if(blitrl) {		if(skip){			if(0 && skip==1)print("note: flush literal pool at %lux: len=%lud ref=%lux\n", p->pc+4, pool.size, pool.start);			q = prg();			q->as = AB;			q->to.type = D_BRANCH;			q->cond = p->link;			q->link = blitrl;			blitrl = q;		}		else if(!force && (p->pc+pool.size-pool.start < (thumb ? 0x3fc+4-pool.extra : 2048)))			return 0;		elitrl->link = p->link;		p->link = blitrl;		blitrl = 0;	/* BUG: should refer back to values until out-of-range */		elitrl = 0;		pool.size = 0;		pool.start = 0;		pool.extra = 0;		return 1;	}	return 0;} voidaddpool(Prog *p, Adr *a){	Prog *q, t;	int c; 	if(thumb)		c = thumbaclass(a, p);	else		c = aclass(a); 	t = zprg;	t.as = AWORD; 	switch(c) {	default:		t.to = *a;		break; 	case	C_SROREG:	case C_LOREG:	case C_ROREG:	case C_FOREG:	case C_SOREG:	case C_HOREG:	case C_GOREG:	case C_FAUTO:	case C_SAUTO:	case C_LAUTO:	case C_LACON:	case C_GACON:		t.to.type = D_CONST;		t.to.offset = instoffset;		break;	} 	for(q = blitrl; q != P; q = q->link)	/* could hash on t.t0.offset */		if(memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {			p->cond = q;			return;		} 	q = prg();	*q = t;	q->pc = pool.size; 	if(blitrl == P) {		blitrl = q;		pool.start = p->pc;		q->align = 4;	} else		elitrl->link = q;	elitrl = q;	pool.size += 4; 	p->cond = q;} voidxdefine(char *p, int t, long v){	Sym *s; 	s = lookup(p, 0);	if(s->type == 0 || s->type == SXREF) {		s->type = t;		s->value = v;	}} 

Lines 1–500 of 1262.