#include "gc.h" static int resvreg[nelem(reg)]; static void gopcode64(int, Node*, Node*, Node*); static void gori64(int, Node*, Node*, Node*); static void gandi64(int, Node*, Node*, Node*); void ginit(void) { Type *t; thechar = 'q'; thestring = "power"; exregoffset = REGEXT; exfregoffset = FREGEXT; newvlongcode = 1; listinit(); nstring = 0; mnstring = 0; nrathole = 0; pc = 0; breakpc = -1; continpc = -1; cases = C; firstp = P; lastp = P; tfield = types[TLONG]; typeswitch = typechlv; zprog.link = P; zprog.as = AGOK; zprog.reg = NREG; zprog.from.type = D_NONE; zprog.from.name = D_NONE; zprog.from.reg = NREG; zprog.from3 = zprog.from; zprog.to = zprog.from; regnode.op = OREGISTER; regnode.class = CEXREG; regnode.reg = 0; regnode.complex = 0; regnode.addable = 11; regnode.type = types[TLONG]; constnode.op = OCONST; constnode.class = CXXX; constnode.complex = 0; constnode.addable = 20; constnode.type = types[TLONG]; fconstnode.op = OCONST; fconstnode.class = CXXX; fconstnode.complex = 0; fconstnode.addable = 20; fconstnode.type = types[TDOUBLE]; nodsafe = new(ONAME, Z, Z); nodsafe->sym = slookup(".safe"); nodsafe->type = types[TINT]; nodsafe->etype = types[TINT]->etype; nodsafe->class = CAUTO; complex(nodsafe); t = typ(TARRAY, types[TCHAR]); symrathole = slookup(".rathole"); symrathole->class = CGLOBL; symrathole->type = t; nodrat = new(ONAME, Z, Z); nodrat->sym = symrathole; nodrat->type = types[TIND]; nodrat->etype = TVOID; nodrat->class = CGLOBL; complex(nodrat); nodrat->type = t; com64init(); memset(reg, 0, sizeof(reg)); reg[REGZERO] = 1; /* don't use */ reg[REGTMP] = 1; reg[FREGCVI+NREG] = 1; reg[FREGZERO+NREG] = 1; reg[FREGHALF+NREG] = 1; reg[FREGONE+NREG] = 1; reg[FREGTWO+NREG] = 1; memmove(resvreg, reg, sizeof(reg)); } void gclean(void) { int i; Sym *s; for(i=0; itype->width = nstring; 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, nodconst(s->type->width)); } nextpc(); p->as = AEND; outcode(); } void nextpc(void) { p = alloc(sizeof(*p)); *p = zprog; p->lineno = nearln; pc++; if(firstp == P) { firstp = p; lastp = p; return; } lastp->link = p; lastp = p; } void gargs(Node *n, Node *tn1, Node *tn2) { long regs; Node fnxargs[20], *fnxp; regs = cursafe; fnxp = fnxargs; garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */ curarg = 0; fnxp = fnxargs; garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */ cursafe = regs; } void garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp) { Node nod; if(n == Z) return; if(n->op == OLIST) { garg1(n->left, tn1, tn2, f, fnxp); garg1(n->right, tn1, tn2, f, fnxp); return; } if(f == 0) { if(n->complex >= FNX) { regsalloc(*fnxp, n); nod = znode; nod.op = OAS; nod.left = *fnxp; nod.right = n; nod.type = n->type; cgen(&nod, Z); (*fnxp)++; } return; } if(typesuv[n->type->etype]) { regaalloc(tn2, n); if(n->complex >= FNX) { cgen(*fnxp, tn2); (*fnxp)++; } else cgen(n, tn2); return; } if(REGARG && curarg == 0 && typechlp[n->type->etype]) { regaalloc1(tn1, n); if(n->complex >= FNX) { cgen(*fnxp, tn1); (*fnxp)++; } else cgen(n, tn1); return; } if(vconst(n) == 0) { regaalloc(tn2, n); gopcode(OAS, n, Z, tn2); return; } regalloc(tn1, n, Z); if(n->complex >= FNX) { cgen(*fnxp, tn1); (*fnxp)++; } else cgen(n, tn1); regaalloc(tn2, n); gopcode(OAS, tn1, Z, tn2); regfree(tn1); } Node* nod32const(vlong v) { constnode.vconst = v & MASK(32); return &constnode; } Node* nodconst(long v) { constnode.vconst = v; return &constnode; } Node* nodfconst(double d) { fconstnode.fconst = d; return &fconstnode; } void nodreg(Node *n, Node *nn, int reg) { *n = regnode; n->reg = reg; n->type = nn->type; n->lineno = nn->lineno; } void regret(Node *n, Node *nn) { int r; r = REGRET; if(typefd[nn->type->etype]) r = FREGRET+NREG; nodreg(n, nn, r); reg[r]++; } void regalloc(Node *n, Node *tn, Node *o) { int i, j; static int lasti; switch(tn->type->etype) { case TCHAR: case TUCHAR: case TSHORT: case TUSHORT: case TINT: case TUINT: case TLONG: case TULONG: case TIND: if(o != Z && o->op == OREGISTER) { i = o->reg; if(i > 0 && i < NREG) goto out; } j = lasti + REGRET+1; for(i=REGRET+1; i= NREG) j = REGRET+1; if(reg[j] == 0) { i = j; goto out; } j++; } diag(tn, "out of fixed registers"); goto err; case TFLOAT: case TDOUBLE: if(o != Z && o->op == OREGISTER) { i = o->reg; if(i >= NREG && i < NREG+NREG) goto out; } j = lasti + NREG; for(i=NREG; i= NREG+NREG) j = NREG; if(reg[j] == 0) { i = j; goto out; } j++; } diag(tn, "out of float registers"); goto err; case TVLONG: case TUVLONG: n->op = OREGPAIR; n->complex = 0; /* already in registers */ n->addable = 11; n->type = tn->type; n->lineno = nearln; n->left = alloc(sizeof(Node)); n->right = alloc(sizeof(Node)); if(o != Z && o->op == OREGPAIR) { regalloc(n->left, ®node, o->left); regalloc(n->right, ®node, o->right); } else { regalloc(n->left, ®node, Z); regalloc(n->right, ®node, Z); } n->right->type = types[TULONG]; if(tn->type->etype == TUVLONG) n->left->type = types[TULONG]; /* TO DO: is this a bad idea? */ return; } diag(tn, "unknown type in regalloc: %T", tn->type); err: i = 0; out: if(i) reg[i]++; lasti++; if(lasti >= 5) lasti = 0; nodreg(n, tn, i); } void regialloc(Node *n, Node *tn, Node *o) { Node nod; nod = *tn; nod.type = types[TIND]; regalloc(n, &nod, o); } void regfree(Node *n) { int i; if(n->op == OREGPAIR) { regfree(n->left); regfree(n->right); return; } i = 0; if(n->op != OREGISTER && n->op != OINDREG) goto err; i = n->reg; if(i < 0 || i >= sizeof(reg)) goto err; if(reg[i] <= 0) goto err; reg[i]--; return; err: diag(n, "error in regfree: %d [%d]", i, reg[i]); prtree(n, "regfree"); } void regsalloc(Node *n, Node *nn) { cursafe = align(cursafe+stkoff, nn->type, Aaut3)-stkoff; maxargsafe = maxround(maxargsafe, cursafe+curarg); // if(nn->type->etype == TDOUBLE || nn->type->etype == TVLONG){ // extern int hasdoubled; // fprint(2, "stkoff=%ld cursafe=%ld curarg=%ld %d\n", stkoff, cursafe, curarg, hasdoubled); // } *n = *nodsafe; n->xoffset = -(stkoff + cursafe); n->type = nn->type; n->etype = nn->type->etype; n->lineno = nn->lineno; } void regaalloc1(Node *n, Node *nn) { nodreg(n, nn, REGARG); reg[REGARG]++; curarg = align(curarg, nn->type, Aarg1); curarg = align(curarg, nn->type, Aarg2); maxargsafe = maxround(maxargsafe, cursafe+curarg); } void regaalloc(Node *n, Node *nn) { curarg = align(curarg, nn->type, Aarg1); *n = *nn; n->op = OINDREG; n->reg = REGSP; n->xoffset = curarg + SZ_LONG; n->complex = 0; n->addable = 20; curarg = align(curarg, nn->type, Aarg2); maxargsafe = maxround(maxargsafe, cursafe+curarg); } void regind(Node *n, Node *nn) { if(n->op != OREGISTER) { diag(n, "regind not OREGISTER"); return; } n->op = OINDREG; n->type = nn->type; } void raddr(Node *n, Prog *p) { Adr a; naddr(n, &a); if(R0ISZERO && a.type == D_CONST && a.offset == 0) { a.type = D_REG; a.reg = REGZERO; } if(a.type != D_REG && a.type != D_FREG) { if(n) diag(n, "bad in raddr: %O", n->op); else diag(n, "bad in raddr: "); p->reg = NREG; } else p->reg = a.reg; } void naddr(Node *n, Adr *a) { long v; a->type = D_NONE; if(n == Z) return; switch(n->op) { default: bad: diag(n, "bad in naddr: %O", n->op); break; case OREGISTER: a->type = D_REG; a->sym = S; a->reg = n->reg; if(a->reg >= NREG) { a->type = D_FREG; a->reg -= NREG; } break; case OIND: naddr(n->left, a); a->offset += n->xoffset; /* little hack for reglcgenv */ if(a->type == D_REG) { a->type = D_OREG; break; } if(a->type == D_CONST) { a->type = D_OREG; break; } goto bad; case OINDREG: a->type = D_OREG; a->sym = S; a->offset = n->xoffset; a->reg = n->reg; break; case ONAME: a->etype = n->etype; a->type = D_OREG; a->name = D_STATIC; a->sym = n->sym; a->offset = n->xoffset; if(n->class == CSTATIC) break; if(n->class == CEXTERN || n->class == CGLOBL) { a->name = D_EXTERN; break; } if(n->class == CAUTO) { a->name = D_AUTO; break; } if(n->class == CPARAM) { a->name = D_PARAM; break; } goto bad; case OCONST: a->sym = S; a->reg = NREG; if(typefd[n->type->etype]) { a->type = D_FCONST; a->dval = n->fconst; } else { a->type = D_CONST; a->offset = n->vconst; } break; case OADDR: naddr(n->left, a); if(a->type == D_OREG) { a->type = D_CONST; break; } goto bad; case OADD: if(n->left->op == OCONST) { naddr(n->left, a); v = a->offset; naddr(n->right, a); } else { naddr(n->right, a); v = a->offset; naddr(n->left, a); } a->offset += v; break; } } void gloadhi(Node *f, Node *t, int c) { Type *ot; if(f->op == OCONST){ f = nodconst((long)(f->vconst>>32)); if(c==1 && sconst(f) || c==2 && uconst(f)){ if(t->op == OREGISTER) regfree(t); *t = *f; return; } } if(f->op == OREGPAIR) { gmove(f->left, t); return; } ot = f->type; f->type = types[TLONG]; gmove(f, t); f->type = ot; } void gloadlo(Node *f, Node *t, int c) { Type *ot; if(f->op == OCONST){ f = nodconst((long)f->vconst); if(c && uconst(f)){ if(t->op == OREGISTER) regfree(t); *t = *f; return; } } if(f->op == OREGPAIR) { gmove(f->right, t); return; } ot = f->type; f->type = types[TLONG]; f->xoffset += SZ_LONG; if(0){ prtree(f, "gloadlo f"); prtree(t, "gloadlo t"); } gmove(f, t); f->xoffset -= SZ_LONG; f->type = ot; } void fop(int as, int f1, int f2, Node *t) { Node nod1, nod2, nod3; nodreg(&nod1, t, NREG+f1); nodreg(&nod2, t, NREG+f2); regalloc(&nod3, t, t); gopcode(as, &nod1, &nod2, &nod3); gmove(&nod3, t); regfree(&nod3); } void gmove(Node *f, Node *t) { int ft, tt, a; Node nod, fxc0, fxc1, fxc2, fxrat; Prog *p1; double d; ft = f->type->etype; tt = t->type->etype; if(ft == TDOUBLE && f->op == OCONST) { d = f->fconst; if(d == 0.0) { a = FREGZERO; goto ffreg; } if(d == 0.5) { a = FREGHALF; goto ffreg; } if(d == 1.0) { a = FREGONE; goto ffreg; } if(d == 2.0) { a = FREGTWO; goto ffreg; } if(d == -.5) { fop(OSUB, FREGHALF, FREGZERO, t); return; } if(d == -1.0) { fop(OSUB, FREGONE, FREGZERO, t); return; } if(d == -2.0) { fop(OSUB, FREGTWO, FREGZERO, t); return; } if(d == 1.5) { fop(OADD, FREGONE, FREGHALF, t); return; } if(d == 2.5) { fop(OADD, FREGTWO, FREGHALF, t); return; } if(d == 3.0) { fop(OADD, FREGTWO, FREGONE, t); return; } } if(ft == TFLOAT && f->op == OCONST) { d = f->fconst; if(d == 0) { a = FREGZERO; ffreg: nodreg(&nod, f, NREG+a); gmove(&nod, t); return; } } if((ft == TVLONG || ft == TUVLONG) && f->op == OCONST && t->op == OREGPAIR) { if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ gmove(nod32const(f->vconst>>32), t->left); else gmove(nod32const(f->vconst), t->left); if(align(0, types[TCHAR], Aarg1)) /* isbigendian */ gmove(nod32const(f->vconst), t->right); else gmove(nod32const(f->vconst>>32), t->right); return; } /* * a load -- * put it into a register then * worry what to do with it. */ if(f->op == ONAME || f->op == OINDREG || f->op == OIND) { switch(ft) { default: a = AMOVW; break; case TFLOAT: a = AFMOVS; break; case TDOUBLE: a = AFMOVD; break; case TCHAR: a = AMOVB; break; case TUCHAR: a = AMOVBZ; break; case TSHORT: a = AMOVH; break; case TUSHORT: a = AMOVHZ; break; } if(typev[ft]) { if(typev[tt]) { regalloc(&nod, f, t); /* low order first, because its value will be used first */ f->xoffset += SZ_LONG; gins(AMOVW, f, nod.right); f->xoffset -= SZ_LONG; gins(AMOVW, f, nod.left); } else { /* assumed not float or double */ regalloc(&nod, ®node, t); f->xoffset += SZ_LONG; gins(AMOVW, f, &nod); f->xoffset -= SZ_LONG; } } else { regalloc(&nod, f, t); gins(a, f, &nod); } gmove(&nod, t); regfree(&nod); return; } /* * a store -- * put it into a register then * store it. */ if(t->op == ONAME || t->op == OINDREG || t->op == OIND) { switch(tt) { default: a = AMOVW; break; case TUCHAR: a = AMOVBZ; break; case TCHAR: a = AMOVB; break; case TUSHORT: a = AMOVHZ; break; case TSHORT: a = AMOVH; break; case TFLOAT: a = AFMOVS; break; case TDOUBLE: a = AFMOVD; break; } if(R0ISZERO && !typefd[ft] && vconst(f) == 0) { gins(a, f, t); if(typev[tt]) { t->xoffset += SZ_LONG; gins(a, f, t); t->xoffset -= SZ_LONG; } return; } if(ft == tt) regalloc(&nod, t, f); else regalloc(&nod, t, Z); gmove(f, &nod); if(typev[tt]) { t->xoffset += SZ_LONG; gins(a, nod.right, t); t->xoffset -= SZ_LONG; gins(a, nod.left, t); } else gins(a, &nod, t); regfree(&nod); return; } /* * type x type cross table */ a = AGOK; switch(ft) { case TDOUBLE: case TFLOAT: switch(tt) { case TDOUBLE: a = AFMOVD; if(ft == TFLOAT) a = AFMOVS; /* AFMOVSD */ break; case TFLOAT: a = AFRSP; if(ft == TFLOAT) a = AFMOVS; break; case TINT: case TUINT: case TLONG: case TULONG: case TIND: case TSHORT: case TUSHORT: case TCHAR: case TUCHAR: /* BUG: not right for unsigned long */ regalloc(&nod, f, Z); /* should be type float */ regsalloc(&fxrat, &fconstnode); gins(AFCTIWZ, f, &nod); gins(AFMOVD, &nod, &fxrat); regfree(&nod); fxrat.type = nodrat->type; fxrat.etype = nodrat->etype; fxrat.xoffset += 4; gins(AMOVW, &fxrat, t); gmove(t, t); return; } break; case TINT: case TUINT: case TLONG: case TULONG: case TIND: switch(tt) { case TDOUBLE: case TFLOAT: goto fxtofl; case TINT: case TUINT: case TLONG: case TULONG: case TIND: case TSHORT: case TUSHORT: case TCHAR: case TUCHAR: a = AMOVW; break; } break; case TSHORT: switch(tt) { case TDOUBLE: case TFLOAT: goto fxtofl; case TINT: case TUINT: case TLONG: case TULONG: case TIND: a = AMOVH; break; case TSHORT: case TUSHORT: case TCHAR: case TUCHAR: a = AMOVW; break; } break; case TUSHORT: switch(tt) { case TDOUBLE: case TFLOAT: goto fxtofl; case TINT: case TUINT: case TLONG: case TULONG: case TIND: a = AMOVHZ; break; case TSHORT: case TUSHORT: case TCHAR: case TUCHAR: a = AMOVW; break; } break; case TCHAR: switch(tt) { case TDOUBLE: case TFLOAT: goto fxtofl; case TINT: case TUINT: case TLONG: case TULONG: case TIND: case TSHORT: case TUSHORT: a = AMOVB; break; case TCHAR: case TUCHAR: a = AMOVW; break; } break; case TUCHAR: switch(tt) { case TDOUBLE: case TFLOAT: fxtofl: /* * rat[0] = 0x43300000; rat[1] = f^0x80000000; * t = *(double*)rat - FREGCVI; * is-unsigned(t) => if(t<0) t += 2^32; * could be streamlined for int-to-float */ regalloc(&fxc0, f, Z); regalloc(&fxc2, f, Z); regsalloc(&fxrat, &fconstnode); /* should be type float */ gins(AMOVW, nodconst(0x43300000L), &fxc0); gins(AMOVW, f, &fxc2); gins(AMOVW, &fxc0, &fxrat); gins(AXOR, nodconst(0x80000000L), &fxc2); fxc1 = fxrat; fxc1.type = nodrat->type; fxc1.etype = nodrat->etype; fxc1.xoffset += SZ_LONG; gins(AMOVW, &fxc2, &fxc1); regfree(&fxc2); regfree(&fxc0); regalloc(&nod, t, t); /* should be type float */ gins(AFMOVD, &fxrat, &nod); nodreg(&fxc1, t, NREG+FREGCVI); gins(AFSUB, &fxc1, &nod); a = AFMOVD; if(tt == TFLOAT) a = AFRSP; gins(a, &nod, t); regfree(&nod); if(ft == TULONG) { regalloc(&nod, t, Z); if(tt == TFLOAT) { gins(AFCMPU, t, Z); p->to.type = D_FREG; p->to.reg = FREGZERO; gins(ABGE, Z, Z); p1 = p; gins(AFMOVS, nodfconst(4294967296.), &nod); gins(AFADDS, &nod, t); } else { gins(AFCMPU, t, Z); p->to.type = D_FREG; p->to.reg = FREGZERO; gins(ABGE, Z, Z); p1 = p; gins(AFMOVD, nodfconst(4294967296.), &nod); gins(AFADD, &nod, t); } patch(p1, pc); regfree(&nod); } return; case TINT: case TUINT: case TLONG: case TULONG: case TIND: case TSHORT: case TUSHORT: a = AMOVBZ; break; case TCHAR: case TUCHAR: a = AMOVW; break; } break; case TVLONG: case TUVLONG: switch(tt) { case TVLONG: case TUVLONG: a = AMOVW; break; } break; } if(a == AGOK) diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type); if(a == AMOVW || a == AFMOVS || a == AFMOVD) if(samaddr(f, t)) return; if(typev[ft]) { if(f->op != OREGPAIR || t->op != OREGPAIR) diag(Z, "bad vlong in gmove (%O->%O)", f->op, t->op); gins(a, f->left, t->left); gins(a, f->right, t->right); } else gins(a, f, t); } void gins(int a, Node *f, Node *t) { nextpc(); p->as = a; if(f != Z) naddr(f, &p->from); if(t != Z) naddr(t, &p->to); if(debug['g']) print("%P\n", p); } void gins3(int a, Node *f1, Node *f2, Node *t) { Adr ta; nextpc(); p->as = a; if(f1 != Z) naddr(f1, &p->from); if(f2 != Z && (f2->op != OREGISTER || !samaddr(f2, t))) { ta = zprog.from; /* TO DO */ naddr(f2, &ta); p->reg = ta.reg; if(ta.type == D_CONST && ta.offset == 0) { if(R0ISZERO) p->reg = REGZERO; else diag(Z, "REGZERO in gins3 %A", a); }else if(ta.type == D_CONST) p->from3 = ta; } if(t != Z) naddr(t, &p->to); if(debug['g']) print("%P\n", p); } void gins4(int a, Node *f1, Node *f2, Node *f3, Node *t) { Adr ta; nextpc(); p->as = a; naddr(f1, &p->from); if(f2->op != OREGISTER && (f2->op != OCONST || vconst(f2) != 0)) diag(f2, "invalid gins4"); naddr(f2, &ta); p->reg = ta.reg; if(ta.type == D_CONST && ta.offset == 0) p->reg = REGZERO; naddr(f3, &p->from3); naddr(t, &p->to); if(debug['g']) print("%P\n", p); } void gopcode(int o, Node *f1, Node *f2, Node *t) { int a, et, uns; if(o == OAS) { gmove(f1, t); return; } et = TLONG; if(f1 != Z && f1->type != T) { if(f1->op == OCONST && t != Z && t->type != T) et = t->type->etype; else et = f1->type->etype; } if((typev[et] || t->type != T && typev[t->type->etype]) && o != OFUNC) { gopcode64(o, f1, f2, t); return; } uns = 0; a = AGOK; switch(o) { case OASADD: case OADD: a = AADD; if(et == TFLOAT) a = AFADDS; else if(et == TDOUBLE) a = AFADD; break; case OASSUB: case OSUB: a = ASUB; if(et == TFLOAT) a = AFSUBS; else if(et == TDOUBLE) a = AFSUB; break; case OASOR: case OOR: a = AOR; break; case OASAND: case OAND: a = AAND; if(f1->op == OCONST) a = AANDCC; break; case OASXOR: case OXOR: a = AXOR; break; case OASLSHR: case OLSHR: a = ASRW; break; case OASASHR: case OASHR: a = ASRAW; break; case OASASHL: case OASHL: a = ASLW; break; case OFUNC: a = ABL; break; case OASLMUL: case OLMUL: case OASMUL: case OMUL: if(et == TFLOAT) { a = AFMULS; break; } else if(et == TDOUBLE) { a = AFMUL; break; } a = AMULLW; break; case OASDIV: case ODIV: if(et == TFLOAT) { a = AFDIVS; break; } else if(et == TDOUBLE) { a = AFDIV; break; } a = ADIVW; break; case OASMOD: case OMOD: a = AREM; break; case OASLMOD: case OLMOD: a = AREMU; break; case OASLDIV: case OLDIV: a = ADIVWU; break; case OCOM: a = ANOR; break; case ONEG: a = ANEG; if(et == TFLOAT || et == TDOUBLE) a = AFNEG; break; case OEQ: a = ABEQ; if(t->op == OCONST && t->vconst >= (1<<15)) goto cmpu; goto cmp; case ONE: a = ABNE; if(t->op == OCONST && t->vconst >= (1<<15)) goto cmpu; goto cmp; case OLT: a = ABLT; goto cmp; case OLE: a = ABLE; goto cmp; case OGE: a = ABGE; goto cmp; case OGT: a = ABGT; goto cmp; case OLO: a = ABLT; goto cmpu; case OLS: a = ABLE; goto cmpu; case OHS: a = ABGE; goto cmpu; case OHI: a = ABGT; goto cmpu; cmpu: uns = 1; cmp: nextpc(); p->as = uns? ACMPU: ACMP; if(et == TFLOAT) p->as = AFCMPU; else if(et == TDOUBLE) p->as = AFCMPU; if(f1 != Z) naddr(f1, &p->from); if(t != Z) naddr(t, &p->to); if(f1 == Z || t == Z || f2 != Z) diag(Z, "bad cmp in gopcode %O", o); if(debug['g']) print("%P\n", p); f1 = Z; f2 = Z; t = Z; break; } if(a == AGOK) diag(Z, "bad in gopcode %O", o); gins3(a, f1, f2, t); } static void gopcode64(int o, Node *f1, Node *f2, Node *t) { int a1, a2; Node nod, nod1, nod2, sh; ulong m; Prog *p1; if(t->op != OREGPAIR || f2 != Z && f2->op != OREGPAIR) { diag(Z, "bad f2/dest in gopcode64 %O", o); return; } if(f1->op != OCONST && (typev[f1->type->etype] && f1->op != OREGPAIR || !typev[f1->type->etype] && f1->op != OREGISTER)) { diag(Z, "bad f1[%O] in gopcode64 %O", f1->op, o); return; } /* a1 for low-order, a2 for high-order */ a1 = AGOK; a2 = AGOK; switch(o) { case OASADD: case OADD: if(f1->op == OCONST && sconst(f1)) { if(f2 == Z) f2 = t; gins3(AADDC, f1, f2->right, t->right); if((f1->vconst>>32) == 0) gins(AADDZE, f2->left, t->left); else if((f1->vconst>>32) == -1) gins(AADDME, f2->left, t->left); else diag(t, "odd vlong ADD: %lld", f1->vconst); return; } a1 = AADDC; a2 = AADDE; break; case OASSUB: case OSUB: a1 = ASUBC; a2 = ASUBE; break; case OASOR: case OOR: if(f1->op == OCONST) { gori64(AOR, f1, f2, t); return; } a1 = a2 = AOR; break; case OASAND: case OAND: if(f1->op == OCONST) { gandi64(AANDCC, f1, f2, t); return; } a1 = a2 = AAND; break; case OASXOR: case OXOR: if(f1->op == OCONST) { gori64(AXOR, f1, f2, t); return; } a1 = a2 = AXOR; break; case OASLSHR: case OLSHR: if(f2 == Z) f2 = t; if(f1->op == OCONST) { if(f1->vconst >= 32) { if(f1->vconst == 32) gmove(f2->left, t->right); else if(f1->vconst < 64) gins3(ASRW, nodconst(f1->vconst-32), f2->left, t->right); else gmove(nodconst(0), t->right); gmove(nodconst(0), t->left); return; } if(f1->vconst <= 0) { if(f2 != t) gmove(f2, t); return; } sh = *nodconst(32 - f1->vconst); m = 0xFFFFFFFFUL >> f1->vconst; gins4(ARLWNM, &sh, f2->right, nodconst(m), t->right); gins4(ARLWMI, &sh, f2->left, nodconst(~m), t->right); gins4(ARLWNM, &sh, f2->left, nodconst(m), t->left); return; } regalloc(&nod, ®node, Z); gins3(ASUBC, f1, nodconst(32), &nod); gins3(ASRW, f1, f2->right, t->right); regalloc(&nod1, ®node, Z); gins3(ASLW, &nod, f2->left, &nod1); gins(AOR, &nod1, t->right); gins3(AADD, nodconst(-32), f1, &nod); gins3(ASRW, &nod, f2->left, &nod1); gins(AOR, &nod1, t->right); gins3(ASRW, f1, f2->left, t->left); regfree(&nod); regfree(&nod1); return; case OASASHR: case OASHR: if(f2 == Z) f2 = t; if(f1->op == OCONST) { if(f1->vconst >= 32) { if(f1->vconst == 32) gmove(f2->left, t->right); else if(f1->vconst < 64) gins3(ASRAW, nodconst(f1->vconst-32), f2->left, t->right); gins3(ASRAW, nodconst(31), f2->left, t->left); if(f1->vconst >= 64) { gmove(t->left, t->right); return; } return; } if(f1->vconst <= 0) { if(f2 != t) gmove(f2, t); return; } sh = *nodconst(32 - f1->vconst); m = 0xFFFFFFFFUL >> f1->vconst; gins4(ARLWNM, &sh, f2->right, nodconst(m), t->right); gins4(ARLWMI, &sh, f2->left, nodconst(~m), t->right); gins3(ASRAW, &sh, f2->left, t->left); return; } regalloc(&nod, ®node, Z); gins3(ASUBC, f1, nodconst(32), &nod); gins3(ASRW, f1, f2->right, t->right); regalloc(&nod1, ®node, Z); gins3(ASLW, &nod, f2->left, &nod1); gins(AOR, &nod1, t->right); gins3(AADDCCC, nodconst(-32), f1, &nod); gins3(ASRAW, &nod, f2->left, &nod1); gins(ABLE, Z, Z); p1 = p; gins(AMOVW, &nod1, t->right); patch(p1, pc); gins3(ASRAW, f1, f2->left, t->left); regfree(&nod); regfree(&nod1); return; case OASASHL: case OASHL: if(f2 == Z) f2 = t; if(f1->op == OCONST) { if(f1->vconst >= 32) { if(f1->vconst == 32) gmove(f2->right, t->left); else if(f1->vconst >= 64) gmove(nodconst(0), t->left); else gins3(ASLW, nodconst(f1->vconst-32), f2->right, t->left); gmove(nodconst(0), t->right); return; } if(f1->vconst <= 0) { if(f2 != t) gmove(f2, t); return; } m = 0xFFFFFFFFUL << f1->vconst; gins4(ARLWNM, f1, f2->left, nodconst(m), t->left); gins4(ARLWMI, f1, f2->right, nodconst(~m), t->left); gins4(ARLWNM, f1, f2->right, nodconst(m), t->right); return; } regalloc(&nod, ®node, Z); gins3(ASUBC, f1, nodconst(32), &nod); gins3(ASLW, f1, f2->left, t->left); regalloc(&nod1, ®node, Z); gins3(ASRW, &nod, f2->right, &nod1); gins(AOR, &nod1, t->left); gins3(AADD, nodconst(-32), f1, &nod); gins3(ASLW, &nod, f2->right, &nod1); gins(AOR, &nod1, t->left); gins3(ASLW, f1, f2->right, t->right); regfree(&nod); regfree(&nod1); return; case OASLMUL: case OLMUL: case OASMUL: case OMUL: if(f2 == Z) f2 = t; regalloc(&nod, ®node, Z); gins3(AMULLW, f1->right, f2->right, &nod); /* lo(f2.low*f1.low) */ regalloc(&nod1, ®node, Z); gins3(AMULHWU, f1->right, f2->right, &nod1); /* hi(f2.low*f1.low) */ regalloc(&nod2, ®node, Z); gins3(AMULLW, f2->right, f1->left, &nod2); /* lo(f2.low*f1.high) */ gins(AADD, &nod2, &nod1); gins3(AMULLW, f1->right, f2->left, &nod2); /* lo(f2.high*f1.low) */ gins(AADD, &nod2, &nod1); regfree(&nod2); gmove(&nod, t->right); gmove(&nod1, t->left); regfree(&nod); regfree(&nod1); return; case OCOM: a1 = a2 = ANOR; break; case ONEG: gins3(ASUBC, t->right, nodconst(0), t->right); gins(ASUBZE, t->left, t->left); return; } if(a1 == AGOK || a2 == AGOK) diag(Z, "bad in gopcode64 %O", o); if(f1->op == OCONST) { if(f2 != Z & f2 != t) diag(Z, "bad const in gopcode64 %O", o); gins(a1, nod32const(f1->vconst), t->right); gins(a2, nod32const(f1->vconst>>32), t->left); } else { if(f2 != Z && f2 != t) { gins3(a1, f1->right, f2->right, t->right); gins3(a2, f1->left, f2->left, t->left); } else { gins(a1, f1->right, t->right); gins(a2, f1->left, t->left); } } } samaddr(Node *f, Node *t) { if(f->op != t->op) return 0; switch(f->op) { case OREGISTER: if(f->reg != t->reg) break; return 1; case OREGPAIR: return samaddr(f->left, t->left) && samaddr(f->right, t->right); } return 0; } static void gori64(int a, Node *f1, Node *f2, Node *t) { ulong lo, hi; if(f2 == Z) f2 = t; lo = f1->vconst & MASK(32); hi = (f1->vconst >> 32) & MASK(32); if(lo & 0xFFFF) gins3(a, nodconst(lo & 0xFFFF), f2->right, t->right); if((lo >> 16) != 0) gins3(a, nodconst(lo & 0xFFFF0000UL), f2->right, t->right); if(hi & 0xFFFF) gins3(a, nodconst(hi & 0xFFFF), f2->left, t->left); if((hi >> 16) != 0) gins3(a, nodconst(hi & 0xFFFF0000UL), f2->left, t->left); } static void gandi64(int a, Node *f1, Node *f2, Node *t) { ulong lo, hi; if(f2 == Z) f2 = t; lo = f1->vconst & MASK(32); hi = (f1->vconst >> 32) & MASK(32); if(lo == 0) gins(AMOVW, nodconst(0), t->right); else gins3(a, nodconst(lo), f2->right, t->right); if(hi == 0) gins(AMOVW, nodconst(0), t->left); else gins3(a, nodconst(hi), f2->left, t->left); } void gbranch(int o) { int a; a = AGOK; switch(o) { case ORETURN: a = ARETURN; break; case OGOTO: a = ABR; break; } nextpc(); if(a == AGOK) { diag(Z, "bad in gbranch %O", o); nextpc(); } p->as = a; } void patch(Prog *op, long pc) { op->to.offset = pc; op->to.type = D_BRANCH; } void gpseudo(int a, Sym *s, Node *n) { nextpc(); p->as = a; p->from.type = D_OREG; p->from.sym = s; if(a == ATEXT) p->reg = (profileflg ? 0 : NOPROF); p->from.name = D_EXTERN; if(s->class == CSTATIC) p->from.name = D_STATIC; naddr(n, &p->to); if(a == ADATA || a == AGLOBL) pc--; } int sval(long v) { if(v >= -(1<<15) && v < (1<<15)) return 1; return 0; } int sconst(Node *n) { vlong vv; if(n->op == OCONST) { if(!typefd[n->type->etype]) { vv = n->vconst; if(vv >= -(((vlong)1)<<15) && vv < (((vlong)1)<<15)) return 1; } } return 0; } int uconst(Node *n) { vlong vv; if(n->op == OCONST) { if(!typefd[n->type->etype]) { vv = n->vconst; if(vv >= 0 && vv < (((vlong)1)<<16)) return 1; } } return 0; } long exreg(Type *t) { long o; if(typechlp[t->etype]) { if(exregoffset <= 3) return 0; o = exregoffset; exregoffset--; return o; } if(typefd[t->etype]) { if(exfregoffset <= 16) return 0; o = exfregoffset + NREG; 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] */ };