void usedset(Node *n, int o) { if(n->op == OLIST) { usedset(n->left, o); usedset(n->right, o); return; } complex(n); if(o == OPREFETCH) { gprefetch(n); return; } switch(n->op) { case OADDR: /* volatile */ gins(ANOP, n, Z); break; case ONAME: if(o == OSET) gins(ANOP, Z, n); else gins(ANOP, n, Z); break; } }
void smod2(int32 c, int v, Node *l, Node *n) { Node nod; if(c == 1) { zeroregm(n); return; } sext(&nod, n, l); if(v == 0) { zeroregm(n); gins(AXORL, &nod, n); gins(ASUBL, &nod, n); } else if(v > 1) { gins(AANDL, nodconst((1 << v) - 1), &nod); gins(AADDL, &nod, n); gins(AANDL, nodconst((1 << v) - 1), n); gins(ASUBL, &nod, n); } else { gins(AANDL, nodconst(1), n); gins(AXORL, &nod, n); gins(ASUBL, &nod, n); } regfree(&nod); }
void sext(Node *d, Node *s, Node *l) { if(s->reg == D_AX && !nodreg(d, Z, D_DX)) { reg[D_DX]++; gins(ACDQ, Z, Z); } else { regalloc(d, l, Z); gins(AMOVL, s, d); gins(ASARL, nodconst(31), d); } }
void noretval(int n) { if(n & 1) { gins(ANOP, Z, Z); p->to.type = D_REG; p->to.reg = REGRET; } if(n & 2) { gins(ANOP, Z, Z); p->to.type = D_FREG; p->to.reg = FREGRET; } }
void gdata(Node *nam, Node *nr, int wid) { Prog *p; vlong v; if(nr->op == OLITERAL) { switch(nr->val.ctype) { case CTCPLX: gdatacomplex(nam, nr->val.u.cval); return; case CTSTR: gdatastring(nam, nr->val.u.sval); return; } } if(wid == 8 && is64(nr->type)) { v = mpgetfix(nr->val.u.xval); p = gins(ADATA, nam, nodintconst(v)); p->reg = 4; p = gins(ADATA, nam, nodintconst(v>>32)); p->reg = 4; p->from.offset += 4; return; }
void gdatastring(Node *nam, Strlit *sval) { Prog *p; Node nod1; p = gins(ADATA, nam, N); datastring(sval->s, sval->len, &p->to); p->from.scale = types[tptr]->width; p->to.index = p->to.type; p->to.type = D_ADDR; //print("%P\n", p); nodconst(&nod1, types[TINT], sval->len); p = gins(ADATA, nam, &nod1); p->from.scale = widthint; p->from.offset += widthptr; }
void gdatacomplex(Node *nam, Mpcplx *cval) { Prog *p; int w; w = cplxsubtype(nam->type->etype); w = types[w]->width; p = gins(ADATA, nam, N); p->from.scale = w; p->to.type = D_FCONST; p->to.u.dval = mpgetflt(&cval->real); p = gins(ADATA, nam, N); p->from.scale = w; p->from.offset += w; p->to.type = D_FCONST; p->to.u.dval = mpgetflt(&cval->imag); }
void gdata(Node *nam, Node *nr, int wid) { Prog *p; vlong v; if(wid == 8 && is64(nr->type)) { v = mpgetfix(nr->val.u.xval); p = gins(ADATA, nam, nodintconst(v)); p->reg = 4; p = gins(ADATA, nam, nodintconst(v>>32)); p->reg = 4; p->from.offset += 4; return; }
int dsname(Sym *s, int off, char *t, int n) { Prog *p; p = gins(ADATA, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; p->from.offset = off; p->from.scale = n; p->from.sym = linksym(s); p->to.type = D_SCONST; p->to.index = D_NONE; memmove(p->to.u.sval, t, n); return off + n; }
void gdata(Node *nam, Node *nr, int wid) { Prog *p; if(nr->op == OLITERAL) { switch(nr->val.ctype) { case CTCPLX: gdatacomplex(nam, nr->val.u.cval); return; case CTSTR: gdatastring(nam, nr->val.u.sval); return; } } p = gins(ADATA, nam, nr); p->from.scale = wid; }
int dsymptr(Sym *s, int off, Sym *x, int xoff) { Prog *p; off = rnd(off, widthptr); p = gins(ADATA, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; p->from.sym = linksym(s); p->from.offset = off; p->from.scale = widthptr; p->to.type = D_ADDR; p->to.index = D_EXTERN; p->to.sym = linksym(x); p->to.offset = xoff; off += widthptr; return off; }
int dstringptr(Sym *s, int off, char *str) { Prog *p; off = rnd(off, widthptr); p = gins(ADATA, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; p->from.sym = linksym(s); p->from.offset = off; p->from.scale = widthptr; datastring(str, strlen(str)+1, &p->to); p->to.index = p->to.type; p->to.type = D_ADDR; p->to.etype = simtype[TINT]; off += widthptr; return off; }
void sdivgen(Node *l, Node *r, Node *ax, Node *dx) { int a, s; uint32 m; vlong c; c = r->vconst; if(c < 0) c = -c; a = sdiv(c, &m, &s); //print("a=%d i=%ld s=%d m=%lux\n", a, (int32)r->vconst, s, m); gins(AMOVL, nodconst(m), ax); gins(AIMULL, l, Z); gins(AMOVL, l, ax); if(a) gins(AADDL, ax, dx); gins(ASHRL, nodconst(31), ax); gins(ASARL, nodconst(s), dx); gins(AADDL, ax, dx); if(r->vconst < 0) gins(ANEGL, Z, dx); }
int dsname(Sym *sym, int off, char *t, int n) { Prog *p; p = gins(ADATA, N, N); p->from.type = D_OREG; p->from.name = D_EXTERN; p->from.etype = TINT32; p->from.offset = off; p->from.reg = NREG; p->from.sym = sym; p->reg = n; p->to.type = D_SCONST; p->to.name = D_NONE; p->to.reg = NREG; p->to.offset = 0; memmove(p->to.sval, t, n); return off + n; }
int dgostrlitptr(Sym *s, int off, Strlit *lit) { Prog *p; if(lit == nil) return duintptr(s, off, 0); off = rnd(off, widthptr); p = gins(ADATA, N, N); p->from.type = D_EXTERN; p->from.index = D_NONE; p->from.sym = linksym(s); p->from.offset = off; p->from.scale = widthptr; datagostring(lit, &p->to); p->to.index = p->to.type; p->to.type = D_ADDR; p->to.etype = simtype[TINT]; off += widthptr; return off; }
void sdiv2(int32 c, int v, Node *l, Node *n) { Node nod; if(v > 0) { if(v > 1) { sext(&nod, n, l); gins(AANDL, nodconst((1 << v) - 1), &nod); gins(AADDL, &nod, n); regfree(&nod); } else { gins(ACMPL, n, nodconst(0x80000000)); gins(ASBBL, nodconst(-1), n); } gins(ASARL, nodconst(v), n); } if(c < 0) gins(ANEGL, Z, n); }
/* * make a refer to the string sval, * emitting DATA if needed. */ void datagostring(Strlit *sval, Addr *a) { Prog *p; Addr ac, ao, ap; int32 wi, wp; static int gen; memset(&ac, 0, sizeof(ac)); memset(&ao, 0, sizeof(ao)); memset(&ap, 0, sizeof(ap)); // constant ac.type = D_CONST; ac.name = D_NONE; ac.offset = 0; // fill in ac.reg = NREG; // string len+ptr ao.type = D_OREG; ao.name = D_STATIC; // fill in ao.etype = TINT32; ao.sym = nil; // fill in ao.reg = NREG; // $string len+ptr datastring(sval->s, sval->len, &ap); ap.type = D_CONST; ap.etype = TINT32; wi = types[TUINT32]->width; wp = types[tptr]->width; if(ap.name == D_STATIC) { // huge strings are made static to avoid long names snprint(namebuf, sizeof(namebuf), ".gostring.%d", ++gen); ao.sym = lookup(namebuf); ao.name = D_STATIC; } else { // small strings get named by their contents, // so that multiple modules using the same string // can share it. snprint(namebuf, sizeof(namebuf), "\"%Z\"", sval); ao.sym = pkglookup(namebuf, gostringpkg); ao.name = D_EXTERN; } *a = ao; if(ao.sym->flags & SymUniq) return; ao.sym->flags |= SymUniq; data(); // DATA gostring, wp, $cstring p = pc; gins(ADATA, N, N); p->from = ao; p->reg = wp; p->to = ap; // DATA gostring+wp, wi, $len p = pc; gins(ADATA, N, N); p->from = ao; p->from.offset = wp; p->reg = wi; p->to = ac; p->to.offset = sval->len; p = pc; ggloblsym(ao.sym, types[TSTRING]->width, ao.name == D_EXTERN); if(ao.name == D_STATIC) p->from.name = D_STATIC; text(); }
void cgenrel(Node *n, Node *nn, int inrel) { Node *l, *r; Prog *p1; Node nod, nod1, nod2, nod3, nod4; int o, t; long v, curs; if(debug['g']) { prtree(nn, "cgen lhs"); prtree(n, "cgen"); } if(n == Z || n->type == T) return; if(typesu[n->type->etype]) { sugen(n, nn, n->type->width); return; } l = n->left; r = n->right; o = n->op; if(n->addable >= INDEXED) { if(nn == Z) { switch(o) { default: nullwarn(Z, Z); break; case OINDEX: nullwarn(l, r); break; } return; } gmove(n, nn); return; } curs = cursafe; if(n->complex >= FNX) if(l->complex >= FNX) if(r != Z && r->complex >= FNX) switch(o) { default: if(cond(o) && typesu[l->type->etype]) break; regret(&nod, r); cgen(r, &nod); regsalloc(&nod1, r); gopcode(OAS, &nod, Z, &nod1); regfree(&nod); nod = *n; nod.right = &nod1; cgen(&nod, nn); return; case OFUNC: case OCOMMA: case OANDAND: case OOROR: case OCOND: case ODOT: break; } switch(o) { default: diag(n, "unknown op in cgen: %O", o); break; case ONEG: case OCOM: if(nn == Z) { nullwarn(l, Z); break; } regalloc(&nod, l, nn); cgen(l, &nod); gopcode(o, &nod, Z, &nod); gmove(&nod, nn); regfree(&nod); break; case OAS: if(l->op == OBIT) goto bitas; if(l->addable >= INDEXED && l->complex < FNX) { if(nn != Z || r->addable < INDEXED) { /* || hardconst(r) */ if(r->complex >= FNX && nn == Z) regret(&nod, r); else regalloc(&nod, r, nn); cgen(r, &nod); gmove(&nod, l); if(nn != Z) gmove(&nod, nn); regfree(&nod); } else gmove(r, l); break; } if(l->complex >= r->complex) { /* TO DO: see 6c for OINDEX && immconst(r) */ reglcgen(&nod1, l, Z); if(r->addable >= INDEXED) { /* && !hardconst(r) */ gmove(r, &nod1); if(nn != Z) gmove(r, nn); regfree(&nod1); break; } regalloc(&nod, r, nn); cgen(r, &nod); } else { regalloc(&nod, r, nn); cgen(r, &nod); reglcgen(&nod1, l, Z); } gmove(&nod, &nod1); regfree(&nod); regfree(&nod1); break; bitas: n = l->left; regalloc(&nod, r, nn); if(l->complex >= r->complex) { reglcgen(&nod1, n, Z); cgen(r, &nod); } else { cgen(r, &nod); reglcgen(&nod1, n, Z); } regalloc(&nod2, n, Z); gopcode(OAS, &nod1, Z, &nod2); bitstore(l, &nod, &nod1, &nod2, nn); break; case OBIT: if(nn == Z) { nullwarn(l, Z); break; } bitload(n, &nod, Z, Z, nn); gopcode(OAS, &nod, Z, nn); regfree(&nod); break; case ODIV: case OMOD: if(nn != Z) if((t = vlog(r)) >= 0) { /* signed div/mod by constant power of 2 */ cgen(l, nn); gopcode(OGE, nodconst(0), nn, Z); p1 = p; if(o == ODIV) { gopcode(OADD, nodconst((1<<t)-1), Z, nn); patch(p1, pc); gopcode(OASHR, nodconst(t), Z, nn); } else { gopcode(ONEG, nn, Z, nn); gopcode(OAND, nodconst((1<<t)-1), Z, nn); gopcode(ONEG, nn, Z, nn); gbranch(OGOTO); patch(p1, pc); p1 = p; gopcode(OAND, nodconst((1<<t)-1), Z, nn); patch(p1, pc); } break; } goto muldiv; case OXOR: #ifdef NOTYET if(nn != Z) if(r->op == OCONST && r->vconst == -1){ cgen(l, nn); gopcode(OCOM, nn, Z, nn); break; } #endif case OSUB: case OADD: case OAND: case OOR: case OLSHR: case OASHL: case OASHR: /* * immediate operands */ if(nn != Z) if(r->op == OCONST) if(!typefd[n->type->etype]) { cgen(l, nn); if(r->vconst == 0) if(o != OAND) break; if(nn != Z) gopcode(o, r, Z, nn); break; } case OLMUL: case OLDIV: case OLMOD: case OMUL: muldiv: if(nn == Z) { nullwarn(l, r); break; } if(o == OMUL || o == OLMUL) { if(mulcon(n, nn)) break; } if(l->complex >= r->complex) { regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, l, Z); /* note: l used for type, so shifts work! */ cgen(r, &nod1); gopcode(o, &nod1, Z, &nod); } else { regalloc(&nod, l, nn); /* note: l used for type, so shifts work! */ cgen(r, &nod); regalloc(&nod1, l, Z); cgen(l, &nod1); gopcode(o, &nod, &nod1, &nod); } gopcode(OAS, &nod, Z, nn); regfree(&nod); regfree(&nod1); break; case OASLSHR: case OASASHL: case OASASHR: case OASAND: case OASADD: case OASSUB: case OASXOR: case OASOR: if(l->op == OBIT) goto asbitop; if(r->op == OCONST) if(!typefd[r->type->etype]) if(!typefd[n->type->etype]) { if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, l, nn); /* note: l used for type, so shifts work! */ gopcode(OAS, &nod2, Z, &nod); gopcode(o, r, Z, &nod); gopcode(OAS, &nod, Z, &nod2); regfree(&nod); if(l->addable < INDEXED) regfree(&nod2); break; } case OASLMUL: case OASLDIV: case OASLMOD: case OASMUL: case OASDIV: case OASMOD: if(l->op == OBIT) goto asbitop; if(l->complex >= r->complex) { if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, n, nn); cgen(r, &nod); } else { regalloc(&nod, n, nn); cgen(r, &nod); if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; } regalloc(&nod1, n, Z); gopcode(OAS, &nod2, Z, &nod1); if(nod1.type->etype != nod.type->etype){ regalloc(&nod3, &nod, Z); gmove(&nod1, &nod3); regfree(&nod1); nod1 = nod3; } gopcode(o, &nod, &nod1, &nod); gmove(&nod, &nod2); if(nn != Z) gmove(&nod, nn); regfree(&nod); regfree(&nod1); if(l->addable < INDEXED) regfree(&nod2); break; asbitop: regalloc(&nod4, n, nn); regalloc(&nod3, r, Z); if(l->complex >= r->complex) { bitload(l, &nod, &nod1, &nod2, &nod4); cgen(r, &nod3); } else { cgen(r, &nod3); bitload(l, &nod, &nod1, &nod2, &nod4); } gmove(&nod, &nod4); gopcode(o, &nod3, Z, &nod4); regfree(&nod3); gmove(&nod4, &nod); regfree(&nod4); bitstore(l, &nod, &nod1, &nod2, nn); break; case OADDR: if(nn == Z) { nullwarn(l, Z); break; } lcgen(l, nn); break; case OFUNC: l = uncomma(l); if(l->complex >= FNX) { if(l->op != OIND) diag(n, "bad function call"); regret(&nod, l->left); cgen(l->left, &nod); regsalloc(&nod1, l->left); gopcode(OAS, &nod, Z, &nod1); regfree(&nod); nod = *n; nod.left = &nod2; nod2 = *l; nod2.left = &nod1; nod2.complex = 1; cgen(&nod, nn); return; } if(REGARG >= 0) o = reg[REGARG]; gargs(r, &nod, &nod1); if(l->addable < INDEXED) { reglcgen(&nod, l, Z); gopcode(OFUNC, Z, Z, &nod); regfree(&nod); } else gopcode(OFUNC, Z, Z, l); if(REGARG >= 0) if(o != reg[REGARG]) reg[REGARG]--; if(nn != Z) { regret(&nod, n); gopcode(OAS, &nod, Z, nn); regfree(&nod); } break; case OIND: if(nn == Z) { nullwarn(l, Z); break; } regialloc(&nod, n, nn); r = l; while(r->op == OADD) r = r->right; if(sconst(r) && (v = r->vconst+nod.xoffset) >= -4096 && v < 4096) { v = r->vconst; r->vconst = 0; cgen(l, &nod); nod.xoffset += v; r->vconst = v; } else cgen(l, &nod); regind(&nod, n); gopcode(OAS, &nod, Z, nn); regfree(&nod); break; case OEQ: case ONE: case OLE: case OLT: case OGE: case OGT: case OLO: case OLS: case OHI: case OHS: if(nn == Z) { nullwarn(l, r); break; } boolgen(n, 1, nn); break; case OANDAND: case OOROR: boolgen(n, 1, nn); if(nn == Z) patch(p, pc); break; case ONOT: if(nn == Z) { nullwarn(l, Z); break; } boolgen(n, 1, nn); break; case OCOMMA: cgen(l, Z); cgen(r, nn); break; case OCAST: if(nn == Z) { nullwarn(l, Z); break; } /* * convert from types l->n->nn */ if(nocast(l->type, n->type) && nocast(n->type, nn->type)) { /* both null, gen l->nn */ cgen(l, nn); break; } if(ewidth[n->type->etype] < ewidth[l->type->etype]){ if(l->type->etype == TIND && typechlp[n->type->etype]) warn(n, "conversion of pointer to shorter integer"); }else if(0){ if(nocast(n->type, nn->type) || castup(n->type, nn->type)){ if(typefd[l->type->etype] != typefd[nn->type->etype]) regalloc(&nod, l, nn); else regalloc(&nod, nn, nn); cgen(l, &nod); gmove(&nod, nn); regfree(&nod); break; } } regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, n, &nod); if(inrel) gmover(&nod, &nod1); else gopcode(OAS, &nod, Z, &nod1); gopcode(OAS, &nod1, Z, nn); regfree(&nod1); regfree(&nod); break; case ODOT: sugen(l, nodrat, l->type->width); if(nn != Z) { warn(n, "non-interruptable temporary"); nod = *nodrat; if(!r || r->op != OCONST) { diag(n, "DOT and no offset"); break; } nod.xoffset += (long)r->vconst; nod.type = n->type; cgen(&nod, nn); } break; case OCOND: bcgen(l, 1); p1 = p; cgen(r->left, nn); gbranch(OGOTO); patch(p1, pc); p1 = p; cgen(r->right, nn); patch(p1, pc); break; case OPOSTINC: case OPOSTDEC: v = 1; if(l->type->etype == TIND) v = l->type->link->width; if(o == OPOSTDEC) v = -v; if(l->op == OBIT) goto bitinc; if(nn == Z) goto pre; if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, l, nn); gopcode(OAS, &nod2, Z, &nod); regalloc(&nod1, l, Z); if(typefd[l->type->etype]) { regalloc(&nod3, l, Z); if(v < 0) { gopcode(OAS, nodfconst(-v), Z, &nod3); gopcode(OSUB, &nod3, &nod, &nod1); } else { gopcode(OAS, nodfconst(v), Z, &nod3); gopcode(OADD, &nod3, &nod, &nod1); } regfree(&nod3); } else gopcode(OADD, nodconst(v), &nod, &nod1); gopcode(OAS, &nod1, Z, &nod2); regfree(&nod); regfree(&nod1); if(l->addable < INDEXED) regfree(&nod2); break; case OPREINC: case OPREDEC: v = 1; if(l->type->etype == TIND) v = l->type->link->width; if(o == OPREDEC) v = -v; if(l->op == OBIT) goto bitinc; pre: if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, l, nn); gopcode(OAS, &nod2, Z, &nod); if(typefd[l->type->etype]) { regalloc(&nod3, l, Z); if(v < 0) { gopcode(OAS, nodfconst(-v), Z, &nod3); gopcode(OSUB, &nod3, Z, &nod); } else { gopcode(OAS, nodfconst(v), Z, &nod3); gopcode(OADD, &nod3, Z, &nod); } regfree(&nod3); } else gopcode(OADD, nodconst(v), Z, &nod); gopcode(OAS, &nod, Z, &nod2); if(nn && l->op == ONAME) /* in x=++i, emit USED(i) */ gins(ANOP, l, Z); regfree(&nod); if(l->addable < INDEXED) regfree(&nod2); break; bitinc: if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { bitload(l, &nod, &nod1, &nod2, Z); gopcode(OAS, &nod, Z, nn); gopcode(OADD, nodconst(v), Z, &nod); bitstore(l, &nod, &nod1, &nod2, Z); break; } bitload(l, &nod, &nod1, &nod2, nn); gopcode(OADD, nodconst(v), Z, &nod); bitstore(l, &nod, &nod1, &nod2, nn); break; } cursafe = curs; return; }
void cgen(Node *n, Node *nn) { Node *l, *r, *t; Prog *p1; Node nod, nod1, nod2, nod3, nod4; int o, hardleft; int32 v, curs; vlong c; if(debug['g']) { prtree(nn, "cgen lhs"); prtree(n, "cgen"); } if(n == Z || n->type == T) return; if(typesu[n->type->etype]) { sugen(n, nn, n->type->width); return; } l = n->left; r = n->right; o = n->op; if(n->op == OEXREG || (nn != Z && nn->op == OEXREG)) { gmove(n, nn); return; } if(n->addable >= INDEXED) { if(nn == Z) { switch(o) { default: nullwarn(Z, Z); break; case OINDEX: nullwarn(l, r); break; } return; } gmove(n, nn); return; } curs = cursafe; if(l->complex >= FNX) if(r != Z && r->complex >= FNX) switch(o) { default: if(cond(o) && typesu[l->type->etype]) break; regret(&nod, r); cgen(r, &nod); regsalloc(&nod1, r); gmove(&nod, &nod1); regfree(&nod); nod = *n; nod.right = &nod1; cgen(&nod, nn); return; case OFUNC: case OCOMMA: case OANDAND: case OOROR: case OCOND: case ODOT: break; } hardleft = l->addable < INDEXED || l->complex >= FNX; switch(o) { default: diag(n, "unknown op in cgen: %O", o); break; case ONEG: case OCOM: if(nn == Z) { nullwarn(l, Z); break; } regalloc(&nod, l, nn); cgen(l, &nod); gopcode(o, n->type, Z, &nod); gmove(&nod, nn); regfree(&nod); break; case OAS: if(l->op == OBIT) goto bitas; if(!hardleft) { if(nn != Z || r->addable < INDEXED || hardconst(r)) { if(r->complex >= FNX && nn == Z) regret(&nod, r); else regalloc(&nod, r, nn); cgen(r, &nod); gmove(&nod, l); if(nn != Z) gmove(&nod, nn); regfree(&nod); } else gmove(r, l); break; } if(l->complex >= r->complex) { if(l->op == OINDEX && immconst(r)) { gmove(r, l); break; } reglcgen(&nod1, l, Z); if(r->addable >= INDEXED && !hardconst(r)) { gmove(r, &nod1); if(nn != Z) gmove(r, nn); regfree(&nod1); break; } regalloc(&nod, r, nn); cgen(r, &nod); } else { regalloc(&nod, r, nn); cgen(r, &nod); reglcgen(&nod1, l, Z); } gmove(&nod, &nod1); regfree(&nod); regfree(&nod1); break; bitas: n = l->left; regalloc(&nod, r, nn); if(l->complex >= r->complex) { reglcgen(&nod1, n, Z); cgen(r, &nod); } else { cgen(r, &nod); reglcgen(&nod1, n, Z); } regalloc(&nod2, n, Z); gmove(&nod1, &nod2); bitstore(l, &nod, &nod1, &nod2, nn); break; case OBIT: if(nn == Z) { nullwarn(l, Z); break; } bitload(n, &nod, Z, Z, nn); gmove(&nod, nn); regfree(&nod); break; case OLSHR: case OASHL: case OASHR: if(nn == Z) { nullwarn(l, r); break; } if(r->op == OCONST) { if(r->vconst == 0) { cgen(l, nn); break; } regalloc(&nod, l, nn); cgen(l, &nod); if(o == OASHL && r->vconst == 1) gopcode(OADD, n->type, &nod, &nod); else gopcode(o, n->type, r, &nod); gmove(&nod, nn); regfree(&nod); break; } /* * get nod to be D_CX */ if(nodreg(&nod, nn, D_CX)) { regsalloc(&nod1, n); gmove(&nod, &nod1); cgen(n, &nod); /* probably a bug */ gmove(&nod, nn); gmove(&nod1, &nod); break; } reg[D_CX]++; if(nn->op == OREGISTER && nn->reg == D_CX) regalloc(&nod1, l, Z); else regalloc(&nod1, l, nn); if(r->complex >= l->complex) { cgen(r, &nod); cgen(l, &nod1); } else { cgen(l, &nod1); cgen(r, &nod); } gopcode(o, n->type, &nod, &nod1); gmove(&nod1, nn); regfree(&nod); regfree(&nod1); break; case OADD: case OSUB: case OOR: case OXOR: case OAND: if(nn == Z) { nullwarn(l, r); break; } if(typefd[n->type->etype]) goto fop; if(r->op == OCONST) { if(r->vconst == 0 && o != OAND) { cgen(l, nn); break; } } if(n->op == OADD && l->op == OASHL && l->right->op == OCONST && (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) { c = l->right->vconst; if(c > 0 && c <= 3) { if(l->left->complex >= r->complex) { regalloc(&nod, l->left, nn); cgen(l->left, &nod); if(r->addable < INDEXED) { regalloc(&nod1, r, Z); cgen(r, &nod1); genmuladd(&nod, &nod, 1 << c, &nod1); regfree(&nod1); } else genmuladd(&nod, &nod, 1 << c, r); } else { regalloc(&nod, r, nn); cgen(r, &nod); regalloc(&nod1, l->left, Z); cgen(l->left, &nod1); genmuladd(&nod, &nod1, 1 << c, &nod); regfree(&nod1); } gmove(&nod, nn); regfree(&nod); break; } } if(r->addable >= INDEXED && !hardconst(r)) { regalloc(&nod, l, nn); cgen(l, &nod); gopcode(o, n->type, r, &nod); gmove(&nod, nn); regfree(&nod); break; } if(l->complex >= r->complex) { regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, r, Z); cgen(r, &nod1); gopcode(o, n->type, &nod1, &nod); } else { regalloc(&nod1, r, nn); cgen(r, &nod1); regalloc(&nod, l, Z); cgen(l, &nod); gopcode(o, n->type, &nod1, &nod); } gmove(&nod, nn); regfree(&nod); regfree(&nod1); break; case OLMOD: case OMOD: case OLMUL: case OLDIV: case OMUL: case ODIV: if(nn == Z) { nullwarn(l, r); break; } if(typefd[n->type->etype]) goto fop; if(r->op == OCONST && typechl[n->type->etype]) { /* TO DO */ SET(v); switch(o) { case ODIV: case OMOD: c = r->vconst; if(c < 0) c = -c; v = xlog2(c); if(v < 0) break; /* fall thru */ case OMUL: case OLMUL: regalloc(&nod, l, nn); cgen(l, &nod); switch(o) { case OMUL: case OLMUL: mulgen(n->type, r, &nod); break; case ODIV: sdiv2(r->vconst, v, l, &nod); break; case OMOD: smod2(r->vconst, v, l, &nod); break; } gmove(&nod, nn); regfree(&nod); goto done; case OLDIV: c = r->vconst; if((c & 0x80000000) == 0) break; regalloc(&nod1, l, Z); cgen(l, &nod1); regalloc(&nod, l, nn); zeroregm(&nod); gins(ACMPL, &nod1, nodconst(c)); gins(ASBBL, nodconst(-1), &nod); regfree(&nod1); gmove(&nod, nn); regfree(&nod); goto done; } } if(o == OMUL) { if(l->addable >= INDEXED) { t = l; l = r; r = t; } /* should favour AX */ regalloc(&nod, l, nn); cgen(l, &nod); if(r->addable < INDEXED || hardconst(r)) { regalloc(&nod1, r, Z); cgen(r, &nod1); gopcode(OMUL, n->type, &nod1, &nod); regfree(&nod1); }else gopcode(OMUL, n->type, r, &nod); /* addressible */ gmove(&nod, nn); regfree(&nod); break; } /* * get nod to be D_AX * get nod1 to be D_DX */ if(nodreg(&nod, nn, D_AX)) { regsalloc(&nod2, n); gmove(&nod, &nod2); v = reg[D_AX]; reg[D_AX] = 0; if(isreg(l, D_AX)) { nod3 = *n; nod3.left = &nod2; cgen(&nod3, nn); } else if(isreg(r, D_AX)) { nod3 = *n; nod3.right = &nod2; cgen(&nod3, nn); } else cgen(n, nn); gmove(&nod2, &nod); reg[D_AX] = v; break; } if(nodreg(&nod1, nn, D_DX)) { regsalloc(&nod2, n); gmove(&nod1, &nod2); v = reg[D_DX]; reg[D_DX] = 0; if(isreg(l, D_DX)) { nod3 = *n; nod3.left = &nod2; cgen(&nod3, nn); } else if(isreg(r, D_DX)) { nod3 = *n; nod3.right = &nod2; cgen(&nod3, nn); } else cgen(n, nn); gmove(&nod2, &nod1); reg[D_DX] = v; break; } reg[D_AX]++; if(r->op == OCONST && (o == ODIV || o == OLDIV) && immconst(r) && typechl[r->type->etype]) { reg[D_DX]++; if(l->addable < INDEXED) { regalloc(&nod2, l, Z); cgen(l, &nod2); l = &nod2; } if(o == ODIV) sdivgen(l, r, &nod, &nod1); else udivgen(l, r, &nod, &nod1); gmove(&nod1, nn); if(l == &nod2) regfree(l); goto freeaxdx; } if(l->complex >= r->complex) { cgen(l, &nod); reg[D_DX]++; if(o == ODIV || o == OMOD) gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); if(o == OLDIV || o == OLMOD) zeroregm(&nod1); if(r->addable < INDEXED || r->op == OCONST) { regsalloc(&nod3, r); cgen(r, &nod3); gopcode(o, n->type, &nod3, Z); } else gopcode(o, n->type, r, Z); } else { regsalloc(&nod3, r); cgen(r, &nod3); cgen(l, &nod); reg[D_DX]++; if(o == ODIV || o == OMOD) gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); if(o == OLDIV || o == OLMOD) zeroregm(&nod1); gopcode(o, n->type, &nod3, Z); } if(o == OMOD || o == OLMOD) gmove(&nod1, nn); else gmove(&nod, nn); freeaxdx: regfree(&nod); regfree(&nod1); break; case OASLSHR: case OASASHL: case OASASHR: if(r->op == OCONST) goto asand; if(l->op == OBIT) goto asbitop; if(typefd[n->type->etype]) goto asand; /* can this happen? */ /* * get nod to be D_CX */ if(nodreg(&nod, nn, D_CX)) { regsalloc(&nod1, n); gmove(&nod, &nod1); cgen(n, &nod); if(nn != Z) gmove(&nod, nn); gmove(&nod1, &nod); break; } reg[D_CX]++; if(r->complex >= l->complex) { cgen(r, &nod); if(hardleft) reglcgen(&nod1, l, Z); else nod1 = *l; } else { if(hardleft) reglcgen(&nod1, l, Z); else nod1 = *l; cgen(r, &nod); } gopcode(o, l->type, &nod, &nod1); regfree(&nod); if(nn != Z) gmove(&nod1, nn); if(hardleft) regfree(&nod1); break; case OASAND: case OASADD: case OASSUB: case OASXOR: case OASOR: asand: if(l->op == OBIT) goto asbitop; if(typefd[l->type->etype] || typefd[r->type->etype]) goto asfop; if(l->complex >= r->complex) { if(hardleft) reglcgen(&nod, l, Z); else nod = *l; if(!immconst(r)) { regalloc(&nod1, r, nn); cgen(r, &nod1); gopcode(o, l->type, &nod1, &nod); regfree(&nod1); } else gopcode(o, l->type, r, &nod); } else { regalloc(&nod1, r, nn); cgen(r, &nod1); if(hardleft) reglcgen(&nod, l, Z); else nod = *l; gopcode(o, l->type, &nod1, &nod); regfree(&nod1); } if(nn != Z) gmove(&nod, nn); if(hardleft) regfree(&nod); break; asfop: if(l->complex >= r->complex) { if(hardleft) reglcgen(&nod, l, Z); else nod = *l; if(r->addable < INDEXED){ regalloc(&nod1, r, nn); cgen(r, &nod1); }else nod1 = *r; regalloc(&nod2, r, Z); gmove(&nod, &nod2); gopcode(o, r->type, &nod1, &nod2); gmove(&nod2, &nod); regfree(&nod2); if(r->addable < INDEXED) regfree(&nod1); } else { regalloc(&nod1, r, nn); cgen(r, &nod1); if(hardleft) reglcgen(&nod, l, Z); else nod = *l; if(o != OASMUL && o != OASADD) { regalloc(&nod2, r, Z); gmove(&nod, &nod2); gopcode(o, r->type, &nod1, &nod2); regfree(&nod1); gmove(&nod2, &nod); regfree(&nod2); } else { gopcode(o, r->type, &nod, &nod1); gmove(&nod1, &nod); regfree(&nod1); } } if(nn != Z) gmove(&nod, nn); if(hardleft) regfree(&nod); break; case OASLMUL: case OASLDIV: case OASLMOD: case OASMUL: case OASDIV: case OASMOD: if(l->op == OBIT) goto asbitop; if(typefd[n->type->etype] || typefd[r->type->etype]) goto asfop; if(r->op == OCONST && typechl[n->type->etype]) { SET(v); switch(o) { case OASDIV: case OASMOD: c = r->vconst; if(c < 0) c = -c; v = xlog2(c); if(v < 0) break; /* fall thru */ case OASMUL: case OASLMUL: if(hardleft) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, l, nn); cgen(&nod2, &nod); switch(o) { case OASMUL: case OASLMUL: mulgen(n->type, r, &nod); break; case OASDIV: sdiv2(r->vconst, v, l, &nod); break; case OASMOD: smod2(r->vconst, v, l, &nod); break; } havev: gmove(&nod, &nod2); if(nn != Z) gmove(&nod, nn); if(hardleft) regfree(&nod2); regfree(&nod); goto done; case OASLDIV: c = r->vconst; if((c & 0x80000000) == 0) break; if(hardleft) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod1, l, nn); cgen(&nod2, &nod1); regalloc(&nod, l, nn); zeroregm(&nod); gins(ACMPL, &nod1, nodconst(c)); gins(ASBBL, nodconst(-1), &nod); regfree(&nod1); goto havev; } } if(o == OASMUL) { /* should favour AX */ regalloc(&nod, l, nn); if(r->complex >= FNX) { regalloc(&nod1, r, Z); cgen(r, &nod1); r = &nod1; } if(hardleft) reglcgen(&nod2, l, Z); else nod2 = *l; cgen(&nod2, &nod); if(r->addable < INDEXED || hardconst(r)) { if(r->complex < FNX) { regalloc(&nod1, r, Z); cgen(r, &nod1); } gopcode(OASMUL, n->type, &nod1, &nod); regfree(&nod1); } else gopcode(OASMUL, n->type, r, &nod); if(r == &nod1) regfree(r); gmove(&nod, &nod2); if(nn != Z) gmove(&nod, nn); regfree(&nod); if(hardleft) regfree(&nod2); break; } /* * get nod to be D_AX * get nod1 to be D_DX */ if(nodreg(&nod, nn, D_AX)) { regsalloc(&nod2, n); gmove(&nod, &nod2); v = reg[D_AX]; reg[D_AX] = 0; if(isreg(l, D_AX)) { nod3 = *n; nod3.left = &nod2; cgen(&nod3, nn); } else if(isreg(r, D_AX)) { nod3 = *n; nod3.right = &nod2; cgen(&nod3, nn); } else cgen(n, nn); gmove(&nod2, &nod); reg[D_AX] = v; break; } if(nodreg(&nod1, nn, D_DX)) { regsalloc(&nod2, n); gmove(&nod1, &nod2); v = reg[D_DX]; reg[D_DX] = 0; if(isreg(l, D_DX)) { nod3 = *n; nod3.left = &nod2; cgen(&nod3, nn); } else if(isreg(r, D_DX)) { nod3 = *n; nod3.right = &nod2; cgen(&nod3, nn); } else cgen(n, nn); gmove(&nod2, &nod1); reg[D_DX] = v; break; } reg[D_AX]++; reg[D_DX]++; if(l->complex >= r->complex) { if(hardleft) reglcgen(&nod2, l, Z); else nod2 = *l; cgen(&nod2, &nod); if(r->op == OCONST && typechl[r->type->etype]) { switch(o) { case OASDIV: sdivgen(&nod2, r, &nod, &nod1); goto divdone; case OASLDIV: udivgen(&nod2, r, &nod, &nod1); divdone: gmove(&nod1, &nod2); if(nn != Z) gmove(&nod1, nn); goto freelxaxdx; } } if(o == OASDIV || o == OASMOD) gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); if(o == OASLDIV || o == OASLMOD) zeroregm(&nod1); if(r->addable < INDEXED || r->op == OCONST || !typeil[r->type->etype]) { regalloc(&nod3, r, Z); cgen(r, &nod3); gopcode(o, l->type, &nod3, Z); regfree(&nod3); } else gopcode(o, n->type, r, Z); } else { regalloc(&nod3, r, Z); cgen(r, &nod3); if(hardleft) reglcgen(&nod2, l, Z); else nod2 = *l; cgen(&nod2, &nod); if(o == OASDIV || o == OASMOD) gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z); if(o == OASLDIV || o == OASLMOD) zeroregm(&nod1); gopcode(o, l->type, &nod3, Z); regfree(&nod3); } if(o == OASMOD || o == OASLMOD) { gmove(&nod1, &nod2); if(nn != Z) gmove(&nod1, nn); } else { gmove(&nod, &nod2); if(nn != Z) gmove(&nod, nn); } freelxaxdx: if(hardleft) regfree(&nod2); regfree(&nod); regfree(&nod1); break; fop: if(l->complex >= r->complex) { regalloc(&nod, l, nn); cgen(l, &nod); if(r->addable < INDEXED) { regalloc(&nod1, r, Z); cgen(r, &nod1); gopcode(o, n->type, &nod1, &nod); regfree(&nod1); } else gopcode(o, n->type, r, &nod); } else { /* TO DO: could do better with r->addable >= INDEXED */ regalloc(&nod1, r, Z); cgen(r, &nod1); regalloc(&nod, l, nn); cgen(l, &nod); gopcode(o, n->type, &nod1, &nod); regfree(&nod1); } gmove(&nod, nn); regfree(&nod); break; asbitop: regalloc(&nod4, n, nn); if(l->complex >= r->complex) { bitload(l, &nod, &nod1, &nod2, &nod4); regalloc(&nod3, r, Z); cgen(r, &nod3); } else { regalloc(&nod3, r, Z); cgen(r, &nod3); bitload(l, &nod, &nod1, &nod2, &nod4); } gmove(&nod, &nod4); { /* TO DO: check floating point source */ Node onod; /* incredible grot ... */ onod = nod3; onod.op = o; onod.complex = 2; onod.addable = 0; onod.type = tfield; onod.left = &nod4; onod.right = &nod3; cgen(&onod, Z); } regfree(&nod3); gmove(&nod4, &nod); regfree(&nod4); bitstore(l, &nod, &nod1, &nod2, nn); break; case OADDR: if(nn == Z) { nullwarn(l, Z); break; } lcgen(l, nn); break; case OFUNC: if(l->complex >= FNX) { if(l->op != OIND) diag(n, "bad function call"); regret(&nod, l->left); cgen(l->left, &nod); regsalloc(&nod1, l->left); gmove(&nod, &nod1); regfree(&nod); nod = *n; nod.left = &nod2; nod2 = *l; nod2.left = &nod1; nod2.complex = 1; cgen(&nod, nn); return; } o = 0; if(REGARG >= 0) o = reg[REGARG]; gargs(r, &nod, &nod1); if(l->addable < INDEXED) { reglcgen(&nod, l, nn); nod.op = OREGISTER; gopcode(OFUNC, n->type, Z, &nod); regfree(&nod); } else gopcode(OFUNC, n->type, Z, l); if(REGARG >= 0) if(o != reg[REGARG]) reg[REGARG]--; if(nn != Z) { regret(&nod, n); gmove(&nod, nn); regfree(&nod); } break; case OIND: if(nn == Z) { nullwarn(l, Z); break; } regialloc(&nod, n, nn); r = l; while(r->op == OADD) r = r->right; if(sconst(r)) { v = r->vconst; r->vconst = 0; cgen(l, &nod); nod.xoffset += v; r->vconst = v; } else cgen(l, &nod); regind(&nod, n); gmove(&nod, nn); regfree(&nod); break; case OEQ: case ONE: case OLE: case OLT: case OGE: case OGT: case OLO: case OLS: case OHI: case OHS: if(nn == Z) { nullwarn(l, r); break; } boolgen(n, 1, nn); break; case OANDAND: case OOROR: boolgen(n, 1, nn); if(nn == Z) patch(p, pc); break; case ONOT: if(nn == Z) { nullwarn(l, Z); break; } boolgen(n, 1, nn); break; case OCOMMA: cgen(l, Z); cgen(r, nn); break; case OCAST: if(nn == Z) { nullwarn(l, Z); break; } /* * convert from types l->n->nn */ if(nocast(l->type, n->type) && nocast(n->type, nn->type)) { /* both null, gen l->nn */ cgen(l, nn); break; } if(ewidth[n->type->etype] < ewidth[l->type->etype]){ if(l->type->etype == TIND && typechlp[n->type->etype]) warn(n, "conversion of pointer to shorter integer"); }else if(0){ if(nocast(n->type, nn->type) || castup(n->type, nn->type)){ if(typefd[l->type->etype] != typefd[nn->type->etype]) regalloc(&nod, l, nn); else regalloc(&nod, nn, nn); cgen(l, &nod); gmove(&nod, nn); regfree(&nod); break; } } regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, n, &nod); gmove(&nod, &nod1); gmove(&nod1, nn); regfree(&nod1); regfree(&nod); break; case ODOT: sugen(l, nodrat, l->type->width); if(nn == Z) break; warn(n, "non-interruptable temporary"); nod = *nodrat; if(!r || r->op != OCONST) { diag(n, "DOT and no offset"); break; } nod.xoffset += (int32)r->vconst; nod.type = n->type; cgen(&nod, nn); break; case OCOND: bcgen(l, 1); p1 = p; cgen(r->left, nn); gbranch(OGOTO); patch(p1, pc); p1 = p; cgen(r->right, nn); patch(p1, pc); break; case OPOSTINC: case OPOSTDEC: v = 1; if(l->type->etype == TIND) v = l->type->link->width; if(o == OPOSTDEC) v = -v; if(l->op == OBIT) goto bitinc; if(nn == Z) goto pre; if(hardleft) reglcgen(&nod, l, Z); else nod = *l; gmove(&nod, nn); if(typefd[n->type->etype]) { regalloc(&nod1, l, Z); gmove(&nod, &nod1); if(v < 0) gopcode(OSUB, n->type, nodfconst(-v), &nod1); else gopcode(OADD, n->type, nodfconst(v), &nod1); gmove(&nod1, &nod); regfree(&nod1); } else gopcode(OADD, n->type, nodconst(v), &nod); if(hardleft) regfree(&nod); break; case OPREINC: case OPREDEC: v = 1; if(l->type->etype == TIND) v = l->type->link->width; if(o == OPREDEC) v = -v; if(l->op == OBIT) goto bitinc; pre: if(hardleft) reglcgen(&nod, l, Z); else nod = *l; if(typefd[n->type->etype]) { regalloc(&nod1, l, Z); gmove(&nod, &nod1); if(v < 0) gopcode(OSUB, n->type, nodfconst(-v), &nod1); else gopcode(OADD, n->type, nodfconst(v), &nod1); gmove(&nod1, &nod); regfree(&nod1); } else gopcode(OADD, n->type, nodconst(v), &nod); if(nn != Z) gmove(&nod, nn); if(hardleft) regfree(&nod); break; bitinc: if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { bitload(l, &nod, &nod1, &nod2, Z); gmove(&nod, nn); gopcode(OADD, tfield, nodconst(v), &nod); bitstore(l, &nod, &nod1, &nod2, Z); break; } bitload(l, &nod, &nod1, &nod2, nn); gopcode(OADD, tfield, nodconst(v), &nod); bitstore(l, &nod, &nod1, &nod2, nn); break; } done: cursafe = curs; }
void udivgen(Node *l, Node *r, Node *ax, Node *dx) { int a, s, t; uint32 m; Node nod; a = udiv(r->vconst, &m, &s, &t); //print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (int32)r->vconst, t, s, m); if(t != 0) { gins(AMOVL, l, ax); gins(ASHRL, nodconst(t), ax); gins(AMOVL, nodconst(m), dx); gins(AMULL, dx, Z); } else if(a) { if(l->op != OREGISTER) { regalloc(&nod, l, Z); gins(AMOVL, l, &nod); l = &nod; } gins(AMOVL, nodconst(m), ax); gins(AMULL, l, Z); gins(AADDL, l, dx); gins(ARCRL, nodconst(1), dx); if(l == &nod) regfree(l); } else { gins(AMOVL, nodconst(m), ax); gins(AMULL, l, Z); } if(s != 0) gins(ASHRL, nodconst(s), dx); }
void gdata(Node *nam, Node *nr, int wid) { Prog *p; vlong v; if(wid == 8 && is64(nr->type)) { v = mpgetfix(nr->val.u.xval); p = gins(ADATA, nam, nodintconst(v)); p->reg = 4; p = gins(ADATA, nam, nodintconst(v>>32)); p->reg = 4; p->from.offset += 4; return; } p = gins(ADATA, nam, nr); p->reg = wid; } void gdatacomplex(Node *nam, Mpcplx *cval) { Prog *p; int w; w = cplxsubtype(nam->type->etype); w = types[w]->width; p = gins(ADATA, nam, N); p->reg = w; p->to.type = D_FCONST;
/* * generate comparison of nl, nr, both 64-bit. * nl is memory; nr is constant or memory. */ void cmp64(Node *nl, Node *nr, int op, Prog *to) { Node lo1, hi1, lo2, hi2, r1, r2; Prog *br; Type *t; split64(nl, &lo1, &hi1); split64(nr, &lo2, &hi2); // compare most significant word; // if they differ, we're done. t = hi1.type; regalloc(&r1, types[TINT32], N); regalloc(&r2, types[TINT32], N); gins(AMOVW, &hi1, &r1); gins(AMOVW, &hi2, &r2); gcmp(ACMP, &r1, &r2); regfree(&r1); regfree(&r2); br = P; switch(op) { default: fatal("cmp64 %O %T", op, t); case OEQ: // cmp hi // bne L // cmp lo // beq to // L: br = gbranch(ABNE, T); break; case ONE: // cmp hi // bne to // cmp lo // bne to patch(gbranch(ABNE, T), to); break; case OGE: case OGT: // cmp hi // bgt to // blt L // cmp lo // bge to (or bgt to) // L: patch(gbranch(optoas(OGT, t), T), to); br = gbranch(optoas(OLT, t), T); break; case OLE: case OLT: // cmp hi // blt to // bgt L // cmp lo // ble to (or jlt to) // L: patch(gbranch(optoas(OLT, t), T), to); br = gbranch(optoas(OGT, t), T); break; } // compare least significant word t = lo1.type; regalloc(&r1, types[TINT32], N); regalloc(&r2, types[TINT32], N); gins(AMOVW, &lo1, &r1); gins(AMOVW, &lo2, &r2); gcmp(ACMP, &r1, &r2); regfree(&r1); regfree(&r2); // jump again patch(gbranch(optoas(op, t), T), to); // point first branch down here if appropriate if(br != P) patch(br, pc); splitclean(); splitclean(); }
/* * generate: * res = &n; */ void agen(Node *n, Node *res) { Node *nl, *nr; Node n1, n2, n3, tmp, n4; Prog *p1; uint32 w; uint64 v; Type *t; if(debug['g']) { dump("\nagen-res", res); dump("agen-r", n); } if(n == N || n->type == T) return; if(!isptr[res->type->etype]) fatal("agen: not tptr: %T", res->type); while(n->op == OCONVNOP) n = n->left; if(n->addable) { regalloc(&n1, types[tptr], res); gins(ALEAQ, n, &n1); gmove(&n1, res); regfree(&n1); goto ret; } nl = n->left; nr = n->right; switch(n->op) { default: fatal("agen: unknown op %N", n); break; case OCALLMETH: cgen_callmeth(n, 0); cgen_aret(n, res); break; case OCALLINTER: cgen_callinter(n, res, 0); cgen_aret(n, res); break; case OCALLFUNC: cgen_call(n, 0); cgen_aret(n, res); break; case OINDEX: w = n->type->width; if(nr->addable) goto irad; if(nl->addable) { if(!isconst(nr, CTINT)) { regalloc(&n1, nr->type, N); cgen(nr, &n1); } regalloc(&n3, types[tptr], res); agen(nl, &n3); goto index; } tempname(&tmp, nr->type); cgen(nr, &tmp); nr = &tmp; irad: regalloc(&n3, types[tptr], res); agen(nl, &n3); if(!isconst(nr, CTINT)) { regalloc(&n1, nr->type, N); cgen(nr, &n1); } goto index; index: // &a is in &n3 (allocated in res) // i is in &n1 (if not constant) // w is width // explicit check for nil if array is large enough // that we might derive too big a pointer. if(!isslice(nl->type) && nl->type->width >= unmappedzero) { regalloc(&n4, types[tptr], &n3); gmove(&n3, &n4); n4.op = OINDREG; n4.type = types[TUINT8]; n4.xoffset = 0; gins(ATESTB, nodintconst(0), &n4); regfree(&n4); } if(w == 0) fatal("index is zero width"); // constant index if(isconst(nr, CTINT)) { v = mpgetfix(nr->val.u.xval); if(isslice(nl->type)) { if(!debug['B'] && !n->etype) { n1 = n3; n1.op = OINDREG; n1.type = types[tptr]; n1.xoffset = Array_nel; nodconst(&n2, types[TUINT64], v); gins(optoas(OCMP, types[TUINT32]), &n1, &n2); p1 = gbranch(optoas(OGT, types[TUINT32]), T); ginscall(throwindex, 0); patch(p1, pc); } n1 = n3; n1.op = OINDREG; n1.type = types[tptr]; n1.xoffset = Array_array; gmove(&n1, &n3); } else if(!debug['B'] && !n->etype) { if(v < 0) yyerror("out of bounds on array"); else if(v >= nl->type->bound) yyerror("out of bounds on array"); } nodconst(&n2, types[tptr], v*w); gins(optoas(OADD, types[tptr]), &n2, &n3); gmove(&n3, res); regfree(&n3); break; } // type of the index t = types[TUINT64]; if(issigned[n1.type->etype]) t = types[TINT64]; regalloc(&n2, t, &n1); // i gmove(&n1, &n2); regfree(&n1); if(!debug['B'] && !n->etype) { // check bounds if(isslice(nl->type)) { n1 = n3; n1.op = OINDREG; n1.type = types[tptr]; n1.xoffset = Array_nel; } else nodconst(&n1, types[TUINT64], nl->type->bound); gins(optoas(OCMP, types[TUINT32]), &n2, &n1); p1 = gbranch(optoas(OLT, types[TUINT32]), T); ginscall(throwindex, 0); patch(p1, pc); } if(isslice(nl->type)) { n1 = n3; n1.op = OINDREG; n1.type = types[tptr]; n1.xoffset = Array_array; gmove(&n1, &n3); } if(w == 1 || w == 2 || w == 4 || w == 8) { p1 = gins(ALEAQ, &n2, &n3); p1->from.scale = w; p1->from.index = p1->from.type; p1->from.type = p1->to.type + D_INDIR; } else { nodconst(&n1, t, w); gins(optoas(OMUL, t), &n1, &n2); gins(optoas(OADD, types[tptr]), &n2, &n3); gmove(&n3, res); } gmove(&n3, res); regfree(&n2); regfree(&n3); break; case ONAME: // should only get here with names in this func. if(n->funcdepth > 0 && n->funcdepth != funcdepth) { dump("bad agen", n); fatal("agen: bad ONAME funcdepth %d != %d", n->funcdepth, funcdepth); } // should only get here for heap vars or paramref if(!(n->class & PHEAP) && n->class != PPARAMREF) { dump("bad agen", n); fatal("agen: bad ONAME class %#x", n->class); } cgen(n->heapaddr, res); if(n->xoffset != 0) { nodconst(&n1, types[TINT64], n->xoffset); gins(optoas(OADD, types[tptr]), &n1, res); } break; case OIND: cgen(nl, res); break; case ODOT: agen(nl, res); if(n->xoffset != 0) { nodconst(&n1, types[TINT64], n->xoffset); gins(optoas(OADD, types[tptr]), &n1, res); } break; case ODOTPTR: cgen(nl, res); if(n->xoffset != 0) { // explicit check for nil if struct is large enough // that we might derive too big a pointer. if(nl->type->type->width >= unmappedzero) { regalloc(&n1, types[tptr], res); gmove(res, &n1); n1.op = OINDREG; n1.type = types[TUINT8]; n1.xoffset = 0; gins(ATESTB, nodintconst(0), &n1); regfree(&n1); } nodconst(&n1, types[TINT64], n->xoffset); gins(optoas(OADD, types[tptr]), &n1, res); } break; } ret: ; }
/* * make a refer to the data s, s+len * emitting DATA if needed. */ void datastring(char *s, int len, Addr *a) { int w; Prog *p; Addr ac, ao; static int gen; struct { Strlit lit; char buf[100]; } tmp; // string memset(&ao, 0, sizeof(ao)); ao.type = D_OREG; ao.name = D_STATIC; ao.etype = TINT32; ao.offset = 0; // fill in ao.reg = NREG; // constant memset(&ac, 0, sizeof(ac)); ac.type = D_CONST; ac.name = D_NONE; ac.offset = 0; // fill in ac.reg = NREG; // huge strings are made static to avoid long names. if(len > 100) { snprint(namebuf, sizeof(namebuf), ".string.%d", gen++); ao.sym = lookup(namebuf); ao.name = D_STATIC; } else { if(len > 0 && s[len-1] == '\0') len--; tmp.lit.len = len; memmove(tmp.lit.s, s, len); tmp.lit.s[len] = '\0'; len++; snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp.lit); ao.sym = pkglookup(namebuf, stringpkg); ao.name = D_EXTERN; } *a = ao; // only generate data the first time. if(ao.sym->flags & SymUniq) return; ao.sym->flags |= SymUniq; data(); for(w=0; w<len; w+=8) { p = pc; gins(ADATA, N, N); // DATA s+w, [NSNAME], $"xxx" p->from = ao; p->from.offset = w; p->reg = NSNAME; if(w+8 > len) p->reg = len-w; p->to = ac; p->to.type = D_SCONST; p->to.offset = len; memmove(p->to.sval, s+w, p->reg); } p = pc; ggloblsym(ao.sym, len, ao.name == D_EXTERN); if(ao.name == D_STATIC) p->from.name = D_STATIC; text(); }
/* * attempt to generate 64-bit * res = n * return 1 on success, 0 if op not handled. */ void cgen64(Node *n, Node *res) { Node t1, t2, *l, *r; Node lo1, lo2, hi1, hi2; Node al, ah, bl, bh, cl, ch, s, n1, creg; Prog *p1, *p2, *p3, *p4, *p5, *p6; uint64 v; if(res->op != OINDREG && res->op != ONAME) { dump("n", n); dump("res", res); fatal("cgen64 %O of %O", n->op, res->op); } l = n->left; if(!l->addable) { tempname(&t1, l->type); cgen(l, &t1); l = &t1; } split64(l, &lo1, &hi1); switch(n->op) { default: fatal("cgen64 %O", n->op); case OMINUS: split64(res, &lo2, &hi2); regalloc(&t1, lo1.type, N); regalloc(&al, lo1.type, N); regalloc(&ah, hi1.type, N); gins(AMOVW, &lo1, &al); gins(AMOVW, &hi1, &ah); gmove(ncon(0), &t1); p1 = gins(ASUB, &al, &t1); p1->scond |= C_SBIT; gins(AMOVW, &t1, &lo2); gmove(ncon(0), &t1); gins(ASBC, &ah, &t1); gins(AMOVW, &t1, &hi2); regfree(&t1); regfree(&al); regfree(&ah); splitclean(); splitclean(); return; case OCOM: split64(res, &lo2, &hi2); regalloc(&n1, lo1.type, N); gins(AMOVW, &lo1, &n1); gins(AMVN, &n1, &n1); gins(AMOVW, &n1, &lo2); gins(AMOVW, &hi1, &n1); gins(AMVN, &n1, &n1); gins(AMOVW, &n1, &hi2); regfree(&n1); splitclean(); splitclean(); return; case OADD: case OSUB: case OMUL: case OLSH: case ORSH: case OAND: case OOR: case OXOR: // binary operators. // common setup below. break; } // setup for binary operators r = n->right; if(r != N && !r->addable) { tempname(&t2, r->type); cgen(r, &t2); r = &t2; } if(is64(r->type)) split64(r, &lo2, &hi2); regalloc(&al, lo1.type, N); regalloc(&ah, hi1.type, N); // Do op. Leave result in ah:al. switch(n->op) { default: fatal("cgen64: not implemented: %N\n", n); case OADD: // TODO: Constants regalloc(&bl, types[TPTR32], N); regalloc(&bh, types[TPTR32], N); gins(AMOVW, &hi1, &ah); gins(AMOVW, &lo1, &al); gins(AMOVW, &hi2, &bh); gins(AMOVW, &lo2, &bl); p1 = gins(AADD, &bl, &al); p1->scond |= C_SBIT; gins(AADC, &bh, &ah); regfree(&bl); regfree(&bh); break; case OSUB: // TODO: Constants. regalloc(&bl, types[TPTR32], N); regalloc(&bh, types[TPTR32], N); gins(AMOVW, &lo1, &al); gins(AMOVW, &hi1, &ah); gins(AMOVW, &lo2, &bl); gins(AMOVW, &hi2, &bh); p1 = gins(ASUB, &bl, &al); p1->scond |= C_SBIT; gins(ASBC, &bh, &ah); regfree(&bl); regfree(&bh); break; case OMUL: // TODO(kaib): this can be done with 4 regs and does not need 6 regalloc(&bl, types[TPTR32], N); regalloc(&bh, types[TPTR32], N); regalloc(&cl, types[TPTR32], N); regalloc(&ch, types[TPTR32], N); // load args into bh:bl and bh:bl. gins(AMOVW, &hi1, &bh); gins(AMOVW, &lo1, &bl); gins(AMOVW, &hi2, &ch); gins(AMOVW, &lo2, &cl); // bl * cl p1 = gins(AMULLU, N, N); p1->from.type = D_REG; p1->from.reg = bl.val.u.reg; p1->reg = cl.val.u.reg; p1->to.type = D_REGREG; p1->to.reg = ah.val.u.reg; p1->to.offset = al.val.u.reg; //print("%P\n", p1); // bl * ch p1 = gins(AMULA, N, N); p1->from.type = D_REG; p1->from.reg = bl.val.u.reg; p1->reg = ch.val.u.reg; p1->to.type = D_REGREG; p1->to.reg = ah.val.u.reg; p1->to.offset = ah.val.u.reg; //print("%P\n", p1); // bh * cl p1 = gins(AMULA, N, N); p1->from.type = D_REG; p1->from.reg = bh.val.u.reg; p1->reg = cl.val.u.reg; p1->to.type = D_REGREG; p1->to.reg = ah.val.u.reg; p1->to.offset = ah.val.u.reg; //print("%P\n", p1); regfree(&bh); regfree(&bl); regfree(&ch); regfree(&cl); break; case OLSH: regalloc(&bl, lo1.type, N); regalloc(&bh, hi1.type, N); gins(AMOVW, &hi1, &bh); gins(AMOVW, &lo1, &bl); if(r->op == OLITERAL) { v = mpgetfix(r->val.u.xval); if(v >= 64) { // TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al) // here and below (verify it optimizes to EOR) gins(AEOR, &al, &al); gins(AEOR, &ah, &ah); } else if(v > 32) { gins(AEOR, &al, &al); // MOVW bl<<(v-32), ah gshift(AMOVW, &bl, SHIFT_LL, (v-32), &ah); } else if(v == 32) { gins(AEOR, &al, &al); gins(AMOVW, &bl, &ah); } else if(v > 0) { // MOVW bl<<v, al gshift(AMOVW, &bl, SHIFT_LL, v, &al); // MOVW bh<<v, ah gshift(AMOVW, &bh, SHIFT_LL, v, &ah); // OR bl>>(32-v), ah gshift(AORR, &bl, SHIFT_LR, 32-v, &ah); } else { gins(AMOVW, &bl, &al); gins(AMOVW, &bh, &ah); } goto olsh_break; } regalloc(&s, types[TUINT32], N); regalloc(&creg, types[TUINT32], N); if (is64(r->type)) { // shift is >= 1<<32 split64(r, &cl, &ch); gmove(&ch, &s); p1 = gins(AMOVW, &s, &s); p1->scond |= C_SBIT; p6 = gbranch(ABNE, T); gmove(&cl, &s); splitclean(); } else { gmove(r, &s); p6 = P; } p1 = gins(AMOVW, &s, &s); p1->scond |= C_SBIT; // shift == 0 p1 = gins(AMOVW, &bl, &al); p1->scond = C_SCOND_EQ; p1 = gins(AMOVW, &bh, &ah); p1->scond = C_SCOND_EQ; p2 = gbranch(ABEQ, T); // shift is < 32 nodconst(&n1, types[TUINT32], 32); gmove(&n1, &creg); gcmp(ACMP, &s, &creg); // MOVW.LO bl<<s, al p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &al); p1->scond = C_SCOND_LO; // MOVW.LO bh<<s, ah p1 = gregshift(AMOVW, &bh, SHIFT_LL, &s, &ah); p1->scond = C_SCOND_LO; // SUB.LO s, creg p1 = gins(ASUB, &s, &creg); p1->scond = C_SCOND_LO; // OR.LO bl>>creg, ah p1 = gregshift(AORR, &bl, SHIFT_LR, &creg, &ah); p1->scond = C_SCOND_LO; // BLO end p3 = gbranch(ABLO, T); // shift == 32 p1 = gins(AEOR, &al, &al); p1->scond = C_SCOND_EQ; p1 = gins(AMOVW, &bl, &ah); p1->scond = C_SCOND_EQ; p4 = gbranch(ABEQ, T); // shift is < 64 nodconst(&n1, types[TUINT32], 64); gmove(&n1, &creg); gcmp(ACMP, &s, &creg); // EOR.LO al, al p1 = gins(AEOR, &al, &al); p1->scond = C_SCOND_LO; // MOVW.LO creg>>1, creg p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg); p1->scond = C_SCOND_LO; // SUB.LO creg, s p1 = gins(ASUB, &creg, &s); p1->scond = C_SCOND_LO; // MOVW bl<<s, ah p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &ah); p1->scond = C_SCOND_LO; p5 = gbranch(ABLO, T); // shift >= 64 if (p6 != P) patch(p6, pc); gins(AEOR, &al, &al); gins(AEOR, &ah, &ah); patch(p2, pc); patch(p3, pc); patch(p4, pc); patch(p5, pc); regfree(&s); regfree(&creg); olsh_break: regfree(&bl); regfree(&bh); break; case ORSH: regalloc(&bl, lo1.type, N); regalloc(&bh, hi1.type, N); gins(AMOVW, &hi1, &bh); gins(AMOVW, &lo1, &bl); if(r->op == OLITERAL) { v = mpgetfix(r->val.u.xval); if(v >= 64) { if(bh.type->etype == TINT32) { // MOVW bh->31, al gshift(AMOVW, &bh, SHIFT_AR, 31, &al); // MOVW bh->31, ah gshift(AMOVW, &bh, SHIFT_AR, 31, &ah); } else { gins(AEOR, &al, &al); gins(AEOR, &ah, &ah); } } else if(v > 32) { if(bh.type->etype == TINT32) { // MOVW bh->(v-32), al gshift(AMOVW, &bh, SHIFT_AR, v-32, &al); // MOVW bh->31, ah gshift(AMOVW, &bh, SHIFT_AR, 31, &ah); } else { // MOVW bh>>(v-32), al gshift(AMOVW, &bh, SHIFT_LR, v-32, &al); gins(AEOR, &ah, &ah); } } else if(v == 32) { gins(AMOVW, &bh, &al); if(bh.type->etype == TINT32) { // MOVW bh->31, ah gshift(AMOVW, &bh, SHIFT_AR, 31, &ah); } else { gins(AEOR, &ah, &ah); } } else if( v > 0) { // MOVW bl>>v, al gshift(AMOVW, &bl, SHIFT_LR, v, &al); // OR bh<<(32-v), al gshift(AORR, &bh, SHIFT_LL, 32-v, &al); if(bh.type->etype == TINT32) { // MOVW bh->v, ah gshift(AMOVW, &bh, SHIFT_AR, v, &ah); } else { // MOVW bh>>v, ah gshift(AMOVW, &bh, SHIFT_LR, v, &ah); } } else { gins(AMOVW, &bl, &al); gins(AMOVW, &bh, &ah); } goto orsh_break; } regalloc(&s, types[TUINT32], N); regalloc(&creg, types[TUINT32], N); if (is64(r->type)) { // shift is >= 1<<32 split64(r, &cl, &ch); gmove(&ch, &s); p1 = gins(AMOVW, &s, &s); p1->scond |= C_SBIT; p6 = gbranch(ABNE, T); gmove(&cl, &s); splitclean(); } else { gmove(r, &s); p6 = P; } p1 = gins(AMOVW, &s, &s); p1->scond |= C_SBIT; // shift == 0 p1 = gins(AMOVW, &bl, &al); p1->scond = C_SCOND_EQ; p1 = gins(AMOVW, &bh, &ah); p1->scond = C_SCOND_EQ; p2 = gbranch(ABEQ, T); // check if shift is < 32 nodconst(&n1, types[TUINT32], 32); gmove(&n1, &creg); gcmp(ACMP, &s, &creg); // MOVW.LO bl>>s, al p1 = gregshift(AMOVW, &bl, SHIFT_LR, &s, &al); p1->scond = C_SCOND_LO; // SUB.LO s,creg p1 = gins(ASUB, &s, &creg); p1->scond = C_SCOND_LO; // OR.LO bh<<(32-s), al p1 = gregshift(AORR, &bh, SHIFT_LL, &creg, &al); p1->scond = C_SCOND_LO; if(bh.type->etype == TINT32) { // MOVW bh->s, ah p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &ah); } else { // MOVW bh>>s, ah p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &ah); } p1->scond = C_SCOND_LO; // BLO end p3 = gbranch(ABLO, T); // shift == 32 if(bh.type->etype == TINT32) p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah); else p1 = gins(AEOR, &al, &al); p1->scond = C_SCOND_EQ; p1 = gins(AMOVW, &bh, &al); p1->scond = C_SCOND_EQ; p4 = gbranch(ABEQ, T); // check if shift is < 64 nodconst(&n1, types[TUINT32], 64); gmove(&n1, &creg); gcmp(ACMP, &s, &creg); // MOVW.LO creg>>1, creg p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg); p1->scond = C_SCOND_LO; // SUB.LO creg, s p1 = gins(ASUB, &creg, &s); p1->scond = C_SCOND_LO; if(bh.type->etype == TINT32) { // MOVW bh->(s-32), al p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &al); p1->scond = C_SCOND_LO; // MOVW bh->31, ah p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah); p1->scond = C_SCOND_LO; } else { // MOVW bh>>(v-32), al p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &al); p1->scond = C_SCOND_LO; p1 = gins(AEOR, &ah, &ah); p1->scond = C_SCOND_LO; } // BLO end p5 = gbranch(ABLO, T); // s >= 64 if (p6 != P) patch(p6, pc); if(bh.type->etype == TINT32) { // MOVW bh->31, al gshift(AMOVW, &bh, SHIFT_AR, 31, &al); // MOVW bh->31, ah gshift(AMOVW, &bh, SHIFT_AR, 31, &ah); } else { gins(AEOR, &al, &al); gins(AEOR, &ah, &ah); } patch(p2, pc); patch(p3, pc); patch(p4, pc); patch(p5, pc); regfree(&s); regfree(&creg); orsh_break: regfree(&bl); regfree(&bh); break; case OXOR: case OAND: case OOR: // TODO(kaib): literal optimizations // make constant the right side (it usually is anyway). // if(lo1.op == OLITERAL) { // nswap(&lo1, &lo2); // nswap(&hi1, &hi2); // } // if(lo2.op == OLITERAL) { // // special cases for constants. // lv = mpgetfix(lo2.val.u.xval); // hv = mpgetfix(hi2.val.u.xval); // splitclean(); // right side // split64(res, &lo2, &hi2); // switch(n->op) { // case OXOR: // gmove(&lo1, &lo2); // gmove(&hi1, &hi2); // switch(lv) { // case 0: // break; // case 0xffffffffu: // gins(ANOTL, N, &lo2); // break; // default: // gins(AXORL, ncon(lv), &lo2); // break; // } // switch(hv) { // case 0: // break; // case 0xffffffffu: // gins(ANOTL, N, &hi2); // break; // default: // gins(AXORL, ncon(hv), &hi2); // break; // } // break; // case OAND: // switch(lv) { // case 0: // gins(AMOVL, ncon(0), &lo2); // break; // default: // gmove(&lo1, &lo2); // if(lv != 0xffffffffu) // gins(AANDL, ncon(lv), &lo2); // break; // } // switch(hv) { // case 0: // gins(AMOVL, ncon(0), &hi2); // break; // default: // gmove(&hi1, &hi2); // if(hv != 0xffffffffu) // gins(AANDL, ncon(hv), &hi2); // break; // } // break; // case OOR: // switch(lv) { // case 0: // gmove(&lo1, &lo2); // break; // case 0xffffffffu: // gins(AMOVL, ncon(0xffffffffu), &lo2); // break; // default: // gmove(&lo1, &lo2); // gins(AORL, ncon(lv), &lo2); // break; // } // switch(hv) { // case 0: // gmove(&hi1, &hi2); // break; // case 0xffffffffu: // gins(AMOVL, ncon(0xffffffffu), &hi2); // break; // default: // gmove(&hi1, &hi2); // gins(AORL, ncon(hv), &hi2); // break; // } // break; // } // splitclean(); // splitclean(); // goto out; // } regalloc(&n1, lo1.type, N); gins(AMOVW, &lo1, &al); gins(AMOVW, &hi1, &ah); gins(AMOVW, &lo2, &n1); gins(optoas(n->op, lo1.type), &n1, &al); gins(AMOVW, &hi2, &n1); gins(optoas(n->op, lo1.type), &n1, &ah); regfree(&n1); break; } if(is64(r->type)) splitclean(); splitclean(); split64(res, &lo1, &hi1); gins(AMOVW, &al, &lo1); gins(AMOVW, &ah, &hi1); splitclean(); //out: regfree(&al); regfree(&ah); }
void cgen(Node *n, Node *nn) { Node *l, *r; Prog *p1; Node nod, nod1, nod2, nod3, nod4; int o; long v, curs; if(debug['g']) { prtree(nn, "cgen lhs"); prtree(n, "cgen"); } if(n == Z || n->type == T) return; if(typesuv[n->type->etype]) { sugen(n, nn, n->type->width); return; } l = n->left; r = n->right; o = n->op; if(n->addable >= INDEXED) { if(nn == Z) { switch(o) { default: nullwarn(Z, Z); break; case OINDEX: nullwarn(l, r); break; } return; } gmove(n, nn); return; } curs = cursafe; if(n->complex >= FNX) if(l->complex >= FNX) if(r != Z && r->complex >= FNX) switch(o) { default: regret(&nod, r); cgen(r, &nod); regsalloc(&nod1, r); gopcode(OAS, &nod, Z, &nod1); regfree(&nod); nod = *n; nod.right = &nod1; cgen(&nod, nn); return; case OFUNC: case OCOMMA: case OANDAND: case OOROR: case OCOND: case ODOT: break; } switch(o) { default: diag(n, "unknown op in cgen: %O", o); break; case OAS: if(l->op == OBIT) goto bitas; if(l->addable >= INDEXED && l->complex < FNX) { if(nn != Z || r->addable < INDEXED) { if(r->complex >= FNX && nn == Z) regret(&nod, r); else regalloc(&nod, r, nn); cgen(r, &nod); gmove(&nod, l); if(nn != Z) gmove(&nod, nn); regfree(&nod); } else gmove(r, l); break; } if(l->complex >= r->complex) { reglcgen(&nod1, l, Z); if(r->addable >= INDEXED) { gmove(r, &nod1); if(nn != Z) gmove(r, nn); regfree(&nod1); break; } regalloc(&nod, r, nn); cgen(r, &nod); } else { regalloc(&nod, r, nn); cgen(r, &nod); reglcgen(&nod1, l, Z); } gmove(&nod, &nod1); regfree(&nod); regfree(&nod1); break; bitas: n = l->left; regalloc(&nod, r, nn); if(l->complex >= r->complex) { reglcgen(&nod1, n, Z); cgen(r, &nod); } else { cgen(r, &nod); reglcgen(&nod1, n, Z); } regalloc(&nod2, n, Z); gopcode(OAS, &nod1, Z, &nod2); bitstore(l, &nod, &nod1, &nod2, nn); break; case OBIT: if(nn == Z) { nullwarn(l, Z); break; } bitload(n, &nod, Z, Z, nn); gopcode(OAS, &nod, Z, nn); regfree(&nod); break; case OADD: case OSUB: case OAND: case OOR: case OXOR: case OLSHR: case OASHL: case OASHR: /* * immediate operands */ if(nn != Z) if(r->op == OCONST) if(!typefd[n->type->etype]) { cgen(l, nn); if(r->vconst == 0) if(o != OAND) break; if(nn != Z) gopcode(o, r, Z, nn); break; } case OLMUL: case OLDIV: case OLMOD: case OMUL: case ODIV: case OMOD: if(nn == Z) { nullwarn(l, r); break; } if(o == OMUL || o == OLMUL) { if(mulcon(n, nn)) break; } if(l->complex >= r->complex) { regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, r, Z); cgen(r, &nod1); gopcode(o, &nod1, Z, &nod); } else { regalloc(&nod, r, nn); cgen(r, &nod); regalloc(&nod1, l, Z); cgen(l, &nod1); gopcode(o, &nod, &nod1, &nod); } gopcode(OAS, &nod, Z, nn); regfree(&nod); regfree(&nod1); break; case OASLSHR: case OASASHL: case OASASHR: case OASAND: case OASADD: case OASSUB: case OASXOR: case OASOR: if(l->op == OBIT) goto asbitop; if(r->op == OCONST) if(!typefd[r->type->etype]) if(!typefd[n->type->etype]) { if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, r, nn); gopcode(OAS, &nod2, Z, &nod); gopcode(o, r, Z, &nod); gopcode(OAS, &nod, Z, &nod2); regfree(&nod); if(l->addable < INDEXED) regfree(&nod2); break; } case OASLMUL: case OASLDIV: case OASLMOD: case OASMUL: case OASDIV: case OASMOD: if(l->op == OBIT) goto asbitop; if(l->complex >= r->complex) { if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod1, r, Z); cgen(r, &nod1); } else { regalloc(&nod1, r, Z); cgen(r, &nod1); if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; } regalloc(&nod, n, nn); gmove(&nod2, &nod); gopcode(o, &nod1, Z, &nod); gmove(&nod, &nod2); if(nn != Z) gopcode(OAS, &nod, Z, nn); regfree(&nod); regfree(&nod1); if(l->addable < INDEXED) regfree(&nod2); break; asbitop: regalloc(&nod4, n, nn); if(l->complex >= r->complex) { bitload(l, &nod, &nod1, &nod2, &nod4); regalloc(&nod3, r, Z); cgen(r, &nod3); } else { regalloc(&nod3, r, Z); cgen(r, &nod3); bitload(l, &nod, &nod1, &nod2, &nod4); } gmove(&nod, &nod4); gopcode(o, &nod3, Z, &nod4); regfree(&nod3); gmove(&nod4, &nod); regfree(&nod4); bitstore(l, &nod, &nod1, &nod2, nn); break; case OADDR: if(nn == Z) { nullwarn(l, Z); break; } lcgen(l, nn); break; case OFUNC: if(l->complex >= FNX) { if(l->op != OIND) diag(n, "bad function call"); regret(&nod, l->left); cgen(l->left, &nod); regsalloc(&nod1, l->left); gopcode(OAS, &nod, Z, &nod1); regfree(&nod); nod = *n; nod.left = &nod2; nod2 = *l; nod2.left = &nod1; nod2.complex = 1; cgen(&nod, nn); return; } o = reg[REGARG]; gargs(r, &nod, &nod1); if(l->addable < INDEXED) { reglcgen(&nod, l, Z); gopcode(OFUNC, Z, Z, &nod); regfree(&nod); } else gopcode(OFUNC, Z, Z, l); if(REGARG) if(o != reg[REGARG]) reg[REGARG]--; if(nn != Z) { regret(&nod, n); gopcode(OAS, &nod, Z, nn); regfree(&nod); } break; case OIND: if(nn == Z) { nullwarn(l, Z); break; } regialloc(&nod, n, nn); r = l; while(r->op == OADD) r = r->right; if(sconst(r)) { v = r->vconst; r->vconst = 0; cgen(l, &nod); nod.xoffset += v; r->vconst = v; } else cgen(l, &nod); regind(&nod, n); gopcode(OAS, &nod, Z, nn); regfree(&nod); break; case OEQ: case ONE: case OLE: case OLT: case OGE: case OGT: case OLO: case OLS: case OHI: case OHS: if(nn == Z) { nullwarn(l, r); break; } boolgen(n, 1, nn); break; case OANDAND: case OOROR: boolgen(n, 1, nn); if(nn == Z) patch(p, pc); break; case ONOT: if(nn == Z) { nullwarn(l, Z); break; } boolgen(n, 1, nn); break; case OCOMMA: cgen(l, Z); cgen(r, nn); break; case OCAST: if(nn == Z) { nullwarn(l, Z); break; } /* * convert from types l->n->nn */ if(nocast(l->type, n->type)) { if(nocast(n->type, nn->type)) { cgen(l, nn); break; } } regalloc(&nod, l, nn); cgen(l, &nod); regalloc(&nod1, n, &nod); gopcode(OAS, &nod, Z, &nod1); gopcode(OAS, &nod1, Z, nn); regfree(&nod1); regfree(&nod); break; case ODOT: sugen(l, nodrat, l->type->width); if(nn != Z) { warn(n, "non-interruptable temporary"); nod = *nodrat; if(!r || r->op != OCONST) { diag(n, "DOT and no offset"); break; } nod.xoffset += (long)r->vconst; nod.type = n->type; cgen(&nod, nn); } break; case OCOND: bcgen(l, 1); p1 = p; cgen(r->left, nn); gbranch(OGOTO); patch(p1, pc); p1 = p; cgen(r->right, nn); patch(p1, pc); break; case OPOSTINC: case OPOSTDEC: v = 1; if(l->type->etype == TIND) v = l->type->link->width; if(o == OPOSTDEC) v = -v; if(l->op == OBIT) goto bitinc; if(nn == Z) goto pre; if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, l, nn); gopcode(OAS, &nod2, Z, &nod); regalloc(&nod1, l, Z); if(typefd[l->type->etype]) { regalloc(&nod3, l, Z); if(v < 0) { gopcode(OAS, nodfconst(-v), Z, &nod3); gopcode(OSUB, &nod3, &nod, &nod1); } else { gopcode(OAS, nodfconst(v), Z, &nod3); gopcode(OADD, &nod3, &nod, &nod1); } regfree(&nod3); } else gopcode(OADD, nodconst(v), &nod, &nod1); gopcode(OAS, &nod1, Z, &nod2); regfree(&nod); regfree(&nod1); if(l->addable < INDEXED) regfree(&nod2); break; case OPREINC: case OPREDEC: v = 1; if(l->type->etype == TIND) v = l->type->link->width; if(o == OPREDEC) v = -v; if(l->op == OBIT) goto bitinc; pre: if(l->addable < INDEXED) reglcgen(&nod2, l, Z); else nod2 = *l; regalloc(&nod, l, nn); gopcode(OAS, &nod2, Z, &nod); if(typefd[l->type->etype]) { regalloc(&nod3, l, Z); if(v < 0) { gopcode(OAS, nodfconst(-v), Z, &nod3); gopcode(OSUB, &nod3, Z, &nod); } else { gopcode(OAS, nodfconst(v), Z, &nod3); gopcode(OADD, &nod3, Z, &nod); } regfree(&nod3); } else gopcode(OADD, nodconst(v), Z, &nod); gopcode(OAS, &nod, Z, &nod2); if(nn && l->op == ONAME) /* in x=++i, emit USED(i) */ gins(ANOP, l, Z); regfree(&nod); if(l->addable < INDEXED) regfree(&nod2); break; bitinc: if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) { bitload(l, &nod, &nod1, &nod2, Z); gopcode(OAS, &nod, Z, nn); gopcode(OADD, nodconst(v), Z, &nod); bitstore(l, &nod, &nod1, &nod2, Z); break; } bitload(l, &nod, &nod1, &nod2, nn); gopcode(OADD, nodconst(v), Z, &nod); bitstore(l, &nod, &nod1, &nod2, nn); break; } cursafe = curs; }
/* * generate: * res = n; * simplifies and calls gmove. */ void cgen(Node *n, Node *res) { Node *nl, *nr, *r; Node n1, n2; int a, f; Prog *p1, *p2, *p3; Addr addr; if(debug['g']) { dump("\ncgen-n", n); dump("cgen-res", res); } if(n == N || n->type == T) goto ret; if(res == N || res->type == T) fatal("cgen: res nil"); while(n->op == OCONVNOP) n = n->left; // inline slices if(cgen_inline(n, res)) goto ret; if(n->ullman >= UINF) { if(n->op == OINDREG) fatal("cgen: this is going to misscompile"); if(res->ullman >= UINF) { tempname(&n1, n->type); cgen(n, &n1); cgen(&n1, res); goto ret; } } if(isfat(n->type)) { sgen(n, res, n->type->width); goto ret; } if(!res->addable) { if(n->ullman > res->ullman) { regalloc(&n1, n->type, res); cgen(n, &n1); if(n1.ullman > res->ullman) { dump("n1", &n1); dump("res", res); fatal("loop in cgen"); } cgen(&n1, res); regfree(&n1); goto ret; } if(res->ullman >= UINF) goto gen; if(complexop(n, res)) { complexgen(n, res); goto ret; } f = 1; // gen thru register switch(n->op) { case OLITERAL: if(smallintconst(n)) f = 0; break; case OREGISTER: f = 0; break; } if(!iscomplex[n->type->etype]) { a = optoas(OAS, res->type); if(sudoaddable(a, res, &addr)) { if(f) { regalloc(&n2, res->type, N); cgen(n, &n2); p1 = gins(a, &n2, N); regfree(&n2); } else p1 = gins(a, n, N); p1->to = addr; if(debug['g']) print("%P [ignore previous line]\n", p1); sudoclean(); goto ret; } } gen: igen(res, &n1, N); cgen(n, &n1); regfree(&n1); goto ret; } // update addressability for string, slice // can't do in walk because n->left->addable // changes if n->left is an escaping local variable. switch(n->op) { case OLEN: if(isslice(n->left->type) || istype(n->left->type, TSTRING)) n->addable = n->left->addable; break; case OCAP: if(isslice(n->left->type)) n->addable = n->left->addable; break; } if(complexop(n, res)) { complexgen(n, res); goto ret; } if(n->addable) { gmove(n, res); goto ret; } nl = n->left; nr = n->right; if(nl != N && nl->ullman >= UINF) if(nr != N && nr->ullman >= UINF) { tempname(&n1, nl->type); cgen(nl, &n1); n2 = *n; n2.left = &n1; cgen(&n2, res); goto ret; } if(!iscomplex[n->type->etype]) { a = optoas(OAS, n->type); if(sudoaddable(a, n, &addr)) { if(res->op == OREGISTER) { p1 = gins(a, N, res); p1->from = addr; } else { regalloc(&n2, n->type, N); p1 = gins(a, N, &n2); p1->from = addr; gins(a, &n2, res); regfree(&n2); } sudoclean(); goto ret; } } switch(n->op) { default: dump("cgen", n); fatal("cgen: unknown op %N", n); break; // these call bgen to get a bool value case OOROR: case OANDAND: case OEQ: case ONE: case OLT: case OLE: case OGE: case OGT: case ONOT: p1 = gbranch(AJMP, T); p2 = pc; gmove(nodbool(1), res); p3 = gbranch(AJMP, T); patch(p1, pc); bgen(n, 1, p2); gmove(nodbool(0), res); patch(p3, pc); goto ret; case OPLUS: cgen(nl, res); goto ret; // unary case OCOM: a = optoas(OXOR, nl->type); regalloc(&n1, nl->type, N); cgen(nl, &n1); nodconst(&n2, nl->type, -1); gins(a, &n2, &n1); gmove(&n1, res); regfree(&n1); goto ret; case OMINUS: if(isfloat[nl->type->etype]) { nr = nodintconst(-1); convlit(&nr, n->type); a = optoas(OMUL, nl->type); goto sbop; } a = optoas(n->op, nl->type); goto uop; // symmetric binary case OAND: case OOR: case OXOR: case OADD: case OMUL: a = optoas(n->op, nl->type); if(a != AIMULB) goto sbop; cgen_bmul(n->op, nl, nr, res); break; // asymmetric binary case OSUB: a = optoas(n->op, nl->type); goto abop; case OCONV: regalloc(&n1, nl->type, res); regalloc(&n2, n->type, &n1); cgen(nl, &n1); // if we do the conversion n1 -> n2 here // reusing the register, then gmove won't // have to allocate its own register. gmove(&n1, &n2); gmove(&n2, res); regfree(&n2); regfree(&n1); break; case ODOT: case ODOTPTR: case OINDEX: case OIND: case ONAME: // PHEAP or PPARAMREF var igen(n, &n1, res); gmove(&n1, res); regfree(&n1); break; case OLEN: if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) { // map and chan have len in the first 32-bit word. // a zero pointer means zero length regalloc(&n1, types[tptr], res); cgen(nl, &n1); nodconst(&n2, types[tptr], 0); gins(optoas(OCMP, types[tptr]), &n1, &n2); p1 = gbranch(optoas(OEQ, types[tptr]), T); n2 = n1; n2.op = OINDREG; n2.type = types[TINT32]; gmove(&n2, &n1); patch(p1, pc); gmove(&n1, res); regfree(&n1); break; } if(istype(nl->type, TSTRING) || isslice(nl->type)) { // both slice and string have len one pointer into the struct. // a zero pointer means zero length regalloc(&n1, types[tptr], res); agen(nl, &n1); n1.op = OINDREG; n1.type = types[TUINT32]; n1.xoffset = Array_nel; gmove(&n1, res); regfree(&n1); break; } fatal("cgen: OLEN: unknown type %lT", nl->type); break; case OCAP: if(istype(nl->type, TCHAN)) { // chan has cap in the second 32-bit word. // a zero pointer means zero length regalloc(&n1, types[tptr], res); cgen(nl, &n1); nodconst(&n2, types[tptr], 0); gins(optoas(OCMP, types[tptr]), &n1, &n2); p1 = gbranch(optoas(OEQ, types[tptr]), T); n2 = n1; n2.op = OINDREG; n2.xoffset = 4; n2.type = types[TINT32]; gmove(&n2, &n1); patch(p1, pc); gmove(&n1, res); regfree(&n1); break; } if(isslice(nl->type)) { regalloc(&n1, types[tptr], res); agen(nl, &n1); n1.op = OINDREG; n1.type = types[TUINT32]; n1.xoffset = Array_cap; gmove(&n1, res); regfree(&n1); break; } fatal("cgen: OCAP: unknown type %lT", nl->type); break; case OADDR: agen(nl, res); break; case OCALLMETH: cgen_callmeth(n, 0); cgen_callret(n, res); break; case OCALLINTER: cgen_callinter(n, res, 0); cgen_callret(n, res); break; case OCALLFUNC: cgen_call(n, 0); cgen_callret(n, res); break; case OMOD: case ODIV: if(isfloat[n->type->etype]) { a = optoas(n->op, nl->type); goto abop; } cgen_div(n->op, nl, nr, res); break; case OLSH: case ORSH: cgen_shift(n->op, nl, nr, res); break; } goto ret; sbop: // symmetric binary if(nl->ullman < nr->ullman) { r = nl; nl = nr; nr = r; } abop: // asymmetric binary if(nl->ullman >= nr->ullman) { regalloc(&n1, nl->type, res); cgen(nl, &n1); if(sudoaddable(a, nr, &addr)) { p1 = gins(a, N, &n1); p1->from = addr; gmove(&n1, res); sudoclean(); regfree(&n1); goto ret; } regalloc(&n2, nr->type, N); cgen(nr, &n2); } else { regalloc(&n2, nr->type, N); cgen(nr, &n2); regalloc(&n1, nl->type, res); cgen(nl, &n1); } gins(a, &n2, &n1); gmove(&n1, res); regfree(&n1); regfree(&n2); goto ret; uop: // unary regalloc(&n1, nl->type, res); cgen(nl, &n1); gins(a, N, &n1); gmove(&n1, res); regfree(&n1); goto ret; ret: ; }