forsyth20121205-174063a80cc13 years agoHistory
1636 lines · 39.0 KB · C
RawDownload
#include "l.h" static long thumboprr(int);static long thumboprrr(int, int);static long thumbopirr(int , int);static long thumbopri(int);static long thumbophh(int);static long thumbopbra(int);static long thumbopmv(int, int);static void lowreg(Prog *, int);static void mult(Prog *, int, int);static void numr(Prog *, int, int, int);static void regis(Prog *, int, int, int);static void dis(int, int); // build a constant using neg, add and shift - only worth it if < 6 bytes */static intimmbuildcon(int c, Prog *p){	int n = 0; 	USED(p);	if(c >= 0 && c <= 255)		return 0;			// mv	if(c >= -255 && c < 0)	// mv, neg		return 1;	if(c >= 256 && c <= 510)	// mv, add		return 1;	if(c < 0)		return 0;	while(!(c & 1)){		n++;		c >>= 1;	}	if(c >= 0 && c <= 255)	// mv, lsl		return 1;	return 0;} // positive 5 bit offset from register - O(R)// positive 8 bit offset from register - mov O, R then [R, R]// otherwise O goes in literal pool - mov O1(PC), R then [R, R]static intimmoreg(int off, Prog *p){	int v = 1;	int as = p->as; 	if(off < 0)		return C_GOREG;	if(as == AMOVW)		v = 4;	else if(as == AMOVH || as == AMOVHU)		v = 2;	else if(as == AMOVB || as == AMOVBU)		v = 1;	else		diag("bad op in immoreg");	if(off/v <= 31)		return C_SOREG;	if(off <= 255)		return C_LOREG;	return C_GOREG;} // positive 8 bit - mov O, R then 0(R)// otherwise O goes in literal pool - mov O1(PC), R then 0(R)static intimmacon(int off, Prog *p, int t1, int t2){	USED(p);	if(off < 0)		return t2;	if(off <= 255)		return t1;	return t2;} // unsigned 8 bit in wordsstatic intimmauto(int off, Prog *p){	if(p->as != AMOVW)		diag("bad op in immauto");	mult(p, off, 4);	if(off >= 0 && off <= 1020)		return C_SAUTO;	return C_LAUTO;} static intimmsmall(int off, Prog *p, int t1, int t2, int t3){	USED(p);	if(off >= 0 && off <= 7)		return t1;	if(off >= 0 && off <= 255)		return t2;	return t3;} static intimmcon(int off, Prog *p){	int as = p->as; 	if(as == ASLL || as == ASRL || as == ASRA)		return C_SCON;	if(p->to.type == D_REG && p->to.reg == REGSP){		if(as == AADD || as == ASUB){			if(off >= 0 && off <= 508)				return C_SCON;			if(as == ASUB){				p->as = AADD;				p->from.offset = -p->from.offset;			}			return C_LCON;		}		diag("unknown type in immcon");	}	if(as == AADD || as == ASUB){		if(p->reg != NREG)			return immsmall(off, p, C_SCON, C_LCON, C_GCON);		return immacon(off, p, C_SCON, C_LCON);	}	if(as == AMOVW && p->from.type == D_CONST && p->to.type == D_REG && immbuildcon(off, p))		return C_BCON;	if(as == ACMP && p->from.type == D_CONST && immbuildcon(off, p))		return C_BCON;	if(as == ACMP || as == AMOVW)		return immacon(off, p, C_SCON, C_LCON);	return C_LCON;} intthumbaclass(Adr *a, Prog *p){	Sym *s;	int t; 	switch(a->type) {	case D_NONE:		return C_NONE;	case D_REG:		if(a->reg == REGSP)			return C_SP;		if(a->reg == REGPC)			return C_PC;		if(a->reg >= 8)			return C_HREG;		return C_REG;	case D_SHIFT:		diag("D_SHIFT in thumbaclass");		return C_SHIFT;	case D_FREG:		diag("D_FREG in thumbaclass");		return C_FREG;	case D_FPCR:		diag("D_FPCR in thumbaclass");		return C_FCR;	case D_OREG:		switch(a->name) {		case D_EXTERN:		case D_STATIC:			if(a->sym == 0 || a->sym->name == 0) {				print("null sym external\n");				print("%D\n", a);				return C_GOK;			}			t = a->sym->type;			if(t == 0 || t == SXREF) {				diag("undefined external: %s in %s\n",					a->sym->name, TNAME);				a->sym->type = SDATA;			}			instoffset = a->sym->value + a->offset + INITDAT;			return C_LEXT;	/* INITDAT unknown at this stage */			// return immacon(instoffset, p, C_SEXT, C_LEXT);		case D_AUTO:			instoffset = autosize + a->offset;			return immauto(instoffset, p);		case D_PARAM:			instoffset = autosize + a->offset + 4L;// print("D_PARAM %s %d+%d+%d = %d\n", a->sym != S ? a->sym->name : "noname", autosize, a->offset, 4, autosize+a->offset+4);			return immauto(instoffset, p);		case D_NONE:			instoffset = a->offset;			if(a->reg == REGSP)				return immauto(instoffset, p);			else				return immoreg(instoffset, p);		}		return C_GOK;	case D_PSR:		diag("D_PSR in thumbaclass");		return C_PSR;	case D_OCONST:		switch(a->name) {		case D_EXTERN:		case D_STATIC:			s = a->sym;			t = s->type;			if(t == 0 || t == SXREF) {				diag("undefined external: %s in %s\n",					s->name, TNAME);				s->type = SDATA;			}			instoffset = s->value + a->offset + INITDAT;			if(s->type == STEXT || s->type == SLEAF){				instoffset = s->value + a->offset;#ifdef CALLEEBX				instoffset += fnpinc(s);#else				if(s->thumb)					instoffset++;	// T bit#endif				return C_LCON;			}			return C_LCON;	/* INITDAT unknown at this stage */			// return immcon(instoffset, p);		}		return C_GOK;	case D_FCONST:		diag("D_FCONST in thumaclass");		return C_FCON;	case D_CONST:		switch(a->name) {		case D_NONE:			instoffset = a->offset;			if(a->reg != NREG)				goto aconsize;			return immcon(instoffset, p);		case D_EXTERN:		case D_STATIC:			s = a->sym;			if(s == S)				break;			t = s->type;			switch(t) {			case 0:			case SXREF:				diag("undefined external: %s in %s\n",					s->name, TNAME);				s->type = SDATA;				break;			case SCONST:			case STEXT:			case SLEAF:				instoffset = s->value + a->offset;#ifdef CALLEEBX				instoffset += fnpinc(s);#else				if(s->thumb)					instoffset++;	// T bit#endif				return C_LCON;			}			instoffset = s->value + a->offset + INITDAT;			return C_LCON;	/* INITDAT unknown at this stage */			// return immcon(instoffset, p);		case D_AUTO:			instoffset = autosize + a->offset;			goto aconsize;		case D_PARAM:			instoffset = autosize + a->offset + 4L;		aconsize:			if(p->from.reg == REGSP || p->from.reg == NREG)				return instoffset >= 0 && instoffset < 1024 ? C_SACON : C_GACON;			else if(p->from.reg == p->to.reg)				return immacon(instoffset, p, C_SACON, C_GACON);			return immsmall(instoffset, p, C_SACON, C_LACON, C_GACON);		}		return C_GOK;	case D_BRANCH: {		int v, va; 		p->align = 0;		v = -4;		va = 0;		if(p->cond != P){			v = (p->cond->pc - p->pc) - 4;			va = p->cond->pc;		}		instoffset = v;		if(p->as == AB){			if(v >= -2048 && v <= 2046)				return C_SBRA;			p->align = 4;			instoffset = va;			return C_LBRA;		}		if(p->as == ABL){#ifdef CALLEEBX			int e; 			if((e = fninc(p->to.sym))) {				v += e;				va += e;				instoffset += e;			}		#endif			if(v >= -4194304 && v <= 4194302)				return C_SBRA;			p->align = 2;			instoffset = va;			return C_LBRA;		}		if(p->as == ABX){			v = va;			if(v >= 0 && v <= 255)				return C_SBRA;			p->align = 2;			instoffset = va;			return C_LBRA;		}		if(v >= -256 && v <= 254)			return C_SBRA;		if(v >= -(2048-2) && v <= (2046+2))			return C_LBRA;		p->align = 2;		instoffset = va;		return C_GBRA;	}	}	return C_GOK;} // as a1 a2 a3 type size param lit versOptab thumboptab[] ={	{ ATEXT,		C_LEXT,		C_NONE,		C_LCON,		0,	0,	0 },	{ ATEXT,		C_LEXT,		C_REG,		C_LCON,		0,	0,	0 },	{ AMVN,		C_REG,		C_NONE,		C_REG,		1,	2,	0 },	{ ASRL,		C_REG,		C_NONE,		C_REG,		1,	2,	0 },	{ ACMP,		C_REG,		C_REG,		C_NONE,		1,	2,	0 },	{ ACMN,		C_REG,		C_REG,		C_NONE,		1,	2,	0 },	{ AADD,		C_REG,		C_REG,		C_REG,		2,	2,	0 },	{ AADD,		C_REG,		C_NONE,		C_REG,		2,	2,	0 },	{ AADD,		C_SCON,		C_REG,		C_REG,		3,	2,	0 },	{ AADD,		C_LCON,		C_REG,		C_REG,		49,	4,	0 },	{ AADD,		C_GCON,		C_REG,		C_REG,		36,	4,	0,	LFROM },	// { AADD,		C_LCON,		C_NONE,		C_REG,		3,	2,	0,	LFROM },	{ ASRL,		C_SCON,		C_REG,		C_REG,		4,	2,	0 },	{ ASRL,		C_SCON,		C_NONE,		C_REG,		4,	2,	0 },	{ AADD,		C_SCON,		C_NONE,		C_REG,		5,	2,	0 },	{ AADD,		C_LCON,		C_NONE,		C_REG,		37,	4,	0,	LFROM },	{ ACMP,		C_SCON,		C_REG,		C_NONE,		5,	2,	0 },	{ ACMP,		C_BCON,		C_REG,		C_NONE,		48,	6,	0 },	{ ACMP,		C_LCON,		C_REG,		C_NONE,		39,	4,	0,	LFROM },	{ AMOVW,		C_SCON,		C_NONE,		C_REG,		5,	2,	0 },	{ AMOVW,		C_BCON,		C_NONE,		C_REG,		47,	4,	0 },	{ AMOVW,		C_LCON,		C_NONE,		C_REG,		38,	2,	0,	LFROM },	// { AADD,		C_LCON,		C_PC,		C_REG,		6,	2,	0,	LFROM },	// { AADD,		C_LCON,		C_SP,		C_REG,		6,	2,	0,	LFROM },	{ AADD,		C_SCON,		C_NONE,		C_SP,		7,	2,	0 },	{ AADD,		C_LCON,		C_NONE,		C_SP,		40,	4,	0,	LFROM },	{ AADD,		C_REG,		C_NONE,		C_HREG,		8,	2,	0 },	{ AADD,		C_HREG,		C_NONE,		C_REG,		8,	2,	0 },	{ AADD,		C_HREG,		C_NONE,		C_HREG,		8,	2,	0 },	{ AMOVW,		C_REG,		C_NONE,		C_HREG,		8,	2,	0 },	{ AMOVW,		C_HREG,		C_NONE,		C_REG,		8,	2,	0 },	{ AMOVW,		C_HREG,		C_NONE,		C_HREG,		8,	2,	0 },	{ ACMP,		C_REG,		C_HREG,		C_NONE,		8,	2,	0 },	{ ACMP,		C_HREG,		C_REG,		C_NONE,		8,	2,	0 },	{ ACMP,		C_HREG,		C_HREG,		C_NONE,		8,	2,	0 },	{ AB,			C_NONE,		C_NONE,		C_SBRA,		9,	2,	0,	LPOOL },	{ ABEQ,		C_NONE,		C_NONE,		C_SBRA,		10,	2,	0 },	{ ABL,		C_NONE,		C_NONE,		C_SBRA,		11,	4,	0 },	{ ABX,		C_NONE,		C_NONE,		C_SBRA,		12,	10,	0 },	{ AB,			C_NONE,		C_NONE,		C_LBRA,		41,	8,	0,	LPOOL },	{ ABEQ,		C_NONE,		C_NONE,		C_LBRA,		46,	4,	0 },	{ ABL,		C_NONE,		C_NONE,		C_LBRA,		43,	14,	0 },	{ ABX,		C_NONE,		C_NONE,		C_LBRA,		44,	14,	0 },	{ ABEQ,		C_NONE,		C_NONE,		C_GBRA,		42,  10, 	0 },	// { AB,		C_NONE,		C_NONE,		C_SOREG,		13,	0,	0 },	// { ABL,		C_NONE,		C_NONE,		C_SOREG,		14,	0,	0 },	{ ABL,		C_NONE,		C_NONE,		C_REG,		51,	4,	0 },	{ ABX,		C_NONE,		C_NONE,		C_REG,		15,	8,	0 },	{ ABX,		C_NONE,		C_NONE,		C_HREG,		15,	8,	0 },	{ ABXRET,		C_NONE,		C_NONE,		C_REG,		45,	2,	0 },	{ ABXRET,		C_NONE,		C_NONE,		C_HREG,		45,	2,	0 },	{ ASWI,		C_NONE,		C_NONE,		C_LCON,		16,	2,	0 },	{ AWORD,		C_NONE,		C_NONE,		C_LCON,		17,	4,	0 },	{ AWORD,		C_NONE,		C_NONE,		C_GCON,		17,	4,	0 },	{ AWORD,		C_NONE,		C_NONE,		C_LEXT,		17,	4, 	0 },	{ ADWORD,	C_LCON,		C_NONE,		C_LCON,		50,	8,	0 },	{ AMOVW,		C_SAUTO,		C_NONE,		C_REG,		18,	2,	REGSP },	{ AMOVW,		C_LAUTO,		C_NONE,		C_REG,		33,	6,	0,	LFROM  },	// { AMOVW,		C_OFFPC,		C_NONE,		C_REG,		18,	2,	REGPC,	LFROM  },	{ AMOVW,		C_SEXT,		C_NONE,		C_REG,		30,	4,	0 },	{ AMOVW,		C_SOREG,		C_NONE,		C_REG,		19,	2,	0 },	{ AMOVHU,	C_SEXT,		C_NONE,		C_REG,		30,	4,	0 },	{ AMOVHU,	C_SOREG,		C_NONE,		C_REG,		19,	2,	0 },	{ AMOVBU,	C_SEXT,		C_NONE,		C_REG,		30,	4,	0 },	{ AMOVBU,	C_SOREG,		C_NONE,		C_REG,		19,	2,	0 },	{ AMOVW,		C_REG,		C_NONE,		C_SAUTO,		20,	2,	0 },	{ AMOVW,		C_REG,		C_NONE,		C_LAUTO,		34,	6,	0,	LTO },	{ AMOVW,		C_REG,		C_NONE,		C_SEXT,		31,	4,	0 },	{ AMOVW,		C_REG,		C_NONE,		C_SOREG,		21,	2,	0 },	{ AMOVH,		C_REG,		C_NONE,		C_SEXT,		31,	4,	0 },	{ AMOVH,		C_REG,		C_NONE,		C_SOREG,		21,	2,	0 },	{ AMOVB,		C_REG,		C_NONE,		C_SEXT,		31,	4,	0 },	{ AMOVB,		C_REG,		C_NONE,		C_SOREG,		21,	2,	0 },	{ AMOVHU,	C_REG,		C_NONE,		C_SEXT,		31,	4,	0 },	{ AMOVHU,	C_REG,		C_NONE,		C_SOREG,		21,	2,	0 },	{ AMOVBU,	C_REG,		C_NONE,		C_SEXT,		31,	4,	0 },	{ AMOVBU,	C_REG,		C_NONE,		C_SOREG,		21,	2,	0 },	{ AMOVW,		C_REG,		C_NONE,		C_REG,		22,	2,	0 },	{ AMOVB,		C_REG,		C_NONE,		C_REG,		23,	4,	0 },	{ AMOVH,		C_REG,		C_NONE,		C_REG,		23,	4,	0 },	{ AMOVBU,	C_REG,		C_NONE,		C_REG,		23,	4,	0 },	{ AMOVHU,	C_REG,		C_NONE,		C_REG,		23,	4,	0 },	{ AMOVH,		C_SEXT,		C_NONE,		C_REG,		32,	6,	0 },	{ AMOVH,		C_SOREG,		C_NONE,		C_REG,		24,	4,	0 },	{ AMOVB,		C_SEXT,		C_NONE,		C_REG,		32,	6,	0 },	{ AMOVB,		C_SOREG,		C_NONE,		C_REG,		24,	4,	0 },	{ AMOVW,		C_SACON,	C_NONE,		C_REG,		25,	2,	0 },	{ AMOVW,		C_LACON,	C_NONE,		C_REG,		35,	4,	0 },	{ AMOVW,		C_GACON,	C_NONE,		C_REG,		35,	4,	0,	LFROM },	{ AMOVM,		C_LCON,		C_NONE,		C_REG,		26,	2,	0 },	{ AMOVM,		C_REG,		C_NONE,		C_LCON,		27,	2,	0 },	{ AMOVW,		C_LOREG,		C_NONE,		C_REG,		28,	4,	0 },	{ AMOVH,		C_LOREG,		C_NONE,		C_REG,		28,	4,	0 },	{ AMOVB,		C_LOREG,		C_NONE,		C_REG,		28,	4,	0 },	{ AMOVHU,	C_LOREG,		C_NONE,		C_REG,		28,	4,	0 },	{ AMOVBU,	C_LOREG,		C_NONE,		C_REG,		28,	4,	0 },	{ AMOVW,		C_REG,		C_NONE,		C_LOREG,		29,	4,	0 },	{ AMOVH,		C_REG,		C_NONE,		C_LOREG,		29,	4,	0 },	{ AMOVB,		C_REG,		C_NONE,		C_LOREG,		29,	4,	0 },	{ AMOVHU,	C_REG,		C_NONE,		C_LOREG,		29,	4,	0 },	{ AMOVBU,	C_REG,		C_NONE,		C_LOREG,		29,	4,	0 },	{ AMOVW,		C_GOREG,		C_NONE,		C_REG,		28,	4,	0,	LFROM },	{ AMOVH,		C_GOREG,		C_NONE,		C_REG,		28,	4,	0,	LFROM },	{ AMOVB,		C_GOREG,		C_NONE,		C_REG,		28,	4,	0,	LFROM },	{ AMOVHU,	C_GOREG,		C_NONE,		C_REG,		28,	4,	0,	LFROM },	{ AMOVBU,	C_GOREG,		C_NONE,		C_REG,		28,	4,	0,	LFROM },	{ AMOVW,		C_REG,		C_NONE,		C_GOREG,		29,	4,	0,	LTO },	{ AMOVH,		C_REG,		C_NONE,		C_GOREG,		29,	4,	0,	LTO },	{ AMOVB,		C_REG,		C_NONE,		C_GOREG,		29,	4,	0,	LTO },	{ AMOVHU,	C_REG,		C_NONE,		C_GOREG,		29,	4,	0,	LTO },	{ AMOVBU,	C_REG,		C_NONE,		C_GOREG,		29,	4,	0,	LTO },	{ AMOVW,		C_LEXT,		C_NONE,		C_REG,		30,	4,	0,	LFROM },	{ AMOVH,		C_LEXT,		C_NONE,		C_REG,		32,	6,	0,	LFROM },	{ AMOVB,		C_LEXT,		C_NONE,		C_REG,		32,	6,	0,	LFROM },	{ AMOVHU,	C_LEXT,		C_NONE,		C_REG,		30,	4,	0,	LFROM },	{ AMOVBU,	C_LEXT,		C_NONE,		C_REG,		30,	4,	0,	LFROM },	{ AMOVW,		C_REG,		C_NONE,		C_LEXT,		31,	4,	0,	LTO },	{ AMOVH,		C_REG,		C_NONE,		C_LEXT,		31,	4,	0,	LTO },	{ AMOVB,		C_REG,		C_NONE,		C_LEXT,		31,	4,	0,	LTO },	{ AMOVHU,	C_REG,		C_NONE,		C_LEXT,		31,	4,	0,	LTO },	{ AMOVBU,	C_REG,		C_NONE,		C_LEXT,		31,	4,	0,	LTO }, 	{ AXXX,		C_NONE,		C_NONE,		C_NONE,		0,	2,	0 },}; #define OPCNTSZ	52int opcount[OPCNTSZ]; // is this too pessimistic ?intbrextra(Prog *p){	int c; 	// +2 is for padding	if(p->as == ATEXT)		return 0-0+2;	if(!isbranch(p))		diag("bad op in brextra()");	c = thumbaclass(&p->to, p);	switch(p->as){	case AB:		if(c != C_SBRA)			return 0;		return 8-2+2;	case ABL:		if(c != C_SBRA)			return 0;		return 14-4+2;	case ABX:		if(c == C_REG || c == C_HREG)			return 0;#ifdef CALLEEBX		diag("ABX $I in brextra");#endif		if(c != C_SBRA)			return 0;		return 14-10+2;	default:		if(c == C_GBRA)			return 0;		if(c == C_LBRA)			return 10-4+2;		return 10-2+2;	}} #define high(r)	((r)>=8) static long

Lines 1–500 of 1636.