diff options
Diffstat (limited to 'amd64')
| -rw-r--r-- | amd64/emit.c | 55 | ||||
| -rw-r--r-- | amd64/isel.c | 103 | ||||
| -rw-r--r-- | amd64/sysv.c | 8 |
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}}, |