Commit e81d97ea authored by Russ Cox's avatar Russ Cox

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
parent b3f303ec
...@@ -201,8 +201,14 @@ cgen(Node *n, Node *res) ...@@ -201,8 +201,14 @@ cgen(Node *n, Node *res)
break; break;
} }
regalloc(&n1, nl->type, res); regalloc(&n1, nl->type, res);
regalloc(&n2, n->type, &n1);
cgen(nl, &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); regfree(&n1);
break; break;
......
...@@ -491,8 +491,10 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx) ...@@ -491,8 +491,10 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
t = types[TUINT32]; t = types[TUINT32];
} }
a = optoas(op, t); a = optoas(op, t);
ax->type = t;
dx->type = t;
regalloc(&n3, nr->type, N); regalloc(&n3, t, N);
if(nl->ullman >= nr->ullman) { if(nl->ullman >= nr->ullman) {
cgen(nl, ax); cgen(nl, ax);
if(!issigned[t->etype]) { if(!issigned[t->etype]) {
......
...@@ -411,575 +411,397 @@ gconreg(int as, vlong c, int reg) ...@@ -411,575 +411,397 @@ gconreg(int as, vlong c, int reg)
#define CASE(a,b) (((a)<<16)|((b)<<0)) #define CASE(a,b) (((a)<<16)|((b)<<0))
/* /*
* generate move: * Is this node a memory operand?
* t = f
*/ */
void int
gmove(Node *f, Node *t) ismem(Node *n)
{ {
int ft, tt, t64, a; switch(n->op) {
Node nod, nod1, nod2, nod3, nodc; case OINDREG:
Prog *p1, *p2; case ONAME:
case OPARAM:
ft = simtype[f->type->etype]; return 1;
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;
}
} }
return 0;
}
/* /*
* load * set up nodes representing 2^63
*/ */
if(f->op == ONAME || f->op == OINDREG || Node bigi;
f->op == OIND || f->op == OINDEX) Node bigf;
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;
ld: void
regalloc(&nod, f->type, t); bignodes(void)
nod.type = t64? types[TINT64]: types[TINT32]; {
gins(a, f, &nod); static int did;
gmove(&nod, t);
regfree(&nod);
return;
case TFLOAT32: if(did)
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);
return; return;
} did = 1;
/* nodconst(&bigi, types[TUINT64], 1);
* store mpshiftfix(bigi.val.u.xval, 63);
*/
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;
case TPTR32: bigf = bigi;
case TPTR64: bigf.type = types[TFLOAT64];
/* bigf.val.ctype = CTFLT;
* store to pointer. bigf.val.u.fval = mal(sizeof *bigf.val.u.fval);
*/ mpmovefixflt(bigf.val.u.fval, bigi.val.u.xval);
if(tt == TPTR32) }
a = AMOVL;
else
a = AMOVQ;
switch(t->op) {
default:
dump("gmove to", t);
fatal("gmove t %O", t->op);
case OINDREG: /*
if(t->val.u.reg != D_SP) * generate move:
goto refcount; * t = f
break; * 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: if(debug['M'])
switch(t->class) { print("gmove %N -> %N\n", f, t);
default:
dump("gmove", t); ft = simsimtype(f->type);
fatal("gmove t %O class %d reg %R", t->op, t->class, t->val.u.reg); tt = simsimtype(t->type);
case PEXTERN: cvt = t->type;
goto refcount;
break; // cannot have two memory operands
case PAUTO: if(ismem(f) && ismem(t))
case PPARAM: goto hard;
case PPARAMOUT:
break; // 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;
} }
/* // value -> value copy, only one memory operand.
* convert // 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)) { switch(CASE(ft, tt)) {
default: default:
/* fatal("gmove %T -> %T", f, t);
* integer to integer
******** /*
* a = AGOK; break; * integer copy and truncate
*/
* case CASE(TBOOL, TBOOL): case CASE(TINT8, TINT8): // same size
* case CASE(TINT8, TBOOL): case CASE(TINT8, TUINT8):
* case CASE(TUINT8, TBOOL): case CASE(TUINT8, TINT8):
* case CASE(TINT16, TBOOL): case CASE(TUINT8, TUINT8):
* case CASE(TUINT16, TBOOL): case CASE(TINT16, TINT8): // truncate
* case CASE(TINT32, TBOOL): case CASE(TUINT16, TINT8):
* case CASE(TUINT32, TBOOL): case CASE(TINT32, TINT8):
* case CASE(TPTR64, TBOOL): case CASE(TUINT32, TINT8):
* 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;
case CASE(TINT64, TINT8): case CASE(TINT64, TINT8):
case CASE(TINT64, TINT16):
case CASE(TINT64, TINT32):
case CASE(TUINT64, TINT8): case CASE(TUINT64, TINT8):
case CASE(TUINT64, TINT16): case CASE(TINT16, TUINT8):
case CASE(TUINT64, TINT32): case CASE(TUINT16, TUINT8):
a = AMOVLQSX; // this looks bad case CASE(TINT32, TUINT8):
case CASE(TUINT32, TUINT8):
case CASE(TINT64, TUINT8):
case CASE(TUINT64, TUINT8):
a = AMOVB;
break; break;
case CASE(TINT32, TINT64): case CASE(TINT16, TINT16): // same size
case CASE(TINT32, TPTR64): case CASE(TINT16, TUINT16):
a = AMOVLQSX; 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; break;
case CASE(TUINT32, TINT64): case CASE(TINT32, TINT32): // same size
case CASE(TUINT32, TUINT64): case CASE(TINT32, TUINT32):
case CASE(TUINT32, TPTR64): case CASE(TUINT32, TINT32):
case CASE(TPTR32, TINT64): case CASE(TUINT32, TUINT32):
case CASE(TPTR32, TUINT64): case CASE(TINT64, TINT32): // truncate
case CASE(TPTR32, TPTR64): case CASE(TUINT64, TINT32):
a = AMOVLQZX; case CASE(TINT64, TUINT32):
case CASE(TUINT64, TUINT32):
a = AMOVL;
break; break;
case CASE(TPTR64, TINT64): case CASE(TINT64, TINT64): // same size
case CASE(TINT64, TINT64):
case CASE(TUINT64, TINT64):
case CASE(TINT64, TUINT64): case CASE(TINT64, TUINT64):
case CASE(TUINT64, TINT64):
case CASE(TUINT64, TUINT64): case CASE(TUINT64, TUINT64):
case CASE(TPTR64, TUINT64):
case CASE(TINT64, TPTR64):
case CASE(TUINT64, TPTR64):
case CASE(TPTR64, TPTR64):
a = AMOVQ; a = AMOVQ;
break; break;
case CASE(TINT16, TINT32): /*
case CASE(TINT16, TUINT32): * integer up-conversions
a = AMOVWLSX; */
// if(f->op == OCONST) { case CASE(TINT8, TINT16): // sign extend int8
// 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):
case CASE(TINT8, TUINT16): case CASE(TINT8, TUINT16):
a = AMOVBWSX;
goto rdst;
case CASE(TINT8, TINT32): case CASE(TINT8, TINT32):
case CASE(TINT8, TUINT32): case CASE(TINT8, TUINT32):
a = AMOVBLSX; a = AMOVBLSX;
// if(f->op == OCONST) { goto rdst;
// f->val.vval &= 0xff;
// if(f->val.vval & 0x80)
// f->val.vval |= 0xffffff00;
// a = AMOVL;
// }
break;
case CASE(TINT8, TINT64): case CASE(TINT8, TINT64):
case CASE(TINT8, TUINT64): case CASE(TINT8, TUINT64):
case CASE(TINT8, TPTR64):
a = AMOVBQSX; a = AMOVBQSX;
// if(f->op == OCONST) { goto rdst;
// f->val.vval &= 0xff;
// if(f->val.vval & 0x80){
// f->val.vval |= 0xffffff00;
// f->val.vval |= (vlong)~0 << 32;
// }
// a = AMOVQ;
// }
break;
case CASE(TBOOL, TINT16): case CASE(TUINT8, TINT16): // zero extend uint8
case CASE(TBOOL, TUINT16):
case CASE(TBOOL, TINT32):
case CASE(TBOOL, TUINT32):
case CASE(TUINT8, TINT16):
case CASE(TUINT8, TUINT16): case CASE(TUINT8, TUINT16):
a = AMOVBWZX;
goto rdst;
case CASE(TUINT8, TINT32): case CASE(TUINT8, TINT32):
case CASE(TUINT8, TUINT32): case CASE(TUINT8, TUINT32):
a = AMOVBLZX; a = AMOVBLZX;
// if(f->op == OCONST) { goto rdst;
// f->val.vval &= 0xff;
// a = AMOVL;
// }
break;
case CASE(TBOOL, TINT64):
case CASE(TBOOL, TUINT64):
case CASE(TBOOL, TPTR64):
case CASE(TUINT8, TINT64): case CASE(TUINT8, TINT64):
case CASE(TUINT8, TUINT64): case CASE(TUINT8, TUINT64):
case CASE(TUINT8, TPTR64):
a = AMOVBQZX; a = AMOVBQZX;
// if(f->op == OCONST) { goto rdst;
// f->val.vval &= 0xff;
// a = AMOVL; /* zero-extends to 64-bits */
// }
break;
/* case CASE(TINT16, TINT32): // sign extend int16
* float to fix case CASE(TINT16, TUINT32):
*/ a = AMOVWLSX;
case CASE(TFLOAT32, TINT8): goto rdst;
case CASE(TFLOAT32, TINT16): 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): case CASE(TFLOAT32, TINT32):
regalloc(&nod, t->type, N); a = ACVTTSS2SL;
gins(ACVTTSS2SL, f, &nod); goto rdst;
gmove(&nod, t);
regfree(&nod); case CASE(TFLOAT64, TINT32):
return; 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, TINT64):
case CASE(TFLOAT32, TUINT64): a = ACVTTSS2SQ;
case CASE(TFLOAT32, TPTR64): goto rdst;
regalloc(&nod, t->type, N);
gins(ACVTTSS2SQ, f, &nod);
gmove(&nod, t);
regfree(&nod);
return;
case CASE(TFLOAT64, TINT8): case CASE(TFLOAT64, TINT64):
case CASE(TFLOAT64, TINT16): a = ACVTTSD2SQ;
case CASE(TFLOAT64, TINT32): goto rdst;
regalloc(&nod, t->type, N);
gins(ACVTTSD2SL, f, &nod);
gmove(&nod, t);
regfree(&nod);
return;
case CASE(TFLOAT64, TBOOL): case CASE(TFLOAT32, TINT16):
case CASE(TFLOAT64, TUINT8): 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, TUINT16):
case CASE(TFLOAT64, TUINT8):
// convert via int32.
cvt = types[TINT32];
goto hard;
case CASE(TFLOAT32, TUINT32):
case CASE(TFLOAT64, TUINT32): case CASE(TFLOAT64, TUINT32):
case CASE(TFLOAT64, TINT64): // convert via int64.
case CASE(TFLOAT64, TUINT64): cvt = types[TINT64];
case CASE(TFLOAT64, TPTR64): goto hard;
regalloc(&nod, t->type, N);
gins(ACVTTSD2SQ, f, &nod);
gmove(&nod, t);
regfree(&nod);
return;
/* case CASE(TFLOAT32, TUINT64):
* uvlong to float case CASE(TFLOAT64, TUINT64):
*/ // algorithm is:
case CASE(TUINT64, TFLOAT64): // if small enough, use native float64 -> int64 conversion.
case CASE(TUINT64, TFLOAT32): // otherwise, subtract 2^63, convert, and add it back.
a = ACVTSQ2SS; a = ACVTSS2SQ;
if(tt == TFLOAT64) if(ft == TFLOAT64)
a = ACVTSQ2SD; a = ACVTSD2SQ;
regalloc(&nod, f->type, f); bignodes();
gmove(f, &nod); regalloc(&r1, types[ft], N);
regalloc(&nod1, t->type, t); regalloc(&r2, types[tt], t);
nodconst(&nodc, types[TUINT64], 0); regalloc(&r3, types[ft], N);
gins(ACMPQ, &nod, &nodc); regalloc(&r4, types[tt], N);
p1 = gbranch(AJLT, T); gins(optoas(OAS, f->type), f, &r1);
gins(a, &nod, &nod1); gins(optoas(OCMP, f->type), &bigf, &r1);
p1 = gbranch(optoas(OLE, f->type), T);
gins(a, &r1, &r2);
p2 = gbranch(AJMP, T); p2 = gbranch(AJMP, T);
patch(p1, pc); patch(p1, pc);
regalloc(&nod2, f->type, N); gins(optoas(OAS, f->type), &bigf, &r3);
regalloc(&nod3, f->type, N); gins(optoas(OSUB, f->type), &r3, &r1);
gmove(&nod, &nod2); gins(a, &r1, &r2);
nodconst(&nodc, types[TUINT64], 1); gins(AMOVQ, &bigi, &r4);
gins(ASHRQ, &nodc, &nod2); gins(AXORQ, &r4, &r2);
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);
patch(p2, pc); patch(p2, pc);
regfree(&nod); gmove(&r2, t);
regfree(&nod1); regfree(&r4);
regfree(&r3);
regfree(&r2);
regfree(&r1);
return; return;
case CASE(TUINT32, TFLOAT64): /*
case CASE(TUINT32, TFLOAT32): * integer to float
a = ACVTSQ2SS; */
if(tt == TFLOAT64) case CASE(TINT32, TFLOAT32):
a = ACVTSQ2SD; a = ACVTSL2SS;
regalloc(&nod, f->type, f); goto rdst;
gins(AMOVLQZX, f, &nod);
regalloc(&nod1, t->type, t);
gins(a, &nod, &nod1); case CASE(TINT32, TFLOAT64):
gmove(&nod1, t); a = ACVTSL2SD;
regfree(&nod); goto rdst;
regfree(&nod1);
return;
/*
* fix to float
*/
case CASE(TINT64, TFLOAT32): case CASE(TINT64, TFLOAT32):
case CASE(TPTR64, TFLOAT32): a = ACVTSQ2SS;
regalloc(&nod, t->type, t); goto rdst;
gins(ACVTSQ2SS, f, &nod);
gmove(&nod, t);
regfree(&nod);
return;
case CASE(TINT64, TFLOAT64): case CASE(TINT64, TFLOAT64):
case CASE(TPTR64, TFLOAT64): a = ACVTSQ2SD;
regalloc(&nod, t->type, t); goto rdst;
gins(ACVTSQ2SD, f, &nod);
gmove(&nod, t);
regfree(&nod);
return;
case CASE(TBOOL, TFLOAT32):
case CASE(TINT8, TFLOAT32):
case CASE(TUINT8, TFLOAT32):
case CASE(TINT16, 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(TINT16, TFLOAT64):
case CASE(TINT8, TFLOAT32):
case CASE(TINT8, TFLOAT64):
case CASE(TUINT16, TFLOAT32):
case CASE(TUINT16, TFLOAT64): case CASE(TUINT16, TFLOAT64):
case CASE(TINT32, TFLOAT64): case CASE(TUINT8, TFLOAT32):
regalloc(&nod, t->type, t); case CASE(TUINT8, TFLOAT64):
gins(ACVTSL2SD, f, &nod); // convert via int32
gmove(&nod, t); cvt = types[TINT32];
regfree(&nod); 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; return;
/* /*
* float to float * float to float
*/ */
case CASE(TFLOAT32, TFLOAT32): case CASE(TFLOAT32, TFLOAT32):
a = AMOVSS; a = AMOVSS;
break; break;
case CASE(TFLOAT64, TFLOAT32):
a = ACVTSD2SS;
break;
case CASE(TFLOAT32, TFLOAT64):
a = ACVTSS2SD;
break;
case CASE(TFLOAT64, TFLOAT64): case CASE(TFLOAT64, TFLOAT64):
a = AMOVSD; a = AMOVSD;
break; 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); 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 int
...@@ -1026,6 +848,17 @@ gins(int as, Node *f, Node *t) ...@@ -1026,6 +848,17 @@ gins(int as, Node *f, Node *t)
// regfree(&nod); // 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); p = prog(as);
if(f != N) if(f != N)
naddr(f, &p->from); naddr(f, &p->from);
......
...@@ -801,3 +801,95 @@ nonnegconst(Node *n) ...@@ -801,3 +801,95 @@ nonnegconst(Node *n)
} }
return -1; 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);
}
...@@ -1061,7 +1061,7 @@ addconst(Node *n, Node *e, int ctxt) ...@@ -1061,7 +1061,7 @@ addconst(Node *n, Node *e, int ctxt)
d = dcl(); d = dcl();
d->dsym = s; d->dsym = s;
d->dnode = e; d->dnode = e;
d->op = OCONST; d->op = OLITERAL;
d->back = r->back; d->back = r->back;
r->back->forw = d; r->back->forw = d;
r->back = d; r->back = d;
......
...@@ -298,7 +298,7 @@ enum ...@@ -298,7 +298,7 @@ enum
{ {
OXXX, OXXX,
OTYPE, OCONST, OVAR, OIMPORT, OTYPE, OVAR, OIMPORT,
ONAME, ONONAME, ODCL, ONAME, ONONAME, ODCL,
ODOT, ODOTPTR, ODOTMETH, ODOTINTER, ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
...@@ -315,7 +315,7 @@ enum ...@@ -315,7 +315,7 @@ enum
OEQ, ONE, OLT, OLE, OGE, OGT, OEQ, ONE, OLT, OLE, OGE, OGT,
OADD, OSUB, OOR, OXOR, OADD, OSUB, OOR, OXOR,
OMUL, ODIV, OMOD, OLSH, ORSH, OAND, OANDNOT, OMUL, ODIV, OMOD, OLSH, ORSH, OAND, OANDNOT,
OINC, ODEC, // placeholders - not used OINC, ODEC,
OFUNC, OFUNC,
OLABEL, OLABEL,
OBREAK, OBREAK,
...@@ -795,6 +795,8 @@ Node* adddot(Node*); ...@@ -795,6 +795,8 @@ Node* adddot(Node*);
void expandmeth(Sym*, Type*); void expandmeth(Sym*, Type*);
void genwrapper(Type*, Type*, Sym*); void genwrapper(Type*, Type*, Sym*);
int simsimtype(Type*);
/* /*
* dcl.c * dcl.c
*/ */
...@@ -949,6 +951,8 @@ int smallintconst(Node*); ...@@ -949,6 +951,8 @@ int smallintconst(Node*);
long nonnegconst(Node*); long nonnegconst(Node*);
int consttype(Node*); int consttype(Node*);
int isconst(Node*, int); int isconst(Node*, int);
Mpflt* truncfltlit(Mpflt*, Type*);
void convconst(Node*, Type*, Val*);
/* /*
* align.c * align.c
......
...@@ -671,7 +671,6 @@ opnames[] = ...@@ -671,7 +671,6 @@ opnames[] =
[OCOMPOS] = "COMPOS", [OCOMPOS] = "COMPOS",
[OCOMPSLICE] = "COMPSLICE", [OCOMPSLICE] = "COMPSLICE",
[OCOM] = "COM", [OCOM] = "COM",
[OCONST] = "CONST",
[OCONTINUE] = "CONTINUE", [OCONTINUE] = "CONTINUE",
[OCONV] = "CONV", [OCONV] = "CONV",
[ODCLARG] = "DCLARG", [ODCLARG] = "DCLARG",
...@@ -3015,3 +3014,29 @@ runifacechecks(void) ...@@ -3015,3 +3014,29 @@ runifacechecks(void)
} }
lineno = lno; 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;
}
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