/* * 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: ; }
void exprfmt(Fmt *f, Node *n, int prec) { int nprec; char *p; nprec = 0; if(n == nil) { fmtprint(f, "<nil>"); return; } if(n->implicit) { exprfmt(f, n->left, prec); return; } switch(n->op) { case OAPPEND: case ONAME: case ONONAME: case OPACK: case OLITERAL: case ODOT: case ODOTPTR: case ODOTINTER: case ODOTMETH: case ODOTTYPE: case ODOTTYPE2: case OXDOT: case OARRAYBYTESTR: case OCAP: case OCLOSE: case OCOPY: case OLEN: case OMAKE: case ONEW: case OPANIC: case OPRINT: case OPRINTN: case OCALL: case OCALLMETH: case OCALLINTER: case OCALLFUNC: case OCONV: case OCONVNOP: case OMAKESLICE: case ORUNESTR: case OADDR: case OCOM: case OIND: case OMINUS: case ONOT: case OPLUS: case ORECV: case OCONVIFACE: case OTPAREN: case OINDEX: case OINDEXMAP: nprec = 7; break; case OMUL: case ODIV: case OMOD: case OLSH: case ORSH: case OAND: case OANDNOT: nprec = 6; break; case OADD: case OSUB: case OOR: case OXOR: nprec = 5; break; case OEQ: case OLT: case OLE: case OGE: case OGT: case ONE: nprec = 4; break; case OSEND: nprec = 3; break; case OANDAND: nprec = 2; break; case OOROR: nprec = 1; break; case OTYPE: if(n->sym != S) nprec = 7; break; } if(prec > nprec) fmtprint(f, "("); switch(n->op) { default: bad: fmtprint(f, "(node %O)", n->op); break; case OLITERAL: if(n->sym != S) { fmtprint(f, "%S", n->sym); break; } switch(n->val.ctype) { default: goto bad; case CTINT: fmtprint(f, "%B", n->val.u.xval); break; case CTBOOL: if(n->val.u.bval) fmtprint(f, "true"); else fmtprint(f, "false"); break; case CTCPLX: fmtprint(f, "%.17g+%.17gi", mpgetflt(&n->val.u.cval->real), mpgetflt(&n->val.u.cval->imag)); break; case CTFLT: fmtprint(f, "%.17g", mpgetflt(n->val.u.fval)); break; case CTSTR: fmtprint(f, "\"%Z\"", n->val.u.sval); break; case CTNIL: fmtprint(f, "nil"); break; } break; case ONAME: case OPACK: case ONONAME: fmtprint(f, "%S", n->sym); break; case OTYPE: if(n->type == T && n->sym != S) { fmtprint(f, "%S", n->sym); break; } fmtprint(f, "%T", n->type); break; case OTARRAY: fmtprint(f, "[]"); exprfmt(f, n->left, PFIXME); break; case OTPAREN: fmtprint(f, "("); exprfmt(f, n->left, 0); fmtprint(f, ")"); break; case OTMAP: fmtprint(f, "map["); exprfmt(f, n->left, 0); fmtprint(f, "] "); exprfmt(f, n->right, 0); break; case OTCHAN: if(n->etype == Crecv) fmtprint(f, "<-"); fmtprint(f, "chan"); if(n->etype == Csend) { fmtprint(f, "<- "); exprfmt(f, n->left, 0); } else { fmtprint(f, " "); if(n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv) { fmtprint(f, "("); exprfmt(f, n->left, 0); fmtprint(f, ")"); } else exprfmt(f, n->left, 0); } break; case OTSTRUCT: fmtprint(f, "<struct>"); break; case OTINTER: fmtprint(f, "<inter>"); break; case OTFUNC: fmtprint(f, "<func>"); break; case OAS: exprfmt(f, n->left, 0); fmtprint(f, " = "); exprfmt(f, n->right, 0); break; case OASOP: exprfmt(f, n->left, 0); fmtprint(f, " %#O= ", n->etype); exprfmt(f, n->right, 0); break; case OADD: case OANDAND: case OANDNOT: case ODIV: case OEQ: case OGE: case OGT: case OLE: case OLT: case OLSH: case OMOD: case OMUL: case ONE: case OOR: case OOROR: case ORSH: case OSEND: case OSUB: case OXOR: exprfmt(f, n->left, nprec); fmtprint(f, " %#O ", n->op); exprfmt(f, n->right, nprec+1); break; case OADDR: case OCOM: case OIND: case OMINUS: case ONOT: case OPLUS: case ORECV: fmtprint(f, "%#O", n->op); if((n->op == OMINUS || n->op == OPLUS) && n->left->op == n->op) fmtprint(f, " "); exprfmt(f, n->left, 0); break; case OCLOSURE: fmtprint(f, "func literal"); break; case OCOMPLIT: fmtprint(f, "composite literal"); break; case OARRAYLIT: if(isslice(n->type)) fmtprint(f, "slice literal"); else fmtprint(f, "array literal"); break; case OMAPLIT: fmtprint(f, "map literal"); break; case OSTRUCTLIT: fmtprint(f, "struct literal"); break; case OXDOT: case ODOT: case ODOTPTR: case ODOTINTER: case ODOTMETH: exprfmt(f, n->left, 7); if(n->right == N || n->right->sym == S) fmtprint(f, ".<nil>"); else { // skip leading type· in method name p = utfrrune(n->right->sym->name, 0xb7); if(p) p+=2; else p = n->right->sym->name; fmtprint(f, ".%s", p); } break; case ODOTTYPE: case ODOTTYPE2: exprfmt(f, n->left, 7); fmtprint(f, ".("); if(n->right != N) exprfmt(f, n->right, 0); else fmtprint(f, "%T", n->type); fmtprint(f, ")"); break; case OINDEX: case OINDEXMAP: exprfmt(f, n->left, 7); fmtprint(f, "["); exprfmt(f, n->right, 0); fmtprint(f, "]"); break; case OSLICE: case OSLICESTR: case OSLICEARR: exprfmt(f, n->left, 7); fmtprint(f, "["); if(n->right->left != N) exprfmt(f, n->right->left, 0); fmtprint(f, ":"); if(n->right->right != N) exprfmt(f, n->right->right, 0); fmtprint(f, "]"); break; case OCALL: case OCALLFUNC: case OCALLINTER: case OCALLMETH: exprfmt(f, n->left, 7); fmtprint(f, "("); exprlistfmt(f, n->list); if(n->isddd) fmtprint(f, "..."); fmtprint(f, ")"); break; case OCOMPLEX: fmtprint(f, "complex("); exprfmt(f, n->left, 0); fmtprint(f, ", "); exprfmt(f, n->right, 0); fmtprint(f, ")"); break; case OREAL: fmtprint(f, "real("); exprfmt(f, n->left, 0); fmtprint(f, ")"); break; case OIMAG: fmtprint(f, "imag("); exprfmt(f, n->left, 0); fmtprint(f, ")"); break; case OCONV: case OCONVIFACE: case OCONVNOP: case OARRAYBYTESTR: case ORUNESTR: if(n->type == T || n->type->sym == S) fmtprint(f, "(%T)(", n->type); else fmtprint(f, "%T(", n->type); if(n->left == N) exprlistfmt(f, n->list); else exprfmt(f, n->left, 0); fmtprint(f, ")"); break; case OAPPEND: case OCAP: case OCLOSE: case OLEN: case OCOPY: case OMAKE: case ONEW: case OPANIC: case OPRINT: case OPRINTN: fmtprint(f, "%#O(", n->op); if(n->left) exprfmt(f, n->left, 0); else exprlistfmt(f, n->list); fmtprint(f, ")"); break; case OMAKESLICE: fmtprint(f, "make(%#T, ", n->type); exprfmt(f, n->left, 0); if(count(n->list) > 2) { fmtprint(f, ", "); exprfmt(f, n->right, 0); } fmtprint(f, ")"); break; case OMAKEMAP: fmtprint(f, "make(%#T)", n->type); break; } if(prec > nprec) fmtprint(f, ")"); }
/* * 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: ; }