#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] */
};