ref: d4bc9052beb3305d64a353a16641740380eb87af
dir: /sys/src/cmd/2c/txt.c/
#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] */ };