Node* typebsw(Case *c0, int ncase) { NodeList *cas; Node *a, *n; Case *c; int i, half; Val v; cas = nil; if(ncase < Ncase) { for(i=0; i<ncase; i++) { n = c0->node; switch(c0->type) { case Ttypenil: v.ctype = CTNIL; a = nod(OIF, N, N); a->ntest = nod(OEQ, facename, nodlit(v)); typecheck(&a->ntest, Erv); a->nbody = list1(n->right); // if i==nil { goto l } cas = list(cas, a); break; case Ttypevar: a = typeone(n); cas = list(cas, a); break; case Ttypeconst: a = nod(OIF, N, N); a->ntest = nod(OEQ, hashname, nodintconst(c0->hash)); typecheck(&a->ntest, Erv); a->nbody = list1(typeone(n)); cas = list(cas, a); break; } c0 = c0->link; } return liststmt(cas); } // find the middle and recur c = c0; half = ncase>>1; for(i=1; i<half; i++) c = c->link; a = nod(OIF, N, N); a->ntest = nod(OLE, hashname, nodintconst(c->hash)); typecheck(&a->ntest, Erv); a->nbody = list1(typebsw(c0, half)); a->nelse = list1(typebsw(c->link, ncase-half)); return a; }
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; }
static Node* typebsw(Case *c0, int ncase) { NodeList *cas; Node *a, *n; Case *c; int i, half; cas = nil; if(ncase < Ncase) { for(i=0; i<ncase; i++) { n = c0->node; if(c0->type != Ttypeconst) fatal("typebsw"); a = nod(OIF, N, N); a->ntest = nod(OEQ, hashname, nodintconst(c0->hash)); typecheck(&a->ntest, Erv); a->nbody = list1(n->right); cas = list(cas, a); c0 = c0->link; } return liststmt(cas); } // find the middle and recur c = c0; half = ncase>>1; for(i=1; i<half; i++) c = c->link; a = nod(OIF, N, N); a->ntest = nod(OLE, hashname, nodintconst(c->hash)); typecheck(&a->ntest, Erv); a->nbody = list1(typebsw(c0, half)); a->nelse = list1(typebsw(c->link, ncase-half)); return a; }
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; }
static int callinstr(Node **np, NodeList **init, int wr, int skip) { Node *f, *b, *n; Type *t; int class, hascalls; n = *np; //print("callinstr for %+N [ %O ] etype=%E class=%d\n", // n, n->op, n->type ? n->type->etype : -1, n->class); if(skip || n->type == T || n->type->etype >= TIDEAL) return 0; t = n->type; if(isartificial(n)) return 0; b = basenod(n); // it skips e.g. stores to ... parameter array if(isartificial(b)) return 0; class = b->class; // BUG: we _may_ want to instrument PAUTO sometimes // e.g. if we've got a local variable/method receiver // that has got a pointer inside. Whether it points to // the heap or not is impossible to know at compile time if((class&PHEAP) || class == PPARAMREF || class == PEXTERN || b->op == OINDEX || b->op == ODOTPTR || b->op == OIND || b->op == OXDOT) { hascalls = 0; foreach(n, hascallspred, &hascalls); if(hascalls) { n = detachexpr(n, init); *np = n; } n = treecopy(n); makeaddable(n); if(t->etype == TSTRUCT || isfixedarray(t)) { f = mkcall(wr ? "racewriterange" : "racereadrange", T, init, uintptraddr(n), nodintconst(t->width)); } else f = mkcall(wr ? "racewrite" : "raceread", T, init, uintptraddr(n)); *init = list(*init, f); return 1; } return 0; }
void walkrange(Node *n) { Node *ohv1, *hv1, *hv2; // hidden (old) val 1, 2 Node *ha, *hit; // hidden aggregate, iterator Node *hn, *hp; // hidden len, pointer Node *hb; // hidden bool Node *a, *v1, *v2; // not hidden aggregate, val 1, 2 Node *fn, *tmp; NodeList *body, *init; Type *th, *t; int lno; t = n->type; init = nil; a = n->right; lno = setlineno(a); if(t->etype == TSTRING && !eqtype(t, types[TSTRING])) { a = nod(OCONV, n->right, N); a->type = types[TSTRING]; } v1 = n->list->n; v2 = N; if(n->list->next) v2 = n->list->next->n; hv2 = N; if(v2 == N && t->etype == TARRAY) { // will have just one reference to argument. // no need to make a potentially expensive copy. ha = a; } else { ha = temp(a->type); init = list(init, nod(OAS, ha, a)); } switch(t->etype) { default: fatal("walkrange"); case TARRAY: hv1 = temp(types[TINT]); hn = temp(types[TINT]); hp = nil; init = list(init, nod(OAS, hv1, N)); init = list(init, nod(OAS, hn, nod(OLEN, ha, N))); if(v2) { hp = temp(ptrto(n->type->type)); tmp = nod(OINDEX, ha, nodintconst(0)); tmp->etype = 1; // no bounds check init = list(init, nod(OAS, hp, nod(OADDR, tmp, N))); } n->ntest = nod(OLT, hv1, hn); n->nincr = nod(OASOP, hv1, nodintconst(1)); n->nincr->etype = OADD; if(v2 == N) body = list1(nod(OAS, v1, hv1)); else { a = nod(OAS2, N, N); a->list = list(list1(v1), v2); a->rlist = list(list1(hv1), nod(OIND, hp, N)); body = list1(a); tmp = nod(OADD, hp, nodintconst(t->type->width)); tmp->type = hp->type; tmp->typecheck = 1; tmp->right->type = types[tptr]; tmp->right->typecheck = 1; body = list(body, nod(OAS, hp, tmp)); } break; case TMAP: th = typ(TARRAY); th->type = ptrto(types[TUINT8]); // see ../../pkg/runtime/hashmap.h:/hash_iter // Size in words. th->bound = 5 + 4*3 + 4*4/widthptr; hit = temp(th); fn = syslook("mapiterinit", 1); argtype(fn, t->down); argtype(fn, t->type); argtype(fn, th); init = list(init, mkcall1(fn, T, nil, typename(t), ha, nod(OADDR, hit, N))); n->ntest = nod(ONE, nod(OINDEX, hit, nodintconst(0)), nodnil()); fn = syslook("mapiternext", 1); argtype(fn, th); n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N)); if(v2 == N) { fn = syslook("mapiter1", 1); argtype(fn, th); argtype(fn, t->down); a = nod(OAS, v1, mkcall1(fn, t->down, nil, nod(OADDR, hit, N))); } else { fn = syslook("mapiter2", 1); argtype(fn, th); argtype(fn, t->down); argtype(fn, t->type); a = nod(OAS2, N, N); a->list = list(list1(v1), v2); a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, nod(OADDR, hit, N))); } body = list1(a); break; case TCHAN: hv1 = temp(t->type); hb = temp(types[TBOOL]); n->ntest = nod(ONE, hb, nodbool(0)); a = nod(OAS2RECV, N, N); a->typecheck = 1; a->list = list(list1(hv1), hb); a->rlist = list1(nod(ORECV, ha, N)); n->ntest->ninit = list1(a); body = list1(nod(OAS, v1, hv1)); break; case TSTRING: ohv1 = temp(types[TINT]); hv1 = temp(types[TINT]); init = list(init, nod(OAS, hv1, N)); if(v2 == N) a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1)); else { hv2 = temp(runetype); a = nod(OAS2, N, N); a->list = list(list1(hv1), hv2); fn = syslook("stringiter2", 0); a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1)); } n->ntest = nod(ONE, hv1, nodintconst(0)); n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a); body = list1(nod(OAS, v1, ohv1)); if(v2 != N) body = list(body, nod(OAS, v2, hv2)); break; } n->op = OFOR; typechecklist(init, Etop); n->ninit = concat(n->ninit, init); typechecklist(n->ntest->ninit, Etop); typecheck(&n->ntest, Erv); typecheck(&n->nincr, Etop); typechecklist(body, Etop); n->nbody = concat(body, n->nbody); walkstmt(&n); lineno = lno; }
static void maplit(int ctxt, Node *n, Node *var, NodeList **init) { Node *r, *a; NodeList *l; int nerr, b; Type *t, *tk, *tv, *t1; Node *vstat, *index, *value; Sym *syma, *symb; ctxt = 0; // make the map var nerr = nerrors; a = nod(OMAKE, N, N); a->list = list1(typenod(n->type)); litas(var, a, init); // count the initializers b = 0; for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; if(isliteral(index) && isliteral(value)) b++; } t = T; if(b != 0) { // build type [count]struct { a Tindex, b Tvalue } t = n->type; tk = t->down; tv = t->type; symb = lookup("b"); t = typ(TFIELD); t->type = tv; t->sym = symb; syma = lookup("a"); t1 = t; t = typ(TFIELD); t->type = tk; t->sym = syma; t->down = t1; t1 = t; t = typ(TSTRUCT); t->type = t1; t1 = t; t = typ(TARRAY); t->bound = b; t->type = t1; dowidth(t); // make and initialize static array vstat = staticname(t, ctxt); b = 0; for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; if(isliteral(index) && isliteral(value)) { // build vstat[b].a = key; a = nodintconst(b); a = nod(OINDEX, vstat, a); a = nod(ODOT, a, newname(syma)); a = nod(OAS, a, index); typecheck(&a, Etop); walkexpr(&a, init); a->dodata = 2; *init = list(*init, a); // build vstat[b].b = value; a = nodintconst(b); a = nod(OINDEX, vstat, a); a = nod(ODOT, a, newname(symb)); a = nod(OAS, a, value); typecheck(&a, Etop); walkexpr(&a, init); a->dodata = 2; *init = list(*init, a); b++; } } // loop adding structure elements to map // for i = 0; i < len(vstat); i++ { // map[vstat[i].a] = vstat[i].b // } index = nod(OXXX, N, N); tempname(index, types[TINT]); a = nod(OINDEX, vstat, index); a->etype = 1; // no bounds checking a = nod(ODOT, a, newname(symb)); r = nod(OINDEX, vstat, index); r->etype = 1; // no bounds checking r = nod(ODOT, r, newname(syma)); r = nod(OINDEX, var, r); r = nod(OAS, r, a); a = nod(OFOR, N, N); a->nbody = list1(r); a->ninit = list1(nod(OAS, index, nodintconst(0))); a->ntest = nod(OLT, index, nodintconst(t->bound)); a->nincr = nod(OASOP, index, nodintconst(1)); a->nincr->etype = OADD; typecheck(&a, Etop); walkstmt(&a); *init = list(*init, a); } // put in dynamic entries one-at-a-time for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; if(isliteral(index) && isliteral(value)) continue; // build list of var[c] = expr a = nod(OINDEX, var, r->left); a = nod(OAS, a, r->right); typecheck(&a, Etop); walkexpr(&a, init); if(nerr != nerrors) break; *init = list(*init, a); } }
void walkrange(Node *n) { Node *ohv1, *hv1, *hv2; // hidden (old) val 1, 2 Node *ha, *hit; // hidden aggregate, iterator Node *a, *v1, *v2; // not hidden aggregate, val 1, 2 Node *fn; NodeList *body, *init; Type *th, *t; t = n->type; init = nil; a = n->right; if(t->etype == TSTRING && !eqtype(t, types[TSTRING])) { a = nod(OCONV, n->right, N); a->type = types[TSTRING]; } ha = nod(OXXX, N, N); tempname(ha, a->type); init = list(init, nod(OAS, ha, a)); v1 = n->list->n; hv1 = N; v2 = N; if(n->list->next) v2 = n->list->next->n; hv2 = N; switch(t->etype) { default: fatal("walkrange"); case TARRAY: hv1 = nod(OXXX, N, n); tempname(hv1, types[TINT]); init = list(init, nod(OAS, hv1, N)); n->ntest = nod(OLT, hv1, nod(OLEN, ha, N)); n->nincr = nod(OASOP, hv1, nodintconst(1)); n->nincr->etype = OADD; body = list1(nod(OAS, v1, hv1)); if(v2) body = list(body, nod(OAS, v2, nod(OINDEX, ha, hv1))); break; case TMAP: th = typ(TARRAY); th->type = ptrto(types[TUINT8]); th->bound = (sizeof(struct Hiter) + widthptr - 1) / widthptr; hit = nod(OXXX, N, N); tempname(hit, th); fn = syslook("mapiterinit", 1); argtype(fn, t->down); argtype(fn, t->type); argtype(fn, th); init = list(init, mkcall1(fn, T, nil, ha, nod(OADDR, hit, N))); n->ntest = nod(ONE, nod(OINDEX, hit, nodintconst(0)), nodnil()); fn = syslook("mapiternext", 1); argtype(fn, th); n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N)); if(v2 == N) { fn = syslook("mapiter1", 1); argtype(fn, th); argtype(fn, t->down); a = nod(OAS, v1, mkcall1(fn, t->down, nil, nod(OADDR, hit, N))); } else { fn = syslook("mapiter2", 1); argtype(fn, th); argtype(fn, t->down); argtype(fn, t->type); a = nod(OAS2, N, N); a->list = list(list1(v1), v2); a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, nod(OADDR, hit, N))); } body = list1(a); break; case TCHAN: hv1 = nod(OXXX, N, n); tempname(hv1, t->type); n->ntest = nod(ONOT, nod(OCLOSED, ha, N), N); n->ntest->ninit = list1(nod(OAS, hv1, nod(ORECV, ha, N))); body = list1(nod(OAS, v1, hv1)); break; case TSTRING: ohv1 = nod(OXXX, N, N); tempname(ohv1, types[TINT]); hv1 = nod(OXXX, N, N); tempname(hv1, types[TINT]); init = list(init, nod(OAS, hv1, N)); if(v2 == N) a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1)); else { hv2 = nod(OXXX, N, N); tempname(hv2, types[TINT]); a = nod(OAS2, N, N); a->list = list(list1(hv1), hv2); fn = syslook("stringiter2", 0); a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1)); } n->ntest = nod(ONE, hv1, nodintconst(0)); n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a); body = list1(nod(OAS, v1, ohv1)); if(v2 != N) body = list(body, nod(OAS, v2, hv2)); break; } n->op = OFOR; typechecklist(init, Etop); n->ninit = concat(n->ninit, init); typechecklist(n->ntest->ninit, Etop); typecheck(&n->ntest, Erv); typecheck(&n->nincr, Etop); typechecklist(body, Etop); n->nbody = concat(body, n->nbody); walkstmt(&n); }
void fninit(NodeList *n) { int i; Node *gatevar; Node *a, *b, *fn; NodeList *r; uint32 h; Sym *s, *initsym; if(debug['A']) { // sys.go or unsafe.go during compiler build return; } n = initfix(n); if(!anyinit(n)) return; r = nil; // (1) snprint(namebuf, sizeof(namebuf), "initdone·"); gatevar = newname(lookup(namebuf)); addvar(gatevar, types[TUINT8], PEXTERN); // (2) maxarg = 0; snprint(namebuf, sizeof(namebuf), "init"); fn = nod(ODCLFUNC, N, N); initsym = lookup(namebuf); fn->nname = newname(initsym); fn->nname->defn = fn; fn->nname->ntype = nod(OTFUNC, N, N); declare(fn->nname, PFUNC); funchdr(fn); // (3) a = nod(OIF, N, N); a->ntest = nod(ONE, gatevar, nodintconst(0)); r = list(r, a); // (4) b = nod(OIF, N, N); b->ntest = nod(OEQ, gatevar, nodintconst(2)); b->nbody = list1(nod(ORETURN, N, N)); a->nbody = list1(b); // (5) b = syslook("throwinit", 0); b = nod(OCALL, b, N); a->nbody = list(a->nbody, b); // (6) a = nod(OAS, gatevar, nodintconst(1)); r = list(r, a); // (7) for(h=0; h<NHASH; h++) for(s = hash[h]; s != S; s = s->link) { if(s->name[0] != 'i' || strcmp(s->name, "init") != 0) continue; if(s->def == N) continue; if(s == initsym) continue; // could check that it is fn of no args/returns a = nod(OCALL, s->def, N); r = list(r, a); } // (8) r = concat(r, n); // (9) // could check that it is fn of no args/returns for(i=1;; i++) { snprint(namebuf, sizeof(namebuf), "init·%d", i); s = lookup(namebuf); if(s->def == N) break; a = nod(OCALL, s->def, N); r = list(r, a); } // (10) a = nod(OAS, gatevar, nodintconst(2)); r = list(r, a); // (11) a = nod(ORETURN, N, N); r = list(r, a); exportsym(fn->nname); fn->nbody = r; funcbody(fn); curfn = fn; typecheck(&fn, Etop); typechecklist(r, Etop); curfn = nil; funccompile(fn, 0); }
/* * 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: ; }
/* * 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: ; }