summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2009-05-27 23:55:14 -0700
committerRuss Cox <rsc@golang.org>2009-05-27 23:55:14 -0700
commitf6f70933698bcfaa2f7fbed24dcc75784d80d5bb (patch)
tree7ec702ad1c80def016cbfd23ccaebc0fdbdf134a /src
parent7d3403fdf5d248c36b407fe33fd5408105d89e2b (diff)
downloadgolang-f6f70933698bcfaa2f7fbed24dcc75784d80d5bb.tar.gz
clean up gmove:
* conversions all in one place. * no separate load, store phases; direct memory addressing when possible (this is the x86 after all!). avoids extra registers, extra MOVQs. * fixes int32 -> uint64 bug (was zero-extending) R=ken OCL=29482 CL=29484
Diffstat (limited to 'src')
-rw-r--r--src/cmd/6g/cgen.c8
-rw-r--r--src/cmd/6g/ggen.c4
-rw-r--r--src/cmd/6g/gsubr.c815
-rw-r--r--src/cmd/gc/const.c92
-rw-r--r--src/cmd/gc/dcl.c2
-rw-r--r--src/cmd/gc/go.h8
-rw-r--r--src/cmd/gc/subr.c27
7 files changed, 459 insertions, 497 deletions
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index 1027f9076..5ac8b0f9c 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -201,8 +201,14 @@ cgen(Node *n, Node *res)
break;
}
regalloc(&n1, nl->type, res);
+ regalloc(&n2, n->type, &n1);
cgen(nl, &n1);
- gmove(&n1, res);
+ // if we do the conversion n1 -> n2 here
+ // reusing the register, then gmove won't
+ // have to allocate its own register.
+ gmove(&n1, &n2);
+ gmove(&n2, res);
+ regfree(&n2);
regfree(&n1);
break;
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index 6da512da1..06b0f8003 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -491,8 +491,10 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
t = types[TUINT32];
}
a = optoas(op, t);
+ ax->type = t;
+ dx->type = t;
- regalloc(&n3, nr->type, N);
+ regalloc(&n3, t, N);
if(nl->ullman >= nr->ullman) {
cgen(nl, ax);
if(!issigned[t->etype]) {
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index 0d9034f2c..d8bd0767f 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -411,575 +411,397 @@ gconreg(int as, vlong c, int reg)
#define CASE(a,b) (((a)<<16)|((b)<<0))
/*
- * generate move:
- * t = f
+ * Is this node a memory operand?
*/
-void
-gmove(Node *f, Node *t)
+int
+ismem(Node *n)
{
- int ft, tt, t64, a;
- Node nod, nod1, nod2, nod3, nodc;
- Prog *p1, *p2;
-
- ft = simtype[f->type->etype];
- tt = simtype[t->type->etype];
-
- t64 = 0;
- if(tt == TINT64 || tt == TUINT64 || tt == TPTR64)
- t64 = 1;
-
- if(debug['M'])
- print("gop: %O %O[%E],%O[%E]\n", OAS,
- f->op, ft, t->op, tt);
- if(isfloat[ft] && f->op == OCONST) {
- /* TO DO: pick up special constants, possibly preloaded */
- if(mpgetflt(f->val.u.fval) == 0.0) {
- regalloc(&nod, t->type, t);
- gins(AXORPD, &nod, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
- }
+ switch(n->op) {
+ case OINDREG:
+ case ONAME:
+ case OPARAM:
+ return 1;
}
+ return 0;
+}
+
/*
- * load
+ * set up nodes representing 2^63
*/
- if(f->op == ONAME || f->op == OINDREG ||
- f->op == OIND || f->op == OINDEX)
- switch(ft) {
- case TINT8:
- a = AMOVBLSX;
- if(t64)
- a = AMOVBQSX;
- goto ld;
- case TBOOL:
- case TUINT8:
- a = AMOVBLZX;
- if(t64)
- a = AMOVBQZX;
- goto ld;
- case TINT16:
- a = AMOVWLSX;
- if(t64)
- a = AMOVWQSX;
- goto ld;
- case TUINT16:
- a = AMOVWLZX;
- if(t64)
- a = AMOVWQZX;
- goto ld;
- case TINT32:
- if(isfloat[tt]) {
- regalloc(&nod, t->type, t);
- if(tt == TFLOAT64)
- a = ACVTSL2SD;
- else
- a = ACVTSL2SS;
- gins(a, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
- }
- a = AMOVL;
- if(t64)
- a = AMOVLQSX;
- goto ld;
- case TUINT32:
- case TPTR32:
- a = AMOVL;
- if(t64)
- a = AMOVLQZX;
- goto ld;
- case TINT64:
- if(isfloat[tt]) {
- regalloc(&nod, t->type, t);
- if(tt == TFLOAT64)
- a = ACVTSQ2SD;
- else
- a = ACVTSQ2SS;
- gins(a, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
- }
- case TUINT64:
- case TPTR64:
- a = AMOVQ;
+Node bigi;
+Node bigf;
- ld:
- regalloc(&nod, f->type, t);
- nod.type = t64? types[TINT64]: types[TINT32];
- gins(a, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
+void
+bignodes(void)
+{
+ static int did;
- case TFLOAT32:
- a = AMOVSS;
- goto fld;
- case TFLOAT64:
- a = AMOVSD;
- fld:
- regalloc(&nod, f->type, t);
- if(tt != TFLOAT64 && tt != TFLOAT32){ /* TO DO: why is this here */
- dump("odd tree", f);
- nod.type = t64? types[TINT64]: types[TINT32];
- }
- gins(a, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
+ if(did)
return;
- }
+ did = 1;
-/*
- * store
- */
- if(t->op == ONAME || t->op == OINDREG ||
- t->op == OIND || t->op == OINDEX)
- switch(tt) {
- case TBOOL:
- case TINT8:
- case TUINT8:
- a = AMOVB;
- goto st;
- case TINT16:
- case TUINT16:
- a = AMOVW;
- goto st;
- case TINT32:
- case TUINT32:
- a = AMOVL;
- goto st;
- case TINT64:
- case TUINT64:
- a = AMOVQ;
- goto st;
+ nodconst(&bigi, types[TUINT64], 1);
+ mpshiftfix(bigi.val.u.xval, 63);
- case TPTR32:
- case TPTR64:
- /*
- * store to pointer.
- */
- if(tt == TPTR32)
- a = AMOVL;
- else
- a = AMOVQ;
- switch(t->op) {
- default:
- dump("gmove to", t);
- fatal("gmove t %O", t->op);
+ bigf = bigi;
+ bigf.type = types[TFLOAT64];
+ bigf.val.ctype = CTFLT;
+ bigf.val.u.fval = mal(sizeof *bigf.val.u.fval);
+ mpmovefixflt(bigf.val.u.fval, bigi.val.u.xval);
+}
- case OINDREG:
- if(t->val.u.reg != D_SP)
- goto refcount;
- break;
+/*
+ * generate move:
+ * t = f
+ * hard part is conversions.
+ */
+void
+gmove(Node *f, Node *t)
+{
+ int a, ft, tt;
+ Type *cvt;
+ Node r1, r2, r3, r4, zero, one, con;
+ Prog *p1, *p2;
- case ONAME:
- switch(t->class) {
- default:
- dump("gmove", t);
- fatal("gmove t %O class %d reg %R", t->op, t->class, t->val.u.reg);
- case PEXTERN:
- goto refcount;
- break;
- case PAUTO:
- case PPARAM:
- case PPARAMOUT:
- break;
+ if(debug['M'])
+ print("gmove %N -> %N\n", f, t);
+
+ ft = simsimtype(f->type);
+ tt = simsimtype(t->type);
+ cvt = t->type;
+
+ // cannot have two memory operands
+ if(ismem(f) && ismem(t))
+ goto hard;
+
+ // convert constant to desired type
+ if(f->op == OLITERAL) {
+ convconst(&con, t->type, &f->val);
+ f = &con;
+ ft = tt; // so big switch will choose a simple mov
+
+ // some constants can't move directly to memory.
+ if(ismem(t)) {
+ // float constants come from memory.
+ if(isfloat[tt])
+ goto hard;
+ // 64-bit immediates are really 32-bit sign-extended
+ // unless moving into a register.
+ if(isint[tt]) {
+ if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0)
+ goto hard;
+ if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0)
+ goto hard;
}
- break;
- }
- goto st;
-
- st:
- // 64-bit immediates only allowed for move into registers.
- // this is not a move into a register.
- if(f->op == OCONST || (f->op == OLITERAL && !t64)) {
- gins(a, f, t);
- return;
}
- fst:
- regalloc(&nod, t->type, f);
- gmove(f, &nod);
- gins(a, &nod, t);
- regfree(&nod);
- return;
-
- refcount:
- if(!debug['r'])
- goto st;
- // for now, mark ref count updates with AXCHGQ.
- // using a temporary on the left, so no semantic
- // changes. code is likely slower, but still correct.
- if(t64)
- a = AXCHGQ;
- else
- a = AXCHGL;
- regalloc(&nod, t->type, f);
- gmove(f, &nod);
- gins(a, &nod, t);
- regfree(&nod);
- return;
-
- case TFLOAT32:
- a = AMOVSS;
- goto fst;
- case TFLOAT64:
- a = AMOVSD;
- goto fst;
}
-/*
- * convert
- */
+ // value -> value copy, only one memory operand.
+ // figure out the instruction to use.
+ // break out of switch for one-instruction gins.
+ // goto rdst for "destination must be register".
+ // goto hard for "convert to cvt type first".
+ // otherwise handle and return.
+
switch(CASE(ft, tt)) {
default:
-/*
- * integer to integer
- ********
- * a = AGOK; break;
-
- * case CASE(TBOOL, TBOOL):
- * case CASE(TINT8, TBOOL):
- * case CASE(TUINT8, TBOOL):
- * case CASE(TINT16, TBOOL):
- * case CASE(TUINT16, TBOOL):
- * case CASE(TINT32, TBOOL):
- * case CASE(TUINT32, TBOOL):
- * case CASE(TPTR64, TBOOL):
-
- * case CASE(TBOOL, TINT8):
- * case CASE(TINT8, TINT8):
- * case CASE(TUINT8, TINT8):
- * case CASE(TINT16, TINT8):
- * case CASE(TUINT16, TINT8):
- * case CASE(TINT32, TINT8):
- * case CASE(TUINT32, TINT8):
- * case CASE(TPTR64, TINT8):
-
- * case CASE(TBOOL, TUINT8):
- * case CASE(TINT8, TUINT8):
- * case CASE(TUINT8, TUINT8):
- * case CASE(TINT16, TUINT8):
- * case CASE(TUINT16, TUINT8):
- * case CASE(TINT32, TUINT8):
- * case CASE(TUINT32, TUINT8):
- * case CASE(TPTR64, TUINT8):
-
- * case CASE(TINT16, TINT16):
- * case CASE(TUINT16, TINT16):
- * case CASE(TINT32, TINT16):
- * case CASE(TUINT32, TINT16):
- * case CASE(TPTR64, TINT16):
-
- * case CASE(TINT16, TUINT16):
- * case CASE(TUINT16, TUINT16):
- * case CASE(TINT32, TUINT16):
- * case CASE(TUINT32, TUINT16):
- * case CASE(TPTR64, TUINT16):
-
- * case CASE(TINT64, TUINT):
- * case CASE(TINT64, TUINT32):
- * case CASE(TUINT64, TUINT32):
- *****/
- a = AMOVL;
- break;
-
+ fatal("gmove %T -> %T", f, t);
+
+ /*
+ * integer copy and truncate
+ */
+ case CASE(TINT8, TINT8): // same size
+ case CASE(TINT8, TUINT8):
+ case CASE(TUINT8, TINT8):
+ case CASE(TUINT8, TUINT8):
+ case CASE(TINT16, TINT8): // truncate
+ case CASE(TUINT16, TINT8):
+ case CASE(TINT32, TINT8):
+ case CASE(TUINT32, TINT8):
case CASE(TINT64, TINT8):
- case CASE(TINT64, TINT16):
- case CASE(TINT64, TINT32):
case CASE(TUINT64, TINT8):
- case CASE(TUINT64, TINT16):
- case CASE(TUINT64, TINT32):
- a = AMOVLQSX; // this looks bad
+ case CASE(TINT16, TUINT8):
+ case CASE(TUINT16, TUINT8):
+ case CASE(TINT32, TUINT8):
+ case CASE(TUINT32, TUINT8):
+ case CASE(TINT64, TUINT8):
+ case CASE(TUINT64, TUINT8):
+ a = AMOVB;
break;
- case CASE(TINT32, TINT64):
- case CASE(TINT32, TPTR64):
- a = AMOVLQSX;
+ case CASE(TINT16, TINT16): // same size
+ case CASE(TINT16, TUINT16):
+ case CASE(TUINT16, TINT16):
+ case CASE(TUINT16, TUINT16):
+ case CASE(TINT32, TINT16): // truncate
+ case CASE(TUINT32, TINT16):
+ case CASE(TINT64, TINT16):
+ case CASE(TUINT64, TINT16):
+ case CASE(TINT32, TUINT16):
+ case CASE(TUINT32, TUINT16):
+ case CASE(TINT64, TUINT16):
+ case CASE(TUINT64, TUINT16):
+ a = AMOVW;
break;
- case CASE(TUINT32, TINT64):
- case CASE(TUINT32, TUINT64):
- case CASE(TUINT32, TPTR64):
- case CASE(TPTR32, TINT64):
- case CASE(TPTR32, TUINT64):
- case CASE(TPTR32, TPTR64):
- a = AMOVLQZX;
+ case CASE(TINT32, TINT32): // same size
+ case CASE(TINT32, TUINT32):
+ case CASE(TUINT32, TINT32):
+ case CASE(TUINT32, TUINT32):
+ case CASE(TINT64, TINT32): // truncate
+ case CASE(TUINT64, TINT32):
+ case CASE(TINT64, TUINT32):
+ case CASE(TUINT64, TUINT32):
+ a = AMOVL;
break;
- case CASE(TPTR64, TINT64):
- case CASE(TINT64, TINT64):
- case CASE(TUINT64, TINT64):
+ case CASE(TINT64, TINT64): // same size
case CASE(TINT64, TUINT64):
+ case CASE(TUINT64, TINT64):
case CASE(TUINT64, TUINT64):
- case CASE(TPTR64, TUINT64):
- case CASE(TINT64, TPTR64):
- case CASE(TUINT64, TPTR64):
- case CASE(TPTR64, TPTR64):
a = AMOVQ;
break;
- case CASE(TINT16, TINT32):
- case CASE(TINT16, TUINT32):
- a = AMOVWLSX;
-// if(f->op == OCONST) {
-// f->val.vval &= 0xffff;
-// if(f->val.vval & 0x8000)
-// f->val.vval |= 0xffff0000;
-// a = AMOVL;
-// }
- break;
-
- case CASE(TINT16, TINT64):
- case CASE(TINT16, TUINT64):
- case CASE(TINT16, TPTR64):
- a = AMOVWQSX;
-// if(f->op == OCONST) {
-// f->val.vval &= 0xffff;
-// if(f->val.vval & 0x8000){
-// f->val.vval |= 0xffff0000;
-// f->val.vval |= (vlong)~0 << 32;
-// }
-// a = AMOVL;
-// }
- break;
-
- case CASE(TUINT16, TINT32):
- case CASE(TUINT16, TUINT32):
- a = AMOVWLZX;
-// if(f->op == OCONST) {
-// f->val.vval &= 0xffff;
-// a = AMOVL;
-// }
- break;
-
- case CASE(TUINT16, TINT64):
- case CASE(TUINT16, TUINT64):
- case CASE(TUINT16, TPTR64):
- a = AMOVWQZX;
-// if(f->op == OCONST) {
-// f->val.vval &= 0xffff;
-// a = AMOVL; /* MOVL also zero-extends to 64 bits */
-// }
- break;
-
- case CASE(TINT8, TINT16):
+ /*
+ * integer up-conversions
+ */
+ case CASE(TINT8, TINT16): // sign extend int8
case CASE(TINT8, TUINT16):
+ a = AMOVBWSX;
+ goto rdst;
case CASE(TINT8, TINT32):
case CASE(TINT8, TUINT32):
a = AMOVBLSX;
-// if(f->op == OCONST) {
-// f->val.vval &= 0xff;
-// if(f->val.vval & 0x80)
-// f->val.vval |= 0xffffff00;
-// a = AMOVL;
-// }
- break;
-
+ goto rdst;
case CASE(TINT8, TINT64):
case CASE(TINT8, TUINT64):
- case CASE(TINT8, TPTR64):
a = AMOVBQSX;
-// if(f->op == OCONST) {
-// f->val.vval &= 0xff;
-// if(f->val.vval & 0x80){
-// f->val.vval |= 0xffffff00;
-// f->val.vval |= (vlong)~0 << 32;
-// }
-// a = AMOVQ;
-// }
- break;
+ goto rdst;
- case CASE(TBOOL, TINT16):
- case CASE(TBOOL, TUINT16):
- case CASE(TBOOL, TINT32):
- case CASE(TBOOL, TUINT32):
- case CASE(TUINT8, TINT16):
+ case CASE(TUINT8, TINT16): // zero extend uint8
case CASE(TUINT8, TUINT16):
+ a = AMOVBWZX;
+ goto rdst;
case CASE(TUINT8, TINT32):
case CASE(TUINT8, TUINT32):
a = AMOVBLZX;
-// if(f->op == OCONST) {
-// f->val.vval &= 0xff;
-// a = AMOVL;
-// }
- break;
-
- case CASE(TBOOL, TINT64):
- case CASE(TBOOL, TUINT64):
- case CASE(TBOOL, TPTR64):
+ goto rdst;
case CASE(TUINT8, TINT64):
case CASE(TUINT8, TUINT64):
- case CASE(TUINT8, TPTR64):
a = AMOVBQZX;
-// if(f->op == OCONST) {
-// f->val.vval &= 0xff;
-// a = AMOVL; /* zero-extends to 64-bits */
-// }
- break;
+ goto rdst;
-/*
- * float to fix
- */
- case CASE(TFLOAT32, TINT8):
- case CASE(TFLOAT32, TINT16):
+ case CASE(TINT16, TINT32): // sign extend int16
+ case CASE(TINT16, TUINT32):
+ a = AMOVWLSX;
+ goto rdst;
+ case CASE(TINT16, TINT64):
+ case CASE(TINT16, TUINT64):
+ a = AMOVWQSX;
+ goto rdst;
+
+ case CASE(TUINT16, TINT32): // zero extend uint16
+ case CASE(TUINT16, TUINT32):
+ a = AMOVWLZX;
+ goto rdst;
+ case CASE(TUINT16, TINT64):
+ case CASE(TUINT16, TUINT64):
+ a = AMOVWQZX;
+ goto rdst;
+
+ case CASE(TINT32, TINT64): // sign extend int32
+ case CASE(TINT32, TUINT64):
+ a = AMOVLQSX;
+ goto rdst;
+
+ case CASE(TUINT32, TINT64): // zero extend uint32
+ case CASE(TUINT32, TUINT64):
+ // AMOVL into a register zeros the top of the register,
+ // so this is not always necessary, but if we rely on AMOVL
+ // the optimizer is almost certain to screw with us.
+ a = AMOVLQZX;
+ goto rdst;
+
+ /*
+ * float to integer
+ */
case CASE(TFLOAT32, TINT32):
- regalloc(&nod, t->type, N);
- gins(ACVTTSS2SL, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
+ a = ACVTTSS2SL;
+ goto rdst;
+
+ case CASE(TFLOAT64, TINT32):
+ a = ACVTTSD2SL;
+ goto rdst;
- case CASE(TFLOAT32, TBOOL):
- case CASE(TFLOAT32, TUINT8):
- case CASE(TFLOAT32, TUINT16):
- case CASE(TFLOAT32, TUINT32):
case CASE(TFLOAT32, TINT64):
- case CASE(TFLOAT32, TUINT64):
- case CASE(TFLOAT32, TPTR64):
- regalloc(&nod, t->type, N);
- gins(ACVTTSS2SQ, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
+ a = ACVTTSS2SQ;
+ goto rdst;
- case CASE(TFLOAT64, TINT8):
- case CASE(TFLOAT64, TINT16):
- case CASE(TFLOAT64, TINT32):
- regalloc(&nod, t->type, N);
- gins(ACVTTSD2SL, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
+ case CASE(TFLOAT64, TINT64):
+ a = ACVTTSD2SQ;
+ goto rdst;
- case CASE(TFLOAT64, TBOOL):
- case CASE(TFLOAT64, TUINT8):
+ case CASE(TFLOAT32, TINT16):
+ case CASE(TFLOAT32, TINT8):
+ case CASE(TFLOAT32, TUINT16):
+ case CASE(TFLOAT32, TUINT8):
+ case CASE(TFLOAT64, TINT16):
+ case CASE(TFLOAT64, TINT8):
case CASE(TFLOAT64, TUINT16):
+ case CASE(TFLOAT64, TUINT8):
+ // convert via int32.
+ cvt = types[TINT32];
+ goto hard;
+
+ case CASE(TFLOAT32, TUINT32):
case CASE(TFLOAT64, TUINT32):
- case CASE(TFLOAT64, TINT64):
- case CASE(TFLOAT64, TUINT64):
- case CASE(TFLOAT64, TPTR64):
- regalloc(&nod, t->type, N);
- gins(ACVTTSD2SQ, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
+ // convert via int64.
+ cvt = types[TINT64];
+ goto hard;
-/*
- * uvlong to float
- */
- case CASE(TUINT64, TFLOAT64):
- case CASE(TUINT64, TFLOAT32):
- a = ACVTSQ2SS;
- if(tt == TFLOAT64)
- a = ACVTSQ2SD;
- regalloc(&nod, f->type, f);
- gmove(f, &nod);
- regalloc(&nod1, t->type, t);
- nodconst(&nodc, types[TUINT64], 0);
- gins(ACMPQ, &nod, &nodc);
- p1 = gbranch(AJLT, T);
- gins(a, &nod, &nod1);
+ case CASE(TFLOAT32, TUINT64):
+ case CASE(TFLOAT64, TUINT64):
+ // algorithm is:
+ // if small enough, use native float64 -> int64 conversion.
+ // otherwise, subtract 2^63, convert, and add it back.
+ a = ACVTSS2SQ;
+ if(ft == TFLOAT64)
+ a = ACVTSD2SQ;
+ bignodes();
+ regalloc(&r1, types[ft], N);
+ regalloc(&r2, types[tt], t);
+ regalloc(&r3, types[ft], N);
+ regalloc(&r4, types[tt], N);
+ gins(optoas(OAS, f->type), f, &r1);
+ gins(optoas(OCMP, f->type), &bigf, &r1);
+ p1 = gbranch(optoas(OLE, f->type), T);
+ gins(a, &r1, &r2);
p2 = gbranch(AJMP, T);
patch(p1, pc);
- regalloc(&nod2, f->type, N);
- regalloc(&nod3, f->type, N);
- gmove(&nod, &nod2);
- nodconst(&nodc, types[TUINT64], 1);
- gins(ASHRQ, &nodc, &nod2);
- gmove(&nod, &nod3);
- gins(AANDL, &nodc, &nod3);
- gins(AORQ, &nod3, &nod2);
- gins(a, &nod2, &nod1);
- gins(tt == TFLOAT64? AADDSD: AADDSS, &nod1, &nod1);
- regfree(&nod2);
- regfree(&nod3);
+ gins(optoas(OAS, f->type), &bigf, &r3);
+ gins(optoas(OSUB, f->type), &r3, &r1);
+ gins(a, &r1, &r2);
+ gins(AMOVQ, &bigi, &r4);
+ gins(AXORQ, &r4, &r2);
patch(p2, pc);
- regfree(&nod);
- regfree(&nod1);
+ gmove(&r2, t);
+ regfree(&r4);
+ regfree(&r3);
+ regfree(&r2);
+ regfree(&r1);
return;
- case CASE(TUINT32, TFLOAT64):
- case CASE(TUINT32, TFLOAT32):
- a = ACVTSQ2SS;
- if(tt == TFLOAT64)
- a = ACVTSQ2SD;
- regalloc(&nod, f->type, f);
- gins(AMOVLQZX, f, &nod);
- regalloc(&nod1, t->type, t);
- gins(a, &nod, &nod1);
- gmove(&nod1, t);
- regfree(&nod);
- regfree(&nod1);
- return;
+ /*
+ * integer to float
+ */
+ case CASE(TINT32, TFLOAT32):
+ a = ACVTSL2SS;
+ goto rdst;
+
+
+ case CASE(TINT32, TFLOAT64):
+ a = ACVTSL2SD;
+ goto rdst;
-/*
- * fix to float
- */
case CASE(TINT64, TFLOAT32):
- case CASE(TPTR64, TFLOAT32):
- regalloc(&nod, t->type, t);
- gins(ACVTSQ2SS, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
+ a = ACVTSQ2SS;
+ goto rdst;
case CASE(TINT64, TFLOAT64):
- case CASE(TPTR64, TFLOAT64):
- regalloc(&nod, t->type, t);
- gins(ACVTSQ2SD, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
+ a = ACVTSQ2SD;
+ goto rdst;
- case CASE(TBOOL, TFLOAT32):
- case CASE(TINT8, TFLOAT32):
- case CASE(TUINT8, TFLOAT32):
case CASE(TINT16, TFLOAT32):
- case CASE(TUINT16, TFLOAT32):
- case CASE(TINT32, TFLOAT32):
- regalloc(&nod, t->type, t);
- gins(ACVTSL2SS, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
- return;
-
- case CASE(TBOOL, TFLOAT64):
- case CASE(TINT8, TFLOAT64):
- case CASE(TUINT8, TFLOAT64):
case CASE(TINT16, TFLOAT64):
+ case CASE(TINT8, TFLOAT32):
+ case CASE(TINT8, TFLOAT64):
+ case CASE(TUINT16, TFLOAT32):
case CASE(TUINT16, TFLOAT64):
- case CASE(TINT32, TFLOAT64):
- regalloc(&nod, t->type, t);
- gins(ACVTSL2SD, f, &nod);
- gmove(&nod, t);
- regfree(&nod);
+ case CASE(TUINT8, TFLOAT32):
+ case CASE(TUINT8, TFLOAT64):
+ // convert via int32
+ cvt = types[TINT32];
+ goto hard;
+
+ case CASE(TUINT32, TFLOAT32):
+ case CASE(TUINT32, TFLOAT64):
+ // convert via int64.
+ cvt = types[TINT64];
+ goto hard;
+
+ case CASE(TUINT64, TFLOAT32):
+ case CASE(TUINT64, TFLOAT64):
+ // algorithm is:
+ // if small enough, use native int64 -> uint64 conversion.
+ // otherwise, halve (rounding to odd?), convert, and double.
+ a = ACVTSQ2SS;
+ if(tt == TFLOAT64)
+ a = ACVTSQ2SD;
+ nodconst(&zero, types[TUINT64], 0);
+ nodconst(&one, types[TUINT64], 1);
+ regalloc(&r1, f->type, f);
+ regalloc(&r2, t->type, t);
+ regalloc(&r3, f->type, N);
+ regalloc(&r4, f->type, N);
+ gmove(f, &r1);
+ gins(ACMPQ, &r1, &zero);
+ p1 = gbranch(AJLT, T);
+ gins(a, &r1, &r2);
+ p2 = gbranch(AJMP, T);
+ patch(p1, pc);
+ gmove(&r1, &r3);
+ gins(ASHRQ, &one, &r3);
+ gmove(&r1, &r4);
+ gins(AANDL, &one, &r4);
+ gins(AORQ, &r4, &r3);
+ gins(a, &r3, &r2);
+ gins(optoas(OADD, t->type), &r2, &r2);
+ patch(p2, pc);
+ gmove(&r2, t);
+ regfree(&r4);
+ regfree(&r3);
+ regfree(&r2);
+ regfree(&r1);
return;
-/*
- * float to float
- */
+ /*
+ * float to float
+ */
case CASE(TFLOAT32, TFLOAT32):
a = AMOVSS;
break;
- case CASE(TFLOAT64, TFLOAT32):
- a = ACVTSD2SS;
- break;
- case CASE(TFLOAT32, TFLOAT64):
- a = ACVTSS2SD;
- break;
+
case CASE(TFLOAT64, TFLOAT64):
a = AMOVSD;
break;
+
+ case CASE(TFLOAT32, TFLOAT64):
+ a = ACVTSS2SD;
+ goto rdst;
+
+ case CASE(TFLOAT64, TFLOAT32):
+ a = ACVTSD2SS;
+ goto rdst;
}
- if(a == AMOVQ ||
- a == AMOVSD ||
- a == AMOVSS ||
- (a == AMOVL && f->type->width == t->type->width)) /* TO DO: check AMOVL */
- if(samaddr(f, t))
- return;
+
gins(a, f, t);
+ return;
+
+rdst:
+ // requires register destination
+ regalloc(&r1, t->type, t);
+ gins(a, f, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
+
+hard:
+ // requires register intermediate
+ regalloc(&r1, cvt, t);
+ gmove(f, &r1);
+ gmove(&r1, t);
+ regfree(&r1);
+ return;
}
int
@@ -1026,6 +848,17 @@ gins(int as, Node *f, Node *t)
// regfree(&nod);
// }
+ switch(as) {
+ case AMOVB:
+ case AMOVW:
+ case AMOVL:
+ case AMOVQ:
+ case AMOVSS:
+ case AMOVSD:
+ if(f != N && t != N && samaddr(f, t))
+ return nil;
+ }
+
p = prog(as);
if(f != N)
naddr(f, &p->from);
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index 33acec6fc..72cf684ad 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -801,3 +801,95 @@ nonnegconst(Node *n)
}
return -1;
}
+
+/*
+ * convert x to type et and back to int64
+ * for sign extension and truncation.
+ */
+int64
+iconv(int64 x, int et)
+{
+ switch(et) {
+ case TINT8:
+ x = (int8)x;
+ break;
+ case TUINT8:
+ x = (uint8)x;
+ break;
+ case TINT16:
+ x = (int16)x;
+ break;
+ case TUINT16:
+ x = (uint64)x;
+ break;
+ case TINT32:
+ x = (int32)x;
+ break;
+ case TUINT32:
+ x = (uint32)x;
+ break;
+ case TINT64:
+ case TUINT64:
+ break;
+ }
+ return x;
+}
+
+/*
+ * convert constant val to type t; leave in con.
+ * for back end.
+ */
+void
+convconst(Node *con, Type *t, Val *val)
+{
+ int64 i;
+ int tt;
+
+ tt = simsimtype(t);
+
+ // copy the constant for conversion
+ nodconst(con, types[TINT8], 0);
+ con->type = t;
+ con->val = *val;
+
+ if(isint[tt]) {
+ con->val.ctype = CTINT;
+ con->val.u.xval = mal(sizeof *con->val.u.xval);
+ switch(val->ctype) {
+ default:
+ fatal("convconst ctype=%d %lT", val->ctype, t->type);
+ case CTINT:
+ i = mpgetfix(val->u.xval);
+ break;
+ case CTBOOL:
+ i = val->u.bval;
+ break;
+ case CTNIL:
+ i = 0;
+ break;
+ }
+ i = iconv(i, tt);
+ mpmovecfix(con->val.u.xval, i);
+ return;
+ }
+
+ if(isfloat[tt]) {
+ if(con->val.ctype == CTINT) {
+ con->val.ctype = CTFLT;
+ con->val.u.fval = mal(sizeof *con->val.u.fval);
+ mpmovefixflt(con->val.u.fval, val->u.xval);
+ }
+ if(con->val.ctype != CTFLT)
+ fatal("convconst ctype=%d %T", con->val.ctype, t);
+ if(!isfloat[tt]) {
+ // easy to handle, but can it happen?
+ fatal("convconst CTINT %T", t);
+ }
+ if(tt == TFLOAT32)
+ con->val.u.fval = truncfltlit(con->val.u.fval, t);
+ return;
+ }
+
+ fatal("convconst %lT constant", t);
+
+}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index e4d1a0455..6068651b8 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -1061,7 +1061,7 @@ addconst(Node *n, Node *e, int ctxt)
d = dcl();
d->dsym = s;
d->dnode = e;
- d->op = OCONST;
+ d->op = OLITERAL;
d->back = r->back;
r->back->forw = d;
r->back = d;
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index eb253d778..5abdfcce0 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -298,7 +298,7 @@ enum
{
OXXX,
- OTYPE, OCONST, OVAR, OIMPORT,
+ OTYPE, OVAR, OIMPORT,
ONAME, ONONAME, ODCL,
ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
@@ -315,7 +315,7 @@ enum
OEQ, ONE, OLT, OLE, OGE, OGT,
OADD, OSUB, OOR, OXOR,
OMUL, ODIV, OMOD, OLSH, ORSH, OAND, OANDNOT,
- OINC, ODEC, // placeholders - not used
+ OINC, ODEC,
OFUNC,
OLABEL,
OBREAK,
@@ -795,6 +795,8 @@ Node* adddot(Node*);
void expandmeth(Sym*, Type*);
void genwrapper(Type*, Type*, Sym*);
+int simsimtype(Type*);
+
/*
* dcl.c
*/
@@ -949,6 +951,8 @@ int smallintconst(Node*);
long nonnegconst(Node*);
int consttype(Node*);
int isconst(Node*, int);
+Mpflt* truncfltlit(Mpflt*, Type*);
+void convconst(Node*, Type*, Val*);
/*
* align.c
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index de32c8e6d..dcaa11a00 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -671,7 +671,6 @@ opnames[] =
[OCOMPOS] = "COMPOS",
[OCOMPSLICE] = "COMPSLICE",
[OCOM] = "COM",
- [OCONST] = "CONST",
[OCONTINUE] = "CONTINUE",
[OCONV] = "CONV",
[ODCLARG] = "DCLARG",
@@ -3015,3 +3014,29 @@ runifacechecks(void)
}
lineno = lno;
}
+
+/*
+ * even simpler simtype; get rid of ptr, bool.
+ * assuming that the front end has rejected
+ * all the invalid conversions (like ptr -> bool)
+ */
+int
+simsimtype(Type *t)
+{
+ int et;
+
+ et = simtype[t->etype];
+ switch(et) {
+ case TPTR32:
+ et = TUINT32;
+ break;
+ case TPTR64:
+ et = TUINT64;
+ break;
+ case TBOOL:
+ et = TUINT8;
+ break;
+ }
+ return et;
+}
+