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)
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;
......
......@@ -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]) {
......
......@@ -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;
// 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.
case TFLOAT32:
a = AMOVSS;
goto fst;
case TFLOAT64:
a = AMOVSD;
goto fst;
}
/*
* convert
*/
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(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, TINT8):
case CASE(TFLOAT32, TINT16):
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;
/*
* fix to float
/*
* integer to float
*/
case CASE(TINT32, TFLOAT32):
a = ACVTSL2SS;
goto rdst;
case CASE(TINT32, TFLOAT64):
a = ACVTSL2SD;
goto rdst;
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
*/
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);
......
......@@ -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);
}
......@@ -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;
......
......@@ -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
......
......@@ -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;
}
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