aboutsummaryrefslogtreecommitdiffhomepage
path: root/amd64
diff options
context:
space:
mode:
Diffstat (limited to 'amd64')
-rw-r--r--amd64/emit.c55
-rw-r--r--amd64/isel.c103
-rw-r--r--amd64/sysv.c8
3 files changed, 66 insertions, 100 deletions
diff --git a/amd64/emit.c b/amd64/emit.c
index d7847f5..6be080e 100644
--- a/amd64/emit.c
+++ b/amd64/emit.c
@@ -478,20 +478,14 @@ gencopy(uchar **pcode, enum irclass cls, struct oper dst, union ref val)
}
static void
-emitinstr(uchar **pcode, uint *stktop, struct function *fn, struct block *blk, int ii, struct instr *ins)
+emitinstr(uchar **pcode, struct function *fn, struct block *blk, int ii, struct instr *ins)
{
struct oper dst, src;
uchar ksiz = cls2siz[ins->cls];
void (*X)(uchar **, uint, struct oper, struct oper) = NULL;
void (*X1)(uchar **, uint, struct oper) = NULL;
- if (oisalloca(ins->op)) {
- uint alignlog2 = ins->op - Oalloca1;
- uint siz = ins->l.i << alignlog2;
- *stktop += siz;
- *stktop = alignup(*stktop, 1 << alignlog2);
- ioper[ins - instrtab] = mkoper(OMEM, .base = RBP, .index = NOINDEX, .disp = -*stktop);
- } else switch (ins->op) {
+ switch (ins->op) {
default: assert(!"nyi ins");
case Onop: break;
case Ostore1: case Ostore2: case Ostore4: case Ostore8:
@@ -581,25 +575,6 @@ calleerestore(uchar **pcode, struct function *fn)
if (bstest(fn->regusage, RBX)) Xpop(pcode, RBX);
}
-static bool /* stack frame size <= 128? */
-smallstack(struct function *fn)
-{
- uint stktop = 0;
- struct block *blk = fn->entry;
- do {
- for (int i = 0; i < blk->ins.n; ++i) {
- struct instr *ins = &instrtab[blk->ins.p[i]];
- if (oisalloca(ins->op)) {
- uint align = 1 << (ins->op - Oalloca1);
- uint siz = ins->l.i * align;
- stktop = alignup(stktop + siz, align);
- if (alignup(stktop, 16) > 128) return 0;
- }
- }
- } while ((blk = blk->lnext) != fn->entry);
- return 1;
-}
-
/* align code using NOPs */
static void
aligncode(uchar **pcode, int align)
@@ -625,9 +600,6 @@ static void
emitbin(struct function *fn)
{
struct block *blk;
- uchar *rspdisp;
- uint stktop = 0;
- bool stack8 = smallstack(fn);
uchar **pcode = &objout.code;
aligncode(pcode, 16);
@@ -637,15 +609,17 @@ emitbin(struct function *fn)
DS("\x55\x48\x89\xE5");
calleesave(pcode, fn);
/* sub rsp, <stack size> */
- if (stack8)
- DS("\x48\x83\xEC"), rspdisp = *pcode, DS("\xAA");
+ if (fn->stksiz < 128)
+ DS("\x48\x83\xEC"), B(fn->stksiz);
+ else if (fn->stksiz == 128)
+ DS("\x48\x83\xC4\x80"); /* add rsp, -128 */
else
- DS("\x48\x81\xEC"), rspdisp = *pcode, DS("\xAA\xAA\xAA\xAA");
+ DS("\x48\x81\xEC"), I32(fn->stksiz);
blk = fn->entry;
do {
for (int i = 0; i < blk->ins.n; ++i) {
- emitinstr(pcode, &stktop, fn, blk, i, &instrtab[blk->ins.p[i]]);
+ emitinstr(pcode, fn, blk, i, &instrtab[blk->ins.p[i]]);
}
if (blk->jmp.t == Jret) {
/* epilogue */
@@ -653,19 +627,6 @@ emitbin(struct function *fn)
DS("\xC9\xC3"); /* leave; ret */
}
} while ((blk = blk->lnext) != fn->entry);
-
- stktop = alignup(stktop, 16);
- if (stack8) {
- assert(stktop <= 128);
- if (stktop < 128) *rspdisp = stktop;
- else {
- /* cannot encode `sub rsp, 128` with 8bit imm, turn into `add rsp, -128` */
- rspdisp[-1] = 0xC4;
- *rspdisp = -128;
- }
- } else {
- wr32le(rspdisp, alignup(stktop, 16));
- }
}
void
diff --git a/amd64/isel.c b/amd64/isel.c
index 858dfbc..3734143 100644
--- a/amd64/isel.c
+++ b/amd64/isel.c
@@ -1,7 +1,5 @@
#include "all.h"
-static bool fuseaddr(struct function *fn, union ref *r);
-
static void
fixarg(struct function *fn, union ref *r, struct instr *ins, struct block *blk, int *curi)
{
@@ -16,7 +14,7 @@ fixarg(struct function *fn, union ref *r, struct instr *ins, struct block *blk,
} else if (in_range(op, Oadd, Osub) && con->i8 == 2147483648) {
/* add X, INT32MAX+1 -> sub X, INT32MIN */
ins->op = Oadd + (op == Oadd);
- *r = mkintcon(fn, KI4, -2147483648);
+ *r = mkintcon(KI4, -2147483648);
} else if (in_range(op, Ocopy, Omove) && kisflt(con->cls)
&& (con->cls == KF4 ? con->fs == 0.0f : con->fd == 0.0))
{
@@ -28,7 +26,7 @@ fixarg(struct function *fn, union ref *r, struct instr *ins, struct block *blk,
uint siz = cls2siz[con->cls];
if (con->cls == KI4 || con->cls == KF4) wr32le(data, con->i4);
else wr64le(data, con->i8);
- *r = mkdatref(fn, siz, /*align*/siz, data, siz, /*deref*/1);
+ *r = mkdatref(siz, /*align*/siz, data, siz, /*deref*/1);
} else if (in_range(op, Odiv, Ourem) && kisint(ins->cls))
goto DivImm;
} else if (r->t == RICON && in_range(op, Odiv, Ourem) && kisint(ins->cls)) {
@@ -46,7 +44,7 @@ fixarg(struct function *fn, union ref *r, struct instr *ins, struct block *blk,
#define rswap(a,b) do { union ref _t = (a); (a) = (b); (b) = _t; } while (0)
static bool
-acon(struct function *fn, struct addr *addr, union ref r)
+acon(struct addr *addr, union ref r)
{
vlong a = addr->disp;
if (r.t == RICON) {
@@ -63,7 +61,7 @@ acon(struct function *fn, struct addr *addr, union ref r)
}
static bool
-ascale(struct function *fn, struct addr *addr, union ref a, union ref b)
+ascale(struct addr *addr, union ref a, union ref b)
{
if (b.t != RICON) return 0;
if (addr->index.t) return 0;
@@ -75,33 +73,41 @@ ascale(struct function *fn, struct addr *addr, union ref a, union ref b)
}
static bool
-aadd(struct function *fn, struct addr *addr, union ref r, bool rec)
+aadd(struct addr *addr, union ref r, bool rec)
{
- struct instr *ins = &instrtab[r.i];
- if (r.t == RTMP && ins->op == Oadd) {
- if (!aadd(fn, addr, ins->l, rec)) return 0;
- if (!aadd(fn, addr, ins->r, rec)) return 0;
- ins->skip = 1;
- } else if (r.t == RTMP && ins->op == Oshl) {
- if (!ascale(fn, addr, ins->l, ins->r)) return 0;
- ins->skip = 1;
- } else if (!rec && r.t == RTMP && ins->op == Ocopy && ins->l.t == RMORE) {
- struct addr save = *addr, *addr2 = &addrtab.p[ins->l.i];
- if ((!addr2->base.t || aadd(fn, addr, addr2->base, 1))
- && aadd(fn, addr, mkintcon(fn, KI4, addr2->disp), 1)
- && (!addr2->index.t || ascale(fn, addr, addr2->index, mkref(RICON, addr2->shift))))
- {
+ if (r.t == RTMP) {
+ struct instr *ins = &instrtab[r.i];
+
+ if (ins->op == Oadd) {
+ if (!aadd(addr, ins->l, rec)) return 0;
+ if (!aadd(addr, ins->r, rec)) return 0;
ins->skip = 1;
- } else {
- *addr = save;
- goto Ref;
- }
- } else if (iscon(r)) return acon(fn, addr, r);
- else Ref: {
+ } else if (ins->op == Oshl) {
+ if (!ascale(addr, ins->l, ins->r)) return 0;
+ ins->skip = 1;
+ } else if (!rec && ins->op == Ocopy && ins->l.t == RMORE) {
+ struct addr save = *addr, *addr2 = &addrtab.p[ins->l.i];
+ if ((!addr2->base.t || aadd(addr, addr2->base, 1))
+ && aadd(addr, mkintcon(KI4, addr2->disp), 1)
+ && (!addr2->index.t || ascale(addr, addr2->index, mkref(RICON, addr2->shift))))
+ {
+ ins->skip = 1;
+ } else {
+ *addr = save;
+ goto Ref;
+ }
+ } else goto Ref;
+ } else if (iscon(r)) {
+ return acon(addr, r);
+ } else if (r.t == RREG) {
+ /* temporaries are single assignment, but register aren't, so they can't be *
+ * safely hoisted into an address value, unless they have global lifetime */
+ if (!bstest(mctarg->rglob, r.i)) return 0;
+ Ref:
if (!addr->base.t) addr->base = r;
else if (!addr->index.t) addr->index = r;
else return 0;
- }
+ } else return 0;
return 1;
}
@@ -109,21 +115,12 @@ static bool
fuseaddr(struct function *fn, union ref *r)
{
struct addr addr = { 0 };
- struct instr *ins = &instrtab[r->i];
+
if (r->t == RMORE) return 1;
- else if (r->t != RTMP) return 0;
- else if (ins->op == Oadd) {
- if (ins->l.t == RTMP && instrtab[ins->l.i].op == Ocopy && instrtab[ins->l.i].l.t == RMORE)
- /* put ADDR in rhs because this code is dumb and it might be better */
- rswap(ins->l, ins->r);
- if (!aadd(fn, &addr, ins->l, 0)) return 0;
- if (!aadd(fn, &addr, ins->r, 0)) return 0;
- ins->skip = 1;
- } else if (ins->op == Oshl) {
- if (!ascale(fn, &addr, ins->l, ins->r)) return 0;
- ins->skip = 1;
- }
- else return 0;
+ if (r->t != RTMP) return 0;
+
+ if (!aadd(&addr, *r, 0)) return 0;
+
vpush(&addrtab, addr);
*r = mkref(RMORE, addrtab.n-1);
return 1;
@@ -141,6 +138,7 @@ addarg4addrp(union ref r)
static void
sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
{
+ uint siz, alignlog2;
struct instr temp = {0};
enum op op = ins->op;
@@ -148,6 +146,13 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
default: assert(0);
case Onop: break;
case Oalloca1: case Oalloca2: case Oalloca4: case Oalloca8: case Oalloca16:
+ alignlog2 = ins->op - Oalloca1;
+ siz = ins->l.i << alignlog2;
+ fn->stksiz += siz;
+ fn->stksiz = alignup(fn->stksiz, 1 << alignlog2);
+ if (fn->stksiz > 1<<24) error(NULL, "'%s' stack frame too big", fn->name);
+ *ins = mkinstr(Oadd, KPTR, mkref(RREG, mctarg->bpr), mkref(RICON, -fn->stksiz));
+ break;
case Ocall: case Ointrin:
break;
case Oshl: case Osar: case Oslr:
@@ -206,8 +211,7 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
ins->op = Oxinc;
ins->r = NOREF;
goto ALU;
- }
- if (kisint(ins->cls) && (addarg4addrp(ins->l) || addarg4addrp(ins->r))) {
+ } else if (kisint(ins->cls) && (addarg4addrp(ins->l) || addarg4addrp(ins->r))) {
temp.op = Ocopy;
temp.cls = ins->cls;
temp.l = mkref(RTMP, ins - instrtab);
@@ -258,8 +262,9 @@ amd64_isel(struct function *fn)
{
struct block *blk = fn->entry;
+ fn->stksiz = 0;
+
do {
- struct instr *ins;
for (int i = 0; i < blk->phi.n; ++i) {
struct phi *phi = &phitab.p[instrtab[blk->phi.p[i]].l.i];
for (int i = 0; i < phi->n; ++i) {
@@ -267,14 +272,14 @@ amd64_isel(struct function *fn)
}
}
for (int i = 0; i < blk->ins.n; ++i) {
- ins = &instrtab[blk->ins.p[i]];
- sel(fn, ins, blk, &i);
+ sel(fn, &instrtab[blk->ins.p[i]], blk, &i);
}
} while ((blk = blk->lnext) != fn->entry);
+ fn->stksiz = alignup(fn->stksiz, 16);
if (ccopt.dbg.i) {
- efmt("after isel:\n");
- irdump(fn, fn->name);
+ efmt("<< After isel >>\n");
+ irdump(fn);
}
}
diff --git a/amd64/sysv.c b/amd64/sysv.c
index 7d391dc..1c84909 100644
--- a/amd64/sysv.c
+++ b/amd64/sysv.c
@@ -68,7 +68,7 @@ abiarg(short r[2], uchar cls[2], int *ni, int *nf, int *ns, union irtype typ)
} else if (*ni < NINT) {
r[0] = intregs[(*ni)++];
} else {
- r[0] = -*ns - 8;
+ r[0] = -*ns - 16;
*ns += 8;
return 0; /* MEMORY */
}
@@ -77,7 +77,7 @@ abiarg(short r[2], uchar cls[2], int *ni, int *nf, int *ns, union irtype typ)
cls[0] = cls[1] = 0;
ret = classify(cls, &typedata[typ.dat], 0);
if (!ret) { /*MEMORY*/
- r[0] = -*ns - 8;
+ r[0] = -*ns - 16;
*ns = alignup(*ns + typedata[typ.dat].siz, 8);
return 0;
}
@@ -91,7 +91,7 @@ abiarg(short r[2], uchar cls[2], int *ni, int *nf, int *ns, union irtype typ)
r[i] = intregs[(*ni)++];
else { /* MEMORY */
*ni = ni_save, *nf = nf_save;
- r[0] = -*ns - 8;
+ r[0] = -*ns - 16;
*ns = alignup(*ns + typedata[typ.dat].siz, 8);
r[1] = -1;
return cls[0] = cls[1] = 0;
@@ -139,7 +139,7 @@ const char amd64_rnames[][6] = {
const struct mctarg t_amd64_sysv = {
.gpr0 = RAX, .ngpr = R15 - RAX + 1,
- .fpr = RBP,
+ .bpr = RBP,
.fpr0 = XMM0, .nfpr = XMM15 - XMM0 + 1,
.rcallee = {{1<<RBX | 1<<R12 | 1<<R13 | 1<<R14 | 1<<R15}},
.rglob = {{1<<RSP | 1<<RBP}},