add a size to all operations (wip)
This commit is contained in:
parent
0ad9bf1c60
commit
28110b1439
8 changed files with 126 additions and 190 deletions
117
lisc/isel.c
117
lisc/isel.c
|
@ -20,15 +20,15 @@
|
|||
extern Ins insb[NIns], *curi; /* shared work buffer */
|
||||
|
||||
static void
|
||||
emit(short op, Ref to, Ref arg0, Ref arg1)
|
||||
emit(int op, int w, Ref to, Ref arg0, Ref arg1)
|
||||
{
|
||||
if (curi == insb)
|
||||
diag("isel: too many instructions");
|
||||
*--curi = (Ins){op, to, {arg0, arg1}};
|
||||
*--curi = (Ins){op, w, to, {arg0, arg1}};
|
||||
}
|
||||
|
||||
static Ref
|
||||
newtmp(int type, Fn *fn)
|
||||
newtmp(Fn *fn)
|
||||
{
|
||||
static int n;
|
||||
int t;
|
||||
|
@ -37,7 +37,7 @@ newtmp(int type, Fn *fn)
|
|||
fn->tmp = realloc(fn->tmp, fn->ntmp * sizeof fn->tmp[0]);
|
||||
if (!fn->tmp)
|
||||
diag("isel: out of memory");
|
||||
fn->tmp[t] = (Tmp){.type = type};
|
||||
memset(&fn->tmp[t], 0, sizeof fn->tmp[t]);
|
||||
sprintf(fn->tmp[t].name, "isel%d", ++n);
|
||||
return TMP(t);
|
||||
}
|
||||
|
@ -80,17 +80,10 @@ noimm(Ref r, Fn *fn)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
islong(Ref r, Fn *fn)
|
||||
{
|
||||
return rtype(r) == RTmp && fn->tmp[r.val].type == TLong;
|
||||
}
|
||||
|
||||
static void
|
||||
selcmp(Ref arg[2], Fn *fn)
|
||||
selcmp(Ref arg[2], int w, Fn *fn)
|
||||
{
|
||||
Ref r;
|
||||
int lng;
|
||||
|
||||
if (rtype(arg[0]) == RCon) {
|
||||
r = arg[1];
|
||||
|
@ -98,12 +91,11 @@ selcmp(Ref arg[2], Fn *fn)
|
|||
arg[0] = r;
|
||||
}
|
||||
assert(rtype(arg[0]) != RCon);
|
||||
lng = islong(arg[0], fn) || islong(arg[1], fn);
|
||||
emit(lng ? OXCmpl : OXCmpw, R, arg[1], arg[0]);
|
||||
emit(OXCmp, w, R, arg[1], arg[0]);
|
||||
r = arg[1];
|
||||
if (lng && rtype(r) == RCon && noimm(r, fn)) {
|
||||
curi->arg[0] = newtmp(TLong, fn);
|
||||
emit(OCopy, curi->arg[0], r, R);
|
||||
if (w && rtype(r) == RCon && noimm(r, fn)) {
|
||||
curi->arg[0] = newtmp(fn);
|
||||
emit(OCopy, w, curi->arg[0], r, R);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,8 +110,8 @@ rslot(Ref r, Fn *fn)
|
|||
static void
|
||||
sel(Ins i, Fn *fn)
|
||||
{
|
||||
Ref r0, r1, ra, rd;
|
||||
int n, ty, c, s;
|
||||
Ref r0, r1;
|
||||
int n, c, s, w;
|
||||
int64_t val;
|
||||
struct {
|
||||
Ref r;
|
||||
|
@ -131,52 +123,38 @@ sel(Ins i, Fn *fn)
|
|||
cpy[n].s = 0;
|
||||
s = rslot(r0, fn);
|
||||
if (s) {
|
||||
r0 = newtmp(TLong, fn);
|
||||
r0 = newtmp(fn);
|
||||
i.arg[n] = r0;
|
||||
cpy[n].r = r0;
|
||||
cpy[n].s = s;
|
||||
}
|
||||
}
|
||||
|
||||
w = i.wide;
|
||||
switch (i.op) {
|
||||
case ODiv:
|
||||
case ORem:
|
||||
ty = fn->tmp[i.to.val].type;
|
||||
switch (ty) {
|
||||
default:
|
||||
diag("isel: invalid division");
|
||||
case TWord:
|
||||
ra = TMP(EAX);
|
||||
rd = TMP(EDX);
|
||||
break;
|
||||
case TLong:
|
||||
ra = TMP(RAX);
|
||||
rd = TMP(RDX);
|
||||
break;
|
||||
}
|
||||
r0 = i.op == ODiv ? ra : rd;
|
||||
r1 = i.op == ODiv ? rd : ra;
|
||||
emit(OCopy, i.to, r0, R);
|
||||
emit(OCopy, R, r1, R);
|
||||
if (i.op == ODiv)
|
||||
r0 = TMP(RAX), r1 = TMP(RDX);
|
||||
else
|
||||
r0 = TMP(RDX), r1 = TMP(RAX);
|
||||
emit(OCopy, w, i.to, r0, R);
|
||||
emit(OCopy, w, R, r1, R);
|
||||
if (rtype(i.arg[1]) == RCon) {
|
||||
/* immediates not allowed for
|
||||
* divisions in x86
|
||||
*/
|
||||
r0 = newtmp(ty, fn);
|
||||
r0 = newtmp(fn);
|
||||
} else
|
||||
r0 = i.arg[1];
|
||||
emit(OXDiv, R, r0, R);
|
||||
emit(OSign, rd, ra, R);
|
||||
emit(OCopy, ra, i.arg[0], R);
|
||||
emit(OXDiv, w, R, r0, R);
|
||||
emit(OSign, w, TMP(RDX), TMP(RAX), R);
|
||||
emit(OCopy, w, TMP(RAX), i.arg[0], R);
|
||||
if (rtype(i.arg[1]) == RCon)
|
||||
emit(OCopy, r0, i.arg[1], R);
|
||||
emit(OCopy, w, r0, i.arg[1], R);
|
||||
break;
|
||||
case ONop:
|
||||
break;
|
||||
case OXTestw:
|
||||
case OXTestl:
|
||||
n = i.op == OXTestl ? 2 : 0;
|
||||
goto Emit;
|
||||
case OSext:
|
||||
case OZext:
|
||||
n = 0;
|
||||
|
@ -189,10 +167,8 @@ sel(Ins i, Fn *fn)
|
|||
case OMul:
|
||||
case OAnd:
|
||||
case OCopy:
|
||||
if (fn->tmp[i.to.val].type == TLong)
|
||||
n = 2;
|
||||
else
|
||||
n = 0;
|
||||
case OXTest:
|
||||
n = w ? 2 : 0;
|
||||
goto Emit;
|
||||
case OStorel:
|
||||
case OStorew:
|
||||
|
@ -215,7 +191,7 @@ sel(Ins i, Fn *fn)
|
|||
}
|
||||
n = 0;
|
||||
Emit:
|
||||
emit(i.op, i.to, i.arg[0], i.arg[1]);
|
||||
emit(i.op, w, i.to, i.arg[0], i.arg[1]);
|
||||
while (n--) {
|
||||
/* load constants that do not fit in
|
||||
* a 32bit signed integer into a
|
||||
|
@ -223,8 +199,8 @@ Emit:
|
|||
*/
|
||||
r0 = i.arg[n];
|
||||
if (rtype(r0) == RCon && noimm(r0, fn)) {
|
||||
curi->arg[n] = newtmp(TLong, fn);
|
||||
emit(OCopy, curi->arg[n], r0, R);
|
||||
curi->arg[n] = newtmp(fn);
|
||||
emit(OCopy, 1, curi->arg[n], r0, R);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -243,14 +219,14 @@ Emit:
|
|||
val = (val + 15) & ~INT64_C(15);
|
||||
if (val < 0 || val > INT32_MAX)
|
||||
diag("isel: alloc too large");
|
||||
emit(OAlloc, i.to, newcon(val, fn), R);
|
||||
emit(OAlloc, 0, i.to, newcon(val, fn), R);
|
||||
} else {
|
||||
/* r0 = (i.arg[0] + 15) & -16 */
|
||||
r0 = newtmp(TLong, fn);
|
||||
r1 = newtmp(TLong, fn);
|
||||
emit(OAlloc, i.to, r0, R);
|
||||
emit(OAnd, r0, r1, newcon(-16, fn));
|
||||
emit(OAdd, r1, i.arg[0], newcon(15, fn));
|
||||
r0 = newtmp(fn);
|
||||
r1 = newtmp(fn);
|
||||
emit(OAlloc, 0, i.to, r0, R);
|
||||
emit(OAnd, 1, r0, r1, newcon(-16, fn));
|
||||
emit(OAdd, 1, r1, i.arg[0], newcon(15, fn));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -258,8 +234,8 @@ Emit:
|
|||
c = i.op - OCmp;
|
||||
if (rtype(i.arg[0]) == RCon)
|
||||
c = COP(c);
|
||||
emit(OXSet+c, i.to, R, R);
|
||||
selcmp(i.arg, fn);
|
||||
emit(OXSet+c, 0, i.to, R, R);
|
||||
selcmp(i.arg, w, fn);
|
||||
break;
|
||||
}
|
||||
diag("isel: non-exhaustive implementation");
|
||||
|
@ -267,7 +243,7 @@ Emit:
|
|||
|
||||
for (n=0; n<2; n++)
|
||||
if (cpy[n].s)
|
||||
emit(OAddr, cpy[n].r, SLOT(cpy[n].s), R);
|
||||
emit(OAddr, 0, cpy[n].r, SLOT(cpy[n].s), R);
|
||||
}
|
||||
|
||||
static Ins *
|
||||
|
@ -327,19 +303,16 @@ seljmp(Blk *b, Fn *fn)
|
|||
c = COP(c);
|
||||
b->jmp.type = JXJc + c;
|
||||
if (fn->tmp[r.val].nuse == 1) {
|
||||
assert(fn->tmp[r.val].ndef==1);
|
||||
selcmp(fi->arg, fn);
|
||||
*fi = (Ins){ONop, R, {R, R}};
|
||||
assert(fn->tmp[r.val].ndef == 1);
|
||||
selcmp(fi->arg, fi->wide, fn);
|
||||
*fi = (Ins){.op = ONop};
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (fi->op == OAnd && fn->tmp[r.val].nuse == 1
|
||||
&& (rtype(fi->arg[0]) == RTmp ||
|
||||
rtype(fi->arg[1]) == RTmp)) {
|
||||
if (fn->tmp[r.val].type == TLong)
|
||||
fi->op = OXTestl;
|
||||
else
|
||||
fi->op = OXTestw;
|
||||
fi->op = OXTest;
|
||||
fi->to = R;
|
||||
b->jmp.type = JXJc + Cne;
|
||||
if (rtype(fi->arg[1]) == RCon) {
|
||||
|
@ -354,7 +327,7 @@ seljmp(Blk *b, Fn *fn)
|
|||
return;
|
||||
}
|
||||
}
|
||||
selcmp((Ref[2]){r, CON_Z}, fn);
|
||||
selcmp((Ref[2]){r, CON_Z}, 0, fn); /* fixme, add long branch if non-zero */
|
||||
b->jmp.type = JXJc + Cne;
|
||||
}
|
||||
|
||||
|
@ -452,8 +425,8 @@ isel(Fn *fn)
|
|||
assert(a+1 < p->narg);
|
||||
s = rslot(p->arg[a], fn);
|
||||
if (s) {
|
||||
p->arg[a] = newtmp(TLong, fn);
|
||||
emit(OAddr, p->arg[a], SLOT(s), R);
|
||||
p->arg[a] = newtmp(fn);
|
||||
emit(OAddr, 0, p->arg[a], SLOT(s), R);
|
||||
}
|
||||
}
|
||||
curi = &insb[NIns];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue