Commit 458b53ea authored by Ken Thompson's avatar Ken Thompson

all done except -

complex divide
float(complex) conversion
8g 5g etc
tests

R=rsc
CC=golang-dev
https://golang.org/cl/218044
parent ed13d399
...@@ -4,20 +4,29 @@ ...@@ -4,20 +4,29 @@
#include "gg.h" #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)) #define CASE(a,b) (((a)<<16)|((b)<<0))
/* /*
* 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) complexmove(Node *f, Node *t, int perm)
{ {
int ft, tt; int ft, tt;
Node n1, n2; Node n1, n2, n3, n4, nc;
if(debug['g']) { if(1||debug['g']) {
dump("\ncomplex-f", f); dump("\ncomplex-f", f);
dump("complex-t", t); dump("complex-t", t);
} }
...@@ -25,55 +34,94 @@ complexmove(Node *f, Node *t) ...@@ -25,55 +34,94 @@ complexmove(Node *f, Node *t)
if(!t->addable) if(!t->addable)
fatal("to no addable"); fatal("to no addable");
ft = cplxsubtype(simsimtype(f->type)); ft = simsimtype(f->type);
tt = cplxsubtype(simsimtype(t->type)); tt = simsimtype(t->type);
switch(CASE(ft,tt)) {
// 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;
}
// make from addable default:
if(!f->addable) { fatal("complexmove: unknown conversion: %T -> %T\n",
tempname(&n1, f->type); f->type, t->type);
complexgen(f, &n1);
f = &n1;
}
// real part case CASE(TCOMPLEX64,TCOMPLEX64):
n1 = *f; case CASE(TCOMPLEX64,TCOMPLEX128):
n1.type = types[ft]; 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; subnode(&n1, &n2, f);
n2.type = types[tt]; 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 case CASE(TFLOAT32,TCOMPLEX64):
n1.xoffset += n1.type->width; case CASE(TFLOAT32,TCOMPLEX128):
n2.xoffset += n2.type->width; case CASE(TFLOAT64,TCOMPLEX64):
gmove(&n1, &n2); 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 void
complexgen(Node *n, Node *res) complexgen(Node *n, Node *res)
{ {
Node *nl, *nr; Node *nl, *nr;
Node n1, n2; Node n1, n2, n3, n4, n5, n6;
Node ra, rb, rc, rd;
int tl, tr; int tl, tr;
if(debug['g']) { if(1||debug['g']) {
dump("\ncomplex-n", n); dump("\ncomplex-n", n);
dump("complex-res", res); dump("complex-res", res);
} }
...@@ -84,42 +132,37 @@ complexgen(Node *n, Node *res) ...@@ -84,42 +132,37 @@ complexgen(Node *n, Node *res)
tr = simsimtype(n->type); tr = simsimtype(n->type);
tr = cplxsubtype(tr); tr = cplxsubtype(tr);
if(tl != tr) { if(tl != tr) {
tempname(&n1, n->type); if(!n->addable) {
complexgen(n, &n1); tempname(&n1, n->type);
complexmove(&n1, n); complexmove(n, &n1, 0);
n = &n1;
}
complexmove(n, res, 0);
return; return;
} }
nl = n->left; nl = n->left;
if(nl == N) if(nl == N)
return; return;
nr = n->right; nr = n->right;
// make both sides addable in ullman order
if(nr != N) { if(nr != N) {
// make both sides addable in ullman order if(nl->ullman > nr->ullman && !nl->addable) {
if(nl->ullman > nr->ullman) { tempname(&n1, nl->type);
if(!nl->addable) { complexgen(nl, &n1);
tempname(&n1, nl->type); nl = &n1;
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(!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) { switch(n->op) {
...@@ -127,21 +170,198 @@ complexgen(Node *n, Node *res) ...@@ -127,21 +170,198 @@ complexgen(Node *n, Node *res)
fatal("opcode %O", n->op); fatal("opcode %O", n->op);
break; 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 OADD:
case OSUB: 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 OMUL:
case ODIV: if(isimag1i(nr)) {
if(nr == N) complexmove(nl, res, 1);
fatal(""); break;
fatal("opcode %O", n->op); }
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; break;
case OMINUS: case ODIV:
if(isimag1i(nr)) {
complexmove(nl, res, 2);
break;
}
fatal("opcode %O", n->op); fatal("opcode %O", n->op);
break; }
}
case OCONV: int
complexmove(nl, res); cplxsubtype(int et)
break; {
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);
} }
...@@ -134,7 +134,7 @@ void nodfconst(Node*, Type*, Mpflt*); ...@@ -134,7 +134,7 @@ void nodfconst(Node*, Type*, Mpflt*);
/* /*
* cplx.c * cplx.c
*/ */
void complexmove(Node*, Node*); void complexmove(Node*, Node*, int);
void complexgen(Node*, Node*); void complexgen(Node*, Node*);
/* /*
......
...@@ -476,7 +476,7 @@ gmove(Node *f, Node *t) ...@@ -476,7 +476,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); complexmove(f, t, 0);
return; return;
} }
...@@ -495,7 +495,7 @@ gmove(Node *f, Node *t) ...@@ -495,7 +495,7 @@ gmove(Node *f, Node *t)
// float constants come from memory. // float constants come from memory.
if(isfloat[tt]) if(isfloat[tt])
goto hard; goto hard;
// complex constants take double move.
// 64-bit immediates are really 32-bit sign-extended // 64-bit immediates are really 32-bit sign-extended
// unless moving into a register. // unless moving into a register.
if(isint[tt]) { if(isint[tt]) {
...@@ -1979,29 +1979,3 @@ no: ...@@ -1979,29 +1979,3 @@ no:
sudoclean(); sudoclean();
return 0; 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);
}
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