#include "gc.h"

void
tindex(Type *tf, Type *tt)
{
	int i, j;

	j = 0;
	if(tt != T) {
		j = tt->etype;
		if(j >= NTYPE)
			j = 0;
	}
	i = 0;
	if(tf != T) {
		i = tf->etype;
		if(i >= NTYPE)
			if(typesu[i])
				i = j;
			else
				i = 0;
	}
	txtp = &txt[i][j];
}

void
ginit(void)
{
	int i, j, si, sj;

	thestring = "68020";
	thechar = '2';
	exregoffset = 7;
	exaregoffset = 5;
	exfregoffset = 7;
	listinit();
	for(i=0; i<NREG; i++) {
		regused[i] = 0;
		fregused[i] = 0;
		aregused[i] = 0;
	}
	regaddr(D_A0+6);
	regaddr(D_A0+7);
	for(i=0; i<sizeof(regbase); i++)
		regbase[i] = D_NONE;
	for(i=0; i<NREG; i++) {
		regbase[D_R0+i] = D_R0+i;
		regbase[D_A0+i] = D_A0+i;
		regbase[D_F0+i] = D_F0+i;
	}
	regbase[D_TOS] = D_TOS;

	for(i=0; i<NTYPE; i++)
	for(j=0; j<NTYPE; j++) {
		txtp = &txt[i][j];
		txtp->movas = AGOK;
		txtp->preclr = 0;
		txtp->postext = AGOK;
		if(!(typechlp[i] && typechlp[j]))
			continue;
		si = types[i]->width;
		sj = types[j]->width;
		if(sj < si)
			txtp->preclr = -1;
		if(sj > si) {
			if(typeu[i]) {
				txtp->preclr = 1;
			} else {
				if(sj == 2)
					txtp->postext = AEXTBW;
				if(sj == 4)
					if(si == 1)
						txtp->postext = AEXTBL;
					else
						txtp->postext = AEXTWL;
			}
			sj = si;
		}
		if(sj == 1)
			txtp->movas = AMOVB;
		if(sj == 2)
			txtp->movas = AMOVW;
		if(sj == 4)
			txtp->movas = AMOVL;
	}

	for(i=0; i<ALLOP; i++)
		for(j=0; j<NTYPE; j++)
			opxt[i][j] = AGOK;
	oinit(OFUNC, ABSR, ATRAP, AGOK, AGOK, AGOK);

	oinit(OAS, AMOVB, AMOVW, AMOVL, AFMOVEF, AFMOVED);
	oinit(OFAS, AFMOVEB, AFMOVEW, AFMOVEL, AFMOVEF, AFMOVED);
	oinit(OADDR, AGOK, APEA, ALEA, AGOK, AGOK);
	oinit(OPREINC, AADDB, AADDW, AADDL, AFADDF, AFADDD);
	oinit(OPOSTINC, AADDB, AADDW, AADDL, AFADDF, AFADDD);
	oinit(OPREDEC, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
	oinit(OPOSTDEC, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
	oinit(OADD, AADDB, AADDW, AADDL, AFADDF, AFADDD);
	oinit(OASADD, AADDB, AADDW, AADDL, AFADDF, AFADDD);
	oinit(OSUB, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
	oinit(OASSUB, ASUBB, ASUBW, ASUBL, AFSUBF, AFSUBD);
	oinit(OMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
	oinit(OLMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
	oinit(OASMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
	oinit(OASLMUL, AGOK, AMULSW, AMULSL, AFMULF, AFMULD);
	oinit(ODIV, AGOK, ADIVSW, ADIVSL, AFDIVF, AFDIVD);
	oinit(OLDIV, AGOK, ADIVUW, ADIVUL, AFDIVF, AFDIVD);
	oinit(OASDIV, AGOK, ADIVSW, ADIVSL, AFDIVF, AFDIVD);
	oinit(OASLDIV, AGOK, ADIVUW, ADIVUL, AFDIVF, AFDIVD);
	oinit(OMOD, AGOK, ADIVSW, ADIVSL, AFMODF, AFMODD);
	oinit(OASMOD, AGOK, ADIVSW, ADIVSL, AGOK, AGOK);
	oinit(OLMOD, AGOK, ADIVUW, ADIVUL, AGOK, AGOK);
	oinit(OASLMOD, AGOK, ADIVUW, ADIVUL, AGOK, AGOK);
	oinit(OAND, AANDB, AANDW, AANDL, AGOK, AGOK);
	oinit(OASAND, AANDB, AANDW, AANDL, AGOK, AGOK);
	oinit(OOR, AORB, AORW, AORL, AGOK, AGOK);
	oinit(OASOR, AORB, AORW, AORL, AGOK, AGOK);
	oinit(OXOR, AEORB, AEORW, AEORL, AGOK, AGOK);
	oinit(OASXOR, AEORB, AEORW, AEORL, AGOK, AGOK);
	oinit(ONEG, ANEGB, ANEGW, ANEGL, AFNEGF, AFNEGD);
	oinit(OCOM, ANOTB, ANOTW, ANOTL, AGOK, AGOK);
	oinit(OTST, ATSTB, ATSTW, ATSTL, AFTSTF, AFTSTD);
	oinit(OEQ, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
	oinit(ONE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
	oinit(OGE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
	oinit(OGT, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
	oinit(OLT, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
	oinit(OLE, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
	oinit(OLS, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
	oinit(OLO, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
	oinit(OHS, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
	oinit(OHI, ACMPB, ACMPW, ACMPL, AFCMPF, AFCMPD);
	oinit(OASHR, AASRB, AASRW, AASRL, AGOK, AGOK);
	oinit(OASASHR, AASRB, AASRW, AASRL, AGOK, AGOK);
	oinit(OLSHR, ALSRB, ALSRW, ALSRL, AGOK, AGOK);
	oinit(OASLSHR, ALSRB, ALSRW, ALSRL, AGOK, AGOK);
	oinit(OASHL, AASLB, AASLW, AASLL, AGOK, AGOK);
	oinit(OASASHL, AASLB, AASLW, AASLL, AGOK, AGOK);
	oinit(OBIT, ABFEXTU, AGOK, AGOK, AGOK, AGOK);

	nstring = 0;
	mnstring = 0;
	nrathole = 0;
	nstatic = 0;
	pc = 0;
	breakpc = -1;
	continpc = -1;
	cases = C;
	firstp = P;
	lastp = P;
	tfield = types[TLONG];

	zprog.link = P;
	zprog.as = AGOK;
	zprog.from.type = D_NONE;
	zprog.from.index = D_NONE;
	zprog.to = zprog.from;

	nodret = new(ONAME, Z, Z);
	nodret->sym = slookup(".ret");
	nodret->type = types[TIND];
	nodret->etype = types[TIND]->etype;
	nodret->class = CPARAM;
	nodret = new(OIND, nodret, Z);
	complex(nodret);

	symrathole = slookup(".rathole");
	symrathole->class = CGLOBL;
	symrathole->type = typ(TARRAY, types[TCHAR]);
	nodrat = new(ONAME, Z, Z);
	nodrat->sym = symrathole;
	nodrat->type = types[TIND];
	nodrat->etype = TVOID;
	nodrat->class = CGLOBL;
	complex(nodrat);
	nodrat->type = symrathole->type;

	com64init();

	symstatic = slookup(".static");
	symstatic->class = CSTATIC;
	symstatic->type = typ(TARRAY, types[TLONG]);
}

void
gclean(void)
{
	int i;
	Sym *s;

	regfree(D_A0+6);
	regfree(D_A0+7);
	for(i=0; i<NREG; i++) {
		if(regused[i])
			diag(Z, "missing R%d", i);
		if(aregused[i])
			diag(Z, "missing A%d", i);
		if(fregused[i])
			diag(Z, "missing F%d", i);
	}

	while(mnstring)
		outstring("", 1L);
	symstring->type->width = nstring;
	symstatic->type->width = nstatic;
	symrathole->type->width = nrathole;
	for(i=0; i<NHASH; i++)
	for(s = hash[i]; s != S; s = s->link) {
		if(s->type == T)
			continue;
		if(s->type->width == 0)
			continue;
		if(s->class != CGLOBL && s->class != CSTATIC)
			continue;
		if(s->type == types[TENUM])
			continue;
		gpseudo(AGLOBL, s, D_CONST, s->type->width);
		pc--;
	}
	nextpc();
	p->as = AEND;
	outcode();
}

void
oinit(int o, int ab, int aw, int al, int af, int ad)
{
	int i;

	i = o;
	if(i >= ALLOP) {
		diag(Z, "op(%d) >= ALLOP(%d)", i, ALLOP);
		errorexit();
	}
	opxt[i][TCHAR] = ab;
	opxt[i][TUCHAR] = ab;
	opxt[i][TSHORT] = aw;
	opxt[i][TUSHORT] = aw;
	opxt[i][TINT] = al;
	opxt[i][TUINT] = al;
	opxt[i][TLONG] = al;
	opxt[i][TULONG] = al;
	opxt[i][TIND] = al;
	opxt[i][TFLOAT] = af;
	opxt[i][TDOUBLE] = ad;
}

Prog*
prg(void)
{
	Prog *p;

	p = alloc(sizeof(*p));
	*p = zprog;
	return p;
}

void
nextpc(void)
{

	p = prg();
	pc++;
	p->lineno = nearln;
	if(firstp == P) {
		firstp = p;
		lastp = p;
		return;
	}
	lastp->link = p;
	lastp = p;
}

void
gargs(Node *n)
{
	long s;

loop:
	if(n == Z)
		return;
	if(n->op == OLIST) {
		gargs(n->right);
		n = n->left;
		goto loop;
	}
	s = argoff;
	cgen(n, D_TOS, n);
	argoff = s + n->type->width;
}

void
naddr(Node *n, Adr *a, int x)
{
	Node *l;
	long v;

	switch(n->op) {
	default:
	bad:
		diag(n, "bad in naddr: %O", n->op);
		break;

	case OADDR:
	case OIND:
		naddr(n->left, a, x);
		goto noadd;

	case OREGISTER:
		a->sym = S;
		a->type = n->reg;
		a->offset = n->xoffset;
		a->displace = 0;
		break;

	case ONAME:
		a->etype = n->etype;
		a->displace = 0;
		a->sym = n->sym;
		a->offset = n->xoffset;
		a->type = D_STATIC;
		if(n->class == CSTATIC)
			break;
		if(n->class == CEXTERN || n->class == CGLOBL) {
			a->type = D_EXTERN;
			break;
		}
		if(n->class == CAUTO) {
			a->type = D_AUTO;
			break;
		}
		if(n->class == CPARAM) {
			a->type = D_PARAM;
			break;
		}
		goto bad;

	case OINDEX:
		naddr(n->left, a, x);
		switch(n->left->addable) {
		default:
			goto bad;
		case 1:
		case 12:
			a->index = x | I_INDEX1;
			a->type &= D_MASK;
			break;
		case 2:
		case 10:
		case 11:
			a->index = x | I_INDEX2;
			break;
		}
		a->scale = n->scale;
		break;

	case OCONST:
		a->displace = 0;
		if(typefd[n->type->etype]) {
			a->type = D_FCONST;
			a->dval = n->fconst;
			break;
		}
		a->type = D_CONST;
		a->offset = n->vconst;
		break;

	case OADD:
		l = n->left;
		if(l->addable == 20) {
			v = l->vconst;
			naddr(n->right, a, x);
			goto add;
		}
		l = n->right;
		if(l->addable == 20) {
			v = l->vconst;
			naddr(n->left, a, x);
			goto add;
		}
		goto bad;
	noadd:
		v = 0;
	add:
		switch(n->addable) {
		default:
			goto bad;
		case 2:
			a->displace += v;
			break;
		case 21:
			a->type &= D_MASK;
			a->type |= I_INDIR;
			break;
		case 1:
		case 12:
			a->offset += v;
			a->type &= D_MASK;
			a->type |= I_ADDR;
			break;
		case 13:
			a->index = D_NONE|I_INDEX3;
		case 10:
		case 11:
		case 20:
			a->type &= D_MASK;
			a->type |= I_DIR;
			break;
		}
		break;

	case OPREINC:
	case OPREDEC:
	case OPOSTINC:
	case OPOSTDEC:

	case OAS:
	case OASLMUL:
	case OASLDIV:
	case OASLMOD:
	case OASMUL:
	case OASDIV:
	case OASMOD:
	case OASXOR:
	case OASOR:
	case OASADD:
	case OASSUB:
	case OASLSHR:
	case OASASHR:
	case OASASHL:
	case OASAND:
		naddr(n->left, a, x);
		break;
	}
}

int
regalloc(Type *t, int g)
{

	if(t == T)
		return D_NONE;
	g &= D_MASK;
	if(typefd[t->etype]) {
		if(g >= D_F0 && g < D_F0+NREG) {
			fregused[g-D_F0]++;
			return g;
		}
		for(g=0; g<NREG; g++)
			if(fregused[g] == 0) {
				fregused[g]++;
				return g + D_F0;
			}
	} else {
		if(g >= D_R0 && g < D_R0+NREG) {
			regused[g-D_R0]++;
			return g;
		}
		for(g=0; g<NREG; g++)
			if(regused[g] == 0) {
				regused[g]++;
				return g + D_R0;
			}
	}
	diag(Z, "out of registers");
	return D_TOS;
}

int
regaddr(int g)
{

	if(g >= D_A0 && g < D_A0+NREG) {
		aregused[g-D_A0]++;
		return g;
	}
	for(g=0; g<NREG; g++)
		if(aregused[g] == 0) {
			aregused[g]++;
			return g + D_A0;
		}
	diag(Z, "out of addr registers");
	return D_TOS;
}

int
regpair(int g)
{

	if(g >= D_R0+1 && g < D_R0+NREG)
		if(!regused[g-D_R0-1]) {
			regused[g-D_R0-1]++;
			regused[g-D_R0]++;
			return g-1;
		}
	if(g >= D_R0 && g < D_R0+NREG-1)
		if(!regused[g-D_R0+1]) {
			regused[g-D_R0+1]++;
			regused[g-D_R0]++;
			return g;
		}
	for(g = 0; g < NREG-1; g++)
		if(!regused[g])
		if(!regused[g+1]) {
			regused[g]++;
			regused[g+1]++;
			return g + D_R0;
		}
	diag(Z, "out of register pairs");
	return D_TOS;
}

int
regret(Type *t)
{

	if(t == T)
		return D_NONE;
	if(typefd[t->etype])
		return D_F0;
	return D_R0;
}

void
regfree(int g)
{

	g &= D_MASK;
	if(g == D_TOS || g == D_TREE || g == D_NONE)
		return;
	if(g >= D_R0 && g < D_R0+NREG) {
		regused[g-D_R0]--;
		return;
	}
	if(g >= D_A0 && g < D_A0+NREG) {
		aregused[g-D_A0]--;
		return;
	}
	if(g >= D_F0 && g < D_F0+NREG) {
		fregused[g-D_F0]--;
		return;
	}
	diag(Z, "bad in regfree: %d", g);
}

void
gmove(Type *tf, Type *tt, int gf, Node *f, int gt, Node *t)
{
	int g, a, b;
	Prog *p1;

	tindex(tf, tt);
	if(txtp->preclr) {
		if(gf >= D_R0 && gf < D_R0+NREG)
		if(txtp->preclr < 0) {
			gmove(tt, tt, gf, f, gt, t);
			return;
		}
		g = regalloc(types[TLONG], gt);
		if(g == gf) {
			g = regalloc(types[TLONG], D_NONE);
			regfree(gf);
		}
		if(txtp->preclr > 0)
			gopcode(OAS, types[TLONG], D_CONST, nodconst(0), g, Z);
		gopcode(OAS, tf, gf, f, g, Z);
		if(g != gt)
			gopcode(OAS, tt, g, Z, gt, t);
		regfree(g);
		return;
	}
	a = txtp->postext;
	if(a != AGOK) {
		if(gf >= D_R0 && gf < D_R0+NREG)
			g = regalloc(types[TLONG], gf);
		else
			g = regalloc(types[TLONG], gt);
		if(g != gf)
			gopcode(OAS, tf, gf, f, g, Z);
		nextpc();
		p->as = a;
		p->to.type = g;
		if(debug['g'])
			print("%P\n", p);
		if(g != gt)
			gopcode(OAS, tt, g, Z, gt, t);
		regfree(g);
		return;
	}
	if((regbase[gf] != D_NONE && regbase[gf] == regbase[gt]) ||
	   (gf == D_TREE && gt == D_TREE && f == t))
		return;
	if(typefd[tf->etype] || typefd[tt->etype]) {
		if(typeu[tf->etype] && typefd[tt->etype]) {	/* unsign->float */
			a = regalloc(types[TLONG], D_NONE);
			gmove(tf, types[TLONG], gf, f, a, t);
			if(tf->etype == TULONG) {
				b = regalloc(types[TDOUBLE], D_NONE);
				gmove(types[TLONG], tt, a, t, b, t);
				gopcode(OTST, types[TLONG], D_NONE, Z, a, t);
				gbranch(OGE);
				p1 = p;
				gopcode(OASADD, types[TDOUBLE],
					D_CONST, nodconst(100), b, t);
				p->from.dval = 4294967296.;
				patch(p1, pc);
				gmove(types[TDOUBLE], tt, b, t, gt, t);
				regfree(b);
			} else
				gmove(types[TLONG], tt, a, t, gt, t);
			regfree(a);
			return;
		}
		if(typefd[tf->etype] && !typefd[tt->etype]) {	/* float->fix */
			a = regalloc(types[TLONG], D_NONE);
			gopcode(OAS, types[TLONG], D_FPCR, t, a, t);
			gopcode(OAS, types[TLONG], D_CONST, nodconst(16), D_FPCR, t);
		}
		if(gf < D_F0 || gf >= D_F0+NREG) {
			g = regalloc(types[TDOUBLE], gt);
			gopcode(OFAS, tf, gf, f, g, t);
			if(g != gt)
				gopcode(OFAS, tt, g, t, gt, t);
			regfree(g);
		} else
			gopcode(OFAS, tt, gf, f, gt, t);
		if(typefd[tf->etype] && !typefd[tt->etype]) {	/* float->fix */
			gopcode(OAS, types[TLONG], a, t, D_FPCR, t);
			regfree(a);
		}
		return;
	}
	gopcode(OAS, tt, gf, f, gt, t);
}

void
gopcode(int o, Type *ty, int gf, Node *f, int gt, Node *t)
{
	int i, fidx, tidx;
	long v;

	if(o == OAS)
		if(gf == gt)
			if(gf != D_TREE || f == t)
				return;

	fidx = D_NONE;
	if(gf == D_TREE) {
		if(f->op == OINDEX) {
			fidx = regalloc(types[TIND], fidx);
			cgen(f->right, fidx, f->right);
		}
	}
	tidx = D_NONE;
	if(gt == D_TREE) {
		if(t->op == OINDEX) {
			v = argoff;
			tidx = regalloc(types[TIND], tidx);
			cgen(t->right, tidx, t->right);
			if(gf == D_TOS)
				adjsp(v - argoff);
		}
	}
	i = 0;
	if(ty != T) {
		i = ty->etype;
		if(i >= NTYPE)
			i = 0;
	}
	nextpc();
	if(gf == D_TREE) {
		naddr(f, &p->from, fidx);
	} else {
		p->from.type = gf;
		if(gf == D_CONST) {
			p->from.offset = (long)(uintptr)f;
			if(typefd[i]) {
				p->from.type = D_FCONST;
				p->from.dval = (long)(uintptr)f;
			}
		}
	}
	p->as = opxt[o][i];
	if(gt == D_TREE) {
		naddr(t, &p->to, tidx);
	} else {
		p->to.type = gt;
		if(gt == D_CONST)
			p->to.offset = (long)(uintptr)t;
	}
	if(o == OBIT) {
		p->from.field = f->type->nbits;
		p->to.field = f->type->shift;
		if(p->from.field == 0)
			diag(Z, "BIT zero width bit field");
	}
	if(p->as == AMOVL || p->as == AMOVW || p->as == AMOVB)
		asopt();
	if(debug['g'])
		print("%P\n", p);
	if(p->as == AGOK)
		diag(Z, "GOK in gopcode: %s", onames[o]);
	if(fidx != D_NONE)
		regfree(fidx);
	if(tidx != D_NONE)
		regfree(tidx);
}

void
asopt(void)
{
	long v;
	int g;
	Prog *q;

	/*
	 * mov $0, ...
	 * ==>
	 * clr , ...
	 */
	v = 0;
	if(p->from.type == D_CONST) {
		v = p->from.offset;
		if(v == 0) {
			p->from.type = D_NONE;
			if(p->as == AMOVL)
				p->as = ACLRL;
			if(p->as == AMOVW)
				p->as = ACLRW;
			if(p->as == AMOVB)
				p->as = ACLRB;
			return;
		}
	}
	/*
	 * mov ..., TOS
	 * ==>
	 * pea (...)
	 */
	if(p->as == AMOVL && p->to.type == D_TOS && p->from.index == D_NONE)
	switch(p->from.type) {
	case D_CONST:
		p->from.type |= I_INDIR;
		p->to = p->from;
		p->from = zprog.from;
		p->as = APEA;
		return;

	case I_ADDR|D_EXTERN:
	case I_ADDR|D_STATIC:
		p->from.type &= ~I_ADDR;
		p->to = p->from;
		p->from = zprog.from;
		p->as = APEA;
		return;
	}
	/*
	 * movL $Qx, ...
	 * ==>
	 * movL $Qx,R
	 * movL R, ...
	 */
	if(p->as == AMOVL && p->from.type == D_CONST)
	if(v >= -128 && v < 128)
	if(p->to.type < D_R0 || p->to.type >= D_R0+NREG) {
		g = regalloc(types[TLONG], D_NONE);
		q = p;
		nextpc();
		p->as = AMOVL;
		p->from.type = g;
		p->to = q->to;
		q->to = p->from;
		regfree(g);
		if(debug['g'])
			print("%P\n", q);
		return;
	}
}

void
gbranch(int o)
{
	int a;

	a = ABNE;
	switch(o) {
	case ORETURN: a = ARTS; break;
	case OGOTO: a = ABRA; break;
	case OEQ: a = ABEQ; break;
	case ONE: a = ABNE; break;
	case OLE: a = ABLE; break;
	case OLS: a = ABLS; break;
	case OLT: a = ABLT; break;
	case OLO: a = ABCS; break;
	case OGE: a = ABGE; break;
	case OHS: a = ABCC; break;
	case OGT: a = ABGT; break;
	case OHI: a = ABHI; break;
	case OBIT: a = ABCS; break;
	case OCASE: a = ABCASE; break;
	}
	nextpc();
	p->from.type = D_NONE;
	p->to.type = D_NONE;
	p->as = a;
}

void
fpbranch(void)
{
	int a;

	a = p->as;
	switch(a) {
	case ABEQ: a = AFBEQ; break;
	case ABNE: a = AFBNE; break;
	case ABLE: a = AFBLE; break;
	case ABLT: a = AFBLT; break;
	case ABGE: a = AFBGE; break;
	case ABGT: a = AFBGT; break;
	}
	p->as = a;
}

void
patch(Prog *op, long pc)
{

	op->to.offset = pc;
	op->to.type = D_BRANCH;
}

void
gpseudo(int a, Sym *s, int g, long v)
{

	nextpc();
	if(a == ADATA)
		pc--;
	p->as = a;
	if(g == D_TREE)
		abort();	/* obsolete */
	p->to.type = g;
	p->to.offset = v;
	p->from.sym = s;
	p->from.type = D_EXTERN;
	if(s->class == CSTATIC)
		p->from.type = D_STATIC;
}

void
gpseudotree(int a, Sym *s, Node *n)
{
	nextpc();
	if(a == ADATA)
		pc--;
	p->as = a;
	naddr(n, &p->to, D_NONE);
	p->from.sym = s;
	p->from.type = D_EXTERN;
	if(s->class == CSTATIC)
		p->from.type = D_STATIC;
}

long
exreg(Type *t)
{
	long o;

	if(typechl[t->etype]) {
		if(exregoffset <= 5)
			return 0;
		o = exregoffset + D_R0;
		exregoffset--;
		return o;
	}
	if(t->etype == TIND) {
		if(exaregoffset <= 3)
			return 0;
		o = exaregoffset + D_A0;
		exaregoffset--;
		return o;
	}
	if(typefd[t->etype]) {
		if(exfregoffset <= 5)
			return 0;
		o = exfregoffset + D_F0;
		exfregoffset--;
		return o;
	}
	return 0;
}

schar	ewidth[NTYPE] =
{
	-1,		/* [TXXX] */
	SZ_CHAR,	/* [TCHAR] */
	SZ_CHAR,	/* [TUCHAR] */
	SZ_SHORT,	/* [TSHORT] */
	SZ_SHORT,	/* [TUSHORT] */
	SZ_INT,		/* [TINT] */
	SZ_INT,		/* [TUINT] */
	SZ_LONG,	/* [TLONG] */
	SZ_LONG,	/* [TULONG] */
	SZ_VLONG,	/* [TVLONG] */
	SZ_VLONG,	/* [TUVLONG] */
	SZ_FLOAT,	/* [TFLOAT] */
	SZ_DOUBLE,	/* [TDOUBLE] */
	SZ_IND,		/* [TIND] */
	0,		/* [TFUNC] */
	-1,		/* [TARRAY] */
	0,		/* [TVOID] */
	-1,		/* [TSTRUCT] */
	-1,		/* [TUNION] */
	SZ_INT,		/* [TENUM] */
};
long	ncast[NTYPE] =
{
	0,				/* [TXXX] */
	BCHAR|BUCHAR,			/* [TCHAR] */
	BCHAR|BUCHAR,			/* [TUCHAR] */
	BSHORT|BUSHORT,			/* [TSHORT] */
	BSHORT|BUSHORT,			/* [TUSHORT] */
	BINT|BUINT|BLONG|BULONG|BIND,	/* [TINT] */
	BINT|BUINT|BLONG|BULONG|BIND,	/* [TUINT] */
	BINT|BUINT|BLONG|BULONG|BIND,	/* [TLONG] */
	BINT|BUINT|BLONG|BULONG|BIND,	/* [TULONG] */
	BVLONG|BUVLONG,			/* [TVLONG] */
	BVLONG|BUVLONG,			/* [TUVLONG] */
	BFLOAT,				/* [TFLOAT] */
	BDOUBLE,			/* [TDOUBLE] */
	BLONG|BULONG|BIND,		/* [TIND] */
	0,				/* [TFUNC] */
	0,				/* [TARRAY] */
	0,				/* [TVOID] */
	BSTRUCT,			/* [TSTRUCT] */
	BUNION,				/* [TUNION] */
	0,				/* [TENUM] */
};
