/* * generate: * res = n; * simplifies and calls gmove. */ void complexmove(Node *f, Node *t) { int ft, tt; Node n1, n2, n3, n4; if(debug['g']) { dump("\ncomplexmove-f", f); dump("complexmove-t", t); } if(!t->addable) fatal("complexmove: to not addable"); ft = simsimtype(f->type); tt = simsimtype(t->type); switch(CASE(ft,tt)) { default: fatal("complexmove: unknown conversion: %T -> %T\n", f->type, t->type); case CASE(TCOMPLEX64,TCOMPLEX64): case CASE(TCOMPLEX64,TCOMPLEX128): case CASE(TCOMPLEX128,TCOMPLEX64): case CASE(TCOMPLEX128,TCOMPLEX128): // complex to complex move/convert. // make f addable. // also use temporary if possible stack overlap. if(!f->addable || overlap(f, t)) { tempname(&n1, f->type); complexmove(f, &n1); f = &n1; } subnode(&n1, &n2, f); subnode(&n3, &n4, t); cgen(&n1, &n3); cgen(&n2, &n4); break; } }
void complexgen(Node *n, Node *res) { Node *nl, *nr; Node tnl, tnr; Node n1, n2, tmp; int tl, tr; if(debug['g']) { dump("\ncomplexgen-n", n); dump("complexgen-res", res); } // pick off float/complex opcodes switch(n->op) { case OCMPLX: subnode(&n1, &n2, res); tempname(&tmp, n1.type); cgen(n->left, &tmp); cgen(n->right, &n2); cgen(&tmp, &n1); return; case OREAL: subnode(&n1, &n2, n->left); cgen(&n1, res); return; case OIMAG: subnode(&n1, &n2, n->left); cgen(&n2, res); return; } // perform conversion from n to res tl = simsimtype(res->type); tl = cplxsubtype(tl); tr = simsimtype(n->type); tr = cplxsubtype(tr); if(tl != tr) { if(!n->addable) { tempname(&n1, n->type); complexmove(n, &n1); n = &n1; } complexmove(n, res); return; } if(!res->addable) { igen(res, &n1, N); cgen(n, &n1); regfree(&n1); return; } if(n->addable) { complexmove(n, res); return; } switch(n->op) { default: dump("complexgen: unknown op", n); fatal("complexgen: unknown op %O", n->op); case ODOT: case ODOTPTR: case OINDEX: case OIND: case ONAME: // PHEAP or PPARAMREF var igen(n, &n1, res); complexmove(&n1, res); regfree(&n1); return; case OCONV: case OADD: case OSUB: case OMUL: case OMINUS: case OCMPLX: case OREAL: case OIMAG: break; } nl = n->left; if(nl == N) return; nr = n->right; // make both sides addable in ullman order if(nr != N) { if(nl->ullman > nr->ullman && !nl->addable) { tempname(&tnl, nl->type); cgen(nl, &tnl); nl = &tnl; } if(!nr->addable) { tempname(&tnr, nr->type); cgen(nr, &tnr); nr = &tnr; } } if(!nl->addable) { tempname(&tnl, nl->type); cgen(nl, &tnl); nl = &tnl; } switch(n->op) { default: fatal("complexgen: unknown op %O", n->op); break; case OCONV: complexmove(nl, res); break; case OMINUS: complexminus(nl, res); break; case OADD: case OSUB: complexadd(n->op, nl, nr, res); break; case OMUL: complexmul(nl, nr, res); break; // ODIV call a runtime function } }