--- /dev/null
+// 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--;
+// }
+// }
+}
--- /dev/null
+// Derived from Inferno utils/5c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gg.h"
+
+void
+clearp(Prog *p)
+{
+ p->as = AEND;
+ p->from.type = D_NONE;
+ p->from.index = D_NONE;
+ p->to.type = D_NONE;
+ p->to.index = D_NONE;
+ p->loc = pcloc;
+ pcloc++;
+}
+
+/*
+ * generate and return proc with p->as = as,
+ * linked into program. pc is next instruction.
+ */
+Prog*
+prog(int as)
+{
+ Prog *p;
+
+ p = pc;
+ pc = mal(sizeof(*pc));
+
+ clearp(pc);
+
+ if(lineno == 0) {
+ if(debug['K'])
+ warn("prog: line 0");
+ }
+
+ p->as = as;
+ p->lineno = lineno;
+ p->link = pc;
+ return p;
+}
+
+/*
+ * generate a branch.
+ * t is ignored.
+ */
+Prog*
+gbranch(int as, Type *t)
+{
+ Prog *p;
+
+ p = prog(as);
+ p->to.type = D_BRANCH;
+ p->to.branch = P;
+ return p;
+}
+
+/*
+ * patch previous branch to jump to to.
+ */
+void
+patch(Prog *p, Prog *to)
+{
+ if(p->to.type != D_BRANCH)
+ fatal("patch: not a branch");
+ p->to.branch = to;
+ p->to.offset = to->loc;
+}
+
+/*
+ * start a new Prog list.
+ */
+Plist*
+newplist(void)
+{
+ Plist *pl;
+
+ pl = mal(sizeof(*pl));
+ if(plist == nil)
+ plist = pl;
+ else
+ plast->link = pl;
+ plast = pl;
+
+ pc = mal(sizeof(*pc));
+ clearp(pc);
+ pl->firstpc = pc;
+
+ return pl;
+}
+
+void
+gused(Node *n)
+{
+ gins(ANOP, n, N); // used
+}
+
+Prog*
+gjmp(Prog *to)
+{
+ Prog *p;
+
+ p = gbranch(AB, T);
+ if(to != P)
+ patch(p, to);
+ return p;
+}
+
+void
+ggloblnod(Node *nam, int32 width)
+{
+ Prog *p;
+
+ p = gins(AGLOBL, nam, N);
+ p->lineno = nam->lineno;
+ p->to.sym = S;
+ p->to.type = D_CONST;
+ p->to.offset = width;
+}
+
+void
+ggloblsym(Sym *s, int32 width, int dupok)
+{
+ Prog *p;
+
+ p = gins(AGLOBL, N, N);
+ p->from.type = D_EXTERN;
+ if(s == symstringl || s == symstringc)
+ p->from.type = D_STATIC;
+ p->from.index = D_NONE;
+ p->from.sym = s;
+ p->to.type = D_CONST;
+ p->to.index = D_NONE;
+ p->to.offset = width;
+ if(dupok)
+ p->from.scale = DUPOK;
+}
+
+int
+isfat(Type *t)
+{
+ if(t != T)
+ switch(t->etype) {
+ case TSTRUCT:
+ case TARRAY:
+ case TSTRING:
+ case TINTER: // maybe remove later
+ case TDDD: // maybe remove later
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * naddr of func generates code for address of func.
+ * if using opcode that can take address implicitly,
+ * call afunclit to fix up the argument.
+ */
+void
+afunclit(Addr *a)
+{
+ if(a->type == D_ADDR && a->index == D_EXTERN) {
+ a->type = D_EXTERN;
+ a->index = D_NONE;
+ }
+}
+
+static int resvd[] =
+{
+// D_DI, // for movstring
+// D_SI, // for movstring
+
+// D_AX, // for divide
+// D_CX, // for shift
+// D_DX, // for divide
+// D_SP, // for stack
+// D_R14, // reserved for m
+// D_R15, // reserved for u
+};
+
+void
+ginit(void)
+{
+// int i;
+
+// for(i=0; i<nelem(reg); i++)
+// reg[i] = 1;
+// for(i=D_AX; i<=D_R15; i++)
+// reg[i] = 0;
+// for(i=D_X0; i<=D_X7; i++)
+// reg[i] = 0;
+
+// for(i=0; i<nelem(resvd); i++)
+// reg[resvd[i]]++;
+ fatal("ginit_unimplemented");
+}
+
+void
+gclean(void)
+{
+// int i;
+
+// for(i=0; i<nelem(resvd); i++)
+// reg[resvd[i]]--;
+
+// for(i=D_AX; i<=D_R15; i++)
+// if(reg[i])
+// yyerror("reg %R left allocated\n", i);
+// for(i=D_X0; i<=D_X7; i++)
+// if(reg[i])
+// yyerror("reg %R left allocated\n", i);
+ fatal("gclean_unimplemented");
+}
+
+/*
+ * allocate register of type t, leave in n.
+ * if o != N, o is desired fixed register.
+ * caller must regfree(n).
+ */
+void
+regalloc(Node *n, Type *t, Node *o)
+{
+// int i, et;
+
+// if(t == T)
+// fatal("regalloc: t nil");
+// et = simtype[t->etype];
+
+// switch(et) {
+// case TINT8:
+// case TUINT8:
+// case TINT16:
+// case TUINT16:
+// case TINT32:
+// case TUINT32:
+// case TINT64:
+// case TUINT64:
+// case TPTR32:
+// case TPTR64:
+// case TBOOL:
+// if(o != N && o->op == OREGISTER) {
+// i = o->val.u.reg;
+// if(i >= D_AX && i <= D_R15)
+// goto out;
+// }
+// for(i=D_AX; i<=D_R15; i++)
+// if(reg[i] == 0)
+// goto out;
+
+// yyerror("out of fixed registers");
+// goto err;
+
+// case TFLOAT32:
+// case TFLOAT64:
+// case TFLOAT80:
+// if(o != N && o->op == OREGISTER) {
+// i = o->val.u.reg;
+// if(i >= D_X0 && i <= D_X7)
+// goto out;
+// }
+// for(i=D_X0; i<=D_X7; i++)
+// if(reg[i] == 0)
+// goto out;
+// yyerror("out of floating registers");
+// goto err;
+// }
+// yyerror("regalloc: unknown type %T", t);
+
+// err:
+// nodreg(n, t, 0);
+// return;
+
+// out:
+// reg[i]++;
+// nodreg(n, t, i);
+ fatal("regalloc_unimplemented");
+}
+
+void
+regfree(Node *n)
+{
+ int i;
+
+ if(n->op != OREGISTER && n->op != OINDREG)
+ fatal("regfree: not a register");
+ i = n->val.u.reg;
+ if(i < 0 || i >= sizeof(reg))
+ fatal("regfree: reg out of range");
+ if(reg[i] <= 0)
+ fatal("regfree: reg not allocated");
+ reg[i]--;
+}
+
+/*
+ * initialize n to be register r of type t.
+ */
+void
+nodreg(Node *n, Type *t, int r)
+{
+ if(t == T)
+ fatal("nodreg: t nil");
+
+ memset(n, 0, sizeof(*n));
+ n->op = OREGISTER;
+ n->addable = 1;
+ ullmancalc(n);
+ n->val.u.reg = r;
+ n->type = t;
+}
+
+/*
+ * initialize n to be indirect of register r; n is type t.
+ */
+void
+nodindreg(Node *n, Type *t, int r)
+{
+ nodreg(n, t, r);
+ n->op = OINDREG;
+}
+
+Node*
+nodarg(Type *t, int fp)
+{
+// Node *n;
+// Type *first;
+// Iter savet;
+
+// // entire argument struct, not just one arg
+// if(t->etype == TSTRUCT && t->funarg) {
+// n = nod(ONAME, N, N);
+// n->sym = lookup(".args");
+// n->type = t;
+// first = structfirst(&savet, &t);
+// if(first == nil)
+// fatal("nodarg: bad struct");
+// if(first->width == BADWIDTH)
+// fatal("nodarg: offset not computed for %T", t);
+// n->xoffset = first->width;
+// n->addable = 1;
+// goto fp;
+// }
+
+// if(t->etype != TFIELD)
+// fatal("nodarg: not field %T", t);
+
+// n = nod(ONAME, N, N);
+// n->type = t->type;
+// n->sym = t->sym;
+// if(t->width == BADWIDTH)
+// fatal("nodarg: offset not computed for %T", t);
+// n->xoffset = t->width;
+// n->addable = 1;
+
+// fp:
+// switch(fp) {
+// case 0: // output arg
+// n->op = OINDREG;
+// n->val.u.reg = D_SP;
+// break;
+
+// case 1: // input arg
+// n->class = PPARAM;
+// break;
+
+// case 2: // offset output arg
+// fatal("shouldnt be used");
+// n->op = OINDREG;
+// n->val.u.reg = D_SP;
+// n->xoffset += types[tptr]->width;
+// break;
+// }
+// return n;
+ fatal("nodarg_unimplemented");
+}
+
+/*
+ * generate
+ * as $c, reg
+ */
+void
+gconreg(int as, vlong c, int reg)
+{
+ Node n1, n2;
+
+ nodconst(&n1, types[TINT64], c);
+ nodreg(&n2, types[TINT64], reg);
+ gins(as, &n1, &n2);
+}
+
+#define CASE(a,b) (((a)<<16)|((b)<<0))
+
+/*
+ * generate move:
+ * t = f
+ */
+void
+gmove(Node *f, Node *t)
+{
+// int ft, tt, t64, a;
+// Node nod, nod1, nod2, nod3, nodc;
+// Prog *p1, *p2;
+
+// ft = simtype[f->type->etype];
+// tt = simtype[t->type->etype];
+
+// t64 = 0;
+// if(tt == TINT64 || tt == TUINT64 || tt == TPTR64)
+// t64 = 1;
+
+// if(debug['M'])
+// print("gop: %O %O[%E],%O[%E]\n", OAS,
+// f->op, ft, t->op, tt);
+// if(isfloat[ft] && f->op == OCONST) {
+// /* TO DO: pick up special constants, possibly preloaded */
+// if(mpgetflt(f->val.u.fval) == 0.0) {
+// regalloc(&nod, t->type, t);
+// gins(AXORPD, &nod, &nod);
+// gmove(&nod, t);
+// regfree(&nod);
+// return;
+// }
+// }
+// /*
+// * load
+// */
+// if(f->op == ONAME || f->op == OINDREG ||
+// f->op == OIND || f->op == OINDEX)
+// switch(ft) {
+// case TINT8:
+// a = AMOVBLSX;
+// if(t64)
+// a = AMOVBQSX;
+// goto ld;
+// case TBOOL:
+// case TUINT8:
+// a = AMOVBLZX;
+// if(t64)
+// a = AMOVBQZX;
+// goto ld;
+// case TINT16:
+// a = AMOVWLSX;
+// if(t64)
+// a = AMOVWQSX;
+// goto ld;
+// case TUINT16:
+// a = AMOVWLZX;
+// if(t64)
+// a = AMOVWQZX;
+// goto ld;
+// case TINT32:
+// if(isfloat[tt]) {
+// regalloc(&nod, t->type, t);
+// if(tt == TFLOAT64)
+// a = ACVTSL2SD;
+// else
+// a = ACVTSL2SS;
+// gins(a, f, &nod);
+// gmove(&nod, t);
+// regfree(&nod);
+// return;
+// }
+// a = AMOVL;
+// if(t64)
+// a = AMOVLQSX;
+// goto ld;
+// case TUINT32:
+// case TPTR32:
+// a = AMOVL;
+// if(t64)
+// a = AMOVLQZX;
+// goto ld;
+// case TINT64:
+// if(isfloat[tt]) {
+// regalloc(&nod, t->type, t);
+// if(tt == TFLOAT64)
+// a = ACVTSQ2SD;
+// else
+// a = ACVTSQ2SS;
+// gins(a, f, &nod);
+// gmove(&nod, t);
+// regfree(&nod);
+// return;
+// }
+// case TUINT64:
+// case TPTR64:
+// a = AMOVQ;
+
+// ld:
+// regalloc(&nod, f->type, t);
+// nod.type = t64? types[TINT64]: types[TINT32];
+// gins(a, f, &nod);
+// gmove(&nod, t);
+// regfree(&nod);
+// return;
+
+// case TFLOAT32:
+// a = AMOVSS;
+// goto fld;
+// case TFLOAT64:
+// a = AMOVSD;
+// fld:
+// regalloc(&nod, f->type, t);
+// if(tt != TFLOAT64 && tt != TFLOAT32){ /* TO DO: why is this here */
+// dump("odd tree", f);
+// nod.type = t64? types[TINT64]: types[TINT32];
+// }
+// gins(a, f, &nod);
+// gmove(&nod, t);
+// regfree(&nod);
+// return;
+// }
+
+// /*
+// * store
+// */
+// if(t->op == ONAME || t->op == OINDREG ||
+// t->op == OIND || t->op == OINDEX)
+// switch(tt) {
+// case TBOOL:
+// case TINT8:
+// case TUINT8:
+// a = AMOVB;
+// goto st;
+// case TINT16:
+// case TUINT16:
+// a = AMOVW;
+// goto st;
+// case TINT32:
+// case TUINT32:
+// a = AMOVL;
+// goto st;
+// case TINT64:
+// case TUINT64:
+// a = AMOVQ;
+// goto st;
+
+// case TPTR32:
+// case TPTR64:
+// /*
+// * store to pointer.
+// */
+// if(tt == TPTR32)
+// a = AMOVL;
+// else
+// a = AMOVQ;
+// switch(t->op) {
+// default:
+// dump("gmove to", t);
+// fatal("gmove t %O", t->op);
+
+// case OINDREG:
+// if(t->val.u.reg != D_SP)
+// goto refcount;
+// break;
+
+// case ONAME:
+// switch(t->class) {
+// default:
+// dump("gmove", t);
+// fatal("gmove t %O class %d reg %R", t->op, t->class, t->val.u.reg);
+// case PEXTERN:
+// goto refcount;
+// break;
+// case PAUTO:
+// case PPARAM:
+// case PPARAMOUT:
+// break;
+// }
+// break;
+// }
+// goto st;
+
+// st:
+// // 64-bit immediates only allowed for move into registers.
+// // this is not a move into a register.
+// if(f->op == OCONST || (f->op == OLITERAL && !t64)) {
+// gins(a, f, t);
+// return;
+// }
+// fst:
+// regalloc(&nod, t->type, f);
+// gmove(f, &nod);
+// gins(a, &nod, t);
+// regfree(&nod);
+// return;
+
+// refcount:
+// if(!debug['r'])
+// goto st;
+// // for now, mark ref count updates with AXCHGQ.
+// // using a temporary on the left, so no semantic
+// // changes. code is likely slower, but still correct.
+// if(t64)
+// a = AXCHGQ;
+// else
+// a = AXCHGL;
+// regalloc(&nod, t->type, f);
+// gmove(f, &nod);
+// gins(a, &nod, t);
+// regfree(&nod);
+// return;
+
+// case TFLOAT32:
+// a = AMOVSS;
+// goto fst;
+// case TFLOAT64:
+// a = AMOVSD;
+// goto fst;
+// }
+
+// /*
+// * convert
+// */
+// switch(CASE(ft, tt)) {
+// default:
+// /*
+// * integer to integer
+// ********
+// * a = AGOK; break;
+
+// * case CASE(TBOOL, TBOOL):
+// * case CASE(TINT8, TBOOL):
+// * case CASE(TUINT8, TBOOL):
+// * case CASE(TINT16, TBOOL):
+// * case CASE(TUINT16, TBOOL):
+// * case CASE(TINT32, TBOOL):
+// * case CASE(TUINT32, TBOOL):
+// * case CASE(TPTR64, TBOOL):
+
+// * case CASE(TBOOL, TINT8):
+// * case CASE(TINT8, TINT8):
+// * case CASE(TUINT8, TINT8):
+// * case CASE(TINT16, TINT8):
+// * case CASE(TUINT16, TINT8):
+// * case CASE(TINT32, TINT8):
+// * case CASE(TUINT32, TINT8):
+// * case CASE(TPTR64, TINT8):
+
+// * case CASE(TBOOL, TUINT8):
+// * case CASE(TINT8, TUINT8):
+// * case CASE(TUINT8, TUINT8):
+// * case CASE(TINT16, TUINT8):
+// * case CASE(TUINT16, TUINT8):
+// * case CASE(TINT32, TUINT8):
+// * case CASE(TUINT32, TUINT8):
+// * case CASE(TPTR64, TUINT8):
+
+// * case CASE(TINT16, TINT16):
+// * case CASE(TUINT16, TINT16):
+// * case CASE(TINT32, TINT16):
+// * case CASE(TUINT32, TINT16):
+// * case CASE(TPTR64, TINT16):
+
+// * case CASE(TINT16, TUINT16):
+// * case CASE(TUINT16, TUINT16):
+// * case CASE(TINT32, TUINT16):
+// * case CASE(TUINT32, TUINT16):
+// * case CASE(TPTR64, TUINT16):
+
+// * case CASE(TINT64, TUINT):
+// * case CASE(TINT64, TUINT32):
+// * case CASE(TUINT64, TUINT32):
+// *****/
+// a = AMOVL;
+// break;
+
+// case CASE(TINT64, TINT8):
+// case CASE(TINT64, TINT16):
+// case CASE(TINT64, TINT32):
+// case CASE(TUINT64, TINT8):
+// case CASE(TUINT64, TINT16):
+// case CASE(TUINT64, TINT32):
+// a = AMOVLQSX; // this looks bad
+// break;
+
+// case CASE(TINT32, TINT64):
+// case CASE(TINT32, TPTR64):
+// a = AMOVLQSX;
+// break;
+
+// case CASE(TUINT32, TINT64):
+// case CASE(TUINT32, TUINT64):
+// case CASE(TUINT32, TPTR64):
+// case CASE(TPTR32, TINT64):
+// case CASE(TPTR32, TUINT64):
+// case CASE(TPTR32, TPTR64):
+// a = AMOVLQZX;
+// break;
+
+// case CASE(TPTR64, TINT64):
+// case CASE(TINT64, TINT64):
+// case CASE(TUINT64, TINT64):
+// case CASE(TINT64, TUINT64):
+// case CASE(TUINT64, TUINT64):
+// case CASE(TPTR64, TUINT64):
+// case CASE(TINT64, TPTR64):
+// case CASE(TUINT64, TPTR64):
+// case CASE(TPTR64, TPTR64):
+// a = AMOVQ;
+// break;
+
+// case CASE(TINT16, TINT32):
+// case CASE(TINT16, TUINT32):
+// a = AMOVWLSX;
+// // if(f->op == OCONST) {
+// // f->val.vval &= 0xffff;
+// // if(f->val.vval & 0x8000)
+// // f->val.vval |= 0xffff0000;
+// // a = AMOVL;
+// // }
+// break;
+
+// case CASE(TINT16, TINT64):
+// case CASE(TINT16, TUINT64):
+// case CASE(TINT16, TPTR64):
+// a = AMOVWQSX;
+// // if(f->op == OCONST) {
+// // f->val.vval &= 0xffff;
+// // if(f->val.vval & 0x8000){
+// // f->val.vval |= 0xffff0000;
+// // f->val.vval |= (vlong)~0 << 32;
+// // }
+// // a = AMOVL;
+// // }
+// break;
+
+// case CASE(TUINT16, TINT32):
+// case CASE(TUINT16, TUINT32):
+// a = AMOVWLZX;
+// // if(f->op == OCONST) {
+// // f->val.vval &= 0xffff;
+// // a = AMOVL;
+// // }
+// break;
+
+// case CASE(TUINT16, TINT64):
+// case CASE(TUINT16, TUINT64):
+// case CASE(TUINT16, TPTR64):
+// a = AMOVWQZX;
+// // if(f->op == OCONST) {
+// // f->val.vval &= 0xffff;
+// // a = AMOVL; /* MOVL also zero-extends to 64 bits */
+// // }
+// break;
+
+// case CASE(TINT8, TINT16):
+// case CASE(TINT8, TUINT16):
+// case CASE(TINT8, TINT32):
+// case CASE(TINT8, TUINT32):
+// a = AMOVBLSX;
+// // if(f->op == OCONST) {
+// // f->val.vval &= 0xff;
+// // if(f->val.vval & 0x80)
+// // f->val.vval |= 0xffffff00;
+// // a = AMOVL;
+// // }
+// break;
+
+// case CASE(TINT8, TINT64):
+// case CASE(TINT8, TUINT64):
+// case CASE(TINT8, TPTR64):
+// a = AMOVBQSX;
+// // if(f->op == OCONST) {
+// // f->val.vval &= 0xff;
+// // if(f->val.vval & 0x80){
+// // f->val.vval |= 0xffffff00;
+// // f->val.vval |= (vlong)~0 << 32;
+// // }
+// // a = AMOVQ;
+// // }
+// break;
+
+// case CASE(TBOOL, TINT16):
+// case CASE(TBOOL, TUINT16):
+// case CASE(TBOOL, TINT32):
+// case CASE(TBOOL, TUINT32):
+// case CASE(TUINT8, TINT16):
+// case CASE(TUINT8, TUINT16):
+// case CASE(TUINT8, TINT32):
+// case CASE(TUINT8, TUINT32):
+// a = AMOVBLZX;
+// // if(f->op == OCONST) {
+// // f->val.vval &= 0xff;
+// // a = AMOVL;
+// // }
+// break;
+
+// case CASE(TBOOL, TINT64):
+// case CASE(TBOOL, TUINT64):
+// case CASE(TBOOL, TPTR64):
+// case CASE(TUINT8, TINT64):
+// case CASE(TUINT8, TUINT64):
+// case CASE(TUINT8, TPTR64):
+// a = AMOVBQZX;
+// // if(f->op == OCONST) {
+// // f->val.vval &= 0xff;
+// // a = AMOVL; /* zero-extends to 64-bits */
+// // }
+// break;
+
+// /*
+// * float to fix
+// */
+// case CASE(TFLOAT32, TINT8):
+// case CASE(TFLOAT32, TINT16):
+// case CASE(TFLOAT32, TINT32):
+// regalloc(&nod, t->type, N);
+// gins(ACVTTSS2SL, f, &nod);
+// gmove(&nod, t);
+// regfree(&nod);
+// return;
+
+// case CASE(TFLOAT32, TBOOL):
+// case CASE(TFLOAT32, TUINT8):
+// case CASE(TFLOAT32, TUINT16):
+// case CASE(TFLOAT32, TUINT32):
+// case CASE(TFLOAT32, TINT64):
+// case CASE(TFLOAT32, TUINT64):
+// case CASE(TFLOAT32, TPTR64):
+// regalloc(&nod, t->type, N);
+// gins(ACVTTSS2SQ, f, &nod);
+// gmove(&nod, t);
+// regfree(&nod);
+// return;
+
+// case CASE(TFLOAT64, TINT8):
+// case CASE(TFLOAT64, TINT16):
+// case CASE(TFLOAT64, TINT32):
+// regalloc(&nod, t->type, N);
+// gins(ACVTTSD2SL, f, &nod);
+// gmove(&nod, t);
+// regfree(&nod);
+// return;
+
+// case CASE(TFLOAT64, TBOOL):
+// case CASE(TFLOAT64, TUINT8):
+// case CASE(TFLOAT64, TUINT16):
+// case CASE(TFLOAT64, TUINT32):
+// case CASE(TFLOAT64, TINT64):
+// case CASE(TFLOAT64, TUINT64):
+// case CASE(TFLOAT64, TPTR64):
+// regalloc(&nod, t->type, N);
+// gins(ACVTTSD2SQ, f, &nod);
+// gmove(&nod, t);
+// regfree(&nod);
+// return;
+
+// /*
+// * uvlong to float
+// */
+// case CASE(TUINT64, TFLOAT64):
+// case CASE(TUINT64, TFLOAT32):
+// a = ACVTSQ2SS;
+// if(tt == TFLOAT64)
+// a = ACVTSQ2SD;
+// regalloc(&nod, f->type, f);
+// gmove(f, &nod);
+// regalloc(&nod1, t->type, t);
+// nodconst(&nodc, types[TUINT64], 0);
+// gins(ACMPQ, &nod, &nodc);
+// p1 = gbranch(AJLT, T);
+// gins(a, &nod, &nod1);
+// p2 = gbranch(AB, T);
+// patch(p1, pc);
+// regalloc(&nod2, f->type, N);
+// regalloc(&nod3, f->type, N);
+// gmove(&nod, &nod2);
+// nodconst(&nodc, types[TUINT64], 1);
+// gins(ASHRQ, &nodc, &nod2);
+// gmove(&nod, &nod3);
+// gins(AANDL, &nodc, &nod3);
+// gins(AORQ, &nod3, &nod2);
+// gins(a, &nod2, &nod1);
+// gins(tt == TFLOAT64? AADDSD: AADDSS, &nod1, &nod1);
+// regfree(&nod2);
+// regfree(&nod3);
+// patch(p2, pc);
+// regfree(&nod);
+// regfree(&nod1);
+// return;
+
+// case CASE(TUINT32, TFLOAT64):
+// case CASE(TUINT32, TFLOAT32):
+// a = ACVTSQ2SS;
+// if(tt == TFLOAT64)
+// a = ACVTSQ2SD;
+// regalloc(&nod, f->type, f);
+// gins(AMOVLQZX, f, &nod);
+// regalloc(&nod1, t->type, t);
+// gins(a, &nod, &nod1);
+// gmove(&nod1, t);
+// regfree(&nod);
+// regfree(&nod1);
+// return;
+
+// /*
+// * fix to float
+// */
+// case CASE(TINT64, TFLOAT32):
+// case CASE(TPTR64, TFLOAT32):
+// regalloc(&nod, t->type, t);
+// gins(ACVTSQ2SS, f, &nod);
+// gmove(&nod, t);
+// regfree(&nod);
+// return;
+
+// case CASE(TINT64, TFLOAT64):
+// case CASE(TPTR64, TFLOAT64):
+// regalloc(&nod, t->type, t);
+// gins(ACVTSQ2SD, f, &nod);
+// gmove(&nod, t);
+// regfree(&nod);
+// return;
+
+// case CASE(TBOOL, TFLOAT32):
+// case CASE(TINT8, TFLOAT32):
+// case CASE(TUINT8, TFLOAT32):
+// case CASE(TINT16, TFLOAT32):
+// case CASE(TUINT16, TFLOAT32):
+// case CASE(TINT32, TFLOAT32):
+// regalloc(&nod, t->type, t);
+// gins(ACVTSL2SS, f, &nod);
+// gmove(&nod, t);
+// regfree(&nod);
+// return;
+
+// case CASE(TBOOL, TFLOAT64):
+// case CASE(TINT8, TFLOAT64):
+// case CASE(TUINT8, TFLOAT64):
+// case CASE(TINT16, TFLOAT64):
+// case CASE(TUINT16, TFLOAT64):
+// case CASE(TINT32, TFLOAT64):
+// regalloc(&nod, t->type, t);
+// gins(ACVTSL2SD, f, &nod);
+// gmove(&nod, t);
+// regfree(&nod);
+// return;
+
+// /*
+// * float to float
+// */
+// case CASE(TFLOAT32, TFLOAT32):
+// a = AMOVSS;
+// break;
+// case CASE(TFLOAT64, TFLOAT32):
+// a = ACVTSD2SS;
+// break;
+// case CASE(TFLOAT32, TFLOAT64):
+// a = ACVTSS2SD;
+// break;
+// case CASE(TFLOAT64, TFLOAT64):
+// a = AMOVSD;
+// break;
+// }
+// if(a == AMOVQ ||
+// a == AMOVSD ||
+// a == AMOVSS ||
+// (a == AMOVL && f->type->width == t->type->width)) /* TO DO: check AMOVL */
+// if(samaddr(f, t))
+// return;
+// gins(a, f, t);
+ fatal("gmove_unimplemented");
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+ if(f->op != t->op)
+ return 0;
+
+ switch(f->op) {
+ case OREGISTER:
+ if(f->val.u.reg != t->val.u.reg)
+ break;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * generate one instruction:
+ * as f, t
+ */
+Prog*
+gins(int as, Node *f, Node *t)
+{
+// Node nod;
+// int32 v;
+ Prog *p;
+
+// if(f != N && f->op == OINDEX) {
+// regalloc(&nod, ®node, Z);
+// v = constnode.vconst;
+// cgen(f->right, &nod);
+// constnode.vconst = v;
+// idx.reg = nod.reg;
+// regfree(&nod);
+// }
+// if(t != N && t->op == OINDEX) {
+// regalloc(&nod, ®node, Z);
+// v = constnode.vconst;
+// cgen(t->right, &nod);
+// constnode.vconst = v;
+// idx.reg = nod.reg;
+// regfree(&nod);
+// }
+
+ p = prog(as);
+ if(f != N)
+ naddr(f, &p->from);
+ if(t != N)
+ naddr(t, &p->to);
+ if(debug['g'])
+ print("%P\n", p);
+ return p;
+}
+
+/*
+ * generate code to compute n;
+ * make a refer to result.
+ */
+void
+naddr(Node *n, Addr *a)
+{
+ a->scale = 0;
+ a->index = D_NONE;
+ a->type = D_NONE;
+ if(n == N)
+ return;
+
+ switch(n->op) {
+ default:
+ fatal("naddr: bad %O %D", n->op, a);
+ break;
+
+// case OREGISTER:
+// a->type = n->val.u.reg;
+// a->sym = S;
+// break;
+
+// case OINDEX:
+// case OIND:
+// naddr(n->left, a);
+// if(a->type >= D_AX && a->type <= D_DI)
+// a->type += D_INDIR;
+// else
+// if(a->type == D_CONST)
+// a->type = D_NONE+D_INDIR;
+// else
+// if(a->type == D_ADDR) {
+// a->type = a->index;
+// a->index = D_NONE;
+// } else
+// goto bad;
+// if(n->op == OINDEX) {
+// a->index = idx.reg;
+// a->scale = n->scale;
+// }
+// break;
+
+// case OINDREG:
+// a->type = n->val.u.reg+D_INDIR;
+// a->sym = n->sym;
+// a->offset = n->xoffset;
+// break;
+
+// case OPARAM:
+// // n->left is PHEAP ONAME for stack parameter.
+// // compute address of actual parameter on stack.
+// a->etype = n->left->type->etype;
+// a->offset = n->xoffset;
+// a->sym = n->left->sym;
+// a->type = D_PARAM;
+// break;
+
+ case ONAME:
+ a->etype = 0;
+ if(n->type != T)
+ a->etype = simtype[n->type->etype];
+ a->offset = n->xoffset;
+ a->sym = n->sym;
+ if(a->sym == S)
+ a->sym = lookup(".noname");
+ if(n->method) {
+ if(n->type != T)
+ if(n->type->sym != S)
+ if(n->type->sym->opackage != nil)
+ a->sym = pkglookup(a->sym->name, n->type->sym->opackage);
+ }
+
+ switch(n->class) {
+ default:
+ fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
+ case PEXTERN:
+ a->type = D_EXTERN;
+ break;
+ case PAUTO:
+ a->type = D_AUTO;
+ break;
+ case PPARAM:
+ case PPARAMOUT:
+ a->type = D_PARAM;
+ break;
+ case PFUNC:
+ a->index = D_EXTERN;
+ a->type = D_ADDR;
+ break;
+ }
+ break;
+
+ case OLITERAL:
+ switch(n->val.ctype) {
+ default:
+ fatal("naddr: const %lT", n->type);
+ break;
+ case CTFLT:
+ a->type = D_FCONST;
+ a->dval = mpgetflt(n->val.u.fval);
+ break;
+ case CTINT:
+ a->sym = S;
+ a->type = D_CONST;
+ a->offset = mpgetfix(n->val.u.xval);
+ break;
+ case CTSTR:
+ a->etype = simtype[n->etype];
+ a->sym = symstringl;
+ a->type = D_STATIC;
+ a->offset = symstringl->offset;
+ stringpool(n);
+ break;
+ case CTBOOL:
+ a->sym = S;
+ a->type = D_CONST;
+ a->offset = n->val.u.bval;
+ break;
+ case CTNIL:
+ a->sym = S;
+ a->type = D_CONST;
+ a->offset = 0;
+ break;
+ }
+ break;
+
+// case OADDR:
+// naddr(n->left, a);
+// if(a->type >= D_INDIR) {
+// a->type -= D_INDIR;
+// break;
+// }
+// if(a->type == D_EXTERN || a->type == D_STATIC ||
+// a->type == D_AUTO || a->type == D_PARAM)
+// if(a->index == D_NONE) {
+// a->index = a->type;
+// a->type = D_ADDR;
+// break;
+// }
+// fatal("naddr: OADDR\n");
+
+// case OADD:
+// if(n->right->op == OLITERAL) {
+// v = n->right->vconst;
+// naddr(n->left, a);
+// } else
+// if(n->left->op == OLITERAL) {
+// v = n->left->vconst;
+// naddr(n->right, a);
+// } else
+// goto bad;
+// a->offset += v;
+// break;
+
+ }
+}
+
+/*
+ * return Axxx for Oxxx on type t.
+ */
+int
+optoas(int op, Type *t)
+{
+// int a;
+
+// if(t == T)
+// fatal("optoas: t is nil");
+
+// a = AGOK;
+// switch(CASE(op, simtype[t->etype])) {
+// default:
+// fatal("optoas: no entry %O-%T", op, t);
+// break;
+
+// case CASE(OADDR, TPTR32):
+// a = ALEAL;
+// break;
+
+// case CASE(OADDR, TPTR64):
+// a = ALEAQ;
+// break;
+
+// case CASE(OEQ, TBOOL):
+// case CASE(OEQ, TINT8):
+// case CASE(OEQ, TUINT8):
+// case CASE(OEQ, TINT16):
+// case CASE(OEQ, TUINT16):
+// case CASE(OEQ, TINT32):
+// case CASE(OEQ, TUINT32):
+// case CASE(OEQ, TINT64):
+// case CASE(OEQ, TUINT64):
+// case CASE(OEQ, TPTR32):
+// case CASE(OEQ, TPTR64):
+// case CASE(OEQ, TFLOAT32):
+// case CASE(OEQ, TFLOAT64):
+// a = AJEQ;
+// break;
+
+// case CASE(ONE, TBOOL):
+// case CASE(ONE, TINT8):
+// case CASE(ONE, TUINT8):
+// case CASE(ONE, TINT16):
+// case CASE(ONE, TUINT16):
+// case CASE(ONE, TINT32):
+// case CASE(ONE, TUINT32):
+// case CASE(ONE, TINT64):
+// case CASE(ONE, TUINT64):
+// case CASE(ONE, TPTR32):
+// case CASE(ONE, TPTR64):
+// case CASE(ONE, TFLOAT32):
+// case CASE(ONE, TFLOAT64):
+// a = AJNE;
+// break;
+
+// case CASE(OLT, TINT8):
+// case CASE(OLT, TINT16):
+// case CASE(OLT, TINT32):
+// case CASE(OLT, TINT64):
+// a = AJLT;
+// break;
+
+// case CASE(OLT, TUINT8):
+// case CASE(OLT, TUINT16):
+// case CASE(OLT, TUINT32):
+// case CASE(OLT, TUINT64):
+// case CASE(OGT, TFLOAT32):
+// case CASE(OGT, TFLOAT64):
+// a = AJCS;
+// break;
+
+// case CASE(OLE, TINT8):
+// case CASE(OLE, TINT16):
+// case CASE(OLE, TINT32):
+// case CASE(OLE, TINT64):
+// a = AJLE;
+// break;
+
+// case CASE(OLE, TUINT8):
+// case CASE(OLE, TUINT16):
+// case CASE(OLE, TUINT32):
+// case CASE(OLE, TUINT64):
+// case CASE(OGE, TFLOAT32):
+// case CASE(OGE, TFLOAT64):
+// a = AJLS;
+// break;
+
+// case CASE(OGT, TINT8):
+// case CASE(OGT, TINT16):
+// case CASE(OGT, TINT32):
+// case CASE(OGT, TINT64):
+// a = AJGT;
+// break;
+
+// case CASE(OGT, TUINT8):
+// case CASE(OGT, TUINT16):
+// case CASE(OGT, TUINT32):
+// case CASE(OGT, TUINT64):
+// case CASE(OLT, TFLOAT32):
+// case CASE(OLT, TFLOAT64):
+// a = AJHI;
+// break;
+
+// case CASE(OGE, TINT8):
+// case CASE(OGE, TINT16):
+// case CASE(OGE, TINT32):
+// case CASE(OGE, TINT64):
+// a = AJGE;
+// break;
+
+// case CASE(OGE, TUINT8):
+// case CASE(OGE, TUINT16):
+// case CASE(OGE, TUINT32):
+// case CASE(OGE, TUINT64):
+// case CASE(OLE, TFLOAT32):
+// case CASE(OLE, TFLOAT64):
+// a = AJCC;
+// break;
+
+// case CASE(OCMP, TBOOL):
+// case CASE(OCMP, TINT8):
+// case CASE(OCMP, TUINT8):
+// a = ACMPB;
+// break;
+
+// case CASE(OCMP, TINT16):
+// case CASE(OCMP, TUINT16):
+// a = ACMPW;
+// break;
+
+// case CASE(OCMP, TINT32):
+// case CASE(OCMP, TUINT32):
+// case CASE(OCMP, TPTR32):
+// a = ACMPL;
+// break;
+
+// case CASE(OCMP, TINT64):
+// case CASE(OCMP, TUINT64):
+// case CASE(OCMP, TPTR64):
+// a = ACMPQ;
+// break;
+
+// case CASE(OCMP, TFLOAT32):
+// a = AUCOMISS;
+// break;
+
+// case CASE(OCMP, TFLOAT64):
+// a = AUCOMISD;
+// break;
+
+// case CASE(OAS, TBOOL):
+// case CASE(OAS, TINT8):
+// case CASE(OAS, TUINT8):
+// a = AMOVB;
+// break;
+
+// case CASE(OAS, TINT16):
+// case CASE(OAS, TUINT16):
+// a = AMOVW;
+// break;
+
+// case CASE(OAS, TINT32):
+// case CASE(OAS, TUINT32):
+// case CASE(OAS, TPTR32):
+// a = AMOVL;
+// break;
+
+// case CASE(OAS, TINT64):
+// case CASE(OAS, TUINT64):
+// case CASE(OAS, TPTR64):
+// a = AMOVQ;
+// break;
+
+// case CASE(OAS, TFLOAT32):
+// a = AMOVSS;
+// break;
+
+// case CASE(OAS, TFLOAT64):
+// a = AMOVSD;
+// break;
+
+// case CASE(OADD, TINT8):
+// case CASE(OADD, TUINT8):
+// a = AADDB;
+// break;
+
+// case CASE(OADD, TINT16):
+// case CASE(OADD, TUINT16):
+// a = AADDW;
+// break;
+
+// case CASE(OADD, TINT32):
+// case CASE(OADD, TUINT32):
+// case CASE(OADD, TPTR32):
+// a = AADDL;
+// break;
+
+// case CASE(OADD, TINT64):
+// case CASE(OADD, TUINT64):
+// case CASE(OADD, TPTR64):
+// a = AADDQ;
+// break;
+
+// case CASE(OADD, TFLOAT32):
+// a = AADDSS;
+// break;
+
+// case CASE(OADD, TFLOAT64):
+// a = AADDSD;
+// break;
+
+// case CASE(OSUB, TINT8):
+// case CASE(OSUB, TUINT8):
+// a = ASUBB;
+// break;
+
+// case CASE(OSUB, TINT16):
+// case CASE(OSUB, TUINT16):
+// a = ASUBW;
+// break;
+
+// case CASE(OSUB, TINT32):
+// case CASE(OSUB, TUINT32):
+// case CASE(OSUB, TPTR32):
+// a = ASUBL;
+// break;
+
+// case CASE(OSUB, TINT64):
+// case CASE(OSUB, TUINT64):
+// case CASE(OSUB, TPTR64):
+// a = ASUBQ;
+// break;
+
+// case CASE(OSUB, TFLOAT32):
+// a = ASUBSS;
+// break;
+
+// case CASE(OSUB, TFLOAT64):
+// a = ASUBSD;
+// break;
+
+// case CASE(OINC, TINT8):
+// case CASE(OINC, TUINT8):
+// a = AINCB;
+// break;
+
+// case CASE(OINC, TINT16):
+// case CASE(OINC, TUINT16):
+// a = AINCW;
+// break;
+
+// case CASE(OINC, TINT32):
+// case CASE(OINC, TUINT32):
+// case CASE(OINC, TPTR32):
+// a = AINCL;
+// break;
+
+// case CASE(OINC, TINT64):
+// case CASE(OINC, TUINT64):
+// case CASE(OINC, TPTR64):
+// a = AINCQ;
+// break;
+
+// case CASE(ODEC, TINT8):
+// case CASE(ODEC, TUINT8):
+// a = ADECB;
+// break;
+
+// case CASE(ODEC, TINT16):
+// case CASE(ODEC, TUINT16):
+// a = ADECW;
+// break;
+
+// case CASE(ODEC, TINT32):
+// case CASE(ODEC, TUINT32):
+// case CASE(ODEC, TPTR32):
+// a = ADECL;
+// break;
+
+// case CASE(ODEC, TINT64):
+// case CASE(ODEC, TUINT64):
+// case CASE(ODEC, TPTR64):
+// a = ADECQ;
+// break;
+
+// case CASE(OMINUS, TINT8):
+// case CASE(OMINUS, TUINT8):
+// a = ANEGB;
+// break;
+
+// case CASE(OMINUS, TINT16):
+// case CASE(OMINUS, TUINT16):
+// a = ANEGW;
+// break;
+
+// case CASE(OMINUS, TINT32):
+// case CASE(OMINUS, TUINT32):
+// case CASE(OMINUS, TPTR32):
+// a = ANEGL;
+// break;
+
+// case CASE(OMINUS, TINT64):
+// case CASE(OMINUS, TUINT64):
+// case CASE(OMINUS, TPTR64):
+// a = ANEGQ;
+// break;
+
+// case CASE(OAND, TINT8):
+// case CASE(OAND, TUINT8):
+// a = AANDB;
+// break;
+
+// case CASE(OAND, TINT16):
+// case CASE(OAND, TUINT16):
+// a = AANDW;
+// break;
+
+// case CASE(OAND, TINT32):
+// case CASE(OAND, TUINT32):
+// case CASE(OAND, TPTR32):
+// a = AANDL;
+// break;
+
+// case CASE(OAND, TINT64):
+// case CASE(OAND, TUINT64):
+// case CASE(OAND, TPTR64):
+// a = AANDQ;
+// break;
+
+// case CASE(OOR, TINT8):
+// case CASE(OOR, TUINT8):
+// a = AORB;
+// break;
+
+// case CASE(OOR, TINT16):
+// case CASE(OOR, TUINT16):
+// a = AORW;
+// break;
+
+// case CASE(OOR, TINT32):
+// case CASE(OOR, TUINT32):
+// case CASE(OOR, TPTR32):
+// a = AORL;
+// break;
+
+// case CASE(OOR, TINT64):
+// case CASE(OOR, TUINT64):
+// case CASE(OOR, TPTR64):
+// a = AORQ;
+// break;
+
+// case CASE(OXOR, TINT8):
+// case CASE(OXOR, TUINT8):
+// a = AXORB;
+// break;
+
+// case CASE(OXOR, TINT16):
+// case CASE(OXOR, TUINT16):
+// a = AXORW;
+// break;
+
+// case CASE(OXOR, TINT32):
+// case CASE(OXOR, TUINT32):
+// case CASE(OXOR, TPTR32):
+// a = AXORL;
+// break;
+
+// case CASE(OXOR, TINT64):
+// case CASE(OXOR, TUINT64):
+// case CASE(OXOR, TPTR64):
+// a = AXORQ;
+// break;
+
+// case CASE(OLSH, TINT8):
+// case CASE(OLSH, TUINT8):
+// a = ASHLB;
+// break;
+
+// case CASE(OLSH, TINT16):
+// case CASE(OLSH, TUINT16):
+// a = ASHLW;
+// break;
+
+// case CASE(OLSH, TINT32):
+// case CASE(OLSH, TUINT32):
+// case CASE(OLSH, TPTR32):
+// a = ASHLL;
+// break;
+
+// case CASE(OLSH, TINT64):
+// case CASE(OLSH, TUINT64):
+// case CASE(OLSH, TPTR64):
+// a = ASHLQ;
+// break;
+
+// case CASE(ORSH, TUINT8):
+// a = ASHRB;
+// break;
+
+// case CASE(ORSH, TUINT16):
+// a = ASHRW;
+// break;
+
+// case CASE(ORSH, TUINT32):
+// case CASE(ORSH, TPTR32):
+// a = ASHRL;
+// break;
+
+// case CASE(ORSH, TUINT64):
+// case CASE(ORSH, TPTR64):
+// a = ASHRQ;
+// break;
+
+// case CASE(ORSH, TINT8):
+// a = ASARB;
+// break;
+
+// case CASE(ORSH, TINT16):
+// a = ASARW;
+// break;
+
+// case CASE(ORSH, TINT32):
+// a = ASARL;
+// break;
+
+// case CASE(ORSH, TINT64):
+// a = ASARQ;
+// break;
+
+// case CASE(OMUL, TINT8):
+// case CASE(OMUL, TUINT8):
+// a = AIMULB;
+// break;
+
+// case CASE(OMUL, TINT16):
+// case CASE(OMUL, TUINT16):
+// a = AIMULW;
+// break;
+
+// case CASE(OMUL, TINT32):
+// case CASE(OMUL, TUINT32):
+// case CASE(OMUL, TPTR32):
+// a = AIMULL;
+// break;
+
+// case CASE(OMUL, TINT64):
+// case CASE(OMUL, TUINT64):
+// case CASE(OMUL, TPTR64):
+// a = AIMULQ;
+// break;
+
+// case CASE(OMUL, TFLOAT32):
+// a = AMULSS;
+// break;
+
+// case CASE(OMUL, TFLOAT64):
+// a = AMULSD;
+// break;
+
+// case CASE(ODIV, TINT8):
+// case CASE(OMOD, TINT8):
+// a = AIDIVB;
+// break;
+
+// case CASE(ODIV, TUINT8):
+// case CASE(OMOD, TUINT8):
+// a = ADIVB;
+// break;
+
+// case CASE(ODIV, TINT16):
+// case CASE(OMOD, TINT16):
+// a = AIDIVW;
+// break;
+
+// case CASE(ODIV, TUINT16):
+// case CASE(OMOD, TUINT16):
+// a = ADIVW;
+// break;
+
+// case CASE(ODIV, TINT32):
+// case CASE(OMOD, TINT32):
+// a = AIDIVL;
+// break;
+
+// case CASE(ODIV, TUINT32):
+// case CASE(ODIV, TPTR32):
+// case CASE(OMOD, TUINT32):
+// case CASE(OMOD, TPTR32):
+// a = ADIVL;
+// break;
+
+// case CASE(ODIV, TINT64):
+// case CASE(OMOD, TINT64):
+// a = AIDIVQ;
+// break;
+
+// case CASE(ODIV, TUINT64):
+// case CASE(ODIV, TPTR64):
+// case CASE(OMOD, TUINT64):
+// case CASE(OMOD, TPTR64):
+// a = ADIVQ;
+// break;
+
+// case CASE(OEXTEND, TINT16):
+// a = ACWD;
+// break;
+
+// case CASE(OEXTEND, TINT32):
+// a = ACDQ;
+// break;
+
+// case CASE(OEXTEND, TINT64):
+// a = ACQO;
+// break;
+
+// case CASE(ODIV, TFLOAT32):
+// a = ADIVSS;
+// break;
+
+// case CASE(ODIV, TFLOAT64):
+// a = ADIVSD;
+// break;
+
+// }
+// return a;
+ fatal("optoas_unimplemented");
+}
+
+enum
+{
+ ODynam = 1<<0,
+ OPtrto = 1<<1,
+};
+
+static Node clean[20];
+static int cleani = 0;
+
+void
+sudoclean(void)
+{
+ if(clean[cleani-1].op != OEMPTY)
+ regfree(&clean[cleani-1]);
+ if(clean[cleani-2].op != OEMPTY)
+ regfree(&clean[cleani-2]);
+ cleani -= 2;
+}
+
+/*
+ * generate code to compute address of n,
+ * a reference to a (perhaps nested) field inside
+ * an array or struct.
+ * return 0 on failure, 1 on success.
+ * on success, leaves usable address in a.
+ *
+ * caller is responsible for calling sudoclean
+ * after successful sudoaddable,
+ * to release the register used for a.
+ */
+int
+sudoaddable(Node *n, Addr *a)
+{
+ int o, i, w;
+ int oary[10];
+ vlong v;
+ Node n1, n2, *nn, *l, *r;
+ Node *reg, *reg1;
+ Prog *p1;
+ Type *t;
+
+ if(n->type == T)
+ return 0;
+
+ switch(n->op) {
+ default:
+ return 0;
+
+ case ODOT:
+ case ODOTPTR:
+ cleani += 2;
+ reg = &clean[cleani-1];
+ reg1 = &clean[cleani-2];
+ reg->op = OEMPTY;
+ reg1->op = OEMPTY;
+ goto odot;
+
+ case OINDEX:
+ cleani += 2;
+ reg = &clean[cleani-1];
+ reg1 = &clean[cleani-2];
+ reg->op = OEMPTY;
+ reg1->op = OEMPTY;
+ goto oindex;
+ }
+
+odot:
+ o = dotoffset(n, oary, &nn);
+ if(nn == N)
+ goto no;
+
+ regalloc(reg, types[tptr], N);
+ n1 = *reg;
+ n1.op = OINDREG;
+ if(oary[0] >= 0) {
+ agen(nn, reg);
+ n1.xoffset = oary[0];
+ } else {
+ cgen(nn, reg);
+ n1.xoffset = -(oary[0]+1);
+ }
+
+ fatal("sudoaddable_unimplemented");
+// for(i=1; i<o; i++) {
+// if(oary[i] >= 0)
+// fatal("cant happen");
+// gins(AMOVQ, &n1, reg);
+// n1.xoffset = -(oary[i]+1);
+// }
+
+ a->type = D_NONE;
+ a->index = D_NONE;
+ naddr(&n1, a);
+ goto yes;
+
+oindex:
+ l = n->left;
+ r = n->right;
+ if(l->ullman >= UINF && r->ullman >= UINF)
+ goto no;
+
+ // set o to type of array
+ o = 0;
+ if(isptr[l->type->etype]) {
+ o += OPtrto;
+ if(l->type->type->etype != TARRAY)
+ fatal("not ptr ary");
+ if(l->type->type->bound < 0)
+ o += ODynam;
+ } else {
+ if(l->type->etype != TARRAY)
+ fatal("not ary");
+ if(l->type->bound < 0)
+ o += ODynam;
+ }
+
+ w = n->type->width;
+ if(isconst(r, CTINT))
+ goto oindex_const;
+
+ switch(w) {
+ default:
+ goto no;
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ }
+
+ // load the array (reg)
+ if(l->ullman > r->ullman) {
+ regalloc(reg, types[tptr], N);
+ if(o & OPtrto)
+ cgen(l, reg);
+ else
+ agen(l, reg);
+ }
+
+ // load the index (reg1)
+ t = types[TUINT64];
+ if(issigned[r->type->etype])
+ t = types[TINT64];
+ regalloc(reg1, t, N);
+ cgen(r, reg1);
+
+ // load the array (reg)
+ if(l->ullman <= r->ullman) {
+ regalloc(reg, types[tptr], N);
+ if(o & OPtrto)
+ cgen(l, reg);
+ else
+ agen(l, reg);
+ }
+
+ // check bounds
+ if(!debug['B']) {
+ if(o & ODynam) {
+ n2 = *reg;
+ n2.op = OINDREG;
+ n2.type = types[tptr];
+ n2.xoffset = Array_nel;
+ } else {
+ nodconst(&n2, types[TUINT64], l->type->bound);
+ if(o & OPtrto)
+ nodconst(&n2, types[TUINT64], l->type->type->bound);
+ }
+ gins(optoas(OCMP, types[TUINT32]), reg1, &n2);
+ p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ ginscall(throwindex, 0);
+ patch(p1, pc);
+ }
+
+ if(o & ODynam) {
+ n2 = *reg;
+ n2.op = OINDREG;
+ n2.type = types[tptr];
+ n2.xoffset = Array_array;
+ gmove(&n2, reg);
+ }
+
+ fatal("sudoaddable_unimplemented");
+// naddr(reg1, a);
+// a->offset = 0;
+// a->scale = w;
+// a->index = a->type;
+// a->type = reg->val.u.reg + D_INDIR;
+
+ goto yes;
+
+oindex_const:
+ // index is constant
+ // can check statically and
+ // can multiply by width statically
+
+ regalloc(reg, types[tptr], N);
+ if(o & OPtrto)
+ cgen(l, reg);
+ else
+ agen(l, reg);
+
+ v = mpgetfix(r->val.u.xval);
+ if(o & ODynam) {
+
+ if(!debug['B']) {
+ n1 = *reg;
+ 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 = *reg;
+ n1.op = OINDREG;
+ n1.type = types[tptr];
+ n1.xoffset = Array_array;
+ gmove(&n1, reg);
+
+ } else
+ if(!debug['B']) {
+ if(v < 0) {
+ yyerror("out of bounds on array");
+ } else
+ if(o & OPtrto) {
+ if(v >= l->type->type->bound)
+ yyerror("out of bounds on array");
+ } else
+ if(v >= l->type->bound) {
+ yyerror("out of bounds on array");
+ }
+ }
+
+ n2 = *reg;
+ n2.op = OINDREG;
+ n2.xoffset = v*w;
+ a->type = D_NONE;
+ a->index = D_NONE;
+ naddr(&n2, a);
+ goto yes;
+
+yes:
+ return 1;
+
+no:
+ sudoclean();
+ return 0;
+}
--- /dev/null
+// Derived from Inferno utils/5c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gg.h"
+
+void
+zname(Biobuf *b, Sym *s, int t)
+{
+ char *n;
+
+ Bputc(b, ANAME); /* as */
+ Bputc(b, ANAME>>8); /* as */
+ Bputc(b, t); /* type */
+ Bputc(b, s->sym); /* sym */
+
+ for(n=s->opackage; *n; n++)
+ Bputc(b, *n);
+ Bputdot(b);
+ for(n=s->name; *n; n++)
+ Bputc(b, *n);
+ Bputc(b, 0);
+}
+
+void
+zfile(Biobuf *b, char *p, int n)
+{
+ Bputc(b, ANAME);
+ Bputc(b, ANAME>>8);
+ Bputc(b, D_FILE);
+ Bputc(b, 1);
+ Bputc(b, '<');
+ Bwrite(b, p, n);
+ Bputc(b, 0);
+}
+
+void
+zhist(Biobuf *b, int line, vlong offset)
+{
+ Addr a;
+
+ Bputc(b, AHISTORY);
+ Bputc(b, AHISTORY>>8);
+ Bputc(b, line);
+ Bputc(b, line>>8);
+ Bputc(b, line>>16);
+ Bputc(b, line>>24);
+ zaddr(b, &zprog.from, 0);
+ a = zprog.to;
+ if(offset != 0) {
+ a.offset = offset;
+ a.type = D_CONST;
+ }
+ zaddr(b, &a, 0);
+}
+
+void
+zaddr(Biobuf *b, Addr *a, int s)
+{
+// int32 l;
+// uint64 e;
+// int i, t;
+// char *n;
+
+// t = 0;
+// if(a->index != D_NONE || a->scale != 0)
+// t |= T_INDEX;
+// if(s != 0)
+// t |= T_SYM;
+
+// switch(a->type) {
+
+// case D_BRANCH:
+// a->offset = a->branch->loc;
+
+// default:
+// t |= T_TYPE;
+
+// case D_NONE:
+// if(a->offset != 0)
+// t |= T_OFFSET;
+// if(a->offset2 != 0)
+// t |= T_OFFSET2;
+// break;
+// case D_FCONST:
+// t |= T_FCONST;
+// break;
+// case D_SCONST:
+// t |= T_SCONST;
+// break;
+// }
+// Bputc(b, t);
+
+// if(t & T_INDEX) { /* implies index, scale */
+// Bputc(b, a->index);
+// Bputc(b, a->scale);
+// }
+// if(t & T_OFFSET) { /* implies offset */
+// l = a->offset;
+// Bputc(b, l);
+// Bputc(b, l>>8);
+// Bputc(b, l>>16);
+// Bputc(b, l>>24);
+// }
+// if(t & T_OFFSET2) { /* implies offset */
+// l = a->offset2;
+// Bputc(b, l);
+// Bputc(b, l>>8);
+// Bputc(b, l>>16);
+// Bputc(b, l>>24);
+// }
+// if(t & T_SYM) /* implies sym */
+// Bputc(b, s);
+// if(t & T_FCONST) {
+// ieeedtod(&e, a->dval);
+// l = e;
+// Bputc(b, l);
+// Bputc(b, l>>8);
+// Bputc(b, l>>16);
+// Bputc(b, l>>24);
+// l = e >> 32;
+// Bputc(b, l);
+// Bputc(b, l>>8);
+// Bputc(b, l>>16);
+// Bputc(b, l>>24);
+// return;
+// }
+// if(t & T_SCONST) {
+// n = a->sval;
+// for(i=0; i<NSNAME; i++) {
+// Bputc(b, *n);
+// n++;
+// }
+// return;
+// }
+// if(t & T_TYPE)
+// Bputc(b, a->type);
+}
+
+void
+dumpfuncs(void)
+{
+ Plist *pl;
+ int sf, st, t, sym;
+ struct { Sym *sym; short type; } h[NSYM];
+ Sym *s;
+ Prog *p;
+
+ for(sym=0; sym<NSYM; sym++) {
+ h[sym].sym = S;
+ h[sym].type = 0;
+ }
+ sym = 1;
+
+ // fix up pc
+ pcloc = 0;
+ for(pl=plist; pl!=nil; pl=pl->link) {
+ for(p=pl->firstpc; p!=P; p=p->link) {
+ p->loc = pcloc;
+ pcloc++;
+ }
+ }
+
+ // put out functions
+ for(pl=plist; pl!=nil; pl=pl->link) {
+
+ if(debug['S']) {
+ s = S;
+ if(pl->name != N)
+ s = pl->name->sym;
+ print("\n--- prog list \"%S\" ---\n", s);
+ for(p=pl->firstpc; p!=P; p=p->link)
+ print("%P\n", p);
+ }
+
+ for(p=pl->firstpc; p!=P; p=p->link) {
+ jackpot:
+ sf = 0;
+ s = p->from.sym;
+ while(s != S) {
+ sf = s->sym;
+ if(sf < 0 || sf >= NSYM)
+ sf = 0;
+ t = p->from.type;
+ if(t == D_ADDR)
+ t = p->from.index;
+ if(h[sf].type == t)
+ if(h[sf].sym == s)
+ break;
+ s->sym = sym;
+ zname(bout, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ sf = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ break;
+ }
+ st = 0;
+ s = p->to.sym;
+ while(s != S) {
+ st = s->sym;
+ if(st < 0 || st >= NSYM)
+ st = 0;
+ t = p->to.type;
+ if(t == D_ADDR)
+ t = p->to.index;
+ if(h[st].type == t)
+ if(h[st].sym == s)
+ break;
+ s->sym = sym;
+ zname(bout, s, t);
+ h[sym].sym = s;
+ h[sym].type = t;
+ st = sym;
+ sym++;
+ if(sym >= NSYM)
+ sym = 1;
+ if(st == sf)
+ goto jackpot;
+ break;
+ }
+ Bputc(bout, p->as);
+ Bputc(bout, p->as>>8);
+ Bputc(bout, p->lineno);
+ Bputc(bout, p->lineno>>8);
+ Bputc(bout, p->lineno>>16);
+ Bputc(bout, p->lineno>>24);
+ zaddr(bout, &p->from, sf);
+ zaddr(bout, &p->to, st);
+ }
+ }
+}
+
+void
+datastring(char *s, int len)
+{
+// int w;
+// Prog *p;
+// Addr ac, ao;
+
+// // string
+// memset(&ao, 0, sizeof(ao));
+// ao.type = D_STATIC;
+// ao.index = D_NONE;
+// ao.etype = TINT32;
+// ao.sym = symstringo;
+// ao.offset = 0; // fill in
+
+// // constant
+// memset(&ac, 0, sizeof(ac));
+// ac.type = D_CONST;
+// ac.index = D_NONE;
+// ac.offset = 0; // fill in
+
+// for(w=0; w<len; w+=8) {
+// p = pc;
+// gins(ADATA, N, N);
+
+// // .stringo<>+oo, [NSNAME], $"xxx"
+// p->from = ao;
+// p->from.offset = stringo;
+
+// p->from.scale = NSNAME;
+// if(w+8 > len)
+// p->from.scale = len-w;
+
+// p->to = ac;
+// p->to.type = D_SCONST;
+// p->to.offset = len;
+// memmove(p->to.sval, s+w, p->from.scale);
+// stringo += p->from.scale;
+// }
+}
+
+void
+dumpstrings(void)
+{
+// Pool *l;
+// Prog *p;
+// Addr ac, ao;
+// int32 wi;
+
+// if(poolist == nil)
+// return;
+
+// memset(&ac, 0, sizeof(ac));
+// memset(&ao, 0, sizeof(ao));
+
+// // constant
+// ac.type = D_CONST;
+// ac.index = D_NONE;
+// ac.offset = 0; // fill in
+
+// // string len+ptr
+// ao.type = D_STATIC;
+// ao.index = D_NONE;
+// ao.etype = TINT32;
+// ao.sym = symstringo;
+// ao.offset = 0; // fill in
+
+// wi = types[TINT32]->width;
+
+// // lay out (count+string)
+// for(l=poolist; l!=nil; l=l->link) {
+
+// p = pc;
+// gins(ADATA, N, N);
+
+// // .stringo<>+xx, wi, $len
+// stringo = rnd(stringo, wi);
+// p->from = ao;
+// p->from.offset = stringo;
+// p->from.scale = wi;
+// p->to = ac;
+// p->to.offset = l->sval->len;
+// stringo += wi;
+
+// datastring(l->sval->s, l->sval->len);
+// }
+}
+
+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 = s;
+// p->from.offset = off;
+// p->from.scale = widthptr;
+// p->to.type = D_ADDR;
+// p->to.index = D_STATIC;
+// p->to.etype = TINT32;
+// p->to.sym = symstringo;
+// p->to.offset = stringo;
+// off += widthptr;
+
+// datastring(str, strlen(str)+1);
+ return off;
+}
+
+int
+duintxx(Sym *s, int off, uint64 v, int wid)
+{
+// Prog *p;
+
+// off = rnd(off, wid);
+
+// p = gins(ADATA, N, N);
+// p->from.type = D_EXTERN;
+// p->from.index = D_NONE;
+// p->from.sym = s;
+// p->from.offset = off;
+// p->from.scale = wid;
+// p->to.type = D_CONST;
+// p->to.index = D_NONE;
+// p->to.offset = v;
+// off += wid;
+
+ return off;
+}
+
+int
+duint32(Sym *s, int off, uint32 v)
+{
+ return duintxx(s, off, v, 4);
+}
+
+int
+duint16(Sym *s, int off, uint32 v)
+{
+ return duintxx(s, off, v, 2);
+}
+
+int
+duintptr(Sym *s, int off, uint32 v)
+{
+ return duintxx(s, off, v, 8);
+}
+
+int
+dsymptr(Sym *s, int off, Sym *x)
+{
+// Prog *p;
+
+// off = rnd(off, widthptr);
+
+// p = gins(ADATA, N, N);
+// p->from.type = D_EXTERN;
+// p->from.index = D_NONE;
+// p->from.sym = s;
+// p->from.offset = off;
+// p->from.scale = widthptr;
+// p->to.type = D_ADDR;
+// p->to.index = D_EXTERN;
+// p->to.sym = x;
+// p->to.offset = 0;
+// off += widthptr;
+
+ return off;
+}
+
+
+void
+genembedtramp(Type *t, Sig *b)
+{
+// Sym *e;
+// int c, d, o;
+// Prog *p;
+// Type *f;
+
+// e = lookup(b->name);
+// for(d=0; d<nelem(dotlist); d++) {
+// c = adddot1(e, t, d, nil);
+// if(c == 1)
+// goto out;
+// }
+// fatal("genembedtramp %T.%s", t, b->name);
+
+// out:
+// if(d == 0)
+// return;
+
+// // print("genembedtramp %d\n", d);
+// // print(" t = %lT\n", t);
+// // print(" name = %s\n", b->name);
+// // print(" sym = %S\n", b->sym);
+// // print(" hash = 0x%ux\n", b->hash);
+
+// newplist()->name = newname(b->sym);
+
+// //TEXT main·S_test2(SB),7,$0
+// p = pc;
+// gins(ATEXT, N, N);
+// p->from.type = D_EXTERN;
+// p->from.sym = b->sym;
+// p->to.type = D_CONST;
+// p->to.offset = 0;
+// p->from.scale = 7;
+// //print("1. %P\n", p);
+
+// //MOVL 4(SP), AX
+// p = pc;
+// gins(AMOVL, N, N);
+// p->from.type = D_INDIR+D_SP;
+// p->from.offset = 4;
+// p->to.type = D_AX;
+// //print("2. %P\n", p);
+
+// o = 0;
+// for(c=d-1; c>=0; c--) {
+// f = dotlist[c].field;
+// o += f->width;
+// if(!isptr[f->type->etype])
+// continue;
+// //MOVL o(AX), AX
+// p = pc;
+// gins(AMOVL, N, N);
+// p->from.type = D_INDIR+D_AX;
+// p->from.offset = o;
+// p->to.type = D_AX;
+// //print("3. %P\n", p);
+// o = 0;
+// }
+// if(o != 0) {
+// //ADDL $XX, AX
+// p = pc;
+// gins(AADDL, N, N);
+// p->from.type = D_CONST;
+// p->from.offset = o;
+// p->to.type = D_AX;
+// //print("4. %P\n", p);
+// }
+
+// //MOVL AX, 4(SP)
+// p = pc;
+// gins(AMOVL, N, N);
+// p->from.type = D_AX;
+// p->to.type = D_INDIR+D_SP;
+// p->to.offset = 8;
+// //print("5. %P\n", p);
+
+// f = dotlist[0].field;
+// //JMP main·*Sub_test2(SB)
+// if(isptr[f->type->etype])
+// f = f->type;
+// p = pc;
+// gins(AJMP, N, N);
+// p->to.type = D_EXTERN;
+// p->to.sym = methodsym(lookup(b->name), ptrto(f->type));
+// //print("6. %P\n", p);
+
+// pc->as = ARET; // overwrite AEND
+}
+
+void
+nopout(Prog *p)
+{
+ p->as = ANOP;
+}