Commit f229c8b5 authored by Ken Thompson's avatar Ken Thompson

identical complex implementation

for 6g and 8g. can also be used
for 5g. 5g is still a stub.

R=rsc
CC=golang-dev
https://golang.org/cl/362041
parent 5b1a196c
...@@ -38,3 +38,6 @@ clean: ...@@ -38,3 +38,6 @@ clean:
install: $(TARG) install: $(TARG)
cp $(TARG) "$(GOBIN)"/$(TARG) cp $(TARG) "$(GOBIN)"/$(TARG)
%.$O: ../gc/%.c
$(CC) $(CFLAGS) -c -I. -o $@ ../gc/$*.c
...@@ -134,12 +134,12 @@ void nodfconst(Node*, Type*, Mpflt*); ...@@ -134,12 +134,12 @@ void nodfconst(Node*, Type*, Mpflt*);
* cplx.c * cplx.c
*/ */
int complexop(Node*, Node*); int complexop(Node*, Node*);
void complexmove(Node*, Node*, int); void complexmove(Node*, Node*);
void complexgen(Node*, Node*); void complexgen(Node*, Node*);
void complexbool(int, Node*, Node*, int, Prog*); void complexbool(int, Node*, Node*, int, Prog*);
/* /*
* obj.c * gobj.c
*/ */
void datastring(char*, int, Addr*); void datastring(char*, int, Addr*);
......
...@@ -483,7 +483,7 @@ gmove(Node *f, Node *t) ...@@ -483,7 +483,7 @@ gmove(Node *f, Node *t)
cvt = t->type; cvt = t->type;
if(iscomplex[ft] || iscomplex[tt]) { if(iscomplex[ft] || iscomplex[tt]) {
complexmove(f, t, 0); complexmove(f, t);
return; return;
} }
......
...@@ -22,6 +22,7 @@ OFILES=\ ...@@ -22,6 +22,7 @@ OFILES=\
gsubr.$O\ gsubr.$O\
cgen.$O\ cgen.$O\
cgen64.$O\ cgen64.$O\
cplx.$O\
peep.$O\ peep.$O\
reg.$O\ reg.$O\
...@@ -38,3 +39,6 @@ clean: ...@@ -38,3 +39,6 @@ clean:
install: $(TARG) install: $(TARG)
cp $(TARG) "$(GOBIN)"/$(TARG) cp $(TARG) "$(GOBIN)"/$(TARG)
%.$O: ../gc/%.c
$(CC) $(CFLAGS) -c -I. -o $@ ../gc/$*.c
...@@ -57,12 +57,6 @@ cgen(Node *n, Node *res) ...@@ -57,12 +57,6 @@ cgen(Node *n, Node *res)
if(res == N || res->type == T) if(res == N || res->type == T)
fatal("cgen: res nil"); fatal("cgen: res nil");
// TODO compile complex
if(n != N && n->type != T && iscomplex[n->type->etype])
return;
if(res != N && res->type != T && iscomplex[res->type->etype])
return;
// inline slices // inline slices
if(cgen_inline(n, res)) if(cgen_inline(n, res))
return; return;
...@@ -98,6 +92,12 @@ cgen(Node *n, Node *res) ...@@ -98,6 +92,12 @@ cgen(Node *n, Node *res)
break; break;
} }
// complex types
if(complexop(n, res)) {
complexgen(n, res);
return;
}
// if both are addressable, move // if both are addressable, move
if(n->addable && res->addable) { if(n->addable && res->addable) {
gmove(n, res); gmove(n, res);
...@@ -741,12 +741,6 @@ bgen(Node *n, int true, Prog *to) ...@@ -741,12 +741,6 @@ bgen(Node *n, int true, Prog *to)
nl = n->left; nl = n->left;
nr = n->right; nr = n->right;
// TODO compile complex
if(nl != N && nl->type != T && iscomplex[nl->type->etype])
return;
if(nr != N && nr->type != T && iscomplex[nr->type->etype])
return;
if(n->type == T) { if(n->type == T) {
convlit(&n, types[TBOOL]); convlit(&n, types[TBOOL]);
if(n->type == T) if(n->type == T)
...@@ -857,6 +851,7 @@ bgen(Node *n, int true, Prog *to) ...@@ -857,6 +851,7 @@ bgen(Node *n, int true, Prog *to)
break; break;
} }
a = brcom(a); a = brcom(a);
true = !true;
} }
// make simplest on right // make simplest on right
...@@ -960,6 +955,10 @@ bgen(Node *n, int true, Prog *to) ...@@ -960,6 +955,10 @@ bgen(Node *n, int true, Prog *to)
patch(gbranch(optoas(a, nr->type), T), to); patch(gbranch(optoas(a, nr->type), T), to);
break; break;
} }
if(iscomplex[nl->type->etype]) {
complexbool(a, nl, nr, true, to);
break;
}
if(is64(nr->type)) { if(is64(nr->type)) {
if(!nl->addable) { if(!nl->addable) {
......
...@@ -157,6 +157,14 @@ void split64(Node*, Node*, Node*); ...@@ -157,6 +157,14 @@ void split64(Node*, Node*, Node*);
void splitclean(void); void splitclean(void);
void nswap(Node*, Node*); void nswap(Node*, Node*);
/*
* cplx.c
*/
int complexop(Node*, Node*);
void complexmove(Node*, Node*);
void complexgen(Node*, Node*);
void complexbool(int, Node*, Node*, int, Prog*);
/* /*
* gobj.c * gobj.c
*/ */
......
...@@ -1059,6 +1059,11 @@ gmove(Node *f, Node *t) ...@@ -1059,6 +1059,11 @@ gmove(Node *f, Node *t)
tt = simsimtype(t->type); tt = simsimtype(t->type);
cvt = t->type; cvt = t->type;
if(iscomplex[ft] || iscomplex[tt]) {
complexmove(f, t);
return;
}
// cannot have two integer memory operands; // cannot have two integer memory operands;
// except 64-bit, which always copies via registers anyway. // except 64-bit, which always copies via registers anyway.
if(isint[ft] && isint[tt] && !is64(f->type) && !is64(t->type) && ismem(f) && ismem(t)) if(isint[ft] && isint[tt] && !is64(f->type) && !is64(t->type) && ismem(f) && ismem(t))
...@@ -1489,13 +1494,13 @@ gmove(Node *f, Node *t) ...@@ -1489,13 +1494,13 @@ gmove(Node *f, Node *t)
// on the floating point stack. So toss it away here. // on the floating point stack. So toss it away here.
// Also, F0 is the *only* register we ever evaluate // Also, F0 is the *only* register we ever evaluate
// into, so we should only see register/register as F0/F0. // into, so we should only see register/register as F0/F0.
if(ismem(f) && ismem(t))
goto hard;
if(f->op == OREGISTER && t->op == OREGISTER) { if(f->op == OREGISTER && t->op == OREGISTER) {
if(f->val.u.reg != D_F0 || t->val.u.reg != D_F0) if(f->val.u.reg != D_F0 || t->val.u.reg != D_F0)
goto fatal; goto fatal;
return; return;
} }
if(ismem(f) && ismem(t))
goto hard;
a = AFMOVF; a = AFMOVF;
if(ft == TFLOAT64) if(ft == TFLOAT64)
a = AFMOVD; a = AFMOVD;
...@@ -1509,6 +1514,8 @@ gmove(Node *f, Node *t) ...@@ -1509,6 +1514,8 @@ gmove(Node *f, Node *t)
break; break;
case CASE(TFLOAT32, TFLOAT64): case CASE(TFLOAT32, TFLOAT64):
if(ismem(f) && ismem(t))
goto hard;
if(f->op == OREGISTER && t->op == OREGISTER) { if(f->op == OREGISTER && t->op == OREGISTER) {
if(f->val.u.reg != D_F0 || t->val.u.reg != D_F0) if(f->val.u.reg != D_F0 || t->val.u.reg != D_F0)
goto fatal; goto fatal;
...@@ -1521,6 +1528,8 @@ gmove(Node *f, Node *t) ...@@ -1521,6 +1528,8 @@ gmove(Node *f, Node *t)
return; return;
case CASE(TFLOAT64, TFLOAT32): case CASE(TFLOAT64, TFLOAT32):
if(ismem(f) && ismem(t))
goto hard;
if(f->op == OREGISTER && t->op == OREGISTER) { if(f->op == OREGISTER && t->op == OREGISTER) {
tempname(&r1, types[TFLOAT32]); tempname(&r1, types[TFLOAT32]);
gins(AFMOVFP, f, &r1); gins(AFMOVFP, f, &r1);
......
...@@ -79,6 +79,7 @@ char *runtimeimport = ...@@ -79,6 +79,7 @@ char *runtimeimport =
"func \"\".uint64mod (? uint64, ? uint64) uint64\n" "func \"\".uint64mod (? uint64, ? uint64) uint64\n"
"func \"\".float64toint64 (? float64) int64\n" "func \"\".float64toint64 (? float64) int64\n"
"func \"\".int64tofloat64 (? int64) float64\n" "func \"\".int64tofloat64 (? int64) float64\n"
"func \"\".complex128div (num complex128, den complex128) (quo complex128)\n"
"\n" "\n"
"$$\n"; "$$\n";
char *unsafeimport = char *unsafeimport =
......
...@@ -5,9 +5,11 @@ ...@@ -5,9 +5,11 @@
#include "gg.h" #include "gg.h"
static void subnode(Node *nr, Node *ni, Node *nc); static void subnode(Node *nr, Node *ni, Node *nc);
static void negate(Node *n);
static void zero(Node *n); static void zero(Node *n);
static int isimag1i(Node*); static void minus(Node *nl, Node *res);
void complexminus(Node*, Node*);
void complexadd(int op, Node*, Node*, Node*);
void complexmul(Node*, Node*, Node*);
#define CASE(a,b) (((a)<<16)|((b)<<0)) #define CASE(a,b) (((a)<<16)|((b)<<0))
...@@ -15,16 +17,12 @@ static int isimag1i(Node*); ...@@ -15,16 +17,12 @@ static int isimag1i(Node*);
* generate: * generate:
* res = n; * res = n;
* simplifies and calls gmove. * simplifies and calls gmove.
* perm is
* 0 (r,i) -> (r,i)
* 1 (r,i) -> (-i,r) *1i
* 2 (r,i) -> (i,-r) /1i
*/ */
void void
complexmove(Node *f, Node *t, int perm) complexmove(Node *f, Node *t)
{ {
int ft, tt; int ft, tt;
Node n1, n2, n3, n4, nc; Node n1, n2, n3, n4;
if(debug['g']) { if(debug['g']) {
dump("\ncomplexmove-f", f); dump("\ncomplexmove-f", f);
...@@ -50,65 +48,27 @@ complexmove(Node *f, Node *t, int perm) ...@@ -50,65 +48,27 @@ complexmove(Node *f, Node *t, int perm)
// make from addable // make from addable
if(!f->addable) { if(!f->addable) {
tempname(&n1, f->type); tempname(&n1, f->type);
complexmove(f, &n1, 0); complexmove(f, &n1);
f = &n1; f = &n1;
} }
subnode(&n1, &n2, f); subnode(&n1, &n2, f);
subnode(&n3, &n4, t); subnode(&n3, &n4, t);
// perform the permutations. cgen(&n1, &n3);
switch(perm) { cgen(&n2, &n4);
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; break;
// these are depricated
case CASE(TFLOAT32,TCOMPLEX64): case CASE(TFLOAT32,TCOMPLEX64):
case CASE(TFLOAT32,TCOMPLEX128): case CASE(TFLOAT32,TCOMPLEX128):
case CASE(TFLOAT64,TCOMPLEX64): case CASE(TFLOAT64,TCOMPLEX64):
case CASE(TFLOAT64,TCOMPLEX128): case CASE(TFLOAT64,TCOMPLEX128):
// float to complex goes to real part // float to complex goes to real part
regalloc(&n1, types[ft], N); subnode(&n1, &n2, t);
cgen(f, &n1); cgen(f, &n1);
subnode(&n3, &n4, t); zero(&n2);
// 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; break;
} }
} }
...@@ -118,40 +78,44 @@ complexop(Node *n, Node *res) ...@@ -118,40 +78,44 @@ complexop(Node *n, Node *res)
{ {
if(n != N && n->type != T) if(n != N && n->type != T)
if(iscomplex[n->type->etype]) { if(iscomplex[n->type->etype]) {
goto yes; goto maybe;
} }
if(res != N && res->type != T) if(res != N && res->type != T)
if(iscomplex[res->type->etype]) { if(iscomplex[res->type->etype]) {
goto yes; goto maybe;
} }
if(n->op == OREAL || n->op == OIMAG) if(n->op == OREAL || n->op == OIMAG)
return 1; goto yes;
return 0; goto no;
yes: maybe:
switch(n->op) { switch(n->op) {
case OCONV: // implemented ops case OCONV: // implemented ops
case OADD: case OADD:
case OSUB: case OSUB:
case OMUL: case OMUL:
case ODIV:
case OMINUS: case OMINUS:
case OCMPLX: case OCMPLX:
case OREAL: case OREAL:
case OIMAG: case OIMAG:
return 1; goto yes;
case ODOT: // sudoaddr case ODOT:
case ODOTPTR: case ODOTPTR:
case OINDEX: case OINDEX:
case OIND: case OIND:
case ONAME: case ONAME:
return 1; goto yes;
} }
no:
//dump("\ncomplex-no", n);
return 0; return 0;
yes:
//dump("\ncomplex-yes", n);
return 1;
} }
void void
...@@ -159,8 +123,7 @@ complexgen(Node *n, Node *res) ...@@ -159,8 +123,7 @@ complexgen(Node *n, Node *res)
{ {
Node *nl, *nr; Node *nl, *nr;
Node tnl, tnr; Node tnl, tnr;
Node n1, n2, n3, n4, n5, n6; Node n1, n2;
Node ra, rb, rc, rd;
int tl, tr; int tl, tr;
if(debug['g']) { if(debug['g']) {
...@@ -171,35 +134,18 @@ complexgen(Node *n, Node *res) ...@@ -171,35 +134,18 @@ complexgen(Node *n, Node *res)
// pick off float/complex opcodes // pick off float/complex opcodes
switch(n->op) { switch(n->op) {
case OCMPLX: case OCMPLX:
tempname(&tnr, n->type); subnode(&n1, &n2, res);
tr = simsimtype(n->type);
tr = cplxsubtype(tr);
n1 = tnr;
n1.type = types[tr];
n2 = tnr;
n2.type = types[tr];
n2.xoffset += n2.type->width;
cgen(n->left, &n1); cgen(n->left, &n1);
cgen(n->right, &n2); cgen(n->right, &n2);
cgen(&tnr, res);
return; return;
case OREAL: case OREAL:
n = n->left; subnode(&n1, &n2, n->left);
tr = simsimtype(n->type);
tr = cplxsubtype(tr);
subnode(&n1, &n2, n);
cgen(&n1, res); cgen(&n1, res);
return; return;
case OIMAG: case OIMAG:
n = n->left; subnode(&n1, &n2, n->left);
tr = simsimtype(n->type);
tr = cplxsubtype(tr);
subnode(&n1, &n2, n);
cgen(&n2, res); cgen(&n2, res);
return; return;
} }
...@@ -212,10 +158,10 @@ complexgen(Node *n, Node *res) ...@@ -212,10 +158,10 @@ complexgen(Node *n, Node *res)
if(tl != tr) { if(tl != tr) {
if(!n->addable) { if(!n->addable) {
tempname(&n1, n->type); tempname(&n1, n->type);
complexmove(n, &n1, 0); complexmove(n, &n1);
n = &n1; n = &n1;
} }
complexmove(n, res, 0); complexmove(n, res);
return; return;
} }
...@@ -226,7 +172,7 @@ complexgen(Node *n, Node *res) ...@@ -226,7 +172,7 @@ complexgen(Node *n, Node *res)
return; return;
} }
if(n->addable) { if(n->addable) {
complexmove(n, res, 0); complexmove(n, res);
return; return;
} }
...@@ -241,7 +187,7 @@ complexgen(Node *n, Node *res) ...@@ -241,7 +187,7 @@ complexgen(Node *n, Node *res)
case OIND: case OIND:
case ONAME: // PHEAP or PPARAMREF var case ONAME: // PHEAP or PPARAMREF var
igen(n, &n1, res); igen(n, &n1, res);
complexmove(&n1, res, 0); complexmove(&n1, res);
regfree(&n1); regfree(&n1);
return; return;
...@@ -249,7 +195,6 @@ complexgen(Node *n, Node *res) ...@@ -249,7 +195,6 @@ complexgen(Node *n, Node *res)
case OADD: case OADD:
case OSUB: case OSUB:
case OMUL: case OMUL:
case ODIV:
case OMINUS: case OMINUS:
case OCMPLX: case OCMPLX:
case OREAL: case OREAL:
...@@ -287,132 +232,22 @@ complexgen(Node *n, Node *res) ...@@ -287,132 +232,22 @@ complexgen(Node *n, Node *res)
break; break;
case OCONV: case OCONV:
complexmove(nl, res, 0); complexmove(nl, res);
break; break;
case OMINUS: case OMINUS:
subnode(&n1, &n2, nl); complexminus(nl, res);
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; break;
case OADD: case OADD:
case OSUB: case OSUB:
complexadd(n->op, nl, nr, res);
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; break;
case OMUL: case OMUL:
if(isimag1i(nr)) { complexmul(nl, nr, res);
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 ODIV:
if(isimag1i(nr)) {
complexmove(nl, res, 2);
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(OADD, 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(OSUB, n5.type), &rd, &rc); // rc = (b*c - a*d)
gmove(&n3, &rb);
gins(optoas(OMUL, n5.type), &rb, &rb); // rb = c*c
gmove(&n4, &rd);
gins(optoas(OMUL, n5.type), &rd, &rd); // rd = d*d
gins(optoas(OADD, n5.type), &rd, &rb); // rb = (c*c + d*d)
gins(optoas(ODIV, n5.type), &rb, &ra); // ra = (a*c + b*d)/(c*c + d*d)
gins(optoas(ODIV, n5.type), &rb, &rc); // rc = (b*c - a*d)/(c*c + d*d)
gmove(&ra, &n5);
gmove(&rc, &n6);
regfree(&ra);
regfree(&rb);
regfree(&rc);
regfree(&rd);
break; break;
// ODIV call a runtime function
} }
} }
...@@ -487,18 +322,6 @@ nodfconst(Node *n, Type *t, Mpflt* fval) ...@@ -487,18 +322,6 @@ nodfconst(Node *n, Type *t, Mpflt* fval)
fatal("nodfconst: bad type %T", t); 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 // break addable nc-complex into nr-real and ni-imaginary
static void static void
subnode(Node *nr, Node *ni, Node *nc) subnode(Node *nr, Node *ni, Node *nc)
...@@ -527,9 +350,9 @@ subnode(Node *nr, Node *ni, Node *nc) ...@@ -527,9 +350,9 @@ subnode(Node *nr, Node *ni, Node *nc)
ni->xoffset += t->width; ni->xoffset += t->width;
} }
// generate code to negate register nr // generate code to zero addable dest nr
static void static void
negate(Node *nr) zero(Node *nr)
{ {
Node nc; Node nc;
Mpflt fval; Mpflt fval;
...@@ -542,26 +365,118 @@ negate(Node *nr) ...@@ -542,26 +365,118 @@ negate(Node *nr)
nc.val.ctype = CTFLT; nc.val.ctype = CTFLT;
nc.type = nr->type; nc.type = nr->type;
mpmovecflt(nc.val.u.fval, -1.0); mpmovecflt(nc.val.u.fval, 0.0);
gins(optoas(OMUL, nr->type), &nc, nr);
cgen(&nc, nr);
} }
// generate code to zero addable dest nr // generate code res = -nl
static void static void
zero(Node *nr) minus(Node *nl, Node *res)
{ {
Node nc; Node ra;
Mpflt fval;
memset(&nc, 0, sizeof(nc)); memset(&ra, 0, sizeof(ra));
nc.op = OLITERAL; ra.op = OMINUS;
nc.addable = 1; ra.left = nl;
ullmancalc(&nc); ra.type = nl->type;
nc.val.u.fval = &fval; cgen(&ra, res);
nc.val.ctype = CTFLT; }
nc.type = nr->type;
mpmovecflt(nc.val.u.fval, 0.0); // build and execute tree
// real(res) = -real(nl)
// imag(res) = -imag(nl)
void
complexminus(Node *nl, Node *res)
{
Node n1, n2, n5, n6;
subnode(&n1, &n2, nl);
subnode(&n5, &n6, res);
minus(&n1, &n5);
minus(&n2, &n6);
}
// build and execute tree
// real(res) = real(nl) op real(nr)
// imag(res) = imag(nl) op imag(nr)
void
complexadd(int op, Node *nl, Node *nr, Node *res)
{
Node n1, n2, n3, n4, n5, n6;
Node ra;
subnode(&n1, &n2, nl);
subnode(&n3, &n4, nr);
subnode(&n5, &n6, res);
memset(&ra, 0, sizeof(ra));
ra.op = op;
ra.left = &n1;
ra.right = &n3;
ra.type = n1.type;
cgen(&ra, &n5);
memset(&ra, 0, sizeof(ra));
ra.op = op;
ra.left = &n2;
ra.right = &n4;
ra.type = n2.type;
cgen(&ra, &n6);
}
// build and execute tree
// real(res) = real(nl)*real(nr) - imag(nl)*imag(nr)
// imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr)
void
complexmul(Node *nl, Node *nr, Node *res)
{
Node n1, n2, n3, n4, n5, n6;
Node rm1, rm2, ra;
subnode(&n1, &n2, nl);
subnode(&n3, &n4, nr);
subnode(&n5, &n6, res);
gmove(&nc, nr); // real part
memset(&rm1, 0, sizeof(ra));
rm1.op = OMUL;
rm1.left = &n1;
rm1.right = &n3;
rm1.type = n1.type;
memset(&rm2, 0, sizeof(ra));
rm2.op = OMUL;
rm2.left = &n2;
rm2.right = &n4;
rm2.type = n2.type;
memset(&ra, 0, sizeof(ra));
ra.op = OSUB;
ra.left = &rm1;
ra.right = &rm2;
ra.type = rm1.type;
cgen(&ra, &n5);
// imag part
memset(&rm1, 0, sizeof(ra));
rm1.op = OMUL;
rm1.left = &n1;
rm1.right = &n4;
rm1.type = n1.type;
memset(&rm2, 0, sizeof(ra));
rm2.op = OMUL;
rm2.left = &n2;
rm2.right = &n3;
rm2.type = n2.type;
memset(&ra, 0, sizeof(ra));
ra.op = OADD;
ra.left = &rm1;
ra.right = &rm2;
ra.type = rm1.type;
cgen(&ra, &n6);
} }
...@@ -101,3 +101,5 @@ func int64mod(int64, int64) int64 ...@@ -101,3 +101,5 @@ func int64mod(int64, int64) int64
func uint64mod(uint64, uint64) uint64 func uint64mod(uint64, uint64) uint64
func float64toint64(float64) int64 func float64toint64(float64) int64
func int64tofloat64(int64) float64 func int64tofloat64(int64) float64
func complex128div(num complex128, den complex128) (quo complex128)
...@@ -851,13 +851,22 @@ walkexpr(Node **np, NodeList **init) ...@@ -851,13 +851,22 @@ walkexpr(Node **np, NodeList **init)
case ODIV: case ODIV:
case OMOD: case OMOD:
walkexpr(&n->left, init);
walkexpr(&n->right, init);
/*
* rewrite complex div into function call.
*/
et = n->left->type->etype;
if(iscomplex[et] && n->op == ODIV) {
n = mkcall("complex128div", n->type, init,
conv(n->left, types[TCOMPLEX128]),
conv(n->right, types[TCOMPLEX128]));
goto ret;
}
/* /*
* rewrite div and mod into function calls * rewrite div and mod into function calls
* on 32-bit architectures. * on 32-bit architectures.
*/ */
walkexpr(&n->left, init);
walkexpr(&n->right, init);
et = n->left->type->etype;
if(widthptr > 4 || (et != TUINT64 && et != TINT64)) if(widthptr > 4 || (et != TUINT64 && et != TINT64))
goto ret; goto ret;
if(et == TINT64) if(et == TINT64)
......
...@@ -48,6 +48,7 @@ OFILES=\ ...@@ -48,6 +48,7 @@ OFILES=\
chan.$O\ chan.$O\
closure.$O\ closure.$O\
float.$O\ float.$O\
complex.$O\
hashmap.$O\ hashmap.$O\
iface.$O\ iface.$O\
malloc.$O\ malloc.$O\
......
// Copyright 2010 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 "runtime.h"
// complex128div(num, den complex128) (quo complex128)
void
·complex128div(float64 numreal, float64 numimag,
float64 denreal, float64 denimag,
float64 quoreal, float64 quoimag)
{
float64 a, b, ratio, denom;
a = denreal;
if(a < 0)
a = -a;
b = denimag;
if(b < 0)
b = -b;
if(a <= b) {
if(b == 0)
throw("complex divide");
ratio = denreal/denimag;
denom = denreal*ratio + denimag;
quoreal = (numreal*ratio + numimag) / denom;
quoimag = (numimag*ratio - numreal) / denom;
} else {
ratio = denimag/denreal;
denom = denimag*ratio + denreal;
quoreal = (numimag*ratio + numreal) / denom;
quoimag = (numimag - numreal*ratio) / denom;
}
FLUSH(&quoreal);
FLUSH(&quoimag);
}
...@@ -56,6 +56,25 @@ Hello World! ...@@ -56,6 +56,25 @@ Hello World!
== ken/ == ken/
=========== ken/cplx0.go
(+5.000000e+000+6.000000e+000i)
(+5.000000e+000+6.000000e+000i)
(+5.000000e+000+6.000000e+000i)
(+5.000000e+000+6.000000e+000i)
=========== ken/cplx3.go
(+1.292308e+000-1.384615e-001i)
(+1.292308e+000-1.384615e-001i)
64
=========== ken/cplx4.go
c = (-5.000000-6.000000i)
c = (5.000000+6.000000i)
c = (5.000000+6.000000i)
c = (5.000000+6.000000i)
c = (5+6i)
c = (13+7i)
=========== ken/intervar.go =========== ken/intervar.go
print 1 bio 2 file 3 -- abc print 1 bio 2 file 3 -- abc
......
// true // $G $D/$F.go && $L $F.$A && ./$A.out
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
// [ $GOARCH != amd64 ] || ($G $D/$F.go && $L $F.$A && ./$A.out) // $G $D/$F.go && $L $F.$A && ./$A.out
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
// [ $GOARCH != amd64 ] || ($G $D/$F.go && $L $F.$A && ./$A.out) // $G $D/$F.go && $L $F.$A && ./$A.out
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
// true // $G $D/$F.go && $L $F.$A && ./$A.out
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -20,7 +20,7 @@ var complexBits = reflect.Typeof(complex(0i)).Size() * 8 ...@@ -20,7 +20,7 @@ var complexBits = reflect.Typeof(complex(0i)).Size() * 8
func main() { func main() {
c0 := C1 c0 := C1
c0 = (c0+c0+c0) / (c0+c0) c0 = (c0+c0+c0) / (c0+c0+3i)
println(c0) println(c0)
c := *(*complex)(unsafe.Pointer(&c0)) c := *(*complex)(unsafe.Pointer(&c0))
......
// true // $G $D/$F.go && $L $F.$A && ./$A.out
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment