diff options
Diffstat (limited to 'amd64')
| -rw-r--r-- | amd64/emit.c | 94 | ||||
| -rw-r--r-- | amd64/isel.c | 26 | ||||
| -rw-r--r-- | amd64/sysv.c | 13 |
3 files changed, 75 insertions, 58 deletions
diff --git a/amd64/emit.c b/amd64/emit.c index b7289d8..160c207 100644 --- a/amd64/emit.c +++ b/amd64/emit.c @@ -6,7 +6,7 @@ #define I32(w) (wr32le(*pcode, (w)), *pcode += 4) #define DS(S) D(S, sizeof S - 1) -enum operkind { ONONE, OREG, OIMM, OMEM, ORDAT }; +enum operkind { ONONE, OREG, OIMM, OMEM, OCONR }; static struct oper { uchar t; struct { uchar shift, index, base; }; /* OMEM */ @@ -14,7 +14,7 @@ static struct oper { uchar reg; /* OREG */ int disp; /* OMEM */ int imm; /* OIMM */ - int dat; /* ORDAT */ + int con; /* OCONR */ }; } ioper[MAXINSTR]; #define mkoper(t, ...) ((struct oper){(t), __VA_ARGS__}) @@ -32,8 +32,8 @@ ref2oper(union ref r) case RXCON: if (conht[r.i].cls == KI4) return mkoper(OIMM, .imm = conht[r.i].i4); - else if (conht[r.i].deref) - return mkoper(ORDAT, .dat = conht[r.i].dat); + else if (conht[r.i].deref || conht[r.i].issym) + return mkoper(OCONR, .con = r.i); assert(0); case RMORE: return mkmemoper(r); default: assert(0); @@ -56,6 +56,7 @@ addmemoper(struct oper mem, struct oper add) } enum operpat { + PNONE, PRAX, PGPR, PFPR, @@ -63,16 +64,19 @@ enum operpat { PI8, PI32, PMEM, + PSYM, }; enum operenc { EN_R = 1, /* reg with /r */ EN_RR, /* reg, reg with /r */ EN_MR, /* mem, reg with /r */ EN_RM, /* reg, mem with /r */ + EN_M, /* mem */ EN_RI8, /* reg, imm8 with /0 */ EN_RI32, /* reg, imm32 with /0 */ - EN_I32, /* imm32 */ EN_OI, /* reg, imm32 with op + reg */ + EN_I32, /* imm32 */ + EN_R32, /* rel32 */ }; struct desc { uchar psiz; /* subset of {1,2,4,8} */ @@ -87,13 +91,15 @@ static inline bool opermatch(enum operpat pat, struct oper oper) { switch (pat) { + case PNONE: return !oper.t; case PRAX: return oper.t == OREG && oper.reg == RAX; case PGPR: return oper.t == OREG && oper.reg <= R15; case PFPR: return oper.t == OREG && oper.reg >= XMM0; case P1: return oper.t == OIMM && oper.imm == 1; case PI8: return oper.t == OIMM && (uint)(oper.imm+128) < 256; case PI32: return oper.t == OIMM; - case PMEM: return in_range(oper.t, OMEM, ORDAT); + case PMEM: return in_range(oper.t, OMEM, OCONR); + case PSYM: return oper.t == OCONR; } assert(0); } @@ -143,17 +149,22 @@ encode(uchar **pcode, const struct desc *tab, int ntab, uint siz, struct oper ds case EN_RM: mem = src; reg = dst.reg; + goto Mem; + case EN_M: + mem = dst; + reg = en->ext; Mem: - if (mem.t == ORDAT) { /* RIP-relative addressing with relocation */ + if (mem.t == OCONR) { /* RIP-relative addressing with relocation */ mod = 0; - mem.disp = mem.dat; + mem.disp = mem.con; mem.base = RBP; sib = 0; if (rex) B(0x40 | rex); goto EmitMem; } - rex |= ( reg >> 3) << 2; /* REX.R */ - rex |= (mem.base >> 3) << 0; /* REX.B */ + rex |= mem.base >> 3; /* REX.B */ + if (mem.t != EN_M) + rex |= (reg >> 3) << 2; /* REX.R */ if (rex) B(0x40 | rex); else if (en->r8 && in_range(reg, RSP, RDI)) B(0x40); if (mem.index == NOINDEX && mem.shift == 0) sib = 0; @@ -181,11 +192,6 @@ encode(uchar **pcode, const struct desc *tab, int ntab, uint siz, struct oper ds else if (en->operenc == EN_RI8) B(src.imm); break; - case EN_I32: - if (rex) B(0x40 | rex); - D(opc, nopc); - I32(src.imm); - break; case EN_OI: rex |= (dst.reg >> 3) << 0; /* REX.B */ if (rex) B(0x40 | rex); @@ -193,9 +199,27 @@ encode(uchar **pcode, const struct desc *tab, int ntab, uint siz, struct oper ds D(opc, nopc - 1); I32(src.imm); break; + case EN_I32: + if (rex) B(0x40 | rex); + D(opc, nopc); + I32(src.imm); + break; + case EN_R32: + if (rex) B(0x40 | rex); + D(opc, nopc); + I32(-1); + break; } } +#define DEFINSTR1(X, ...) \ + static void \ + X(uchar **pcode, uint siz, struct oper oper) \ + { \ + static const struct desc tab[] = { __VA_ARGS__ }; \ + encode(pcode, tab, arraylength(tab), siz, oper, mkoper(0,)); \ + } + #define DEFINSTR2(X, ...) \ static void \ X(uchar **pcode, uint siz, struct oper dst, struct oper src) \ @@ -207,7 +231,7 @@ encode(uchar **pcode, const struct desc *tab, int ntab, uint siz, struct oper ds DEFINSTR2(Xmov, {1, PMEM, PGPR, "\x88", EN_MR, .r8=1}, /* MOV m8, r8 */ {2, PMEM, PGPR, "\x66\x89", EN_MR}, /* MOV m16, r16 */ - {4|8, PGPR, PGPR, "\x89", EN_RR}, /* MOV r32/64, r32/64 */ + {4|8, PGPR, PGPR, "\x8B", EN_RR}, /* MOV r32/64, r32/64 */ {4|8, PMEM, PGPR, "\x89", EN_MR}, /* MOV m32/64, r32/64 */ {4|8, PGPR, PMEM, "\x8B", EN_RM}, /* MOV r32/64, m32/64 */ {4|8, PGPR, PI32, "\xB8", EN_OI}, /* MOV r32/64, imm */ @@ -258,6 +282,11 @@ DEFINSTR2(Xshl, {4|8, PGPR, P1, "\xD1", EN_R, .ext=4}, /* SHL r32/64, 1 */ {4|8, PGPR, PI32, "\xC1", EN_RI8, .ext=4}, /* SHL r32/64, imm */ ) +DEFINSTR1(Xcall, + {-1, PSYM, 0, "\xE8", EN_R32}, /* CALL rel32 */ + {-1, PGPR, 0, "\xFF", EN_R, .ext=2}, /* CALL r64 */ + {-1, PMEM, 0, "\xFF", EN_M, .ext=2}, /* CALL m64 */ +) static void Xpush(uchar **pcode, enum reg reg) @@ -316,6 +345,15 @@ mkmemoper(union ref r) return mkoper(OMEM, .base = wop.reg, .index = NOINDEX); } else if (r.t == RMORE) { struct addr *addr = &addrtab.p[r.i]; + struct oper mem; + if (addr->base.t == RTMP && ioper[addr->base.i].t == OMEM) { + mem = ioper[addr->base.i]; + if (addr->index.t) addmemoper(mem, mkregoper(addr->index)); + assert(!mem.shift); + mem.shift = addr->shift; + addmemoper(mem, mkoper(OIMM, .imm = addr->disp)); + return mem; + } return mkoper(OMEM, .base = addr->base.t ? mkregoper(addr->base).reg : NOBASE, .index = addr->index.t ? mkregoper(addr->index).reg : NOINDEX, .disp = addr->disp, @@ -367,7 +405,7 @@ gencopy(uchar **pcode, enum irclass cls, struct oper dst, union ref val) Lea: Xlea(pcode, cls2siz[cls], dst, ref2oper(val)); } else if (val.t == RXCON && conht[val.i].isdat && !conht[val.i].deref) { - Xlea(pcode, cls2siz[cls], dst, mkoper(ORDAT, .dat = conht[val.i].dat)); + Xlea(pcode, cls2siz[cls], dst, mkoper(OCONR, .con = val.i)); } else { struct oper src = mkimmregoper(val); if (memcmp(&dst, &src, sizeof dst) != 0) @@ -388,24 +426,13 @@ emitinstr(uchar **pcode, uint *stktop, struct function *fn, struct block *blk, i *stktop += siz; *stktop = alignup(*stktop, 1 << alignlog2); ioper[ins - instrtab] = mkoper(OMEM, .base = RBP, .index = NOINDEX, .disp = -*stktop); - } else if (oisstore(ins->op)) { - dst = mkmemoper(ins->l); - if (ins->r.t == RPARAM) { - int off = 8; - struct abiarg abi; - for (int i = 0; i < ins->r.i; ++i) { - abi = fn->abiarg[ins->r.i]; - if (abi.reg == -1) - off = alignup(off + typedata[abi.ty.dat].siz, 8); - } - assert(abi.reg == -1 && "reg par"); - assert(!"nyi"); - } else { - Xmov(pcode, 1 << (ins->op - Ostore1), dst, mkimmregoper(ins->r)); - } } else switch (ins->op) { default: assert(!"nyi ins"); case Onop: break; + case Ostore1: case Ostore2: case Ostore4: case Ostore8: + dst = mkmemoper(ins->l); + Xmov(pcode, 1 << (ins->op - Ostore1), dst, mkimmregoper(ins->r)); + break; case Oexts1: src = mkregoper(ins->l); goto Movsx1; case Oextu1: src = mkregoper(ins->l); goto Movzx1; case Oexts2: src = mkregoper(ins->l); goto Movsx2; @@ -435,6 +462,9 @@ emitinstr(uchar **pcode, uint *stktop, struct function *fn, struct block *blk, i dst = reg2oper(ins->reg-1); gencopy(pcode, ins->cls, dst, ins->l); break; + case Ocall: + Xcall(pcode, -1, ref2oper(ins->l)); + break; } if (ins->reg) ioper[ins - instrtab] = reg2oper(ins->reg-1); } diff --git a/amd64/isel.c b/amd64/isel.c index 7883e28..f99c8a2 100644 --- a/amd64/isel.c +++ b/amd64/isel.c @@ -1,6 +1,6 @@ #include "all.h" -static bool mkaddr(struct function *fn, union ref *r); +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) @@ -27,10 +27,6 @@ fixarg(struct function *fn, union ref *r, struct instr *ins, struct block *blk, sh = r->i; ShiftImm: /* shift immediate is always 8bit */ *r = mkref(RICON, sh & 255); - } else if (r->t == RPARAM) { - if (fn->abiarg[r->i].reg != -1) { - *r = mkref(RREG, fn->abiarg[r->i].reg); - } } } @@ -99,7 +95,7 @@ aadd(struct function *fn, struct addr *addr, union ref r, bool rec) } static bool -mkaddr(struct function *fn, union ref *r) +fuseaddr(struct function *fn, union ref *r) { struct addr addr = { 0 }; struct instr *ins = &instrtab[r->i]; @@ -167,7 +163,7 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi) temp.op = Ocopy; temp.cls = ins->cls; temp.l = mkref(RTMP, ins - instrtab); - if (mkaddr(fn, &temp.l)) { + if (fuseaddr(fn, &temp.l)) { *ins = temp; break; } @@ -193,12 +189,12 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi) case Oloads4: case Oloadu4: case Oloadi8: case Oloadf4: case Oloadf8: if (ins->l.t != RTMP && ins->l.t != RREG) ins->l = insertinstr(blk, (*curi)++, mkinstr(Ocopy, ins->cls, ins->l)); - mkaddr(fn, &ins->l); + fuseaddr(fn, &ins->l); break; case Ostore1: case Ostore2: case Ostore4: case Ostore8: if (ins->l.t != RTMP && ins->l.t != RREG) ins->l = insertinstr(blk, (*curi)++, mkinstr(Ocopy, ins->cls, ins->l)); - mkaddr(fn, &ins->l); + fuseaddr(fn, &ins->l); fixarg(fn, &ins->r, ins, blk, curi); break; case Ocopy: @@ -224,18 +220,6 @@ amd64_isel(struct function *fn) ins = &instrtab[blk->ins.p[i]]; sel(fn, ins, blk, &i); } - if (blk->jmp.t == Jret) { - if (blk->jmp.arg[0].t) { - insertinstr(blk, blk->ins.n, mkinstr(Omove, fn->abiret[0].ty.cls, - mkref(RREG, fn->abiret[0].reg), blk->jmp.arg[0])); - blk->jmp.arg[0] = mkref(RREG, fn->abiret[0].reg); - if (blk->jmp.arg[1].t) { - insertinstr(blk, blk->ins.n, mkinstr(Omove, fn->abiret[1].ty.cls, - mkref(RREG, fn->abiret[1].reg), blk->jmp.arg[1])); - blk->jmp.arg[1] = mkref(RREG, fn->abiret[1].reg); - } - } - } } while ((blk = blk->lnext) != fn->entry); if (ccopt.dbg.i) { diff --git a/amd64/sysv.c b/amd64/sysv.c index 69ebce4..1128cc2 100644 --- a/amd64/sysv.c +++ b/amd64/sysv.c @@ -68,8 +68,8 @@ 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 { - ++*ns; - r[0] = -1; + r[0] = -*ns - 8; + *ns += 8; return 0; /* MEMORY */ } return 1; @@ -77,7 +77,8 @@ 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*/ - ++*ns; + r[0] = -*ns - 8; + *ns = alignup(*ns + typedata[typ.dat].siz, 8); return 0; } assert(ret <= 2); @@ -90,8 +91,9 @@ 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; - ++*ns; - r[0] = r[1] = -1; + r[0] = -*ns - 8; + *ns = alignup(*ns + typedata[typ.dat].siz, 8); + r[1] = -1; return cls[0] = cls[1] = 0; } } @@ -137,6 +139,7 @@ const char amd64_rnames[][6] = { const struct mctarg t_amd64_sysv = { .gpr0 = RAX, .ngpr = R15 - RAX + 1, + .spr = RSP, .fpr0 = XMM0, .nfpr = XMM15 - XMM0 + 1, .rcallee = {{1<<RBX | 1<<R12 | 1<<R13 | 1<<R14 | 1<<R15}}, .rglob = {{1<<RSP | 1<<RBP}}, |