// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. #include "gg.h" /* * generate: * res = n; * simplifies and calls gmove. */ void cgen(Node *n, Node *res) { // fatal("cgen_unimplemented"); // 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) // return; // if(res == N || res->type == T) // fatal("cgen: res nil"); // 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; // f = 1; // gen thru register // switch(n->op) { // case OLITERAL: // if(smallintconst(n)) // f = 0; // break; // case OREGISTER: // f = 0; // break; // } // if(sudoaddable(res, &addr)) { // a = optoas(OAS, res->type); // 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; // } // 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(sudoaddable(n, &addr)) { // a = optoas(OAS, n->type); // 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(AB, T); // p2 = pc; // gmove(nodbool(1), res); // p3 = gbranch(AB, 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: // 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: // if(eqtype(n->type, nl->type, 0)) { // cgen(nl, res); // break; // } // regalloc(&n1, nl->type, res); // cgen(nl, &n1); // gmove(&n1, res); // 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)) { // // map hsd 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 in the first 32-bit word. // // 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(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 OCALL: // 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(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: ; } /* * generate: * res = &n; */ void agen(Node *n, Node *res) { fatal("agen_unimplemented"); // Node *nl, *nr; // Node n1, n2, n3, tmp; // 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); // 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 OCONV: // if(!eqtype(n->type, nl->type, 0)) // fatal("agen: non-trivial OCONV"); // agen(nl, res); // return; // case OCALLMETH: // cgen_callmeth(n, 0); // cgen_aret(n, res); // break; // case OCALLINTER: // cgen_callinter(n, res, 0); // cgen_aret(n, res); // break; // case OCALL: // 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; // } // cgen(nr, res); // tempname(&tmp, nr->type); // gmove(res, &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 // 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']) { // 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']) { // 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']) { // // 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: // t = nl->type; // agen(nl, res); // if(n->xoffset != 0) { // nodconst(&n1, types[TINT64], n->xoffset); // gins(optoas(OADD, types[tptr]), &n1, res); // } // break; // case ODOTPTR: // t = nl->type; // if(!isptr[t->etype]) // fatal("agen: not ptr %N", n); // cgen(nl, res); // if(n->xoffset != 0) { // nodconst(&n1, types[TINT64], n->xoffset); // gins(optoas(OADD, types[tptr]), &n1, res); // } // break; // } // ret: // ; } /* * generate: * newreg = &n; * res = newreg * * on exit, a has been changed to be *newreg. * caller must regfree(a). */ void igen(Node *n, Node *a, Node *res) { regalloc(a, types[tptr], res); agen(n, a); a->op = OINDREG; a->type = n->type; } /* * generate: * if(n == true) goto to; */ void bgen(Node *n, int true, Prog *to) { // zzz // fatal("bgen_unimplemented"); // int et, a; // Node *nl, *nr, *r; // Node n1, n2, tmp; // Prog *p1, *p2; // if(debug['g']) { // dump("\nbgen", n); // } // if(n == N) // n = nodbool(1); // nl = n->left; // nr = n->right; // if(n->type == T) { // convlit(n, types[TBOOL]); // if(n->type == T) // goto ret; // } // et = n->type->etype; // if(et != TBOOL) { // yyerror("cgen: bad type %T for %O", n->type, n->op); // patch(gins(AEND, N, N), to); // goto ret; // } // nl = N; // nr = N; // switch(n->op) { // default: // regalloc(&n1, n->type, N); // cgen(n, &n1); // nodconst(&n2, n->type, 0); // gins(optoas(OCMP, n->type), &n1, &n2); // a = AJNE; // if(!true) // a = AJEQ; // patch(gbranch(a, n->type), to); // regfree(&n1); // goto ret; // case OLITERAL: // // need to ask if it is bool? // if(!true == !n->val.u.bval) // patch(gbranch(AB, T), to); // goto ret; // case ONAME: // nodconst(&n1, n->type, 0); // gins(optoas(OCMP, n->type), n, &n1); // a = AJNE; // if(!true) // a = AJEQ; // patch(gbranch(a, n->type), to); // goto ret; // case OANDAND: // if(!true) // goto caseor; // caseand: // p1 = gbranch(AB, T); // p2 = gbranch(AB, T); // patch(p1, pc); // bgen(n->left, !true, p2); // bgen(n->right, !true, p2); // p1 = gbranch(AB, T); // patch(p1, to); // patch(p2, pc); // goto ret; // case OOROR: // if(!true) // goto caseand; // caseor: // bgen(n->left, true, to); // bgen(n->right, true, to); // goto ret; // case OEQ: // case ONE: // case OLT: // case OGT: // case OLE: // case OGE: // nr = n->right; // if(nr == N || nr->type == T) // goto ret; // case ONOT: // unary // nl = n->left; // if(nl == N || nl->type == T) // goto ret; // } // switch(n->op) { // case ONOT: // bgen(nl, !true, to); // goto ret; // case OEQ: // case ONE: // case OLT: // case OGT: // case OLE: // case OGE: // a = n->op; // if(!true) // a = brcom(a); // // make simplest on right // if(nl->op == OLITERAL || nl->ullman < nr->ullman) { // a = brrev(a); // r = nl; // nl = nr; // nr = r; // } // if(isslice(nl->type)) { // // only valid to cmp darray to literal nil // if((a != OEQ && a != ONE) || nr->op != OLITERAL) { // yyerror("illegal array comparison"); // break; // } // a = optoas(a, types[tptr]); // regalloc(&n1, types[tptr], N); // agen(nl, &n1); // n2 = n1; // n2.op = OINDREG; // n2.xoffset = Array_array; // nodconst(&tmp, types[tptr], 0); // gins(optoas(OCMP, types[tptr]), &n2, &tmp); // patch(gbranch(a, types[tptr]), to); // regfree(&n1); // break; // } // a = optoas(a, nr->type); // if(nr->ullman >= UINF) { // regalloc(&n1, nr->type, N); // cgen(nr, &n1); // tempname(&tmp, nr->type); // gmove(&n1, &tmp); // regfree(&n1); // regalloc(&n1, nl->type, N); // cgen(nl, &n1); // regalloc(&n2, nr->type, &n2); // cgen(&tmp, &n2); // gins(optoas(OCMP, nr->type), &n1, &n2); // patch(gbranch(a, nr->type), to); // regfree(&n1); // regfree(&n2); // break; // } // regalloc(&n1, nl->type, N); // cgen(nl, &n1); // if(smallintconst(nr)) { // gins(optoas(OCMP, nr->type), &n1, nr); // patch(gbranch(a, nr->type), to); // regfree(&n1); // break; // } // regalloc(&n2, nr->type, N); // cgen(nr, &n2); // gins(optoas(OCMP, nr->type), &n1, &n2); // patch(gbranch(a, nr->type), to); // regfree(&n1); // regfree(&n2); // break; // } // goto ret; // ret: // ; } /* * n is on stack, either local variable * or return value from function call. * return n's offset from SP. */ int32 stkof(Node *n) { Type *t; Iter flist; switch(n->op) { case OINDREG: return n->xoffset; case OCALLMETH: case OCALLINTER: case OCALL: t = n->left->type; if(isptr[t->etype]) t = t->type; t = structfirst(&flist, getoutarg(t)); if(t != T) return t->width; break; } // botch - probably failing to recognize address // arithmetic on the above. eg INDEX and DOT return -1000; } /* * block copy: * memmove(&n, &ns, w); */ void sgen(Node *n, Node *ns, int32 w) { fatal("sgen_unimplemented"); // Node nodl, nodr; // int32 c, q, odst, osrc; // if(debug['g']) { // print("\nsgen w=%d\n", w); // dump("r", n); // dump("res", ns); // } // if(w == 0) // return; // if(n->ullman >= UINF && ns->ullman >= UINF) { // fatal("sgen UINF"); // } // if(w < 0) // fatal("sgen copy %d", w); // // offset on the stack // osrc = stkof(n); // odst = stkof(ns); // nodreg(&nodl, types[tptr], D_DI); // nodreg(&nodr, types[tptr], D_SI); // if(n->ullman >= ns->ullman) { // agen(n, &nodr); // agen(ns, &nodl); // } else { // agen(ns, &nodl); // agen(n, &nodr); // } // c = w % 8; // bytes // q = w / 8; // quads // // if we are copying forward on the stack and // // the src and dst overlap, then reverse direction // if(osrc < odst && odst < osrc+w) { // // reverse direction // gins(ASTD, N, N); // set direction flag // if(c > 0) { // gconreg(AADDQ, w-1, D_SI); // gconreg(AADDQ, w-1, D_DI); // gconreg(AMOVQ, c, D_CX); // gins(AREP, N, N); // repeat // gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)- // } // if(q > 0) { // if(c > 0) { // gconreg(AADDQ, -7, D_SI); // gconreg(AADDQ, -7, D_DI); // } else { // gconreg(AADDQ, w-8, D_SI); // gconreg(AADDQ, w-8, D_DI); // } // gconreg(AMOVQ, q, D_CX); // gins(AREP, N, N); // repeat // gins(AMOVSQ, N, N); // MOVQ *(SI)-,*(DI)- // } // // we leave with the flag clear // gins(ACLD, N, N); // } else { // // normal direction // if(q >= 4) { // gconreg(AMOVQ, q, D_CX); // gins(AREP, N, N); // repeat // gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+ // } else // while(q > 0) { // gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+ // q--; // } // if(c >= 4) { // gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+ // c -= 4; // } // while(c > 0) { // gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+ // c--; // } // } }