1
0
mirror of https://github.com/golang/go synced 2024-11-22 00:24:41 -07:00

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
This commit is contained in:
Ken Thompson 2010-03-09 12:49:24 -08:00
parent 5b1a196c37
commit f229c8b546
19 changed files with 274 additions and 268 deletions

View File

@ -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

View File

@ -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*);

View File

@ -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;
} }

View File

@ -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:
install: $(TARG) install: $(TARG)
cp $(TARG) "$(GOBIN)"/$(TARG) cp $(TARG) "$(GOBIN)"/$(TARG)
%.$O: ../gc/%.c
$(CC) $(CFLAGS) -c -I. -o $@ ../gc/$*.c

View File

@ -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)
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)
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)
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)
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) {

View File

@ -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
*/ */

View File

@ -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)
// 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)
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)
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);

View File

@ -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 =

View File

@ -4,10 +4,12 @@
#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 void minus(Node *nl, Node *res);
static int isimag1i(Node*); 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*);
* 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)
// 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)
{ {
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)
{ {
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)
// 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)
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)
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)
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)
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)
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)
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,25 +350,6 @@ subnode(Node *nr, Node *ni, Node *nc)
ni->xoffset += t->width; 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 // generate code to zero addable dest nr
static void static void
zero(Node *nr) zero(Node *nr)
@ -563,5 +367,116 @@ zero(Node *nr)
mpmovecflt(nc.val.u.fval, 0.0); mpmovecflt(nc.val.u.fval, 0.0);
gmove(&nc, nr); cgen(&nc, nr);
}
// generate code res = -nl
static void
minus(Node *nl, Node *res)
{
Node ra;
memset(&ra, 0, sizeof(ra));
ra.op = OMINUS;
ra.left = nl;
ra.type = nl->type;
cgen(&ra, res);
}
// 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);
// 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);
} }

View File

@ -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)

View File

@ -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)

View File

@ -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\

36
src/pkg/runtime/complex.c Normal file
View File

@ -0,0 +1,36 @@
// 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);
}

View File

@ -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

View File

@ -1,6 +1,6 @@
// 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.

View File

@ -1,6 +1,6 @@
// [ $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.

View File

@ -1,6 +1,6 @@
// [ $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.

View File

@ -1,6 +1,6 @@
// 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
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))

View File

@ -1,6 +1,6 @@
// 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.