diff options
author | Ken Thompson <ken@golang.org> | 2010-02-21 17:51:39 -0800 |
---|---|---|
committer | Ken Thompson <ken@golang.org> | 2010-02-21 17:51:39 -0800 |
commit | 458b53ea7df53a1398f2dc4ec2bf90e6f663e8a2 (patch) | |
tree | c5f6efe8cbbf539b6cc53028b9e9f3122d9554b1 | |
parent | ed13d39972b0fa04512aba5f2c404a17f2b2f771 (diff) | |
download | go-458b53ea7df53a1398f2dc4ec2bf90e6f663e8a2.tar.gz go-458b53ea7df53a1398f2dc4ec2bf90e6f663e8a2.zip |
all done except -
complex divide
float(complex) conversion
8g 5g etc
tests
R=rsc
CC=golang-dev
https://golang.org/cl/218044
-rw-r--r-- | src/cmd/6g/cplx.c | 368 | ||||
-rw-r--r-- | src/cmd/6g/gg.h | 2 | ||||
-rw-r--r-- | src/cmd/6g/gsubr.c | 30 |
3 files changed, 297 insertions, 103 deletions
diff --git a/src/cmd/6g/cplx.c b/src/cmd/6g/cplx.c index 0a8b999c43..6c91761a35 100644 --- a/src/cmd/6g/cplx.c +++ b/src/cmd/6g/cplx.c @@ -4,20 +4,29 @@ #include "gg.h" +static void subnode(Node *nr, Node *ni, Node *nc); +static void negate(Node *n); +static void zero(Node *n); +static int isimag1i(Node*); + #define CASE(a,b) (((a)<<16)|((b)<<0)) /* * generate: * res = n; * simplifies and calls gmove. + * perm is + * 0 (r,i) -> (r,i) + * 1 (r,i) -> (-i,r) *1i + * 2 (r,i) -> (i,-r) /1i */ void -complexmove(Node *f, Node *t) +complexmove(Node *f, Node *t, int perm) { int ft, tt; - Node n1, n2; + Node n1, n2, n3, n4, nc; - if(debug['g']) { + if(1||debug['g']) { dump("\ncomplex-f", f); dump("complex-t", t); } @@ -25,55 +34,94 @@ complexmove(Node *f, Node *t) if(!t->addable) fatal("to no addable"); - ft = cplxsubtype(simsimtype(f->type)); - tt = cplxsubtype(simsimtype(t->type)); - - // copy halfs of complex literal - if(f->op == OLITERAL) { - // real part - nodfconst(&n1, types[ft], &f->val.u.cval->real); - n2 = *t; - n2.type = types[tt]; - gmove(&n1, &n2); - - // imag part - nodfconst(&n1, types[ft], &f->val.u.cval->imag); - n2.xoffset += n2.type->width; - gmove(&n1, &n2); - return; - } + ft = simsimtype(f->type); + tt = simsimtype(t->type); + switch(CASE(ft,tt)) { - // make from addable - if(!f->addable) { - tempname(&n1, f->type); - complexgen(f, &n1); - f = &n1; - } + default: + fatal("complexmove: unknown conversion: %T -> %T\n", + f->type, t->type); - // real part - n1 = *f; - n1.type = types[ft]; + case CASE(TCOMPLEX64,TCOMPLEX64): + case CASE(TCOMPLEX64,TCOMPLEX128): + case CASE(TCOMPLEX128,TCOMPLEX64): + case CASE(TCOMPLEX128,TCOMPLEX128): + // complex to complex move/convert + // make from addable + if(!f->addable) { + tempname(&n1, f->type); + complexmove(f, &n1, 0); + f = &n1; + } - n2 = *t; - n2.type = types[tt]; + subnode(&n1, &n2, f); + subnode(&n3, &n4, t); - gmove(&n1, &n2); + // perform the permutations. + switch(perm) { + case 0: // r,i => r,i + gmove(&n1, &n3); + gmove(&n2, &n4); + break; + case 1: // r,i => -i,r + regalloc(&nc, n3.type, N); + gmove(&n2, &nc); + negate(&nc); + gmove(&n1, &n4); + gmove(&nc, &n3); + regfree(&nc); + break; + case 2: // r,i => i,-r + regalloc(&nc, n4.type, N); + gmove(&n1, &nc); + negate(&nc); + gmove(&n2, &n3); + gmove(&nc, &n4); + regfree(&nc); + break; + } + break; - // imag part - n1.xoffset += n1.type->width; - n2.xoffset += n2.type->width; - gmove(&n1, &n2); + case CASE(TFLOAT32,TCOMPLEX64): + case CASE(TFLOAT32,TCOMPLEX128): + case CASE(TFLOAT64,TCOMPLEX64): + case CASE(TFLOAT64,TCOMPLEX128): + // float to complex goes to real part + regalloc(&n1, types[ft], N); + cgen(f, &n1); + subnode(&n3, &n4, t); + + // perform the permutations. + switch(perm) { + case 0: // no permutations + gmove(&n1, &n3); + zero(&n4); + break; + case 1: + gmove(&n1, &n4); + zero(&n3); + break; + case 2: + negate(&n1); + gmove(&n1, &n4); + zero(&n3); + break; + } + regfree(&n1); + break; + } } void complexgen(Node *n, Node *res) { Node *nl, *nr; - Node n1, n2; + Node n1, n2, n3, n4, n5, n6; + Node ra, rb, rc, rd; int tl, tr; - if(debug['g']) { + if(1||debug['g']) { dump("\ncomplex-n", n); dump("complex-res", res); } @@ -84,42 +132,37 @@ complexgen(Node *n, Node *res) tr = simsimtype(n->type); tr = cplxsubtype(tr); if(tl != tr) { - tempname(&n1, n->type); - complexgen(n, &n1); - complexmove(&n1, n); + if(!n->addable) { + tempname(&n1, n->type); + complexmove(n, &n1, 0); + n = &n1; + } + complexmove(n, res, 0); return; } nl = n->left; if(nl == N) return; - nr = n->right; + + // make both sides addable in ullman order if(nr != N) { - // make both sides addable in ullman order - if(nl->ullman > nr->ullman) { - if(!nl->addable) { - tempname(&n1, nl->type); - complexgen(nl, &n1); - nl = &n1; - } - if(!nr->addable) { - tempname(&n1, nr->type); - complexgen(nr, &n2); - nr = &n2; - } - } else { - if(!nr->addable) { - tempname(&n1, nr->type); - complexgen(nr, &n2); - nr = &n2; - } - if(!nl->addable) { - tempname(&n1, nl->type); - complexgen(nl, &n1); - nl = &n1; - } + if(nl->ullman > nr->ullman && !nl->addable) { + tempname(&n1, nl->type); + complexgen(nl, &n1); + nl = &n1; } + if(!nr->addable) { + tempname(&n2, nr->type); + complexgen(nr, &n2); + nr = &n2; + } + } + if(!nl->addable) { + tempname(&n1, nl->type); + complexgen(nl, &n1); + nl = &n1; } switch(n->op) { @@ -127,21 +170,198 @@ complexgen(Node *n, Node *res) fatal("opcode %O", n->op); break; + case OCONV: + complexmove(nl, res, 0); + break; + + case OMINUS: + subnode(&n1, &n2, nl); + subnode(&n5, &n6, res); + + regalloc(&ra, n5.type, N); + gmove(&n1, &ra); + negate(&ra); + gmove(&ra, &n5); + regfree(&ra); + + regalloc(&ra, n5.type, N); + gmove(&n2, &ra); + negate(&ra); + gmove(&ra, &n6); + regfree(&ra); + break; + case OADD: case OSUB: + + subnode(&n1, &n2, nl); + subnode(&n3, &n4, nr); + subnode(&n5, &n6, res); + + regalloc(&ra, n5.type, N); + gmove(&n1, &ra); + gins(optoas(n->op, n5.type), &n3, &ra); + gmove(&ra, &n5); + regfree(&ra); + + regalloc(&ra, n6.type, N); + gmove(&n2, &ra); + gins(optoas(n->op, n6.type), &n4, &ra); + gmove(&ra, &n6); + regfree(&ra); + break; + case OMUL: - case ODIV: - if(nr == N) - fatal(""); - fatal("opcode %O", n->op); + if(isimag1i(nr)) { + complexmove(nl, res, 1); + break; + } + if(isimag1i(nl)) { + complexmove(nr, res, 1); + break; + } + + subnode(&n1, &n2, nl); + subnode(&n3, &n4, nr); + subnode(&n5, &n6, res); + + regalloc(&ra, n5.type, N); + regalloc(&rb, n5.type, N); + regalloc(&rc, n6.type, N); + regalloc(&rd, n6.type, N); + + gmove(&n1, &ra); + gmove(&n3, &rc); + gins(optoas(OMUL, n5.type), &rc, &ra); // ra = a*c + + gmove(&n2, &rb); + gmove(&n4, &rd); + gins(optoas(OMUL, n5.type), &rd, &rb); // rb = b*d + gins(optoas(OSUB, n5.type), &rb, &ra); // ra = (a*c - b*d) + + gins(optoas(OMUL, n5.type), &n2, &rc); // rc = b*c + gins(optoas(OMUL, n5.type), &n1, &rd); // rd = a*d + gins(optoas(OADD, n5.type), &rd, &rc); // rc = (b*c + a*d) + + gmove(&ra, &n5); + gmove(&rc, &n6); + + regfree(&ra); + regfree(&rb); + regfree(&rc); + regfree(&rd); break; - case OMINUS: + case ODIV: + if(isimag1i(nr)) { + complexmove(nl, res, 2); + break; + } fatal("opcode %O", n->op); - break; + } +} - case OCONV: - complexmove(nl, res); - break; +int +cplxsubtype(int et) +{ + if(et == TCOMPLEX64) + return TFLOAT32; + if(et == TCOMPLEX128) + return TFLOAT64; + fatal("cplxsubtype: %E\n", et); + return 0; +} + +void +nodfconst(Node *n, Type *t, Mpflt* fval) +{ + memset(n, 0, sizeof(*n)); + n->op = OLITERAL; + n->addable = 1; + ullmancalc(n); + n->val.u.fval = fval; + n->val.ctype = CTFLT; + n->type = t; + + if(!isfloat[t->etype]) + fatal("nodfconst: bad type %T", t); +} + +static int +isimag1i(Node *n) +{ + if(n != N) + if(n->op == OLITERAL) + if(n->val.ctype == CTCPLX) + if(mpgetflt(&n->val.u.cval->real) == 0.0) + if(mpgetflt(&n->val.u.cval->imag) == 1.0) + return 1; + return 0; +} + +// break addable nc-complex into nr-real and ni-imaginary +static void +subnode(Node *nr, Node *ni, Node *nc) +{ + int tc; + Type *t; + + if(!nc->addable) + fatal("subnode not addable"); + + tc = simsimtype(nc->type); + tc = cplxsubtype(tc); + t = types[tc]; + + if(nc->op == OLITERAL) { + nodfconst(nr, t, &nc->val.u.cval->real); + nodfconst(ni, t, &nc->val.u.cval->imag); + return; } + + *nr = *nc; + nr->type = t; + + *ni = *nc; + ni->type = t; + ni->xoffset += t->width; +} + +// generate code to negate register nr +static void +negate(Node *nr) +{ + Node nc; + Mpflt fval; + + memset(&nc, 0, sizeof(nc)); + nc.op = OLITERAL; + nc.addable = 1; + ullmancalc(&nc); + nc.val.u.fval = &fval; + nc.val.ctype = CTFLT; + nc.type = nr->type; + + mpmovecflt(nc.val.u.fval, -1.0); + gins(optoas(OMUL, nr->type), &nc, nr); +} + +// generate code to zero addable dest nr +static void +zero(Node *nr) +{ + Node nc; + Mpflt fval; + + memset(&nc, 0, sizeof(nc)); + nc.op = OLITERAL; + nc.addable = 1; + ullmancalc(&nc); + nc.val.u.fval = &fval; + nc.val.ctype = CTFLT; + nc.type = nr->type; + + mpmovecflt(nc.val.u.fval, 0.0); + + gmove(&nc, nr); } diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h index 264d01f851..d2d5629cd4 100644 --- a/src/cmd/6g/gg.h +++ b/src/cmd/6g/gg.h @@ -134,7 +134,7 @@ void nodfconst(Node*, Type*, Mpflt*); /* * cplx.c */ -void complexmove(Node*, Node*); +void complexmove(Node*, Node*, int); void complexgen(Node*, Node*); /* diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c index c58ebb78de..2ad6535b1e 100644 --- a/src/cmd/6g/gsubr.c +++ b/src/cmd/6g/gsubr.c @@ -476,7 +476,7 @@ gmove(Node *f, Node *t) cvt = t->type; if(iscomplex[ft] || iscomplex[tt]) { - complexmove(f, t); + complexmove(f, t, 0); return; } @@ -495,7 +495,7 @@ gmove(Node *f, Node *t) // float constants come from memory. if(isfloat[tt]) goto hard; - // complex constants take double move. + // 64-bit immediates are really 32-bit sign-extended // unless moving into a register. if(isint[tt]) { @@ -1979,29 +1979,3 @@ no: sudoclean(); return 0; } - -int -cplxsubtype(int et) -{ - if(et == TCOMPLEX64) - return TFLOAT32; - if(et == TCOMPLEX128) - return TFLOAT64; - fatal("cplxsubtype: %E\n", et); - return 0; -} - -void -nodfconst(Node *n, Type *t, Mpflt* fval) -{ - memset(n, 0, sizeof(*n)); - n->op = OLITERAL; - n->addable = 1; - ullmancalc(n); - n->val.u.fval = fval; - n->val.ctype = CTFLT; - n->type = t; - - if(!isfloat[t->etype]) - fatal("nodfconst: bad type %T", t); -} |