#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; imovas = 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; ilink = tint; } ewidth[TENUM] = ewidth[TINT]; types[TENUM]->width = ewidth[TENUM]; suround = SU_ALLIGN; supad = SU_PAD; 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; itype->width = nstring; symstatic->type->width = nstatic; symrathole->type->width = nrathole; for(i=0; ilink) { 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][TLONG] = al; opxt[i][TULONG] = al; opxt[i][TIND] = al; opxt[i][TFLOAT] = af; opxt[i][TDOUBLE] = ad; } Prog* prg(void) { Prog *p; ALLOC(p, Prog); *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->u0.s0.nright); n = n->u0.s0.nleft; 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->u0.s0.nleft, a, x); goto noadd; case OREGISTER: a->sym = S; a->type = n->u0.s2.nreg; a->u0.s0.offset = n->u0.s2.noffset; a->u0.s0.displace = 0; break; case ONAME: a->etype = n->etype; a->u0.s0.displace = 0; a->sym = n->sym; a->u0.s0.offset = n->u0.s2.noffset; 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->u0.s0.nleft, a, x); switch(n->u0.s0.nleft->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->u0.s0.displace = 0; if(typefd[n->type->etype]) { a->type = D_FCONST; a->u0.dval = n->u0.nfconst; break; } a->type = D_CONST; a->u0.s0.offset = n->u0.nvconst; break; case OADD: l = n->u0.s0.nleft; if(l->addable == 20) { v = l->u0.nvconst; naddr(n->u0.s0.nright, a, x); goto add; } l = n->u0.s0.nright; if(l->addable == 20) { v = l->u0.nvconst; naddr(n->u0.s0.nleft, a, x); goto add; } goto bad; noadd: v = 0; add: switch(n->addable) { default: goto bad; case 2: a->u0.s0.displace += v; break; case 21: a->type &= D_MASK; a->type |= I_INDIR; break; case 1: case 12: a->u0.s0.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->u0.s0.nleft, 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= D_R0 && g < D_R0+NREG) { regused[g-D_R0]++; return g; } for(g=0; g= D_A0 && g < D_A0+NREG) { aregused[g-D_A0]++; return g; } for(g=0; 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.u0.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->u0.s0.nright, fidx, f->u0.s0.nright); } } tidx = D_NONE; if(gt == D_TREE) { if(t->op == OINDEX) { v = argoff; tidx = regalloc(types[TIND], tidx); cgen(t->u0.s0.nright, tidx, t->u0.s0.nright); 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.u0.s0.offset = (long)f; if(typefd[i]) { p->from.type = D_FCONST; p->from.u0.dval = (long)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.u0.s0.offset = (long)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.u0.s0.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.u0.s0.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) { p->to.type = g; p->to.u0.s0.offset = v; } else naddr((Node*)v, &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[XTYPE] = { -1, /* TXXX */ SZ_CHAR, SZ_CHAR, /* TCHAR TUCHAR */ SZ_SHORT, SZ_SHORT, /* TSHORT TUSHORT */ SZ_LONG, SZ_LONG, /* TLONG TULONG */ SZ_VLONG, SZ_VLONG, /* TVLONG TUVLONG */ SZ_FLOAT, SZ_DOUBLE, /* TFLOAT TDOUBLE */ SZ_IND, 0, /* TIND TFUNC */ -1, 0, /* TARRAY TVOID */ -1, -1, /* TSTRUCT TUNION */ -1 /* TENUM */ }; long ncast[XTYPE] = { /* TXXX */ 0, /* TCHAR */ BCHAR|BUCHAR, /* TUCHAR */ BCHAR|BUCHAR, /* TSHORT */ BSHORT|BUSHORT, /* TUSHORT */ BSHORT|BUSHORT, /* TLONG */ BLONG|BULONG|BIND, /* TULONG */ BLONG|BULONG|BIND, /* TVLONG */ BVLONG|BUVLONG, /* TUVLONG */ BVLONG|BUVLONG, /* TFLOAT */ BFLOAT, /* TDOUBLE */ BDOUBLE, /* TIND */ BLONG|BULONG|BIND, /* TFUNC */ 0, /* TARRAY */ 0, /* TVOID */ 0, /* TSTRUCT */ BSTRUCT, /* TUNION */ BUNION, /* TENUM */ 0, };